Skip to main content

neqsim-api-patterns

NeqSim Java/Python API patterns for fluids, flashes, process equipment and units. USE WHEN: selecting EOS/mixing-rule selection and property retrieval, including viscosity, thermal conductivity, binary/effective diffusion, gas-oil-water interfacial tension and black-oil PVT table conversion. Follow linked references for exact model selection, initialization and tested examples.

Informations de source

Dépôt
equinor/neqsim
Dernière activité de la source
26 octobre 2026 à 21:05
Langue détectée de SKILL.md
anglais
Étoiles
161
Forks
77

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Explorateur de fichiers
2 fichiers

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
neqsim-api-patterns
description
NeqSim Java/Python API patterns for fluids, flashes, process equipment and units. USE WHEN: selecting EOS/mixing-rule selection and property retrieval, including viscosity, thermal conductivity, binary/effective diffusion, gas-oil-water interfacial tension and black-oil PVT table conversion. Follow linked references for exact model selection, initialization and tested examples.
last_verified
2026-10-12
# NeqSim API Patterns Copy-paste reference for common NeqSim operations. All Java code must be Java 8 compatible. Use progressive disclosure: search headings and read only the task-relevant section. For property-model selection, diffusion or gas-oil-water interfacial tension, read [references/physical-properties.md](references/physical-properties.md) and its tested guides. For black-oil tables, conversion and reservoir export, use `docs/blackoil/README.md` and the `pvt-simulation` agent. For APIs absent from this recipe list, follow [source/runtime discovery](../../../docs/development/AGENT_CAPABILITY_DISCOVERY.md). ## MCP server vs. Python/Java API — which to use **Default policy: MCP first.** For any single calculation, always check whether a NeqSim MCP tool (`mcp_neqsim_*`) already covers it before writing Python or Java. Only drop to code when MCP genuinely cannot do the job. Concretely: 1. **Curated tool exists** (`runFlash`, `runProcess`, `runPVT`, `getPhaseEnvelope`, `sizeEquipment`, `calculateStandard`, `runFlowAssurance`, `runBatch`, ...) → use it directly. Confirm field names with `getSchema`/`validateInput` first. 2. **No curated tool, but it might still be reachable** → use `runCapability` (`search` → `inspectApi` → invoke) before writing any code. 3. **`runCapability` reports `inspect-only`, or the task needs loops/plotting/ state/notebooks/reports** → fall back to the Python API (`import neqsim`) or Java in a checkout. This is the *only* reason to write code for a calculation MCP already exposes. 4. **NeqSim itself lacks the capability** (not a packaging gap, an engine gap) → implement it in Java with tests (`spotless:apply`) rather than working around it with ad-hoc Python; see `neqsim-troubleshooting` and the continuous-improvement rule in `AGENTS.md`. Both the MCP tools and the Python/Java API call the same NeqSim engine — the difference is packaging, not physics — but MCP additionally gives a stable JSON contract, schema validation, and provenance/quality-gate info (EOS, convergence, benchmark trust, standards) for free. | Use the **MCP server** (`mcp_neqsim_*` tools) when... | Use the **Python/Java API** (`import neqsim`, or Java in a checkout) when... | |---|---| | No dev environment is available (chat-only client, no terminal/Python/JVM) | Building a task notebook, multi-unit flowsheet, or anything with loops, custom logic, plotting, or state you inspect between steps | | The need is one bounded calculation a curated tool already covers (`runFlash`, `runProcess`, `getPhaseEnvelope`, `sizeEquipment`, `calculateStandard`, ...) | The calculation is not covered by a curated tool and `runCapability` routes it `inspect-only` (no safe generic invocation exists) | | You want the built-in provenance/quality-gate envelope (EOS, convergence, benchmark trust, standards) with no extra code | The run is long or iterative (Monte Carlo, sweeps, optimizer loops) — `runCapability`'s cooperative timeout is for short calls; a script has none | | A different agent/tool needs the result over a stable JSON contract (`composeWorkflow`, `composeMultiServerWorkflow`, cross-client interoperability) | You are inside the `/solve-task` workflow — task folders, validators, report generation, and the NeqSim Runner are Python-only, not exposed over MCP | | Doing bounded discovery of a capability before writing code (`runCapability` search, `inspectApi`) | You need direct object access (intermediate phase properties, custom equipment subclassing, mechanical design classes) beyond what any tool exposes | In a session with both available (e.g. this workspace), default to a curated MCP tool for a single quick calculation or lookup; switch to writing code as soon as the task needs more than one call, custom logic, or a deliverable (notebook, report, task folder). See `neqsim-task-workflow` skill §0.6 for the matrix by *environment* (workspace checkout / pip toolkit / chat-only) rather than by task. ## MCP Runtime Capability Routing When a calculation is not exposed by a curated MCP domain tool, use the generic runtime index before proposing a new tool: 1. Search with `runCapability({"action":"search","query":"<domain method>"})`. 2. Inspect the selected class with `inspectApi` to pin the deployed signature. 3. Follow the returned route: - `static-json`: invoke through `runCapability` with exact `className`, `methodName`, `parameterTypes`, and ordered JSON `arguments`. - `process-json`: build the stateful equipment through `runProcess`. - `inspect-only`: use a curated tool or add an explicit, reviewed adapter. Discovery is broader than execution by design. `runCapability` only invokes public static methods in approved domain packages with scalar, enum, or bounded-array JSON types; MCP runners, raw generic containers, oversized payloads, arbitrary objects, and instance methods are excluded. Its timeout uses cooperative Java interruption, so route long-running calculations through a curated runner or `runProcess`. Treat runtime presence as capability evidence, then check tests, benchmark trust, and standards before using the result for engineering decisions. ### MCP tool inputs: schema first, validate, then run Every calculation tool (`run*`, `sizeEquipment`, `designUtilities`, `calculateStandard`) has a tool-specific input schema whose field names and units mirror the runner exactly. Do not guess field names such as `flowRate_kg_hr` or `setPressure_barg`: 1. `getSchema("run_relief", "input")` — snake_case or camelCase (`runRelief`) both resolve. `required` / `allOf` (mode-dependent, e.g. `case: gas`) / `oneOf` tell you what to send. 2. `validateInput({"tool": "runRelief", "input": {...}})` — any tool; returns `SCHEMA_VIOLATION` issues naming the missing or mistyped field. Flash and process JSON may also be passed bare (auto-detected). 3. Run, then read `status`, `qualityGate`, `provenance.converged` and `warnings`. Process JSON pre-flight is strict: `UNRESOLVED_INLET` (an `inlet` naming no unit — feeds are units of `"type": "Stream"`), `MISPLACED_UNIT_PARAMETERS` (keys beside `properties`, e.g. `outletPressure_bara`; they are otherwise ignored and the unit runs on defaults) and `UNRECOGNIZED_INPUT_SHAPE` (no `process`/`areas`/`components`) are errors, and `runProcess` refuses to report success for a disconnected flowsheet. `runFlowAssurance` `hydrateRiskMap` requires `water` in the composition; an unavailable hydrate temperature is returned as `RESULT_NOT_AVAILABLE`, never as `LOW` risk (`RiskLevel.UNKNOWN` in Java). ## EOS Selection Guide | Fluid Type | Java Class | Mixing Rule | |-----------|-----------|-------------| | Dry/lean gas, simple HC | `SystemSrkEos` | `"classic"` | | General hydrocarbons, oil | `SystemPrEos` | `"classic"` | | **Matched to commercial simulator PR-LK** | **`SystemPrLeeKeslerEos`** | `"classic"` | | Water, MEG, methanol, polar | `SystemSrkCPAstatoil` | `10` (numeric) | | Custody transfer, fiscal metering | `SystemGERG2008Eos` | (none needed) | | Electrolyte systems, **hydrate with salt brine** | `SystemElectrolyteCPAstatoil` | `10` | | Volume-corrected SRK | `SystemSrkEosvolcor` | `"classic"` | | Predictive group contribution (UMR-PRU) | `SystemUMRPRUMCEos` | `setMixingRule("HV", "UNIFAC_UMRPRU")` | **UMR-PRU mixing rule:** the two-argument form is required. `setMixingRule(EosMixingRuleType.HV)` (or copying `otherFluid.getMixingRule()`) selects NRTL-modified Huron-Vidal, not the UMR-PRU UNIFAC model, and silently changes dew points (about 2 C in a lean-gas check). **PR-LK vs PR78**: `SystemPrLeeKeslerEos` uses PR76 alpha for ALL ω: `m = 0.37464 + 1.54226ω − 0.26992ω²`. Standard `SystemPrEos1978` uses a modified cubic for ω > 0.49. Use PR-LK when matching commercial simulator models that use this EOS label. ## Fluid Creation (Required Sequence) ```java // 1. Create: temperature in KELVIN, pressure in bara SystemInterface fluid = new SystemSrkEos(273.15 + 25.0, 60.0); // 2. Add components (name, mole fraction) fluid.addComponent("methane", 0.85); fluid.addComponent("ethane", 0.10); fluid.addComponent("propane", 0.05); // 3. MANDATORY: set mixing rule — NEVER skip fluid.setMixingRule("classic"); // 4. Optional: multi-phase check for water/heavy systems fluid.setMultiPhaseCheck(true); ``` ## Oil Characterization (C7+ Fractions) ```java fluid.addTBPfraction("C7", 0.05, 92.0 / 1000, 0.727); // name, moleFrac, MW_kg/mol, density fluid.addTBPfraction("C8", 0.04, 104.0 / 1000, 0.749); fluid.addPlusFraction("C20", 0.02, 350.0 / 1000, 0.88); // no "+" in the name -- breaks parsing fluid.getCharacterization().configureLumping().model("standard").totalPseudoComponents(6).build(); fluid.getCharacterization().characterisePlusFraction(); fluid.setMixingRule("classic"); // MUST come AFTER characterisePlusFraction() -- see below ``` **Do not call `fluid.getCharacterization().getLumpingModel().setNumberOfLumpedComponents(n)` directly on the default ("standard") lumping model** -- confirmed (2026-10-12, PR review) that `StandardLumpingModel.generateLumpedComposition()` overwrites `numberOfLumpedComponents` with `numberOfPseudocomponents` (both default to 7) at generation time, so `setNumberOfLumpedComponents(6)` alone silently produces 7 pseudo-components, not 6. Use `configureLumping().model("standard").totalPseudoComponents(n).build()`, which sets `numberOfPseudocomponents` directly and is the value the generator actually reads. ## Loading Fluids from E300 Files NeqSim can read Eclipse E300-format fluid files with full component properties and binary interaction parameters: ```java // Load fluid from E300 file (returns SystemInterface with PR-EOS) SystemInterface fluid = EclipseFluidReadWrite.read("path/to/fluid.e300"); // Returns a PR-EOS fluid with all components, properties, and BIPs set ``` **Required E300 sections**: `CNAMES`, `TCRIT`, `PCRIT`, `ACF`, `MW`, `TBOIL`, `VCRIT`, `PARACHOR`, `SSHIFT`, `BIC`, `ZI`. **Optional E300 sections** (NeqSim parses and applies these): - `OMEGAA` / `OMEGAB` — per-component OmegaA/B overrides (applied after `init(0)`) - `BICS` — surface-condition BICs (parsed, same lower-triangular format as `BIC`) - `SSHIFTS` — surface-condition volume shift - `PEDERSEN` — activates Pedersen viscosity model **EOS keyword determines fluid class:** - `EOS\nSRK /` → `SystemSrkEos` - `EOS\nPR /\nPRCORR` → `SystemPrEos1978` - `EOS\nPR /\nPRLKCORR` → `SystemPrLeeKeslerEos` ← use for PR-LK matching - `EOS\nPR /` → `SystemPrEos` **CRITICAL**: The `BIC` section must ALWAYS be present. If omitted, NeqSim defaults to zero BIPs (no crash, but results may differ significantly from the source simulator). The `PARACHOR` section is also required — estimate unknown values with `4.0 * MW^0.77`. **Component name mapping**: `C1`→methane, `C2`→ethane, `C3`→propane, `iC4`→i-butane, `C4`→n-butane, `iC5`→i-pentane, `C5`→n-pentane, `C6`→n-hexane, `N2`→nitrogen, `CO2`→CO2, `H2O`→water. All other names are treated as TBP pseudo-fractions via `addTBPfraction()` — including aromatics (Benzene, Toluene, etc.). ```python # Python usage — auto-detects EOS from file from neqsim import jneqsim EclipseFluidReadWrite = jneqsim.thermo.util.readwrite.EclipseFluidReadWrite fluid = EclipseFluidReadWrite.read("path/to/fluid.e300") # Force a specific EOS regardless of what's in the file SystemPrLeeKeslerEos = jneqsim.thermo.system.SystemPrLeeKeslerEos target_fluid = SystemPrLeeKeslerEos(288.15, 1.01325) fluid = EclipseFluidReadWrite.read("path/to/fluid.e300", target_fluid) ``` **JSON process builder also supports PR-LK** via `"model": "PR_LK"`: ```json { "fluid": { "model": "PR_LK", "temperature": 288.15, "pressure": 50.0, ... } } ``` ## Flash Calculations and Property Retrieval ```java ThermodynamicOperations ops = new ThermodynamicOperations(fluid); ops.TPflash(); // CRITICAL: call initProperties() AFTER flash, BEFORE reading properties // init(3) alone does NOT initialize transport properties — they return ZERO fluid.initProperties(); // Bulk properties double density = fluid.getDensity("kg/m3"); double molarMass = fluid.getMolarMass("kg/mol"); double Z = fluid.getZ(); // Phase properties double gasDensity = fluid.getPhase("gas").getDensity("kg/m3"); double gasViscosity = fluid.getPhase("gas").getViscosity("kg/msec"); double gasThermalCond = fluid.getPhase("gas").getThermalConductivity("W/mK"); double gasCp = fluid.getPhase("gas").getCp("J/kgK"); // Phase checks int numPhases = fluid.getNumberOfPhases(); boolean hasGas = fluid.hasPhaseType("gas"); ``` ### Other Flash Types ```java ops.PHflash(enthalpy); // Pressure-Enthalpy ops.PSflash(entropy); // Pressure-Entropy ops.dewPointTemperatureFlash(); // Dew point temperature ops.bubblePointPressureFlash(); // Bubble point pressure ops.hydrateFormationTemperature(); // Hydrate T at given P ops.calcPTphaseEnvelope(); // Phase envelope ``` > **Saturation flashes can fail without throwing.** A failed continuation in > `dewPointPressureFlash()` / `bubblePointPressureFlash()` can leave a > non-physical pressure on the system and return normally. In a single run someone > notices; inside a Monte Carlo loop it silently poisons a percentile. Validate the > result on physical grounds instead of trusting the absence of an exception: > ```python > ops.dewPointPressureFlash() > p_dew = fluid.getPressure() > if not (10.0 < p_dew < 3.0 * p_reservoir): > p_dew = float("nan") # reject, do not propagate > ``` > > **A plausible value can still be a false root — the start pressure matters.** > For a CO2-rich volatile oil (GOR 383 Sm3/Sm3, 43 % CO2 in gas, 80 C) the same > fluid gave Psat = 474 bara when the flash started at 300 or 450 bara, but > 584 bara when it started at the 641 bara reservoir pressure — and a TP flash > at 480-640 bara is single-phase. Start below the expected saturation pressure > and confirm the root with a stability check either side: > ```python > b = fluid.clone(); b.setPressure(0.5 * p_reservoir) > ThermodynamicOperations(b).bubblePointPressureFlash(False); psat = b.getPressure() > phases = [] > for dp in (-5.0, 5.0): > c = fluid.clone(); c.setPressure(psat + dp) > ThermodynamicOperations(c).TPflash(); phases.append(c.getNumberOfPhases()) > assert phases == [2, 1], "bubble point not bracketed by a phase change" > ``` ### Re-flashing a characterised fluid many times (CRITICAL for loops) To take a phase's composition and flash it somewhere else — produced gas at each depletion step, a recycle stream, a Monte Carlo realization — **clone the already characterised fluid and overwrite its composition**. Do NOT rebuild it with
Voir sur GitHub
Ce SKILL.md est tres volumineux, SkillsMP affiche donc ici seulement la premiere section. Voir sur GitHub