Optimizing an Asset with the Asset API
The asset API allows optimizing a single asset at once. Internally the assets are using the epl.Site
, but this is hidden when using the asset API.
You can find full examples for each asset here.
Battery
Dispatch an electric battery operating in wholesale price arbitrage using epl.Battery
:
import energypylinear as epl
# 2.0 MW, 4.0 MWh battery
asset = epl.battery.Battery(power_mw=2, capacity_mwh=4, efficiency=0.9)
results = asset.optimize(
electricity_prices=[100.0, 50, 200, -100, 0, 200, 100, -100],
freq_mins=60,
initial_charge_mwh=1,
final_charge_mwh=3,
objective="price"
)
assert all(
results.simulation.columns
== [
'site-import_power_mwh',
'site-export_power_mwh',
'spill-electric_generation_mwh',
'spill-electric_load_mwh',
'spill-high_temperature_generation_mwh',
'spill-low_temperature_generation_mwh',
'spill-high_temperature_load_mwh',
'spill-low_temperature_load_mwh',
'spill-gas_consumption_mwh',
'battery-electric_charge_mwh',
'battery-electric_charge_binary',
'battery-electric_discharge_mwh',
'battery-electric_discharge_binary',
'battery-electric_loss_mwh',
'battery-initial_charge_mwh',
'battery-final_charge_mwh',
'total-electric_generation_mwh',
'total-electric_load_mwh',
'total-high_temperature_generation_mwh',
'total-low_temperature_generation_mwh',
'total-high_temperature_load_mwh',
'total-low_temperature_load_mwh',
'total-gas_consumption_mwh',
'total-electric_charge_mwh',
'total-electric_discharge_mwh',
'total-spills_mwh',
'total-electric_loss_mwh',
'site-electricity_balance_mwh',
'electricity_prices',
'electricity_carbon_intensities',
'load-high_temperature_load_mwh',
'load-low_temperature_load_mwh',
'load-low_temperature_generation_mwh'
]
)
The battery will charge with electricity at low prices, and discharge at high prices. An efficiency penalty is applied to the battery charge energy (energy is lost during charging).
Generator
Dispatch a CHP (combined heat & power) generator to generate electricity, high & low temperature heat from natural gas.
The epl.Generator
model can be configured with electric, high and low temperature thermal efficiencies.
This allows modelling both gas engines and gas turbines.
When optimizing, we can use interval data for the high and low temperature loads. These thermal loads will be met by gas boilers if the CHP chooses not to generate, or cannot meet thermal demands. High temperature heat can be let-down into low temperature heat.
The epl.Generator
is allowed to dump both high temperature and low temperature heat.
The high and low temperature heat demands are supplied alongside the electricity prices when optimizing:
import energypylinear as epl
# 100 MWe gas turbine
asset = epl.chp.Generator(
electric_power_max_mw=100,
electric_power_min_mw=50,
electric_efficiency_pct=0.3,
high_temperature_efficiency_pct=0.5,
)
# 100 MWe gas engine
asset = epl.chp.Generator(
electric_power_max_mw=100,
electric_power_min_mw=10,
electric_efficiency_pct=0.4,
high_temperature_efficiency_pct=0.2,
low_temperature_efficiency_pct=0.2,
)
results = asset.optimize(
electricity_prices=[100, 50, 200, -100, 0, 200, 100, -100],
high_temperature_load_mwh=[100, 50, 200, 40, 0, 200, 100, 100],
low_temperature_load_mwh=20
)
assert all(
results.simulation.columns == [
'site-import_power_mwh',
'site-export_power_mwh',
'spill-electric_generation_mwh',
'spill-electric_load_mwh',
'spill-high_temperature_generation_mwh',
'spill-low_temperature_generation_mwh',
'spill-high_temperature_load_mwh',
'spill-low_temperature_load_mwh',
'spill-gas_consumption_mwh',
'generator-electric_generation_mwh',
'generator-gas_consumption_mwh',
'generator-high_temperature_generation_mwh',
'generator-low_temperature_generation_mwh',
'boiler-high_temperature_generation_mwh',
'boiler-gas_consumption_mwh',
'valve-high_temperature_load_mwh',
'valve-low_temperature_generation_mwh',
'total-electric_generation_mwh',
'total-electric_load_mwh',
'total-high_temperature_generation_mwh',
'total-low_temperature_generation_mwh',
'total-high_temperature_load_mwh',
'total-low_temperature_load_mwh',
'total-gas_consumption_mwh',
'total-electric_charge_mwh',
'total-electric_discharge_mwh',
'total-spills_mwh',
'total-electric_loss_mwh',
'site-electricity_balance_mwh',
'electricity_prices',
'electricity_carbon_intensities',
'load-high_temperature_load_mwh',
'load-low_temperature_load_mwh',
'load-low_temperature_generation_mwh'
]
)
Electric Vehicle Charging
Control a number of EV chargers to charge a number of charge events.
Chargers are configured by their size given in charger_mws
.
A charge_event
is a time interval where an EV can be charged. This is given as a boolean 2D array, with one binary digit for each charge events, interval pairs.
Each charge event has a required amount of electricity charge_event_mwh
, that can be delivered when the charge_event
is 1. The model is constrained so that each charge event receives all of it's charge_event_mwh
.
To optimize two 100 MWe chargers for 4 charge events over 5 intervals:
import energypylinear as epl
# 2 100 MW EV chargers
asset = epl.EVs(
chargers_power_mw=[100, 100],
charge_events_capacity_mwh = [50, 100, 30, 40],
charger_turndown=0.1
)
electricity_prices = [-100, 50, 30, 50, 40]
charge_events = [
[1, 0, 0, 0, 0],
[0, 1, 1, 1, 0],
[0, 0, 0, 1, 1],
[0, 1, 0, 0, 0],
]
results = asset.optimize(
electricity_prices=electricity_prices,
charge_events=charge_events,
)
assert all(
results.simulation.columns == [
'site-import_power_mwh',
'site-export_power_mwh',
'spill-electric_generation_mwh',
'spill-electric_load_mwh',
'spill-high_temperature_generation_mwh',
'spill-low_temperature_generation_mwh',
'spill-high_temperature_load_mwh',
'spill-low_temperature_load_mwh',
'spill-gas_consumption_mwh',
'evs-charger-0-electric_charge_mwh',
'evs-charger-0-electric_charge_binary',
'evs-charger-0-electric_discharge_mwh',
'evs-charger-0-electric_discharge_binary',
'evs-charger-1-electric_charge_mwh',
'evs-charger-1-electric_charge_binary',
'evs-charger-1-electric_discharge_mwh',
'evs-charger-1-electric_discharge_binary',
'evs-charge-event-0-electric_charge_mwh',
'evs-charge-event-0-electric_discharge_mwh',
'evs-charge-event-0-electric_loss_mwh',
'evs-charge-event-1-electric_charge_mwh',
'evs-charge-event-1-electric_discharge_mwh',
'evs-charge-event-1-electric_loss_mwh',
'evs-charge-event-2-electric_charge_mwh',
'evs-charge-event-2-electric_discharge_mwh',
'evs-charge-event-2-electric_loss_mwh',
'evs-charge-event-3-electric_charge_mwh',
'evs-charge-event-3-electric_discharge_mwh',
'evs-charge-event-3-electric_loss_mwh',
'evs-charge-event-0-initial_soc_mwh',
'evs-charge-event-1-initial_soc_mwh',
'evs-charge-event-2-initial_soc_mwh',
'evs-charge-event-3-initial_soc_mwh',
'evs-charge-event-0-final_soc_mwh',
'evs-charge-event-1-final_soc_mwh',
'evs-charge-event-2-final_soc_mwh',
'evs-charge-event-3-final_soc_mwh',
'evs-charger-spill-evs-electric_charge_mwh',
'evs-charger-spill-evs-electric_charge_binary',
'evs-charger-spill-evs-electric_discharge_mwh',
'evs-charger-spill-evs-electric_discharge_binary',
'total-electric_generation_mwh',
'total-electric_load_mwh',
'total-high_temperature_generation_mwh',
'total-low_temperature_generation_mwh',
'total-high_temperature_load_mwh',
'total-low_temperature_load_mwh',
'total-gas_consumption_mwh',
'total-electric_charge_mwh',
'total-electric_discharge_mwh',
'total-spills_mwh',
'total-electric_loss_mwh',
'site-electricity_balance_mwh',
'electricity_prices',
'electricity_carbon_intensities',
'load-high_temperature_load_mwh',
'load-low_temperature_load_mwh',
'load-low_temperature_generation_mwh'
]
)
Heat Pump
Optimize the operation of a heat pump. A heat pump uses electricity to convert low temperature heat to high temperature heat.
When using epl.HeatPump.optimize
, the alternative to the heat pump is generating high temperature heat from a gas boiler. Under the hood of epl.HeatPump.optimize
, a epl.Boiler
asset is used to supply the balance of high temperature heat demand of the site.
The gas price is important as the alternative to using a heat pump to supply the high_temperature_load_mwh
is using a natural gas boiler.
In order for the heat pump to work, it needs to have both a source of low temperature heat and a sink of high temperature heat.
The high_temperature_load_mwh
is the amount of heat consumed by the site, and low_temperature_generation_mwh
is the amount of available low temperature heat.
import energypylinear as epl
asset = epl.HeatPump(electric_power_mw=1.0, cop=2)
results = asset.optimize(
gas_prices=20,
electricity_prices=[100, -100],
high_temperature_load_mwh=3.0,
low_temperature_generation_mwh=3.0,
verbose=False
)
print(results.simulation[
[
"electricity_prices",
'heat-pump-electric_load_mwh',
'heat-pump-low_temperature_load_mwh',
'heat-pump-high_temperature_generation_mwh',
]
])
assert all(
results.simulation.columns
== [
'site-import_power_mwh',
'site-export_power_mwh',
'spill-electric_generation_mwh',
'spill-electric_load_mwh',
'spill-high_temperature_generation_mwh',
'spill-low_temperature_generation_mwh',
'spill-high_temperature_load_mwh',
'spill-low_temperature_load_mwh',
'spill-gas_consumption_mwh',
'boiler-high_temperature_generation_mwh',
'boiler-gas_consumption_mwh',
'valve-high_temperature_load_mwh',
'valve-low_temperature_generation_mwh',
'heat-pump-electric_load_mwh',
'heat-pump-low_temperature_load_mwh',
'heat-pump-high_temperature_generation_mwh',
'total-electric_generation_mwh',
'total-electric_load_mwh',
'total-high_temperature_generation_mwh',
'total-low_temperature_generation_mwh',
'total-high_temperature_load_mwh',
'total-low_temperature_load_mwh',
'total-gas_consumption_mwh',
'total-electric_charge_mwh',
'total-electric_discharge_mwh',
'total-spills_mwh',
'total-electric_loss_mwh',
'site-electricity_balance_mwh',
'electricity_prices',
'electricity_carbon_intensities',
'load-high_temperature_load_mwh',
'load-low_temperature_load_mwh',
'load-low_temperature_generation_mwh'
]
)
{
'n_spills': 1,
'spill_columns': 8,
'spills': {'spill-low_temperature_load_mwh': 5.0},
'event': 'warn_spills',
'timestamp': '2023-09-08T00:41:33.743617Z',
'logger':'default_logger',
'level': 'warning'
}
electricity_prices heat-pump-electric_load_mwh heat-pump-low_temperature_load_mwh heat-pump-high_temperature_generation_mwh
0 100 0.0 0.0 0.0
1 -100 1.0 1.0 2.0
Under the hood the heat pump asset also includes a epl.Spill
, which allows dumping of excess low temperature heat, and a epl.Valve
to allow high temperature heat to flow into low temperature heat.
The combination of a epl.Spill
, epl.Valve
and negative electricity prices can lead to the heat pump using electricity to generate high temperature heat which is then dumped as low temperature heat. For this reason the epl.HeatPump
asset includes a include_valve: bool
option to turn off the valve.
You could also setup an epl.Site
with other assets that generate high temperature heat to explore different tradeoffs (such as a heat pump using low temperature heat from a CHP system).