Late-Life Operations Support in NeqSim
This document describes how NeqSim supports analysis of late-life field operations, a key topic in TPG4230 and critical for maximizing economic recovery from mature fields.
Overview
Late-life operations present unique challenges:
| Challenge | Description | NeqSim Support |
|---|---|---|
| High water cut | 80-98% water production | Three-phase separator modeling |
| Increasing GOR | Gas cap expansion, solution gas | Phase behavior changes |
| Low rates | Equipment turndown limits | Off-design simulation |
| Declining pressure | Artificial lift requirements | Well performance |
| Infrastructure aging | Debottlenecking needs | Capacity analysis |
| Economic marginal | Operating cost vs revenue | Economic cut-off |
1. High Water Cut Operations
1.1 Separator Performance at High Water Cut
import neqsim.process.equipment.separator.ThreePhaseSeparator;
import neqsim.process.fielddevelopment.evaluation.SeparatorSizingCalculator;
// Analyze separator at 90% water cut
SystemInterface fluid = new SystemSrkEos(333.15, 30.0);
fluid.addComponent("methane", 0.05);
fluid.addComponent("nC10", 0.05); // 5% oil
fluid.addComponent("water", 0.90); // 90% water
fluid.setMixingRule("classic");
Stream wellStream = new Stream("well", fluid);
wellStream.setFlowRate(50000.0, "kg/hr");
wellStream.run();
ThreePhaseSeparator separator = new ThreePhaseSeparator("HP-Sep", wellStream);
separator.run();
// Check residence time adequacy
SeparatorSizingCalculator calc = new SeparatorSizingCalculator();
double oilDensity = separator.getOilOutStream().getFluid().getDensity("kg/m3");
double requiredRetention = calc.getAPI12JRetentionTime(oilDensity);
double waterVolume = separator.getWaterOutStream().getFlowRate("m3/hr");
double oilVolume = separator.getOilOutStream().getFlowRate("m3/hr");
System.out.println("Water cut: " + waterVolume / (waterVolume + oilVolume) * 100 + "%");
System.out.println("Required retention time: " + requiredRetention + " s");
1.2 Water Treatment Capacity
At high water cuts, produced water treatment becomes a bottleneck:
import neqsim.process.equipment.watertreatment.ProducedWaterTreatmentTrain;
import neqsim.process.fielddevelopment.evaluation.BottleneckAnalyzer;
// Late-life water production
ProducedWaterTreatmentTrain pwt = new ProducedWaterTreatmentTrain("PWTT");
pwt.setInletOilConcentration(800.0); // mg/L (lower due to better separator)
pwt.setWaterFlowRate(1200.0); // m³/hr (high volume)
pwt.run();
// Check if water treatment is bottleneck
BottleneckAnalyzer analyzer = new BottleneckAnalyzer("Late-Life Analysis");
analyzer.addEquipment("Water-Treatment", EquipmentType.WATER_TREATMENT,
1200.0, 1500.0); // 80% utilization
if (analyzer.getPrimaryBottleneck().getEquipmentName().equals("Water-Treatment")) {
System.out.println("Water treatment is primary bottleneck");
System.out.println("Consider: Additional hydrocyclones, IGF upgrade");
}
2. Increasing GOR Impact
2.1 Compression Capacity Analysis
// GOR evolution over field life
double[] yearlyGOR = {150, 180, 220, 280, 350, 450, 600, 800};
for (int year = 0; year < yearlyGOR.length; year++) {
double oilRate = 5000.0 * Math.pow(0.88, year); // Declining oil
double gasRate = oilRate * yearlyGOR[year]; // Increasing gas
// Check compression capacity
double compressionPower = estimateCompressionPower(gasRate);
double designCapacity = 25.0; // MW
double utilization = compressionPower / designCapacity;
System.out.printf("Year %d: GOR=%.0f, Gas=%.0f Sm3/d, Comp=%.1f MW (%.0f%%)%n",
2025 + year, yearlyGOR[year], gasRate, compressionPower, utilization * 100);
if (utilization > 0.95) {
System.out.println(" ⚠️ Compression constraint reached");
}
}
2.2 Phase Envelope Shifts
Track how the phase envelope changes with depletion:
import neqsim.thermodynamicoperations.ThermodynamicOperations;
// Initial composition
SystemInterface initial = createReservoirFluid(GOR_initial);
ThermodynamicOperations opsInitial = new ThermodynamicOperations(initial);
opsInitial.calcPTphaseEnvelope();
double initialCricondenbar = opsInitial.get("cricondenbarP");
// Late-life composition (higher GOR = more gas)
SystemInterface latLife = createReservoirFluid(GOR_lateLife);
ThermodynamicOperations opsLate = new ThermodynamicOperations(latLife);
opsLate.calcPTphaseEnvelope();
double lateCricondenbar = opsLate.get("cricondenbarP");
System.out.println("Initial cricondenbar: " + initialCricondenbar + " bara");
System.out.println("Late-life cricondenbar: " + lateCricondenbar + " bara");
System.out.println("Phase envelope has shifted - check dewpoint constraints");
3. Low-Rate Operations
3.1 Equipment Turndown Analysis
import neqsim.process.fielddevelopment.evaluation.ScenarioAnalyzer;
ScenarioAnalyzer analyzer = new ScenarioAnalyzer(processSystem);
// Analyze different production rates
double[] rateScenarios = {10000, 7500, 5000, 3000, 1500};
for (double rate : rateScenarios) {
analyzer.addScenario("Rate " + rate,
new ScenarioParameters()
.setOilRate(rate)
.setGOR(400.0)
.setWaterCut(0.85));
}
List<ScenarioResult> results = analyzer.runAll();
System.out.println("=== TURNDOWN ANALYSIS ===");
for (ScenarioResult r : results) {
System.out.printf("%s: Power=%.2f MW, Converged=%s%n",
r.getName(), r.getPowerMW(), r.isConverged());
if (!r.isConverged()) {
System.out.println(" ⚠️ Process unstable at this rate - minimum turndown reached");
}
}
3.2 Separator Turndown
Low liquid rates affect separation efficiency:
// Check separator liquid level and retention time
double designLiquidRate = 500.0; // m³/hr design
double actualLiquidRate = 50.0; // m³/hr late-life (10% of design)
double separatorVolume = 100.0; // m³ (liquid section)
double actualRetention = separatorVolume / actualLiquidRate * 3600; // seconds
double requiredRetention = 120.0; // seconds for medium crude
if (actualRetention > requiredRetention * 5) {
System.out.println("Excessive retention time: " + actualRetention + " s");
System.out.println("Risk: Gas carry-under, emulsion stabilization");
System.out.println("Consider: Internals modification, level control upgrade");
}
4. Artificial Lift Requirements
4.1 Well Performance Decline
import neqsim.process.equipment.reservoir.WellFlow;
// Analyze well deliverability decline
double reservoirPressure = 150.0; // bara (depleted from 300 bar initial)
double wellheadPressure = 30.0; // bara
WellFlow well = new WellFlow(reservoirStream);
well.setProductivityIndex(5.0); // Sm3/d/bar
// Calculate natural flow rate
double naturalRate = well.calculateFlowRate(reservoirPressure, wellheadPressure);
if (naturalRate < economicLimit) {
System.out.println("Natural flow below economic limit: " + naturalRate + " Sm3/d");
System.out.println("Artificial lift required");
// Estimate ESP/gas lift benefit
double liftedRate = naturalRate * 1.5; // Typical 30-50% increase
System.out.println("Potential with artificial lift: " + liftedRate + " Sm3/d");
}
5. Economic Cut-Off Analysis
5.1 Break-Even Rate Calculation
import neqsim.process.fielddevelopment.economics.CashFlowEngine;
// Fixed operating costs
double fixedOpex = 50.0; // MUSD/year (regardless of rate)
double variableOpex = 5.0; // USD/bbl
// Revenue vs cost at different rates
double oilPrice = 70.0; // USD/bbl
System.out.println("=== ECONOMIC CUT-OFF ANALYSIS ===");
System.out.println("Rate (bbl/d)\tRevenue\t\tOPEX\t\tNet");
for (double rate = 10000; rate >= 500; rate -= 500) {
double annualProduction = rate * 365;
double revenue = annualProduction * oilPrice / 1e6; // MUSD
double opex = fixedOpex + (annualProduction * variableOpex / 1e6);
double net = revenue - opex;
System.out.printf("%.0f\t\t%.1f\t\t%.1f\t\t%.1f%n", rate, revenue, opex, net);
if (net < 0) {
System.out.printf("Economic cut-off between %.0f and %.0f bbl/d%n",
rate + 500, rate);
break;
}
}
5.2 Tail Production Economics
// Include abandonment timing in economics
double abandonmentCost = 200.0; // MUSD
CashFlowEngine engine = new CashFlowEngine("NO");
engine.setOpexPerUnit(variableOpexPerBbl);
engine.setFixedOpex(fixedOpexMUSD);
engine.setAbandonmentCost(abandonmentCost);
// Compare: Produce another 3 years vs abandon now
engine.setForecastYears(3);
CashFlowResult continue3Years = engine.calculate(0.08);
engine.setForecastYears(0);
CashFlowResult abandonNow = engine.calculate(0.08);
System.out.println("NPV if continue 3 years: " + continue3Years.getNpv());
System.out.println("NPV if abandon now: " + abandonNow.getNpv());
if (continue3Years.getNpv() > abandonNow.getNpv()) {
System.out.println("Recommendation: Continue production");
} else {
System.out.println("Recommendation: Initiate abandonment");
}
6. Debottlenecking Opportunities
6.1 Identify Late-Life Bottlenecks
import neqsim.process.fielddevelopment.evaluation.BottleneckAnalyzer;
BottleneckAnalyzer analyzer = new BottleneckAnalyzer("Mature Field");
// Equipment at late-life conditions
analyzer.addEquipment("HP-Separator-Gas", EquipmentType.SEPARATOR,
2.8, 3.0); // 93% - gas limited at high GOR
analyzer.addEquipment("Water-Injection-Pump", EquipmentType.PUMP,
12000, 15000); // 80% - increased water injection
analyzer.addEquipment("Produced-Water-Treatment", EquipmentType.WATER_TREATMENT,
1400, 1500); // 93% - high water cut
analyzer.addEquipment("Export-Compressor", EquipmentType.COMPRESSOR,
32, 35); // 91% - increased gas volume
// Find primary constraint
BottleneckResult primary = analyzer.getPrimaryBottleneck();
System.out.println("Primary late-life bottleneck: " + primary.getEquipmentName());
// Evaluate debottleneck options
List<DebottleneckOption> options = analyzer.evaluateDebottleneckOptions();
for (DebottleneckOption opt : options) {
System.out.printf("Option: %s, Cost: %.0f MUSD, Benefit: +%.0f bbl/d%n",
opt.getDescription(), opt.getCostMUSD(), opt.getRateBenefit());
}
7. Decommissioning Timing
7.1 Optimal Abandonment Timing
import neqsim.process.fielddevelopment.evaluation.DecommissioningEstimator;
import neqsim.process.fielddevelopment.economics.CashFlowEngine;
DecommissioningEstimator decom = new DecommissioningEstimator("Platform");
double decomCost = decom.getTotalCostMUSD();
// NPV of different abandonment timing scenarios
int[] abandonYears = {2027, 2028, 2029, 2030, 2031};
double[] npvs = new double[abandonYears.length];
for (int i = 0; i < abandonYears.length; i++) {
CashFlowEngine engine = createCashFlowToYear(abandonYears[i]);
// Add discounted abandonment cost
int yearsToAbandon = abandonYears[i] - 2025;
double pvDecomCost = decomCost / Math.pow(1.08, yearsToAbandon);
npvs[i] = engine.calculate(0.08).getNpv() - pvDecomCost;
System.out.printf("Abandon in %d: NPV = %.0f MUSD%n", abandonYears[i], npvs[i]);
}
// Find optimal
int optimalYear = abandonYears[0];
double maxNpv = npvs[0];
for (int i = 1; i < npvs.length; i++) {
if (npvs[i] > maxNpv) {
maxNpv = npvs[i];
optimalYear = abandonYears[i];
}
}
System.out.println("\nOptimal abandonment year: " + optimalYear);
8. Key Performance Indicators for Late-Life
| KPI | Early Life | Late Life | Action Trigger |
|---|---|---|---|
| Water cut | <30% | >80% | Water treatment upgrade |
| GOR | <200 | >500 | Compression upgrade |
| Uptime | >95% | <90% | Maintenance review |
| OPEX/bbl | <10 USD | >25 USD | Cost reduction |
| Power consumption | Design | +50% | Energy efficiency |
| CO₂ intensity | <10 kg/boe | >25 kg/boe | Emissions reduction |
9. NeqSim Classes for Late-Life Analysis
| Class | Purpose | Key Methods |
|---|---|---|
ScenarioAnalyzer |
Compare operating scenarios | runAll(), generateReport() |
BottleneckAnalyzer |
Identify constraints | getPrimaryBottleneck() |
ProducedWaterTreatmentTrain |
Water handling capacity | isDischargeCompliant() |
DecommissioningEstimator |
Abandonment cost | getTotalCostMUSD() |
ProductionProfile |
Decline forecasting | forecast() |
CashFlowEngine |
Economic analysis | calculate(), getBreakevenOilPrice() |
See Also
- TPG4230_SUPPORT_GUIDE.md - Overall TPG4230 support
- TPG4230_EXAMPLES.md - Code examples
- INTEGRATED_FIELD_DEVELOPMENT_FRAMEWORK.md - Full API reference