Cantera
Loading...
Searching...
No Matches
PlasmaPhase.cpp
Go to the documentation of this file.
1//! @file PlasmaPhase.cpp
2
3// This file is part of Cantera. See License.txt in the top-level directory or
4// at https://cantera.org/license.txt for license and copyright information.
5
8#include <boost/math/special_functions/gamma.hpp>
10#include "cantera/base/global.h"
11#include "cantera/numerics/eigen_dense.h"
15#include <boost/polymorphic_pointer_cast.hpp>
17
18namespace Cantera {
19
20namespace {
21 const double gamma = sqrt(2 * ElectronCharge / ElectronMass);
22}
23
24PlasmaPhase::PlasmaPhase(const string& inputFile, const string& id_)
25{
26 // Initialize the Boltzmann solver and default energy grid before reading
27 // input so that isotropic/discretized EEDF setters have a valid grid.
28 m_eedfSolver = make_unique<EEDFTwoTermApproximation>(this);
29
30 double kTe_max = 60;
31 size_t nGridCells = 301;
32 m_nPoints = nGridCells + 1;
33 m_eedfSolver->setLinearGrid(kTe_max, nGridCells);
36
37 // initial electron temperature; may be updated by input file data
39
40 initThermoFile(inputFile, id_);
41}
42
43PlasmaPhase::~PlasmaPhase()
44{
45 if (shared_ptr<Solution> soln = m_soln.lock()) {
46 soln->removeChangedCallback(this);
47 soln->kinetics()->removeReactionAddedCallback(this);
48 }
49 for (size_t k = 0; k < nCollisions(); k++) {
50 // remove callback
51 m_collisions[k]->removeSetRateCallback(this);
52 }
53}
54
56{
58
59 // Check if there is an electron species in the phase.
61 throw CanteraError("PlasmaPhase::initThermo",
62 "No electron species found.");
63 }
65}
66
68{
69 // Update the heavy species thermodynamic properties
70 // before updating the electron species properties.
72 static const int cacheId = m_cache.getId();
73 CachedScalar cached = m_cache.getScalar(cacheId);
74 double tempNow = temperature();
75 double electronTempNow = electronTemperature();
76 size_t k = m_electronSpeciesIndex;
77 // If the electron temperature has changed since the last time these
78 // properties were computed, recompute them.
79 if (cached.state1 != tempNow || cached.state2 != electronTempNow) {
80 // Evaluate the electron species thermodynamic properties
81 // at the electron temperature.
82 m_spthermo.update_single(k, electronTemperature(),
83 m_cp0_R[k], m_h0_RT[k], m_s0_R[k]);
84 cached.state1 = tempNow;
85 cached.state2 = electronTempNow;
86
87 // Update the electron Gibbs functions, with the electron temperature.
88 m_g0_RT[k] = m_h0_RT[k] - m_s0_R[k];
89 }
90}
91
92// ================================================================= //
93// Overridden from IdealGasPhase or ThermoPhase //
94// ================================================================= //
95
96bool PlasmaPhase::addSpecies(shared_ptr<Species> spec)
97{
98 bool added = IdealGasPhase::addSpecies(spec);
99 size_t k = m_kk - 1;
100
101 if ((spec->name == "e" || spec->name == "Electron") ||
102 (spec->composition.find("E") != spec->composition.end() &&
103 spec->composition.size() == 1 &&
104 spec->composition["E"] == 1)) {
107 } else {
108 throw CanteraError("PlasmaPhase::addSpecies",
109 "Cannot add species, {}. "
110 "Only one electron species is allowed.", spec->name);
111 }
112 }
113
114 // Modifying the species in the phase may also means that the vibrational
115 // reservoir species have been modified.
116 // Set the flag to true to run a check.
117 if (added) {
119 }
120
121 return added;
122}
123
124void PlasmaPhase::setSolution(std::weak_ptr<Solution> soln) {
126 // Register callback function to be executed
127 // when the thermo or kinetics object changed.
128 if (shared_ptr<Solution> soln = m_soln.lock()) {
129 soln->registerChangedCallback(this, [&]() {
131 });
132 }
133}
134
135void PlasmaPhase::getParameters(AnyMap& phaseNode) const
136{
139 phaseNode["vibrational-reservoir-species-mapping"] =
141 }
142 AnyMap eedf;
143 eedf["type"] = m_distributionType;
144 vector<double> levels(m_nPoints);
145 Eigen::Map<Eigen::ArrayXd>(levels.data(), m_nPoints) = m_electronEnergyLevels;
146 eedf["energy-levels"] = levels;
147 if (m_distributionType == "isotropic") {
148 eedf["shape-factor"] = m_isotropicShapeFactor;
149 eedf["mean-electron-energy"].setQuantity(meanElectronEnergy(), "eV");
150 } else if (m_distributionType == "discretized") {
151 vector<double> dist(m_nPoints);
152 Eigen::Map<Eigen::ArrayXd>(dist.data(), m_nPoints) = m_electronEnergyDist;
153 eedf["distribution"] = dist;
154 eedf["normalize"] = m_do_normalizeElectronEnergyDist;
155 }
156 phaseNode["electron-energy-distribution"] = std::move(eedf);
157}
158
160{
161 const string routineName = "PlasmaPhase::setElectronEnergyDistributionParameters";
162 if (!eedf.hasKey("type")) {
163 throw InputFileError(routineName, eedf,
164 "The electron energy distribution mapping requires the key 'type'.");
165 }
166
167 m_distributionType = eedf["type"].asString();
168 if (m_distributionType == "isotropic") {
169 if (eedf.hasKey("shape-factor")) {
170 setIsotropicShapeFactor(eedf["shape-factor"].asDouble());
171 } else {
172 throw InputFileError(routineName, eedf,
173 "isotropic type requires shape-factor key.");
174 }
175 if (eedf.hasKey("mean-electron-energy")) {
176 double energy = eedf.convert("mean-electron-energy", "eV");
177 setMeanElectronEnergy(energy);
178 } else {
179 throw InputFileError(routineName, eedf,
180 "isotropic type requires mean-electron-energy key.");
181 }
182 if (eedf.hasKey("energy-levels")) {
183 auto levels = eedf["energy-levels"].asVector<double>();
185 }
187 } else if (m_distributionType == "discretized") {
188 if (!eedf.hasKey("energy-levels")) {
189 throw InputFileError(routineName, eedf,
190 "Cannot find key energy-levels.");
191 }
192 if (!eedf.hasKey("distribution")) {
193 throw InputFileError(routineName, eedf,
194 "Cannot find key distribution.");
195 }
196 if (eedf.hasKey("normalize")) {
197 enableNormalizeElectronEnergyDist(eedf["normalize"].asBool());
198 }
199 auto levels = eedf["energy-levels"].asVector<double>();
200 auto distribution = eedf["distribution"].asVector<double>(levels.size());
201 setDiscretizedElectronEnergyDist(levels, distribution);
202 } else if (m_distributionType == "Boltzmann-two-term") {
203 if (eedf.hasKey("energy-levels")) {
204 auto levels = eedf["energy-levels"].asVector<double>();
205 m_eedfSolver->setCustomGrid(levels);
206 m_eedfSolver->enableGridAdaptation(false);
207 m_nPoints = levels.size();
208 } else {
209 if (!eedf.hasKey("initial-max-energy-level")) {
210 throw InputFileError(routineName, eedf,
211 "Boltzmann-two-term requires either "
212 "'energy-levels' or 'initial-max-energy-level'.");
213 }
214
215 if (!eedf.hasKey("grid-cell-count")) {
216 throw InputFileError(routineName, eedf,
217 "Boltzmann-two-term requires either 'energy-levels' "
218 "or 'grid-cell-count'.");
219 }
220
221 double initialMaxEnergy = eedf["initial-max-energy-level"].asDouble();
222 size_t nGridCells = static_cast<size_t>(eedf["grid-cell-count"].asInt());
223
224 if (!std::isfinite(initialMaxEnergy) || initialMaxEnergy <= 0.0) {
225 throw InputFileError(routineName, eedf,
226 "initial-max-energy-level must be finite and greater than zero.");
227 }
228
229 if (nGridCells == 0) {
230 throw InputFileError(routineName, eedf,
231 "grid-cell-count must be greater than zero.");
232 }
233
234 string energyLevelsDistribution =
235 eedf.getString("energy-level-spacing", "linear");
236
237 m_eedfSolver->setInitialGridParameters(
238 initialMaxEnergy, nGridCells, energyLevelsDistribution);
239
240 if (energyLevelsDistribution == "linear") {
241 m_eedfSolver->setLinearGrid(initialMaxEnergy, nGridCells);
242 } else if (energyLevelsDistribution == "quadratic") {
243 m_eedfSolver->setQuadraticGrid(initialMaxEnergy, nGridCells);
244 } else if (energyLevelsDistribution == "geometric") {
245 if (eedf.hasKey("geometric-grid-ratio")) {
246 double ratio = eedf["geometric-grid-ratio"].asDouble();
247 if (!std::isfinite(ratio) || ratio <= 1.0) {
248 throw InputFileError(routineName, eedf,
249 "geometric-grid-ratio must be finite and greater than 1.0.");
250 }
251 m_eedfSolver->setGeometricGrid(initialMaxEnergy, nGridCells, ratio);
252 } else {
253 m_eedfSolver->setGeometricGrid(initialMaxEnergy, nGridCells);
254 }
255 } else {
256 throw InputFileError(routineName, eedf,
257 "energy-level-spacing should be linear, quadratic or geometric.");
258 }
259
260 if (eedf.hasKey("energy-grid-adaptation")) {
261 const AnyMap adapt = eedf["energy-grid-adaptation"].as<AnyMap>();
262 bool enabled = adapt.getBool("enabled", true);
263 bool maxwellianReset = adapt.getBool("Maxwellian-reset", true);
264 double minDecayDecades = adapt.getDouble("min-decay-decades", 10.0);
265 double maxDecayDecades = adapt.getDouble("max-decay-decades", 12.0);
266 double updateFactor = adapt.getDouble("update-factor", 0.1);
267 size_t maxIterations = adapt.getInt("max-iterations", 1000);
268 m_eedfSolver->enableGridAdaptation(enabled);
269 m_eedfSolver->setGridAdaptationParameters(
270 minDecayDecades, maxDecayDecades, updateFactor, maxIterations,
271 maxwellianReset);
272 } else {
273 m_eedfSolver->enableGridAdaptation(false);
274 }
275
276 m_nPoints = nGridCells + 1;
277 }
278
279 if (eedf.hasKey("reduced-field-threshold-before-Maxwellian")) {
280 double maxwellianThreshold =
281 eedf.convert("reduced-field-threshold-before-Maxwellian", "Td");
282 if (!std::isfinite(maxwellianThreshold) || maxwellianThreshold < 0.0) {
283 throw InputFileError(routineName, eedf,
284 "reduced-field-threshold-before-Maxwellian must be finite "
285 "and non-negative.");
286 }
287 // The input to this function is expected to be in Townsend.
288 m_eedfSolver->setReducedElectricFieldThresholdForMaxwellian(
289 maxwellianThreshold);
290 }
291
292 auto levels = m_eedfSolver->getGridEdge();
293 m_nPoints = levels.size();
295 m_electronEnergyDist.setZero(static_cast<Eigen::Index>(m_nPoints));
296
299 } else {
300 throw InputFileError(routineName, eedf,
301 "Unknown electron energy distribution type '{}'. Supported types are "
302 "'isotropic', 'discretized', and 'Boltzmann-two-term'.",
304 }
305}
306
307void PlasmaPhase::setParameters(const AnyMap& phaseNode, const AnyMap& rootNode)
308{
309 IdealGasPhase::setParameters(phaseNode, rootNode);
310 if (phaseNode.hasKey("electron-energy-distribution")) {
311 const AnyMap eedf = phaseNode["electron-energy-distribution"].as<AnyMap>();
313 }
314
316 if (phaseNode.hasKey("vibrational-reservoir-species-mapping")) {
318 phaseNode["vibrational-reservoir-species-mapping"].asMap<string>();
319 }
320
321 if (rootNode.hasKey("electron-collisions")) {
322 for (const auto& item : rootNode["electron-collisions"].asVector<AnyMap>()) {
323 auto rate = make_shared<ElectronCollisionPlasmaRate>(item);
324 Composition reactants, products;
325 reactants[item["target"].asString()] = 1;
326 reactants[electronSpeciesName()] = 1;
327 if (item.hasKey("product")) {
328 products[item["product"].asString()] = 1;
329 } else {
330 products[item["target"].asString()] = 1;
331 }
332 products[electronSpeciesName()] = 1;
333 if (rate->kind() == "ionization") {
334 products[electronSpeciesName()] += 1;
335 } else if (rate->kind() == "attachment") {
336 products[electronSpeciesName()] -= 1;
337 }
338 auto R = make_shared<Reaction>(reactants, products, rate);
339 addCollision(R);
340 }
341 }
342}
343
344// ================================================================= //
345// Electron Energy Distribution Functions //
346// ================================================================= //
347
349{
350 if (m_distributionType == "discretized") {
351 throw CanteraError("PlasmaPhase::updateElectronEnergyDistribution",
352 "Invalid for discretized electron energy distribution.");
353 } else if (m_distributionType == "isotropic") {
355 } else if (m_distributionType == "Boltzmann-two-term") {
356 auto ierr = m_eedfSolver->calculateDistributionFunction();
357 if (ierr == 0) {
362 } else {
363 throw CanteraError("PlasmaPhase::updateElectronEnergyDistribution",
364 "Call to calculateDistributionFunction failed.");
365 }
366 } else {
367 throw CanteraError("PlasmaPhase::updateElectronEnergyDistribution",
368 "Unknown method '{}' for determining EEDF", m_distributionType);
369 }
372}
373
375 Eigen::ArrayXd eps32 = m_electronEnergyLevels.pow(3./2.);
376 double norm = 2./3. * numericalQuadrature(m_quadratureMethod,
377 m_electronEnergyDist, eps32);
378 if (norm < 0.0) {
379 throw CanteraError("PlasmaPhase::normalizeElectronEnergyDistribution",
380 "The norm is negative. This might be caused by bad "
381 "electron energy distribution");
382 }
383 m_electronEnergyDist /= norm;
384}
385
387{
388 if (type == "discretized" ||
389 type == "isotropic" ||
390 type == "Boltzmann-two-term") {
392 } else {
393 throw CanteraError("PlasmaPhase::setElectronEnergyDistributionType",
394 "Unknown type for electron energy distribution.");
395 }
396}
397
399{
401 double x = m_isotropicShapeFactor;
402 double gamma1 = boost::math::tgamma(3.0 / 2.0 / x);
403 double gamma2 = boost::math::tgamma(5.0 / 2.0 / x);
404 double c1 = x * std::pow(gamma2, 1.5) / std::pow(gamma1, 2.5);
405 double c2 = std::pow(gamma2 / gamma1, x);
407 c1 / std::pow(meanElectronEnergy(), 1.5) *
408 (-c2 * (m_electronEnergyLevels /
409 meanElectronEnergy()).pow(x)).exp();
411}
412
414 if (Te < 0.0) {
415 throw CanteraError("PlasmaPhase::setElectronTemperature",
416 "Electron temperature cannot be negative.");
417 }
418 m_electronTemp = Te;
420}
421
423{
425
426 if (!m_inEquilibrate) {
427 m_inEquilibrate = true;
428 // Remember current Te and lock Te -> T for the duration
431 }
432}
433
435{
436 if (m_inEquilibrate) {
437 // Restore Te to the pre-equilibrate value
439 m_inEquilibrate = false;
440 }
441
443}
444
446 setElectronTemperature(2.0 / 3.0 * energy * ElectronCharge / Boltzmann);
447}
448
449void PlasmaPhase::setElectronEnergyLevels(span<const double> levels)
450{
451 m_nPoints = levels.size();
452 m_electronEnergyLevels = Eigen::Map<const Eigen::ArrayXd>(levels.data(), m_nPoints);
456}
457
462
464{
465 m_levelNum++;
466 // Cross sections are interpolated on the energy levels
467 if (m_collisions.size() > 0) {
468 for (shared_ptr<Reaction> collision : m_collisions) {
469 const auto& rate = boost::polymorphic_pointer_downcast
471 rate->updateInterpolatedCrossSection(asSpan(m_electronEnergyLevels));
472 }
473 }
474}
475
477{
478 Eigen::ArrayXd h = m_electronEnergyLevels.tail(m_nPoints - 1) -
480 if (m_electronEnergyLevels[0] < 0.0 || (h <= 0.0).any()) {
481 throw CanteraError("PlasmaPhase::checkElectronEnergyLevels",
482 "Values of electron energy levels need to be positive and "
483 "monotonically increasing.");
484 }
485}
486
488{
489 Eigen::ArrayXd h = m_electronEnergyLevels.tail(m_nPoints - 1) -
491 if ((m_electronEnergyDist < 0.0).any()) {
492 throw CanteraError("PlasmaPhase::checkElectronEnergyDistribution",
493 "Values of electron energy distribution cannot be negative.");
494 }
495 if (m_electronEnergyDist[m_nPoints - 1] > 0.01) {
496 warn_user("PlasmaPhase::checkElectronEnergyDistribution",
497 "The value of the last element of electron energy distribution exceed 0.01. "
498 "This indicates that the value of electron energy level is not high enough "
499 "to contain the isotropic distribution at mean electron energy of "
500 "{} eV", meanElectronEnergy());
501 }
502}
503
521
523{
524 // calculate mean electron energy and electron temperature
525 Eigen::ArrayXd eps52 = m_electronEnergyLevels.pow(5./2.);
526 double epsilon_m = 2.0 / 5.0 * numericalQuadrature(m_quadratureMethod,
527 m_electronEnergyDist, eps52);
528 if (epsilon_m < 0.0 && m_quadratureMethod == "simpson") {
529 // try trapezoidal method
530 epsilon_m = 2.0 / 5.0 * numericalQuadrature(
531 "trapezoidal", m_electronEnergyDist, eps52);
532 }
533
534 if (epsilon_m < 0.0) {
535 throw CanteraError("PlasmaPhase::updateElectronTemperatureFromEnergyDist",
536 "The electron energy distribution produces negative electron temperature.");
537 }
538
539 m_electronTemp = 2.0 / 3.0 * epsilon_m * ElectronCharge / Boltzmann;
540}
541
543 m_isotropicShapeFactor = x;
545}
546
548{
549 if (shared_ptr<Solution> soln = m_soln.lock()) {
550 shared_ptr<Kinetics> kin = soln->kinetics();
551 if (!kin) {
552 return;
553 }
554
555 // add collision from the initial list of reactions. Only add reactions we
556 // haven't seen before
557 set<Reaction*> existing;
558 for (auto& R : m_collisions) {
559 existing.insert(R.get());
560 }
561 for (size_t i = 0; i < kin->nReactions(); i++) {
562 shared_ptr<Reaction> R = kin->reaction(i);
563 if (R->rate()->type() != "electron-collision-plasma"
564 || existing.count(R.get())) {
565 continue;
566 }
567 addCollision(R);
568 }
569
570 // Register callback when reaction is added later.
571 // Modifying collision reactions is not supported.
572 kin->registerReactionAddedCallback(this, [this, kin]() {
573 size_t i = kin->nReactions() - 1;
574 if (kin->reaction(i)->type() == "electron-collision-plasma") {
575 addCollision(kin->reaction(i));
576 }
577 });
578 }
579}
580
581void PlasmaPhase::addCollision(shared_ptr<Reaction> collision)
582{
583 size_t i = nCollisions();
584
585 // setup callback to signal updating the cross-section-related
586 // parameters
587 collision->registerSetRateCallback(this, [this, i, collision]() {
588 m_interp_cs_ready[i] = false;
590 std::dynamic_pointer_cast<ElectronCollisionPlasmaRate>(collision->rate());
591 });
592
593 // Identify target species for electron-collision reactions
594 string target;
595 for (const auto& [name, _] : collision->reactants) {
596 // Reactants are expected to be electrons and the target species
597 if (name != electronSpeciesName()) {
598 m_targetSpeciesIndices.emplace_back(speciesIndex(name, true));
599 target = name;
600 break;
601 }
602 }
603 if (target.empty()) {
604 throw CanteraError("PlasmaPhase::addCollision", "Error identifying target for"
605 " collision with equation '{}'", collision->equation());
606 }
607
608 m_collisions.emplace_back(collision);
609 m_collisionRates.emplace_back(
610 std::dynamic_pointer_cast<ElectronCollisionPlasmaRate>(collision->rate()));
611 m_interp_cs_ready.emplace_back(false);
612
613 // resize parameters
616
617 // Set up data used by Boltzmann solver
618 auto& rate = *m_collisionRates.back();
619 string kind = m_collisionRates.back()->kind();
620
621 if ((kind == "effective" || kind == "elastic")) {
622 for (size_t k = 0; k < m_collisions.size() - 1; k++) {
623 if (m_collisions[k]->reactants == collision->reactants &&
624 (m_collisionRates[k]->kind() == "elastic" ||
625 m_collisionRates[k]->kind() == "effective") && !collision->duplicate)
626 {
627 throw CanteraError("PlasmaPhase::addCollision", "Phase already contains"
628 " an effective/elastic cross section for '{}'.", target);
629 }
630 }
631 m_kElastic.push_back(i);
632 } else {
633 m_kInelastic.push_back(i);
634 }
635
636 auto levels = rate.energyLevels();
637 m_energyLevels.emplace_back(levels.begin(), levels.end());
638 auto sections = rate.crossSections();
639 m_crossSections.emplace_back(sections.begin(), sections.end());
640 m_eedfSolver->setGridCache();
641}
642
644{
645 if (m_interp_cs_ready[i]) {
646 return false;
647 }
648 vector<double> levels(m_nPoints);
649 Eigen::Map<Eigen::ArrayXd>(levels.data(), m_nPoints) = m_electronEnergyLevels;
650 m_collisionRates[i]->updateInterpolatedCrossSection(levels);
651 m_interp_cs_ready[i] = true;
652 return true;
653}
654
656{
658 // Forward difference for the first point
662
663 // Central difference for the middle points
664 for (size_t i = 1; i < m_nPoints - 1; i++) {
668 (h1 * h1 - h0 * h0) * m_electronEnergyDist[i] -
669 h1 * h1 * m_electronEnergyDist[i-1]) /
670 (h1 * h0) / (h1 + h0);
671 }
672
673 // Backward difference for the last point
679}
680
682{
683 // cache of cross section plus distribution plus energy-level number
684 static const int cacheId = m_cache.getId();
685 CachedScalar last_stateNum = m_cache.getScalar(cacheId);
686
687 // combine the distribution and energy level number
688 int stateNum = m_distNum + m_levelNum;
689
690 vector<bool> interpChanged(m_collisions.size());
691 for (size_t i = 0; i < m_collisions.size(); i++) {
692 interpChanged[i] = updateInterpolatedCrossSection(i);
693 }
694
695 if (last_stateNum.validate(temperature(), stateNum)) {
696 // check each cross section, and only update coefficients that
697 // the interpolated cross sections change
698 for (size_t i = 0; i < m_collisions.size(); i++) {
699 if (interpChanged[i]) {
701 }
702 }
703 } else {
704 // update every coefficient if distribution, temperature,
705 // or energy levels change.
706 for (size_t i = 0; i < m_collisions.size(); i++) {
708 }
709 }
710}
711
713{
714 // @todo exclude attachment collisions
715 size_t k = m_targetSpeciesIndices[i];
716
717 // Map cross sections to Eigen::ArrayXd
718 auto cs_array = Eigen::Map<const Eigen::ArrayXd>(
719 m_collisionRates[i]->crossSectionInterpolated().data(),
720 m_collisionRates[i]->crossSectionInterpolated().size()
721 );
722
723 // Mass ratio calculation
724 double mass_ratio = ElectronMass / molecularWeight(k) * Avogadro;
725
726 // Calculate the rate using Simpson's rule or trapezoidal rule
727 Eigen::ArrayXd f0_plus = m_electronEnergyDist + Boltzmann * temperature() /
729 m_elasticElectronEnergyLossCoefficients[i] = 2.0 * mass_ratio * gamma *
731 m_quadratureMethod, 1.0 / 3.0 * f0_plus.cwiseProduct(cs_array),
732 m_electronEnergyLevels.pow(3.0));
733}
734
736{
737 if (m_electronEnergyDist.size() != m_nPoints
738 || m_electronEnergyDistDiff.size() != m_nPoints) {
739 throw CanteraError("PlasmaPhase::elasticPowerLoss:",
740 "EEDF not initialized");
741 }
742
744 // The elastic power loss includes the contributions from inelastic
745 // collisions (inelastic recoil effects).
746 double rate = 0.0;
747 for (size_t i = 0; i < nCollisions(); i++) {
750 }
751 const double q_elastic = Avogadro * Avogadro * ElectronCharge *
753
754 if (!std::isfinite(q_elastic)) {
755 throw CanteraError("PlasmaPhase::elasticPowerLoss:",
756 "Non-finite elastic power loss");
757 }
758
759 return q_elastic;
760}
761
763{
764 // Only implemented when using the Boltzmann two-term EEDF
765 if (m_distributionType == "Boltzmann-two-term") {
766 return m_eedfSolver->getElectronMobility();
767 } else {
768 throw NotImplementedError("PlasmaPhase::electronMobility",
769 "Electron mobility is only available for 'Boltzmann-two-term' "
770 "electron energy distributions.");
771 }
772}
773
774// ================================================================= //
775// Molar Thermodynamic Properties of the Solution //
776// ================================================================= //
777
779{
780 m_work.resize(m_kk);
782 double h = 0.0;
783 for (size_t k = 0; k < m_kk; ++k) {
784 h += moleFraction(k) * m_work[k];
785 }
786 return h;
787}
788
790{
791 m_work.resize(m_kk);
793 double u = 0.0;
794 for (size_t k = 0; k < m_kk; ++k) {
795 u += moleFraction(k) * m_work[k];
796 }
797 return u;
798}
799
801{
802 m_work.resize(m_kk);
804 double s = 0.0;
805 for (size_t k = 0; k < m_kk; ++k) {
806 s += moleFraction(k) * m_work[k];
807 }
808 return s;
809}
810
812{
813 m_work.resize(m_kk);
815 double g = 0.0;
816 for (size_t k = 0; k < m_kk; ++k) {
817 g += moleFraction(k) * m_work[k];
818 }
819 return g;
820}
821
822// ================================================================= //
823// Mechanical Equation of State //
824// ================================================================= //
825
827{
828 double T_g = temperature();
829 double T_e = electronTemperature();
831 return T_g + X_e * (T_e - T_g);
832}
833
837
838
839// ================================================================= //
840// Chemical Potentials and Activities //
841// ================================================================= //
842
844{
845 return pressure() / (GasConstant * temperature());
846}
847
848void PlasmaPhase::getActivities(span<double> a) const
849{
850 double tmp = temperature() / meanTemperature();
851 for (size_t k = 0; k < nSpecies(); k++) {
852 a[k] = tmp * moleFraction(k);
853 }
854}
855
856void PlasmaPhase::getActivityCoefficients(span<double> ac) const
857{
858 checkArraySize("PlasmaPhase::getActivityCoefficients", ac.size(), m_kk);
859 double tmp = temperature() / meanTemperature();
860 for (size_t k = 0; k < m_kk; k++) {
861 ac[k] = tmp;
862 }
863}
864
865
866// ================================================================= //
867// Partial Molar Properties of the Solution //
868// ================================================================= //
869
870void PlasmaPhase::getChemPotentials(span<double> mu) const
871{
873 size_t k = m_electronSpeciesIndex;
874 double xx = std::max(SmallNumber, moleFraction(k));
875 mu[k] += (RTe() - RT()) * log(xx);
876}
877
878void PlasmaPhase::getPartialMolarEnthalpies(span<double> hbar) const
879{
880 // Since the `updateThermo` is overriden in `PlasmaPhase`,
881 // `enthalpy_RT_ref` returns \tilde{h}_k(T_k) / (R * T_k).
882 // When calling `IdealGasPhase::getPartialMolarEnthalpies(hbar)`,
883 // the `hbar` array is equal to \tilde{h}_k(T_k) * (R * T) / (R * T_k).
884 // For all heavy species, T_k == T, so we get \tilde{h}_k(T).
885 // For electrons, we need to multiply by T_e/T to get \tilde{h}_k(T_e).
888}
889
890void PlasmaPhase::getPartialMolarEntropies(span<double> sbar) const
891{
892 // Since the `updateThermo` is overriden in `PlasmaPhase`,
893 // `entropy_R_ref` returns s^\text{ref}_k(T_k)/R.
894 // When calling `IdealGasPhase::getPartialMolarEntropies(hbar)`,
895 // the `sbar` array is equal to s^\text{ref}_k(T_k)*R/R - R ln(X_k P/P^ref).
896 // Therefore, there is no need to correct for temperature.
898}
899
900void PlasmaPhase::getPartialMolarIntEnergies(span<double> ubar) const
901{
902 checkArraySize("PlasmaPhase::getPartialMolarIntEnergies", ubar.size(), m_kk);
903 auto _h = enthalpy_RT_ref();
904 for (size_t k = 0; k < m_kk; k++) {
905 ubar[k] = RT() * (_h[k] - 1.0);
906 }
907 // Redefine it for the electron species.
908 size_t k = m_electronSpeciesIndex;
909 ubar[k] = RTe() * (_h[k] - 1.0);
910}
911
912void PlasmaPhase::getPartialMolarVolumes(span<double> vbar) const
913{
914 double vol = RT() / pressure();
915 for (size_t k = 0; k < m_kk; k++) {
916 vbar[k] = vol;
917 }
918 vbar[m_electronSpeciesIndex] = RTe() / pressure();
919}
920
921// ================================================================= //
922// Properties of the Standard State of the Species in the Solution //
923// ================================================================= //
924
925void PlasmaPhase::getStandardChemPotentials(span<double> muStar) const
926{
927 // After calling PlasmaPhase::getGibbs_ref, muStar = mu^\text{ref}_k(T_k)(T_k).
928 // mu^\text{ref} is evaluated at T for heavy species and at Te for electrons.
929 getGibbs_ref(muStar);
930
931 // Then, we need to add R*T_k*ln(P/Pref) to mu^\text{ref}.
932 // .. For heavy species, mu_star = mu^\text{ref}(T) + R*T*ln(P/Pref)
933 double tmp = log(pressure() / refPressure()) * RT();
934 for (size_t k = 0; k < m_kk; k++) {
935 muStar[k] += tmp;
936 }
937 // .. For electrons, mu_star = mu^\text{ref}(Te) + R*T_e*ln(P/Pref)
938 size_t k = m_electronSpeciesIndex;
939 muStar[k] -= log(pressure() / refPressure()) * RT();
940 muStar[k] += log(pressure() / refPressure()) * RTe();
941}
942
943void PlasmaPhase::getStandardVolumes(span<double> vol) const
944{
945 double tmp = RT() / pressure();
946 for (size_t k = 0; k < m_kk; k++) {
947 vol[k] = tmp;
948 }
950}
951
952// ================================================================= //
953// Thermodynamic Values for the Species Reference States //
954// ================================================================= //
955
956void PlasmaPhase::getGibbs_ref(span<double> g) const
957{
958 // Since the `updateThermo` is overriden in `PlasmaPhase`,
959 // `gibbs_RT_ref` returns \mu^\text{ref}_k(T_k) / (R * T_k).
960 // When calling `IdealGasPhase::getGibbs_ref(g)`,
961 // the `g` array is equal to \mu^\text{ref}_k(T_k) * (R * T) / (R * T_k).
962 // For all heavy species, T_k == T, so we get \mu^\text{ref}_k(T).
963 // For electrons, we need to multiply by T_e/T to get \mu^\text{ref}_k(T_e).
966}
967
973
974// ================================================================= //
975// Setting the State //
976// ================================================================= //
977
978void PlasmaPhase::setState(const AnyMap& input_state)
979{
980 AnyMap state = input_state;
981
982 // Set electron temperature first.
983 if (state.hasKey("electron-temperature")) {
984 state["Te"] = state["electron-temperature"];
985 }
986
987 if (state.hasKey("Te")) {
988 setElectronTemperature(state.convert("Te", "K"));
989 }
990
991 // Remap allowable synonyms for gas temperature after setting electron temperature,
992 if (state.hasKey("gas-temperature")) {
993 state["T"] = state["gas-temperature"];
994 }
995 if (state.hasKey("Tg")) {
996 state["T"] = state["Tg"];
997 }
998
999 // Call the base class method to set the remaining state variables.
1001}
1002
1004{
1005 // sigma = e * n_e * mu_e [S/m]; q_J = sigma * E^2 [W/m^3]
1006 const double mu_e = electronMobility(); // m^2 / (V·s)
1007 if (mu_e <= 0.0) {
1008 return 0.0;
1009 }
1010 const double ne = concentration(m_electronSpeciesIndex) * Avogadro; // m^-3
1011 if (ne <= 0.0) {
1012 return 0.0;
1013 }
1014 const double E = electricField(); // V/m
1015 if (E <= 0.0) {
1016 return 0.0;
1017 }
1018 const double sigma = ElectronCharge * ne * mu_e; // S/m
1019 return sigma * E * E; // W/m^3
1020}
1021
1023{
1024 // Joule heating: sigma * E^2 [W/m^3]
1025 const double qJ = jouleHeatingPower();
1026 checkFinite(qJ);
1027
1028 // set the check here to be updated at runtime
1030
1031 return qJ;
1032}
1033
1035{
1037
1038 for (const auto& [reservoirName, baseName] : m_vibrationalReservoirSpeciesMapping) {
1039 size_t kReservoir = speciesIndex(reservoirName, false);
1040 size_t kBase = speciesIndex(baseName, false);
1041
1042 if (kReservoir == npos) {
1043 throw CanteraError(
1044 "PlasmaPhase::updateVibrationalReservoirSpecies",
1045 "Vibrational reservoir species '{}' is not present "
1046 "in the phase.",
1047 reservoirName);
1048 }
1049
1050 if (kBase == npos) {
1051 throw CanteraError(
1052 "PlasmaPhase::updateVibrationalReservoirSpecies",
1053 "Base species '{}' associated with vibrational "
1054 "reservoir '{}' is not present in the phase.",
1055 baseName,
1056 reservoirName);
1057 }
1058
1060 reservoir.reservoirIndex = kReservoir;
1061 reservoir.baseSpeciesIndex = kBase;
1062
1063 m_vibrationalReservoirSpecies.push_back(reservoir);
1064 }
1065 // the update being done, the flag can be set back to false.
1067}
1068
1070{
1073 }
1074
1075 const double resetThreshold = 0.5 * m_vibrationalMoleFractionThreshold;
1076
1077 for (auto& reservoir : m_vibrationalReservoirSpecies) {
1078 const size_t kReservoir = reservoir.reservoirIndex;
1079 const size_t kBase = reservoir.baseSpeciesIndex;
1080
1081 // Mole fractions of the vibrational reservoir species and of the base
1082 // species it is associated with
1083 const double Xv = moleFraction(kReservoir);
1084 const double Xb = moleFraction(kBase);
1085
1086 const double pool = Xv + Xb;
1087
1088 // Ignore species pools that are too diluted to meaningfully affect chemistry.
1090 reservoir.warningActive = false;
1091 continue;
1092 }
1093
1094 // Check that the fraction of vibrational species is not too high
1095 // with respect to its base species. Should this fraction be too high, there
1096 // is a risk for the phase chemistry to be altered by the reservoir:
1097 // the code raises a warning to the user.
1098 const double reservoirFraction = Xv / pool;
1099
1100 // Re-arm the warning only after the reservoir fraction has
1101 // dropped sufficiently below the warning threshold.
1102 if (reservoir.warningActive) {
1103 if (reservoirFraction < resetThreshold) {
1104 reservoir.warningActive = false;
1105 }
1106 continue;
1107 }
1108
1109 if (reservoirFraction > m_vibrationalMoleFractionThreshold) {
1110 const string& reservoirName = speciesName(kReservoir);
1111 const string& baseName = speciesName(kBase);
1112
1113 warn_user("PlasmaPhase::checkVibrationalReservoirMoleFractions",
1114 "Warning: fictive vibrational reservoir species '{}' contains "
1115 "{:.3e} of the total '{}' pool. "
1116 "X({}) = {:.3e}, X({}) = {:.3e}, threshold = {:.3e}. "
1117 "Chemistry involving '{}' may be affected because part of the "
1118 "material is stored in an inert vibrational reservoir.\n",
1119 reservoirName,
1120 reservoirFraction,
1121 baseName,
1122 reservoirName, Xv,
1123 baseName, Xb,
1125 baseName);
1126 reservoir.warningActive = true;
1127 }
1128 }
1129}
1130
1131}
EEDF Two-Term approximation solver.
Header for plasma reaction rates parameterized by electron collision cross section and electron energ...
Base class for kinetics managers and also contains the kineticsmgr module documentation (see Kinetics...
Header file for class PlasmaPhase.
Declaration for class Cantera::Species.
A map of string keys to values whose type can vary at runtime.
Definition AnyMap.h:431
long int getInt(const string &key, long int default_) const
If key exists, return it as a long int, otherwise return default_.
Definition AnyMap.cpp:1585
double getDouble(const string &key, double default_) const
If key exists, return it as a double, otherwise return default_.
Definition AnyMap.cpp:1580
bool hasKey(const string &key) const
Returns true if the map contains an item named key.
Definition AnyMap.cpp:1477
double convert(const string &key, const string &units) const
Convert the item stored by the given key to the units specified in units.
Definition AnyMap.cpp:1595
bool getBool(const string &key, bool default_) const
If key exists, return it as a bool, otherwise return default_.
Definition AnyMap.cpp:1575
const string & getString(const string &key, const string &default_) const
If key exists, return it as a string, otherwise return default_.
Definition AnyMap.cpp:1590
Base class for exceptions thrown by Cantera classes.
Electron collision plasma reaction rate type.
void getGibbs_ref(span< double > g) const override
Returns the vector of the Gibbs function of the reference state at the current temperature of the sol...
void getPartialMolarEnthalpies(span< double > hbar) const override
Returns an array of partial molar enthalpies for the species in the mixture.
vector< double > m_g0_RT
Temporary storage for dimensionless reference state Gibbs energies.
vector< double > m_h0_RT
Temporary storage for dimensionless reference state enthalpies.
span< const double > enthalpy_RT_ref() const
Returns a reference to the dimensionless reference state enthalpy vector.
virtual void updateThermo() const
Update the species reference state thermodynamic functions.
vector< double > m_s0_R
Temporary storage for dimensionless reference state entropies.
void getPartialMolarEntropies(span< double > sbar) const override
Returns an array of partial molar entropies of the species in the solution.
vector< double > m_cp0_R
Temporary storage for dimensionless reference state heat capacities.
bool addSpecies(shared_ptr< Species > spec) override
Add a Species to this Phase.
void getChemPotentials(span< double > mu) const override
Get the species chemical potentials. Units: J/kmol.
void getStandardVolumes_ref(span< double > vol) const override
Get the molar volumes of the species reference states at the current T and P_ref of the solution.
Error thrown for problems processing information contained in an AnyMap or AnyValue.
Definition AnyMap.h:749
An error indicating that an unimplemented function has been called.
ValueCache m_cache
Cached for saved calculations within each ThermoPhase.
Definition Phase.h:862
size_t nSpecies() const
Returns the number of species in the phase.
Definition Phase.h:247
size_t m_kk
Number of species in the phase.
Definition Phase.h:882
size_t speciesIndex(const string &name, bool raise=true) const
Returns the index of a species named 'name' within the Phase object.
Definition Phase.cpp:127
double temperature() const
Temperature (K).
Definition Phase.h:586
double meanMolecularWeight() const
The mean molecular weight. Units: (kg/kmol).
Definition Phase.h:677
virtual double concentration(const size_t k) const
Concentration of species k.
Definition Phase.cpp:495
string speciesName(size_t k) const
Name of the species with index k.
Definition Phase.cpp:143
double moleFraction(size_t k) const
Return the mole fraction of a single species.
Definition Phase.cpp:457
virtual double density() const
Density (kg/m^3).
Definition Phase.h:611
double molecularWeight(size_t k) const
Molecular weight of species k.
Definition Phase.cpp:398
string name() const
Return the name of the phase.
Definition Phase.cpp:20
void checkElectronEnergyDistribution() const
Check the electron energy distribution.
void getStandardChemPotentials(span< double > muStar) const override
Return the standard chemical potentials of the species. Units: J/kmol.
vector< vector< double > > m_energyLevels
Electron energy levels corresponding to the cross section data.
void setCollisions()
Set collisions.
double meanElectronEnergy() const
Mean electron energy [eV].
void getGibbs_ref(span< double > g) const override
Return the reference chemical potentials of the species. Units: J/kmol.
double m_electronTempEquil
Saved electron temperature during an equilibrium solve.
double enthalpy_mole() const override
Return the Molar enthalpy. Units: J/kmol.
size_t m_nPoints
Number of points of electron energy levels.
void setState(const AnyMap &state) override
Set the state using an AnyMap containing any combination of properties supported by the thermodynamic...
void getActivities(span< double > a) const override
Get the array of non-dimensional activities at the current solution temperature, pressure,...
void addCollision(shared_ptr< Reaction > collision)
Add a collision and record the target species.
bool m_vibrationalReservoirSpeciesNeedUpdate
A boolean flag to update vibrational reservoir species.
virtual void setSolution(std::weak_ptr< Solution > soln) override
Set the link to the Solution object that owns this ThermoPhase.
void normalizeElectronEnergyDistribution()
Electron energy distribution norm.
void updateThermo() const override
Update the species reference state thermodynamic functions.
void getPartialMolarEnthalpies(span< double > hbar) const override
Return the partial molar enthalpies of the species in the solution. Units: J/kmol.
vector< size_t > m_targetSpeciesIndices
The collision-target species indices of m_collisions.
void setElectronTemperature(double Te) override
Set the internally stored electron temperature of the phase [K].
void electronEnergyLevelChanged()
When electron energy level changed, plasma properties such as electron-collision reaction rates need ...
double pressure() const override
Return the pressure of the plasma phase. Units: Pa.
double elasticPowerLoss()
The elastic power loss [J/s/m³].
int m_levelNum
Electron energy level change variable.
bool updateInterpolatedCrossSection(size_t k)
Update interpolated cross section of a collision.
double m_vibrationalAbsoluteMoleFractionThreshold
The absolute mole threshold below which a the chemistry is assumed to be safe from alterations from v...
bool m_inEquilibrate
Lock flag (default off).
void electronEnergyDistributionChanged()
When electron energy distribution changed, plasma properties such as electron-collision reaction rate...
vector< VibrationalReservoirSpecies > m_vibrationalReservoirSpecies
Vector of species serving as mean vibrational energy reservoirs.
size_t nElectronEnergyLevels() const
Number of electron levels.
size_t nCollisions() const
Number of electron collision cross sections.
void endEquilibrate() override
Hook called at the end of an equilibrium calculation on this phase.
Eigen::ArrayXd m_electronEnergyDist
Normalized electron energy distribution vector [-] Length: m_nPoints.
double electricField() const
Get the applied electric field strength [V/m].
Eigen::ArrayXd m_electronEnergyLevels
electron energy levels [ev]. Length: m_nPoints
void updateVibrationalReservoirSpecies()
Resolve configured vibrational reservoir and base species names to their corresponding phase species ...
void getActivityCoefficients(span< double > ac) const override
Get the array of non-dimensional activity coefficients at the current solution temperature,...
double meanTemperature() const
Return the mean temperature of the plasma phase. Units: K.
double intrinsicHeating() override
Intrinsic volumetric heating rate [W/m³].
double electronMobility() const
The electron mobility (m²/V/s).
void getParameters(AnyMap &phaseNode) const override
Store the parameters of a ThermoPhase object such that an identical one could be reconstructed using ...
string type() const override
String indicating the thermodynamic model implemented.
void checkElectronEnergyLevels() const
Check the electron energy levels.
void initThermo() override
Initialize the ThermoPhase object after all species have been set up.
void updateElasticElectronEnergyLossCoefficients()
Update elastic electron energy loss coefficients.
void updateElectronTemperatureFromEnergyDist()
Update electron temperature (K) From energy distribution.
string m_distributionType
Electron energy distribution type. Can be "isotropic", "discretized" or "Boltzmann-two-term".
void updateElectronEnergyDistribution()
Update the electron energy distribution.
void checkVibrationalReservoirMoleFractions()
A function to check that vibrational reservoir species are not at risk to hinder phase chemistry.
vector< double > m_elasticElectronEnergyLossCoefficients
Elastic electron energy loss coefficients (eV m3/s).
string m_quadratureMethod
Numerical quadrature method for electron energy distribution.
map< string, string > m_vibrationalReservoirSpeciesMapping
Mapping of vibrational reservoir species names to their corresponding base species names.
PlasmaPhase(const string &inputFile="", const string &id="")
Construct and initialize a PlasmaPhase object directly from an input file.
void beginEquilibrate() override
Hook called at the beginning of an equilibrium calculation on this phase.
void setDiscretizedElectronEnergyDist(span< const double > levels, span< const double > distrb)
Set discretized electron energy distribution.
double m_electronTemp
Electron temperature [K].
double RTe() const
Return the Gas Constant multiplied by the current electron temperature [J/kmol].
double intEnergy_mole() const override
Return the molar internal energy. Units: J/kmol.
double entropy_mole() const override
Return the molar entropy. Units: J/kmol/K.
bool m_do_normalizeElectronEnergyDist
Flag of normalizing electron energy distribution.
void updateElectronEnergyDistDifference()
Update electron energy distribution difference.
void updateElasticElectronEnergyLossCoefficient(size_t i)
Updates the elastic electron energy loss coefficient for collision index i.
vector< size_t > m_kElastic
Indices of elastic collisions in m_crossSections.
double m_vibrationalMoleFractionThreshold
Threshold fraction of vibrational reservoirs to their ground state above which they may be at risk of...
unique_ptr< EEDFTwoTermApproximation > m_eedfSolver
Solver used to calculate the EEDF based on electron collision rates.
string electronSpeciesName() const
Electron species name.
void setElectronEnergyDistributionParameters(const AnyMap &eedf)
Set parameters for the electron energy distribution.
void setIsotropicElectronEnergyDistribution()
Set isotropic electron energy distribution.
void getPartialMolarVolumes(span< double > vbar) const override
Return the partial molar volumes of the species in the solution. Units: m³/kmol.
Eigen::ArrayXd m_electronEnergyDistDiff
ionization degree for the electron-electron collisions (tmp is the previous one)
void getStandardVolumes(span< double > vol) const override
Return the standard molar volumes of the species. Units: m³/kmol.
void getPartialMolarEntropies(span< double > sbar) const override
Return the partial molar entropies of the species in the solution. Units: J/kmol/K.
double gibbs_mole() const override
Return the molar Gibbs free energy. Units: J/kmol.
double standardConcentration(size_t k=0) const override
Returns the standard concentration , which is used to normalize the generalized concentration.
std::vector< double > m_work
Work array.
bool addSpecies(shared_ptr< Species > spec) override
Add a Species to this Phase.
const shared_ptr< Reaction > collision(size_t i) const
Get the Reaction object associated with electron collision i.
vector< bool > m_interp_cs_ready
The list of whether the interpolated cross sections is ready.
vector< shared_ptr< ElectronCollisionPlasmaRate > > m_collisionRates
The list of shared pointers of collision rates.
void getChemPotentials(span< double > mu) const override
Return the chemical potentials of the species in the solution. Units: J/kmol.
void setElectronEnergyLevels(span< const double > levels)
Set electron energy levels.
vector< shared_ptr< Reaction > > m_collisions
The list of shared pointers of plasma collision reactions.
void setParameters(const AnyMap &phaseNode, const AnyMap &rootNode=AnyMap()) override
Set equation of state parameters from an AnyMap phase description.
void setMeanElectronEnergy(double energy)
Set mean electron energy [eV].
void getStandardVolumes_ref(span< double > vol) const override
Return the molar volumes of the species reference states. Units: m³/kmol.
size_t m_electronSpeciesIndex
Index of electron species.
vector< vector< double > > m_crossSections
Cross section data.
void setElectronEnergyDistributionType(const string &type)
Set electron energy distribution type.
double jouleHeatingPower() const
The joule heating power (W/m³).
vector< size_t > m_kInelastic
Indices of inelastic collisions in m_crossSections.
double electronTemperature() const override
Electron Temperature [K].
void setIsotropicShapeFactor(double x)
Set the shape factor of isotropic electron energy distribution.
void enableNormalizeElectronEnergyDist(bool enable)
Set flag of automatically normalize electron energy distribution.
void getPartialMolarIntEnergies(span< double > ubar) const override
Return the partial molar internal energies of the species in the solution. Units: J/kmol.
int m_distNum
Electron energy distribution change variable.
virtual void endEquilibrate()
Hook called at the end of an equilibrium calculation on this phase.
virtual void setParameters(const AnyMap &phaseNode, const AnyMap &rootNode=AnyMap())
Set equation of state parameters from an AnyMap phase description.
virtual void getParameters(AnyMap &phaseNode) const
Store the parameters of a ThermoPhase object such that an identical one could be reconstructed using ...
virtual void setState(const AnyMap &state)
Set the state using an AnyMap containing any combination of properties supported by the thermodynamic...
double RT() const
Return the Gas Constant multiplied by the current temperature.
virtual void setSolution(std::weak_ptr< Solution > soln)
Set the link to the Solution object that owns this ThermoPhase.
virtual void initThermo()
Initialize the ThermoPhase object after all species have been set up.
void initThermoFile(const string &inputFile, const string &id)
Initialize a ThermoPhase object using an input file.
std::weak_ptr< Solution > m_soln
reference to Solution
virtual void beginEquilibrate()
Hook called at the beginning of an equilibrium calculation on this phase.
MultiSpeciesThermo m_spthermo
Pointer to the calculation manager for species reference-state thermodynamic properties.
virtual double refPressure() const
Returns the reference pressure in Pa.
Header for a file containing miscellaneous numerical functions.
This file contains definitions for utility functions and text for modules, inputfiles and logging,...
double numericalQuadrature(const string &method, const Eigen::ArrayXd &f, const Eigen::ArrayXd &x)
Numerical integration of a function.
Definition funcs.cpp:116
const double Boltzmann
Boltzmann constant [J/K].
Definition ct_defs.h:87
const double Avogadro
Avogadro's Number [number/kmol].
Definition ct_defs.h:84
const double GasConstant
Universal Gas Constant [J/kmol/K].
Definition ct_defs.h:123
const double ElectronCharge
Elementary charge [C].
Definition ct_defs.h:93
const double ElectronMass
Electron Mass [kg].
Definition ct_defs.h:114
void warn_user(const string &method, const string &msg, const Args &... args)
Print a user warning raised from method as CanteraWarning.
Definition global.h:263
Namespace for the Cantera kernel.
Definition AnyMap.cpp:595
const size_t npos
index returned by functions to indicate "no position"
Definition ct_defs.h:183
void checkFinite(const double tmp)
Check to see that a number is finite (not NaN, +Inf or -Inf).
MappedVector asVectorXd(vector< double > &v)
Convenience wrapper for accessing std::vector as an Eigen VectorXd.
Definition eigen_dense.h:60
span< double > asSpan(Eigen::DenseBase< Derived > &v)
Convenience wrapper for accessing Eigen vector/array/map data as a span.
Definition eigen_dense.h:46
const double SmallNumber
smallest number to compare to zero.
Definition ct_defs.h:161
map< string, double > Composition
Map from string names to doubles.
Definition ct_defs.h:180
void checkArraySize(const char *procedure, size_t available, size_t required)
Wrapper for throwing ArraySizeError.
double state2
Value of the second state variable for the state at which value was evaluated, for example density or...
Definition ValueCache.h:106
bool validate(double state1New)
Check whether the currently cached value is valid based on a single state variable.
Definition ValueCache.h:39
double state1
Value of the first state variable for the state at which value was evaluated, for example temperature...
Definition ValueCache.h:102
A structure to describe species serving as mean vibrational energy reservoirs.
size_t reservoirIndex
Index of the vibrational reservoir species.
size_t baseSpeciesIndex
Index of the corresponding ground state phase species.