Skip to content

Commit 4e7d6e2

Browse files
spethBangShiuh
authored andcommitted
[1D] Prevent two-point control from finding solutions with reverse flow
Fixes #1787
1 parent f3d77f4 commit 4e7d6e2

File tree

10 files changed

+286
-26
lines changed

10 files changed

+286
-26
lines changed

include/cantera/kinetics/ElectronCollisionPlasmaRate.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ struct ElectronCollisionPlasmaData : public ReactionData
8989
class ElectronCollisionPlasmaRate : public ReactionRate
9090
{
9191
public:
92+
9293
ElectronCollisionPlasmaRate() = default;
9394

9495
ElectronCollisionPlasmaRate(const AnyMap& node,
@@ -135,6 +136,16 @@ class ElectronCollisionPlasmaRate : public ReactionRate
135136
return m_crossSections;
136137
}
137138

139+
//! The value of #m_crossSectionsInterpolated [m2]
140+
const vector<double>& crossSectionInterpolated() const {
141+
return m_crossSectionsInterpolated;
142+
}
143+
144+
//! Set the value of #m_crossSectionsInterpolated [m2]
145+
void setCrossSectionInterpolated(vector<double>& cs) {
146+
m_crossSectionsInterpolated = cs;
147+
}
148+
138149
private:
139150
//! electron energy levels [eV]
140151
vector<double> m_energyLevels;

include/cantera/thermo/Phase.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ namespace Cantera
1818

1919
class Solution;
2020
class Species;
21+
class Kinetics;
2122

2223
//! Class Phase is the base class for phases of matter, managing the species and
2324
//! elements in a phase, as well as the independent variables of temperature,

include/cantera/thermo/PlasmaPhase.h

Lines changed: 81 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
namespace Cantera
1616
{
1717

18+
class Reaction;
19+
class ElectronCollisionPlasmaRate;
20+
1821
/**
1922
* Base class for a phase with plasma properties. This class manages the
2023
* plasma properties such as electron energy distribution function (EEDF).
@@ -99,13 +102,6 @@ class PlasmaPhase: public IdealGasPhase
99102
const double* distrb,
100103
size_t length);
101104

102-
//! Set discretized electron energy distribution.
103-
//! @param distrb The vector of electron energy distribution.
104-
//! Length: #m_nPoints.
105-
//! @param length The length of the vectors, which equals #m_nPoints.
106-
void setDiscretizedElectronEnergyDist(const double* distrb,
107-
size_t length);
108-
109105
//! Get electron energy distribution.
110106
//! @param distrb The vector of electron energy distribution.
111107
//! Length: #m_nPoints.
@@ -198,6 +194,11 @@ class PlasmaPhase: public IdealGasPhase
198194
return m_nPoints;
199195
}
200196

197+
//! Number of collisions
198+
size_t nCollisions() const {
199+
return m_collisions.size();
200+
}
201+
201202
//! Electron Species Index
202203
size_t electronSpeciesIndex() const {
203204
return m_electronSpeciesIndex;
@@ -271,6 +272,25 @@ class PlasmaPhase: public IdealGasPhase
271272
return m_levelNum;
272273
}
273274

275+
//! Return the interpolated cross section Number #m_csNum
276+
int interpCrossSectionNum() const {
277+
return m_csNum;
278+
}
279+
280+
//! add Solution object
281+
virtual void addSolution(std::weak_ptr<Solution> soln) override;
282+
283+
/**
284+
* The elastic power loss(J/s/m3)
285+
* @f[
286+
* P_k = N_A N_A C_e e \sum_k C_k K_k,
287+
* @f]
288+
* where @f$ C_k @f$ and @f$ C_e @f$ are the concentration (kmol/m3) of the
289+
* target species and electrons, respectively. @f$ K_k @f$ is the elastic
290+
* electron energy loss coefficient (eV-m3/s).
291+
*/
292+
double elasticPowerLoss();
293+
274294
protected:
275295
void updateThermo() const override;
276296

@@ -284,6 +304,10 @@ class PlasmaPhase: public IdealGasPhase
284304
//! the new level.
285305
void electronEnergyLevelChanged();
286306

307+
//! When the interpolated cross sections changed, plasma properties such as
308+
//! elastic power loss need to be re-evaluated.
309+
void interpolatedCrossSectionsChanged();
310+
287311
//! Check the electron energy levels
288312
/*!
289313
* The values of electron energy levels need to be positive and
@@ -317,6 +341,12 @@ class PlasmaPhase: public IdealGasPhase
317341
//! Electron energy distribution norm
318342
void normalizeElectronEnergyDistribution();
319343

344+
//! Update interpolated cross sections
345+
void updateInterpolatedCrossSections();
346+
347+
//! Update electron energy distribution difference
348+
void updateElectronEnergyDistDifference();
349+
320350
// Electron energy order in the exponential term
321351
double m_isotropicShapeFactor = 2.0;
322352

@@ -345,6 +375,28 @@ class PlasmaPhase: public IdealGasPhase
345375
//! Flag of normalizing electron energy distribution
346376
bool m_do_normalizeElectronEnergyDist = true;
347377

378+
//! Data for initiate reaction
379+
AnyMap m_root;
380+
381+
//! Electron energy distribution Difference dF/dε (V^-5/2)
382+
Eigen::ArrayXd m_electronEnergyDistDiff;
383+
384+
//! Elastic electron energy loss coefficients (eV m3/s)
385+
/*! The elastic electron energy loss coefficient for species k is,
386+
* @f[
387+
* K_k = \frac{2 m_e}{m_k} \sqrt{\frac{2 e}{m_e}} \int_0^{\infty} \sigma_k
388+
* \epsilon^2 \left( F_0 + \frac{k_B T}{e}
389+
* \frac{\partial F_0}{\partial \epsilon} \right) d \epsilon,
390+
* @f]
391+
* where @f$ m_e @f$ [kg] is the electron mass, @f$ \epsilon @f$ [V] is the
392+
* electron energy, @f$ \sigma_k @f$ [m2] is the reaction collision cross section,
393+
* @f$ F_0 @f$ [V^(-3/2)] is the normalized electron energy distribution function.
394+
*/
395+
vector<double> m_elasticElectronEnergyLossCoefficients;
396+
397+
//! update elastic electron energy loss coefficients
398+
void updateElasticElectronEnergyLossCoefficients();
399+
348400
private:
349401
//! Electron energy distribution change variable. Whenever
350402
//! #m_electronEnergyDist changes, this int is incremented.
@@ -353,6 +405,28 @@ class PlasmaPhase: public IdealGasPhase
353405
//! Electron energy level change variable. Whenever
354406
//! #m_electronEnergyLevels changes, this int is incremented.
355407
int m_levelNum = -1;
408+
409+
//! Interpolated collision cross section change variable. Whenever
410+
//! #ElectronCollisionPlasmaRate::m_crossSectionsInterpolated changes,
411+
//! this int is incremented.
412+
int m_csNum = -1;
413+
414+
//! The list of shared pointers of plasma collision reactions
415+
vector<shared_ptr<Reaction>> m_collisions;
416+
417+
//! The list of shared pointers of ElectronCollisionPlasmaRate
418+
vector<shared_ptr<ElectronCollisionPlasmaRate>> m_collisionRates;
419+
420+
//! The collision-target species indices of #m_collisions
421+
vector<size_t> m_targetSpeciesIndices;
422+
423+
//! Interpolated cross sections. This is used for storing
424+
//! interpolated cross sections temporarily.
425+
vector<double> m_interp_cs;
426+
427+
//! Set collisions
428+
void setCollisions();
429+
356430
};
357431

358432
}

include/cantera/thermo/ThermoPhase.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "MultiSpeciesThermo.h"
1616
#include "cantera/base/Units.h"
1717
#include "cantera/base/AnyMap.h"
18+
#include "cantera/base/Solution.h"
1819

1920
namespace Cantera
2021
{
@@ -1957,6 +1958,11 @@ class ThermoPhase : public Phase
19571958

19581959
//! @}
19591960

1961+
//! add Solution object
1962+
virtual void addSolution(std::weak_ptr<Solution> soln) {
1963+
m_soln = soln;
1964+
}
1965+
19601966
protected:
19611967
//! Store the parameters of a ThermoPhase object such that an identical
19621968
//! one could be reconstructed using the newThermo(AnyMap&) function. This
@@ -1993,6 +1999,9 @@ class ThermoPhase : public Phase
19931999

19942000
//! last value of the temperature processed by reference state
19952001
mutable double m_tlast = 0.0;
2002+
2003+
//! reference to Solution
2004+
std::weak_ptr<Solution> m_soln;
19962005
};
19972006

19982007
}

interfaces/cython/cantera/thermo.pxd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ cdef extern from "cantera/thermo/PlasmaPhase.h":
210210
size_t nElectronEnergyLevels()
211211
double electronPressure()
212212
string electronSpeciesName()
213+
double elasticPowerLoss() except +translate_exception
213214

214215

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

interfaces/cython/cantera/thermo.pyx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1904,6 +1904,12 @@ cdef class ThermoPhase(_SolutionBase):
19041904
raise ThermoModelMethodError(self.thermo_model)
19051905
return pystr(self.plasma.electronSpeciesName())
19061906

1907+
property elastic_power_loss:
1908+
""" Elastic power loss (J/s/m3) """
1909+
def __get__(self):
1910+
if not self._enable_plasma:
1911+
raise ThermoModelMethodError(self.thermo_model)
1912+
return self.plasma.elasticPowerLoss()
19071913

19081914
cdef class InterfacePhase(ThermoPhase):
19091915
""" A class representing a surface, edge phase """

src/base/Solution.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ void Solution::setName(const string& name) {
4242

4343
void Solution::setThermo(shared_ptr<ThermoPhase> thermo) {
4444
m_thermo = thermo;
45+
m_thermo->addSolution(weak_from_this());
4546
for (const auto& [id, callback] : m_changeCallbacks) {
4647
callback();
4748
}

src/kinetics/ElectronCollisionPlasmaRate.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,19 @@ double ElectronCollisionPlasmaRate::evalFromStruct(
7676
// Interpolate cross-sections data to the energy levels of
7777
// the electron energy distribution function
7878
if (shared_data.levelChanged) {
79-
m_crossSectionsInterpolated.resize(0);
79+
m_crossSectionsInterpolated.clear();
80+
m_crossSectionsInterpolated.reserve(shared_data.energyLevels.size());
8081
for (double level : shared_data.energyLevels) {
81-
m_crossSectionsInterpolated.push_back(linearInterp(level,
82-
m_energyLevels, m_crossSections));
82+
m_crossSectionsInterpolated.emplace_back(linearInterp(level,
83+
m_energyLevels, m_crossSections));
84+
}
85+
} else {
86+
// The interpolated cross section is set by the PlasmaPhase
87+
// check the size of the vector
88+
if (m_crossSectionsInterpolated.size() != shared_data.energyLevels.size()) {
89+
throw CanteraError("ElectronCollisionPlasmaRate::evalFromStruct",
90+
"Energy levels and interpolated cross section ",
91+
"must have the same length.");
8392
}
8493
}
8594

src/oneD/Flow1D.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1258,6 +1258,9 @@ void Flow1D::enableTwoPointControl(bool twoPointControl)
12581258
{
12591259
if (isStrained()) {
12601260
m_twoPointControl = twoPointControl;
1261+
// Prevent finding spurious solutions with negative velocity (outflow) at either
1262+
// inlet.
1263+
setBounds(c_offset_V, -1e-5, 1e20);
12611264
} else {
12621265
throw CanteraError("Flow1D::enableTwoPointControl",
12631266
"Invalid operation: two-point control can only be used"

0 commit comments

Comments
 (0)