battery_optimizer.uk.request#
Classes
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Parameters that all UK dynamic services (DC, DM, DR) share. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- class battery_optimizer.uk.request.BMActivationRatio(*, start, activation_ratio=0.1)#
Bases:
BaseModel- model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'ignore', 'frozen': False, 'json_encoders': {<class 'datetime.datetime'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timedeltas.Timedelta'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timestamps.Timestamp'>: <function BaseModel.<lambda>>, <class 'pandas.core.frame.DataFrame'>: <function BaseModel.<lambda>>, <class 'pandas.core.series.Series'>: <function BaseModel.<lambda>>}, 'validate_default': True}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class battery_optimizer.uk.request.BalancingMechanism(*, activation_time_minutes=Timedelta('0 days 00:32:00'), activation_ratio=1.0)#
Bases:
BaseModel- Parameters:
- activation_ratio: float | list[BMActivationRatio] | DataFrame#
- model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'ignore', 'frozen': False, 'json_encoders': {<class 'datetime.datetime'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timedeltas.Timedelta'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timestamps.Timestamp'>: <function BaseModel.<lambda>>, <class 'pandas.core.frame.DataFrame'>: <function BaseModel.<lambda>>, <class 'pandas.core.series.Series'>: <function BaseModel.<lambda>>}, 'validate_default': True}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class battery_optimizer.uk.request.DCParameters(*, prequalified_power_high_kw=None, prequalified_power_low_kw=None, ramp_rate_perc_min=0.05, delivery_duration_sec=900, baseline_buffer_perc=0.12, delivery_duration_buffer_perc=1.1, min_energy_recovery_perc=0.2)#
Bases:
DynamicServicesParameters- Parameters:
prequalified_power_high_kw (Annotated[float, FieldInfo(annotation=NoneType, required=True, metadata=[Ge(ge=0.0)])] | list[PrequalifiedPowerHighKW] | Series | None)
prequalified_power_low_kw (Annotated[float, FieldInfo(annotation=NoneType, required=True, metadata=[Ge(ge=0.0)])] | list[PrequalifiedPowerLowKW] | Series | None)
ramp_rate_perc_min (float)
baseline_buffer_perc (Annotated[float, Ge(ge=0.0), Le(le=1.0)])
delivery_duration_buffer_perc (Annotated[float, Ge(ge=1.0), Le(le=2.0)])
min_energy_recovery_perc (Annotated[float, Ge(ge=0.0), Le(le=1.0)])
- model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'ignore', 'frozen': False, 'json_encoders': {<class 'datetime.datetime'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timedeltas.Timedelta'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timestamps.Timestamp'>: <function BaseModel.<lambda>>, <class 'pandas.core.frame.DataFrame'>: <function BaseModel.<lambda>>, <class 'pandas.core.series.Series'>: <function BaseModel.<lambda>>}, 'validate_default': True}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class battery_optimizer.uk.request.DMParameters(*, prequalified_power_high_kw=None, prequalified_power_low_kw=None, delivery_duration_sec=1800, baseline_buffer_perc=0.22, delivery_duration_buffer_perc=1.1, min_energy_recovery_perc=0.2)#
Bases:
DynamicServicesParameters- Parameters:
prequalified_power_high_kw (Annotated[float, FieldInfo(annotation=NoneType, required=True, metadata=[Ge(ge=0.0)])] | list[PrequalifiedPowerHighKW] | Series | None)
prequalified_power_low_kw (Annotated[float, FieldInfo(annotation=NoneType, required=True, metadata=[Ge(ge=0.0)])] | list[PrequalifiedPowerLowKW] | Series | None)
baseline_buffer_perc (Annotated[float, Ge(ge=0.0), Le(le=1.0)])
delivery_duration_buffer_perc (Annotated[float, Ge(ge=1.0), Le(le=2.0)])
min_energy_recovery_perc (Annotated[float, Ge(ge=0.0), Le(le=1.0)])
- model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'ignore', 'frozen': False, 'json_encoders': {<class 'datetime.datetime'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timedeltas.Timedelta'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timestamps.Timestamp'>: <function BaseModel.<lambda>>, <class 'pandas.core.frame.DataFrame'>: <function BaseModel.<lambda>>, <class 'pandas.core.series.Series'>: <function BaseModel.<lambda>>}, 'validate_default': True}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class battery_optimizer.uk.request.DRParameters(*, prequalified_power_high_kw=None, prequalified_power_low_kw=None, delivery_duration_sec=3600, baseline_buffer_perc=0.44, delivery_duration_buffer_perc=1.1, min_energy_recovery_perc=0.2)#
Bases:
DynamicServicesParameters- Parameters:
prequalified_power_high_kw (Annotated[float, FieldInfo(annotation=NoneType, required=True, metadata=[Ge(ge=0.0)])] | list[PrequalifiedPowerHighKW] | Series | None)
prequalified_power_low_kw (Annotated[float, FieldInfo(annotation=NoneType, required=True, metadata=[Ge(ge=0.0)])] | list[PrequalifiedPowerLowKW] | Series | None)
baseline_buffer_perc (Annotated[float, Ge(ge=0.0), Le(le=1.0)])
delivery_duration_buffer_perc (Annotated[float, Ge(ge=1.0), Le(le=2.0)])
min_energy_recovery_perc (Annotated[float, Ge(ge=0.0), Le(le=1.0)])
- model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'ignore', 'frozen': False, 'json_encoders': {<class 'datetime.datetime'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timedeltas.Timedelta'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timestamps.Timestamp'>: <function BaseModel.<lambda>>, <class 'pandas.core.frame.DataFrame'>: <function BaseModel.<lambda>>, <class 'pandas.core.series.Series'>: <function BaseModel.<lambda>>}, 'validate_default': True}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class battery_optimizer.uk.request.DSEnergyThroughput(*, start, dcl_MWh_per_MW=0.0, dch_MWh_per_MW=0.0, dml_MWh_per_MW=0.0, dmh_MWh_per_MW=0.0, drl_MWh_per_MW=0.0, drh_MWh_per_MW=0.0)#
Bases:
BaseModel- Parameters:
- model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'ignore', 'frozen': False, 'json_encoders': {<class 'datetime.datetime'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timedeltas.Timedelta'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timestamps.Timestamp'>: <function BaseModel.<lambda>>, <class 'pandas.core.frame.DataFrame'>: <function BaseModel.<lambda>>, <class 'pandas.core.series.Series'>: <function BaseModel.<lambda>>}, 'validate_default': True}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class battery_optimizer.uk.request.DSEnergyThroughputBuffer(*, enabled=False, rev_factor=0.06, rev_factor_mdo_mdb=1.0, efficiency_correct=False)#
Bases:
BaseModel- Parameters:
- model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'ignore', 'frozen': False, 'json_encoders': {<class 'datetime.datetime'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timedeltas.Timedelta'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timestamps.Timestamp'>: <function BaseModel.<lambda>>, <class 'pandas.core.frame.DataFrame'>: <function BaseModel.<lambda>>, <class 'pandas.core.series.Series'>: <function BaseModel.<lambda>>}, 'validate_default': True}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class battery_optimizer.uk.request.DynamicServicesParameters(*, prequalified_power_high_kw=None, prequalified_power_low_kw=None)#
Bases:
BaseModelParameters that all UK dynamic services (DC, DM, DR) share.
- Parameters:
prequalified_power_high_kw (Annotated[float, FieldInfo(annotation=NoneType, required=True, metadata=[Ge(ge=0.0)])] | list[PrequalifiedPowerHighKW] | Series | None)
prequalified_power_low_kw (Annotated[float, FieldInfo(annotation=NoneType, required=True, metadata=[Ge(ge=0.0)])] | list[PrequalifiedPowerLowKW] | Series | None)
- model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'ignore', 'frozen': False, 'json_encoders': {<class 'datetime.datetime'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timedeltas.Timedelta'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timestamps.Timestamp'>: <function BaseModel.<lambda>>, <class 'pandas.core.frame.DataFrame'>: <function BaseModel.<lambda>>, <class 'pandas.core.series.Series'>: <function BaseModel.<lambda>>}, 'validate_default': True}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class battery_optimizer.uk.request.MelMilNowParameters(*, timestamp_now, soc_now)#
Bases:
BaseModel- model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'ignore', 'frozen': False, 'json_encoders': {<class 'datetime.datetime'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timedeltas.Timedelta'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timestamps.Timestamp'>: <function BaseModel.<lambda>>, <class 'pandas.core.frame.DataFrame'>: <function BaseModel.<lambda>>, <class 'pandas.core.series.Series'>: <function BaseModel.<lambda>>}, 'validate_default': True}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class battery_optimizer.uk.request.PVForecast(*, start, technical_maximum_kw, production_forecast_kw)#
Bases:
BaseModel- model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'ignore', 'frozen': False, 'json_encoders': {<class 'datetime.datetime'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timedeltas.Timedelta'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timestamps.Timestamp'>: <function BaseModel.<lambda>>, <class 'pandas.core.frame.DataFrame'>: <function BaseModel.<lambda>>, <class 'pandas.core.series.Series'>: <function BaseModel.<lambda>>}, 'validate_default': True}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class battery_optimizer.uk.request.PowerSwingLimit(*, applies, value_kw)#
Bases:
BaseModel- model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'ignore', 'frozen': False, 'json_encoders': {<class 'datetime.datetime'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timedeltas.Timedelta'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timestamps.Timestamp'>: <function BaseModel.<lambda>>, <class 'pandas.core.frame.DataFrame'>: <function BaseModel.<lambda>>, <class 'pandas.core.series.Series'>: <function BaseModel.<lambda>>}, 'validate_default': True}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class battery_optimizer.uk.request.PrequalifiedPowerHighKW(*, start, prequalified_power_high_kw)#
Bases:
BaseModel- model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'ignore', 'frozen': False, 'json_encoders': {<class 'datetime.datetime'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timedeltas.Timedelta'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timestamps.Timestamp'>: <function BaseModel.<lambda>>, <class 'pandas.core.frame.DataFrame'>: <function BaseModel.<lambda>>, <class 'pandas.core.series.Series'>: <function BaseModel.<lambda>>}, 'validate_default': True}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class battery_optimizer.uk.request.PrequalifiedPowerLowKW(*, start, prequalified_power_low_kw)#
Bases:
BaseModel- model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'ignore', 'frozen': False, 'json_encoders': {<class 'datetime.datetime'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timedeltas.Timedelta'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timestamps.Timestamp'>: <function BaseModel.<lambda>>, <class 'pandas.core.frame.DataFrame'>: <function BaseModel.<lambda>>, <class 'pandas.core.series.Series'>: <function BaseModel.<lambda>>}, 'validate_default': True}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class battery_optimizer.uk.request.TraderExclusion(*, start, dch, dcl, dmh=False, dml=False, drh=False, drl=False)#
Bases:
BaseModel- model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'ignore', 'frozen': False, 'json_encoders': {<class 'datetime.datetime'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timedeltas.Timedelta'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timestamps.Timestamp'>: <function BaseModel.<lambda>>, <class 'pandas.core.frame.DataFrame'>: <function BaseModel.<lambda>>, <class 'pandas.core.series.Series'>: <function BaseModel.<lambda>>}, 'validate_default': True}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class battery_optimizer.uk.request.UKAsset(*, asset_id='Unique ID of the asset', battery_parameters, battery_initial_conditions, battery_marketed, battery_availabilities, price_forecast, price_buckets=None, strategy_optimization, asset_states=[], skipped_validations={'ensure_battery_marketed_respects_battery_parameters'}, battery_commercials, PV_forecast, dynamic_services_energy_throughput=Empty DataFrame Columns: [] Index: [], allow_pv_to_battery=False)#
Bases:
Asset- Parameters:
battery_parameters (UKBatteryParameters)
battery_initial_conditions (UKBatteryInitialConditions)
battery_marketed (list[UKBatteryMarketed] | DataFrame)
battery_availabilities (list[BatteryAvailability] | DataFrame)
price_forecast (list[UKPriceForecast] | DataFrame)
price_buckets (Dict[datetime, PriceBuckets] | None)
strategy_optimization (UKStrategyOptimization)
asset_states (list[AssetState] | DataFrame | None)
battery_commercials (list[UKBatteryCommercials] | DataFrame)
PV_forecast (list[PVForecast] | DataFrame)
dynamic_services_energy_throughput (list[DSEnergyThroughput] | DataFrame)
allow_pv_to_battery (bool)
- PV_forecast: list[PVForecast] | DataFrame#
- property all_markets#
- battery_commercials: list[UKBatteryCommercials] | DataFrame#
- battery_initial_conditions: UKBatteryInitialConditions#
- battery_marketed: list[UKBatteryMarketed] | DataFrame#
- battery_parameters: UKBatteryParameters#
- property day_ahead_products#
- property dc_max_basepoint_change_per_dc_kW_trapezium#
- property dc_max_basepoint_change_per_dc_kW_triangle#
- dynamic_services_energy_throughput: list[DSEnergyThroughput] | DataFrame#
- property energy_products#
- ensure_PV_forecast_respects_grid_connection()#
PV production forecasts are currently provided as-is as fixed input. Since we cannot control the quality of the these PV production forecasts we need to guard our optimization routine against PV forecasts that would render our mixed-integer problem infeasible. Infeasible solutions arise e.g. when the provided PV forecast is greater than the grid connection export limit. To this end, we refuse obviously wrong PV forecast inputs (e.g. negative values) and clip the PV forecast from above to the grid connection export limit - thus ensuring that the PV forecast does not render our problem infeasible.
- classmethod ensure_ds_marketed_in_integer_increments_of_MW(battery_marketed)#
- ensure_energy_cost_provided_if_customer_perspective()#
- property frequency_markets#
- model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'ignore', 'frozen': False, 'json_encoders': {<class 'datetime.datetime'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timedeltas.Timedelta'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timestamps.Timestamp'>: <function BaseModel.<lambda>>, <class 'pandas.core.frame.DataFrame'>: <function BaseModel.<lambda>>, <class 'pandas.core.series.Series'>: <function BaseModel.<lambda>>}, 'validate_default': True}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- price_forecast: list[UKPriceForecast] | DataFrame#
- strategy_optimization: UKStrategyOptimization#
- property uk_dynamic_services_variables_high#
- property uk_dynamic_services_variables_low#
- class battery_optimizer.uk.request.UKBatteryCommercials(*, start, min_revenue_per_intraday_sell=0.01, min_revenue_per_virtual_wholesale_sell=0.01, BSUoS, FiT, RO, AAHEDC, CfD, CM_Levy, LLF, TLM, Mgmt_Fee, Imbal_risk, RCRC, Elexon, TNuOS_charg, TNuOS_disch, DUoS_ch, DUoS_disch, energy_cost, min_revenue_per_n2ex1h_sell=0.01, min_revenue_per_epex30min_sell=0.01)#
Bases:
BatteryCommercials- Parameters:
start (datetime)
min_revenue_per_intraday_sell (Annotated[float, Ge(ge=0.0)])
min_revenue_per_virtual_wholesale_sell (Annotated[float, Ge(ge=0.0)])
BSUoS (float)
FiT (float)
RO (float)
AAHEDC (float)
CfD (float)
CM_Levy (float)
LLF (float)
TLM (float)
Mgmt_Fee (float)
Imbal_risk (float)
RCRC (float)
Elexon (float)
TNuOS_charg (float)
TNuOS_disch (float)
DUoS_ch (float)
DUoS_disch (float)
energy_cost (float)
min_revenue_per_epex30min_sell (Annotated[float, Ge(ge=0.0)])
- model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'ignore', 'frozen': False, 'json_encoders': {<class 'datetime.datetime'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timedeltas.Timedelta'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timestamps.Timestamp'>: <function BaseModel.<lambda>>, <class 'pandas.core.frame.DataFrame'>: <function BaseModel.<lambda>>, <class 'pandas.core.series.Series'>: <function BaseModel.<lambda>>}, 'validate_default': True}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class battery_optimizer.uk.request.UKBatteryInitialConditions(*, initial_soe, initial_soe_kwh=None, perform_initial_soe_checks=False, initial_dch_kw, initial_dcl_kw, initial_dmh_kw=0.0, initial_dml_kw=0.0, initial_drh_kw=0.0, initial_drl_kw=0.0, battery_marketed=Empty DataFrame Columns: [] Index: [], dynamic_services_energy_throughput=Empty DataFrame Columns: [] Index: [])#
Bases:
BatteryInitialConditions- Parameters:
initial_soe (float)
perform_initial_soe_checks (bool)
initial_dch_kw (float)
initial_dcl_kw (float)
initial_dmh_kw (float)
initial_dml_kw (float)
initial_drh_kw (float)
initial_drl_kw (float)
battery_marketed (list[UKBatteryMarketed] | DataFrame)
dynamic_services_energy_throughput (list[DSEnergyThroughput] | DataFrame)
- battery_marketed: list[UKBatteryMarketed] | DataFrame#
- dynamic_services_energy_throughput: list[DSEnergyThroughput] | DataFrame#
- classmethod ensure_battery_marketed_dataframe(v)#
- classmethod ensure_dynamic_services_energy_throughput_dataframe(v)#
- model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'ignore', 'frozen': False, 'json_encoders': {<class 'datetime.datetime'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timedeltas.Timedelta'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timestamps.Timestamp'>: <function BaseModel.<lambda>>, <class 'pandas.core.frame.DataFrame'>: <function BaseModel.<lambda>>, <class 'pandas.core.series.Series'>: <function BaseModel.<lambda>>}, 'validate_default': True}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class battery_optimizer.uk.request.UKBatteryMarketed(*, start, bought_intraday_kw, sold_intraday_kw, bought_virtual_wholesale_kw=0.0, sold_virtual_wholesale_kw=0.0, sold_n2ex1h_kw, bought_n2ex1h_kw, dcl_kw, dch_kw, dml_kw=0.0, dmh_kw=0.0, drl_kw=0.0, drh_kw=0.0, sold_epex30min_kw, bought_epex30min_kw)#
Bases:
BatteryMarketed- Parameters:
start (datetime)
bought_intraday_kw (float)
sold_intraday_kw (float)
bought_virtual_wholesale_kw (float)
sold_virtual_wholesale_kw (float)
sold_n2ex1h_kw (float)
bought_n2ex1h_kw (float)
dcl_kw (float)
dch_kw (float)
dml_kw (float)
dmh_kw (float)
drl_kw (float)
drh_kw (float)
sold_epex30min_kw (float)
bought_epex30min_kw (float)
- model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'ignore', 'frozen': False, 'json_encoders': {<class 'datetime.datetime'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timedeltas.Timedelta'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timestamps.Timestamp'>: <function BaseModel.<lambda>>, <class 'pandas.core.frame.DataFrame'>: <function BaseModel.<lambda>>, <class 'pandas.core.series.Series'>: <function BaseModel.<lambda>>}, 'validate_default': True}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class battery_optimizer.uk.request.UKBatteryParameters(*, min_soe, max_soe, min_soe_kwh=None, max_soe_kwh=None, charging_efficiency, discharging_efficiency, max_charging_power_kw, max_discharging_power_kw, capacity_kwh, capacity_nominal_kwh=None, max_daily_cycle, daily_cycle_limit_applies=True, daily_cycle_limit_penalty=False, grid_connection_export_kw, grid_connection_import_kw, ramp_rates=UKRampRates(type=<RampingLogicName.dc_only: 'dc_only'>, charging_perf_related_kw_per_second=None, discharging_perf_related_kw_per_second=None, charging_tech_limited_kw_per_second=None, discharging_tech_limited_kw_per_second=None), power_swing_limit)#
Bases:
BatteryParameters- Parameters:
min_soe (Annotated[float, FieldInfo(annotation=NoneType, required=True, metadata=[Ge(ge=0.0), Le(le=1.0)])] | list[MinSoE] | Series)
max_soe (Annotated[float, FieldInfo(annotation=NoneType, required=True, metadata=[Ge(ge=0.0), Le(le=1.0)])] | list[MaxSoE] | Series)
min_soe_kwh (Annotated[float, FieldInfo(annotation=NoneType, required=True, metadata=[Ge(ge=0.0)])] | list[MinAbsoluteSoE] | Series | None)
max_soe_kwh (Annotated[float, FieldInfo(annotation=NoneType, required=True, metadata=[Ge(ge=0.0)])] | list[MaxAbsoluteSoE] | Series | None)
charging_efficiency (float)
discharging_efficiency (float)
max_charging_power_kw (Annotated[float, FieldInfo(annotation=NoneType, required=True, metadata=[Ge(ge=0.0)])] | list[MaxChargingPowerKW] | Series)
max_discharging_power_kw (Annotated[float, FieldInfo(annotation=NoneType, required=True, metadata=[Ge(ge=0.0)])] | list[MaxDischargingPowerKW] | Series)
capacity_kwh (Annotated[float, FieldInfo(annotation=NoneType, required=True, metadata=[Ge(ge=0.0)])] | list[CapacityKWh] | Series)
max_daily_cycle (Annotated[float, FieldInfo(annotation=NoneType, required=True, metadata=[Ge(ge=0.0)])] | list[MaxDailyCycle] | Series)
daily_cycle_limit_applies (bool | None)
daily_cycle_limit_penalty (bool)
ramp_rates (UKRampRates)
power_swing_limit (PowerSwingLimit)
- model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'ignore', 'frozen': False, 'json_encoders': {<class 'datetime.datetime'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timedeltas.Timedelta'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timestamps.Timestamp'>: <function BaseModel.<lambda>>, <class 'pandas.core.frame.DataFrame'>: <function BaseModel.<lambda>>, <class 'pandas.core.series.Series'>: <function BaseModel.<lambda>>}, 'validate_default': True}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- power_swing_limit: PowerSwingLimit#
- ramp_rates: UKRampRates#
- class battery_optimizer.uk.request.UKCommercialObjective(*, commercial_columns=['revenue_PV', 'dc_high_revenue', 'dc_low_revenue', 'commodity_revenue', 'third_party_revenue', 'third_party_cost', 'commodity_cost'])#
Bases:
CommercialObjective- model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'ignore', 'frozen': False, 'json_encoders': {<class 'datetime.datetime'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timedeltas.Timedelta'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timestamps.Timestamp'>: <function BaseModel.<lambda>>, <class 'pandas.core.frame.DataFrame'>: <function BaseModel.<lambda>>, <class 'pandas.core.series.Series'>: <function BaseModel.<lambda>>}, 'validate_default': True}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class battery_optimizer.uk.request.UKFeatureFlags(*, return_pickled_optimizer=False, perform_check_battery_marketed_is_in_correct_unit=True, da_ds_rounding_method='da_rerun', check_ds_energy_constraints_within_settlement_period=True, account_for_ds_energy_throughput_third_party_cost=False, mel_mil_version=MelMilVersion.v1)#
Bases:
FeatureFlags- Parameters:
return_pickled_optimizer (bool)
perform_check_battery_marketed_is_in_correct_unit (bool)
da_ds_rounding_method (Literal['da_rerun', 'imbalance_rerun'])
check_ds_energy_constraints_within_settlement_period (bool)
account_for_ds_energy_throughput_third_party_cost (bool)
mel_mil_version (MelMilVersion)
- mel_mil_version: MelMilVersion#
- model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'ignore', 'frozen': False, 'json_encoders': {<class 'datetime.datetime'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timedeltas.Timedelta'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timestamps.Timestamp'>: <function BaseModel.<lambda>>, <class 'pandas.core.frame.DataFrame'>: <function BaseModel.<lambda>>, <class 'pandas.core.series.Series'>: <function BaseModel.<lambda>>}, 'validate_default': True}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class battery_optimizer.uk.request.UKMelMilNowRequest(*, request_id, country=Country.UK, user_id, request_creation_time, elastic_filter=False, already_auctioned_as_constants=False, asset, verbose=False, epsilon=1e-06, commercial_objective=UKCommercialObjective(commercial_columns=['revenue_PV', 'dc_high_revenue', 'dc_low_revenue', 'commodity_revenue', 'third_party_revenue', 'third_party_cost', 'commodity_cost']), multiplier_buy_sell_exceed_limit=10.0, upper_bound_risk_increment=None, imbalance=Imbalance(imbalance_cost_per_MWh=1000000.0, min_imbalance_cost_per_MWh=100000.0, imbalance_cost_shaping=True, provide_imbalance_cost_in_result=False), solve_optimization_problem_max_seconds=90.0, intraday_strategy=IntradayStrategy(name=<IntradayStrategyName.vwap: 'vwap'>, delivery_length=<IntradayDeliveryLength.half_hour: 'HalfHour'>, tradeable_time_window_minutes=NaT), intraday_result_aggregation=IntradayResultAggregation(name=<IntradayResultAggregationName.minmax: 'minmax'>, no_buckets=1), objective=UKObjective(name=<ObjectiveName.pnl: 'pnl'>, frozen_window_plus_buffer=Timedelta('0 days 01:30:00'), melmil_optimization_horizon=Timedelta('0 days 01:00:00')), solver_settings=SolverSettings(gapRel=0.01), do_input_for_intraday_bucketing_correct_bucket=True, elastic_soe_constraints=False, global_max_charging_power_kw=None, global_max_discharging_power_kw=None, feature_flags=UKFeatureFlags(return_pickled_optimizer=False, perform_check_battery_marketed_is_in_correct_unit=True, da_ds_rounding_method='da_rerun', check_ds_energy_constraints_within_settlement_period=True, account_for_ds_energy_throughput_third_party_cost=False, mel_mil_version=<MelMilVersion.v1: 'v1'>), use_case=UseCase.BESS, iterative_commodity_and_ds=True, keep_n2ex_constant_hourly=True, default_penalty_for_discharge_during_dc=1000000.0, apply_penalty_for_discharge_during_dc=False, balancing_mechanism=BalancingMechanism(activation_time_minutes=Timedelta('0 days 00:32:00'), activation_ratio=1.0), mel_mil_now_parameters)#
Bases:
UKRequest- Parameters:
request_id (str)
country (Country)
request_creation_time (datetime)
elastic_filter (bool)
already_auctioned_as_constants (bool)
asset (UKAsset)
verbose (bool)
epsilon (float)
commercial_objective (UKCommercialObjective)
multiplier_buy_sell_exceed_limit (Annotated[float, Ge(ge=0.0)])
upper_bound_risk_increment (float | dict | UpperBoundRiskIncrement | None)
imbalance (Imbalance)
solve_optimization_problem_max_seconds (float)
intraday_strategy (IntradayStrategy)
intraday_result_aggregation (IntradayResultAggregation)
objective (UKObjective)
solver_settings (SolverSettings)
do_input_for_intraday_bucketing_correct_bucket (bool)
elastic_soe_constraints (bool)
global_max_charging_power_kw (float | None)
global_max_discharging_power_kw (float | None)
feature_flags (UKFeatureFlags)
use_case (UseCase)
iterative_commodity_and_ds (bool)
keep_n2ex_constant_hourly (bool)
default_penalty_for_discharge_during_dc (float)
apply_penalty_for_discharge_during_dc (bool)
balancing_mechanism (BalancingMechanism | None)
mel_mil_now_parameters (MelMilNowParameters)
- mel_mil_now_parameters: MelMilNowParameters#
- model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'ignore', 'frozen': False, 'json_encoders': {<class 'datetime.datetime'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timedeltas.Timedelta'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timestamps.Timestamp'>: <function BaseModel.<lambda>>, <class 'pandas.core.frame.DataFrame'>: <function BaseModel.<lambda>>, <class 'pandas.core.series.Series'>: <function BaseModel.<lambda>>}, 'validate_default': True}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class battery_optimizer.uk.request.UKObjective(*, name=ObjectiveName.pnl, frozen_window_plus_buffer=Timedelta('0 days 01:30:00'), melmil_optimization_horizon=Timedelta('0 days 01:00:00'))#
Bases:
Objective- Parameters:
name (ObjectiveName)
- model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'ignore', 'frozen': False, 'json_encoders': {<class 'datetime.datetime'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timedeltas.Timedelta'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timestamps.Timestamp'>: <function BaseModel.<lambda>>, <class 'pandas.core.frame.DataFrame'>: <function BaseModel.<lambda>>, <class 'pandas.core.series.Series'>: <function BaseModel.<lambda>>}, 'validate_default': True}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class battery_optimizer.uk.request.UKPriceForecast(*, start, intraday=None, intraday_sell=None, intraday_buy=None, virtual_wholesale=None, virtual_wholesale_sell=None, virtual_wholesale_buy=None, dch=None, dcl=None, dmh=None, dml=None, drh=None, drl=None, n2ex1h=None, n2ex1h_sell=None, n2ex1h_buy=None, epex30min=None, epex30min_sell=None, epex30min_buy=None)#
Bases:
PriceForecast- Parameters:
start (datetime)
intraday (float | None)
intraday_sell (float | None)
intraday_buy (float | None)
virtual_wholesale (float | None)
virtual_wholesale_sell (float | None)
virtual_wholesale_buy (float | None)
dch (float | None)
dcl (float | None)
dmh (float | None)
dml (float | None)
drh (float | None)
drl (float | None)
n2ex1h (float | None)
n2ex1h_sell (float | None)
n2ex1h_buy (float | None)
epex30min (float | None)
epex30min_sell (float | None)
epex30min_buy (float | None)
- model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'ignore', 'frozen': False, 'json_encoders': {<class 'datetime.datetime'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timedeltas.Timedelta'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timestamps.Timestamp'>: <function BaseModel.<lambda>>, <class 'pandas.core.frame.DataFrame'>: <function BaseModel.<lambda>>, <class 'pandas.core.series.Series'>: <function BaseModel.<lambda>>}, 'validate_default': True}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class battery_optimizer.uk.request.UKRampRates(*, type=RampingLogicName.dc_only, charging_perf_related_kw_per_second=None, discharging_perf_related_kw_per_second=None, charging_tech_limited_kw_per_second=None, discharging_tech_limited_kw_per_second=None)#
Bases:
RampRates- Parameters:
type (Literal[RampingLogicName.performance_related, RampingLogicName.dc_only])
charging_perf_related_kw_per_second (Annotated[float | None, Gt(gt=0.0)])
discharging_perf_related_kw_per_second (Annotated[float | None, Gt(gt=0.0)])
charging_tech_limited_kw_per_second (Annotated[float | None, Gt(gt=0.0)])
discharging_tech_limited_kw_per_second (Annotated[float | None, Gt(gt=0.0)])
- model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'ignore', 'frozen': False, 'json_encoders': {<class 'datetime.datetime'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timedeltas.Timedelta'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timestamps.Timestamp'>: <function BaseModel.<lambda>>, <class 'pandas.core.frame.DataFrame'>: <function BaseModel.<lambda>>, <class 'pandas.core.series.Series'>: <function BaseModel.<lambda>>}, 'validate_default': True}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class battery_optimizer.uk.request.UKRequest(*, request_id, country=Country.UK, user_id, request_creation_time, elastic_filter=False, already_auctioned_as_constants=False, asset, verbose=False, epsilon=1e-06, commercial_objective=UKCommercialObjective(commercial_columns=['revenue_PV', 'dc_high_revenue', 'dc_low_revenue', 'commodity_revenue', 'third_party_revenue', 'third_party_cost', 'commodity_cost']), multiplier_buy_sell_exceed_limit=10.0, upper_bound_risk_increment=None, imbalance=Imbalance(imbalance_cost_per_MWh=1000000.0, min_imbalance_cost_per_MWh=100000.0, imbalance_cost_shaping=True, provide_imbalance_cost_in_result=False), solve_optimization_problem_max_seconds=90.0, intraday_strategy=IntradayStrategy(name=<IntradayStrategyName.vwap: 'vwap'>, delivery_length=<IntradayDeliveryLength.half_hour: 'HalfHour'>, tradeable_time_window_minutes=NaT), intraday_result_aggregation=IntradayResultAggregation(name=<IntradayResultAggregationName.minmax: 'minmax'>, no_buckets=1), objective=UKObjective(name=<ObjectiveName.pnl: 'pnl'>, frozen_window_plus_buffer=Timedelta('0 days 01:30:00'), melmil_optimization_horizon=Timedelta('0 days 01:00:00')), solver_settings=SolverSettings(gapRel=0.01), do_input_for_intraday_bucketing_correct_bucket=True, elastic_soe_constraints=False, global_max_charging_power_kw=None, global_max_discharging_power_kw=None, feature_flags=UKFeatureFlags(return_pickled_optimizer=False, perform_check_battery_marketed_is_in_correct_unit=True, da_ds_rounding_method='da_rerun', check_ds_energy_constraints_within_settlement_period=True, account_for_ds_energy_throughput_third_party_cost=False, mel_mil_version=<MelMilVersion.v1: 'v1'>), use_case=UseCase.BESS, iterative_commodity_and_ds=True, keep_n2ex_constant_hourly=True, default_penalty_for_discharge_during_dc=1000000.0, apply_penalty_for_discharge_during_dc=False, balancing_mechanism=BalancingMechanism(activation_time_minutes=Timedelta('0 days 00:32:00'), activation_ratio=1.0))#
Bases:
Request- Parameters:
request_id (str)
country (Country)
request_creation_time (datetime)
elastic_filter (bool)
already_auctioned_as_constants (bool)
asset (UKAsset)
verbose (bool)
epsilon (float)
commercial_objective (UKCommercialObjective)
multiplier_buy_sell_exceed_limit (Annotated[float, Ge(ge=0.0)])
upper_bound_risk_increment (float | dict | UpperBoundRiskIncrement | None)
imbalance (Imbalance)
solve_optimization_problem_max_seconds (float)
intraday_strategy (IntradayStrategy)
intraday_result_aggregation (IntradayResultAggregation)
objective (UKObjective)
solver_settings (SolverSettings)
do_input_for_intraday_bucketing_correct_bucket (bool)
elastic_soe_constraints (bool)
global_max_charging_power_kw (float | None)
global_max_discharging_power_kw (float | None)
feature_flags (UKFeatureFlags)
use_case (UseCase)
iterative_commodity_and_ds (bool)
keep_n2ex_constant_hourly (bool)
default_penalty_for_discharge_during_dc (float)
apply_penalty_for_discharge_during_dc (bool)
balancing_mechanism (BalancingMechanism | None)
- property asset_time_series_input_matches_asset_strategy_optimization_names#
- balancing_mechanism: BalancingMechanism | None#
- property capacity_product_variables#
- property capacity_products#
- commercial_objective: UKCommercialObjective#
- property energy_markets#
- ensure_ds_marketed_respects_soe_management_rules()#
- ensure_initial_dynamic_services_commitments_respect_initial_soe()#
- ensure_time_dependent_prequalified_power()#
Ensure that the prequalified power of every dynamic service is either None, meaning no prequalification limit, or a pd.Series aligned with the optimization time range, so that optimization methods can always call .loc[timestamp] without type guards. Scalar inputs apply to the entire horizon. Records and Series must contain exactly one value for every settlement period; missing timestamps are not filled.
In contrast to the German FCR / aFRR prequalified_power_kW we do NOT default None to the maximal (dis-)charging power: in the UK those time series are already scaled with the battery availabilities, so their minimum would be zero for any availability gap and would silently forbid dynamic services. Availability is therefore handled by the (dis-)charging power limits alone, and unset prequalified power means “not limited by prequalification”.
- feature_flags: UKFeatureFlags#
- get_reserved_power_fraction_simultaneous_ds_both(ds_field_name)#
- initialize_optional_time_series_input()#
- intraday_strategy: IntradayStrategy#
- model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'ignore', 'frozen': False, 'json_encoders': {<class 'datetime.datetime'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timedeltas.Timedelta'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timestamps.Timestamp'>: <function BaseModel.<lambda>>, <class 'pandas.core.frame.DataFrame'>: <function BaseModel.<lambda>>, <class 'pandas.core.series.Series'>: <function BaseModel.<lambda>>}, 'validate_default': True}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- objective: UKObjective#
- property reserved_power_fraction_simultaneous_dc_both#
- property reserved_power_fraction_simultaneous_dm_both#
- property reserved_power_fraction_simultaneous_dr_both#
- warn_about_already_auctioned_ds_volumes_above_prequalified_power()#
Already auctioned dynamic service volumes are fixed in the optimization and hence cannot be limited to a lower prequalified power without rendering the problem infeasible. We only warn about them. Needs to run after “ensure_time_dependent_prequalified_power”.
- class battery_optimizer.uk.request.UKStrategyOptimization(*, frequency_min, horizon, markets={}, optimization_id=None, ds_energy_throughput_buffer=DSEnergyThroughputBuffer(enabled=False, rev_factor=0.06, rev_factor_mdo_mdb=1.0, efficiency_correct=False), dc_parameters, dm_parameters=DMParameters(prequalified_power_high_kw=None, prequalified_power_low_kw=None, delivery_duration_sec=Timedelta('0 days 00:30:00'), baseline_buffer_perc=0.22, delivery_duration_buffer_perc=1.1, min_energy_recovery_perc=0.2), dr_parameters=DRParameters(prequalified_power_high_kw=None, prequalified_power_low_kw=None, delivery_duration_sec=Timedelta('0 days 01:00:00'), baseline_buffer_perc=0.44, delivery_duration_buffer_perc=1.1, min_energy_recovery_perc=0.2), trader_exclusion, perspective)#
Bases:
StrategyOptimization- Parameters:
horizon (OptimizationHorizon)
optimization_id (str | None)
ds_energy_throughput_buffer (DSEnergyThroughputBuffer)
dc_parameters (DCParameters)
dm_parameters (DMParameters)
dr_parameters (DRParameters)
trader_exclusion (list[TraderExclusion] | DataFrame)
perspective (Literal['Customer', 'EON'])
- dc_parameters: DCParameters#
- dm_parameters: DMParameters#
- dr_parameters: DRParameters#
- ds_energy_throughput_buffer: DSEnergyThroughputBuffer#
- ensure_dc_ramp_rate_not_too_steep()#
- horizon_min_max_in_trader_exclusion_timeframe()#
- model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'ignore', 'frozen': False, 'json_encoders': {<class 'datetime.datetime'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timedeltas.Timedelta'>: <function BaseModel.<lambda>>, <class 'pandas._libs.tslibs.timestamps.Timestamp'>: <function BaseModel.<lambda>>, <class 'pandas.core.frame.DataFrame'>: <function BaseModel.<lambda>>, <class 'pandas.core.series.Series'>: <function BaseModel.<lambda>>}, 'validate_default': True}#
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- trader_exclusion: list[TraderExclusion] | DataFrame#