-
-
Notifications
You must be signed in to change notification settings - Fork 348
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
Add get/set equivalenceRatio/mixtureFraction functions #851
Conversation
Codecov Report
@@ Coverage Diff @@
## main #851 +/- ##
==========================================
+ Coverage 70.95% 71.11% +0.16%
==========================================
Files 376 376
Lines 45889 46201 +312
==========================================
+ Hits 32560 32858 +298
- Misses 13329 13343 +14
Continue to review full report at Codecov.
|
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 for submitting this pull request. In general, I think this will be a useful addition.
One concern I have is the sheer number of new functions introduced here, especially in the C++ interface. What I think would help would be to use an argument to switch between molar and mass basis, rather than having separate function names for each. This could just be an optional basis
argument, which would mirror what you've done in the Python interface.
AUTHORS
Outdated
@@ -18,7 +18,7 @@ Steven DeCaluwe (@decaluwe), Colorado School of Mines | |||
Vishesh Devgan (@vdevgan) | |||
Thomas Fiala (@thomasfiala), Technische Universität München | |||
David Fronczek | |||
@g3bk47 | |||
Thorsten Zirwes, Karlsruhe Institute of Technology |
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.
We generally include the GitHub handle for contributors who have one, i.e.
Thorsten Zirwes, Karlsruhe Institute of Technology | |
Thorsten Zirwes (@g3bk47), Karlsruhe Institute of Technology |
but it's up to you if you don't want to include it.
src/thermo/ThermoPhase.cpp
Outdated
auto iC = elementIndex("C"); | ||
auto iS = elementIndex("S"); | ||
auto iO = elementIndex("O"); | ||
auto iH = elementIndex("H"); |
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.
For very simple types like size_t
and double
, I would suggest using the type names explicitly rather than auto
.
src/thermo/ThermoPhase.cpp
Outdated
for (size_t i=0; i!=m_kk; ++i) | ||
{ |
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.
A couple of style notes applicable here and elsewhere:
for (size_t i=0; i!=m_kk; ++i) | |
{ | |
for (size_t i = 0; i != m_kk; ++i) { |
The opening brace should be on the same line for if
statements as well.
include/cantera/thermo/ThermoPhase.h
Outdated
//! Set the mixture composition according to the equivalence ratio. | ||
//! Fuel and oxidizer compositions are specified by their mass fractions (do | ||
//! not need to be normalized). Pressure is kept constant. | ||
//! Elements C, S, H and O are considered for the oxidation. | ||
// | ||
// | ||
/*! | ||
* @param phi equivalence ratio | ||
* @param fuelComp mass fractions of species in the fuel | ||
* @param oxComp mass fractions of species in the oxidizer | ||
*/ |
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.
To get Doxygen to do the right thing, the formatting for the longer comment blocks like this should be
//! One or two line
//! summary.
/*!
*! (extended description, including parameters)
*/
include/cantera/thermo/ThermoPhase.h
Outdated
void setMixtureFraction_X(double mixFrac, const double* fuelComp, const double* oxComp); | ||
|
||
//! @copydoc ThermoPhase::setMixtureFraction_X(double mixFrac, const double* fuelComp, const double* oxComp) | ||
void setMixtureFraction_X(double mixFrac, const vector_fp& fuelComp, const vector_fp& oxComp); |
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.
Cantera doesn't generally provide functions which take vector_fp&
as arguments -- users are expected to use the functions which take simple double*
. So I think this overload and the other similar ones should be removed. The string
and compsitionMap
ones are of course fine.
src/thermo/ThermoPhase.cpp
Outdated
throw CanteraError("ThermoPhase::getMixtureFraction_Y", | ||
"fuel and oxidizer have the same composition"); | ||
|
||
auto mf = ( 2.0*(Z_C -Z_Co) + 0.5*(Z_H -Z_Ho) + 2.0*(Z_S -Z_So) - (Z_O -Z_Oo) ) |
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.
auto mf = ( 2.0*(Z_C -Z_Co) + 0.5*(Z_H -Z_Ho) + 2.0*(Z_S -Z_So) - (Z_O -Z_Oo) ) | |
auto mf = (2.0*(Z_C - Z_Co) + 0.5*(Z_H - Z_Ho) + 2.0*(Z_S - Z_So) - (Z_O - Z_Oo)) |
src/thermo/ThermoPhase.cpp
Outdated
// mass fractions of fuel and oxidizer | ||
vector_fp massFractions(m_kk * 2); |
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.
Using a single vector to store both the fuel and oxidizer compositions is an unnecessary complication.
src/thermo/ThermoPhase.cpp
Outdated
// mean molecular weights of fuel and oxidizer | ||
auto rmmw_f = std::inner_product(fuelComp, fuelComp+m_kk, molecularWeights().data(), | ||
0.0, std::plus<double>(), std::divides<double>()); | ||
auto rmmw_o = std::inner_product(oxComp, oxComp+m_kk, molecularWeights().data(), 0.0, | ||
std::plus<double>(), std::divides<double>()); |
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 I would prefer the readability of the straightforward loop for doing this calculation.
src/thermo/ThermoPhase.cpp
Outdated
auto YtoX = [=](const double& Xk, const double& Mk){return Xk/(rmmw_f*Mk);}; | ||
|
||
// compute mole fractions for fuel and oxidizer | ||
std::transform(fuelComp, fuelComp+m_kk, molecularWeights().data(), X.data(), YtoX); | ||
std::transform(oxComp, oxComp+m_kk, molecularWeights().data(), X.data()+m_kk, YtoX); |
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 I would prefer the readability of the straightforward loop for doing this calculation.
include/cantera/thermo/ThermoPhase.h
Outdated
* @param returns equivalence ratio | ||
*/ | ||
|
||
double getEquivalenceRatio() const; |
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.
So this is essentially an implementation of the previous definition of getEquivalenceRatio
, is that correct? In that case, is it necessary or useful?
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.
This function is the special case of assuming that fuel and oxidizer are pure (what is sometimes called "local equivalence ratio", because it only considers the locally available oxygen and required oxygen and is therefore independent of fuel or oxidizer compositions). I introduced this function for convenience, because you can just write gas.getEquivalenceRatio()
instead of specifying a concrete oxidizer and fuel composition like gas.getEquivalenceRatio("H2:1","O2:1")
, where the actual values do not matter as long as the compositions only contain fuel and oxidizer elements, respectively.
In the python interface, I solved this by defaulting the oxidizer and fuel compositions to None
. However, defaulting the compositionMap& oxComp
to compositionMap{}
or double* oxComp
to nullptr
feels a but clunky in the C++ interface. I could rename the function to getLocalEquivalenceRatio
, but this might be more confusing. What do you think?
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 what you have here makes sense. Maybe it would help to add a suggestion to use the versions that take fuel and oxidizer compositions if either of these conditions for the fuel or oxidizer isn't met.
Thanks for the comments. I will make the requested changes. Just a few questions:
|
Yes, I think the "old" definition can be deprecated. I agree that bringing the "old" definition into C++ is not worthwhile, so we will just have to deal with the discrepancy for this version.
For the C++ interface, probably an enum class ThermoBasis
{
mass,
molar
};
That sounds like an interesting generalization, and having the option of getting the Bilger mixture fraction for the counterflow flame would be nice. I like the idea of doing this with an extra, optional argument as you've suggested. |
I think I addressed all requested changes in the most recent commits. Just one comment: cantera/interfaces/cython/cantera/thermo.pyx Lines 8 to 10 in d02f2a7
ThermoBasis could be changed to use the ThermoBasisType definition so that everything is named ThermoBasis . But I didn't want to change the existing code in this PR.
|
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 for providing the updates, I think they have helped a lot. I have some more comments, but I think most of these are relatively minor issues.
include/cantera/thermo/ThermoPhase.h
Outdated
/*! | ||
* @name CONSTANTS - Specification of the input mixture composition | ||
*/ | ||
//@{ |
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.
Despite the error in the existing code, there should only be one block (delimited by @{
and @}
) with the name "constants", and this enum should go inside that block.
There are still some inconsistencies, good catch. I will take care of making all requested changes ASAP. To address your questions:
|
Ah yes, I see your point about the stoichiometric air fuel ratio, and I realize now that the documentation does indeed say that it provides the AFR on a molar basis. Like the mixture fraction, though, I think that the mass-based definition is the one more often used. If you switched this to use the mass-based definition, you would just need to swap mole fractions for mass fractions in the equivalence ratio methods, and they will work the same way. |
In addition to the requested changes, I introduced two helper functions on the C++ side ( Regarding the doxygen comment for |
One python test in the CI has failed ("test_ignition_delay_sensitivity").
When I look at the result of
I get e.g. for the mass fraction of H2:
When I calculate this by hand, the correct mass fraction should be
which is pretty much the same. So maybe someone else should double check why this test fails, before merging the PR. |
I just rebased this onto the current main branch, and didn't get any test failures locally. Hopefully, it will pass the checks on the CI servers as well. |
The failures seem to be on macOS only... I can take a look tomorrow now that the conda packages seem sorted out |
The test failure persists on macOS. At least, the "wrong" result seems so to be always the same numerical value (across all different python versions and also from the last CI run), which might make debugging easier. Is there a way to get an image of the macOS VM (if it is a VM), so I can help debugging? |
I can't reproduce this locally on my mac. I'm going to push some debugging statements to this branch to see what the CI is doing. |
5de2dc3
to
f41fdaf
Compare
I pushed a commit to tighten the tolerances on the sensitivity variables, which at least on my computer gives better agreement between the finite difference and sensitivity coefficient-based calculations in this test (worst relative agreement is around 1e-3, which is much less than the test tolerance of 5e-2). Hopefully this will be enough to pass the CI tests. The problem seems to stem from the fact that the default tolerances on the sensitivity variables is fairly loose (1e-4), but tightening them has a tendency to lead to integration failures. I suspect this is another reminder that we need to take another look at the details of how we solve the equations for the sensitivities, since it's not as efficient or robust as I think should be possible. But that's obviously well outside the scope of this PR. |
Thanks @speth! Feel free to drop my commit with the debug statements (either you or @g3bk47).
Can you file an issue about this so we don't forget? |
The test_ignition_delay_sensitivity test needs tighter intergrator tolerances on the sensitivity coefficients in order to give results that reliably match the finite difference approach on all platforms.
The old version of the sample was using a strange definition for the composition of air which corresponded to neither of the typical approximations, for example "O2: 1.0, N2: 3.76" or "O2: 0.21, N2: 0.79".
@bryanwweber I documented the issues I've observed with sensitivity analysis in Cantera/enhancements#55. |
I accidentally deleted the original pull request. The exact same changes are provided again in this PR. The original discussion can be found here: #811