The electric vehicle formulation: the shared battery model (see storage) with trip energy drawn while driving, plus the driving and departure-SOC constraints. Vehicles charge and discharge only through chargers (see charging).
Electric vehicles: the shared battery model with trip energy drawn from the battery while driving.
A vehicle cannot charge or discharge while driving and must reach its departure SOC
before each trip. It charges and discharges only through a charger (ChargingFormulation).
Source code in src/odys/optimization/formulations/electric_vehicle.py
classElectricVehicleFormulation(VariableFormulation[StorageVariables]):"""Electric vehicles: the shared battery model with trip energy drawn from the battery while driving. A vehicle cannot charge or discharge while driving and must reach its departure SOC before each trip. It charges and discharges only through a charger (`ChargingFormulation`). """dimension=EVentity_type=ElectricVehiclepower_in_name:ClassVar[str]=f"{EV}_power_in"net_power_name:ClassVar[str]=f"{EV}_net_power"soc_name:ClassVar[str]=f"{EV}_soc"charge_mode_name:ClassVar[str]=f"{EV}_charge_mode"def__init__(self,electric_vehicles:Sequence[ElectricVehicle],context:ModelContext)->None:"""Initialize with the electric vehicles of the system. Args: electric_vehicles: The electric vehicles, at least one. context: The shared indexing of the problem. """super().__init__(electric_vehicles,context)arrays=electric_vehicle_arrays(electric_vehicles,self.coordinates,context)self.trips:ElectricVehicleTripArrays=arrays.tripsself.storage=StorageFormulation(self.coordinates,arrays.battery,arrays.states,context,soc_drop=arrays.trips.trip_energy/arrays.battery.capacity,)@classmethoddefbuild(cls,inputs:FormulationInputs)->Self|None:"""Return the formulation of the electric vehicles, or None if there are none."""electric_vehicles=inputs.of_type(ElectricVehicle)returncls(electric_vehicles,inputs.context)ifelectric_vehicleselseNonedef_create_variables(self,model:linopy.Model)->StorageVariables:"""Add the battery variables of every electric vehicle."""returnself.storage.create_variables(model)@constraintdef_get_ev_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_ev_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_ev_soc_dynamics_constraint(self)->ModelConstraint:"""SOC follows self-discharge, charging, discharging and trip energy from step to step."""returnself.storage.soc_dynamics_constraint(self.variables)@constraintdef_get_ev_soc_start_constraint(self)->ModelConstraint:"""The SOC after the first step starts from the initial state of charge, less a trip departing at t=0."""returnself.storage.soc_start_constraint(self.variables)@constraintdef_get_ev_soc_end_constraint(self)->list[ModelConstraint]:"""The SOC at the last step equals the vehicle's final state of charge, where set."""returnself.storage.soc_end_constraint(self.variables)@constraintdef_get_ev_soc_min_constraint(self)->ModelConstraint:"""The SOC never falls below `soc_min`."""returnself.storage.soc_min_constraint(self.variables)@constraintdef_get_ev_soc_max_constraint(self)->ModelConstraint:"""The SOC never exceeds `soc_max`."""returnself.storage.soc_max_constraint(self.variables)@constraintdef_get_ev_capacity_constraint(self)->ModelConstraint:"""The SOC never exceeds a full battery."""returnself.storage.capacity_constraint(self.variables)@constraintdef_get_ev_driving_constraint(self)->ModelConstraint:"""A vehicle cannot charge or discharge while driving."""battery=self.storage.batterymax_power=battery.max_charge_power+battery.max_discharge_powerreturnModelConstraint(constraint=self.variables.power_in+self.variables.power_out<=max_power*(1-self.trips.is_driving),name="ev_driving_constraint",)@constraintdef_get_ev_min_soc_departure_constraint(self)->ModelConstraint:"""A vehicle reaches its departure SOC by the end of the step before the trip."""min_soc_before_departure=self.trips.min_soc_at_departure.shift({ModelDimension.Time:-1},fill_value=0)returnModelConstraint(constraint=self.variables.soc>=min_soc_before_departure,name="ev_min_soc_departure_constraint",)@constraintdef_get_ev_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 (V2G minus charging), summed over the vehicles."""returnself.storage.power_injection(self.variables)defprofit(self)->linopy.LinearExpression:"""Return minus the battery degradation cost per scenario."""profit:linopy.LinearExpression=-self.storage.degradation_cost(self.variables)returnprofitdefdispatch(self,solution:xr.Dataset)->ElectricVehicleDispatch:"""Return the net power, state of charge and charge mode of the electric vehicles."""returnElectricVehicleDispatch(self.storage.dispatch_data(solution),EV)
Source code in src/odys/optimization/formulations/electric_vehicle.py
3637383940414243444546474849505152
def__init__(self,electric_vehicles:Sequence[ElectricVehicle],context:ModelContext)->None:"""Initialize with the electric vehicles of the system. Args: electric_vehicles: The electric vehicles, at least one. context: The shared indexing of the problem. """super().__init__(electric_vehicles,context)arrays=electric_vehicle_arrays(electric_vehicles,self.coordinates,context)self.trips:ElectricVehicleTripArrays=arrays.tripsself.storage=StorageFormulation(self.coordinates,arrays.battery,arrays.states,context,soc_drop=arrays.trips.trip_energy/arrays.battery.capacity,)
Return the formulation of the electric vehicles, or None if there are none.
Source code in src/odys/optimization/formulations/electric_vehicle.py
5455565758
@classmethoddefbuild(cls,inputs:FormulationInputs)->Self|None:"""Return the formulation of the electric vehicles, or None if there are none."""electric_vehicles=inputs.of_type(ElectricVehicle)returncls(electric_vehicles,inputs.context)ifelectric_vehicleselseNone
Return the net power, state of charge and charge mode of the electric vehicles.
Source code in src/odys/optimization/formulations/electric_vehicle.py
137138139
defdispatch(self,solution:xr.Dataset)->ElectricVehicleDispatch:"""Return the net power, state of charge and charge mode of the electric vehicles."""returnElectricVehicleDispatch(self.storage.dispatch_data(solution),EV)
Return discharging minus charging power (V2G minus charging), summed over the vehicles.
Source code in src/odys/optimization/formulations/electric_vehicle.py
128129130
defpower_injection(self)->linopy.LinearExpression:"""Return discharging minus charging power (V2G minus charging), summed over the vehicles."""returnself.storage.power_injection(self.variables)
Return minus the battery degradation cost per scenario.
Source code in src/odys/optimization/formulations/electric_vehicle.py
132133134135
defprofit(self)->linopy.LinearExpression:"""Return minus the battery degradation cost per scenario."""profit:linopy.LinearExpression=-self.storage.degradation_cost(self.variables)returnprofit