25 auto thermo = m_sol->thermo();
26 const std::size_t nsp = thermo->nSpecies();
28 if (m_plasma ==
nullptr)
30 throw std::invalid_argument(
31 "PlasmaReactor0D: phase \"" + cfg.
phase +
"\" in \"" + cfg.
mech +
32 "\" is a " + thermo->type() +
33 ", not a PlasmaPhase, so it carries no electron temperature.");
37 std::vector<double> wt(thermo->molecularWeights().begin(),
38 thermo->molecularWeights().end());
42 if (cfg.
specs.size() != nsp)
44 throw std::invalid_argument(
45 "PlasmaReactor0D: got collision specs for " +
46 std::to_string(cfg.
specs.size()) +
" species, but \"" + cfg.
mech +
47 "\" has " + std::to_string(nsp) +
48 " species. Give one spec per mechanism species, in its order.");
50 std::vector<CollisionModel::SpeciesSpec> specs = cfg.
specs;
51 for (std::size_t k = 0; k < nsp; k++)
53 specs[k].molar_mass = wt[k] * 1.0e-3;
54 specs[k].is_electron = (k == m_ie);
67 m_rhs = std::make_unique<PlasmaCell>(m_sol, std::move(rc));
76 std::vector<std::string> names(m_rhs->nSpecies());
77 for (std::size_t k = 0; k < names.size(); k++)
78 names[k] = m_rhs->speciesName(k);
83 double mass,
double p_ext,
double polytropic_index,
95 const double rho = mass / V;
105 const bool constant_volume = std::isinf(polytropic_index) && polytropic_index > 0.0;
106 if (!constant_volume && !(polytropic_index > 0.0))
108 throw std::invalid_argument(
109 "PlasmaReactor0D::rhs: polytropic_index must be positive, or +inf for a "
110 "constant volume; got " +
significant(polytropic_index) +
".");
112 if (!constant_volume && !(m_gap > 0.0))
114 throw std::invalid_argument(
115 "PlasmaReactor0D::rhs: a finite polytropic_index needs gap > 0, since "
116 "the rarefaction timescale comes from that length; got gap = " +
119 double dTg = 0.0, dTe = 0.0, lhsTg = 1.0, lhsTe = 1.0;
122 m_rhs->sourceTerms(Tg, Te, Y, rho, E, dTg, dTe, dydt + 3, lhsTg, lhsTe, &m_diag);
126 if (!constant_volume)
131 auto thermo = m_rhs->solution()->thermo();
151 const double cp = thermo->cp_mass();
152 const double cv = thermo->cv_mass();
159 std::ostringstream message;
160 message <<
"PlasmaReactor0D::rhs: heat capacity at constant "
162 << std::scientific << cv
163 <<
" J/kg/K at Tg=" << Tg <<
" K, Te=" << Te
165 <<
" kg/m^3. It must be positive for the polytropic "
166 "volume equation's speed of sound. Check the "
167 "composition and the temperatures at this state.";
168 throw std::runtime_error(message.str());
170 const double gamma = cp / cv;
171 const double M = thermo->meanMolecularWeight() * 1.0e-3;
181 const double radius = std::sqrt(V / (m_gap *
units::pi));
182 const double c_sound = std::sqrt(gamma *
units::R * Tmean / M);
183 const double tau = radius / c_sound;
191 const double dp_dt = -(P - p_ext) / tau;
192 dV = -1.0 / polytropic_index * (V / P) * dp_dt;
196 if (!std::isfinite(dV))
198 std::ostringstream message;
199 message <<
"PlasmaReactor0D::rhs: non-finite volume rate dV/dt = "
200 << dV <<
" m^3/s at P = " << P <<
" Pa, p_ext = " << p_ext
201 <<
" Pa, V = " << V <<
" m^3, tau = " << tau
202 <<
" s, polytropic index " << polytropic_index <<
".";
203 throw std::runtime_error(message.str());
206 dTe -= (p_e * dV / V) / lhsTe;
207 dTg -= ((P - p_e) * dV / V) / lhsTg;
The standalone 0-D two-temperature reactor: PlasmaCell plus the constant-mass volume equation,...
The two-temperature quantities every model in this extension reads back from a PlasmaPhase,...
size_t electronSpeciesIndex() const
Composition-resolved electron-heavy momentum-transfer collision model.
void rhs(double Tg, double Te, double V, const double *Y, double E, double mass, double p_ext, double polytropic_index, double *dydt) const
Full 0D RHS.
PlasmaReactor0D(const PlasmaReactor0DConfig &cfg)
Construct from a mechanism/phase and collision-model configuration.
std::vector< std::string > speciesNames() const
Species names in mechanism index order, so a caller passing plain numbers across the Python boundary ...
constexpr double R
Ideal gas constant [J/(mol K)].
constexpr double pi
pi (matches numpy's np.pi used in units.py).
std::shared_ptr< Cantera::Solution > loadMechanism(const std::string &mech, const std::string &phase)
Load a mechanism with rizer's custom rate types registered first.
std::string significant(double value)
value to 6 significant digits, for exception messages.
TwoTemperatureState readTwoTemperatureState(const Cantera::PlasmaPhase &phase)
Read the two-temperature EOS back from a phase whose state is set.
CollisionModel collision
Composition-resolved sigma/nu_E (preferred).
bool reacting
Include finite-rate chemistry source terms (true) or freeze composition (false) [-].
std::vector< double > species_h0k
Per-species standard enthalpy of formation at 0 K [J/kmol], length nSpecies(), in mechanism species-i...
double Te_max
Upper bound of the tabulated electron-temperature grid [K].
double Te_min
Lower bound of the tabulated electron-temperature grid [K].
std::string phase
Mechanism file/URI, and phase name within it.
std::vector< CollisionModel::SpeciesSpec > specs
Per-species cross-section model (cross-section data / radius / ion Z), exactly one entry per mechanis...
std::size_t Te_n
Number of points in the tabulated Te grid [-].
std::vector< double > species_h0k
Per-species standard enthalpy of formation at 0 K [J/kmol]; forwarded to PlasmaCellConfig::species_h0...
bool reacting
If false, disables chemistry source terms in the RHS.
The two-temperature equation of state at the state currently set on a phase, PHYSICS....
double mean_temperature
[K], the one pressure uses
double pressure
Total [Pa].
double electron_pressure
[Pa]
Physical constants and unit conversions, in SI by default.