Coupled release and inventory depletion
ReleaseInventory is an opt-in process unit for one rigid, adiabatic, well-mixed equilibrium
inventory and one short opening. Unlike a hypothetical source sample, its native
runTransient removes mass and energy. The changed temperature, pressure and composition
then determine the next release calculation. It works within both ProcessSystem and
ProcessModel; neither container nor the existing separator/blowdown APIs are changed.
The original constructor remains a single-gas compatibility API. An overload ending in an
explicit PhaseType selects GAS, OIL, LIQUID or AQUEOUS withdrawal. The selected
equilibrium phase supplies the upstream state and withdrawn composition; the entire remaining
inventory is then reflashed. This is a boundary condition, not a level/geometry model: no
entrainment, slip, interfacial transfer rate or automatic fallback phase is inferred.
An overload accepting List<PhaseType> and phaseExhaustionMassFraction adds a caller-declared
ordered transition plan. The first phase must initially be present above the threshold. A transient
step advances only to the next named phase when the active phase inventory mass fraction reaches
the explicit threshold. It never selects a phase from density, position or phase count. If the
immediately next planned phase is not usable, the complete call fails atomically.
The constructor clones the supplied EOS system and scales its amount to the specified volume at its initial temperature and pressure. The supplied mole count defines composition, not vessel size or kg/s. Returned fluids and accounting snapshots are independent copies.
The dynamic-capability audit classifies the unit as DYNAMIC_LUMPED because it owns
component masses and internal energy. This state-ownership category persists when the
opening is closed or steady-state mode is requested. It does not certify runtime readiness:
activation remains UNVERIFIED and source-frame evidence remains UNQUALIFIED.
Balance equations and numerical method
For component inventory $m_i$ in kg, selected-phase component mass fraction $w_{i,s}$, internal energy $U$ in J, fixed volume $V$ in m3, and release rate $\dot m$ in kg/s:
\[\frac{dm_i}{dt}=-w_{i,s}\dot m,\qquad \frac{dU}{dt}=-h_{0,s}\dot m,\qquad V=\mathrm{constant}\]$h_{0,s}$ is the selected phase’s EOS upstream stagnation enthalpy in J/kg. The discharge removes enthalpy, including flow work; subtracting only specific internal energy would predict the wrong cooling. Enthalpy and internal energy can be negative under the selected EOS reference. Their signed balance is retained. No heat input, boundary work, inflow, kinetic inventory energy or potential-energy change is included.
Each explicit Euler substep removes selected-phase composition and integrated $h_{0,s}\dot m$,
then calls NeqSim’s volume/internal-energy flash with explicit m3 and J units.
It verifies component, volume and energy closure to relative $10^{-7}$, including cumulative
closure against the original inventory. The substep is limited by maxSubstepS, remaining
duration, and 1% of current selected-phase mass. This bound prevents overdraw; it is not an
accuracy estimate. Refine maxSubstepS and the external output timestep for each study.
A call needing more than 10,000 substeps fails without committing this unit’s state.
For an ordered plan, the phase-exhaustion threshold is a model input, not a numerical tolerance. It represents the minimum phase inventory for which the selected homogeneous withdrawal boundary is considered applicable. The transition preserves all residual material in the reflashed vessel; it changes only which explicitly named equilibrium phase supplies subsequent outflow composition and enthalpy. Threshold sensitivity therefore belongs in each study’s validation matrix.
The general VU flash’s stopping tolerance is looser than the cumulative accounting target.
Each substep therefore permits up to 32 repeated solves of the same VU equations until
volume and energy residuals are at most $10^{-11}$ relative to their respective scales.
This is explicit residual refinement with unchanged physics, not a replacement flash or
property fallback. Failure to meet it produces INVENTORY_VU_REFINEMENT_FAILED. The total
number of VU solves is available through getLastVolumeEnergySolves() and frame provenance.
The release model is explicitly selected. Its upstream pressure, temperature and enthalpy
must match the selected phase and its upstream/exit composition must match that phase’s withdrawal.
Exit static enthalpy plus specific kinetic energy must equal upstream stagnation enthalpy.
Legacy SCREENING_ONLY or unresolved-station results are rejected. No alternate release
model, property default or flash recovery is substituted.
Executable process example
The corresponding construction, registration, stepping, balance access and isolation calls
are exercised by ReleaseInventoryTest.documentationExampleAndPhysicalIsolationWorkForBothContainers.
Use imports from neqsim.process.safety.release, neqsim.process.processmodel,
neqsim.thermo.system and java.util.List.
SystemInterface gas = new SystemSrkEos(300.0, 2.0); // K and bara
gas.addComponent("nitrogen", 1.0);
gas.setMixingRule("classic");
ReleaseInventory vessel = new ReleaseInventory("inventory", gas,
1.0, 0.01, 0.7, 10000.0, new IdealGasReleaseModel(), 0.1);
ProcessSystem process = new ProcessSystem();
process.add(vessel);
SourceTermSession session = new SourceTermSession("inventory-study", process);
session.addInventorySource("opening", "inventory");
List<SourceTermFrame> initial = session.runSteadyState(); // no depletion
List<SourceTermFrame> next = session.step(0.5);
ReleaseInventory.Balance accounting = vessel.getBalance();
double emittedMassKg = accounting.getReleasedMassKg();
double outgoingEnthalpyJ = accounting.getReleasedEnergyJ();
vessel.setReleaseEnabled(false); // physically close this opening
List<SourceTermFrame> isolated = session.step(0.5);
For an equilibrium gas-over-liquid inventory, select the gas boundary explicitly:
ReleaseInventory phaseSelected = new ReleaseInventory("two-phase", flashedFluid,
1.0, 0.01, 0.62, 101325.0, new HomogeneousEquilibriumReleaseModel(), 0.02,
PhaseType.GAS);
Use the actual equilibrated phase type when selecting a hydrocarbon liquid (OIL or
LIQUID). Construction rejects an absent or unsupported phase. If re-equilibration removes
the selected phase during a transient call, the call fails atomically with
INVENTORY_SELECTED_PHASE_ABSENT; callers must split the regime or select another assessed model.
For an assessed gas-to-liquid transition, declare both phases and the inventory mass-fraction boundary explicitly:
List<PhaseType> withdrawalPlan = Arrays.asList(PhaseType.GAS, liquidType);
ReleaseInventory staged = new ReleaseInventory("staged", flashedFluid,
1.0, 0.01, 0.62, 101325.0, new HomogeneousEquilibriumReleaseModel(), 0.02,
withdrawalPlan, 1.0e-4);
This does not model a vessel level, interface geometry, entrainment or interfacial transfer rate. Use a threshold justified for the modeled inventory and verify sensitivity around it.
For an area-based model, add process under "gas-area", construct the session from that
ProcessModel, and use session.addInventorySource("opening", "gas-area", "inventory").
Keep dynamic mode enabled; this unit is constructed with setCalculateSteadyState(false).
A steady run checks the present state without resetting the inventory or accounting.
Repeated native evaluations with the same transient UUID do not withdraw twice; a different
duration with that same UUID is rejected.
getBalance() provides immutable initial, remaining and released component masses in kg,
initial/current internal energy and released enthalpy in J, fixed volume, simulation time
and the last substep count. These integrated quantities are the balance evidence. A frame’s
rate is the instantaneous rate at its simulation time, not a timestep average. Do not
apply the frame rate as an additional withdrawal from this unit.
Frame and failure semantics
addInventorySource binds the inventory’s own geometry and release model. It rejects a
second physical-source registration for the same unit. Existing addSource remains a
hypothetical sample and does not enable inventory coupling.
The finite-pipe ReleaseInventory constructor adds flow-path length and specified Darcy friction
before the model argument. That geometry is retained as inventory pressure and composition evolve
and is exported by addInventorySource. It enables quasi-steady coupling to the ideal-gas Fanno
model; it does not add transient pipe-wave storage to the lumped inventory. Schema v1 accepts the
paired optional flowPathLength and darcyFrictionFactor source fields.
Compatibility frames carry releaseBasis=COUPLED_RIGID_ADIABATIC_GAS_INVENTORY.
Explicit phase-selected frames carry
releaseBasis=COUPLED_RIGID_ADIABATIC_PHASE_SELECTED_INVENTORY and
inventoryWithdrawalPhase. Both carry the integrator
identity, inventory volume/time, cumulative released mass/enthalpy, and
rateTimeBasis=INSTANTANEOUS_AT_FRAME_TIME in provenance. Evidence stays UNQUALIFIED.
Process, equipment, calculation UUID and session sequence semantics are retained.
The configured maximum substep and last substep count are also recorded in provenance.
Ordered-plan frames instead carry
releaseBasis=COUPLED_RIGID_ADIABATIC_PHASE_TRANSITION_INVENTORY, the complete ordered plan,
the exhaustion threshold, active phase, last-call transition count and cumulative transition
count. All remain string-valued provenance in schema v1; SI source quantities are unchanged.
vessel.setReleaseEnabled(false) stops physical withdrawal and yields an
INVENTORY_OPENING_CLOSED disabled frame after the next successful process call.
It invalidates the prior equipment calculation identity. In contrast,
session.setEnabled(sourceId, false) disables export only; process physics continue.
Opening/closure changes occur at step boundaries; split steps at known event times.
| Condition | Behavior |
|---|---|
| Receiving pressure at or above initial inventory pressure | Valid zero flow; no reverse flow modeled. |
| Substep would reduce pressure below receiving pressure | Bounded event location lands on receiving pressure; provenance records the physical release duration. |
| Selected phase is absent initially | Construction rejects the configuration. |
| Selected phase disappears after re-equilibration | INVENTORY_SELECTED_PHASE_ABSENT; the unit call commits no state. |
| Active planned phase reaches its explicit exhaustion threshold | Advances only to the immediately next usable caller-declared phase and records the transition. |
| Immediately next planned phase is absent or exhausted | INVENTORY_WITHDRAWAL_PHASE_PLAN_EXHAUSTED; the unit call commits no state. |
| Reactions, forced phases, solids or hydrates | INVENTORY_REGIME_UNSUPPORTED; no fallback physics is invented. |
| Invalid model, mismatched upstream state/composition, or screening result | Fail closed without committing inventory. |
| Volume, component or energy closure failure | Fail closed, with the corresponding closure diagnostic. |
| Native process step failure | Session emits INVALID without numeric source payload and becomes faulted. |
Updates are transactional within this unit: failure preserves its pre-call fluid, accounting, clock and UUID. Other process units and the process clock may already have advanced. Follow the session recovery guidance; a steady rerun is not a rollback of the surrounding process. Caller-owned custom release models must be deterministic and must not mutate themselves or the process during evaluation.
Validation and applicability
ReleaseInventoryTest checks multicomponent gas depletion, phase-selected gas-over-liquid and
liquid withdrawal using the homogeneous-equilibrium release model. A controlled deterministic
release model isolates explicit gas-to-liquid exhaustion transition, conservation and timestep/
threshold refinement from release-model solver noise. The suite also checks component/energy/volume closure, cooling and decreasing release rate, input
immutability, cloning, zero flow, isolation/reopening, invalid steps, pressure-boundary
rollback, injected mid-step failure, and both process containers. Actual frames, including
disabled and failed cases, are validated against the bundled JSON Schema.
Phase-selected source frames are schema-validated from both process containers. A three-level
substep refinement checks convergent pressure for gas withdrawal from a methane/n-butane
two-phase inventory, while released component mass verifies selection of the gas composition.
For 0.04, 0.02 and 0.01 s maximum substeps over 0.2 s, the final pressures are
998944.206, 998944.262 and 998944.290 Pa; the fine/coarse pressure-difference ratio is 0.500.
CI retains the component withdrawals and energy residuals in
target/source-term-benchmarks/inventory-phase-selected-convergence.csv.
The capability regression checks both process containers and preserves the distinction
between audited state ownership and unverified runtime activation. The focused safety workflow
also runs DynamicCapabilityBuiltInInventoryTest to catch missing built-in registrations.
For an independent temporal reference, the constant-gamma ideal-gas choked, rigid adiabatic solution follows by combining the balance equations with $U=mc_vT$ and the choked discharge relation. With $a=\dot m_0/m_0$ in 1/s:
\[\frac{m(t)}{m_0}=\left[1+\frac{\gamma-1}{2}at\right]^{-2/(\gamma-1)}\] \[\frac{T(t)}{T_0}=\left(\frac{m(t)}{m_0}\right)^{\gamma-1},\qquad \frac{p(t)}{p_0}=\left(\frac{m(t)}{m_0}\right)^\gamma\]The test uses nitrogen at 300 K, initially 2.0 and 2.2 bara, 1 m3, a 0.01 m opening,
$C_d=0.7$, receiving pressure 0.1 bara and 10 s duration. It compares three substep
limits (0.2, 0.1 and 0.05 s) to the closed-form mass, pressure and temperature and checks
first-order refinement. The reference uses the initial NeqSim molar mass/gamma; its temporal
solution is independent, while the implemented inventory retains the real EOS and variable
properties. The test tolerance is 0.3% of initial values and is not an experimental accuracy
claim. CI retains target/source-term-benchmarks/inventory-convergence.csv.
The local 0.05 s results at 10 s are:
| Initial pressure (Pa) | Remaining mass (kg) | Pressure (Pa) | Closed-form pressure (Pa) | Absolute energy residual (J) |
|---|---|---|---|---|
| 200000 | 2.00989363 | 171096.452 | 171105.421 | 0.000224 |
| 220000 | 2.21087835 | 188197.626 | 188206.827 | 0.000243 |
The fine/coarse pressure-difference ratio is approximately 0.499 in both cases. These results separate numerical refinement from the small real-EOS/constant-gamma reference difference.
The transition benchmark spans thresholds 0.026175–0.026185 and maximum substeps 0.15–0.0375 s. All nine cases conserve 0.0003 kg release, commit exactly one transition and retain component, energy and volume closure. The finest nearby-threshold pressure spread is below 0.032%; successive step refinement is non-increasing within the asserted numerical tolerance.
This increment covers equilibrium, phase-selected withdrawal and explicit ordered phase-exhaustion
transitions in a well-mixed rigid inventory. Phase level/geometry, entrainment and slip, finite-rate interfacial transfer, wall/fire heat transfer,
pipe decompression, non-equilibrium transfer, solid-bearing flow physics and experimental qualification
remain separate work in #3860.
The numerical limit of the selected release model still applies. No facility qualification
or independent safety/domain review is implied.
\n### Receiving-pressure event provenance\n\ninventoryPressureEquilibrationEvent records whether the last successful transient call landed on the no-flow boundary. inventoryReleaseDurationS is the physical discharge duration within that caller timestep. Event trials use the same EOS, component removal and enthalpy balance as ordinary substeps; failed event location commits no state.\n