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

Import relevant packages for the model calculation
1import warnings
2import math
3from eelib.utils import cos_phi_fix

Class definition

Short explanation, listing of all model parameters with their allowed values for initialization (+ method to return these).
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__()

takes parameter values as inputs
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):
creates entity of this model by setting the properties and initializing attributes
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

Type-specific function like calculation of power limits, aging, efficiency, adaption of stored energy etc.
 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).

For handling of the processes of the model (its calculation) within a time step
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     """
At first: Always handling of a new time step (if entity was called for first time, do some processes once, like adapting energy). This is needed for storages etc., but may not be needed for other model types.
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()
Call model-specific methods in supposed order
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?
  1. Add the part of code to the model

  2. Write proper comments and documentation (docstrings for every method!)

  3. 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 …
  1. … added to the META of the simulator.

  2. If they are also input data, add them to the model_data of the test scenarios (examples/data/model_data_scenario) as well as the VALID_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!

New models need to be integrated …
  1. … into the test scenario scripts (in the SIM_CONFIG).

  2. … into the model_data of the test scenarios (examples/data/model_data_scenario).

  3. … 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 the simulation_helper functions connect_entities() and connect_entities_of_two_model_types().

  4. … into the simulator META data.

  5. … with a unit test file that checks all the relevant model functionalities.