Skip to content

Including fuel volume rates when starting up / shutting down#236

Open
jfrederik-nrel wants to merge 10 commits intoNatLabRockies:developfrom
jfrederik-nrel:feature/startup_fuel_consumption
Open

Including fuel volume rates when starting up / shutting down#236
jfrederik-nrel wants to merge 10 commits intoNatLabRockies:developfrom
jfrederik-nrel:feature/startup_fuel_consumption

Conversation

@jfrederik-nrel
Copy link
Copy Markdown
Collaborator

@jfrederik-nrel jfrederik-nrel commented Mar 19, 2026

This PR (partly) fixes issue #234.

Work in progress. To do:

  • Properly test it: still needs to be added to __init__
  • Implement in all thermal classes (not just thermal_component_base)
  • Include it in the examples
  • Update documentation
  • Update tests

How I implemented it now is that users can provide the startup_fuel_fraction and shutdown_fuel_fraction as a fraction of the rated fuel consumption. If not provided, it is assumed to be 0 (startup and shutdown costs no fuel). This is probably the easiest way to implement it, but perhaps not the easiest value to obtain. Alternatively, we could directly provide the startup/shutdown_fuel_volume_rate, which might be easier to obtain.

Would appreciate feedback on which method sounds best @dzalkind, @genevievestarke. Both input methods should be similarly easy to implement.

@genevievestarke genevievestarke linked an issue Mar 20, 2026 that may be closed by this pull request
Copy link
Copy Markdown
Collaborator

@genevievestarke genevievestarke left a comment

Choose a reason for hiding this comment

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

This looks good @jfrederik-nrel! I just had a few comments before it's ready to come in!

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", 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.

Is this the current behavior? Where the starting and stopping fuel consumption is zero?

Copy link
Copy Markdown
Collaborator Author

@jfrederik-nrel jfrederik-nrel Mar 24, 2026

Choose a reason for hiding this comment

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

Yes, the current behavior automatically sets fuel consumption to 0 when the power is <=0. So if startup_fuel_consumption is not defined, we get the same response as we had before this PR.

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.

It looks like the original behavior uses fuel when it is ramping up and down (not just the ON status), but not before the ramp up starts:
image

The power output is above zero once ramping starts, so it goes past the zero power return.

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.

Also, if you change the startup_fuel_fraction to 0.9, it changes the fuel behavior for the whole simulation:
image

Should we have limits on the fuel fraction numbers?

self.hhv * self.calculate_efficiency(self.rated_capacity)
) # m³/s at rated capacity

if self.state == self.STATES.ON:
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.

It seems like we could make the ON state the default and call out the starting and stopping behavior with the ifs?

(power_output * 1000.0) / (efficiency * self.hhv),
rated_fuel_consumption_rate * self.startup_fuel_fraction,
)
elif self.state == self.STATES.OFF:
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.

I think this is taken care of on line 611. We could combine this one and the earlier one, perhaps?

| `hhv` | J/m³ | Higher heating value of fuel |
| `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. |
| `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.

@jfrederik-nrel
Copy link
Copy Markdown
Collaborator Author

@genevievestarke I think my latest push addresses your previous comments:

  1. I removed the max operation in calculate_fuel_volume_rate to get rid of the undesired behavior when startup_fuel_rate is set very high.
  2. I redefined how the efficiency is calculated, reversing the order (calculate fuel rate first, base efficiency on this fuel rate and the current power)
  3. Created a new function interpolate_efficiency that basically has the functionality that the old calculate_efficiency had, i.e., determine the efficiency by interpolating the power_fraction-efficiency table. This method is now only used when the turbine is on.

Note that it is now failing some tests, as I defined the efficiency as NaN if fuel consumption is zero to prevent divide-by-zero errors. As a result we will need to redefine some of the tests that assume efficiency is the lowest value in the table when power is zero. If we like this solution, I can easily implement that, but I wanted to make sure that we like this solution before I spent time on doing that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve fuel consumption calculations of thermal units

2 participants