Closed
Conversation
Try the legacy PH-flash loop first; on EOS failure (NaN Campbell guess, non-finite target enthalpy, NeqSim PHflash IsNaNException) fall back to a bracket+bisect on outlet pressure that uses TP-flashes for property updates and a single PH-flash at the converged point.
Treat speeds that make the EOS / fluid layer fail as infeasible probes rather than letting the exception crash the run. Bisect down from the max-speed probe when it's rejected by the EOS, and add an outer guard that marks otherwise-unrecoverable timesteps as NOT_CALCULATED.
ca47f99 to
68c430e
Compare
Contributor
Author
|
Closing — superseded by three PRs that cover the same problem space:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Robustness fixes for compressor train evaluation on dense / supercritical fluids
Three layered fixes — one real physical bug, two layers of EOS-failure
robustness — so compressor trains keep evaluating cleanly when fed
pathological dense-fluid operating points produced by the speed solver's
max-speed probes.
Branched from
v13.7.0. All 236 compressor / train / thermo / fluid /liquid regression tests pass.
1.
fix(process): scale mass rate when LiquidRemover drops out liquid phaseLiquidRemover.propagate_streamreplaced the inlet stream's fluid with agas-phase-only fluid via
FluidStream.with_new_fluid(...), which preservesmass_rate_kg_per_h. Because the gas phase has a lower molar mass than theoriginal two-phase mixture and only carries a fraction of the total mass,
holding
mass_rateconstant re-injects the dropped-out liquid mass into thegas stream as "phantom mass" and inflates the actual molar / volumetric flow
handed to the next compressor stage.
For real models with non-trivial liquid drop-out this can push downstream
compressor stages many times above their chart's max rate, far into
extrapolation, producing unphysical polytropic head and target enthalpies that
NeqSim's PH flash cannot solve and which surface as
IsNaNExceptionfromPhasePrEos.molarVolumeAnalytical.Scale the new stream's mass rate by the gas mass fraction:
2.
fix(process): robust outlet-pressure solver with TP-flash fallbackcalculate_outlet_pressure_and_streamhistorically did a PH-flashfixed-point iteration whose first guess is the Campbell formula evaluated
with inlet
zandkappa. For dense supercritical fluids that first guesscan be wildly off (10000+ bara) and NeqSim's PH-flash crashes with
IsNaNExceptionfromPhasePrEos.molarVolumeAnalyticalbefore the loop hasany chance to converge.
Two changes to make this layer robust:
fluid_service.flash_phwraps the underlying py4j call so a NeqSimIsNaNExceptionsurfaces asIllegalStateExceptionat the Python boundaryinstead of bubbling up as
Py4JJavaError.calculate_outlet_pressure_and_streamnow tries the legacy PH-flash loopfirst (cheap, well-calibrated, preserves historical numbers for the bulk
of operating points). If that loop refuses (NaN Campbell guess, non-finite
target enthalpy, or PHflash
IsNaNException), it falls back to a morerobust bracket-and-bisect:
For a candidate outlet pressure
P_out, estimate outlet temperaturewith the polytropic ideal-gas relation
T_out ~ T_in * (P_out / P_in) ^ ((k - 1) / k)and TP-flash there.TP-flash is far more numerically stable than PH-flash because pressure
and temperature uniquely fix the EoS state (no inner enthalpy root).
Plug the resulting average
zandkappaback into Campbell:The physical outlet pressure is the root of
f. Solve with Brent on[inlet_p, MAX_FIRST_GUESS_BAR].At the converged
P*, do one PH-flash at the real target enthalpy toobtain the final outlet fluid state.
If even the bracket has no sign change (chart head is genuinely
unphysical), the fallback raises
IllegalStateExceptionso the upstreamspeed solver can treat the proposal as infeasible.
Normal cases are unchanged (PH-flash loop succeeds, no drift in golden
numbers). Pathological dense-fluid cases that previously crashed now resolve
through the fallback.
3.
fix(process): speed solver tolerates infeasible EOS probesWhen a candidate
(speed, rate, pressure)proposal makes the underlyingEOS / fluid layer fail (e.g. NeqSim PHflash returns NaN even after the
TP-flash fallback in the outlet-pressure solver, or a chart point is being
extrapolated outside its valid envelope), the shaft-speed solver should treat
the probe as infeasible and try a different one — not crash the whole train
evaluation.
Changes in
find_fixed_shaft_speed_given_constraints(and its outerevaluate_given_constraintswrapper):Inner
_calculate_compressor_trainclosure catchesIllegalStateExceptionand returns an infeasible sentinel train result
(
point_is_valid=False, rate_exceeds_maximum=True), so the speed solvertreats it like any other out-of-capacity probe rather than letting the
exception bubble up.
When the max-speed probe is rejected by the EOS rather than by a real
chart capacity flag (
chart_area_flag == NOT_CALCULATEDinstead of e.g.ABOVE_MAXIMUM_FLOW_RATE), bisect downward to find the highest evaluablespeed and continue the normal speed search from there, instead of
short-circuiting to the unevaluable
maximum_speed.Outer
evaluate_given_constraintswrapper catches any remainingIllegalStateExceptionand marks the timestepNOT_CALCULATEDinstead ofcrashing the whole run.
Adds
CompressorTrainStageResultSingleTimeStep.create_infeasibleandCompressorTrainResultSingleTimeStep.create_infeasibleclassmethods next tothe existing
create_emptyconstructors so the infeasible sentinel isdiscoverable and reusable.