Skip to content

fix: correct multi-liquid selection flag in pure-component flash - #182

Merged
CalebBell merged 1 commit into
CalebBell:masterfrom
steps-re:fix/flash-one-liquid
Jul 12, 2026
Merged

CalebBell merged 1 commit into
CalebBell:masterfrom
steps-re:fix/flash-one-liquid

Conversation

@steps-re

Copy link
Copy Markdown
Contributor

What's wrong

In thermo/flash/flash_utils.py, six pure-component flash helpers set a selection flag from a count instead of a boolean:

one_liquid = len(liquids)
...
if one_liquid:
    lowest_phase = liquids[0].to_TP_zs(T, P, zs)
else:
    # pick the phase with the lowest Gibbs energy

len(liquids) is truthy for any count greater than zero, so the if one_liquid: branch runs whenever there is at least one liquid phase, not just when there is exactly one. With two or more liquid phases, this skips the Gibbs-energy comparison entirely and always returns liquids[0], regardless of which phase is actually stable. With zero liquids, it falls to the else branch, the phase list comprehension is empty, lowest_phase stays None, and the next line crashes calling .fugacities() on None.

Same pattern for one_other = len(other_phases) and one_solid = len(solids) in TSF_pure_newton and PSF_pure_newton.

Fix

Make the flags actual booleans:

one_liquid = len(liquids) == 1

applied to all six functions: TVF_pure_newton, TVF_pure_secant, PVF_pure_newton, PVF_pure_secant, TSF_pure_newton, PSF_pure_newton. This preserves the fast path for the single-phase case and correctly runs the Gibbs-energy comparison whenever there's more than one candidate phase.

Testing

I wrote a standalone repro using lightweight fake phase objects (mocking to_TP_zs, G, fugacities, dfugacities_dP/dT) to isolate the selection logic from the full EOS/data stack, since these functions don't have dedicated unit tests. With two liquid phases passed in liquids[0] = high Gibbs energy, liquids[1] = low Gibbs energy, and gas fugacity matched to the low-Gibbs phase:

  • On current master, TVF_pure_secant raises fluids.numerics.SamePointError because it locks onto liquids[0] (the wrong, high-Gibbs phase) and the solver never converges.
  • With this fix, all four TVF_pure_*/PVF_pure_* functions correctly select the low-Gibbs phase and converge.
  • A single-liquid case confirms the len == 1 fast path is unaffected.

I also confirmed git blame shows this line unchanged since it was introduced in 2021.

one_liquid/one_other/one_solid were assigned len(x) instead of a
boolean, so the truthy check on any count > 1 skipped the
lowest-Gibbs-energy phase selection and just took index 0. A count
of 0 fell through to the else branch and left lowest_phase as None,
which crashes on the following .fugacities() call.

Affects TVF_pure_newton, TVF_pure_secant, PVF_pure_newton,
PVF_pure_secant, TSF_pure_newton, and PSF_pure_newton in
thermo/flash/flash_utils.py.

Signed-off-by: Mike German <mike@stepsventures.com>
@CalebBell

Copy link
Copy Markdown
Owner

Hi, yes this is a typo.
Is there a person on the other side of this PR?

@steps-re

steps-re commented Jul 12, 2026 via email

Copy link
Copy Markdown
Contributor Author

@CalebBell
CalebBell merged commit bd54ef3 into CalebBell:master Jul 12, 2026
43 of 58 checks passed
@CalebBell

Copy link
Copy Markdown
Owner

Hey Mike,
Your system did find a bug - not one that I think anyone has ran into, but it's one I didn't realize I created.
I appreciate it.
Sincerely,
Caleb

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.

2 participants