2020
2121#pragma once
2222
23- #include " pmacc_types.hpp"
2423#include " simulation_defines.hpp"
2524#include " particles/traits/GetAtomicNumbers.hpp"
2625#include " traits/attribute/GetChargeState.hpp"
26+
2727#include " algorithms/math/floatMath/floatingPoint.tpp"
28- #include " particles/ionization/byCollision/ThomasFermi/TFFittingParameters.def"
2928
3029/* * \file AlgorithmThomasFermi.hpp
3130 *
@@ -48,11 +47,13 @@ namespace ionization
4847 * \brief calculation for the Thomas-Fermi pressure ionization model
4948 *
5049 * This model uses local density and "temperature" values as input
51- * parameters. To be able to speak of a "temperature" an equilibrium state
52- * would be required. Typical high power laser-plasma interaction is highly
50+ * parameters. A physical temperature requires a defined equilibrium state.
51+ * Typical high power laser-plasma interaction is highly
5352 * non-equilibrated, though. The name "temperature" is kept to illustrate
5453 * the origination from the Thomas-Fermi model. It is nevertheless
55- * more accurate to think of it as an averaged kinetic energy.
54+ * more accurate to think of it as an averaged kinetic energy
55+ * which is not backed by the model and should therefore only be used with
56+ * a certain suspicion in such Non-LTE scenarios.
5657 */
5758 struct AlgorithmThomasFermi
5859 {
@@ -68,86 +69,87 @@ namespace ionization
6869 * \param randNr random number
6970 */
7071 template <typename KinEnergyDensityType, typename DensityType, typename ParticleType >
71- HDINLINE void
72+ HDINLINE float_X
7273 operator ()( const KinEnergyDensityType kinEnergyDensity, const DensityType density, ParticleType& parentIon, float_X randNr )
7374 {
7475
7576 /* @TODO replace the float_64 with float_X and make sure the values are scaled to PIConGPU units */
76- const float_64 protonNumber = GetAtomicNumbers<ParticleType>::type::numberOfProtons;
77- const float_64 neutronNumber = GetAtomicNumbers<ParticleType>::type::numberOfNeutrons;
77+ float_64 constexpr protonNumber = GetAtomicNumbers<ParticleType>::type::numberOfProtons;
78+ float_64 constexpr neutronNumber = GetAtomicNumbers<ParticleType>::type::numberOfNeutrons;
7879 float_64 chargeState = attribute::getChargeState (parentIon);
7980
8081 /* ionization condition */
8182 if (chargeState < protonNumber)
8283 {
8384 /* atomic mass number (usually A) A = N + Z */
84- float_64 massNumber = neutronNumber + protonNumber;
85+ float_64 constexpr massNumber = neutronNumber + protonNumber;
8586
8687 /* * @TODO replace the static_cast<float_64> by casts to float_X
8788 * or leave out entirely and compute everything in PIConGPU scaled units
8889 */
89- float_64 const densityUnit = static_cast <float_64>(particleToGrid::derivedAttributes::Density ().getUnit ()[0 ]);
90- float_64 const kinEnergyDensityUnit = static_cast <float_64>(particleToGrid::derivedAttributes::EnergyDensity ().getUnit ()[0 ]);
90+ float_64 constexpr densityUnit = static_cast <float_64>(particleToGrid::derivedAttributes::Density ().getUnit ()[0 ]);
91+ float_64 constexpr kinEnergyDensityUnit = static_cast <float_64>(particleToGrid::derivedAttributes::EnergyDensity ().getUnit ()[0 ]);
9192 /* convert from kinetic energy density to average kinetic energy per particle */
92- float_64 kinEnergy = (kinEnergyDensity / density) * (kinEnergyDensityUnit / densityUnit);
93+ float_64 constexpr kinEnergyUnit = kinEnergyDensityUnit / densityUnit;
94+ float_64 const kinEnergy = (kinEnergyDensity / density) * kinEnergyUnit;
9395 /* * convert kinetic energy in J to "temperature" in eV by assuming an ideal electron gas
9496 * E_kin = 3/2 k*T
9597 */
96- float_64 temperature = kinEnergy * UNITCONV_Joule_to_keV * float_64 (1 .e3 ) * float_64 (2 ./3 .);
98+ float_64 constexpr convKinEnergyToTemperature = UNITCONV_Joule_to_keV * float_64 (1 .e3 ) * float_64 (2 ./3 .);
99+ float_64 const temperature = kinEnergy * convKinEnergyToTemperature;
97100
98- float_64 T_0 = temperature/math::pow (protonNumber,float_64 (4 ./3 .));
101+ float_64 const T_0 = temperature/math::pow (protonNumber,float_64 (4 ./3 .));
99102
100- float_64 T_F = T_0 / (float_64 (1 .) + T_0);
103+ float_64 const T_F = T_0 / (float_64 (1 .) + T_0);
101104
102- /* for all the fitting parameters @see TFFittingParameters.def */
105+ /* for all the fitting parameters @see ionizerConfig.param */
103106
104107 /* * this is weird - I have to define temporary variables because
105108 * otherwise the math::pow function won't recognize those at the
106109 * exponent position */
107- float_64 TFA2_temp = TFA2;
108- float_64 TFA4_temp = TFA4;
109- float_64 TFBeta_temp = TFBeta;
110+ float_64 constexpr TFA2_temp = TFA2;
111+ float_64 constexpr TFA4_temp = TFA4;
112+ float_64 constexpr TFBeta_temp = TFBeta;
110113
111- float_64 A = TFA1 * math::pow (T_0,TFA2_temp) + TFA3 * math::pow (T_0,TFA4_temp);
114+ float_64 const A = TFA1 * math::pow (T_0,TFA2_temp) + TFA3 * math::pow (T_0,TFA4_temp);
112115
113- float_64 B = -math::exp (TFB0 + TFB1*T_F + TFB2*math::pow (T_F,float_64 (7 .)));
116+ float_64 const B = -math::exp (TFB0 + TFB1*T_F + TFB2*math::pow (T_F,float_64 (7 .)));
114117
115- float_64 C = TFC1 * T_F + TFC2;
118+ float_64 const C = TFC1 * T_F + TFC2;
116119
117- /* * requires mass density in g/cm^3
118- * @TODO relocate constants to param file or leave out and calculate unitless
119- */
120- float_64 const nAvogadro = 6.022e23 ;
121- float_64 const convM3ToCM3 = 1 .e6 ;
120+ /* requires mass density in g/cm^3 */
121+ float_64 constexpr nAvogadro = SI::N_AVOGADRO;
122+ float_64 constexpr convM3ToCM3 = 1 .e6 ;
122123
123- float_64 massDensity = density * densityUnit * massNumber / nAvogadro / convM3ToCM3;
124- float_64 R = massDensity/(protonNumber * massNumber) ;
124+ float_64 constexpr convToMassDensity = densityUnit * massNumber / nAvogadro / convM3ToCM3;
125+ float_64 const massDensity = density * convToMassDensity ;
125126
126- float_64 Q_1 = A * math::pow (R,B);
127+ float_64 constexpr atomicTimesMassNumber = protonNumber * massNumber;
128+ float_64 const R = massDensity/atomicTimesMassNumber;
127129
128- float_64 Q = math::pow ( math::pow (R,C) + math::pow (Q_1,C), float_64 ( 1 .)/C );
130+ float_64 const Q_1 = A * math::pow (R,B );
129131
130- float_64 x = TFAlpha * math::pow (Q,TFBeta_temp);
132+ float_64 const Q = math::pow (math::pow (R,C) + math::pow (Q_1,C), float_64 (1 .)/C);
133+
134+ float_64 const x = TFAlpha * math::pow (Q,TFBeta_temp);
131135
132136 /* Thomas-Fermi average ionization state */
133- float_64 ZStar = protonNumber * x / (float_64 (1 .) + x + math::sqrt (float_64 (1 .) + float_64 (2 .)*x));
137+ float_64 const ZStar = protonNumber * x / (float_64 (1 .) + x + math::sqrt (float_64 (1 .) + float_64 (2 .)*x));
134138
135139 /* integral part of the charge state */
136140 float_64 intZStar;
137141 /* fractional part of the charge state */
138142 float_X fracZStar = static_cast <float_X>(math::modf (ZStar,&intZStar));
139143
140144 /* determine charge state */
141- float_X chargeState = static_cast <float_X>(intZStar) + float_X (1.0 )*(randNr < fracZStar);
145+ float_X const chargeState = static_cast <float_X>(intZStar) + float_X (1.0 )*(randNr < fracZStar);
142146
143147 /* * determine the new number of bound electrons from the TF ionization state
144148 * @TODO introduce partial macroparticle ionization / ionization distribution at some point
145149 */
146- float_X newBoundElectrons = protonNumber - chargeState;
147- /* safety check to avoid double counting since recombination is not yet implemented */
148- if (newBoundElectrons < parentIon[boundElectrons_])
149- /* update the particle attribute only if more free electrons are to be created */
150- parentIon[boundElectrons_] = newBoundElectrons;
150+ float_X const newBoundElectrons = protonNumber - chargeState;
151+
152+ return newBoundElectrons;
151153 }
152154
153155 }
0 commit comments