- name
- neqsim-power-generation
- description
- Power generation patterns for NeqSim. USE WHEN: modeling gas turbines, steam turbines, HRSG, combined cycle systems, waste heat recovery, or calculating fuel gas consumption and thermal efficiency. Covers GasTurbine, SteamTurbine, HRSG, CombinedCycleSystem classes and heat integration with PinchAnalysis.
- last_verified
- 2026-07-04
# Power Generation with NeqSim
Guide for modeling power generation equipment — gas turbines, steam turbines,
heat recovery steam generators (HRSG), and combined cycle systems.
## When to Use This Skill
- Gas turbine modeling (power output, fuel consumption, exhaust conditions)
- Steam turbine expansion and power generation
- Heat recovery steam generator (HRSG) design
- Combined cycle system integration (GT + HRSG + ST)
- Waste heat recovery from process streams
- Fuel gas consumption and CO2 emissions from drivers
- Thermal efficiency calculations
- Heat integration / pinch analysis for process plants
## Key NeqSim Classes
| Class | Package | Purpose |
|-------|---------|---------|
| `GasTurbine` | `process.equipment.powergeneration` | Gas turbine with compressor, combustor, expander |
| `GasTurbineVendorPerformance` | `process.equipment.powergeneration` | Vendor ISO-rated GT driver — fuel + CO2 matched to a shaft/electric load demand |
| `SteamTurbine` | `process.equipment.powergeneration` | Steam expansion turbine |
| `HRSG` | `process.equipment.powergeneration` | Heat recovery steam generator |
| `CombinedCycleSystem` | `process.equipment.powergeneration` | GT + HRSG + ST integrated system |
| `PinchAnalysis` | `process.equipment.heatexchanger.heatintegration` | Pinch analysis for heat integration |
| `HeatStream` | `process.equipment.heatexchanger.heatintegration` | Hot/cold stream for pinch analysis |
## Vendor-performance GT driver — matched fuel & power (PREFERRED for drivers)
For a real mechanical-drive or generator gas turbine (e.g. a GE LM2500 driving a
compressor or an AC generator), the built-in simple-cycle `GasTurbine` is a rough
model and is unreliable for net power / efficiency. Use
`GasTurbineVendorPerformance` instead: it takes a **load demand** and returns the
fuel rate and CO2 **matched to that load** using the fuel gas's rigorous ISO 6976
LCV and stoichiometric carbon.
```java
GasTurbineVendorPerformance gt = new GasTurbineVendorPerformance("GT driver", fuelStream);
gt.setVendorRating(22.4, "MW", 0.37); // ISO base power, base LHV efficiency
gt.setAmbientDerating(15.0, 0.007); // design ambient C, power lapse /degC
gt.setSiteAmbientTemperature(15.0);
gt.setPartLoadHeatRateCoefficient(0.15); // heat-rate rise at part load
gt.setLoadDemand(compressor.getPower("kW"), "kW"); // <-- the process power need
gt.run(UUID.randomUUID());
double fuel = gt.getFuelFlowRate("kg/hr");
double co2 = gt.getCO2EmissionRate("tonne/day");
double loadFrac = gt.getLoadFraction(); // vs site-rated MAX (bottleneck basis)
double spareKW = gt.getSiteRatedPower("kW") - compressor.getPower("kW");
```
**Matching rule (do this, never hardcode fuel/power):**
- **Mechanical-drive GT** load demand = the *simulated* compressor shaft power
(`compressor.getPower("kW")`), so fuel and CO2 track the process automatically.
- **Fuel gas** is a slip-stream of the real process gas (e.g. treated export gas).
For a closed mass balance, physically tap it with a `Splitter`
(`setFlowRates([-1.0, fuelKgHr], "kg/hr")`) so sales gas = gas − fuel.
- **Platform electric LOAD** is an *operational* quantity — resolve it by source
priority, do NOT hardcode: (1) measured historian tag (tagreader/Seeq
main-switchboard active power) — the correct primary source; (2) STID
generator installed rating × documented load factor *if* STID exposes a
structured rating; (3) a clearly-flagged fallback. STID's structured
`rating`/`load` fields are frequently empty (they live in the datasheet PDF),
so the historian is the right source for the actual load — record the chosen
`source` in `results.json` so the value is never an unsourced magic number.
- **Max limits / bottlenecks** for production optimization: report per-GT
`getSiteRatedPower`, `getLoadFraction`, spare power, and N+1 firm capacity for
the generators; the highest-loaded unit is the power bottleneck.
## 1. Gas Turbine
```java
// Fuel gas stream — the combustion air is generated internally by the GasTurbine.
SystemInterface fuelGas = new SystemSrkEos(273.15 + 25, 30.0);
fuelGas.addComponent("methane", 0.90);
fuelGas.addComponent("ethane", 0.06);
fuelGas.addComponent("propane", 0.02);
fuelGas.addComponent("nitrogen", 0.02);
fuelGas.setMixingRule("classic");
Stream fuelStream = new Stream("Fuel Gas", fuelGas);
fuelStream.setFlowRate(5000.0, "kg/hr");
fuelStream.run();
// Simplified Brayton-cycle gas turbine: internal air compressor + combustor + expander + cooler.
GasTurbine gt = new GasTurbine("GT-001", fuelStream);
gt.combustionpressure = 18.0; // firing / combustion pressure [bara]
gt.setExcessAirFactor(2.5); // excess air over stoichiometric (caps firing temperature)
gt.run();
double power_MW = gt.getPower("MW"); // net shaft power (expander - air compressor)
double rejectHeat_W = gt.getHeat(); // heat rejected by the exhaust cooler [W]
double idealAFR = gt.calcIdealAirFuelRatio(); // stoichiometric air/fuel mass ratio
```
> The legacy `GasTurbine` is a simplified thermodynamic Brayton model. For
> vendor-rated power, part-load + ambient correction, degradation, emissions,
> and dispatch use `GasTurbineUnit` + `GasTurbineCatalog` (see section 7).
### Inverse (power-demand) mode — size fuel to a load
`GasTurbine` can also run **inverse**: instead of fuel-in → power-out, give it a
required net power and it sizes the fuel-gas flow so the turbine delivers that
load from the fuel lower heating value (LCV) and its `thermalEfficiency`. Use
this when a compressor/generator load is known and you want the matching fuel
(and CO₂) consumption as the process solves.
```java
GasTurbine gt = new GasTurbine("GT-driver", fuelStream);
gt.setThermalEfficiency(0.36); // REQUIRED (> 0) for power-demand mode
gt.setRequiredPower(18.0, "MW"); // driven load; unit: "W", "kW" or "MW"
gt.run();
double fuel_kghr = gt.getFuelFlowRate("kg/hr"); // fuel-gas consumption sized to the load
double fuel_Sm3d = gt.getFuelFlowRate("Sm3/day");
boolean inverse = gt.isPowerDemandMode(); // true
double reqW = gt.getRequiredPower(); // required power in Watts
```
> `setRequiredPower(0.0, ...)` returns the turbine to the normal fuel-to-power
> mode. Power-demand mode throws if `thermalEfficiency <= 0`. For vendor-accurate
> fuel/CO₂ vs a load demand, prefer `GasTurbineVendorPerformance` (top of this
> skill) or the catalog-driven `GasTurbineUnit` (section 7).
### Reading CO₂ off a load-driven turbine — three traps
`addDrivenLoad(compressor)` is the cleanest way to size fuel to a real duty: the
turbine sums `Compressor.getPower()` over its loads each solve, so the fuel gas
tracks the process. Getting an **emission** number out of it has three traps.
```java
GasTurbine gt = new GasTurbine("GT-driver");
gt.setInletStream(fuelStream);
gt.setThermalEfficiency(0.32); // REQUIRED
gt.addDrivenLoad(exportCompressor); // loads must be run before the turbine
gt.run();
double fuel_kghr = gt.getFuelFlowRate("kg/hr");
```
1. **Pseudo-components abort the combustion balance.** The stoichiometry asks the
element database for each hydrocarbon's C and H count, and a characterised
fluid's `C7P`/`C10A`… pseudo-components are not in it. Older builds threw
`Element:getNumberOfElements - Input C component not in element database`;
current builds estimate the atom counts from molar mass. Either way, prefer
building the **fuel** from real named components (`nitrogen, CO2, methane,
ethane, propane, i-butane, n-butane, i-pentane, n-pentane, n-hexane`) —
renormalising an export-gas composition onto that set typically captures
>99.8 mol% and matches what a plant actually burns.
2. **The combustion air carries CO₂ of its own.** `Fluid.create("combustion air")`
is an *unnormalised* `N2 0.78084 / O2 0.20946 / CO2 0.033 / water 0.1`, i.e.
**2.9 mol% CO₂** against atmospheric 0.04 %. Subtract the air-borne CO₂
(`gt.airStream`) before quoting an exhaust CO₂, or the number is inflated
(75 % in one 1.7 MW case).
3. **Cross-check against a carbon balance.** The defensible number is
`fuel_moles × (C atoms per mole fuel) × 44.01 g/mol`. Compare it with the
exhaust read; agreement to <1 % is the check that both the fuel sizing and the
exhaust composition are right. Do this before putting a CO₂ profile in a
report or a STEA export.
## 2. Steam Turbine
```java
// Steam at high pressure and temperature
SystemInterface steam = new SystemSrkEos(273.15 + 540, 100.0);
steam.addComponent("water", 1.0);
steam.setMixingRule("classic");
Stream steamFeed = new Stream("HP Steam", steam);
steamFeed.setFlowRate(50000.0, "kg/hr");
SteamTurbine st = new SteamTurbine("ST-001", steamFeed);
st.setOutletPressure(0.1); // Condenser pressure in bara
st.setIsentropicEfficiency(0.85);
st.run();
double stPower = st.getPower("MW");
double outletT = st.getOutletStream().getTemperature() - 273.15;
```
## 3. Heat Recovery Steam Generator (HRSG)
```java
// Recover heat from a hot turbine-exhaust gas stream. The HRSG takes a single
// hot-gas inlet stream; steam conditions are set on the unit.
HRSG hrsg = new HRSG("HRSG-001", exhaustGasStream);
hrsg.setSteamPressure(40.0); // bara
hrsg.setSteamTemperature(400.0, "C");
hrsg.setFeedWaterTemperature(105.0, "C");
hrsg.setApproachTemperature(15.0);
hrsg.run();
double duty_W = hrsg.getHeatTransferred();
double steamFlow = hrsg.getSteamFlowRate("kg/hr");
double stackT = hrsg.getGasOutletTemperature() - 273.15; // °C
```
## 4. Combined Cycle System
```java
// Integrated GT + HRSG + ST. The sub-units are built internally from the fuel
// gas stream — configure conditions through the setters below.
CombinedCycleSystem ccgt = new CombinedCycleSystem("CCGT", fuelStream);
ccgt.setCombustionPressure(18.0);
ccgt.setSteamPressure(40.0);
ccgt.setSteamTemperature(400.0, "C");
ccgt.setGasTurbineEfficiency(0.38);
ccgt.setSteamTurbineEfficiency(0.85);
ccgt.run();
double totalPower = ccgt.getTotalPower("MW");
double gtPower_W = ccgt.getGasTurbinePower();
double stPower_W = ccgt.getSteamTurbinePower();
double combinedEfficiency = ccgt.getOverallEfficiency();
// Typical: 55-62% for modern CCGT
```
## 5. Heat Integration (Pinch Analysis)
```java
// Identify minimum utility requirements for a process
PinchAnalysis pinch = new PinchAnalysis("Plant Heat Integration");
// Add hot streams (need cooling)
pinch.addHotStream(new HeatStream("Reactor effluent", 250.0, 60.0, 5000.0));
pinch.addHotStream(new HeatStream("Column overhead", 120.0, 40.0, 3000.0));
pinch.addHotStream(new HeatStream("Product cooler", 80.0, 30.0, 1500.0));
// Add cold streams (need heating)
pinch.addColdStream(new HeatStream("Feed preheater", 25.0, 180.0, 4500.0));
pinch.addColdStream(new HeatStream("Reboiler", 150.0, 160.0, 2000.0));
// Set minimum approach temperature
pinch.setMinApproachTemperature(10.0); // degrees C
pinch.run();
double minHotUtility = pinch.getMinHotUtility(); // kW
double minColdUtility = pinch.getMinColdUtility(); // kW
double pinchTemp = pinch.getPinchTemperature(); // °C
```
## 6. Emissions from Power Generation
```java
// Fuel gas composition determines CO2 emissions
// CH4 + 2O2 -> CO2 + 2H2O
// C2H6 + 3.5O2 -> 2CO2 + 3H2O
// C3H8 + 5O2 -> 3CO2 + 4H2O
// Approximate: 2.75 kg CO2 per kg natural gas (varies with composition)
double fuelRate_kg_hr = fuelStream.getFlowRate("kg/hr");
double co2Factor = 2.75; // kg CO2 / kg fuel (adjust for actual composition)
double co2_tonnes_yr = fuelRate_kg_hr * co2Factor * 8760 / 1e6;
// For a rigorous full-carbon-balance CO2, NOx, and methane-slip estimate use the
// catalog-driven GasTurbineUnit (section 7): gt.getCO2EmissionKgPerHr().
```
## 7. Right-Sizing & Dispatch (gasturbine sub-package)
For late-life or turndown studies where the question is *"which turbines, how
many, and at what load?"* — use the catalog-driven classes under
`neqsim.process.equipment.powergeneration.gasturbine`. These integrate directly
with `ProcessSystem` and link to `Compressor.getPower()` via the
`PowerDemandConsumer` interface.
| Class | Purpose |
|-------|---------|
| `GasTurbineCatalog` | Loads the bundled `gas_turbine_catalog.csv` (14 aero + industrial models: LM2500, LM2500PLUS_G4, LM6000PF/PG, RB211_6562, Trent 60, SGT-700/750, Centaur 50, Taurus 60/70, Mars 100, Titan 130/250) |
| `GasTurbineSpec` | Immutable rating point (rated MW, ISO heat rate, exhaust flow/T, NOx, mass) |
| `GasTurbinePerformanceMap` | Part-load + ambient correction (aero vs industrial polynomials, min-load fraction) |
| `GasTurbineDegradation` | Recoverable + non-recoverable fouling vs fired hours, `offlineWash()` full reset and `onlineWash(effectiveness)` partial recovery |
| `GasTurbineWashPlanner` | Wash-interval economics: sawtooth with partial recovery, extra fuel/CO2/cost per interval, optimal interval, payback of a permanent on-line wash installation |
| `GasTurbineEmissions` | Full-carbon-balance CO2, NOx, methane slip from fuel composition |
| `CO2TaxSchedule` | Loads `co2_tax_norway.csv` (2020–2040 NOK/tonne, CO2 tax + EU ETS), linear interpolation |
| `GasTurbineUnit` | `TwoPortEquipment` — runs inside a `ProcessSystem`, accepts fuel `Stream`, aggregates `Compressor` shaft load via `addPowerConsumer` |
| `TurbineDispatchOptimizer` | Picks the cheapest feasible on/off combination (brute-force ≤8 units, merit-order above) with N+1 reserve |
| `LateLifeRetrofitStudy` | Year-by-year NPV / CO2-avoided / payback for baseline vs retrofit fleet over a declining demand profile |
### Water-wash interval and permanent-wash business case
When the question is *"how often should we wash, and is a permanent on-line wash
skid worth it?"*, drive `GasTurbineWashPlanner` from the plant's **measured**
corrected-efficiency trend rather than a generic OEM rate. An energy-management
system usually trends "corrected turbine efficiency" in percentage points;
`lossRateFromCorrectedEfficiencyTrend(ppPer1000FiredHours, cleanEfficiencyPercent)`
converts that KPI slope into the fractional loss rate the planner needs.
```java
GasTurbineWashPlanner planner = new GasTurbineWashPlanner();
planner.setShaftPowerW(22.1e6);
planner.setBaselineHeatRateKJPerKWh(10090.0);
planner.setFuelLhvKJPerSm3(36500.0); // from Standard_ISO6976 getValue("LCV","kJ/m3")
planner.setCo2PerSm3Fuel(2.06); // carbon balance on the fuel composition
planner.setEfficiencyLossRatePerFiredHour(
GasTurbineWashPlanner.lossRateFromCorrectedEfficiencyTrend(0.24, 92.0));
planner.setRecoveryEffectiveness(0.40); // on-line ~0.3-0.5, off-line crank ~0.85-0.95
planner.setOutageHoursPerWash(0.0); // on-line washing has no outage
planner.setWashCostPerEvent(20000.0);
planner.setFuelValuePerSm3(3.0);
View on GitHub