Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/skills/neqsim-wax-calculations/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ wax_weight_fractions = list(wax.getWaxWeightFractions())
| WAT is unrealistically low | Heavy-end characterization is too light or missing n-paraffins | Review TBP cuts, plus-fraction molar mass, density, and wax model parameters |
| WAT calculation fails | Search range or initial fluid state is poor | Use `WaxCurveCalculator` over a broad temperature range and inspect failed flashes |
| `calcWAT()` throws `molarVolumeAnalytical - compressibility factor is NaN`, or `WaxCurveCalculator` returns `NaN` WAT | Synthetic/hand-built heavy end with no n-paraffin distribution — the wax model has nothing physical to solve against | Do **not** substitute a guessed WAT. Report it as a lab-data gap and require a measured WAT/DSC or a real PVTsim/E300 characterization |
| Wax fraction decreases when cooling | Numerical flash artifact | Use monotonicity-enforced `WaxCurveCalculator` output and record correction count |
| Wax fraction decreases or gas/wax disappears when cooling | Possible phase-selection or convergence artifact | Inspect unsmoothed independent TP trials, phase identities, conserved inventories and component fugacities; material balance or monotonicity smoothing alone cannot validate stability. See the #4324 cold-start regression in the [wax guide](../../../docs/thermo/characterization/wax_characterization.md). |
| Python notebook sees old API | Installed neqsim package is stale | Use the devtools setup cell with workspace classes or rebuild/package the JAR |

## Reporting Requirements
Expand Down Expand Up @@ -236,4 +236,4 @@ For task reports, include:
- `neqsim-wax-margin-check`
- `neqsim-api-patterns`
- `neqsim-regression-baselines`
- `neqsim-professional-reporting`
- `neqsim-professional-reporting`
25 changes: 25 additions & 0 deletions docs/thermo/characterization/wax_characterization.md
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,31 @@ it is not experimental validation. Laboratory WAT and wax-fraction data are stil
needed for fluid-specific prediction, and equilibrium wax appearance does not
by itself predict deposition rate or location.

The named-component cold-start regression in
[issue #4324](https://github.com/equinor/neqsim/issues/4324) uses SRK/classic with
methane / n-heptane / nc14 / nc20 / nc24 = 40 / 10 / 10 / 20 / 20 mol, the default
Pedersen wax model and fluid multiphase checking. Fresh, warm and cold starts,
with and without explicit initialization at the trial temperature, retain gas,
oil and wax at 260, 265 and 270 K at both 1 and 5 bara; 275 K is wax-free.
At 265 K and 5 bara the wax mass fraction is **0.331530523**. Initial guesses of
265, 270 and 320 K give the same numerical WAT: **270.421295 K at 5 bara** and
**271.307144 K at 1 bara**, within the search tolerance.

The repair restricts fluid-only endpoint cleanup to fluid calculations. The
homogeneous fluid Gibbs-energy reference must not overwrite a wax equilibrium:
the solid phase's caloric properties do not implement the wax fugacity reference
used by the equilibrium model. Equal fluid and solid compositions likewise do
not make the phases duplicates. WAT reads wax mass from phase mole inventory
and molar mass, independently of solid-density correlations.

`NamedWaxColdStartTest` checks normalized phases, component and total mass
conservation, equal component fugacities, and independent vapor, liquid and wax
tangent-plane trials seeded from the feed and each component. These are
model-consistency checks for this synthetic feed, not experimental qualification,
a validation of solid density/caloric properties, or a guarantee of global
stability for arbitrary compositions. Preserve unsmoothed results when diagnosing
a disappearing phase; material closure alone does not establish phase stability.

### Step 4: Wax Fraction vs Temperature

```java
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4352,7 +4352,8 @@ private double maximumLogFugacityResidual(PhaseInterface firstPhase, PhaseInterf
* only a single subtraction beyond the {@code getGibbsEnergy()} call (no extra {@code init} is performed —
* {@code init(1)} from the preceding {@code orderByDensity} is sufficient). A threshold of
* {@link #SPURIOUS_MULTIPHASE_GIBBS_DROP_THRESHOLD_J} joules avoids triggering on numerical noise. Skipped for
* chemical / electrolyte systems.
* chemical / electrolyte systems and solid/wax calculations: their phase-specific fugacity reference models are not
* represented by this homogeneous fluid Gibbs comparison.
* </p>
*
* <p>
Expand All @@ -4367,8 +4368,9 @@ private void rescueSpuriousMultiphaseEndpoint() {
// results (the dominant case after the removePhase cleanup just above the call site) bail
// on the first term without touching any property method.
final int numPhases = system.getNumberOfPhases();
if (numPhases < 2 || !system.doMultiPhaseCheck() || referenceSinglePhaseType == null
|| Double.isNaN(referenceSinglePhaseGibbs) || system.getPhase(0).getNumberOfComponents() <= 1) {
if (numPhases < 2 || !system.doMultiPhaseCheck() || solidCheck || system.doSolidPhaseCheck()
|| system.isMultiphaseWaxCheck() || referenceSinglePhaseType == null || Double.isNaN(referenceSinglePhaseGibbs)
|| system.getPhase(0).getNumberOfComponents() <= 1) {
return;
}
// Smallest beta — fast path for the 2-phase case (overwhelmingly common); generic loop
Expand Down Expand Up @@ -4422,12 +4424,14 @@ private void rescueSpuriousMultiphaseEndpoint() {
* fluid into two identical copies is physically meaningless (it is a single phase), so this guard removes the
* artifact and keeps the reported phase boundary consistent with the phase-envelope saturation solver. Only the
* two-phase case is handled; genuine two-phase splits have compositionally distinct phases (even when the incipient
* phase fraction is tiny) and are left untouched. Skipped for chemical / electrolyte systems.
* phase fraction is tiny) and are left untouched. Skipped for chemical / electrolyte systems and solid/wax
* calculations, where matching compositions do not make a solid and a fluid the same phase.
* </p>
*/
private void collapseTrivialMultiphaseSplit() {
if (system.getNumberOfPhases() != 2 || !system.doMultiPhaseCheck() || referenceSinglePhaseType == null
|| system.isChemicalSystem() || system.hasIons()) {
if (system.getNumberOfPhases() != 2 || !system.doMultiPhaseCheck() || solidCheck || system.doSolidPhaseCheck()
|| system.isMultiphaseWaxCheck() || referenceSinglePhaseType == null || system.isChemicalSystem()
|| system.hasIons()) {
return;
}
neqsim.thermo.phase.PhaseInterface phaseA = system.getPhase(0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
* <p>
* The onset is the transition through a wax mass fraction of {@value #WAX_MASS_TOLERANCE}. The returned temperature is
* the warm endpoint of a bracket narrower than {@value #TEMPERATURE_TOLERANCE} K. This is a numerical onset for the
* configured TP wax model, not an experimental WAT or a deposition model. Trials always start from the feed, so an
* configured TP wax model, not an experimental WAT or a deposition model. The wax mass fraction is calculated from
* phase mole inventory and molar mass, without a solid-density conversion. Trials always start from the feed, so an
* existing wax phase or reordered fluid phases cannot seed a spurious saturation solution.
* </p>
*
Expand Down Expand Up @@ -206,7 +207,8 @@ private boolean hasWax(SystemInterface trial) {
if (!trial.hasPhaseType("wax")) {
return false;
}
double fraction = trial.getPhaseFraction("wax", "mass");
// The onset is an inventory threshold, independent of solid density correlations.
double fraction = trial.getWtFraction(trial.getPhaseNumberOfPhase("wax"));
if (!Double.isFinite(fraction) || fraction < 0.0 || fraction > 1.0) {
throw failure("Invalid wax mass fraction");
}
Expand Down
4 changes: 2 additions & 2 deletions src/main/resources/neqsim/mcp/engineering-coverage.json
Original file line number Diff line number Diff line change
Expand Up @@ -4726,7 +4726,7 @@
{"id":"neqsim.thermodynamicoperations.flashops.THflash","kind":"class","source":"src/main/java/neqsim/thermodynamicoperations/flashops/THflash.java","sourceDigest":"b1d48c2c469dc4497ac512ce708653e2d162edd5cc3335d96c61514ce6d75a95","domain":"thermodynamicoperations","skills":[],"agents":[],"capabilities":[],"disposition":"review_required"},
{"id":"neqsim.thermodynamicoperations.flashops.TPHybridEosGeFlash","kind":"class","source":"src/main/java/neqsim/thermodynamicoperations/flashops/TPHybridEosGeFlash.java","sourceDigest":"397929dede61cf58709265a8e5ccdf8205b6b0a1c3142bce8167dabe5d0608bf","domain":"thermodynamicoperations","skills":[],"agents":[],"capabilities":[],"disposition":"review_required"},
{"id":"neqsim.thermodynamicoperations.flashops.TPHydrateFlash","kind":"class","source":"src/main/java/neqsim/thermodynamicoperations/flashops/TPHydrateFlash.java","sourceDigest":"7eaa800aa6e8c27b746652e5f0030a0ac8cbfd8bdc1b0924ec3a81a0e0db60b4","domain":"thermodynamicoperations","skills":[],"agents":[],"capabilities":[],"disposition":"review_required"},
{"id":"neqsim.thermodynamicoperations.flashops.TPflash","kind":"class","source":"src/main/java/neqsim/thermodynamicoperations/flashops/TPflash.java","sourceDigest":"a77d7563c4301438b6cfa21217b62e140d8a3d61b85d84d1cdf46f975bb5f39b","domain":"thermodynamicoperations","skills":["generate-publication-figures","neqsim-api-patterns","neqsim-dynamic-equipment-implementation","neqsim-eos-regression","neqsim-flow-accelerated-corrosion","neqsim-flow-assurance","neqsim-hazid-fmea-eta-fta","neqsim-input-validation","neqsim-lng-liquefaction","neqsim-notebook-patterns","neqsim-phase-envelope","neqsim-physics-explanations","neqsim-production-chemistry","neqsim-production-optimization","neqsim-professional-reporting","neqsim-subsea-and-wells","neqsim-thermodynamic-initialization","neqsim-troubleshooting","run-flash-experiments","write-methods-section"],"agents":["capability-scout","capacity-increase-screening","ccs-hydrogen","consequence-analysis","continuous-improvement","control-system","documentation","dynamic-equipment","emissions-environmental","engineering-deliverables","field-development","flow-assurance","gas-processing-refining","gas-quality","lng-value-chain","mechanical-design","neqsim-test","network-energy-systems","notebook-example","optimize","optimize-processmodel","paperlab","process-model","production-chemistry","pvt-simulation","reaction-engineering","review","root-cause","rotating-equipment","solve-process","solve-task","standards-review","thermo-fluid","unisim-reader","utility-design"],"capabilities":[],"disposition":"review_required"},
{"id":"neqsim.thermodynamicoperations.flashops.TPflash","kind":"class","source":"src/main/java/neqsim/thermodynamicoperations/flashops/TPflash.java","sourceDigest":"befd2b684e9e4164cdf9c4034d2fef1a599fa6a07784edcbdde0bee114fb281c","domain":"thermodynamicoperations","skills":["generate-publication-figures","neqsim-api-patterns","neqsim-dynamic-equipment-implementation","neqsim-eos-regression","neqsim-flow-accelerated-corrosion","neqsim-flow-assurance","neqsim-hazid-fmea-eta-fta","neqsim-input-validation","neqsim-lng-liquefaction","neqsim-notebook-patterns","neqsim-phase-envelope","neqsim-physics-explanations","neqsim-production-chemistry","neqsim-production-optimization","neqsim-professional-reporting","neqsim-subsea-and-wells","neqsim-thermodynamic-initialization","neqsim-troubleshooting","run-flash-experiments","write-methods-section"],"agents":["capability-scout","capacity-increase-screening","ccs-hydrogen","consequence-analysis","continuous-improvement","control-system","documentation","dynamic-equipment","emissions-environmental","engineering-deliverables","field-development","flow-assurance","gas-processing-refining","gas-quality","lng-value-chain","mechanical-design","neqsim-test","network-energy-systems","notebook-example","optimize","optimize-processmodel","paperlab","process-model","production-chemistry","pvt-simulation","reaction-engineering","review","root-cause","rotating-equipment","solve-process","solve-task","standards-review","thermo-fluid","unisim-reader","utility-design"],"capabilities":[],"disposition":"review_required"},
{"id":"neqsim.thermodynamicoperations.flashops.TPflashSAFT","kind":"class","source":"src/main/java/neqsim/thermodynamicoperations/flashops/TPflashSAFT.java","sourceDigest":"5c8778f7c5c107487162aaf3ed3d2fc0b8e483dc321a09e1ffe5eac48e4de713","domain":"thermodynamicoperations","skills":[],"agents":[],"capabilities":[],"disposition":"review_required"},
{"id":"neqsim.thermodynamicoperations.flashops.TPgradientFlash","kind":"class","source":"src/main/java/neqsim/thermodynamicoperations/flashops/TPgradientFlash.java","sourceDigest":"196518fa2c15a9216880614e26917a9e265cdcb68bb698d08664396edff26ee3","domain":"thermodynamicoperations","skills":[],"agents":[],"capabilities":[],"disposition":"review_required"},
{"id":"neqsim.thermodynamicoperations.flashops.TPmultiflash","kind":"class","source":"src/main/java/neqsim/thermodynamicoperations/flashops/TPmultiflash.java","sourceDigest":"b012ab24b4481987f5ebf0c8907d4b2d6c6a24cf0c6554a09aec8dbd340c8a75","domain":"thermodynamicoperations","skills":[],"agents":[],"capabilities":[],"disposition":"review_required"},
Expand Down Expand Up @@ -4791,7 +4791,7 @@
{"id":"neqsim.thermodynamicoperations.flashops.saturationops.SaltPrecipitationResult","kind":"class","source":"src/main/java/neqsim/thermodynamicoperations/flashops/saturationops/SaltPrecipitationResult.java","sourceDigest":"1282280c9602381c92247ae45f7e52e39eb3eb7fee5d4e03bf0303333d2923ca","domain":"thermodynamicoperations","skills":[],"agents":[],"capabilities":[],"disposition":"review_required"},
{"id":"neqsim.thermodynamicoperations.flashops.saturationops.SaltSaturationResult","kind":"class","source":"src/main/java/neqsim/thermodynamicoperations/flashops/saturationops/SaltSaturationResult.java","sourceDigest":"601f1b7bbaca5eca0a8b092807dc74ea4a94063afb89f76438b021dad96fbf3e","domain":"thermodynamicoperations","skills":[],"agents":[],"capabilities":[],"disposition":"review_required"},
{"id":"neqsim.thermodynamicoperations.flashops.saturationops.SolidComplexTemperatureCalc","kind":"class","source":"src/main/java/neqsim/thermodynamicoperations/flashops/saturationops/SolidComplexTemperatureCalc.java","sourceDigest":"36ef89f9be5852586b961b06ae4c09fe06dc5865a990fa39b97e77ca4e09dce6","domain":"thermodynamicoperations","skills":[],"agents":[],"capabilities":[],"disposition":"review_required"},
{"id":"neqsim.thermodynamicoperations.flashops.saturationops.WATcalc","kind":"class","source":"src/main/java/neqsim/thermodynamicoperations/flashops/saturationops/WATcalc.java","sourceDigest":"bb30b9505139d1e294eb801eda64dd8aeb3a85c1107b9cc1a1eedce09a3fe896","domain":"thermodynamicoperations","skills":[],"agents":[],"capabilities":[],"disposition":"review_required"},
{"id":"neqsim.thermodynamicoperations.flashops.saturationops.WATcalc","kind":"class","source":"src/main/java/neqsim/thermodynamicoperations/flashops/saturationops/WATcalc.java","sourceDigest":"67ce2f4e279518a76772f3f5ab616d9789433b5e8436794cf6a257ef85a26911","domain":"thermodynamicoperations","skills":[],"agents":[],"capabilities":[],"disposition":"review_required"},
{"id":"neqsim.thermodynamicoperations.flashops.saturationops.WaterDewPointEquilibriumLine","kind":"class","source":"src/main/java/neqsim/thermodynamicoperations/flashops/saturationops/WaterDewPointEquilibriumLine.java","sourceDigest":"d331af519cfcc8eaac17e1c29640510d82ea76ffedaf0a584ec60116eb93971d","domain":"thermodynamicoperations","skills":[],"agents":[],"capabilities":[],"disposition":"review_required"},
{"id":"neqsim.thermodynamicoperations.flashops.saturationops.WaterDewPointTemperatureFlash","kind":"class","source":"src/main/java/neqsim/thermodynamicoperations/flashops/saturationops/WaterDewPointTemperatureFlash.java","sourceDigest":"4f9362e298b91b603660cada8fe4d1481423bfc4f52866336d761656885dff55","domain":"thermodynamicoperations","skills":[],"agents":[],"capabilities":[],"disposition":"review_required"},
{"id":"neqsim.thermodynamicoperations.flashops.saturationops.WaterDewPointTemperatureMultiphaseFlash","kind":"class","source":"src/main/java/neqsim/thermodynamicoperations/flashops/saturationops/WaterDewPointTemperatureMultiphaseFlash.java","sourceDigest":"32f3f88225b6189413fd4a294d14d387a8d620212a7be6a17f1df311e46d8157","domain":"thermodynamicoperations","skills":[],"agents":[],"capabilities":[],"disposition":"review_required"},
Expand Down
Loading
Loading