Configuration of a Model
A model, as explained in the glossary, represents a real process or component in form of code. It follows the general structure of Input - internal calculation - output, which is triggered by its corresponding simulator that needs to be existent for using the model in simulations. The model is just representing the calculation steps and an entity (see the glossary) is the instantiation of a model. So within a scenario it is possible to have multiple entities (like battery storages) for one model type (battery storage model).
This page explains the structure of a _model.py
to enable you to create your own model.
As there can be different implementations of a device type (like storage system), the can be more
than one class within a _model.py
(like a very detailled model and a generic model).
Note
All code-blocks derive from charging_station_model.py
as of (01/24)
if not stated otherwise.
Imports
1import warnings
2import math
3from eelib.utils import cos_phi_fix
Class definition
13class ChargingStation:
14 """Models a charging station for electric vehicles of different types."""
15
16 # Valid values and types for each parameter
17 _VALID_PARAMETERS = {
18 "p_rated": {"types": [float], "values": (0, math.inf)},
19 "output_type": {"types": [str], "values": ["AC", "DC"]},
20 "charge_efficiency": {"types": [float, int], "values": (0, 1)},
21 "discharge_efficiency": {"types": [float, int], "values": (0, 1)},
22 "cos_phi": {"types": [float, int], "values": (0, 1)},
23 }
24
25 @classmethod
26 def get_valid_parameters(cls):
27 """Returns dictionary containing valid parameter types and values.
28
29 Returns:
30 dict: valid parameters for this model
31 """
32 return cls._VALID_PARAMETERS
E.g. the rated power p_rated
of a charging station has to be a floating point value on should be
non-negative. The efficiency
should have a value between zero and one (100%). These values are
used when creating a model in simulations to check for correct values.
Initialization method __init__()
55def __init__(
56 self,
57 ename: str,
58 p_rated: int,
59 output_type: str = "AC",
60 charge_efficiency: float = 0.99,
61 discharge_efficiency: float = 0.99,
62 cos_phi: float = 1.0,
63 step_size=60 * 15, # step size in seconds
64):
78 # Set attributes of init_vals to static properties
79 self.ename = ename
80 self.p_rated = p_rated # rated active power (AC/DC) [W]
81 self.output_type = output_type # source AC/DC [-]
82 self.discharge_efficiency = discharge_efficiency # discharging efficiency [-]
83 self.charge_efficiency = charge_efficiency # charging efficiency [-]
84 self.cos_phi = cos_phi
85
86 # initialize dynamic output properties
87 self.p = 0 # Active Power (after control) [W]
88 self.q = 0 # Reactive Power (after control) [W]
89 self.p_device = {} # active power for every vehicle [W]
90 self.p_min = 0 # Minimal active Power [W]
91 self.p_max = 0 # Maximal active Power [W]
92
93 ...
94
95 # save time step length and current time step
96 self.step_size = step_size
97 self.time = 0
Model methods
99 def _calc_power_limits(self):
100 """Calculate the power limits for the charging station with the input thats coming from the
101 electric vehicles.
102
103 Raises:
104 ValueError: If the power limits of at least one connected ev do not work together.
105 """
106
107 # calculate current efficiency depending on the direction of power flow
108 self._calc_current_efficiency()
109
110 # in case no ev is connected to cs - no active power flexibility
111 self.p_min = 0
112 self.p_max = 0
113 for ev_id, ev_data in self.ev_data.items():
114 # check for each ev if connected - consider their limits, efficiency and nominal power
115 if ev_data.appearance:
116 # check if min. and max. power are correct
117 if ev_data.p_min > ev_data.p_max:
118 raise ValueError(f"Min. and max. power of ev {ev_id} do not comply.")
119 # handle the power limits
120 self.p_min = max(
121 self.p_min + ev_data.p_min / self.efficiency,
122 -self.p_rated,
123 )
124 self.p_max = min(
125 self.p_max + ev_data.p_max / self.efficiency,
126 self.p_rated,
127 )
128
129 ...
step()
method
Within the step()
method, the calculation processes are executed for the model entity.
This example is coming from the storage_model.py
(01/24).
226 def step(self, time):
227 """Performs simulation step of eELib battery model.
228 Calculates all of the Dynamic Properties based on the Input Properties.
229
230 Args:
231 time (int): Current simulation time
232 """
233 # handle current time step
234 if not self.time == time:
235 self.time = time
236
237 # adapt energy content from last time step ( + self-discharge)
238 if self.p >= 0: # charging
239 self.e_bat_step_volume = (
240 self.p * self.charge_efficiency * (self.step_size / 3600)
241 )
242 else: # discharging
243 self.e_bat_step_volume = (
244 self.p / self.discharge_efficiency * (self.step_size / 3600)
245 )
246 self.e_bat += self.e_bat_step_volume
247
248 # Calculate battery cycles
249 self.bat_cycles += abs(self.e_bat_step_volume / self.e_cycle)
250
251 # Calculate battery state of health and aging properties
252 if self.status_aging:
253 self.__calculate_aging_status()
259 # Set active power and energy within limits
260 self.__set_power_within_limit()
261 self.__set_energy_within_limit()
262 self.soc = self.e_bat / self.e_bat_usable
263
264 self.__calc_charging_efficiency()
265
266 self.__calc_power_limits()
Checklist for adding / enhancing a model
What changes?
- adapting current implementation?
Try to make use of the existing properties and methods of the model
- adding new implementation (e.g. new method) or need for new properties?
Add the part of code to the model
Write proper comments and documentation (docstrings for every method!)
Write a corresponding test function!
- New packages have been added?
add them to the
requirements.txt
file
Where to add?
- New model attributes need to be …
… added to the
META
of the simulator.If they are also input data, add them to the
model_data
of the test scenarios (examples/data/model_data_scenario
) as well as theVALID_PARAMETERS
of the model.
- New connections between properties of different models …
- … need to be integrated to the
model_connections/model_connect_config.json
file, simply paste them in the direction of the connection.
- … in case of connections in both direction, the setup of strong (first sent value) and weak (at
beginning only done with default value) connection has to be set in
model_connections/connect_directions_config.json
file. Always use lower-case letters for the model names!
- … need to be integrated to the
- New models need to be integrated …
… into the test scenario scripts (in the
SIM_CONFIG
).… into the
model_data
of the test scenarios (examples/data/model_data_scenario
).… into the
model_connections/model_connect_config.json
file with their connections to/from other models. If the direction of the connection is of importance, there may be a need to adapt thesimulation_helper
functionsconnect_entities()
andconnect_entities_of_two_model_types()
.… into the simulator
META
data.… with a unit test file that checks all the relevant model functionalities.