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

[Thermo] Adds phaseOfMatter function #722

Merged
merged 9 commits into from
Jan 2, 2020

Conversation

bryanwweber
Copy link
Member

@bryanwweber bryanwweber commented Oct 6, 2019

Changes proposed in this pull request:

  • phaseOfMatter() returns the mechanical phase (liquid, vapor, etc.) of the matter in the Phase.

Not sure if this will be more generally useful. I was using it to help debug #721, but added it here to the PureFluidPhase instead of WaterSSTP because I don't want to touch WaterSSTP with a 39.5-foot pole. I could add a similar function to WaterSSTP though, if desired.

@codecov
Copy link

codecov bot commented Oct 6, 2019

Codecov Report

Merging #722 into master will increase coverage by 0.01%.
The diff coverage is 63.09%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #722      +/-   ##
==========================================
+ Coverage    71.4%   71.41%   +0.01%     
==========================================
  Files         372      372              
  Lines       43863    43904      +41     
==========================================
+ Hits        31320    31355      +35     
- Misses      12543    12549       +6
Impacted Files Coverage Δ
include/cantera/thermo/PureFluidPhase.h 84.61% <ø> (ø) ⬆️
include/cantera/thermo/ThermoPhase.h 28.28% <100%> (+0.95%) ⬆️
include/cantera/thermo/MolalityVPSSTP.h 100% <100%> (ø) ⬆️
test/thermo/thermoFromYaml.cpp 100% <100%> (ø) ⬆️
include/cantera/thermo/LatticeSolidPhase.h 48.38% <100%> (+3.55%) ⬆️
include/cantera/thermo/IdealGasPhase.h 97.05% <100%> (+0.18%) ⬆️
src/thermo/PureFluidPhase.cpp 59.63% <24.24%> (+0.51%) ⬆️
include/cantera/thermo/IdealSolnGasVPSS.h 88.88% <75%> (-11.12%) ⬇️
src/thermo/ThermoPhase.cpp 68.66% <86.84%> (+0.67%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 149a397...2bf1a7d. Read the comment docs.

Copy link
Member

@ischoegl ischoegl left a comment

Choose a reason for hiding this comment

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

Minor comments.

include/cantera/thermo/ThermoPhase.h Outdated Show resolved Hide resolved
interfaces/cython/cantera/_cantera.pxd Outdated Show resolved Hide resolved
@bryanwweber
Copy link
Member Author

@ischoegl I tried requesting a re-review from you but it's not working 😖 Anyways, your comments (and @speth) are appreciated when you have some time! Thanks

@ischoegl
Copy link
Member

ischoegl commented Dec 3, 2019

@bryanwweber ... sure. Before leaving more detailed feedback, I have a philosophical question. I am very much in favor of using small utility functions like getPhase to act as quick reminders / sanity checks of what phases are actually doing or representing (especiallly for some of the less commonly used phases): in the spirit of #652 this creates self-documenting code. (I have similar objectives for isCompressible and isPure in #720)

My main concern of this PR is that it appears to be geared towards a very special case, rather than being applicable to any thermo phase. Would it make sense to implement getPhase across the board, and return an actual phase rather than the NotImplementedError? E.g. return one of the following: gas, liquid, solid, gas-liquid-mix, liquid-solid-mix, gas-solid-mix, three-phase, supercritical (i.e. start with combinations for a thermodynamic simple compressible substance; some may not apply to what's currently implemented). In most cases, the getPhase routine would return a hard-coded string.

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.

I like the idea of at least making room to implement this for most ThermoPhase objects, which would suggest using names that aren't particular to the pure fluid equation of state model. @ischoegl's suggestions of gas, liquid, and gas-liquid-mix seem reasonable to me.

I wouldn't necessarily suggest adding implementations for all of the other ThermoPhase types here. I suspect that we'll find some cases where there's not a clear choice of what to return. The one that comes to mind immediately is IdealSolidSolnPhase, which, despite the name, is equally applicable to solids and liquids, and has no information on which kind of phase it is currently implementing.

I think it would make sense to add this information to the output of PureFluidPhase::report. If we wanted to add it to the report for all phases, we could change the default implementation to just return unspecified.

include/cantera/thermo/PureFluidPhase.h Outdated Show resolved Hide resolved
include/cantera/thermo/ThermoPhase.h Show resolved Hide resolved
@bryanwweber
Copy link
Member Author

@ischoegl

Would it make sense to implement getPhase across the board, and return an actual phase rather than the NotImplementedError?

I think this will make sense eventually, and like @speth I think the names you've suggested are very good. However, at this point, I think it is better to have only one phase where this works, and we know that it works. Since, as @speth notes, for many phases it isn't clear what should be returned, I don't want to dig into adding that kind of functionality here, I think that could be done as a general cleanup/improvement of each phase individually.

@ischoegl
Copy link
Member

ischoegl commented Dec 3, 2019

Since, as @speth notes, for many phases it isn't clear what should be returned, I don't want to dig into adding that kind of functionality here, I think that could be done as a general cleanup/improvement of each phase individually.

I can certainly see this perspective. Is there a good way to hit a middle ground? I.e. add the information where it is evident (i.e. we know that it works), and defer the tricky ones to #652 (which btw miraculously disappeared).

@speth
Copy link
Member

speth commented Dec 3, 2019

defer the tricky ones to #652 (which btw miraculously disappeared).

We just created a new repository so that we could have a separate issue tracker for some of these bigger-picture enhancements to Cantera, and I moved #652 there (now Cantera/enhancements#6). If you use the old URL (https://github.com/Cantera/cantera/issues/652) it will redirect, but unfortunately it looks like the automatic links just using the issue number are now broken.

@ischoegl
Copy link
Member

ischoegl commented Dec 3, 2019

I moved #652 there (now Cantera/enhancements#6)

Ah. I noticed this new repo, and start to see what it's for. Makes sense. It'll be interesting to see how this evolves.

@decaluwe
Copy link
Member

decaluwe commented Dec 3, 2019

@ischoegl the idea is that this would be a place to document longer-term development goals, projects, etc, separate from bugs and quicker fixes in the main repo issues. So that people know what others are working on, what is coming down the pike, etc., and also a place to make those types of requests. Hopefully, this will eventually be a place to host a clearer development roadmap.

@ischoegl
Copy link
Member

ischoegl commented Dec 3, 2019

@decaluwe ... thanks for the info. It may be good to have a template that illustrates the mechanism for how enhancements can get merged to master. I.e. is this just a fork or something entirely separate?

This discussion is admittedly off-topic, but my main point was that some incremental improvements in line with (former) #652 could be applied whenever appropriate.

@speth
Copy link
Member

speth commented Dec 3, 2019

@ischoegl I'm not sure I understand what you mean by "a template that illustrates the mechanism for how enhancements can get merged to master" -- that process will still be a PR to Cantera/cantera, and there's no requirement that anything needs to originate in enhancements . If you have more questions / suggestions about the enhancements repository, maybe it would be best to create an issue there for the meta-discussion. Obviously what's there now is just a seed, not a fully-realized system.

Copy link
Member

@ischoegl ischoegl left a comment

Choose a reason for hiding this comment

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

Minor comments per discussion.

include/cantera/thermo/ThermoPhase.h Outdated Show resolved Hide resolved
include/cantera/thermo/PureFluidPhase.h Outdated Show resolved Hide resolved
@bryanwweber
Copy link
Member Author

Here are the names I came up with:

  • supercritical
  • gas
  • liquid
  • solid
  • solid-liquid-mix
  • solid-gas-mix
  • liquid-gas-mix
  • solid-liquid-gas-mix
  • unspecified

The last one is 20 characters wide, whereas the current fields in the report() output are 12 characters wide. Any preferences for how to handle this? The output looks nice for names shorter than the 12 characters:

  gri30:

       temperature             300  K
          pressure          101325  Pa
           density       0.0818939  kg/m^3
  mean mol. weight           2.016  amu
             phase     unspecified

  water:

       temperature             300  K
          pressure          101325  Pa
           density         996.633  kg/m^3
  mean mol. weight          18.016  amu
    vapor fraction               0
             phase          liquid

Not so much for the ones that are longer:

  water:

       temperature             300  K
          pressure         3528.21  Pa
           density        0.051041  kg/m^3
  mean mol. weight          18.016  amu
    vapor fraction             0.5
             phase    liquid-gas-mix

@speth
Copy link
Member

speth commented Dec 6, 2019

This is a bit more dramatic change, but what about giving up on right aligning the numbers, given that none of them are comparable or have a similar number of digits to the right of the decimal point?

  water:

       temperature  300 K
          pressure  3528.21 Pa
           density  0.051041 kg/m^3
  mean mol. weight  18.016 amu
    vapor fraction  0.5
   phase of matter  liquid-gas-mix

@bryanwweber bryanwweber changed the title [Thermo] Adds getPhase function [Thermo] Adds phaseOfMatter function Dec 6, 2019
@bryanwweber bryanwweber force-pushed the add-get-phase branch 2 times, most recently from 2cb6b25 to bf949cc Compare December 6, 2019 18:11
@bryanwweber
Copy link
Member Author

bryanwweber commented Dec 6, 2019

@speth @ischoegl I made a bunch of changes in bf949cc to make the strings used in the report methods composable. I'm not sure it improved readability and would appreciate your opinions.

One of the reasons I wanted to use variables to format the strings is in anticipation of new and/or different properties that might be reported for different phase types.

@speth
Copy link
Member

speth commented Dec 6, 2019

@speth @ischoegl I made a bunch of changes in bf949cc to make the strings used in the report methods composable. I'm not sure it improved readability and would appreciate your opinions.

One of the reasons I wanted to use variables to format the strings is in anticipation of new and/or different properties that might be reported for different phase types.

Hmm, that's interesting, but I agree that this creates some significant readability challenges. I find the doubly-substituted format strings to be particularly mind-bending. While making the report method more flexible in terms of the properties displayed is a good idea, how important is it for the field widths to be variable? What about just completing the separation of the definitions of the format strings from their use, e.g.

string two_property = "{:>18}   {:12.5g}   {:12.5g}  {}\n";
...
format_to(b, two_property, "enthalpy", enthalpy_mass(), enthalpy_mole(), "J");

@bryanwweber
Copy link
Member Author

@speth OK, that makes sense. One of the things I'd like to do is keep the width of the first field as a variable, since I anticipate that's one of the things most likely to change if we add new properties, if a property's name is too long, we want to support longer species names, etc. That's actually how 0ce4f1b is implemented, and combined with your suggestion, I think it could still be pretty readable.

Another thing I forgot to ask... in 4dba1d1 I switched X and Y in the report, a defect identified by @rwest some time ago. That's obviously a much more significant change than the other stuff, so I'd appreciate opinions on that too.

@speth
Copy link
Member

speth commented Dec 6, 2019

@speth OK, that makes sense. One of the things I'd like to do is keep the width of the first field as a variable, since I anticipate that's one of the things most likely to change if we add new properties, if a property's name is too long, we want to support longer species names, etc. That's actually how 0ce4f1b is implemented, and combined with your suggestion, I think it could still be pretty readable.

That looks fine to me. Limited use of the variable field width syntax seems fine. It's really just the case of using fmt::format to generate a format string that ends up being unreadable.

One minor issue I noticed is that this leaves trailing whitespace on the line which reads:

                         1 kg          1 kmol   

Another thing I forgot to ask... in 4dba1d1 I switched X and Y in the report, a defect identified by @rwest some time ago. That's obviously a much more significant change than the other stuff, so I'd appreciate opinions on that too.

I'm 👍 on this change. I had been hoping that @rwest would submit a fix for this himself. Unsurprisingly, there are some test failures associated with this change that need to be updated.

@ischoegl
Copy link
Member

ischoegl commented Dec 6, 2019

So we've got the old output as

In [3]: gas()                                                                   

  gri30:

       temperature             300  K
          pressure          101325  Pa
           density       0.0818891  kg/m^3
  mean mol. weight         2.01588  amu

                          1 kg            1 kmol
                       -----------      ------------
          enthalpy           26470        5.336e+04     J
   internal energy     -1.2109e+06       -2.441e+06     J
           entropy           64914        1.309e+05     J/K
    Gibbs function     -1.9448e+07        -3.92e+07     J
 heat capacity c_p           14312        2.885e+04     J/K
 heat capacity c_v           10187        2.054e+04     J/K

                           X                 Y          Chem. Pot. / RT
                     -------------     ------------     ------------
                H2              1                1         -15.7173
     [  +52 minor]              0                0

vs the proposed version

In [3]: gas()

  gri30:

       temperature   300 K
          pressure   1.0133e+05 Pa
           density   0.081894 kg/m^3
  mean mol. weight   2.016 amu
             phase   unspecified

                         1 kg          1 kmol   
                     ------------   ------------
          enthalpy          26469          53361  J
   internal energy    -1.2108e+06     -2.441e+06  J
           entropy          64910     1.3086e+05  J/K
    Gibbs function    -1.9447e+07    -3.9204e+07  J
 heat capacity c_p          14311          28851  J/K
 heat capacity c_v          10187          20536  J/K

                          Y              X         Chem. Pot. / RT
                     ------------   ------------   ---------------
                H2              1              1           -15.717
     [  +52 minor]              0              0  

What about a compromise, where an additional newline separates the state and other currently not shown information is added, i.e.

  gri30:

      thermo model   IdealGas
    kinetics model   Gas
   transport model   Mix
   phase of matter   unspecified

       temperature             300  K
          pressure          101325  Pa
           density       0.0818891  kg/m^3
  mean mol. weight         2.01588  amu

                         1 kg          1 kmol   

@rwest
Copy link
Member

rwest commented Dec 6, 2019

I had been hoping that @rwest would submit a fix for this himself.

There’s a lot of things I hope that @rwest will do some day. One can always hope. Fortunately he’s typically relieved more than offended when people give up waiting.

@bryanwweber
Copy link
Member Author

@rwest

“ For mixtures of gases, IUPAC recommends the letter y” for mole fraction according to Wikipedia

I always wondered why my thermo book did this. Fortunately, it should now be much easier to be explicit here, will happily update!

@ischoegl What about putting the extra information behind a flag that's default False? I don't think most people will need that information most of the time. As such, I'd prefer to keep the phase of matter with the rest of the state-defining information (good call on phase of matter though).

@speth I'll look into those EOL spaces on the header line. And yes, the regression tests... well, I didn't get to them yet 😄

@ischoegl
Copy link
Member

ischoegl commented Dec 6, 2019

@rwest

“ For mixtures of gases, IUPAC recommends the letter y” for mole fraction according to Wikipedia

ugh, yes (which has been aggravating in teaching). I'd still suggest to stick with Kee's notation, as everything else in Cantera uses Y for mass fraction and X for mole fractions

@rwest
Copy link
Member

rwest commented Dec 6, 2019

Oh, I wasn’t suggesting we switch to IUPAC (just perhaps also label it “mass fraction”)

@ischoegl
Copy link
Member

ischoegl commented Dec 6, 2019

@bryanwweber ... the formatting was just a suggestion. I have already added Solution.composite to summarize the make-up of a Solution object, which will yield the same information. I.e. I'm fine with whatever.

@ischoegl
Copy link
Member

ischoegl commented Dec 6, 2019

Alright. Going back to the original issue (with an insufficient column width), why not just expanding it to 15 characters? Overall, this still stays below the 80 character line length recommendation, plus allows to add mole fraction and mass fraction column labels (per @rwest's suggestion), i.e.

gri30:

       temperature               300  K
          pressure            101325  Pa
           density         0.0818891  kg/m^3
  mean mol. weight           2.01588  amu
   phase of matter       unspecified

                                1 kg              1 kmol   
                     ---------------     ---------------
          enthalpy             26469               53361  J
   internal energy       -1.2108e+06          -2.441e+06  J
           entropy             64910          1.3086e+05  J/K
    Gibbs function       -1.9447e+07         -3.9204e+07  J
 heat capacity c_p             14311               28851  J/K
 heat capacity c_v             10187               20536  J/K

                     mass fraction Y     mole fraction X     Chem. Pot. / RT
                     ---------------     ---------------     ---------------
                H2                 1                   1             -15.717
     [  +52 minor]                 0                   0  

PS: the only phase of matter that won't align nicely with 15 characters is thus solid-liquid-gas-mix, which is (a) exceedingly unlikely due to numerics, and (b) could be renamed to triple-point (I’m also not aware of a model that supports it).

@bryanwweber
Copy link
Member Author

bryanwweber commented Dec 7, 2019

Here's where I've landed now:


  gri30:

       temperature   300 K
          pressure   1.0133e+05 Pa
           density   0.081894 kg/m^3
  mean mol. weight   2.016 amu
             phase   unspecified

                         1 kg          1 kmol
                     ------------   ------------
          enthalpy          26469          53361  J
   internal energy    -1.2108e+06     -2.441e+06  J
           entropy          64910     1.3086e+05  J/K
    Gibbs function    -1.9447e+07    -3.9204e+07  J
 heat capacity c_p          14311          28851  J/K
 heat capacity c_v          10187          20536  J/K

                     mass frac. Y   mole frac. X   Chem. Pot. / RT
                     ------------   ------------   ---------------
                H2              1              1           -15.717
     [  +52 minor]              0              0
  1. I actually prefer the left-aligned numbers in the state-definition information. It's not a strong preference though, I'm willing to be convinced to restore the original alignment.
  2. I think Chem. Pot should probably be lower case
  3. @speth the spaces at the end of that line are unavoidable without trimCopy()ing (or another means to trim) the string, since the 1 kmol is centered in a field of width 12. Likewise, there are extra spaces at the end of the "minor" line, due to the missing "units" field there.
  4. I haven't added the optional additional information yet.

@ischoegl
Copy link
Member

ischoegl commented Dec 7, 2019

@bryanwweber ... I think any solution will work, but still believe that the old right-adjusted way is quicker to parse visually (also, it is consistent with the specific properties block right underneath)

Regarding chem. potential I agree that lowercase is more consistent. For trailing white space, right adjusting 1 kmol looks ok also. These are just 2 cents ...

PS: any opinions on replacing amu by kg/kmol, as the former is not clearly SI (and had several changes in definition over the years)?

format_to(b, one_property, "density", name_width, density(), "kg/m^3");
format_to(b, one_property, "mean mol. weight", name_width, meanMolecularWeight(), "amu");
format_to(b, "{:>{}} {:15.6g}\n", "vapor fraction", name_width, vaporFraction());
format_to(b, "{:>{}} {:>15}\n", "phase", name_width, phaseOfMatter());
Copy link
Member

Choose a reason for hiding this comment

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

Should this be "phase of matter"?

@bryanwweber
Copy link
Member Author

Here's the format I finished with:

  gri30:

       temperature   300 K
          pressure   1.0133e+05 Pa
           density   0.081894 kg/m^3
  mean mol. weight   2.016 kg/kmol
   phase of matter   unspecified

                          1 kg             1 kmol
                     ---------------   ---------------
          enthalpy             26469             53361  J
   internal energy       -1.2108e+06        -2.441e+06  J
           entropy             64910        1.3086e+05  J/K
    Gibbs function       -1.9447e+07       -3.9204e+07  J
 heat capacity c_p             14311             28851  J/K
 heat capacity c_v             10187             20536  J/K

                      mass frac. Y      mole frac. X     chem. pot. / RT
                     ---------------   ---------------   ---------------
                H2                 1                 1           -15.717
     [  +52 minor]                 0                 0

I've now updated all the regression tests, so hopefully everything passes this time!

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.

I'm satisfied with the revised report() format. I wish the code to generate it were a little less cumbersome, but that seems to be how it goes with string formatting code most of the time, and we can always come back to this later.

I think if we're adding a phase of matter field to the report, implementations of that method for at least the easy and commonly-used phases need to be added at this time. It's okay if there are a few complicated cases that are deferred until later.

src/thermo/PureFluidPhase.cpp Outdated Show resolved Hide resolved
@bryanwweber
Copy link
Member Author

@speth I was only able to determine definite phases for IdealGasPhase, IdealSolnGasVPSS (for the m_idealGas case), and LatticeSolid. Were there others you were thinking of?

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.

As far as other phase types go, IdealGasPhase was the big one that I think we needed to resolve. One other easy one is that all the descendants of MolalityVPSSTP are all liquids.

include/cantera/thermo/IdealSolnGasVPSS.h Show resolved Hide resolved
phaseOfMatter returns the mechanical phase (liquid, gas, etc.) of the
matter in the Phase. The default value is 'unspecified' for phases
that don't contain enough information to determine the mechanical
phase.
The Phase report now includes the mechanical phase of the matter in the
Phase. The report is reformatted to use field widths consistently and
realign some of the data to better fit the mechanical phase type.
The columns for mole and mass fraction are swapped in the output of
report. This makes the two property tables consistent with mass listed
first and then moles.
Make the strings in the report method composable. Enables setting string
parameters by variables at the top of the function.
Python 3.8 now warns about misuse of the is comparison operator.
These regression tests include the output of ThermoPhase::report in the
test comparison.
@speth speth merged commit 3003156 into Cantera:master Jan 2, 2020
@bryanwweber bryanwweber deleted the add-get-phase branch January 11, 2020 20:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants