Configuration of a Simulator
This page explains the structure of a simulator.py
to enable you to create your own simulators.
The simulator.py
stores information about the connected models and mediates between them and
mosaik (e.g. passing the order to step()
as well as associated values).
As there may be multiple instances of a model connected to a single simulator, you only need one
simulator of a type per scenario, set within the SIM_CONFIG
of scenario file.
A simulator.py
is always paired with a model.py.
Note
All code-blocks derive from charging_station_simulator.py
as of (01/24)
if not stated otherwise.
Introduction and imports
1"""
2Mosaik interface for the eELib charging station model.
3Simulator for communication between orchestrator (mosaik) and charging station entities.
4
5Author: elenia@TUBS
6"""
7
8import mosaik_api_v3
9from eelib.core.devices.charging_station import charging_station_model
10import eelib.utils.validation as vld
11from copy import deepcopy
Listing of model META
17META = {
18 "type": "hybrid",
19 "models": {
20 "ChargingStation": {
21 "public": True,
22 "params": ["init_vals"],
23 "attrs": [
24 "type",
25 "output_type",
26 "step_size",
27 "time",
28 ...
46 "trigger": [
47 "p_set",
48 "e_bat",
49 "e_bat_max",
50 "p_charge_max",
51 "p_discharge_max",
52 "appearance",
53 "appearance_end_step",
54 "bev_consumption_period",
55 ], # input attributes
56 "non-persistent": [
57 "p_min",
58 "p_max",
59 "appearance_end_step",
60 "p_device",
61 "p",
62 "discharge_efficiency",
63 "charge_efficiency",
64 "e_bat",
65 "e_bat_max",
66 ], # output attributes
Initialization of simulator class
72class Sim(mosaik_api_v3.Simulator):
73 """Simulator class for eELib charging station model.
74
75 Args:
76 mosaik_api_v3 (module): defines communication between mosaik and simulator
77
78 Raises:
79 ValueError: Unknown output attribute, when not described in META of simulator
80 """
81
82 def __init__(self):
83 """Constructs an object of the Charging-Station:Sim class."""
84
85 super(Sim, self).__init__(META)
86
87 # storing of event-based output info (for same-time loop or next time step)
88 self.output_cache = {}
89
90 # initiate empty dict for model entities
91 self.entities = {}
92
93 def init(self, sid, scenario_config, time_resolution=1.0):
94 """Initializes parameters for an object of the Charging-Station:Sim class.
95
96 Args:
97 sid (str): Id of the created instance of the simulator (e.g. CSSim-0)
98 scenario_config (dict): scenario configuration data, like resolution or step size
99 time_resolution (float): Time resolution of current scenario.
100
101 Returns:
102 meta: description of the simulator
103 """
104
105 # assign properties
106 self.sid = sid
107 self.scenario_config = scenario_config
108
109 return self.meta
Following are the so called core functions
create()
,
step()
and get_data()
that are
found in every simulator.py
.
Caution
All core functions of the simulators are called by mosaik and should not be deleted!
Creation of model entities in create()
111 def create(self, num, model_type, init_vals):
112 """Creates entities of the eELib charging station model.
113 Core function of mosaik.
114
115 Args:
116 num (int): Number of cs models to be created
117 model_type (str): type of created instance (e.g. "charging_station")
118 init_vals (list): list with initial values for each charging_station entity
119
120 Returns:
121 dict: created entities
122 """
124# generated next unused ID for entity
125next_eid = len(self.entities)
126
127# create empty list for created entities
128entities_orchestrator = []
129
130for i in range(next_eid, next_eid + num):
131 # create entity by specified name and ID
132 ename = "%s%s%d" % (model_type, "_", i)
133 full_id = self.sid + "." + ename
134
135 # get class of specific model and create entity with init values after validation
136 entity_cls = getattr(charging_station_model, model_type)
137 vld.validate_init_parameters(entity_cls, init_vals[i])
138 entity = entity_cls(
139 ename,
140 **init_vals[i],
141 step_size=self.scenario_config["step_size"],
142 )
144 # add info to the simulators entity-list and current entities
145 self.entities[ename] = {
146 "ename": ename,
147 "etype": model_type,
148 "model": entity,
149 "full_id": full_id,
150 }
151 entities_orchestrator.append({"eid": ename, "type": model_type})
152
153return entities_orchestrator
Stepping of models in step()
The step()
method of storage_simulator.py
(01/24).
175# assign property values for each entity and attribute with entity ID
176# process input signals: for the entities (eid), attr is a dict for attributes to be set
177for eid, attrs in inputs.items():
178 # for the attributes (attr), setter is a dict for entities with corresponding set values
179 for attr, setter in attrs.items():
180 # for transmitter (eid_setter), value_dict contains set values (with ids, when dict)
181 setting_value_dict = deepcopy(getattr(self.entities[eid]["model"], attr))
182 for eid_setter, value_dict in setter.items():
183 if isinstance(value_dict, dict):
184 # go by each id and search for corresponding entity id
185 for getter_id, value in value_dict.items():
186 if eid in getter_id:
187 setting_value_dict[eid_setter] = value
188 # value_dict is not a dict, only a single value -> write directly
189 elif isinstance(value_dict, (float, int)):
190 setting_value_dict[eid_setter] = value_dict
191 else:
192 raise TypeError("Unknown format for value_dict")
193 setattr(self.entities[eid]["model"], attr, setting_value_dict)
194
195 # check if there is more than one power set value - otherwise directly set it
196 if attr == "p_set":
197 if len(setting_value_dict) > 1:
198 raise ValueError("There is more than one power set value for " + eid)
200# call step function for each entity in the list
201for ename, entity_dict in self.entities.items():
202 entity_dict["model"].step(time)
Note
You might return
the next timestep for when this model should be called again.
Handling of output data in get_data()
233for transmitter_ename, attrs in outputs.items():
234 # get name for current entity and create dict field
235 entry = self.entities[transmitter_ename]
236 if transmitter_ename not in self.output_cache:
237 self.output_cache[transmitter_ename] = {}
238
239 # loop over all targeted attributes and check if info is available
240 for attr in attrs:
241 if attr not in self.meta["models"][type(entry["model"]).__name__]["attrs"]:
242 raise ValueError("Unknown output attribute: %s" % attr)
243
244 # create empty field for cache and output data
245 if attr not in self.output_cache[transmitter_ename]:
246 self.output_cache[transmitter_ename][attr] = {}
247
248 output_data_to_save = getattr(entry["model"], attr)
291# check if nothing is to be send out - send output 1 step later to avoid waiting for data
292if not flag_output_changed:
293 if self.time == self.scenario_config["n_steps"] - 1: # is last time step?
294 data["time"] = self.time + 1
295 else:
296 data = {"time": self.time}