Skip to content
Open
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
4 changes: 4 additions & 0 deletions docs/thermal_component_base.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ All parameters below are defined in the Hercules input YAML file. The base class
| `fuel_density` | kg/m³ | Fuel density for mass calculations |
| `efficiency_table` | dict | Dictionary containing `power_fraction` and `efficiency` arrays (see below). Efficiency values must be HHV net plant efficiencies. |

### Optional Parameters
| `startup_fuel_fraction` | fraction (0-1) | Optional, fuel consumption during startup, as a fraction of rated fuel consumption. Defaults to 0 |
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this to the new optional parameters section in the docs.

| `shutdown_fuel_fraction` | fraction (0-1) | Optional, fuel consumption during shutdown, as a fraction of rated fuel consumption. Defaults to 0 |

### Optional Parameters
| Parameter | Units | Description |
|-----------|-------|-------------|
Expand Down
4 changes: 4 additions & 0 deletions examples/07_open_cycle_gas_turbine/hercules_input.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ open_cycle_gas_turbine:
# HHV: 39.05 MJ/m³, Density: 0.768 kg/m³
hhv: 39050000 # J/m³ for natural gas (39.05 MJ/m³) [6]
fuel_density: 0.768 # kg/m³ for natural gas [6]
# Optional startup/shutdown fuel fractions (as fractions of rated fuel flow)
# Approximated using case SC1A described in Exhibits 3-70, 3-71, and 3-173 of [5]
startup_fuel_fraction: 0.35 # 35% of rated fuel flow for startup
shutdown_fuel_fraction: 0.30 # 30% of rated fuel flow for shutdown
efficiency_table:
power_fraction:
- 1.0
Expand Down
59 changes: 48 additions & 11 deletions hercules/plant_components/thermal_component_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ def __init__(self, h_dict, component_name):
self.min_up_time = component_dict["min_up_time"] # s
self.min_down_time = component_dict["min_down_time"] # s

# Extract optional parameters for startup and shutdown fuel fractions
self.startup_fuel_fraction = component_dict.get("startup_fuel_fraction", None)
self.shutdown_fuel_fraction = component_dict.get("shutdown_fuel_fraction", None)

# Check all required parameters are numbers
if not isinstance(self.rated_capacity, (int, float, hercules_float_type)):
raise ValueError("rated_capacity must be a number")
Expand Down Expand Up @@ -573,7 +577,23 @@ def _apply_on_constraints(self, power_setpoint):
return P_constrained

def calculate_efficiency(self, power_output):
"""Calculate HHV net efficiency based on current power output.
"""Calculate HHV net efficiency based on current power output and state.

Args:
power_output (float): Current power output in kW.

Returns:
float: HHV net efficiency as a fraction (0-1).
"""
fuel_consumption_rate = self.calculate_fuel_volume_rate(power_output) # m³/s

if fuel_consumption_rate == 0:
return np.nan # Efficiency is undefined when fuel consumption is zero

return (power_output * 1000.0) / (fuel_consumption_rate * self.hhv)

def interpolate_efficiency(self, power_output):
"""Interpolate HHV net efficiency based on current power output.

Uses linear interpolation from the efficiency table. Values outside the
table range are clamped to the nearest endpoint.
Expand All @@ -584,10 +604,6 @@ def calculate_efficiency(self, power_output):
Returns:
float: HHV net efficiency as a fraction (0-1).
"""
if power_output <= 0:
# Return efficiency at lowest power fraction when off
return self.efficiency_values[0]

# Calculate power fraction
power_fraction = power_output / self.rated_capacity

Expand All @@ -607,15 +623,36 @@ def calculate_fuel_volume_rate(self, power_output):
Returns:
float: Fuel volume flow rate in m³/s.
"""
if power_output <= 0:
rated_fuel_consumption_rate = (self.rated_capacity * 1000.0) / (
self.hhv * self.interpolate_efficiency(self.rated_capacity)
) # m³/s at rated capacity

if self.state == self.STATES.OFF:
# When off, fuel flow is zero
return 0.0
elif self.state == self.STATES.STOPPING and self.shutdown_fuel_fraction is not None:
# When stopping, use shutdown fuel fraction if provided
return max(
self.shutdown_fuel_fraction * rated_fuel_consumption_rate,
power_output * 1000.0 / (self.hhv * self.interpolate_efficiency(power_output)),
)

# Calculate current HHV net efficiency
efficiency = self.calculate_efficiency(power_output)
elif (
self.state
in [
self.STATES.HOT_STARTING,
self.STATES.WARM_STARTING,
self.STATES.COLD_STARTING,
]
and self.startup_fuel_fraction is not None
):
# During startup (HOT_STARTING, WARM_STARTING, COLD_STARTING), use startup fuel fraction
return self.startup_fuel_fraction * rated_fuel_consumption_rate

# When on, calculate fuel rate based on current HHV net efficiency
efficiency = self.interpolate_efficiency(power_output)

# Calculate fuel volume rate using HHV net efficiency
# fuel_volume_rate (m³/s) = power (W) / (efficiency * hhv (J/m³))
# Convert power from kW to W (multiply by 1000)
fuel_m3_per_s = (power_output * 1000.0) / (efficiency * self.hhv)

return fuel_m3_per_s
return (power_output * 1000.0) / (efficiency * self.hhv)
3 changes: 2 additions & 1 deletion tests/thermal_component_base_test.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import copy

import numpy as np
import pytest
from hercules.plant_components.thermal_component_base import ThermalComponentBase

Expand Down Expand Up @@ -435,7 +436,7 @@ def test_efficiency_clamping():

# Test at zero power (should return first efficiency value)
eff_0 = tcb.calculate_efficiency(0)
assert eff_0 == pytest.approx(0.30)
assert np.isnan(eff_0)


def test_efficiency_interpolation():
Expand Down
Loading