-
-
Notifications
You must be signed in to change notification settings - Fork 361
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
Fix automatic flame solving when Soret diffusion is enabled #511
Conversation
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 reasonable to me, with a few small modifications.
interfaces/cython/cantera/onedim.pyx
Outdated
# Do initial steps without Soret diffusion. | ||
# Has to be done before the multicomponent check because setting | ||
# the transport model to 'Mix' with soret_enabled throws an error | ||
solve_soret = any(getattr(dom, 'soret_enabled', False) for dom in self.domains) |
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.
What about writing
soret_doms = [dom for dom in self.domains if getattr(dom, 'soret_enabled', False)]
then just using this list below, to spare the isinstance
checks (and the if
as well, for that matter)?
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.
OK, this should work since an empty list will evaluate to False for the checks further down
src/oneD/StFlow.cpp
Outdated
@@ -147,6 +147,13 @@ void StFlow::setTransport(Transport& trans) | |||
m_trans = &trans; | |||
m_do_multicomponent = (m_trans->transportType() == "Multi"); | |||
|
|||
if (!m_do_multicomponent && m_do_soret) { | |||
throw CanteraError("setTransport", | |||
"Thermal diffusion (the Soret effect) is " |
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.
Extremely minor: with longer error messages, I tend to indent subsequent lines just one level, rather than lining up after the (
, which gets to be a bit ridiculous once you're already 30 columns in.
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.
👍
src/oneD/StFlow.cpp
Outdated
"Thermal diffusion (the Soret effect) is " | ||
"enabled, and requires using a multicomponent " | ||
"transport model."); | ||
} |
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 if we are doing this check here, can we get rid of the one in StFlow::enableSoret
? That would make it possible to toggle these flags in either order, and all that matters is that they are consistent once you call solve
, which seems like an improvement to me.
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 we can. The check here is only for the case where Soret is enabled and you're trying to set the transport back to mixture averaged. I think if we want to be able to set the flags in either order (i.e., set m_do_soret = True
when m_do_multicomponent == False
or set m_do_multicomponent = False
when m_do_soret == True
), then we should automatically enable/disable multicomponent transport. For instance, what if the user enables Soret diffusion with the mixture averaged model and then tries to compute the diffusion coefficients? Is that affected by the Soret option?
I think it would be better to make sure the transport is always in a consistent state, either by forcing the user to manage it, or by doing it in the code. Since there are effectively only three options for consistency, it shouldn't be hard to manage automatically, if we'd prefer that. I guess I have a mild preference for making the user do it, given that I chose to write an exception rather than just manage it (also, the exception was easier to write 😄)
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.
But I should also note that I have little experience with managing this part of the code, so I'll defer to your expertise if you think we should remove the other check.
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 agree that the user should always be expected to set a valid combination of flags, with no magic that changes either the soret_enabled
flag or the m_do_multicomponent
flag. But in the case where the user is switching from (no soret & no multicomponent) to (soret & multicomponent) or vice versa, I think we can let them set those flags in either order, rather than forcing them to do it in a particular order. And I think that this test here is sufficient to achieve that.
I don't think there is any issue with the user doing other things besides calling the solve
method -- all the methods for calculating transport properties are independent of the settings of the Sim1D
object. For example, the Soret diffusion coefficients can be calculated iff a multicomponent transport object is loaded, whether or not the attached Sim1D
object is set to use mixture averaged or multicomponent properties.
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.
Just to make sure I'm understanding everything: I don't think just this test is sufficient. If the state is (no soret & no multicomponent), and the test is removed from enableSoret
, the user can enable Soret and run solve, there's no check that multicomponent is enabled (unless you're suggesting I add a check in the solve method?) On the other hand, if the state is (soret & multicomponent), and the user tries to set mixture-averaged, and the test I've added here is not in place, then the state becomes (soret & no multicomponent) and the user can go and solve with no exceptions raised (until the simulation fails). Moreover, in that case (provided the test in the enableSoret function is still in place) the user cannot even turn off Soret without first turning multicomponent back on and turning off Soret first, so its a very confusing state of affairs (I realize you're not suggesting I remove this new check).
I guess I don't see a way (without having another check somewhere else) to allow the flags to be specified in either order and remain in a consistent state. Am I missing something?
Also, what happens in Sim1D
when Soret diffusion coefficients are enabled but the underlying Phase is mixture-averaged? How does it get diffusion coefficients, and if they're the same as the "normal" mixture averaged coefficients, why does a simulation that runs fine for a regular mixture-averaged case fail when Soret is incorrectly enabled?
def test_set_mix_with_soret(self): | ||
"""Test that setting mixture averaged transport with | ||
Soret diffusion enabled raises an error. | ||
""" |
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.
Don't ask me why, but unittest
doesn't get along well with docstrings. See https://travis-ci.org/Cantera/cantera/jobs/349570469#L3048. The easiest thing to do is just write this as 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.
👍
Codecov Report
@@ Coverage Diff @@
## master #511 +/- ##
=======================================
Coverage 64.78% 64.78%
=======================================
Files 383 383
Lines 40734 40734
=======================================
Hits 26390 26390
Misses 14344 14344
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.
I still think we can get rid of the other multi/soret check, but otherwise this looks good (assuming you want to squash a few things before merging). And hooray for fixing the latest 💩 that Homebrew left us.
src/oneD/StFlow.cpp
Outdated
"Thermal diffusion (the Soret effect) is " | ||
"enabled, and requires using a multicomponent " | ||
"transport model." | ||
); |
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 was assuming this would fit on fewer lines now. I also prefer the close parentheses on the same line, fwiw (I know, nitpicky).
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.
OK I'll fix it up, and yes, I do plan to squash the commits before merging 😄
self.sim.transport_model = 'Multi' | ||
self.sim.soret_enabled = True | ||
with self.assertRaises(ct.CanteraError): | ||
self.sim.transport_model = 'Mix' |
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.
Right, so I guess my suggestion about how this should work breaks the ability to write fast tests...
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.
Unfortunately, GitHub hid my previous comment: #511 (comment) and I didn't see these down here until just now... Can you clarify that other comment?
Sorry, I was misreading the diff, and didn't realize where the new exception was being raised. The behavior I am suggesting is this: # Currently allowed:
f.transport_model = 'Multi'
f.soret_enabled = True
f.solve(loglevel)
f.soret_enabled = False
f.transport_model = 'Mix'
f.solve(loglevel)
# These should also work:
f.soret_enabled = True
f.transport_model = 'Multi'
f.solve(loglevel)
f.transport_model = 'Mix'
f.soret_enabled = False
f.solve(loglevel)
# This should throw an exception:
f.transport_model = 'Mix'
f.soret_enabled = False
f.solve(loglevel) I think that moving the check for As far as my other comment, the point is that now writing a test for this requires actually calling |
I tried to move the check to |
Although, I'm realizing now that I didn't do too much to try and debug this... let me take a look with pdb and see if I can sort it out. |
Oh, I see what's happening. |
Thanks @speth. Are there any other functions where this might happen? How can I trace that? |
The method I used for identifying this as the cause was to run the test suite through gdb, e.g.
Then type The Doxygen docs actually provide a route to seeing where these functions are called from: http://cantera.github.io/dev-docs/doxygen/html/classCantera_1_1Sim1D.html#a32d626626eee0bc4ade146973f6abb1c says that |
The user can enable Soret (thermal) diffusion or multicomponent transport in either order, but attempts to solve flame problems with Soret enabled and the mixture-averaged transport approximation will result in an error
0861b69
to
742bfbc
Compare
Don't use Soret diffusion for the initial solve steps, and re-enable it at the end if the user desires
If Soret diffusion and mixture-averaged transport properties are enabled, test that an exception is thrown. Also test that multicomponent diffusion and Soret diffusion can be enabled/disabled in either order. Also test that the automatic flame solver correctly disables Soret diffusion.
Homebrew switched their default Python recipe to Python 3, so install python@2 recipe. Also, directly specify which version of Python should run SCons to prevent picking up the wrong version of Python as the sys.executable.
742bfbc
to
ed648d3
Compare
Changes proposed in this pull request:
I wasn't sure if there should be an exception thrown or if we should (silently?) force Soret to be false when mixture-averaged transport is used. Also, although the test is for a FreeFlame, this should apply to all the flames equally.