-
-
Notifications
You must be signed in to change notification settings - Fork 349
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
[Species] Add molecular weight attribute #1266
[Species] Add molecular weight attribute #1266
Conversation
98ba137
to
1a720d8
Compare
Posted a question about the test failures on the UG: https://groups.google.com/g/cantera-users/c/mdNdCulK4gc/m/3G53KMDzAAAJ |
I think you need to implement a I also replied on the UG |
Can you explain more about why this is a necessary / useful feature? I don't quite understand what role it plays in implementing |
Thanks @speth! Good question. It will be useful to simplify sorting species in the CK output. I also think it's a logical place to keep the molecular weight... ideally, a species knows its own data. It's where I'd expect to find it if I had only a That said, one of my test failures is because I'm not handling custom elements right now. I think it would make sense to raise an error if a custom element is present and the species is not part of a phase. Then the phase can set the molecular weight when the species is added. What do you think? |
@speth and @bryanwweber ... I actually agree that having Per implementation, I see that custom elements add a wrinkle to what I said on the UG. My preferred solution here would still be to strengthen the C++ constructor for
I haven't looked into details about custom elements. As these are just computational entities/placeholders, they presumably don't need a weight, so there isn't an issue? Regarding species that contain (custom or regular) elements that aren't part of the phase, this is absolutely an error, and can be handled separately from the instantiation. |
I'm unclear on what the extra constructor is supposed to do differently --
Don't you have access to a
That's one use case. Another is handling isotopes, where of course you do want to include the different value of the atomic weight.
This is already handled, of course. The default behavior for "regular" elements is to just add them to the phase, but this can be changed by calling one of
So how do you create such a |
Ugh. That is correct - didn't track down the definitions cantera/include/cantera/base/ct_defs.h Lines 172 to 180 in 9573e6b
In this case, I honestly think that there is one So ... no new constructor needed. Good point about isotopes, and it frankly would have been surprising if there hadn't already been exception handling for undefined elements. Either way, my personal preference here would be to strengthen the constructor for |
Yes, but it feels strange to write: solution = ct.Solution(...)
species = {s.name: s for s in solution.species()}
dict(sorted(species.items(), key=lambda s: solution[s[0]].molecular_weights))
# or
dict(sorted(species, key=lambda s: solution.molecular_weight(solution.species_index(s[0])))) or something like that, when it could be: sorted(solution.species(), key=operator.attrgetter("molecular_weight")) since, at least in
I meant throw if someone tries to read/get the molecular weight when the |
If you want to just let the |
@bryanwweber ... I had the exact same issue (minus resorting to solution = ct.Solution(...)
species = {s.name: s for s in solution.species()}
dict(sorted(species.items(), key=lambda s: solution[s[0]].molecular_weights)) while wanting to implement a dictionary comprehension. @speth ... I still don't fully understand what the hangup is about phases needing to set molecular weights (instead of species themselves). Can you direct me to a YAML input file where this shows up? (I mention YAML and not C++ here intentionally) |
@speth I think it would be useful to be able to get the molecular weight of an unattached species, provided it used only the elements/isotopes defined in I think this can be resolved by introducing a new/modified constructor as @ischoegl suggested, or perhaps a setter/getter method pair... The question to me is what the signature should look like to be most clear. Or, put another way, how can Maybe there isn't a way to resolve this satisfactorily, but I hope there is. |
Here is an existing example from the test suite that would lead to errors/inconsistencies with some of the implementations proposed here. Phase definition: cantera/test/data/ideal-gas.yaml Lines 31 to 38 in 9573e6b
where the referenced element definitions are: cantera/test/data/test_subdir/species-elements.yaml Lines 3 to 7 in 9573e6b
|
@speth ... thank you, this sheds some light! This is an interesting case. But the larger question here is: what do you do if you have more than one isotope? ... One alternative would be to specify the isotope further down in the definition of the species, i.e. cantera/test/data/ideal-gas.yaml Lines 139 to 149 in 9573e6b
for example by adding a key for molecular weight. (which imho would be a cleaner solution to this conundrum). I believe that would allow for the co-existence of multiple isotopes of the same element. |
If you take my suggestion of letting
|
While I do not like the That said, what @speth suggests is exactly how things are usually implemented based on our coding style recommendations (no surprises!). I only have one friendly amendment: initialize it to a negative value, as it is an easier sentinel value to handle. |
@ischoegl - that test case admittedly isn't super exciting. It uses just The way to have multiple isotopes of an element would be to give them distinct names, like I don't think you want to just store the molecular weight in the species definition (this seems like it's a long way from the original topic of this PR...), because we still want reactions and equilibrium calculations to preserve isotopic abundances. |
@speth ... I agree.
That makes sense (of course), which leads to a compromise: calculate the molecular weight if it's listed in |
The test may be a bit contrived, but being able to do this has been a feature in the CTI format since Cantera 1.6, so it's better to test it than not. I'd agree that overriding the default element weights is kind of a niche feature, but I'm not ready to assert that there's no use case for it just so a |
Ok. As mentioned above:
At the same time, with CTI gone we could revisit this historical feature (which I don’t think is good practice). I just don’t like it. If anything, switching out an element at the phase level should not be viewed as an ambiguity, but a deliberate choice by the user, where changing values are to be expected. |
What ambiguity is there in the existing implementation? You have to be quite explicit in the phase definition to use alternative element definitions, as shown in the example I linked to before: - name: element-remote
thermo: ideal-gas
elements:
- default: [N, O]
- test_subdir/species-elements.yaml/isotopes: [Ar]
species: [O2, NO, N2, AR]
note: replace Argon with custom element from a different file
state: {T: 900.0, P: 5 atm, Y: {O2: 0.4, N2: 0.4, AR: 0.2}} |
I agree that there is no ambiguity. What I mean here is that on principle, there shouldn't be an issue with a default value (as created by a PS: I am stopping here, as I'm ok with any path taken at this point - it's ultimately not a big enough issue to me |
@speth / @ischoegl I updated the implementation to remove code from FWIW, I think having |
d9a5e55
to
8067877
Compare
Codecov Report
@@ Coverage Diff @@
## main #1266 +/- ##
==========================================
+ Coverage 68.02% 68.04% +0.02%
==========================================
Files 314 314
Lines 41966 42007 +41
Branches 16863 16880 +17
==========================================
+ Hits 28547 28584 +37
Misses 11166 11166
- Partials 2253 2257 +4
📣 Codecov can now indicate which changes are the most critical in Pull Requests. Learn more |
8067877
to
918d14b
Compare
@speth / @ischoegl I think I need to add some more tests here to address the coverage, but can you guys take a look at the C++ changes? I think I got things correct, but I'd be happy to have some advice on improvements, especially with respect to improving the memory usage of the new functions I've added. |
918d14b
to
9d8a815
Compare
I think I fixed the pre-Python 3.9 failures with Edit: The helper functions are necessary because using a list/tuple comprehension with the |
3d868ac
to
78c7591
Compare
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 the updates, @bryanwweber. I had a few more suggested updates.
bb3f91d
to
9d4b0f1
Compare
9d4b0f1
to
e6d3fad
Compare
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.
HI @bryanwweber ... thanks for working on this, as I believe that this is a nice addition. I have a few suggestions that should simplify a couple of things.
One thing I believe could be improved in this context (although I do not suggest to add to this PR) is the handling of modified element or isotope weights - while this can be done (see the element-override
example), it appears to exist completely outside of the element handler.
The type is more properly the size_t type since it's a size not just an integer.
The methods added here get the element symbols and names as vectors of strings and a map of the element symbols and names to the atomic weights. This is simplified by converting the weight tables to std::vectors instead of C-style vectors.
The molecular weight is computed for each species when the molecular weight is accessed on the species or added to a phase. The Phase private attribute m_mwt is not changed.
Co-authored-by: Ray Speth <[email protected]>
Since setting the species molecular weight can throw, all modifications to Phase member variables should be done after calling Species::setMolecularWeight() so that the Phase instance is not left in an inconsistent state.
If the species molecular weight is undefined when retrieved, the weight is computed in the getter. This simplifies the logic in the setter, which now only has to worry about checking the value, not computing the value.
e6d3fad
to
24021f8
Compare
24021f8
to
1e41410
Compare
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.
Looks good to me. I did notice some really minor formatting issues that are trivially easy.
Co-authored-by: Ingmar Schoegl <[email protected]>
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.
LGTM
The molecular weight is computed for each species when it is created.
The Phase private attribute m_mwt is not changed.
This will be useful in general, but specifically for #1185. This does not need to go in for 2.6.
Checklist
scons build
&scons test
) and unit tests address code coverage