-
-
Notifications
You must be signed in to change notification settings - Fork 397
Energy equation for reactors using PlasmaPhase #2068
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
base: main
Are you sure you want to change the base?
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #2068 +/- ##
==========================================
- Coverage 76.75% 76.67% -0.09%
==========================================
Files 457 457
Lines 53699 53779 +80
Branches 9121 9134 +13
==========================================
+ Hits 41219 41235 +16
- Misses 9375 9442 +67
+ Partials 3105 3102 -3 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
BangShiuh
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mquiram Thanks for working on this. I left some comments for the changes in class PlasmaPhase.
| } | ||
| return m_eedfSolver->getElectronMobility(); | ||
| } else { | ||
| throw NotImplementedError("PlasmaPhase::electronMobility", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Electron mobility can be supported without Boltzmann-two-term if we provide the cross-section data and the EEDF. The equation is different according to the bolsig document. I am fine with the current implementation. But I would make another PR to improve this so that the plasma reactor can be more flexible. In addition, IonGasTransport.::getMobilities can use the electron mobility. We can cache the electron mobility value in PlasmaPhase so we don't need to call getElectronMobility() when it stays the same value.
| // sigma = e * n_e * mu_e [S/m]; q_J = sigma * E^2 [W/m^3] | ||
| const double mu_e = electronMobility(); // m^2 / (V·s) | ||
| if (!(mu_e > 0.0) || !std::isfinite(mu_e)) { | ||
| return 0.0; | ||
| } | ||
| const double ne = concentration(m_electronSpeciesIndex) * Avogadro; // m^-3 | ||
| if (!(ne > 0.0) || !std::isfinite(ne)) { | ||
| return 0.0; | ||
| } | ||
| const double E = electricField(); // V/m | ||
| if (!std::isfinite(E) || E == 0.0) { | ||
| return 0.0; | ||
| } | ||
| const double sigma = ElectronCharge * ne * mu_e; // S/m | ||
| return sigma * E * E; // W/m^3 | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think checking std::isfinite for each term is needed. The error should be caught when calling the function. We can check if any term is or smaller than zero and return zero..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right. This, along with lines 577-579 is a sort of debugging artifact, and I agree that it's now unnecessary looking back at it.
…ng single temperature
… tests g_eq_sum_gk_Xk
74dc550 to
c738296
Compare
speth
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, @mquiram, I think this is a good step towards making PlasmaPhase work more smoothly with other parts of Cantera.
I think the new equilibrate behavior makes sense, but I'd like to suggest making the implementation a little more generic. Instead of introducing the setLockTeToT method on PlasmaPhase, we could instead introduce a pair of virtual methods on the ThermoPhase class that are always called at the start / end of the equilibrium solver, for example beginEquilibrate and endEquilibrate. The equilibrium "lock" class would then just call this method for every phase, with the special PlasmaPhase behavior being implemented in its overrides of these methods. While there aren't currently any other uses for this, I could imagine other phase types implementing some special behavior during an equilibrium solve, for example skipping some dependent property lookups or adjusting some internal tolerances, so this feature might come in use again.
Likewise, I think we want to avoid having to do conditional dynamic_casts to PlasmaPhase within the reactor classes, and introduce a virtual method on the base ThermoPhase class that gets called no matter what (and returns 0 for most phase types). I'm not sure what the best name for this method would be -- something like intrinsicHeating, with Joule heating being one example.
| if (m_thermo->type() != "ideal-gas") { | ||
| /* if (m_thermo->type() != "ideal-gas") { | ||
| throw CanteraError("IdealGasConstPressureMoleReactor::initialize", | ||
| "Incompatible phase type '{}' provided", m_thermo->type()); | ||
| } | ||
| } */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than disabling this check, it would be better to make it allow both ideal-gas and plasma as the type() to avoid letting other ThermoPhase models through.
| if (!m_eedfSolver) { | ||
| throw CanteraError("PlasmaPhase::electronMobility", | ||
| "EEDF solver is not initialized."); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this case is impossible, given that m_eedfSolver is initialized in the PlasmaPhase constructor.
| if (m_electronEnergyDist.size() != m_nPoints | ||
| || m_electronEnergyDistDiff.size() != m_nPoints) { | ||
| writelog("PlasmaPhase::elasticPowerLoss: " | ||
| "EEDF not initialized, returning 0.\n"); | ||
| return 0.0; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this needs to be a bit more firm about when it does/doesn't work. If the Boltzmann-two-term mode is active, then an empty EEDF should trigger an update. And otherwise, calling this method should be an presumably be an error (like for electronMobility).
| rate += concentration(m_targetSpeciesIndices[i]) * | ||
| m_elasticElectronEnergyLossCoefficients[i]; | ||
| } | ||
| const double q_elastic = Avogadro * Avogadro * ElectronCharge * concentration(m_electronSpeciesIndex) * rate; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please try to stick to our style recommendation of 88 characters per line maximum.
| EXPECT_NEAR(g, phase->mean_X(gk), atol); | ||
| if (phase->type() == "plasma") { | ||
| // PlasmaPhase is a two-temperature, non-equilibrium model. The mixture Gibbs | ||
| // free energy is defined via g = h - T*s using the gas temperature T, while | ||
| // the electron chemical potential is defined using Te and pe. As a result, | ||
| // the single-temperature identity g = sum_k X_k * mu_k is not enforced for | ||
| // PlasmaPhase, so this particular consistency check is skipped. | ||
| GTEST_SKIP() << "PlasmaPhase: g = sum_k X_k * mu_k identity not enforced"; | ||
| } else { | ||
| // Standard single-temperature identity | ||
| EXPECT_NEAR(g, phase->mean_X(gk), atol); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the Gibbs free energy be calculated from the chemical potentials instead, using the species-specific temperature as is done for
| } | ||
|
|
||
| struct TeLockGuard { | ||
| std::vector<std::pair<PlasmaPhase*, double>> items; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to use the std:: prefix for vector or pair -- we have using directives for these and other common types in ct_defs.h.
| throw CanteraError("MultiPhase::equilibrate_MultiPhaseEquil", | ||
| "No convergence for T"); | ||
| } else if (XY == SP) { | ||
| TeLockGuard te_guard(*this); // also single-T during SP |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You may want to move this up to the more general MultiPhase::equilibrate method, as it will then be activated for both the MultiPhaseEquil (aka "Gibbs") solver and the VCS solver. You should probably also implement something on this front for the ChemEquil solver (aka "element potential").
| throw CanteraError("WeaklyIonizedGas::converge", "Convergence failed"); | ||
| throw CanteraError("WeaklyIonizedGas::converge", "Convergence failed; returning last iterate.\n"); | ||
| return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need for the unreachable return after throw. Also, watch the line length.
| double PlasmaPhase::cp_mole() const | ||
| { | ||
| return IdealGasPhase::cp_mole(); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this doesn't do anything other than what the base class does, there's no need for an explicit override. I do think the class docstring could use a bit more documentation about how this and the definitions for the other properties result in a consistent set of thermodynamic properties (or even what the definition of
|
|
||
| double PlasmaPhase::intEnergy_mole() const | ||
| { | ||
| std::vector<double> ubar(m_kk); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be worth having a temporary m_work array as a member of the class to avoid repeatedly allocating this vector.
Changes proposed in this pull request
Checklist
scons build&scons test) and unit tests address code coverage