Host Tie-In Capacity and Holdback Planning
Brownfield tieback decisions often fail because a host has spare capacity on paper but not in the year when the satellite peaks. The host may already use most separator, compression, liquid-handling, produced-water, export, or power capacity. The host tie-in capacity planner turns that question into a repeatable time-series calculation:
- Compare base-host production and satellite production against host nameplate capacities.
- Allocate constrained capacity with a clear policy.
- Optionally inject accepted production into an attached
ProcessSystemor multi-areaProcessModeland check equipment capacity constraints across the complete host. - Quantify held-back or deferred production and screen a debottleneck investment.
Use this for early DG0-DG2 screening when the question is not only whether a route is hydraulically feasible, but whether the host can process the combined production without unacceptable holdback.
Main API
| Class | Role |
|---|---|
ProductionLoad |
Immutable load for one period: gas, oil, water, total liquid, period length, and optional commodity values |
ProductionProfileSeries |
Ordered base-host or satellite production time series |
CapacityAllocationPolicy |
Allocation rule: BASE_FIRST, SATELLITE_FIRST, PRO_RATA, or VALUE_WEIGHTED |
HoldbackPolicy |
Holdback rule: curtail constrained production or defer it to later periods |
HostTieInPoint |
Maps profile rates to a stream flow in an attached ProcessSystem or ProcessModel |
TieInCapacityPlanner |
Runs nameplate, process-capacity, holdback, and debottleneck calculations |
TieInCapacityResult |
Aggregated result with period tables, totals, bottleneck summary, and decisions |
The planner complements TiebackAnalyzer: use TiebackAnalyzer for route feasibility and use TieInCapacityPlanner to test whether the host can absorb the combined production profile.
Nameplate Ullage Example
This example preserves base-host production first and accepts only the satellite rate that fits within the host gas capacity.
import neqsim.process.fielddevelopment.tieback.HostFacility;
import neqsim.process.fielddevelopment.tieback.capacity.CapacityAllocationPolicy;
import neqsim.process.fielddevelopment.tieback.capacity.ProductionProfileSeries;
import neqsim.process.fielddevelopment.tieback.capacity.TieInCapacityPlanner;
import neqsim.process.fielddevelopment.tieback.capacity.TieInCapacityResult;
HostFacility host = HostFacility.builder("Host A")
.gasCapacity(5.0)
.build();
ProductionProfileSeries base = new ProductionProfileSeries("base")
.addPeriod(2028, 4.0, 0.0, 0.0, 0.0);
ProductionProfileSeries satellite = new ProductionProfileSeries("satellite")
.addPeriod(2028, 3.0, 0.0, 0.0, 0.0);
TieInCapacityResult result = new TieInCapacityPlanner(host)
.setHostProductionProfile(base)
.setSatelliteProductionProfile(satellite)
.setAllocationPolicy(CapacityAllocationPolicy.BASE_FIRST)
.run();
System.out.println(result.toMarkdownTable());
Expected behavior: the host accepts 1.0 MSm3/d of the satellite gas and holds back 2.0 MSm3/d because the base host production already uses 4.0 of 5.0 MSm3/d.
Process-Equipment Capacity Layer
If the HostFacility has an attached ProcessSystem, the planner can set a configured stream rate, run the process, and inspect equipment capacity constraints through the existing NeqSim capacity API.
import neqsim.process.equipment.capacity.CapacityConstraint;
import neqsim.process.equipment.capacity.CapacityConstraint.ConstraintType;
import neqsim.process.equipment.stream.Stream;
import neqsim.process.fielddevelopment.tieback.HostFacility;
import neqsim.process.fielddevelopment.tieback.capacity.CapacityAllocationPolicy;
import neqsim.process.fielddevelopment.tieback.capacity.HostTieInPoint;
import neqsim.process.fielddevelopment.tieback.capacity.ProductionProfileSeries;
import neqsim.process.fielddevelopment.tieback.capacity.TieInCapacityPlanner;
import neqsim.process.fielddevelopment.tieback.capacity.TieInCapacityResult;
import neqsim.process.processmodel.ProcessSystem;
import neqsim.thermo.system.SystemInterface;
import neqsim.thermo.system.SystemSrkEos;
SystemInterface gas = new SystemSrkEos(288.15, 60.0);
gas.addComponent("methane", 1.0);
gas.setMixingRule("classic");
final Stream hostFeed = new Stream("Host Feed", gas);
hostFeed.setFlowRate(1000.0, "kg/hr");
hostFeed.addCapacityConstraint(new CapacityConstraint("hostFeedFlow", "kg/hr", ConstraintType.HARD)
.setDesignValue(2500.0)
.setValueSupplier(() -> hostFeed.getFlowRate("kg/hr")));
ProcessSystem hostProcess = new ProcessSystem("host process");
hostProcess.add(hostFeed);
HostFacility host = HostFacility.builder("Example Host")
.gasCapacity(10.0)
.processSystem(hostProcess)
.build();
ProductionProfileSeries base = new ProductionProfileSeries("base host")
.addPeriod(2028, 1.0, 0.0, 0.0, 0.0);
ProductionProfileSeries satellite = new ProductionProfileSeries("satellite")
.addPeriod(2028, 4.0, 0.0, 0.0, 0.0);
HostTieInPoint tieInPoint = new HostTieInPoint("Host Feed", "kg/hr")
.setGasToProcessRateFactor(1000.0);
TieInCapacityResult result = new TieInCapacityPlanner(host)
.setHostProductionProfile(base)
.setSatelliteProductionProfile(satellite)
.setAllocationPolicy(CapacityAllocationPolicy.BASE_FIRST)
.setTieInPoint(tieInPoint)
.run();
System.out.println(result.getPeriodResults().get(0).getProcessBottleneck());
The example maps 1.0 MSm3/d gas to 1000 kg/hr. The host stream hard limit is 2500 kg/hr, so the planner accepts about 1.5 MSm3/d of the 4.0 MSm3/d satellite request after considering the base load.
Multi-Area Brownfield Host
Use a ProcessModel when gathering, processing, utilities, and export are separate composable areas. Qualify the tie-in
stream as area::streamReference; returned utilization keys and the limiting equipment retain the same area
provenance.
import neqsim.process.equipment.capacity.CapacityConstraint;
import neqsim.process.equipment.capacity.CapacityConstraint.ConstraintType;
import neqsim.process.equipment.separator.Separator;
import neqsim.process.equipment.stream.Stream;
import neqsim.process.fielddevelopment.tieback.HostFacility;
import neqsim.process.fielddevelopment.tieback.capacity.HostTieInPoint;
import neqsim.process.processmodel.ProcessModel;
import neqsim.process.processmodel.ProcessSystem;
import neqsim.thermo.system.SystemInterface;
import neqsim.thermo.system.SystemSrkEos;
SystemInterface hostFluid = new SystemSrkEos(288.15, 60.0);
hostFluid.addComponent("methane", 1.0);
hostFluid.setMixingRule("classic");
final Stream hostFeed = new Stream("Host Feed", hostFluid);
hostFeed.setFlowRate(1000.0, "kg/hr");
ProcessSystem gathering = new ProcessSystem("gathering");
gathering.add(hostFeed);
Separator inletSeparator = new Separator("Inlet Separator", hostFeed);
inletSeparator.addCapacityConstraint(
new CapacityConstraint("separatorFeedFlow", "kg/hr", ConstraintType.HARD)
.setDesignValue(2500.0)
.setValueSupplier(() -> hostFeed.getFlowRate("kg/hr")));
ProcessSystem processing = new ProcessSystem("processing");
processing.add(inletSeparator);
ProcessModel hostModel = new ProcessModel();
hostModel.add("gathering", gathering);
hostModel.add("processing", processing);
HostFacility multiAreaHost = HostFacility.builder("Example Host")
.gasCapacity(10.0)
.processModel(hostModel)
.build();
HostTieInPoint qualifiedTieIn = new HostTieInPoint("gathering::Host Feed", "kg/hr")
.setGasToProcessRateFactor(1000.0);
The planner runs every area for each trial. If the separator is limiting, the period result reports
processing::Inlet Separator; after the study it restores the original host-feed rate and reruns the full model. Bare
stream names remain supported when unique across all areas. Duplicate bare names fail closed, so parallel trains must
be addressed explicitly.
Allocation Policies
| Policy | Use when | Behavior |
|---|---|---|
BASE_FIRST |
Existing host production has priority | Allocates capacity to base production first, then satellite production |
SATELLITE_FIRST |
Satellite acceleration is strategically preferred | Allocates capacity to satellite production first |
PRO_RATA |
Commercial sharing or joint-venture fairness is needed | Scales base and satellite production by the same feasible factor |
VALUE_WEIGHTED |
Highest-value production should pass first | Prioritizes the load with highest daily value |
Holdback and Debottlenecking
With HoldbackPolicy.CURTAIL, unaccepted satellite production is treated as lost in the screening case. With HoldbackPolicy.DEFER_TO_LATER_YEARS, the held-back production is carried into the next period and re-tested against future ullage.
The result also builds a simple DebottleneckDecision when constrained production has material value. It reports:
- bottleneck category or equipment name,
- default or configured CAPEX in MUSD,
- discounted recovered value in MUSD,
- NPV after debottleneck CAPEX,
- simple payback.
For detailed equipment-specific investments, use the bottleneck name to route the case to compressor, separator, heat-exchanger, water-treatment, or export-system design classes.
Interpreting Results
Useful accessors include:
result.hasHoldback();
result.getTotalAcceptedGasMSm3();
result.getTotalHeldBackGasMSm3();
result.getTotalDeferredValueNpvMusd();
result.getPrimaryBottleneck();
result.getDebottleneckDecisions();
result.toCsv();
result.toMarkdownTable();
Each TieInPeriodResult contains the scheduled satellite load, deferred backlog entering the year, accepted satellite production, held-back production, primary bottleneck, process utilization summary, and deferred value.