The battery storage formulation: the shared battery model (see storage), injecting discharge minus charge into the power balance, with its degradation cost in the profit.
The variables, constraints and objective terms are written out on the Batteries formulation page.
classBatteryStorageFormulation(VariableFormulation[StorageVariables]):"""Battery storage: the shared battery model, injecting its net discharge into the bus."""dimension=BATTERY_STORAGEentity_type=BatteryStoragenet_power_name:ClassVar[str]=f"{BATTERY_STORAGE}_net_power"soc_name:ClassVar[str]=f"{BATTERY_STORAGE}_soc"charge_mode_name:ClassVar[str]=f"{BATTERY_STORAGE}_charge_mode"def__init__(self,storages:Sequence[BatteryStorage],context:ModelContext)->None:"""Initialize with the battery storages of the system. Args: storages: The battery storages, at least one. context: The shared indexing of the problem. """super().__init__(storages,context)battery=vectorize(BatteryArrays,[storage.batteryforstorageinstorages],self.coordinates)states=battery_storage_state_arrays(storages,self.coordinates,context)self.storage=StorageFormulation(self.coordinates,battery,states,context)@classmethoddefbuild(cls,inputs:FormulationInputs)->Self|None:"""Return the formulation of the battery storages, or None if there are none."""storages=inputs.of_type(BatteryStorage)returncls(storages,inputs.context)ifstorageselseNonedef_create_variables(self,model:linopy.Model)->StorageVariables:"""Add the battery variables of every battery storage."""returnself.storage.create_variables(model)@constraintdef_get_battery_storage_max_charge_constraint(self)->ModelConstraint:"""Charging power is limited by `max_charge_power`, and only in charging mode."""returnself.storage.max_charge_constraint(self.variables)@constraintdef_get_battery_storage_max_discharge_constraint(self)->ModelConstraint:"""Discharging power is limited by `max_discharge_power`, and only outside charging mode."""returnself.storage.max_discharge_constraint(self.variables)@constraintdef_get_battery_storage_soc_dynamics_constraint(self)->ModelConstraint:"""SOC follows self-discharge, charging and discharging from step to step."""returnself.storage.soc_dynamics_constraint(self.variables)@constraintdef_get_battery_storage_soc_start_constraint(self)->ModelConstraint:"""The SOC after the first step starts from the storage's initial state of charge."""returnself.storage.soc_start_constraint(self.variables)@constraintdef_get_battery_storage_soc_end_constraint(self)->list[ModelConstraint]:"""The SOC at the last step equals the storage's final state of charge, where set."""returnself.storage.soc_end_constraint(self.variables)@constraintdef_get_battery_storage_soc_min_constraint(self)->ModelConstraint:"""The SOC never falls below `soc_min`."""returnself.storage.soc_min_constraint(self.variables)@constraintdef_get_battery_storage_soc_max_constraint(self)->ModelConstraint:"""The SOC never exceeds `soc_max`."""returnself.storage.soc_max_constraint(self.variables)@constraintdef_get_battery_storage_capacity_constraint(self)->ModelConstraint:"""The SOC never exceeds a full battery."""returnself.storage.capacity_constraint(self.variables)@constraintdef_get_battery_storage_net_power_constraint(self)->ModelConstraint:"""Net power is charging minus discharging power."""returnself.storage.net_power_constraint(self.variables)defpower_injection(self)->linopy.LinearExpression:"""Return discharging minus charging power, summed over the storages."""returnself.storage.power_injection(self.variables)defprofit(self)->linopy.LinearExpression:"""Return minus the degradation cost per scenario."""profit:linopy.LinearExpression=-self.storage.degradation_cost(self.variables)returnprofitdefdispatch(self,solution:xr.Dataset)->BatteryStorageDispatch:"""Return the net power, state of charge and charge mode of the battery storages."""returnBatteryStorageDispatch(self.storage.dispatch_data(solution),BATTERY_STORAGE)
Source code in src/odys/optimization/formulations/battery_storage.py
3132333435363738394041
def__init__(self,storages:Sequence[BatteryStorage],context:ModelContext)->None:"""Initialize with the battery storages of the system. Args: storages: The battery storages, at least one. context: The shared indexing of the problem. """super().__init__(storages,context)battery=vectorize(BatteryArrays,[storage.batteryforstorageinstorages],self.coordinates)states=battery_storage_state_arrays(storages,self.coordinates,context)self.storage=StorageFormulation(self.coordinates,battery,states,context)
Return the formulation of the battery storages, or None if there are none.
Source code in src/odys/optimization/formulations/battery_storage.py
4344454647
@classmethoddefbuild(cls,inputs:FormulationInputs)->Self|None:"""Return the formulation of the battery storages, or None if there are none."""storages=inputs.of_type(BatteryStorage)returncls(storages,inputs.context)ifstorageselseNone
Return the net power, state of charge and charge mode of the battery storages.
Source code in src/odys/optimization/formulations/battery_storage.py
107108109
defdispatch(self,solution:xr.Dataset)->BatteryStorageDispatch:"""Return the net power, state of charge and charge mode of the battery storages."""returnBatteryStorageDispatch(self.storage.dispatch_data(solution),BATTERY_STORAGE)
Return discharging minus charging power, summed over the storages.
Source code in src/odys/optimization/formulations/battery_storage.py
98 99100
defpower_injection(self)->linopy.LinearExpression:"""Return discharging minus charging power, summed over the storages."""returnself.storage.power_injection(self.variables)
Source code in src/odys/optimization/formulations/battery_storage.py
102103104105
defprofit(self)->linopy.LinearExpression:"""Return minus the degradation cost per scenario."""profit:linopy.LinearExpression=-self.storage.degradation_cost(self.variables)returnprofit