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
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@ input while preserving the edge hydraulic model. Candidate indices are categoric
minimum-temperature requirements must be invariant, and flexible/vendor designs are
outside this contract. Never combine this selector with a second diameter variable
on the same edge or treat a passing screen as qualified design.
For coherent direct, brownfield and redundant-loop line-ups, register named
`FieldWellNetworkProcessUnit.RouteConfiguration` options on the existing process-unit
adapter. `configuration.<selector>.selection` is a categorical `ProcessAutomation`
input: one write atomically assigns exact zero/one availability to the complete
controlled edge set and preserves all per-edge hydraulic models. Do not emulate a
multi-edge line-up with independent availability actions; that permits partial
configurations during candidate application and restoration.
The dedicated `TwoFluidPipeNetwork` already owns storage-node transients; do not
replace it. Live well/injection coupling must reuse WellSystem/WellFlow physics.

Expand All @@ -86,6 +93,7 @@ replace it. Live well/injection coupling must reuse WellSystem/WellFlow physics.
| Hydraulic details: `NetworkLinearSolver`, `NetworkPipe`, pipe-model bindings | `neqsim.process.equipment.network` | Linear solve helpers and per-edge hydraulic state; edges may use Darcy-Weisbach or a configured `PipeBeggsAndBrills` model. | `NetworkLinearSolver.solve`, `NetworkLinearSolver.solveGaussian`, `NetworkPipe.getFlowRate`, `NetworkPipe.getBBModel` |
| Well and facility elements | `neqsim.process.equipment.network` | IPR, tubing, choke, compressor, pump, regulator, artificial-lift, and related source/edge elements within the network. | `addWellIPR`, `addChoke`; configure through `NetworkPipe` element-specific setters |
| Typed field/SURF identity: `FieldNetworkTopology` | `neqsim.process.equipment.network` | Stable production/injection roles, equipment tags and ports over the canonical network, including typed choke, pump and compressor construction. | `addPipe`, `addChoke`, `addPump`, `addPumpDifferentialPressure`, `addCompressor`, `validateForExecution`, `copyDefinition` |
| Live field route line-ups: `FieldWellNetworkProcessUnit`, `RouteConfiguration` | `neqsim.process.equipment.network` | Runs the live well/network coupler in a process model and atomically switches named multi-edge direct, brownfield or redundant configurations on the same canonical graph. | `registerExclusiveRouteSelector`, `registerRouteConfigurationSelector`, `getRouteConfigurationNames`, `setRouteConfigurationSelection` |
| Canonical SURF design basis: `FieldNetworkSurfDesignBasis`, `SubseaProductionSystem` | `neqsim.process.fielddevelopment.subsea` | Read-only typed equipment and exact route geometry plus edge-keyed mechanical/cost/thermal selections into existing Class 4 and steady network contracts. | `createSurfDesignBasis`, `setLineDesign`, `createLineDesignDecisionVariable`, `createLineDesignScreeningConstraints`, `applyLineThermalDesigns`, `assessDnvStF101LineDesigns`, `assessOnBottomStabilityLineDesigns`, `estimateSurfCosts`, `createSurfCapitalCostObjective` |
| SURF route cost/design: `SURFCostEstimator.LineDesign`, `PipeMechanicalDesignCalculator`, `MultilayerThermalCalculator`, DNV screening kernels | `neqsim.process.mechanicaldesign.subsea`, `neqsim.process.mechanicaldesign.pipeline`, `neqsim.process.equipment.pipeline` | Route-specific OD, wall, material, installation, typed insulation and explicit structural/environmental input with existing mechanical/thermal screening and MTO output. | `LineDesign.builder`, `dnvStF101Input`, `onBottomStabilityInput`, `resolveOverallHeatTransferCoefficientWm2K`, `getDetailedEstimateResult` |
| Constrained optimization: `NetworkOptimizer`, `NetworkConstraints`, `NetworkObjectives`, `NetworkDecisionVariable` | `neqsim.process.equipment.network` | Bounded operating search plus complete fail-closed enumeration of all-discrete physical designs. | `NetworkDecisionVariable.pipeDiameter`, `NetworkDecisionVariable.customDiscrete`, `NetworkOptimizer.optimize`, `optimizeMultiObjective` |
Expand Down
20 changes: 19 additions & 1 deletion docs/fielddevelopment/SURF_NETWORK_INTEGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,22 @@ therefore feeds back through the same live well/network coupling instead of acti
downstream flow split. Copies preserve selector definitions but keep independent edge
state.

For a line-up that changes several edges together, construct named
`FieldWellNetworkProcessUnit.RouteConfiguration` objects and register them with
`registerRouteConfigurationSelector(...)`. Automation exposes
`configuration.<selector>.selection`. Each option lists the controlled edges that are
fully available; every other edge appearing in any option is exactly closed. This
supports direct versus brownfield routes and an option with both paths open as one
redundant loop without rebuilding the topology. Registration rejects missing edges,
duplicate line-ups, selector overlap and a current state that does not match exactly one
declared option. A selection snapshots every controlled availability, applies and reads
back the complete line-up, and restores the snapshot after any failure. Edge geometry,
equipment identity and Darcy-Weisbach/Beggs-Brill/two-fluid selection are never changed.
The focused live-well acceptance case checks direct, higher-resistance brownfield and
dual-path configurations, exact restoration, positive flow in both redundant paths and
network mass conservation. This is synthetic integration evidence, not an outage or
brownfield field qualification.

The synthetic `FieldToFacilityOptimizationAcceptanceTest` connects two live wells and
well chokes through exclusive per-well routes to distinct 45 bara HP and 30 bara LP
fixed-pressure sinks. Those stable sink streams feed separators, compressor-suction
Expand All @@ -481,7 +497,9 @@ physical limits to obtain a feasible optimizer result.
1. Extend the field-scale cases to live `WellSystem`/`WellFlow` production and injection
boundaries, qualified pump/compressor maps, shared host power/capacity constraints and
controlled reservoir-pressure updates without duplicating reservoir ownership.
Add branch/loop outage and brownfield impact studies through #4188/#3154 optimization.
The canonical multi-edge line-up contract now supports branch/loop outage and brownfield
actions through #4188/#3154 optimization; next exercise it in the larger production and
injection field cases with qualified facility maps and lifecycle evidence.
2. Qualify steady arrival temperature, DNV-ST-F101 and DNV-RP-F109 route cases against independent
field, laboratory or commercial-simulator evidence. The software contract for staged
OD/ID/wall/material/installation/insulation/stability alternatives now exists with synthetic
Expand Down
52 changes: 52 additions & 0 deletions src/main/java/neqsim/process/automation/ProcessAutomation.java
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,9 @@ public double getVariableValue(String address, String unitOfMeasure) {
if (unit instanceof FieldWellNetworkProcessUnit && parts.length == 3 && "route".equals(parts[1])) {
return getFieldRouteProperty((FieldWellNetworkProcessUnit) unit, parts[2], unitOfMeasure);
}
if (unit instanceof FieldWellNetworkProcessUnit && parts.length == 3 && "configuration".equals(parts[1])) {
return getFieldConfigurationProperty((FieldWellNetworkProcessUnit) unit, parts[2], unitOfMeasure);
}
LoopedPipeNetwork addressableNetwork = getAddressableNetwork(unit);
if (addressableNetwork != null && parts.length == 3) {
return getNetworkProperty(addressableNetwork, parts[1], parts[2], unitOfMeasure);
Expand Down Expand Up @@ -656,6 +659,11 @@ public void setVariableValue(String address, double value, String unitOfMeasure)
this.dirty = true;
return;
}
if (unit instanceof FieldWellNetworkProcessUnit && parts.length == 3 && "configuration".equals(parts[1])) {
setFieldConfigurationProperty((FieldWellNetworkProcessUnit) unit, parts[2], value, unitOfMeasure);
this.dirty = true;
return;
}
LoopedPipeNetwork addressableNetwork = getAddressableNetwork(unit);
if (addressableNetwork != null && parts.length == 3) {
setNetworkProperty(addressableNetwork, parts[1], parts[2], value, unitOfMeasure);
Expand Down Expand Up @@ -892,6 +900,14 @@ private List<SimulationVariable> buildVariableList(String unitName, ProcessEquip
"Exclusive route index; provenance: " + fieldUnit.getExclusiveRouteProvenance(selectorName)).withBounds(
Double.valueOf(0.0), Double.valueOf(fieldUnit.getExclusiveRouteEdges(selectorName).size() - 1.0)));
}
for (String selectorName : fieldUnit.getRouteConfigurationSelectorNames()) {
networkVariables.add(new SimulationVariable(unitName + ".configuration." + selectorName + ".selection",
"configuration." + selectorName + ".selection", VariableType.INPUT, "-",
"Route configuration index; options: " + fieldUnit.getRouteConfigurationNames(selectorName)
+ "; provenance: " + fieldUnit.getRouteConfigurationProvenance(selectorName))
.withBounds(Double.valueOf(0.0),
Double.valueOf(fieldUnit.getRouteConfigurationNames(selectorName).size() - 1.0)));
}
}
return enrichVariableMetadata(networkVariables);
}
Expand Down Expand Up @@ -1251,6 +1267,42 @@ private void setFieldRouteProperty(FieldWellNetworkProcessUnit unit, String targ
unit.setExclusiveRouteSelection(targetProperty[0], value);
}

/**
* Read one field-unit multi-edge route configuration.
*
* @param unit field well/network process unit
* @param targetAndProperty selector name and selection property
* @param unitOfMeasure requested dimensionless unit
* @return zero-based selected configuration index
*/
private double getFieldConfigurationProperty(FieldWellNetworkProcessUnit unit, String targetAndProperty,
String unitOfMeasure) {
String[] targetProperty = splitNetworkTargetProperty(targetAndProperty);
requireDimensionlessUnit(unitOfMeasure);
if (!"selection".equals(targetProperty[1])) {
throw new IllegalArgumentException("Unknown field route-configuration property: " + targetProperty[1]);
}
return unit.getRouteConfigurationSelection(targetProperty[0]);
}

/**
* Write one field-unit multi-edge route configuration.
*
* @param unit field well/network process unit
* @param targetAndProperty selector name and selection property
* @param value zero-based selected configuration index
* @param unitOfMeasure requested dimensionless unit
*/
private void setFieldConfigurationProperty(FieldWellNetworkProcessUnit unit, String targetAndProperty, double value,
String unitOfMeasure) {
String[] targetProperty = splitNetworkTargetProperty(targetAndProperty);
requireDimensionlessUnit(unitOfMeasure);
if (!"selection".equals(targetProperty[1])) {
throw new IllegalArgumentException("Unknown field route-configuration property: " + targetProperty[1]);
}
unit.setRouteConfigurationSelection(targetProperty[0], value);
}

/**
* Require a dimensionless route-selector unit.
*
Expand Down
Loading
Loading