NeqSim Digital Field Twin Framework
Overview
NeqSim provides a comprehensive Digital Field Twin capability that links field development planning to detailed thermodynamic, process, and mechanical calculations. This creates consistency throughout the field lifecycle—from exploration through development, operation, and decommissioning.
┌─────────────────────────────────────────────────────────────────────────────┐
│ NEQSIM DIGITAL FIELD TWIN ARCHITECTURE │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ EXPLORATION │───▶│ DEVELOPMENT │───▶│ OPERATION │───▶│ LATE LIFE │ │
│ │ DG0-DG1 │ │ DG2-DG4 │ │ Steady & │ │ Decommiss. │ │
│ │ │ │ │ │ Transient │ │ │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ UNIFIED THERMODYNAMIC ENGINE │ │
│ │ • Equations of State (SRK, PR, CPA) │ │
│ │ • Flash Calculations (PT, PH, PS, TVn) │ │
│ │ • Phase Equilibria & Properties │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ PROCESS SIMULATION ENGINE │ │
│ │ • Equipment Models (Separators, Compressors, Heat Exchangers) │ │
│ │ • Flowsheet Solving (Sequential, Recycle, Adjust) │ │
│ │ • Mechanical Design (Sizing, Pressure Rating) │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Key Integration Points
1. Reservoir ↔ Wells ↔ Facilities
// Create unified model from reservoir to export
FieldConcept concept = FieldConcept.builder("Johan Sverdrup Phase 2")
.reservoir(ReservoirInput.builder()
.fluidType(FluidType.MEDIUM_OIL)
.gor(150.0) // Sm³/Sm³
.waterCut(0.0) // Initial
.reservoirPressure(280.0) // bara
.reservoirTemperature(90.0) // °C
.build())
.wells(WellsInput.builder()
.producerCount(8)
.injectorCount(4)
.ratePerWell(15000.0) // Sm³/d oil
.wellType(WellType.HORIZONTAL)
.build())
.infrastructure(InfrastructureInput.builder()
.processingLocation(ProcessingLocation.PLATFORM)
.exportType(ExportType.PIPELINE)
.waterDepth(120.0) // m
.build())
.build();
// Generate detailed process model from concept
ConceptToProcessLinker linker = new ConceptToProcessLinker();
ProcessSystem process = linker.generateProcessSystem(concept, FidelityLevel.CONCEPT);
// Run thermodynamic simulation
process.run();
// Extract results for reservoir coupling
ReservoirCouplingExporter exporter = new ReservoirCouplingExporter(process);
exporter.exportToFile("vfp_tables.inc", ExportFormat.ECLIPSE_100);
2. PVT ↔ Process ↔ Flow Assurance
// Define fluid with detailed PVT
SystemInterface fluid = new SystemSrkEos(273.15 + 60.0, 50.0);
fluid.addComponent("methane", 0.45);
fluid.addComponent("ethane", 0.08);
fluid.addComponent("propane", 0.05);
fluid.addComponent("nC10", 0.35);
fluid.addComponent("water", 0.07);
fluid.setMixingRule("classic");
fluid.setMultiPhaseCheck(true);
// Create process stream
Stream wellStream = new Stream("Well-1 Stream", fluid);
wellStream.setFlowRate(100000.0, "kg/hr");
wellStream.run();
// Flow assurance check with consistent thermodynamics
MultiphaseFlowIntegrator flowIntegrator = new MultiphaseFlowIntegrator();
PipelineResult result = flowIntegrator.calculateHydraulics(
wellStream,
5000.0, // length (m)
0.25, // diameter (m)
-2.0 // inclination (degrees)
);
// Check flow regime and liquid holdup
System.out.println("Flow Regime: " + result.getFlowRegime());
System.out.println("Pressure Drop: " + result.getPressureDropBar() + " bar");
System.out.println("Liquid Holdup: " + result.getLiquidHoldup());
Mathematical Foundations
Portfolio Optimization
The PortfolioOptimizer solves the capital-constrained project selection problem:
Subject to: \(\sum_{i=1}^{n} x_i \cdot CAPEX_{i,t} \leq Budget_t \quad \forall t\) \(x_i \in \{0, 1\}\)
Optimization Strategies
| Strategy | Ranking Function | Use Case |
|---|---|---|
| GREEDY_NPV_RATIO | $\frac{NPV_i}{CAPEX_i}$ | Capital-constrained portfolios |
| RISK_WEIGHTED | $P_i \cdot NPV_i$ | High-uncertainty environments |
| EMV_MAXIMIZATION | $EMV_i = P_i \cdot NPV_i - (1-P_i) \cdot Cost_{dry}$ | Exploration portfolios |
| BALANCED | Weighted mix ensuring type diversity | Strategic balance |
Usage Example
PortfolioOptimizer optimizer = new PortfolioOptimizer();
// Add candidate projects
optimizer.addProject("Field A", 800.0, 1200.0, ProjectType.DEVELOPMENT, 0.85);
optimizer.addProject("Field B IOR", 150.0, 280.0, ProjectType.IOR, 0.92);
optimizer.addProject("Exploration C", 200.0, 800.0, ProjectType.EXPLORATION, 0.35);
optimizer.addProject("Tieback D", 300.0, 450.0, ProjectType.TIEBACK, 0.88);
// Set budget constraints
optimizer.setAnnualBudget(2025, 500.0);
optimizer.setAnnualBudget(2026, 600.0);
optimizer.setAnnualBudget(2027, 400.0);
optimizer.setTotalBudget(1500.0);
// Optimize and compare strategies
Map<OptimizationStrategy, PortfolioResult> results = optimizer.compareStrategies();
// Generate report
String report = optimizer.generateComparisonReport();
Multi-Criteria Decision Analysis (MCDA)
The DevelopmentOptionRanker uses weighted sum normalization:
Where normalized scores are:
For “higher is better” criteria: \(\tilde{s}_{ij} = \frac{s_{ij} - s_j^{min}}{s_j^{max} - s_j^{min}}\)
For “lower is better” criteria: \(\tilde{s}_{ij} = \frac{s_j^{max} - s_{ij}}{s_j^{max} - s_j^{min}}\)
Criterion Categories
| Category | Criteria | Direction |
|---|---|---|
| Economic | NPV, IRR, Capital Efficiency, Breakeven Price | ↑↓ mixed |
| Technical | Complexity, Risk, Reservoir Uncertainty | ↓ lower is better |
| Environmental | CO₂ Intensity, Total Emissions | ↓ lower is better |
| Strategic | Strategic Fit, Synergies, Optionality | ↑ higher is better |
| Risk | HSE Risk, Execution Risk, Commercial Risk | ↓ lower is better |
Weight Profiles
DevelopmentOptionRanker ranker = new DevelopmentOptionRanker();
// Pre-defined profiles
ranker.setWeightProfile("economic"); // NPV/IRR focused
ranker.setWeightProfile("sustainability"); // CO2/environment focused
ranker.setWeightProfile("balanced"); // Equal weights
ranker.setWeightProfile("risk_averse"); // Risk minimization
// Or custom weights
ranker.setWeight(Criterion.NPV, 0.25);
ranker.setWeight(Criterion.CO2_INTENSITY, 0.20);
ranker.setWeight(Criterion.TECHNICAL_RISK, 0.15);
ranker.setWeight(Criterion.STRATEGIC_FIT, 0.15);
ranker.setWeight(Criterion.EXECUTION_RISK, 0.25);
Multiphase Flow Correlations
The MultiphaseFlowIntegrator implements Beggs & Brill correlation for pipeline hydraulics:
Liquid Holdup Calculation
\[H_L(\theta) = H_L(0) \cdot \psi\]Where horizontal holdup: \(H_L(0) = \frac{a \cdot \lambda_L^b}{Fr^c}\)
Inclination correction: \(\psi = 1 + C \cdot [\sin(1.8\theta) - \frac{1}{3}\sin^3(1.8\theta)]\)
Froude Number
\[Fr = \frac{v_m^2}{g \cdot D}\]Where:
- $v_m$ = mixture velocity (m/s)
- $g$ = gravitational acceleration (9.81 m/s²)
- $D$ = pipe diameter (m)
Flow Regime Determination
| Regime | $L_1$ | $L_2$ | Condition |
|---|---|---|---|
| Segregated | $316 \lambda_L^{0.302}$ | $0.0009252 \lambda_L^{-2.4684}$ | $\lambda_L < 0.01$ and $Fr < L_1$ |
| Intermittent | - | - | $0.01 \leq \lambda_L \leq 0.4$ and $L_3 < Fr \leq L_1$ |
| Distributed | - | - | $\lambda_L \geq 0.4$ and $Fr \geq L_1$ |
MultiphaseFlowIntegrator integrator = new MultiphaseFlowIntegrator();
// Single calculation
PipelineResult result = integrator.calculateHydraulics(
stream, length, diameter, inclination);
// Generate hydraulic curve
List<PipelineResult> curve = integrator.calculateHydraulicsCurve(
stream, length, diameter, inclination,
minFlowRate, maxFlowRate, numPoints);
// Pipe sizing
double optimalDiameter = integrator.sizePipeline(
stream, length, inclination, maxPressureDrop, minVelocity, maxVelocity);
Norwegian Petroleum Tax Model
The NorwegianTaxModel implements the 2022+ tax regime:
Tax Calculation
\[Tax_{total} = Tax_{corporate} + Tax_{special}\]Where: \(Tax_{corporate} = 0.22 \times (Revenue - OPEX - DD\&A - Interest)\) \(Tax_{special} = 0.56 \times (Revenue - OPEX - Uplift \times CAPEX - Special DD\&A)\)
Key Parameters
| Parameter | Value | Description |
|---|---|---|
| Corporate Rate | 22% | Standard Norwegian corporate tax |
| Special Petroleum Tax | 56% | Additional petroleum sector tax |
| Marginal Rate | 78% | Combined marginal rate |
| Uplift | 20.8% | CAPEX deduction for special tax |
| Depreciation Period | 6 years | Linear depreciation |
NorwegianTaxModel taxModel = new NorwegianTaxModel();
// Configure parameters
taxModel.setOilPrice(75.0); // USD/bbl
taxModel.setGasPrice(8.0); // USD/MMBtu
taxModel.setExchangeRate(10.5); // NOK/USD
// Calculate for a production year
TaxResult result = taxModel.calculateTax(
oilProductionSm3,
gasProductionSm3,
opexMNOK,
capexMNOK,
previousCapex // for depreciation
);
// Results
System.out.println("Corporate Tax: " + result.getCorporateTax() + " MNOK");
System.out.println("Special Tax: " + result.getSpecialTax() + " MNOK");
System.out.println("Net Cash Flow: " + result.getNetCashFlow() + " MNOK");
Tieback Analysis
The TiebackAnalyzer performs comprehensive feasibility screening:
Distance-Based Pressure Drop
\[\Delta P_{tieback} = \frac{f \cdot L \cdot \rho \cdot v^2}{2D} + \rho \cdot g \cdot \Delta h\]Where Darcy friction factor from Colebrook-White: \(\frac{1}{\sqrt{f}} = -2 \log_{10}\left(\frac{\epsilon/D}{3.7} + \frac{2.51}{Re \sqrt{f}}\right)\)
Screening Criteria
| Criterion | Threshold | Notes |
|---|---|---|
| Maximum Distance | 50 km (typical) | Depends on fluid type |
| Pressure Availability | ΔP > tieback losses | Wellhead to host |
| Water Depth Compatibility | ±20% host capability | Subsea equipment limits |
| Flow Assurance | Hydrate, wax, scale | Temperature-dependent |
| Capacity Availability | Host spare capacity | Processing constraints |
TiebackAnalyzer analyzer = new TiebackAnalyzer();
// Define satellite field
analyzer.setSatelliteLocation(61.2, 2.1); // lat/lon
analyzer.setWaterDepth(320.0);
analyzer.setProductionRateSm3d(8000.0);
analyzer.setFluidType(FluidType.LIGHT_OIL);
analyzer.setGOR(200.0);
// Add potential hosts
HostFacility host1 = HostFacility.builder("Troll C")
.location(60.8, 3.5)
.facilityType(FacilityType.PLATFORM)
.waterDepth(340.0)
.processingCapacity(150000.0)
.currentThroughput(120000.0)
.maxWaterCut(0.90)
.build();
analyzer.addHost(host1);
// Quick screening
TiebackScreeningResult screening = analyzer.quickScreen(
host1, 25000.0, 320.0, 8000.0, FluidType.LIGHT_OIL, 200.0);
// Full analysis
TiebackReport report = analyzer.analyze(host1);
Reservoir Coupling (VFP Tables)
The ReservoirCouplingExporter generates ECLIPSE-compatible VFP tables:
VFPPROD Format
\[BHP = f(THP, WFR, GFR, ALQ, Q_{oil})\]Tubing performance: \(BHP = THP + \Delta P_{friction} + \Delta P_{gravity} - \Delta P_{acceleration}\)
ReservoirCouplingExporter exporter = new ReservoirCouplingExporter(processSystem);
// Configure VFP generation parameters
exporter.setThpRange(10.0, 100.0, 10); // bara
exporter.setWaterCutRange(0.0, 0.95, 10); // fraction
exporter.setGorRange(50.0, 500.0, 10); // Sm³/Sm³
exporter.setRateRange(1000.0, 20000.0, 15); // Sm³/d
// Generate VFP tables
VfpTable vfpProd = exporter.generateVfpProd(1, "WELL-1");
VfpTable vfpInj = exporter.generateVfpInj(2, "INJECTOR-1");
// Add schedule constraints
exporter.addGroupConstraint("FIELD", "ORAT", 50000.0);
exporter.addGroupConstraint("FIELD", "GRAT", 10e6);
// Export to file
exporter.exportToFile("include/vfp_tables.inc", ExportFormat.ECLIPSE_100);
Lifecycle Integration Examples
Example 1: Concept Screening (DG0-DG1)
// Quick screening of multiple concepts
BatchConceptRunner runner = new BatchConceptRunner();
// Add concepts to evaluate
runner.addConcept(FieldConcept.oilDevelopment("Concept A - FPSO", 120.0, 12, 5000));
runner.addConcept(FieldConcept.oilDevelopment("Concept B - Tieback", 80.0, 6, 4000));
runner.addConcept(FieldConcept.oilDevelopment("Concept C - Platform", 150.0, 15, 6000));
// Run parallel evaluation
BatchResults results = runner.runParallel(4);
// Compare KPIs
for (ConceptKPIs kpis : results.getAllKpis()) {
System.out.println(kpis.getConceptName() + ": NPV = " + kpis.getNpv()
+ " MUSD, CO2 = " + kpis.getCo2Intensity() + " kg/boe");
}
// Rank by multiple criteria
DevelopmentOptionRanker ranker = new DevelopmentOptionRanker();
ranker.setWeightProfile("balanced");
for (ConceptKPIs kpis : results.getAllKpis()) {
DevelopmentOption opt = ranker.addOption(kpis.getConceptName());
opt.setScore(Criterion.NPV, kpis.getNpv());
opt.setScore(Criterion.CO2_INTENSITY, kpis.getCo2Intensity());
opt.setScore(Criterion.CAPITAL_EFFICIENCY, kpis.getNpv() / kpis.getCapex());
}
RankingResult ranking = ranker.rank();
System.out.println(ranking.generateReport());
Example 2: Detailed Development Design (DG2-DG3)
// From concept to detailed process design
FieldConcept selectedConcept = FieldConcept.builder("Selected Development")
.reservoir(ReservoirInput.builder()
.fluidType(FluidType.MEDIUM_OIL)
.gor(180.0)
.apiGravity(32.0)
.h2sContent(50.0) // ppm
.co2Content(2.5) // mol%
.build())
.wells(WellsInput.builder()
.producerCount(10)
.injectorCount(5)
.ratePerWell(12000.0)
.wellType(WellType.DEVIATED)
.completionType(CompletionType.FRAC_PACK)
.build())
.infrastructure(InfrastructureInput.builder()
.processingLocation(ProcessingLocation.FPSO)
.exportType(ExportType.SHUTTLE_TANKER)
.waterDepth(380.0)
.distanceToShore(180.0)
.powerSupply(PowerSupply.GAS_TURBINE)
.build())
.build();
// Generate FEED-level process model
ConceptToProcessLinker linker = new ConceptToProcessLinker();
linker.setHpSeparatorPressure(45.0);
linker.setLpSeparatorPressure(4.0);
linker.setExportGasPressure(180.0);
linker.setCompressionEfficiency(0.78);
ProcessSystem process = linker.generateProcessSystem(
selectedConcept, FidelityLevel.PRE_FEED);
// Run simulation
process.run();
// Extract utility requirements
double powerMW = linker.getTotalPowerMW(process);
double heatingMW = linker.getTotalHeatingMW(process);
double coolingMW = linker.getTotalCoolingMW(process);
System.out.println("Power Demand: " + powerMW + " MW");
System.out.println("Heating Duty: " + heatingMW + " MW");
System.out.println("Cooling Duty: " + coolingMW + " MW");
// Flow assurance analysis
FlowAssuranceScreener faScreener = new FlowAssuranceScreener();
FlowAssuranceReport faReport = faScreener.screen(process);
// Detailed emissions calculation
DetailedEmissionsCalculator emissions = new DetailedEmissionsCalculator();
emissions.setPowerSource("gas_turbine");
emissions.setFlaringRate(0.5); // % of gas
DetailedEmissionsReport emReport = emissions.calculate(process);
Example 3: Production Operations
// Real-time production optimization
ProcessSystem operations = loadOperationalModel("field_model.json");
// Update with current conditions
Stream wellStream = (Stream) operations.getUnit("Well-1");
wellStream.setFlowRate(getCurrentFlowRate(), "Sm3/hr");
wellStream.setTemperature(getCurrentWellheadTemp(), "C");
wellStream.setPressure(getCurrentWellheadPressure(), "bara");
// Run updated model
operations.run();
// Production allocation
ProductionAllocator allocator = new ProductionAllocator();
allocator.setTestSeparatorData(testSepData);
Map<String, Double> allocation = allocator.allocateProduction(operations);
// Bottleneck analysis
BottleneckAnalyzer bottleneck = new BottleneckAnalyzer();
bottleneck.setCapacities(equipmentCapacities);
String constrainingEquipment = bottleneck.findBottleneck(operations);
// Gas lift optimization
GasLiftOptimizer glOptimizer = new GasLiftOptimizer();
glOptimizer.setAvailableGas(5.0); // MSm³/d
glOptimizer.setWellPerformance(iprCurves);
Map<String, Double> optimalAllocation = glOptimizer.optimize();
Example 4: Late-Life and Decommissioning
// Late-life screening
ArtificialLiftScreener liftScreener = new ArtificialLiftScreener();
liftScreener.setCurrentConditions(
reservoirPressure,
waterCut,
gor,
productivityIndex
);
List<MethodResult> liftOptions = liftScreener.screenAllMethods();
for (MethodResult option : liftOptions) {
System.out.println(option.getMethod() + ": "
+ (option.isFeasible() ? "Feasible" : "Not feasible")
+ " - " + option.getRationale());
}
// IOR/EOR evaluation
ScenarioAnalyzer scenarios = new ScenarioAnalyzer();
scenarios.setBaseCase(currentProduction);
// Water injection scenario
scenarios.addScenario("Water Injection", () -> {
InjectionWellModel injector = new InjectionWellModel();
injector.setInjectionType(InjectionType.WATER);
injector.setInjectionRate(15000.0); // Sm³/d
return injector.simulateResponse(reservoirModel);
});
// Gas injection scenario
scenarios.addScenario("Gas Injection", () -> {
InjectionWellModel injector = new InjectionWellModel();
injector.setInjectionType(InjectionType.GAS);
injector.setInjectionRate(3.0e6); // Sm³/d
return injector.simulateResponse(reservoirModel);
});
ScenarioResults results = scenarios.runAll();
System.out.println(results.generateComparisonTable());
// Decommissioning cost estimation
DecommissioningEstimator decom = new DecommissioningEstimator();
decom.setFacilityType(FacilityType.FPSO);
decom.setWellCount(15);
decom.setWaterDepth(380.0);
decom.setSubseaEquipment(subseaInventory);
double decomCost = decom.estimateTotalCost();
Map<String, Double> breakdown = decom.getCostBreakdown();
Monte Carlo Uncertainty Analysis
The framework supports probabilistic analysis across all lifecycle phases:
MonteCarloRunner mc = new MonteCarloRunner(1000);
// Define uncertain parameters
mc.addParameter("oilPrice", Distribution.triangular(50.0, 75.0, 120.0));
mc.addParameter("recoveryFactor", Distribution.normal(0.45, 0.05));
mc.addParameter("capexMultiplier", Distribution.lognormal(1.0, 0.15));
mc.addParameter("opexMultiplier", Distribution.triangular(0.9, 1.0, 1.3));
mc.addParameter("firstOilDelay", Distribution.discrete(0, 0.7, 6, 0.2, 12, 0.1));
// Define model function
mc.setModel((params) -> {
FieldConcept concept = createConcept(params);
ConceptEvaluator evaluator = new ConceptEvaluator();
return evaluator.evaluate(concept);
});
// Run simulation
MonteCarloResults results = mc.run();
// Statistical analysis
System.out.println("NPV P10: " + results.getPercentile("npv", 10));
System.out.println("NPV P50: " + results.getPercentile("npv", 50));
System.out.println("NPV P90: " + results.getPercentile("npv", 90));
System.out.println("Probability NPV > 0: " + results.probabilityAbove("npv", 0.0));
// Sensitivity (tornado) analysis
Map<String, Double> sensitivities = results.computeSensitivities("npv");
SURF Equipment Integration
The Digital Field Twin integrates with NeqSim’s comprehensive SURF (Subsea, Umbilicals, Risers, Flowlines) equipment modeling for complete subsea field development.
Subsea Production System Design
import neqsim.process.equipment.subsea.*;
import neqsim.process.mechanicaldesign.subsea.*;
// Create well stream
SystemInterface fluid = new SystemSrkEos(273.15 + 80, 150.0);
fluid.addComponent("methane", 0.70);
fluid.addComponent("ethane", 0.08);
fluid.addComponent("propane", 0.05);
fluid.addComponent("nC10", 0.17);
fluid.setMixingRule("classic");
Stream wellStream = new Stream("Well-1", fluid);
wellStream.setFlowRate(100000.0, "kg/hr");
wellStream.run();
// Subsea Tree
SubseaTree tree = new SubseaTree("Well-1 Tree", wellStream);
tree.setTreeType(SubseaTree.TreeType.HORIZONTAL);
tree.setPressureRating(SubseaTree.PressureRating.PR10000);
tree.setBoreSizeInches(7.0);
tree.setWaterDepth(400.0);
tree.run();
// Jumper to Manifold
SubseaJumper jumper = new SubseaJumper("Tree-Manifold", tree.getOutletStream());
jumper.setJumperType(SubseaJumper.JumperType.RIGID_M_SHAPE);
jumper.setLength(50.0);
jumper.setNominalBoreInches(6.0);
jumper.run();
// Manifold
SubseaManifold manifold = new SubseaManifold("Field Manifold");
manifold.setManifoldType(SubseaManifold.ManifoldType.PRODUCTION_TEST);
manifold.setNumberOfWellSlots(6);
manifold.setWaterDepth(400.0);
manifold.addWellStream(jumper.getOutletStream(), 1);
manifold.routeWellToProduction(1);
manifold.run();
// Export PLET
PLET exportPLET = new PLET("Export PLET", manifold.getProductionOutputStream());
exportPLET.setConnectionType(PLET.ConnectionType.VERTICAL_HUB);
exportPLET.setHubSizeInches(12.0);
exportPLET.setStructureType(PLET.StructureType.GRAVITY_BASE);
exportPLET.run();
// Dynamic Riser
FlexiblePipe riser = new FlexiblePipe("Production Riser", exportPLET.getOutletStream());
riser.setPipeType(FlexiblePipe.PipeType.UNBONDED);
riser.setApplication(FlexiblePipe.Application.DYNAMIC_RISER);
riser.setRiserConfiguration(FlexiblePipe.RiserConfiguration.LAZY_WAVE);
riser.setLength(1200.0);
riser.setInnerDiameterInches(8.0);
riser.setWaterDepth(400.0);
riser.setHasBuoyancyModules(true);
riser.run();
// Control Umbilical
Umbilical umbilical = new Umbilical("Field Umbilical");
umbilical.setLength(15000.0);
umbilical.setWaterDepth(400.0);
umbilical.addHydraulicLine(12.7, 517.0, "HP Supply");
umbilical.addHydraulicLine(12.7, 517.0, "HP Return");
umbilical.addChemicalLine(25.4, 207.0, "MEG Injection");
umbilical.addChemicalLine(19.05, 207.0, "Scale Inhibitor");
umbilical.addElectricalCable(35.0, 6600.0, "Power");
umbilical.addFiberOptic(12, "Communication");
umbilical.run(null);
// Process system
ProcessSystem process = new ProcessSystem();
process.add(wellStream);
process.add(tree);
process.add(jumper);
process.add(manifold);
process.add(exportPLET);
process.add(riser);
process.run();
SURF Mechanical Design
Each SURF equipment type has a dedicated mechanical design class:
// Tree Mechanical Design
tree.initMechanicalDesign();
SubseaTreeMechanicalDesign treeDesign =
(SubseaTreeMechanicalDesign) tree.getMechanicalDesign();
treeDesign.setMaxOperationPressure(690.0);
treeDesign.setDesignStandardCode("API-17D");
treeDesign.setRegion(SubseaCostEstimator.Region.NORWAY);
treeDesign.calcDesign();
// PLET Mechanical Design
exportPLET.initMechanicalDesign();
PLETMechanicalDesign pletDesign =
(PLETMechanicalDesign) exportPLET.getMechanicalDesign();
pletDesign.setMaxOperationPressure(250.0);
pletDesign.setMaterialGrade("X65");
pletDesign.setDesignStandardCode("DNV-ST-F101");
pletDesign.calcDesign();
// Get design results
double hubWallThickness = pletDesign.getHubWallThickness();
double mudmatArea = pletDesign.getRequiredMudmatArea();
double connectorCapacity = pletDesign.getConnectorLoadCapacity();
System.out.println("Hub Wall Thickness: " + hubWallThickness + " mm");
System.out.println("Required Mudmat Area: " + mudmatArea + " m²");
// Flexible Pipe Design
riser.initMechanicalDesign();
FlexiblePipeMechanicalDesign riserDesign =
(FlexiblePipeMechanicalDesign) riser.getMechanicalDesign();
riserDesign.setMaxOperationPressure(200.0);
riserDesign.setDesignStandardCode("API-17J");
riserDesign.calcDesign();
SURF Cost Estimation
Comprehensive cost estimation with regional factors:
import neqsim.process.mechanicaldesign.subsea.SubseaCostEstimator;
// Create cost estimator for Norway
SubseaCostEstimator estimator = new SubseaCostEstimator(
SubseaCostEstimator.Region.NORWAY);
// PLET Cost
estimator.calculatePLETCost(
25.0, // dry weight (tonnes)
12.0, // hub size (inches)
400.0, // water depth (m)
true, // has isolation valve
false // has pigging facility
);
double pletCost = estimator.getTotalCost();
// Tree Cost
estimator.calculateTreeCost(
10000.0, // pressure rating (psi)
7.0, // bore size (inches)
400.0, // water depth (m)
true, // is horizontal
false // is dual bore
);
double treeCost = estimator.getTotalCost();
// Manifold Cost
estimator.calculateManifoldCost(
6, // number of slots
80.0, // dry weight (tonnes)
400.0, // water depth (m)
true // has test header
);
double manifoldCost = estimator.getTotalCost();
// Umbilical Cost
estimator.calculateUmbilicalCost(
15.0, // length (km)
4, // hydraulic lines
2, // chemical lines
2, // electrical cables
400.0, // water depth (m)
false // is dynamic
);
double umbilicalCost = estimator.getTotalCost();
// Riser Cost
estimator.calculateFlexiblePipeCost(
1200.0, // length (m)
8.0, // inner diameter (inches)
400.0, // water depth (m)
true, // is dynamic
true // has buoyancy
);
double riserCost = estimator.getTotalCost();
// Total SURF CAPEX
double totalSurfCapex = pletCost + treeCost + manifoldCost + umbilicalCost + riserCost;
System.out.println("Total SURF CAPEX: $" + String.format("%,.0f", totalSurfCapex));
// Regional Comparison
SubseaCostEstimator.Region[] regions = SubseaCostEstimator.Region.values();
for (SubseaCostEstimator.Region region : regions) {
SubseaCostEstimator regional = new SubseaCostEstimator(region);
regional.calculateManifoldCost(6, 80.0, 400.0, true);
System.out.println(region.name() + ": $" +
String.format("%,.0f", regional.getTotalCost()));
}
Integrated Cost Estimation from Mechanical Design
// Get costs directly from mechanical design
PLETMechanicalDesign design = (PLETMechanicalDesign) exportPLET.getMechanicalDesign();
design.setRegion(SubseaCostEstimator.Region.NORWAY);
design.calcDesign();
// Cost breakdown
Map<String, Object> costBreakdown = design.getCostBreakdown();
System.out.println("Equipment Cost: $" +
((Map)costBreakdown.get("directCosts")).get("equipmentCostUSD"));
System.out.println("Installation Cost: $" +
((Map)costBreakdown.get("directCosts")).get("installationCostUSD"));
System.out.println("Total Cost: $" + costBreakdown.get("totalCostUSD"));
// Bill of Materials
List<Map<String, Object>> bom = design.generateBillOfMaterials();
for (Map<String, Object> item : bom) {
System.out.println(item.get("item") + ": " +
item.get("quantity") + " " + item.get("unit") +
" @ $" + item.get("unitCost"));
}
// Full JSON report (includes design AND costs)
String jsonReport = design.toJson();
Complete Subsea Field Development Example
// Field Concept with Subsea Tieback
FieldConcept concept = FieldConcept.builder("Barents Sea Discovery")
.reservoir(ReservoirInput.builder()
.fluidType(FluidType.LIGHT_OIL)
.gor(200.0)
.reservoirPressure(280.0)
.reservoirTemperature(85.0)
.stoiip(120.0)
.build())
.wells(WellsInput.builder()
.producerCount(6)
.ratePerWell(8000.0)
.wellType(WellType.HORIZONTAL)
.build())
.infrastructure(InfrastructureInput.builder()
.processingLocation(ProcessingLocation.SUBSEA_TIEBACK)
.waterDepth(380.0)
.distanceToShore(180.0)
.tiebackDistance(45.0)
.hostFacility("Goliat FPSO")
.build())
.build();
// Generate subsea production system
SubseaProductionSystem subseaSystem = new SubseaProductionSystem();
subseaSystem.setFieldConcept(concept);
subseaSystem.setManifoldWellSlots(6);
subseaSystem.setTiebackPipelineDiameter(12.0); // inches
subseaSystem.setUmbilicalLength(48.0); // km
// Run design
subseaSystem.designSystem();
// Get SURF CAPEX breakdown
Map<String, Double> surfCapex = subseaSystem.getCAPEXBreakdown();
System.out.println("SURF CAPEX Breakdown:");
System.out.println(" Trees: $" + String.format("%,.0f", surfCapex.get("trees")));
System.out.println(" Manifold: $" + String.format("%,.0f", surfCapex.get("manifold")));
System.out.println(" Jumpers: $" + String.format("%,.0f", surfCapex.get("jumpers")));
System.out.println(" Flowlines: $" + String.format("%,.0f", surfCapex.get("flowlines")));
System.out.println(" Umbilical: $" + String.format("%,.0f", surfCapex.get("umbilical")));
System.out.println(" Installation: $" + String.format("%,.0f", surfCapex.get("installation")));
System.out.println(" TOTAL: $" + String.format("%,.0f", surfCapex.get("total")));
// Evaluate field economics including SURF
ConceptEvaluator evaluator = new ConceptEvaluator();
evaluator.setOilPrice(75.0);
evaluator.setDiscountRate(0.08);
evaluator.setSubseaSystem(subseaSystem);
ConceptKPIs kpis = evaluator.evaluate(concept);
System.out.println("NPV: $" + String.format("%,.0f", kpis.getNpv()) + " MUSD");
System.out.println("IRR: " + String.format("%.1f", kpis.getIrr() * 100) + "%");
System.out.println("Breakeven Oil Price: $" +
String.format("%.1f", kpis.getBreakevenOilPrice()) + "/bbl");
Integration with External Systems
ECLIPSE/E300 Reservoir Coupling
// Export VFP tables for reservoir simulation
ReservoirCouplingExporter exporter = new ReservoirCouplingExporter(process);
// Production well VFP
VfpTable vfpProd = exporter.generateVfpProd(1, "PROD-1");
// Injection well VFP
VfpTable vfpInj = exporter.generateVfpInj(2, "INJ-1");
// Schedule keywords
exporter.addGroupConstraint("FIELD", "ORAT", 50000.0);
exporter.addWellConstraint("PROD-1", "BHP", 150.0);
// Export
String eclipseKeywords = exporter.getEclipseKeywords();
exporter.exportToFile("vfp_wells.inc", ExportFormat.ECLIPSE_100);
Python Integration
import jpype
import jpype.imports
from jpype.types import *
# Start JVM with NeqSim
jpype.startJVM(classpath=['neqsim.jar'])
from neqsim.process.fielddevelopment.concept import FieldConcept
from neqsim.process.fielddevelopment.evaluation import ConceptEvaluator
from neqsim.process.fielddevelopment.economics import PortfolioOptimizer
# Create and evaluate concept
concept = FieldConcept.oilDevelopment("Python Field", 100.0, 8, 5000)
evaluator = ConceptEvaluator()
kpis = evaluator.evaluate(concept)
print(f"NPV: {kpis.getNpv()} MUSD")
print(f"IRR: {kpis.getIrr() * 100:.1f}%")
print(f"CO2 Intensity: {kpis.getCo2Intensity():.1f} kg/boe")
Python SURF Cost Estimation
from neqsim.process.mechanicaldesign.subsea import SubseaCostEstimator
# Create estimator
estimator = SubseaCostEstimator(SubseaCostEstimator.Region.NORWAY)
# Calculate costs for each SURF component
costs = {}
# Trees (6 wells @ $15M each approx)
estimator.calculateTreeCost(10000, 7.0, 400, True, False)
costs['trees'] = estimator.getTotalCost() * 6
# Manifold
estimator.calculateManifoldCost(6, 80.0, 400.0, True)
costs['manifold'] = estimator.getTotalCost()
# Jumpers (6 x 50m)
estimator.calculateJumperCost(50.0, 6.0, True, 400.0)
costs['jumpers'] = estimator.getTotalCost() * 6
# Flowline (45 km)
pipeline_cost_per_km = 2_500_000 # Typical subsea pipeline
costs['flowlines'] = 45 * pipeline_cost_per_km
# Umbilical (48 km)
estimator.calculateUmbilicalCost(48.0, 4, 2, 2, 400.0, False)
costs['umbilical'] = estimator.getTotalCost()
# Total
total = sum(costs.values())
print(f"Total SURF CAPEX: ${total:,.0f}")
for item, cost in costs.items():
print(f" {item}: ${cost:,.0f} ({100*cost/total:.1f}%)")
---
## Best Practices
### 1. Maintain Thermodynamic Consistency
Always use the same equation of state throughout the workflow:
```java
// Create master fluid definition
SystemInterface masterFluid = new SystemSrkEos(273.15 + 60, 50.0);
masterFluid.addComponent("methane", 0.45);
// ... add all components
masterFluid.setMixingRule("classic");
masterFluid.setMultiPhaseCheck(true);
// Clone for different uses
SystemInterface wellFluid = masterFluid.clone();
SystemInterface separatorFluid = masterFluid.clone();
2. Progressive Fidelity
Start with screening-level models and increase fidelity as project progresses:
// DG0-DG1: Screening
ProcessSystem screening = linker.generateProcessSystem(concept, FidelityLevel.SCREENING);
// DG2: Concept
ProcessSystem conceptModel = linker.generateProcessSystem(concept, FidelityLevel.CONCEPT);
// DG3: Pre-FEED
ProcessSystem preFeed = linker.generateProcessSystem(concept, FidelityLevel.PRE_FEED);
// DG4: FEED
ProcessSystem feed = linker.generateProcessSystem(concept, FidelityLevel.FEED);
3. Document Assumptions
Use the built-in logging and reporting:
FieldConcept concept = FieldConcept.builder("My Field")
.notes("Based on 2024 CPR. Assumes analog reservoir performance.")
.dataSource("Exploration Well EXP-1, 2023")
.confidenceLevel(ConfidenceLevel.MEDIUM)
// ... configuration
.build();