Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance the PlasmaPhase to use the cross section data with an example of calculating the elastic collision energy loss rate #1731

Open
wants to merge 10 commits into
base: main
Choose a base branch
from

Conversation

BangShiuh
Copy link
Contributor

@BangShiuh BangShiuh commented Jul 8, 2024

Changes proposed in this pull request
This PR change the initiation of the PlasmaPhase. The PlasmaPhase after this change takes the ElectronCollisionPlasmaRate cross section data to calculate the plasma thermal properties (specifically the elastic collision energy loss rate). The elastic collision energy loss is the energy transfer from electron to molecule when a fast electron (higher electron temperature) collides to a slower molecule (lower gas temperature). This is useful for modelling a non-equilibrium plasma which electron temperature is much higher than the gas temperature. The elastic collision reaction does not produce a new species, but can heat up the gas: e + O2 => e + O2 + heat. We check all the ElectronCollisionPlasmaReaction to find every reaction which the reactants is equal to the products in the initTherm method in PlasmaPhase. We then calculate the elastic collision energy loss using the cross section data from those reactions we found. The result is compared to BOLOS https://github.com/aluque/bolos. The grid definition and finite difference is different. The result is close when the number of grid points is high. The definition of the electron energy distribution function is different in Cantera and BOLOS. To compare the result, I made a modification to BOLOS, https://github.com/BangShiuh/bolos/tree/mod. You can reproduce the result using the scripts and data in
scripts.zip.

Future work to utilize "effective" cross section:
BOLOS calculates the elastic cross section subtracting the inelastic cross section from the effective cross section. This can be included in the parsing script, lxcat2yaml.py to obtain the elastic cross section. I think it is much simpler to use an elastic cross section in a yaml input file as it does not need further transformation like an effective cross section.

Design philosophy: the original cross section data has the collision type such as attachment, ionization, elastic,... etc. However, the collision type can be determined from the collision equation. For example, elastic collisions have the same reactants and products. Ionization collisions have an extra electron in the products. Cantera manages the reaction equations well and we should use it to our advantage to simplify the input data format.

If applicable, fill in the issue number this pull request is fixing

Closes #

If applicable, provide an example illustrating new features this pull request is introducing

Checklist

  • The pull request includes a clear description of this code change
  • Commit messages have short titles and reference relevant issues
  • Build passes (scons build & scons test) and unit tests address code coverage
  • Style & formatting of contributed code follows contributing guidelines
  • The pull request is ready for review

@BangShiuh BangShiuh changed the title Collision Enhance the PlasmaPhase to use the cross section data with an example of calculating the elastic collision energy loss rate Jul 8, 2024
@BangShiuh BangShiuh changed the title Enhance the PlasmaPhase to use the cross section data with an example of calculating the elastic collision energy loss rate Enhance the PlasmaPhase to use the cross section data with an example of calculating the elastic collision energy loss rate (WIP) Jul 8, 2024
Copy link

codecov bot commented Jul 8, 2024

Codecov Report

Attention: Patch coverage is 74.40000% with 32 lines in your changes missing coverage. Please review.

Project coverage is 75.71%. Comparing base (0c89553) to head (7d866c9).
Report is 397 commits behind head on main.

Files with missing lines Patch % Lines
src/thermo/PlasmaPhase.cpp 72.60% 13 Missing and 7 partials ⚠️
src/kinetics/KineticsFactory.cpp 78.57% 3 Missing and 3 partials ⚠️
src/kinetics/ElectronCollisionPlasmaRate.cpp 0.00% 3 Missing and 1 partial ⚠️
src/kinetics/Kinetics.cpp 0.00% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1731      +/-   ##
==========================================
+ Coverage   72.76%   75.71%   +2.94%     
==========================================
  Files         378      445      +67     
  Lines       56986    61622    +4636     
  Branches    20691     9675   -11016     
==========================================
+ Hits        41468    46658    +5190     
+ Misses      12463    11894     -569     
- Partials     3055     3070      +15     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@BangShiuh BangShiuh changed the title Enhance the PlasmaPhase to use the cross section data with an example of calculating the elastic collision energy loss rate (WIP) Enhance the PlasmaPhase to use the cross section data with an example of calculating the elastic collision energy loss rate Jul 8, 2024
Copy link
Member

@speth speth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this, @BangShiuh. I had some suggestions that I think will lead to a simpler implementation. Please let me know if you have any questions.

@@ -1905,6 +1905,24 @@ cdef class ThermoPhase(_SolutionBase):
raise ThermoModelMethodError(self.thermo_model)
return pystr(self.plasma.electronSpeciesName())

property elastic_electron_energy_loss_rate:
""" Elastic electron energy loss rate """
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are the units of this quantity?

Comment on lines +213 to +214
double elasticElectronEnergyLossRate()
double normalizedElasticElectronEnergyLossRate()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These methods should probably have the except +translate_exception specifier -- generally recommended except for trivial getters that can't throw.

Comment on lines +1917 to +1919
Normalized elastic electron energy loss rate
The elastic electron energy loss rate is normalized
by dividing the concentration of electron.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Careful with the formatting here -- the second line will be seen as a continuation of the same sentence by Sphinx.

Comment on lines +277 to +285
//! Get elastic electron energy loss rate (eV/s)
double elasticElectronEnergyLossRate() {
return concentration(m_electronSpeciesIndex) *
normalizedElasticElectronEnergyLossRate();
}

//! Get normalized elastic electron energy loss rate (eV-m3/kmol/s)
double normalizedElasticElectronEnergyLossRate();

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need both of these methods, given the relatively simple conversion? Which one is more likely to be used? My guess would be the non-normalized version, but I could easily be convinced otherwise. Also, are you sure about the units for the first method? I think this should be an intrinsic property, so the dimensions should be power per unit mass (or possibly power per unit volume).

Also, can you write out the equation being evaluated, and say something about how that's being done? (since as you note in the PR, the finite difference scheme chosen matters)

self.phase.TPX = 1000, ct.one_atm, "O2:1, E:1e-10"
r1 = self.phase.elastic_electron_energy_loss_rate
c_electron = self.phase.concentrations[self.phase.species_index("E")]
self.assertNear(self.phase.elastic_electron_energy_loss_rate, 4.233683742587e-05)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've been shifting away from the unittest style assert methods to use plain assert statements that are handled by pytest. Here, you can write:

Suggested change
self.assertNear(self.phase.elastic_electron_energy_loss_rate, 4.233683742587e-05)
assert self.phase.elastic_electron_energy_loss_rate == approx(4.233683742587e-05)

Comment on lines +286 to +300
vector<shared_ptr<Reaction>> reactions;
for (AnyMap R : reactionsAnyMapList(*m_kinetics, m_input, m_root)) {
reactions.push_back(newReaction(R, *m_kinetics));
}

// add reactions to kinetics object
addReactions(*m_kinetics, reactions);

// init m_collisions
m_collisions.resize(0);
size_t i = 0;
for (shared_ptr<Reaction> reaction : reactions) {
if (reaction->type() == "electron-collision-plasma") {
m_collisions.push_back(reaction);
if (reaction->reactants == reaction->products) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of building a standalone list of Reactions, you could just call the existing method addReactions(*m_kinetics, m_input, m_root), and then use Kinetics.reaction(i) to loop over the reaction objects and build up m_collisions. Then, you wouldn't need the two new functions reactionsAnyMapList and addReactions(Kinetics&, vector<shared_ptr<Reaction>>).

Comment on lines +2003 to +2006
//! The kinetics object associates with ThermoPhase
//! Some phase requires Kinetics to perform calculation
//! such as PlasmaPhase
shared_ptr<Kinetics> m_kinetics;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because the Kinetics object also holds a shared_ptr<ThermoPhase>, this will create a reference cycle and introduce a memory leak. The solution to this problem is to only hold a weak_ptr in one direction. I'd recommend doing this by having the ThermoPhase object hold a weak_ptr to the Solution (say, m_soln), which will also eliminate the need to inherit from enable_shared_from_this, as you can access the shared_ptr<ThermoPhase> from the Solution.

Comment on lines +1962 to +1964
shared_ptr<Kinetics> kinetics() {
return m_kinetics;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Method needs a docstring.

Comment on lines +314 to +317
if (!sol->thermo()->kinetics()) {
// only add phases that doesn't have kinetics
// The phase that has kinetics already
phases.push_back(sol->thermo());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment could be worded more clearly. Also, I'm not sure I follow the behavior here. Shouldn't the behavior be to skip calling newKinetics if the phase already has a Kinetics object? The logic about adjacent phases only applies to surfaces/edges in any case.

Comment on lines +283 to +284
m_kinetics = newKinetics("bulk");
m_kinetics->addThermo(shared_from_this());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a lot of this logic might be simpler if you leave initialization of the Kinetics object to the newSolution factory function as it originally stood. The way to connect the Kinetics object to the PlasmaPhase would then be to add here in initThermo a callback to the Solution object (see Solution.registerChangedCallback) that would then update m_collisions when it sees a change in the Kinetics object. You'll also need to call removeChangedCallback from the PlasmaPhase destructor.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants