rizer.cantera_ext
C++ Cantera 1-D plasma extension (custom Domain1D models and solvers)
Loading...
Searching...
No Matches
PlasmaCell.cpp
Go to the documentation of this file.
1#include "PlasmaCell.h"
3
6#include "units.h"
7
12
13#include <algorithm>
14#include <cmath>
15#include <sstream>
16#include <stdexcept>
17#include <string>
18
19namespace rizer
20{
21
22 // ------------------------------------------------------------------------------ //
23 // Constructor //
24 // ------------------------------------------------------------------------------ //
25
26 PlasmaCell::PlasmaCell(std::shared_ptr<Cantera::Solution> sol,
28 : m_sol(std::move(sol)),
29 m_nsp(m_sol->thermo()->nSpecies()),
30 m_reacting(cfg.reacting),
31 m_collision(std::move(cfg.collision)),
32 // The legacy fallback members (m_sigma, m_nu_m_tab, m_nu_m, m_nu_E) are always
33 // built from cfg here, but transport() only reads them when m_collision.empty()
34 // is true -- i.e. only one of the two closures is ever actually exercised at
35 // evaluation time.
36 m_sigma(PropertyTable::fromTableOrScalar(
37 cfg.sigma_T, cfg.sigma_v, "sigma_T/sigma_v")),
38 m_nu_m_tab(PropertyTable::fromTableOrScalar(
39 cfg.nu_m_T, cfg.nu_m_v, "nu_m_T/nu_m_v")),
40 m_nu_m(cfg.nu_m),
41 m_nu_E(cfg.nu_E)
42 {
43 m_plasma = dynamic_cast<Cantera::PlasmaPhase *>(m_sol->thermo().get());
44 if (m_plasma == nullptr)
45 {
46 throw std::invalid_argument(
47 "PlasmaCell: the phase is a " + m_sol->thermo()->type() +
48 ", not a PlasmaPhase, so it carries no electron temperature.");
49 }
50 m_ie = m_plasma->electronSpeciesIndex();
51 m_wt.assign(m_sol->thermo()->molecularWeights().begin(),
52 m_sol->thermo()->molecularWeights().end());
53 m_Yc.resize(m_nsp);
54 m_wdot.resize(m_nsp);
55 m_uk.resize(m_nsp);
56 m_cpR.resize(m_nsp);
57 m_cp_mass.resize(m_nsp);
58 m_X.resize(m_nsp);
59 m_nk.resize(m_nsp);
60 const std::size_t nR = m_sol->kinetics()->nReactions();
61 m_rop.resize(nR);
62 // Which reactions the electron takes part in and what each costs it:
63 // a property of the MECHANISM, built in kinetics/ElectronReactions.h.
64 const ElectronReactionIndex electron_reactions =
65 buildElectronReactionIndex(*m_sol->kinetics(),
66 m_sol->thermo()->speciesName(m_ie),
67 cfg.species_h0k, m_nsp, m_reacting);
68 m_is_electron_rxn = std::move(electron_reactions.is_electron_reaction);
69 m_eps_th = std::move(electron_reactions.threshold_energy);
70 }
71
72 // ------------------------------------------------------------------------------ //
73 // Public methods //
74 // ------------------------------------------------------------------------------ //
75
76 std::string PlasmaCell::speciesName(std::size_t k) const
77 {
78 return m_sol->thermo()->speciesName(k);
79 }
80
81 void PlasmaCell::sourceTerms(double Tg, double Te, const double *Y, double rho, double E,
82 double &dTg, double &dTe, double *dY, double &lhs_Tg,
83 double &lhs_Te, Diagnostics *diag) const
84 {
85 // Seven steps, in order:
86 // 1. reject a state outside the range the fits hold over
87 // 2. put the state on the phase, read the two-temperature EOS back
88 // 3. capacitances lhs_Tg, lhs_Te -- the J/m^3/K the balances divide by
89 // 4. transport closure: sigma and the collision frequencies
90 // 5. the field-driven powers, Joule and elastic exchange
91 // 6. chemistry: dY, the two chemical powers and the inelastic one
92 // 7. assemble both balances, check them, fill the diagnostics
93
94 auto thermo = m_sol->thermo();
95 auto kin = m_sol->kinetics();
96
97 // ---- 1-2. reject an invalid state, set it, read the EOS back --------
98 // setState() raises a TrialStateError for a temperature under
99 // TemperatureFloor, so CVODE rejects the trial step and retries a
100 // smaller one rather than abandoning the solve.
101 const TwoTemperatureState state = setState(Tg, Te, Y, rho);
102 const double n_e = state.electron_density;
103
104 // ---- 3. energy-equation capacitances --------------------------------
105 // Also leaves m_cpR current, which the heavy-pool capacitance below reads.
106 fillSpeciesCp();
107 const double We = m_wt[m_ie];
108 const double cve = monatomicElectronCv(We);
109
110 // Gas-side heat capacity at constant volume, @f$c_v/R = c_p/R - 1@f$ per species
111 // (ideal gas), mass-weighted over the heavy species only (electron excluded -- it
112 // has its own energy equation with capacitance lhs_Te below) and converted to a
113 // per-volume capacitance via rho: cv_heavy has units J/(kg K) before the rho
114 // multiply.
115 double cv_heavy = 0.0;
116 for (std::size_t k = 0; k < m_nsp; k++)
117 {
118 if (k == m_ie)
119 continue;
120 cv_heavy += m_Yc[k] * (m_cpR[k] - 1.0) * GasConstant / m_wt[k];
121 }
122 // Electron-energy capacitance @f$Y_e \rho c_{v,e}@f$; Y_e is floored away from
123 // zero so lhs_Te stays finite/positive even when the electron mass fraction
124 // underflows to ~0.
125 const double Ye_cap = std::max(m_Yc[m_ie], 1.0e-12);
126 lhs_Te = Ye_cap * cve * rho;
127 // Raised, never floored: the gas balance divides by it, and a stand-in
128 // returns a finite rate for a state with no heavy gas to heat. With
129 // the temperatures inside the fits every heavy cv is positive, so this
130 // fires only on a composition with no heavy species in it.
131 lhs_Tg = cv_heavy * rho;
132 if (!(lhs_Tg > 0.0))
133 {
134 throw TrialStateError(
135 "PlasmaCell::sourceTerms",
136 "the heavy-pool heat capacity is " + std::to_string(lhs_Tg) +
137 " J/m^3/K at Tg = " + std::to_string(Tg) + " K, Te = " +
138 std::to_string(Te) + " K, rho = " + std::to_string(rho) +
139 " kg/m^3; it must be positive for the gas-temperature balance.");
140 }
141
142 // ---- 4. transport closure -------------------------------------------
143 double sigma, nu_E, nu_eH, nu_eI, nu_eH_mass_weighted;
144 transport(Te, state, sigma, nu_E, nu_eH, nu_eI, nu_eH_mass_weighted);
145
146 // ---- 5. field-driven powers -----------------------------------------
147 // Elastic electron-heavy energy exchange (classic elastic-collision power
148 // transfer rate from electrons to the heavy gas, positive when Te > Tg):
149 // @f[
150 // P_\text{el} = \nu_E n_e \frac{3}{2} k_B (T_e - T_g)
151 // @f]
152 // It appears with a minus sign in the electron balance and a plus sign in the
153 // gas balance below (energy conserved between the two) [W/m^3].
154 const double P_el = nu_E * n_e * 1.5 * Boltzmann * (Te - Tg);
155 // Joule heating, @f$P_\text{joule} = \sigma E^2@f$ [W/m^3]: the resistive power
156 // deposited into the electron population by the electric field; it only enters
157 // the electron-energy balance (dTe), never the gas balance (dTg) directly.
158 const double P_joule = sigma * E * E;
159
160 // ---- 6. chemistry: dY and the chemical powers -----------------------
161 double P_chem_H = 0.0, P_chem_e = 0.0, P_inel = 0.0;
162 for (std::size_t k = 0; k < m_nsp; k++)
163 dY[k] = 0.0;
164 if (m_reacting)
165 {
166 kin->getNetProductionRates(m_wdot);
167 kin->getNetRatesOfProgress(m_rop);
168 thermo->getPartialMolarIntEnergies(m_uk);
169 for (std::size_t k = 0; k < m_nsp; k++)
170 {
171 // m_wdot[k] is the net production rate in [kmol/m^3/s] (Cantera
172 // convention); multiplying by the molecular weight [kg/kmol] and
173 // dividing by rho [kg/m^3] converts it to the mass-fraction time
174 // derivative @f$dY_k = \dot\omega_k W_k / \rho@f$ [1/s].
175 dY[k] = m_wdot[k] * m_wt[k] / rho;
176 if (k != m_ie)
177 P_chem_H += m_uk[k] * m_wdot[k];
178 }
179 P_chem_e = m_wdot[m_ie] * cve * We * Te;
180 // Fixed threshold energy per reaction (m_eps_th, precomputed once in the
181 // constructor from 0K formation enthalpies -- see plasma_power_inelastic
182 // in the Python reference).
183 for (std::size_t i = 0; i < m_rop.size(); i++)
184 {
185 if (m_is_electron_rxn[i])
186 P_inel += m_eps_th[i] * m_rop[i];
187 }
188 }
189
190 // ---- 7. assemble the two balances -----------------------------------
191 dTe = (-P_chem_e - P_el - P_inel + P_joule) / lhs_Te;
192 dTg = (-P_chem_H + P_el + P_inel) / lhs_Tg;
193
194 // Raised, never zeroed. A non-finite rate means the state this was
195 // evaluated at is not one the closures can describe -- an overflowing
196 // rate constant, or a trial composition the integrator should back away
197 // from. Substituting 0.0 hands CVODE a smooth, well-behaved derivative
198 // instead, so its error test passes and the step is ACCEPTED: the
199 // integration then continues from the corrupted state and returns a
200 // plausible wrong answer rather than failing. A TrialStateError lets
201 // CVODE reject the step and retry smaller, which is what its error
202 // control is for.
203 if (!std::isfinite(dTg) || !std::isfinite(dTe))
204 {
205 throw TrialStateError(
206 "PlasmaCell::sourceTerms",
207 "non-finite temperature rate at Tg = " +
208 std::to_string(Tg) +
209 " K, Te = " +
210 std::to_string(Te) +
211 " K, rho = " +
212 std::to_string(rho) +
213 " kg/m^3 (dTg = " +
214 std::to_string(dTg) +
215 ", dTe = " +
216 std::to_string(dTe) + ").");
217 }
218 for (std::size_t k = 0; k < m_nsp; k++)
219 {
220 if (!std::isfinite(dY[k]))
221 {
222 throw TrialStateError(
223 "PlasmaCell::sourceTerms",
224 "non-finite production rate for species " +
225 std::to_string(k) +
226 " at Tg = " +
227 std::to_string(Tg) +
228 " K, Te = " +
229 std::to_string(Te) +
230 " K, rho = " +
231 std::to_string(rho) +
232 " kg/m^3.");
233 }
234 }
235
236 // Fill the optional Diagnostics struct if the caller passed a non-null pointer.
237 if (diag != nullptr)
238 {
239 diag->P_elastic = P_el;
240 diag->P_inelastic = P_inel;
241 diag->P_chemical_H = P_chem_H;
242 diag->P_chemical_e = P_chem_e;
243 diag->P_Joule = P_joule;
244 // Collision-frequency diagnostics (Mitchner II-13.3 / II-8.11e /
245 // VIII-3.8), from the same transport() call that produced sigma/nu_E
246 // for this state.
247 diag->nu_eH = nu_eH;
249 diag->nu_eI = nu_eI;
250 diag->nu_eH_mass_weighted = nu_eH_mass_weighted;
251 }
252 }
253
254 double PlasmaCell::electricalConductivity(double Tg, double Te, const double *Y,
255 double rho) const
256 {
257 const TwoTemperatureState state = setState(Tg, Te, Y, rho);
258 double sigma, nu_E, nu_eH, nu_eI, nu_eH_mass_weighted;
259 transport(Te, state, sigma, nu_E, nu_eH, nu_eI, nu_eH_mass_weighted);
260 return sigma;
261 }
262
263 double PlasmaCell::electronDensity(double Tg, double Te, const double *Y,
264 double rho) const
265 {
266 return setState(Tg, Te, Y, rho).electron_density;
267 }
268
269 void PlasmaCell::pressureAndElectronDensity(double Tg, double Te,
270 const double *Y, double rho,
271 double &p,
272 double &electron_density) const
273 {
274 const TwoTemperatureState state = setState(Tg, Te, Y, rho);
275 p = state.pressure;
276 electron_density = state.electron_density;
277 }
278
279 void PlasmaCell::updateSpeciesCp(double Tg, double Te, const double *Y,
280 double rho) const
281 {
282 setState(Tg, Te, Y, rho);
283 fillSpeciesCp();
284 }
285
286 void PlasmaCell::speciesEnthalpies(double Tg, double Te, const double *Y,
287 double rho, double *h) const
288 {
289 setState(Tg, Te, Y, rho);
290 m_sol->thermo()->getPartialMolarEnthalpies(
291 Cantera::span<double>(h, m_nsp));
292 for (std::size_t k = 0; k < m_nsp; k++)
293 {
294 h[k] /= m_wt[k];
295 }
296 const double We = m_wt[m_ie];
297 h[m_ie] = (monatomicElectronCv(We) + GasConstant / We) * Te;
298 }
299
300 // ------------------------------------------------------------------------------ //
301 // Private methods //
302 // ------------------------------------------------------------------------------ //
303
304 void PlasmaCell::fillSpeciesCp() const
305 {
306 // Mass-basis species heat capacity c_p,k = (Cp_k/R)*R/W_k [J/kg/K],
307 // exposed via speciesCp() for PlasmaChannel1D's enthalpy-diffusion
308 // energy-equation term. The electron slot instead mirrors the analytic
309 // monatomic-ideal-gas value c_p,e = cv_e + R/W_e, for consistency with
310 // how cve/lhs_Te bypass Cantera's own electron Cp in sourceTerms().
311 m_sol->thermo()->getCp_R(m_cpR);
312 for (std::size_t k = 0; k < m_nsp; k++)
313 {
314 m_cp_mass[k] = m_cpR[k] * GasConstant / m_wt[k];
315 }
316 const double We = m_wt[m_ie];
317 m_cp_mass[m_ie] = monatomicElectronCv(We) + GasConstant / We;
318 }
319
320 TwoTemperatureState PlasmaCell::setState(double Tg, double Te, const double *Y,
321 double rho) const
322 {
323 // Rejected rather than clamped. Every rate, capacity and collision
324 // frequency is a fit that stops at TemperatureFloor, so a colder state
325 // is a diverged iterate, and clamping it would hand the caller a value
326 // for a temperature it never proposed. Tg is also held under
327 // TemperatureCeiling, above which the heavy-species thermo fits
328 // extrapolate: the C+, C++ and C+++ fits of the CH4 mechanism give
329 // cp/R < 1 from 1.52e5 K, i.e. a negative heavy-pool heat capacity.
330 // Te has no such ceiling here: the electron's own heat capacity is the
331 // analytic monatomic value, and the P4 and pulsed-reactor runs reach
332 // Te above 1e5 K. Checked here, where every public read sets its
333 // state, so no read can skip it. The negated comparisons also reject a
334 // NaN, which `Tg < TemperatureFloor` would wave through.
335 if (!(Tg >= TemperatureFloor) || !(Te >= TemperatureFloor) ||
336 !(Tg <= TemperatureCeiling))
337 {
338 std::ostringstream message;
339 message << "Tg = " << Tg << " K, Te = "
340 << Te << " K, rho = " << rho
341 << " kg/m^3; Tg must lie within [" << TemperatureFloor << ", "
342 << TemperatureCeiling << "] K and Te must be at least "
344 << " K, where the mechanism's thermo and rate fits hold.";
345 throw TrialStateError("PlasmaCell::setState", message.str());
346 }
347 auto thermo = m_sol->thermo();
348 // Negative mass fractions are clipped to zero before Cantera sees them;
349 // setMassFractions_NoNorm keeps them un-renormalized so Y still sums to
350 // (numerically) 1 as the integrator expects. Clipped rather than passed
351 // through, as Cantera's own reactors and the Python reference do, because
352 // the closures cannot take a negative density: a negative n_e has no
353 // Coulomb logarithm. Measured over the suite and the native examples: the
354 // native channel's negatives stay at round-off (1e-13 or below, trial
355 // states), held there by CVODE's tolerances, since Cantera's CVODE wrapper
356 // applies no positivity constraint; the Python split solver's scipy vode
357 // has none either and reaches -1.3e-7 (C2H6+). A NaN is
358 // a broken state rather than round-off, so it raises instead of being
359 // clipped to zero.
360 for (std::size_t k = 0; k < m_nsp; k++)
361 {
362 if (std::isnan(Y[k]))
363 {
364 throw TrialStateError(
365 "PlasmaCell::setState",
366 "the mass fraction of species " + m_sol->thermo()->speciesName(k) +
367 " is NaN at Tg = " + std::to_string(Tg) + " K, Te = " +
368 std::to_string(Te) + " K.");
369 }
370 m_Yc[k] = (Y[k] > 0.0) ? Y[k] : 0.0;
371 }
372 thermo->setMassFractions_NoNorm(Cantera::span<const double>(m_Yc.data(), m_nsp));
373 thermo->setElectronTemperature(Te);
374 thermo->setState_TD(Tg, rho);
375 // Read back rather than rebuilt: the mean temperature and the electron
376 // density follow from the state just set, and PlasmaPhase is the one
377 // that defines them (thermo/PlasmaState.h). Returned whole rather than
378 // unpacked into out-parameters, so a caller takes the one field it
379 // wants instead of declaring four locals to drop three of them.
380 return readTwoTemperatureState(*m_plasma);
381 }
382
383 void PlasmaCell::transport(double Te, const TwoTemperatureState &state,
384 double &sigma, double &nu_E, double &nu_eH,
385 double &nu_eI, double &nu_eH_mass_weighted) const
386 {
387 const double n_e = state.electron_density;
388 // Closure selection: the composition-resolved CollisionModel is preferred and used
389 // exclusively whenever it was supplied (m_collision non-empty); the legacy
390 // tabulated/scalar closure below is only reached when no CollisionModel was given.
391 // Exactly one branch executes per call -- see PlasmaCellConfig in PlasmaCell.h.
392 if (!m_collision.empty())
393 {
394 // Composition-resolved: convert Cantera's mole fractions X_k [-] to
395 // per-species number densities n_k [1/m^3] via the ideal-gas number density
396 // @f$n_\text{tot} = P/(k_B T_\text{mean})@f$, since CollisionModel::evaluate()
397 // needs absolute densities, not fractions.
398 const double n_tot = state.pressure / (Boltzmann * state.mean_temperature);
399 m_sol->thermo()->getMoleFractions(Cantera::span<double>(m_X.data(), m_nsp));
400 for (std::size_t k = 0; k < m_nsp; k++)
401 m_nk[k] = m_X[k] * n_tot;
402 m_collision.evaluate(Te, n_e, m_nk.data(), m_nsp, sigma, nu_E, nu_eH, nu_eI,
403 nu_eH_mass_weighted);
404 }
405 else
406 {
407 // Legacy closure: prefer nu_m(Te) (table or scalar) and derive sigma from the
408 // Drude relation @f$\sigma = n_e e^2 / (m_e \nu_m)@f$; if no nu_m is available
409 // at all (nu_m_eff <= 0), fall back further to a directly tabulated sigma(Te).
410 // nu_E is always the fixed scalar in this legacy path (no Te-dependent table
411 // for nu_E). nu_eH/nu_eI/nu_eH_mass_weighted need per-species composition,
412 // unavailable here.
413 const double nu_m_eff =
414 m_nu_m_tab.empty()
415 ? m_nu_m
416 : evalAtState(m_nu_m_tab, Te, "PlasmaCell::transport", "nu_m(Te)", "K",
417 "Extend the nu_m_T/nu_m_v table.");
418 if (nu_m_eff > 0.0)
419 {
420 sigma = n_e * units::e * units::e / (units::m_e * nu_m_eff);
421 }
422 else
423 {
424 sigma = m_sigma.empty()
425 ? 0.0
426 : evalAtState(m_sigma, Te, "PlasmaCell::transport",
427 "sigma(Te)", "K",
428 "Extend the sigma_T/sigma_v table.");
429 }
430 nu_E = m_nu_E;
431 nu_eH = 0.0;
432 nu_eI = 0.0;
433 nu_eH_mass_weighted = 0.0;
434 }
435 }
436
437} // namespace rizer
Which reactions of a mechanism the electron takes part in, and what each of them costs the electron p...
One cell of two-temperature reacting plasma: the source terms the 0-D reactor and the 1-D channel bot...
The two-temperature quantities every model in this extension reads back from a PlasmaPhase,...
Evaluate a PropertyTable at a state, refusing a state outside its range.
size_t electronSpeciesIndex() const
static double electronElectronCollisionFrequency(double n_e, double Te)
Electron-electron collision frequency [1/s] (Mitchner II-8.11e with Z=1), the closed-form ingredient...
double electronDensity(double Tg, double Te, const double *Y, double rho) const
Electron number density [1/m^3], .
void updateSpeciesCp(double Tg, double Te, const double *Y, double rho) const
Refresh speciesCp() at one state without evaluating anything else.
void pressureAndElectronDensity(double Tg, double Te, const double *Y, double rho, double &p, double &electron_density) const
Total pressure [Pa] and electron number density [1/m^3] together, from the two-temperature equation o...
void sourceTerms(double Tg, double Te, const double *Y, double rho, double E, double &dTg, double &dTe, double *dY, double &lhs_Tg, double &lhs_Te, Diagnostics *diag=nullptr) const
Single-cell RHS (no transport, no volume work).
PlasmaCell(std::shared_ptr< Cantera::Solution > sol, PlasmaCellConfig cfg)
Construct a PlasmaCell for a given plasma Solution and configuration.
void speciesEnthalpies(double Tg, double Te, const double *Y, double rho, double *h) const
Mass-basis species enthalpy h_k [J/kg], the energy one kilogram of species k carries in when the spec...
std::size_t nSpecies() const
Definition PlasmaCell.h:127
double electricalConductivity(double Tg, double Te, const double *Y, double rho) const
Electrical conductivity [S/m] at a node state.
std::string speciesName(std::size_t k) const
Name of species k in the mechanism.
TrialStateError(const std::string &procedure, std::string message)
const double GasConstant
constexpr double e
Elementary charge [C]. Exact (CODATA).
Definition units.h:26
constexpr double m_e
Electron mass [kg] (CODATA 2022).
Definition units.h:36
constexpr double Boltzmann
Definition PlasmaState.h:49
constexpr double TemperatureFloor
Lower limit of the mechanism's NASA polynomials [K].
Definition PlasmaState.h:34
double monatomicElectronCv(double electron_molecular_weight)
Electron specific heat at constant volume, per kg of ELECTRONS, .
Definition PlasmaState.h:64
constexpr double GasConstant
Universal gas constant [J/kmol/K] and Boltzmann's constant [J/K], from units.h rather than Cantera's ...
Definition PlasmaState.h:48
ElectronReactionIndex buildElectronReactionIndex(Cantera::Kinetics &kinetics, const std::string &electron, const std::vector< double > &species_h0k, std::size_t n_species, bool reacting)
Build the index for one mechanism.
constexpr double TemperatureCeiling
Upper limit of the physically meaningful range [K].
Definition PlasmaState.h:43
double evalAtState(const PropertyTable &table, double x, const char *procedure, const char *what, const char *unit, const char *remedy)
Value of table at x, refused outside its tabulated range.
Definition TableLookup.h:50
TwoTemperatureState readTwoTemperatureState(const Cantera::PlasmaPhase &phase)
Read the two-temperature EOS back from a phase whose state is set.
Definition PlasmaState.h:84
The per-reaction data the electron pool's inelastic power needs.
std::vector< double > species_h0k
Per-species standard enthalpy of formation at 0 K [J/kmol], length nSpecies(), in mechanism species-i...
Definition PlasmaCell.h:83
Optional power / Maxwellian-condition breakdown filled by rates() when a non-null pointer is passed.
Definition PlasmaCell.h:98
double nu_eH
Electron-electron collision frequency [1/s] (Mitchner II-8.11e).
Definition PlasmaCell.h:110
double P_elastic
< Elastic electron-heavy exchange power [W/m^3]
Definition PlasmaCell.h:100
double P_chemical_e
Joule heating power [W/m^3].
Definition PlasmaCell.h:106
double nu_ee
Electron-ion momentum-transfer collision frequency [1/s].
Definition PlasmaCell.h:112
double P_Joule
Electron-heavy momentum-transfer collision frequency [1/s] (Mitchner II-13.3).
Definition PlasmaCell.h:108
double P_inelastic
Heavy-species chemical power [W/m^3].
Definition PlasmaCell.h:102
double nu_eI
sum_h nu_eh/m_h [1/kg/s] (Mitchner VIII-3.8, term 2)
Definition PlasmaCell.h:114
double P_chemical_H
Electron chemical power [W/m^3].
Definition PlasmaCell.h:104
The two-temperature equation of state at the state currently set on a phase, PHYSICS....
Definition PlasmaState.h:72
double pressure
Total [Pa].
Definition PlasmaState.h:73
double electron_density
[1/m^3]
Definition PlasmaState.h:78
Physical constants and unit conversions, in SI by default.