Skip to content

Commit 24bbab2

Browse files
committed
[plasma] add inelastic_power_loss
1 parent acf3f0e commit 24bbab2

File tree

9 files changed

+128
-12
lines changed

9 files changed

+128
-12
lines changed

include/cantera/kinetics/BulkKinetics.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ class BulkKinetics : public Kinetics
8181
Eigen::SparseMatrix<double> netRatesOfProgress_ddCi() override;
8282
//! @}
8383

84+
virtual double fwdRateConstant(size_t i) override;
85+
8486
//! @name Rate calculation intermediate methods
8587
//! @{
8688

include/cantera/kinetics/Kinetics.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1244,6 +1244,11 @@ class Kinetics
12441244
throw NotImplementedError("Kinetics::getRevRateConstants");
12451245
}
12461246

1247+
//! Forward rate constants by indices
1248+
virtual double fwdRateConstant(size_t i) {
1249+
throw NotImplementedError("Kinetics::fwdRateConstant");
1250+
}
1251+
12471252
//! @}
12481253
//! @name Reaction Mechanism Construction
12491254
//! @{

include/cantera/thermo/PlasmaPhase.h

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ namespace Cantera
1616
{
1717

1818
class Reaction;
19+
class Kinetics;
1920
class ElectronCollisionPlasmaRate;
2021

2122
//! Base class for handling plasma properties, specifically focusing on the
@@ -311,6 +312,16 @@ class PlasmaPhase: public IdealGasPhase
311312
*/
312313
double elasticPowerLoss();
313314

315+
/**
316+
* The inelastic power loss (J/s/m³)
317+
* @f[
318+
* P_i = N_A e \sum_i U_i ROP_i,
319+
* @f]
320+
* where @f$ U_i @f$ is the threshold energy (eV) and @f$ ROP_i @f$ is the
321+
* net rate of progress of the collision (kmol/s/m³).
322+
*/
323+
double inelasticPowerLoss();
324+
314325
protected:
315326
void updateThermo() const override;
316327

@@ -424,6 +435,9 @@ class PlasmaPhase: public IdealGasPhase
424435
*/
425436
void updateElasticElectronEnergyLossCoefficients();
426437

438+
//! Update collision rate constants from #m_kin
439+
void updateCollisionRateConstants();
440+
427441
private:
428442
//! Electron energy distribution change variable. Whenever
429443
//! #m_electronEnergyDist changes, this int is incremented.
@@ -433,6 +447,12 @@ class PlasmaPhase: public IdealGasPhase
433447
//! #m_electronEnergyLevels changes, this int is incremented.
434448
int m_levelNum = -1;
435449

450+
//! Forward rate constants of collisions
451+
vector<double> m_fwd_collision_rate_constants;
452+
453+
//! Kinetic object
454+
shared_ptr<Kinetics> m_kin;
455+
436456
//! The list of shared pointers of plasma collision reactions
437457
vector<shared_ptr<Reaction>> m_collisions;
438458

@@ -449,12 +469,17 @@ class PlasmaPhase: public IdealGasPhase
449469
//! The list of whether the interpolated cross sections is ready
450470
vector<bool> m_interp_cs_ready;
451471

472+
//! Indices of electron collision plasma reactions
473+
//! This is used for getting the rates of progress.
474+
vector<size_t> m_electronCollisionReactionIndices;
475+
452476
//! Set collisions. This function sets the list of collisions and
453477
//! the list of target species using #addCollision.
454478
void setCollisions();
455479

456480
//! Add a collision and record the target species
457-
void addCollision(std::shared_ptr<Reaction> collision);
481+
//! @param j index of the corresponding reaction for the collision
482+
void addCollision(size_t j);
458483

459484
};
460485

interfaces/cython/cantera/thermo.pxd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ cdef extern from "cantera/thermo/PlasmaPhase.h":
211211
double electronPressure()
212212
string electronSpeciesName()
213213
double elasticPowerLoss() except +translate_exception
214+
double inelasticPowerLoss() except +translate_exception
214215

215216

216217
cdef extern from "cantera/cython/thermo_utils.h":

interfaces/cython/cantera/thermo.pyx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1914,6 +1914,16 @@ cdef class ThermoPhase(_SolutionBase):
19141914
raise ThermoModelMethodError(self.thermo_model)
19151915
return self.plasma.elasticPowerLoss()
19161916

1917+
property inelastic_power_loss:
1918+
"""
1919+
Inelastic power loss (J/s/m3)
1920+
.. versionadded:: 3.2
1921+
"""
1922+
def __get__(self):
1923+
if not self._enable_plasma:
1924+
raise ThermoModelMethodError(self.thermo_model)
1925+
return self.plasma.inelasticPowerLoss()
1926+
19171927
cdef class InterfacePhase(ThermoPhase):
19181928
""" A class representing a surface, edge phase """
19191929
def __cinit__(self, *args, **kwargs):

src/kinetics/BulkKinetics.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,12 @@ Eigen::SparseMatrix<double> BulkKinetics::netRatesOfProgress_ddCi()
454454
return jac - calculateCompositionDerivatives(m_revProductStoich, rop_rates, false);
455455
}
456456

457+
double BulkKinetics::fwdRateConstant(size_t i)
458+
{
459+
updateROP();
460+
return m_kf0[i];
461+
}
462+
457463
void BulkKinetics::updateROP()
458464
{
459465
static const int cacheId = m_cache.getId();

src/thermo/PlasmaPhase.cpp

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -315,35 +315,37 @@ void PlasmaPhase::setCollisions()
315315
m_collisions.clear();
316316
m_collisionRates.clear();
317317
m_targetSpeciesIndices.clear();
318+
m_electronCollisionReactionIndices.clear();
318319

319320
if (shared_ptr<Solution> soln = m_soln.lock()) {
320-
shared_ptr<Kinetics> kin = soln->kinetics();
321-
if (!kin) {
321+
m_kin = soln->kinetics();
322+
if (!m_kin) {
322323
return;
323324
}
324325

325326
// add collision from the initial list of reactions
326-
for (size_t i = 0; i < kin->nReactions(); i++) {
327-
std::shared_ptr<Reaction> R = kin->reaction(i);
327+
for (size_t j = 0; j < m_kin->nReactions(); j++) {
328+
std::shared_ptr<Reaction> R = m_kin->reaction(j);
328329
if (R->rate()->type() != "electron-collision-plasma") {
329330
continue;
330331
}
331-
addCollision(R);
332+
addCollision(j);
332333
}
333334

334335
// register callback when reaction is added later
335336
// Modifying collision reactions is not supported
336-
kin->registerReactionAddedCallback(this, [this, kin]() {
337-
size_t i = kin->nReactions() - 1;
338-
if (kin->reaction(i)->type() == "electron-collision-plasma") {
339-
addCollision(kin->reaction(i));
337+
m_kin->registerReactionAddedCallback(this, [this]() {
338+
size_t j = m_kin->nReactions() - 1;
339+
if (m_kin->reaction(j)->type() == "electron-collision-plasma") {
340+
addCollision(j);
340341
}
341342
});
342343
}
343344
}
344345

345-
void PlasmaPhase::addCollision(std::shared_ptr<Reaction> collision)
346+
void PlasmaPhase::addCollision(size_t j)
346347
{
348+
std::shared_ptr<Reaction> collision = m_kin->reaction(j);
347349
size_t i = nCollisions();
348350

349351
// setup callback to signal updating the cross-section-related
@@ -368,8 +370,11 @@ void PlasmaPhase::addCollision(std::shared_ptr<Reaction> collision)
368370
std::dynamic_pointer_cast<ElectronCollisionPlasmaRate>(collision->rate()));
369371
m_interp_cs_ready.emplace_back(false);
370372

373+
m_electronCollisionReactionIndices.push_back(j);
374+
371375
// resize parameters
372376
m_elasticElectronEnergyLossCoefficients.resize(nCollisions());
377+
m_fwd_collision_rate_constants.resize(nCollisions());
373378
}
374379

375380
bool PlasmaPhase::updateInterpolatedCrossSection(size_t i)
@@ -464,6 +469,36 @@ void PlasmaPhase::updateElasticElectronEnergyLossCoefficient(size_t i)
464469
m_electronEnergyLevels.pow(3.0));
465470
}
466471

472+
void PlasmaPhase::updateCollisionRateConstants()
473+
{
474+
static const int cacheId = m_cache.getId();
475+
CachedScalar last = m_cache.getScalar(cacheId);
476+
477+
// combine the distribution and energy level number
478+
int stateNum = m_distNum + m_levelNum;
479+
480+
// update only if the reaction rates coefficients have changed
481+
// which depends on the energy distribution, and energy levels
482+
if (!last.validate(stateNum)) {
483+
for (size_t i = 0; i < nCollisions(); i++) {
484+
m_fwd_collision_rate_constants[i] =
485+
m_kin->fwdRateConstant(m_electronCollisionReactionIndices[i]);
486+
}
487+
}
488+
}
489+
490+
double PlasmaPhase::inelasticPowerLoss()
491+
{
492+
updateCollisionRateConstants();
493+
double rate = 0.0;
494+
for (size_t i = 0; i < nCollisions(); i++) {
495+
rate += concentration(m_targetSpeciesIndices[i]) *
496+
m_collisionRates[i]->energyLevels()[0] *
497+
m_fwd_collision_rate_constants[i];
498+
}
499+
return Avogadro * ElectronCharge * concentration(m_electronSpeciesIndex) * rate;
500+
}
501+
467502
double PlasmaPhase::elasticPowerLoss()
468503
{
469504
updateElasticElectronEnergyLossCoefficients();

test/data/oxygen-plasma.yaml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ phases:
88
thermo: plasma
99
elements: [O, E]
1010
species:
11-
- species: [E]
11+
- species: [E, O2(a1dg)]
1212
- nasa_gas.yaml/species: [O2, O2-]
1313

1414
kinetics: gas
@@ -46,6 +46,17 @@ species:
4646
s0: 12.679 J/mol/K
4747
cp0: 20.786 J/mol/K
4848

49+
- name: O2(a1dg)
50+
composition: {O: 2}
51+
thermo:
52+
model: NASA7
53+
temperature-ranges: [200.0, 1000.0, 6000.0]
54+
data:
55+
- [3.78535371, -3.2192854e-03, 1.12323443e-05, -1.17254068e-08, 4.17659585e-12,
56+
1.02922572e+04, 3.27320239]
57+
- [3.45852381, 1.04045351e-03, -2.79664041e-07, 3.11439672e-11, -8.55656058e-16,
58+
1.02229063e+04, 4.15264119]
59+
4960
reactions:
5061
- equation: E + O2 + O2 => O2- + O2
5162
type: two-temperature-plasma

test/python/test_thermo.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1200,6 +1200,17 @@ def collision_data(self):
12001200
5.49e-20, 5.64e-20, 5.77e-20, 5.87e-20, 5.97e-20]
12011201
}
12021202

1203+
@property
1204+
def inelastic_collision_data(self):
1205+
return {
1206+
"equation": "O2 + E => E + O2(a1dg)",
1207+
"type": "electron-collision-plasma",
1208+
"note": "This is a electron collision process of plasma",
1209+
"energy-levels": [0.977, 1.5, 2.0, 3.0, 3.5, 4.0, 5.0],
1210+
"cross-sections": [0.0, 5.8000e-23, 1.5300e-22, 3.8000e-22, 4.9000e-22,
1211+
5.7000e-22, 7.4000e-22]
1212+
}
1213+
12031214
def test_converting_electron_energy_to_temperature(self, phase):
12041215
phase.mean_electron_energy = 1.0
12051216
Te = 2.0 / 3.0 * ct.electron_charge / ct.boltzmann
@@ -1297,6 +1308,16 @@ def test_elastic_power_loss_change_shape_factor(self, phase):
12971308
phase.isotropic_shape_factor = 1.1
12981309
assert phase.elastic_power_loss == approx(4273351243)
12991310

1311+
def test_inelastic_power_loss(self, phase):
1312+
phase.TPX = 1000, ct.one_atm, "O2:1, E:1e-5"
1313+
phase.add_reaction(ct.Reaction.from_dict(self.inelastic_collision_data, phase))
1314+
value = phase.inelastic_power_loss
1315+
assert value == approx(1470414640)
1316+
# change of gas temperature does not change inelastic power loss
1317+
# when the concentrations hold constant
1318+
phase.TDX = 2000, phase.density, "O2:1, E:1e-5"
1319+
assert phase.inelastic_power_loss == approx(value)
1320+
13001321
class TestImport:
13011322
"""
13021323
Tests the various ways of creating a Solution object

0 commit comments

Comments
 (0)