Skip to content

Commit 8fc6bff

Browse files
committed
[plasma] add inelastic power loss
1 parent 439ed3e commit 8fc6bff

File tree

8 files changed

+130
-12
lines changed

8 files changed

+130
-12
lines changed

include/cantera/kinetics/Kinetics.h

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

1248+
//! Net rates of progress by reaction indices
1249+
//! @param indices The indices of the reactions for which to return the net rates
1250+
//! of progress.
1251+
//! @return A vector of the net rates of progress for the specified reactions.
1252+
virtual vector<double> netRatesOfProgressByIndices(const vector<size_t>& indices);
1253+
12481254
//! @}
12491255
//! @name Reaction Mechanism Construction
12501256
//! @{

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 rates of progress from #m_kin
439+
void updateCollisionRatesOfProgress();
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+
//! Net rates of progress of collisions
451+
vector<double> m_netROPCollisions;
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/Kinetics.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,18 @@ void Kinetics::getNetProductionRates(double* net)
413413
m_reactantStoich.decrementSpecies(m_ropnet.data(), net);
414414
}
415415

416+
vector<double> Kinetics::netRatesOfProgressByIndices(const vector<size_t>& indices)
417+
{
418+
updateROP();
419+
420+
vector<double> rates(indices.size());
421+
for (size_t i = 0; i < indices.size(); i++) {
422+
rates[i] = m_ropnet[indices[i]];
423+
}
424+
425+
return rates;
426+
}
427+
416428
void Kinetics::getCreationRates_ddT(double* dwdot)
417429
{
418430
Eigen::Map<Eigen::VectorXd> out(dwdot, m_kk);

src/thermo/PlasmaPhase.cpp

Lines changed: 42 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_netROPCollisions.resize(nCollisions());
373378
}
374379

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

472+
void PlasmaPhase::updateCollisionRatesOfProgress()
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+
m_netROPCollisions =
484+
m_kin->netRatesOfProgressByIndices(m_electronCollisionReactionIndices);
485+
}
486+
}
487+
488+
double PlasmaPhase::inelasticPowerLoss()
489+
{
490+
updateCollisionRatesOfProgress();
491+
double powerLoss = 0.0;
492+
for (size_t i = 0; i < nCollisions(); i++) {
493+
powerLoss += m_netROPCollisions[i] * m_collisionRates[i]->energyLevels()[0];
494+
}
495+
powerLoss *= Avogadro * ElectronCharge;
496+
return powerLoss;
497+
}
498+
467499
double PlasmaPhase::elasticPowerLoss()
468500
{
469501
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(7408711810)
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(285091336)
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)