diff --git a/pywrparser/parsers/pywrjsonparser.py b/pywrparser/parsers/pywrjsonparser.py index 70f4ca1..f881a15 100644 --- a/pywrparser/parsers/pywrjsonparser.py +++ b/pywrparser/parsers/pywrjsonparser.py @@ -11,6 +11,7 @@ PywrTimestepper, PywrMetadata, PywrScenario, + PywrScenarioCombination, PywrTable, PywrNode, PywrEdge, @@ -54,6 +55,7 @@ def __init__(self, json_src, ruleset=None): self.parameters = {} self.recorders = {} self.scenarios = [] + self.scenario_combinations = [] self.tables = {} @@ -147,9 +149,15 @@ def parse(self, raise_on_error=False, raise_on_warning=False, for scenario in self.src.get("scenarios", []): with component_exc_capture("scenarios") as cc: scen = PywrScenario(scenario) - cc.capture_warnings(self.scen) + cc.capture_warnings(scen) self.scenarios.append(scen) + for combination in self.src.get("scenario_combinations", []): + with component_exc_capture("scenario_combinations") as cc: + comb = PywrScenarioCombination(combination) + cc.capture_warnings(comb) + self.scenario_combinations.append(comb) + for table_name, table_data in self.src.get("tables", {}).items(): with component_exc_capture("tables") as cc: t = PywrTable(table_name, table_data) diff --git a/pywrparser/rules.py b/pywrparser/rules.py index 9e32a0b..83fb063 100644 --- a/pywrparser/rules.py +++ b/pywrparser/rules.py @@ -53,7 +53,7 @@ def identify_types(module): from pywrparser.types.node import PywrNode from pywrparser.types.timestepper import PywrTimestepper from pywrparser.types.metadata import PywrMetadata - from pywrparser.types.scenario import PywrScenario + from pywrparser.types.scenario import PywrScenario, PywrScenarioCombination from pywrparser.types.table import PywrTable from pywrparser.types.parameter import PywrParameter from pywrparser.types.recorder import PywrRecorder @@ -61,7 +61,8 @@ def identify_types(module): base_types = ( PywrNode, PywrTimestepper, PywrMetadata, PywrScenario, - PywrTable, PywrParameter, PywrRecorder, PywrEdge + PywrTable, PywrParameter, PywrRecorder, PywrEdge, + PywrScenarioCombination ) typemap = {t.__qualname__: t for t in base_types} diff --git a/pywrparser/types/__init__.py b/pywrparser/types/__init__.py index fc3b924..a82193b 100644 --- a/pywrparser/types/__init__.py +++ b/pywrparser/types/__init__.py @@ -5,6 +5,7 @@ PywrTimestepper = rs.typemap["PywrTimestepper"] PywrMetadata = rs.typemap["PywrMetadata"] PywrScenario = rs.typemap["PywrScenario"] +PywrScenarioCombination = rs.typemap["PywrScenarioCombination"] PywrTable = rs.typemap["PywrTable"] PywrParameter = rs.typemap["PywrParameter"] PywrRecorder = rs.typemap["PywrRecorder"] diff --git a/pywrparser/types/network.py b/pywrparser/types/network.py index 90cee73..c66ba01 100644 --- a/pywrparser/types/network.py +++ b/pywrparser/types/network.py @@ -29,6 +29,7 @@ def __init__(self, parser): self.metadata = parser.metadata self.timestepper = parser.timestepper self.scenarios = parser.scenarios + self.scenario_combinations = parser.scenario_combinations self.tables = parser.tables self.nodes = parser.nodes self.edges = parser.edges @@ -159,6 +160,9 @@ def as_dict(self): if len(self.scenarios) > 0: network["scenarios"] = [s.as_dict() for s in self.scenarios] + if len(self.scenario_combinations) > 0: + network["scenario_combinations"] = [s.as_dict() for s in self.scenario_combinations] + if len(self.tables) > 0: network["tables"] = {n: t.as_dict() for n, t in self.tables.items()} diff --git a/pywrparser/types/scenario.py b/pywrparser/types/scenario.py index 068ef93..5973eab 100644 --- a/pywrparser/types/scenario.py +++ b/pywrparser/types/scenario.py @@ -15,3 +15,15 @@ def name(self): def rule_name_required(self): assert isinstance(self.name, str), "Scenario has invalid name" + + + +class PywrScenarioCombination(PywrType): + def __init__(self, data): + self.data = data + + + """ Validation rules """ + + def rule_name_required(self): + assert isinstance(self.data, list), "Scenario combination must be a list of scenario numbers" diff --git a/tests/data/valid_network.json b/tests/data/valid_network.json index 39e203c..d889b25 100644 --- a/tests/data/valid_network.json +++ b/tests/data/valid_network.json @@ -10,6 +10,13 @@ "timestep": "h" }, "scenarios": [ + { + "name": "scenario0", + "size": 1, + "ensemble_names": [ + "scn0" + ] + }, { "name": "scenario1", "size": 1, @@ -18,6 +25,9 @@ ] } ], + "scenario_combinations": [ + [0, 1] + ], "nodes": [ { "name": "Node_1", diff --git a/tests/test_scenarios.py b/tests/test_scenarios.py new file mode 100644 index 0000000..2ee5d3e --- /dev/null +++ b/tests/test_scenarios.py @@ -0,0 +1,26 @@ +import json +import pytest + +from pywrparser.types.network import PywrNetwork +from pywrparser.types.scenario import PywrScenario, PywrScenarioCombination + +def test_scenarios(valid_network_file): + """ + Two scenarios are defined + """ + network, errors, warnings = PywrNetwork.from_file(valid_network_file) + assert network is not None + assert errors is None + assert len(network.scenarios) == 2 + assert isinstance(network.scenarios[0], PywrScenario) + + +def test_scenario_combinations(valid_network_file): + """ + One scenario combination is defined + """ + network, errors, warnings = PywrNetwork.from_file(valid_network_file) + assert network is not None + assert errors is None + assert len(network.scenario_combinations) == 1 + assert isinstance(network.scenario_combinations[0], PywrScenarioCombination)