NeqSim Code Patterns
Copy-paste starters for every common task type. All Java 8 compatible.
Table of Contents
- Fluid Creation
- Flash Calculations
- Reading Properties
- Oil Characterization
- Process Equipment
- Stream Introspection
- Named Controllers and Connections
- Complete Process Flowsheet
- Recycle and Adjuster
- PVT Simulations
- Standards Calculations
- Field Development Economics
- SURF Cost Estimation
- Test Patterns
- Jupyter Notebook Patterns
- Benchmark Validation Notebook
- Unit Conversion Reference
Fluid Creation
Simple Gas
SystemInterface fluid = new SystemSrkEos(273.15 + 25.0, 60.0);
fluid.addComponent("methane", 0.85);
fluid.addComponent("ethane", 0.10);
fluid.addComponent("propane", 0.05);
fluid.setMixingRule("classic");
Gas with CO2 and H2S (Sour Gas)
SystemInterface fluid = new SystemSrkEos(273.15 + 40.0, 80.0);
fluid.addComponent("methane", 0.80);
fluid.addComponent("CO2", 0.10);
fluid.addComponent("H2S", 0.05);
fluid.addComponent("nitrogen", 0.05);
fluid.setMixingRule("classic");
Wet Gas (with Water — CPA required)
SystemInterface fluid = new SystemSrkCPAstatoil(273.15 + 30.0, 50.0);
fluid.addComponent("methane", 0.80);
fluid.addComponent("ethane", 0.10);
fluid.addComponent("water", 0.10);
fluid.setMixingRule(10); // numeric rule for CPA
fluid.setMultiPhaseCheck(true);
Gas with MEG (Hydrate Inhibitor)
SystemInterface fluid = new SystemSrkCPAstatoil(273.15 + 5.0, 100.0);
fluid.addComponent("methane", 0.80);
fluid.addComponent("ethane", 0.05);
fluid.addComponent("propane", 0.03);
fluid.addComponent("water", 0.10);
fluid.addComponent("MEG", 0.02);
fluid.setMixingRule(10);
fluid.setMultiPhaseCheck(true);
Rich Gas / Condensate
SystemInterface fluid = new SystemPrEos(273.15 + 80.0, 150.0);
fluid.addComponent("methane", 0.70);
fluid.addComponent("ethane", 0.08);
fluid.addComponent("propane", 0.05);
fluid.addComponent("i-butane", 0.02);
fluid.addComponent("n-butane", 0.03);
fluid.addComponent("i-pentane", 0.01);
fluid.addComponent("n-pentane", 0.01);
fluid.addComponent("n-hexane", 0.005);
fluid.addComponent("CO2", 0.03);
fluid.addComponent("nitrogen", 0.02);
fluid.setMixingRule("classic");
fluid.setMultiPhaseCheck(true);
Flash Calculations
ThermodynamicOperations ops = new ThermodynamicOperations(fluid);
// TP flash (given T and P)
ops.TPflash();
// Bubble/dew point
ops.bubblePointPressureFlash(false); // finds bubble P at current T
ops.dewPointTemperatureFlash(); // finds dew T at current P
// PH flash (constant pressure, given enthalpy)
fluid.init(3);
double enthalpy = fluid.getEnthalpy();
fluid.setPressure(newPressure);
ops.PHflash(enthalpy);
// PS flash (constant pressure, given entropy)
double entropy = fluid.getEntropy();
ops.PSflash(entropy);
// Phase envelope
ops.calcPTphaseEnvelope();
double[] dewT = ops.get("dewT");
double[] dewP = ops.get("dewP");
double[] bubT = ops.get("bubT");
double[] bubP = ops.get("bubP");
Reading Properties
// CRITICAL: call initProperties() after flash — this initializes BOTH
// thermodynamic properties (Cp, enthalpy, entropy) AND transport properties
// (viscosity, thermal conductivity, density with volume correction).
//
// WHY THIS IS NEEDED: Flash calculations (TPflash, PHflash, PSflash) only solve
// phase equilibrium (compositions, phase fractions, Z-factor). They do NOT compute
// transport properties automatically — this is by design for performance, since
// many internal NeqSim loops (stability analysis, phase envelope) only need
// equilibrium results. Without initProperties(), getViscosity() and
// getThermalConductivity() will return ZERO.
//
// NOTE: When using ProcessSystem.run(), initProperties() is called internally
// by each equipment's run() method — no separate call needed for process streams.
fluid.initProperties();
// System-level
double density = fluid.getDensity("kg/m3");
double molarMass = fluid.getMolarMass("kg/mol");
double Z = fluid.getZ();
int numPhases = fluid.getNumberOfPhases();
// Phase-level (transport properties REQUIRE initProperties())
double gasDensity = fluid.getPhase("gas").getDensity("kg/m3");
double oilVisc = fluid.getPhase("oil").getViscosity("kg/msec");
double gasThermCond = fluid.getPhase("gas").getThermalConductivity("W/mK");
double gasCp = fluid.getPhase("gas").getCp("J/kgK");
double surfTension = fluid.getInterphaseProperties().getSurfaceTension(
fluid.getPhaseIndex("gas"), fluid.getPhaseIndex("oil"));
// Component in a phase
double methaneInGas = fluid.getPhase("gas").getComponent("methane").getx(); // mole fraction
// Stream-level (after process.run())
double temp = stream.getTemperature("C"); // Celsius
double pres = stream.getPressure("bara");
double flow = stream.getFlowRate("kg/hr");
double mflow = stream.getFlowRate("MSm3/day"); // million Sm3/day
Oil Characterization
TBP Fractions
SystemInterface oil = new SystemPrEos(273.15 + 80.0, 50.0);
oil.addComponent("methane", 0.30);
oil.addComponent("ethane", 0.05);
oil.addComponent("propane", 0.03);
// addTBPfraction(name, moleFraction, molarMass_kg/mol, density_g/cm3)
oil.addTBPfraction("C7", 0.10, 92.0 / 1000.0, 0.727);
oil.addTBPfraction("C8", 0.08, 104.0 / 1000.0, 0.749);
oil.addTBPfraction("C9", 0.06, 121.0 / 1000.0, 0.768);
oil.addTBPfraction("C10", 0.05, 134.0 / 1000.0, 0.781);
// Plus fraction
oil.addPlusFraction("C11+", 0.33, 250.0 / 1000.0, 0.85);
oil.getCharacterization().getLumpingModel().setNumberOfLumpedComponents(6);
oil.getCharacterization().characterise();
oil.setMixingRule("classic");
oil.setMultiPhaseCheck(true);
Process Equipment
Separator
Separator sep = new Separator("HP Separator", feedStream);
// Outlets:
StreamInterface gasOut = sep.getGasOutStream();
StreamInterface liquidOut = sep.getLiquidOutStream();
// Three-phase:
ThreePhaseSeparator sep3 = new ThreePhaseSeparator("3-Phase Sep", feedStream);
StreamInterface gasOut = sep3.getGasOutStream();
StreamInterface oilOut = sep3.getOilOutStream();
StreamInterface waterOut = sep3.getWaterOutStream();
Compressor
Compressor comp = new Compressor("Compressor", gasStream);
comp.setOutletPressure(120.0, "bara");
// OR set pressure ratio:
// comp.setPressureRatio(3.0);
comp.setIsentropicEfficiency(0.75);
// After run:
double power = comp.getPower("kW");
double outletT = comp.getOutletStream().getTemperature("C");
Compressor Casing Mechanical Design (API 617 / ASME VIII)
// Via CompressorMechanicalDesign (after process run)
Compressor comp = new Compressor("K-100", gasStream);
comp.setOutletPressure(120.0, "bara");
comp.setIsentropicEfficiency(0.75);
process.add(comp);
process.run();
comp.initMechanicalDesign();
CompressorMechanicalDesign design =
(CompressorMechanicalDesign) comp.getMechanicalDesign();
design.setCasingMaterialGrade("SA-516-70");
design.setCasingCorrosionAllowanceMm(3.0);
// For sour service:
// design.setH2sPartialPressureKPa(0.5);
design.calcDesign();
CompressorCasingDesignCalculator casing = design.getCasingDesignCalculator();
double wallMm = casing.getRequiredWallThicknessMm();
double mawpBarg = casing.getMawpBarg();
String flangeClass = casing.getSelectedFlangeClass();
boolean naceOk = casing.isNaceCompliant();
String json = casing.toJson();
// Standalone calculator (without process simulation)
CompressorCasingDesignCalculator calc = new CompressorCasingDesignCalculator();
calc.setDesignPressureBarg(135.0);
calc.setDesignTemperatureC(200.0);
calc.setInnerDiameterMm(800.0);
calc.setMaterialGrade("F316L");
calc.setCorrosionAllowanceMm(1.5);
calc.setJointEfficiency(0.85);
calc.setCasingType("horizontally-split");
calc.calculate();
Cooler / Heater
Cooler cooler = new Cooler("Aftercooler", compressor.getOutletStream());
cooler.setOutTemperature(273.15 + 35.0); // Kelvin!
// After run:
double duty = cooler.getDuty(); // Watts (negative = cooling)
Heater heater = new Heater("Preheater", feedStream);
heater.setOutTemperature(273.15 + 80.0);
Valve
ThrottlingValve valve = new ThrottlingValve("JT Valve", stream);
valve.setOutletPressure(20.0, "bara");
// After run: check outlet temperature (JT cooling)
double outT = valve.getOutletStream().getTemperature("C");
Pump
Pump pump = new Pump("Export Pump", liquidStream);
pump.setOutletPressure(80.0, "bara");
pump.setIsentropicEfficiency(0.75);
// After run:
double power = pump.getPower("kW");
Heat Exchanger
HeatExchanger hx = new HeatExchanger("Lean/Rich HX", hotStream);
hx.setFeedStream(1, coldStream);
hx.setUAvalue(15000.0); // W/K
// After run:
double duty = hx.getDuty();
Mixer
Mixer mixer = new Mixer("Mixer");
mixer.addStream(stream1);
mixer.addStream(stream2);
StreamInterface mixed = mixer.getOutletStream();
Splitter
Splitter splitter = new Splitter("Splitter", feedStream);
splitter.setSplitNumber(2);
splitter.setSplitFactors(new double[]{0.7, 0.3});
StreamInterface out1 = splitter.getSplitStream(0);
StreamInterface out2 = splitter.getSplitStream(1);
Pipeline
AdiabaticPipe pipe = new AdiabaticPipe("Pipeline", feedStream);
pipe.setLength(50000.0); // meters
pipe.setDiameter(0.508); // meters (20 inch)
pipe.setPipeWallRoughness(5e-5); // meters
// After run:
double outP = pipe.getOutletStream().getPressure("bara");
Two-Fluid Pipe (Transient Multiphase)
TwoFluidPipe pipe = new TwoFluidPipe("Flowline", feedStream);
pipe.setLength(5000); // meters
pipe.setDiameter(0.3); // meters
pipe.setNumberOfSections(100); // computational cells
pipe.setRoughness(4.5e-5); // wall roughness (m)
// Steady-state initialization
pipe.run();
// Transient simulation
UUID simId = UUID.randomUUID();
for (int step = 0; step < 600; step++) {
pipe.runTransient(0.5, simId); // 0.5 s time step
}
// Results
double[] pressures = pipe.getPressureProfile();
double[] holdups = pipe.getLiquidHoldupProfile();
double inventory = pipe.getLiquidInventory("m3");
Two-Fluid Pipe Benchmark (Cross-Validate vs Beggs & Brill)
// Compare TwoFluidPipe pressure drop against PipeBeggsAndBrills
PipeBeggsAndBrills bbPipe = new PipeBeggsAndBrills("BB", feedStream);
bbPipe.setLength(5000); bbPipe.setDiameter(0.3);
bbPipe.setAngle(0); bbPipe.setPipeWallRoughness(4.5e-5);
TwoFluidPipe tfPipe = new TwoFluidPipe("TF", feedStream);
tfPipe.setLength(5000); tfPipe.setDiameter(0.3);
tfPipe.setNumberOfSections(50); tfPipe.setRoughness(4.5e-5);
// Run both
bbPipe.run(); tfPipe.run();
double dpBB = feedStream.getPressure() - bbPipe.getOutletStream().getPressure();
double dpTF = feedStream.getPressure() - tfPipe.getOutletStream().getPressure();
double ratio = dpTF / dpBB;
// Expect ratio 0.8–1.3 for engineering accuracy
Two-Fluid Pipe with Virtual Mass Force
// Enable virtual mass force for improved slug dynamics and pressure surge prediction
TwoFluidPipe pipe = new TwoFluidPipe("Pipeline", feedStream);
pipe.setLength(5000);
pipe.setDiameter(0.3);
pipe.setNumberOfSections(100);
// Enable virtual mass force (Drew & Lahey 1987)
pipe.getEquations().setEnableVirtualMassForce(true);
pipe.getEquations().setVirtualMassCoefficient(0.5); // Default for spheres
pipe.getEquations().setTimestep(0.1); // Required for dv/dt calculation
pipe.run();
Two-Fluid Pipe with Junction/Bend Losses
// Add local loss coefficients for fittings
TwoFluidPipe pipe = new TwoFluidPipe("Pipeline", feedStream);
pipe.setLength(5000);
pipe.setDiameter(0.3);
pipe.setNumberOfSections(100);
// Add named K-factor losses
pipe.addLocalLoss("Tee junction", 0.9);
pipe.addLocalLoss("Gate valve", 0.17);
pipe.addLocalLoss("Check valve", 2.0);
// Use convenience methods for standard bends
pipe.setNumberOf90DegreeBends(4); // K=0.3 each
pipe.setNumberOf45DegreeBends(2); // K=0.16 each
pipe.setInletLossCoefficient(0.5); // Sharp entrance
pipe.setOutletLossCoefficient(1.0); // Exit to tank
pipe.run();
// Get pressure drop breakdown
double dpFriction = pipe.getPressureDrop();
double dpLocal = pipe.calculateLocalLossPressureDrop();
double dpTotal = pipe.getTotalPressureDrop();
System.out.println(pipe.getLocalLossSummary());
Interfacial Friction Correlations
// Use Hart correlation for oil-gas stratified wavy flow
double fi = InterfacialFriction.calcHartCorrelation(
liquidHoldup, diameter, gasVelocity, liquidVelocity);
// Use Andreussi-Persen (OLGA-style) with inclination
double fi = InterfacialFriction.calcAndreussiPersenCorrelation(
liquidHoldup, diameter, gasVelocity, liquidVelocity,
gasDensity, liquidDensity, surfaceTension, inclinationRadians);
Transient Boundary Conditions
// Configure boundary conditions for transient two-fluid simulation
TwoFluidPipe pipe = new TwoFluidPipe("Pipeline", feedStream);
pipe.setLength(10000);
pipe.setDiameter(0.25);
pipe.setNumberOfSections(50);
// Default: flow from stream, fixed outlet pressure
pipe.setOutletPressure(30.0, "bara");
// Option 1: Explicit mass flow (decoupled from stream)
pipe.setInletBoundaryCondition(TwoFluidPipe.BoundaryCondition.CONSTANT_FLOW);
pipe.setInletMassFlow(50.0); // kg/s
// or with unit: pipe.setInletMassFlow(180000, "kg/hr");
// Option 2: Fixed pressures at both ends (flow computed)
pipe.setInletBoundaryCondition(TwoFluidPipe.BoundaryCondition.CONSTANT_PRESSURE);
pipe.setInletPressure(60.0, "bara");
pipe.setOutletPressure(30.0, "bara");
// Query current BC types
TwoFluidPipe.BoundaryCondition inletBC = pipe.getInletBoundaryCondition();
TwoFluidPipe.BoundaryCondition outletBC = pipe.getOutletBoundaryCondition();
// Initialize and run transient
pipe.run();
for (int t = 0; t < 120; t++) {
// Can change flow rate during simulation
if (t == 60) {
pipe.setInletMassFlow(75.0); // Step increase at 60s
}
pipe.runTransient(1.0);
}
Shut-In and Surge Scenarios
// Close outlet for shut-in / pressure surge analysis
TwoFluidPipe pipe = new TwoFluidPipe("Pipeline", feedStream);
pipe.setLength(10000);
pipe.setDiameter(0.25);
pipe.setNumberOfSections(100);
pipe.setOutletPressure(30.0, "bara");
pipe.run();
// Shut-in: close outlet valve
pipe.closeOutlet(); // Sets BC to CLOSED (zero velocity, pressure floats)
for (int t = 0; t < 60; t++) {
pipe.runTransient(1.0);
double[] pressures = pipe.getPressureProfile();
System.out.printf("t=%ds: inlet=%.2f bara, outlet=%.2f bara%n",
t, pressures[0]/1e5, pressures[pressures.length-1]/1e5);
}
// Reopen outlet
pipe.openOutlet(30.0, "bara"); // Opens with specified back-pressure
// Blowdown: close inlet, open outlet
pipe.closeInlet();
pipe.openOutlet(1.0, "bara"); // Vent to atmospheric
// Check closure state
if (pipe.isOutletClosed()) {
System.out.println("Outlet is blocked");
}
Stream Introspection
Query inlet/outlet streams on any equipment without casting:
// Works on any ProcessEquipmentInterface
List<StreamInterface> inlets = equipment.getInletStreams();
List<StreamInterface> outlets = equipment.getOutletStreams();
// Example: walk the flowsheet
for (ProcessEquipmentInterface unit : process.getUnitOperations()) {
System.out.printf("%-20s in=%d out=%d%n",
unit.getName(),
unit.getInletStreams().size(),
unit.getOutletStreams().size());
}
| Equipment | Inlets | Outlets |
|---|---|---|
| TwoPortEquipment (Heater, Compressor, Valve, …) | 1 | 1 |
| Separator | N | 2 (gas, liquid) |
| ThreePhaseSeparator | N | 3 (gas, oil, water) |
| Mixer | N | 1 |
| Splitter | 1 | N |
Named Controllers and Connections
Multiple Controllers per Equipment
// Attach by tag
valve.addController("LC-100", levelController);
valve.addController("PC-200", pressureController);
// Retrieve by tag
ControllerDeviceInterface lc = valve.getController("LC-100");
// All controllers
Collection<ControllerDeviceInterface> all = valve.getControllers();
Explicit Connections (metadata for DEXPI / diagrams)
process.connect(feed, separator, feed.getOutletStream(),
ProcessConnection.ConnectionType.MATERIAL, "Feed to HP Sep");
// Simple form
process.connect(separator, compressor);
// Query
List<ProcessConnection> conns = process.getConnections();
Unified Element Query
// All elements: equipment + measurements + controllers
List<ProcessElementInterface> all = process.getAllElements();
Complete Process Flowsheet
Gas Compression Train
ProcessSystem process = new ProcessSystem();
// Feed
Stream feed = new Stream("feed", fluid);
feed.setFlowRate(50000.0, "kg/hr");
feed.setTemperature(30.0, "C");
feed.setPressure(10.0, "bara");
process.add(feed);
// Stage 1
Compressor comp1 = new Compressor("Stage 1", feed);
comp1.setOutletPressure(30.0, "bara");
comp1.setIsentropicEfficiency(0.75);
process.add(comp1);
Cooler cool1 = new Cooler("Intercooler 1", comp1.getOutletStream());
cool1.setOutTemperature(273.15 + 35.0);
process.add(cool1);
// Stage 2
Compressor comp2 = new Compressor("Stage 2", cool1.getOutletStream());
comp2.setOutletPressure(90.0, "bara");
comp2.setIsentropicEfficiency(0.75);
process.add(comp2);
Cooler cool2 = new Cooler("Aftercooler", comp2.getOutletStream());
cool2.setOutTemperature(273.15 + 35.0);
process.add(cool2);
process.run();
double totalPower = comp1.getPower("kW") + comp2.getPower("kW");
System.out.println("Total power: " + totalPower + " kW");
Recycle and Adjuster
Recycle (Iteration Loop)
// Used when an outlet stream feeds back to an earlier point
Recycle recycle = new Recycle("recycle");
recycle.addStream(returnStream); // the stream coming back
recycle.setOutletStream(inletStream); // the stream it feeds into
recycle.setTolerance(1e-4);
process.add(recycle);
// ProcessSystem.run() will iterate until recycle converges
Adjuster (Match a Spec)
// Adjust flow to match a target outlet pressure
Adjuster adj = new Adjuster("pressure adj");
adj.setAdjustedVariable(stream1, "flow", "MSm3/day"); // what to vary
adj.setTargetVariable(outletStream, "pressure", 50.0, "bara"); // target spec
adj.setMaxAdjustmentSteps(50);
process.add(adj);
PVT Simulations
Constant Mass Expansion (CME)
SystemInterface fluid = new SystemPrEos(273.15 + 100.0, 300.0);
// add components...
fluid.setMixingRule("classic");
ConstantMassExpansion cme = new ConstantMassExpansion(fluid);
cme.setTemperature(273.15 + 100.0);
cme.setPressures(new double[]{400, 350, 300, 250, 200, 150, 100, 50});
cme.runCalc();
double satP = cme.getSaturationPressure();
double[] relVol = cme.getRelativeVolume();
Constant Volume Depletion (CVD)
ConstantVolumeDepletion cvd = new ConstantVolumeDepletion(fluid);
cvd.setTemperature(273.15 + 100.0);
cvd.setPressures(pressures);
cvd.runCalc();
Standards Calculations
Gas Quality (ISO 6976)
SystemInterface gas = new SystemSrkEos(273.15 + 15.0, 1.01325);
gas.addComponent("methane", 0.90);
gas.addComponent("ethane", 0.06);
gas.addComponent("propane", 0.03);
gas.addComponent("CO2", 0.01);
gas.setMixingRule("classic");
ThermodynamicOperations ops = new ThermodynamicOperations(gas);
ops.TPflash();
Standard_ISO6976 iso = new Standard_ISO6976(gas);
iso.setReferenceState("15C");
iso.calculate();
double gcv = iso.getValue("GCV");
double wobbe = iso.getValue("WobbeIndex");
Field Development Economics (NPV / Cash Flow)
Norwegian Petroleum Tax Model
// Norwegian tax: corporate (22%) + special petroleum (56%) on INDEPENDENT bases
double corporateTaxRate = 0.22;
double specialTaxRate = 0.56;
double upliftRate = 0.055; // 5.5% per year for 4 years
int upliftYears = 4;
int depreciationYears = 6; // Straight-line
// Depreciation (straight-line over 6 years)
double annualDepreciation = (year >= 1 && year <= depreciationYears)
? totalCapex / depreciationYears : 0.0;
// Uplift (only for special petroleum tax base)
double uplift = (year >= 1 && year <= upliftYears)
? totalCapex * upliftRate : 0.0;
// INDEPENDENT taxable incomes (NOT cascaded)
double taxableIncomeCorp = revenue - opex - annualDepreciation - tariff;
double taxableIncomePetro = revenue - opex - annualDepreciation - tariff - uplift;
// Loss carry-forward per pool (no interest on carried losses)
double corpLoss = Math.max(0, -taxableIncomeCorp + carriedCorpLoss);
double petroLoss = Math.max(0, -taxableIncomePetro + carriedPetroLoss);
double corpTax = Math.max(0, taxableIncomeCorp - carriedCorpLoss) * corporateTaxRate;
double petroTax = Math.max(0, taxableIncomePetro - carriedPetroLoss) * specialTaxRate;
double totalTax = corpTax + petroTax;
// Cash flow: Year 0 = CAPEX only, revenue starts Year 1
double cashFlow = (year == 0) ? -totalCapex : revenue - opex - tariff - totalTax;
Production Profile (Plateau + Decline)
import numpy as np
def production_profile(reserves_Sm3, plateau_rate_Sm3_yr, decline_rate, years):
"""Generate plateau + exponential decline production profile."""
production = np.zeros(years)
cumulative = 0.0
for yr in range(years):
if cumulative < reserves_Sm3 * 0.3: # plateau phase
annual = min(plateau_rate_Sm3_yr, reserves_Sm3 - cumulative)
else: # decline phase
annual = production[yr-1] * (1 - decline_rate) if yr > 0 else plateau_rate_Sm3_yr
annual = min(annual, reserves_Sm3 - cumulative)
production[yr] = max(0, annual)
cumulative += production[yr]
return production
NPV Calculation
def calculate_npv(cash_flows, discount_rate):
"""Calculate NPV from array of annual cash flows (year 0 at index 0)."""
return sum(cf / (1 + discount_rate)**t for t, cf in enumerate(cash_flows))
Using CashFlowEngine (Java)
import neqsim.process.fielddevelopment.economics.CashFlowEngine;
import neqsim.process.fielddevelopment.economics.CashFlowEngine.CashFlowResult;
// Create engine with Norwegian tax model ("NO")
CashFlowEngine engine = new CashFlowEngine("NO");
// Prices (units match your currency — e.g., NOK/Sm3 for Norwegian gas)
engine.setGasPrice(1.5); // NOK/Sm3
engine.setGasTariff(0.015); // NOK/Sm3
engine.setFixedOpexPerYear(200.0); // MNOK/year
// CAPEX schedule by calendar year
engine.addCapex(50.0, 2020); // Pre-DG3
engine.addCapex(150.0, 2021);
engine.addCapex(4033.0, 2022); // DG3-DG4 construction
engine.addCapex(4033.0, 2023);
engine.addCapex(4033.0, 2024);
// Annual production (year, oilBbl, gasSm3, nglBbl)
engine.addAnnualProduction(2025, 0, 3.4e9, 0);
engine.addAnnualProduction(2026, 0, 3.4e9, 0);
engine.addAnnualProduction(2027, 0, 3.0e9, 0);
// ... more years
// Calculate
CashFlowResult result = engine.calculate(0.08); // 8% discount rate
double npv = result.getNpv();
double irr = result.getIrr();
double payback = result.getPaybackYears();
String summary = result.getSummary();
String table = result.toMarkdownTable();
// Breakeven analysis
double breakevenGasPrice = engine.calculateBreakevenGasPrice(0.08);
SURF Cost Estimation (Subsea Field Development)
Using SURFCostEstimator (Java)
import neqsim.process.mechanicaldesign.subsea.SURFCostEstimator;
import neqsim.process.mechanicaldesign.subsea.SubseaCostEstimator;
// Constructor: (numberOfWells, waterDepthM, region)
SURFCostEstimator surf = new SURFCostEstimator(6, 300.0, SubseaCostEstimator.Region.NORWAY);
// S — Subsea infrastructure
surf.setTreePressureRatingPsi(10000.0);
surf.setTreeBoreSizeInches(5.0);
surf.setHorizontalTrees(true);
surf.setManifoldSlots(6);
surf.setManifoldWeightTonnes(140.0);
surf.setNumberOfPLETs(2);
surf.setNumberOfJumpers(6);
// U — Umbilicals
surf.setUmbilicalLengthKm(10.0);
surf.setUmbilicalDynamic(true);
// R — Risers
surf.setIncludeRisers(true);
surf.setFlexibleRiser(true);
surf.setRiserDiameterInches(8.0);
surf.setNumberOfProductionRisers(1);
// F — Flowlines
surf.setInfieldFlowlineLengthKm(10.0);
surf.setInfieldFlowlineDiameterInches(14.0);
surf.setExportPipelineLengthKm(80.0);
surf.setExportPipelineDiameterInches(24.0);
surf.setPipelineMaterialGrade("X65");
surf.setPipelineDesignPressureBar(165.0);
surf.setPipelineInstallMethod("S-lay");
surf.setContingencyPct(0.15);
double totalUSD = surf.calculate();
// Get cost breakdown
double subseaCost = surf.getSubseaCostUSD();
double umbilicalCost = surf.getUmbilicalCostUSD();
double riserCost = surf.getRiserCostUSD();
double flowlineCost = surf.getFlowlineCostUSD();
double totalNOK = surf.getTotalCostInCurrency(10.5); // exchange rate
String json = surf.toJson();
Using SURFCostEstimator from Python Notebook
import jpype
# Load from local build if not in pip package
try:
SURFCostEstimator = jpype.JClass(
"neqsim.process.mechanicaldesign.subsea.SURFCostEstimator")
SubseaCostEstimator = jpype.JClass(
"neqsim.process.mechanicaldesign.subsea.SubseaCostEstimator")
except Exception:
import glob, pathlib
jar = glob.glob(str(pathlib.Path("target") / "neqsim-*-shaded.jar"))
if jar:
jpype.addClassPath(jar[0])
SURFCostEstimator = jpype.JClass(
"neqsim.process.mechanicaldesign.subsea.SURFCostEstimator")
SubseaCostEstimator = jpype.JClass(
"neqsim.process.mechanicaldesign.subsea.SubseaCostEstimator")
surf = SURFCostEstimator(6, 300.0, SubseaCostEstimator.Region.NORWAY)
surf.setExportPipelineLengthKm(80.0)
surf.setExportPipelineDiameterInches(24.0)
surf.setNumberOfPLETs(2)
surf.setNumberOfJumpers(6)
surf.calculate()
total_usd = float(surf.getTotalSURFCostUSD())
total_nok = float(surf.getTotalCostInCurrency(10.5))
Typical NCS SURF Cost Benchmarks
| Component | Typical Range (MUSD) | Notes |
|---|---|---|
| Subsea tree | 5-15 per tree | Vertical or horizontal |
| Manifold | 10-25 each | 4-slot or 8-slot |
| PLET | 2-5 each | Per flowline end |
| Jumper | 3-8 each | Rigid or flexible |
| Umbilical | 800-2,000/km | Static + dynamic |
| Riser | 15-50 each | Flexible; more for SCR |
| Flowline (rigid) | 1,500-5,000/m | Depends on diameter and wall thickness |
| Export pipeline | 1,500-4,000/m | Material + installation |
| SURF as % of total CAPEX | 40-60% | NCS subsea tieback |
Test Patterns
Basic Process Test
package neqsim.process.equipment.compressor;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
import neqsim.process.processmodel.ProcessSystem;
import neqsim.process.equipment.stream.Stream;
import neqsim.thermo.system.SystemInterface;
import neqsim.thermo.system.SystemSrkEos;
public class CompressorFeatureTest extends neqsim.NeqSimTest {
@Test
void testCompressorPower() {
SystemInterface fluid = new SystemSrkEos(273.15 + 30.0, 10.0);
fluid.addComponent("methane", 0.9);
fluid.addComponent("ethane", 0.1);
fluid.setMixingRule("classic");
ProcessSystem process = new ProcessSystem();
Stream feed = new Stream("feed", fluid);
feed.setFlowRate(10000.0, "kg/hr");
feed.setPressure(10.0, "bara");
feed.setTemperature(30.0, "C");
process.add(feed);
Compressor comp = new Compressor("comp", feed);
comp.setOutletPressure(30.0, "bara");
comp.setIsentropicEfficiency(0.75);
process.add(comp);
process.run();
assertTrue(comp.getPower("kW") > 0, "Compressor should consume power");
assertTrue(comp.getOutletStream().getTemperature("C") > 30.0,
"Outlet should be hotter than inlet");
assertEquals(30.0, comp.getOutletStream().getPressure("bara"), 0.01);
}
}
Regression Test (Baseline Values)
@Test
void testBaselineValues() {
// Setup...
process.run();
// Capture these values once, then assert they don't drift
assertEquals(245.3, comp.getPower("kW"), 5.0,
"Power should be ~245 kW (baseline from 2026-03-01)");
assertEquals(98.7, stream.getTemperature("C"), 1.0,
"Outlet T should be ~99°C");
}
Jupyter Notebook Patterns
Standard Setup Cell (pip)
from neqsim import jneqsim
SystemSrkEos = jneqsim.thermo.system.SystemSrkEos
ProcessSystem = jneqsim.process.processmodel.ProcessSystem
Stream = jneqsim.process.equipment.stream.Stream
Separator = jneqsim.process.equipment.separator.Separator
Compressor = jneqsim.process.equipment.compressor.Compressor
Cooler = jneqsim.process.equipment.heatexchanger.Cooler
Devtools Setup Cell (local dev)
from neqsim_dev_setup import neqsim_init, neqsim_classes
ns = neqsim_init(recompile=False)
ns = neqsim_classes(ns)
# Use: ns.SystemSrkEos, ns.Stream, ns.Compressor, etc.
Results Display
import pandas as pd
process.run()
results = {
"Equipment": ["Compressor", "Cooler"],
"Power/Duty (kW)": [
float(comp.getPower("kW")),
float(cooler.getDuty()) / 1000.0
],
"Outlet T (°C)": [
float(comp.getOutletStream().getTemperature("C")),
float(cooler.getOutletStream().getTemperature("C"))
],
"Outlet P (bara)": [
float(comp.getOutletStream().getPressure("bara")),
float(cooler.getOutletStream().getPressure("bara"))
],
}
pd.DataFrame(results)
Benchmark Validation Notebook
Every task MUST include a separate benchmark notebook. Use this template:
# Cell 1: Introduction (markdown)
# ## Benchmark Validation
# Compare NeqSim results against independent reference data to verify
# that the model and equations are producing trustworthy results.
# Cell 2: Reference data
import pandas as pd
import numpy as np
benchmark_data = pd.DataFrame({
"Condition": ["25C, 1 bar", "25C, 50 bar", "25C, 100 bar", "50C, 100 bar"],
"Source": ["NIST", "NIST", "NIST", "NIST"],
"density_kg_m3": [0.656, 35.18, 77.50, 60.12], # reference values
"Cp_J_kgK": [2226, 2950, 4100, 3200],
})
print("Reference data from NIST Webbook (methane)")
benchmark_data
# Cell 3: NeqSim calculation at same conditions
from neqsim import jneqsim
ThermodynamicOperations = jneqsim.thermodynamicoperations.ThermodynamicOperations
def calc_properties(T_C, P_bar):
fluid = jneqsim.thermo.system.SystemSrkEos(273.15 + T_C, P_bar)
fluid.addComponent("methane", 1.0)
fluid.setMixingRule("classic")
ops = ThermodynamicOperations(fluid)
ops.TPflash()
fluid.initProperties() # initializes thermo + transport properties
return {
"density_kg_m3": float(fluid.getDensity("kg/m3")),
"Cp_J_kgK": float(fluid.getCp("J/kgK")),
}
conditions = [(25, 1), (25, 50), (25, 100), (50, 100)]
neqsim_results = [calc_properties(T, P) for T, P in conditions]
# Cell 4: Comparison table
for i, res in enumerate(neqsim_results):
benchmark_data.loc[i, "neqsim_density"] = res["density_kg_m3"]
benchmark_data.loc[i, "density_dev_pct"] = abs(
res["density_kg_m3"] - benchmark_data.loc[i, "density_kg_m3"]
) / benchmark_data.loc[i, "density_kg_m3"] * 100
print("\nComparison: Benchmark vs NeqSim")
benchmark_data[["Condition", "density_kg_m3", "neqsim_density", "density_dev_pct"]]
# Cell 5: Parity plot
import matplotlib.pyplot as plt
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
# Parity plot
ax = axes[0]
ax.scatter(benchmark_data["density_kg_m3"], benchmark_data["neqsim_density"])
lims = [0, max(benchmark_data["density_kg_m3"].max(), benchmark_data["neqsim_density"].max()) * 1.1]
ax.plot(lims, lims, 'k--', label='Perfect agreement')
ax.set_xlabel("Benchmark density (kg/m\u00b3)")
ax.set_ylabel("NeqSim density (kg/m\u00b3)")
ax.set_title("Parity Plot: Density")
ax.legend(); ax.grid(True)
# Deviation bar chart
ax = axes[1]
ax.bar(benchmark_data["Condition"], benchmark_data["density_dev_pct"])
ax.axhline(y=5.0, color='r', linestyle='--', label='5% tolerance')
ax.set_ylabel("Deviation (%)")
ax.set_title("Deviation from NIST Benchmark")
ax.legend(); ax.grid(True, axis='y')
plt.tight_layout()
# fig.savefig(str(FIGURES_DIR / "benchmark_parity.png"), dpi=150, bbox_inches="tight")
plt.show()
# Cell 6: Save benchmark results to results.json
benchmark_validation = {
"benchmark_source": "NIST Webbook",
"comparisons": [
{"parameter": "density_kg_m3",
"benchmark": float(row["density_kg_m3"]),
"neqsim": float(row["neqsim_density"]),
"deviation_pct": round(float(row["density_dev_pct"]), 2),
"condition": row["Condition"]}
for _, row in benchmark_data.iterrows()
],
"max_deviation_pct": round(float(benchmark_data["density_dev_pct"].max()), 2),
"all_within_tolerance": bool(benchmark_data["density_dev_pct"].max() < 5.0),
"tolerance_pct": 5.0,
}
# Add to results dict: results["benchmark_validation"] = benchmark_validation
Unit Conversion Reference
| Property | NeqSim Default | Common Units |
|---|---|---|
| Temperature | Kelvin | "C", "K" |
| Pressure | bara | "bara", "barg", "Pa", "psi" |
| Flow rate | — | "kg/hr", "m3/hr", "MSm3/day", "MMSCFD" |
| Power | Watts | "W", "kW", "MW", "hp" |
| Density | kg/m3 | "kg/m3", "lb/ft3" |
| Viscosity | — | "kg/msec", "cP" |
| Molar mass | kg/mol | "kg/mol", "g/mol" |
Constructor temperature is always Kelvin. Use 273.15 + celsius.
setTemperature(30.0, "C") on streams accepts a unit string.
getTemperature() without a unit returns Kelvin.