Skip to content

Commit

Permalink
Merge pull request #46 from manuGil/feature/model-constructor
Browse files Browse the repository at this point in the history
Feature/model constructor
  • Loading branch information
manuGil authored Sep 27, 2024
2 parents 90e44b4 + c6ecffa commit 7a062e9
Show file tree
Hide file tree
Showing 10 changed files with 489 additions and 180 deletions.
105 changes: 0 additions & 105 deletions Models/construct_model.py

This file was deleted.

89 changes: 45 additions & 44 deletions configs/modelling-example.yaml
Original file line number Diff line number Diff line change
@@ -1,55 +1,56 @@
scenario:
name: "ExampleScenario" # in mosaik so called world
scenario_data: 'path/to/file' #path to the scenario data file ()
start_time: '2012-01-02 00:00:00' # ISO 8601 start time of the simulation
end_time: 10 # duration in seconds
models: # list of model for the energy network
end_time: '2012-01-02 00:00:10' # duration in seconds
models: # list of models for the energy network
- name: Battery1 # name for the model (must be unique)
type: BatteryModel # name of the model registered in the Illuminator
inputs: [input1=0]
outputs: [output1=0, output2=None]
parameters: [charge_power_max=100, discharge_power_max=200, soc_min=0.1, soc_max=0.9, capacity=1000]
states: [initial_soc=0.5]
inputs:
input1: 0 # input-name: initial value, default value will be used if not defined
outputs:
output1: 0
output2: null
parameters:
charge_power_max: 100
discharge_power_max: 200
soc_min: 0.1
soc_max: 0.9
capacity: 1000
states:
initial_soc: 0.5
triggers: # list of triggers for the of another model??. It must be an input, output or state of the model
- capacity
- soc_min
scenario_data: 'path/to/file' #path to the scenario data file for the model. This should be optional
- name: Battery2
type: BatteryModel # models can reuse the same type
inputs: [input1=0]
outputs: [output1=0, output2=None]
parameters: [charge_power_max=100, discharge_power_max=200, soc_min=0.1, soc_max=0.9, capacity=5000]
states: [initial_soc=0.5]
inputs:
input1: 0 # input-name: initial value, default value will be used if not defined
outputs:
output1: 0
output2: null
parameters:
charge_power_max: 100
states:
soc: 0.5 # initial value for the state, optional
- name: PV1
type: PVModel
inputs: [input3=0, input4=0]
outputs: [output4=0, output5=None]
parameters: [charge_power_max=100, discharge_power_max=200, soc_min=0.1, soc_max=0.9, capacity=1000]
states: [initial_soc=0.5]
inputs:
input1: 0 # input-name: initial value, default value will be used if not defined
input2: 0
outputs:
output1: 0
parameters:
power_max: 100
states:
initial_soc: 0.5
connections:
- from: Battery1 # start model
to: PV1 # end model
data: !!pairs # a list values to be exchanged between the model. 'pairs' is a YAML keyword
- output1: input3 # output of 'from model': input of 'to model'
- output2: input4
- from: Battery2
to: PV1
data: !!pairs # using the generic 'data' keyword to define what it is exchanged between the nodes
- output1: input3
- output2: input4
- from: Battery1.output2 # start model, pattern: model_name.output_name/input_name
to: PV1.input1 # end model
- from: Battery2.output
to: PV1.input2
monitor: # a list of models, its inputs, output and states to be monitored and logged
- name: Battery1 # name of the model
inputs: [input1]
outputs: [output1, output2] # list of input, output, state names to be monitored
states: [initial_soc]
- name: Battery2
# not all inputs, outputs and states are required, but at least one must be defined
outputs: [output1, output2]
- name: PV1
outputs: [output4, output5]










- Battery1.input1 # pattern model_name.state_name
- Battery2.output1 # no duplicates allowed
- PV1.soc # pattern model_name.state_name
- PV1.output1
61 changes: 35 additions & 26 deletions configs/modelling_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,58 +2,67 @@
A schema for validating a simulation configuration file
in the Illuminaotr.
"""
from typing import Any, Dict
from schema import Schema, And, Use, Regex, Optional, SchemaError
import datetime

# format: YYYY-MM-DD HH:MM:SS"
valid_start_time = r'^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$'


class ScenarioSchema(Schema):
"""
A schema for validating the scenario section of the simulation configuration file.
"""
def validate(self, data, _is_scenario_schema=True): # _is_scenario_schema is a flag to limit validation of the scenario schema
data = super(ScenarioSchema, self).validate(data, _is_scenario_schema=False)

if _is_scenario_schema and data.get("start_time", None) and data.get("end_time", None):
# convert strings to datetime objects
start_time_ = datetime.datetime.strptime(data["start_time"], "%Y-%m-%d %H:%M:%S")
end_time_ = datetime.datetime.strptime(data["end_time"], "%Y-%m-%d %H:%M:%S")
if start_time_ >= end_time_:
raise SchemaError("End time cannot be less than or equal to the start time.")
return data

# Define the schema for the simulation configuration file
schema = Schema( # a mapping of mappings
{
"scenario": Schema(
"scenario": ScenarioSchema(
{
"name": And(str, len),
"scenario_data": And(str, len),
"start_time": Regex(valid_start_time, error="Invalid start time format. Must be in the format: YYYY-MM-DDTHH:MM:SS"),
"end_time": And(Use(int), lambda n: n > 0),
"start_time": Regex(valid_start_time, error="Invalid start_time format. Must be in the format: YYYY-MM-DDTHH:MM:SS"),
"end_time": Regex(valid_start_time, error="Invalid end_time format. Must be in the format: YYYY-MM-DDTHH:MM:SS"),
}
),
"models": Schema( # a sequence of mappings
[ {
"name": And(str, len),
"type": And(str, len),
"inputs": And(list, lambda l: all(isinstance(x, str) for x in l)),
"outputs": And(list, lambda l: all(isinstance(x, str) for x in l)),
"parameters": And(list, lambda l: all(isinstance(x, str) for x in l)),
"states": And(list, lambda l: all(isinstance(x, str) for x in l)),
"inputs": And(dict, len, error="if 'inputs' is used, it must contain at least one key-value pair"),
"outputs": And(dict, len, error="if 'outputs' is used, it must contain at least one key-value pair"),
Optional("parameters"): And(dict, len, error="if 'parameters' is used, it must contain at least one key-value pair"),
Optional("states"): And(dict, len, error="if 'states' is used, it must contain at least one key-value pair"),
Optional("triggers"): And(list, len, error="if 'trigger' is used, it must contain at least one key-value pair"),
Optional("scenario_data"): And(str, len, error="you must provide a scenario data file if using 'scenario_data'"),
} ]
),
"connections": Schema( # a sequence of mappings
[{
"from": And(str, len),
"to": And(str, len),
"data": And(list, lambda l: all(And(isinstance(x, tuple), len(x) == 2 ) for x in l)),
}]
),
"monitor": Schema( # a sequence of mappings
[{
"name": And(str, len),
Optional("inputs"): And(list, lambda l: all(And(isinstance(x, str)) for x in l)),
Optional("outputs"): And(list, lambda l: all(And(isinstance(x, str)) for x in l)),
Optional("states"): And(list, lambda l: all(And(isinstance(x, str)) for x in l)),
}]
)
"monitor": And(list, len, error="you must provide an item to monitor"),
}
)


# validades monitor contains at least one set of inputs, outputs, or states
def at_least_one_set(d):
return any(d.get(key) for key in ["inputs", "outputs", "states"])
# TODO: Write a more rubust validator for the monitor section
# Any input, output, or state declared in the monitor section must be declared in the models section

# TODO: Write a more rubust validator for connections section
# Any input, output, or state declared in the connection section must be declared in the models section

def validate_monitor(data):
for item in data.get("monitor", []):
print(item)
if not at_least_one_set(item):
raise SchemaError("At least one of 'inputs', 'outputs', or 'states' must be set in each monitor item.")
return True
# TODO: Write a validator for the scenario data file. It should check that the fiel exists
# TODO: write a validator for triggers. It should check that the trigger is a valid input, output, or state.
8 changes: 3 additions & 5 deletions configs/parser.py → configs/validate_yaml.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
from ruamel.yaml import YAML
import sys
import json
from modelling_schema import schema, validate_monitor
from modelling_schema import schema

# this if a yaml file complies with the modelling schema

_file = open('./configs/modelling-example.yaml', 'r')

yaml = YAML(typ='safe')
data = yaml.load(_file)

# yaml.dump(data, sys.stdout)

val = schema.validate(data)
validate_monitor(data)
print(val)

json_data = json.dumps(data, indent=4)
print(json_data)
Expand Down
Empty file.
Loading

0 comments on commit 7a062e9

Please sign in to comment.