diff --git a/docs/source/conf.py b/docs/source/conf.py index 596f453..e912ee9 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -13,16 +13,16 @@ import os import sys -sys.path.insert(0, os.path.abspath('../..')) +sys.path.insert(0, os.path.abspath("../..")) import hadar # -- Project information ----------------------------------------------------- -master_doc = 'index' -project = 'hadar-simulator' -copyright = 'Except where otherwise noted, this content is Copyright (c) 2020, RTE (https://www.rte-france.com) and licensed under a CC-BY-4.0 (https://creativecommons.org/licenses/by/4.0/) license.' -author = 'RTE' +master_doc = "index" +project = "hadar-simulator" +copyright = "Except where otherwise noted, this content is Copyright (c) 2020, RTE (https://www.rte-france.com) and licensed under a CC-BY-4.0 (https://creativecommons.org/licenses/by/4.0/) license." +author = "RTE" # The full version, including alpha/beta/rc tags release = hadar.__version__ @@ -34,19 +34,19 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'sphinx.ext.autodoc', - 'nbsphinx', - 'IPython.sphinxext.ipython_console_highlighting', - 'sphinx.ext.mathjax', + "sphinx.ext.autodoc", + "nbsphinx", + "IPython.sphinxext.ipython_console_highlighting", + "sphinx.ext.mathjax", ] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ['_build', '**.ipynb_checkpoints'] +exclude_patterns = ["_build", "**.ipynb_checkpoints"] # -- Options for HTML output ------------------------------------------------- @@ -54,12 +54,12 @@ # The theme to use for HTML and HTML Help pages. See the reference for # a list of builtin themes. # -html_theme = 'pydata_sphinx_theme' +html_theme = "pydata_sphinx_theme" html_logo = "_static/logo.png" # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] -nbsphinx_execute = 'never' +nbsphinx_execute = "never" diff --git a/examples/utils.py b/examples/utils.py index 132cc6d..64b21da 100644 --- a/examples/utils.py +++ b/examples/utils.py @@ -15,7 +15,7 @@ from nbconvert.preprocessors import ExecutePreprocessor exporter = RSTExporter() -ep = ExecutePreprocessor(timeout=600, kernel_name='python3', store_widget_state=True) +ep = ExecutePreprocessor(timeout=600, kernel_name="python3", store_widget_state=True) def open_nb(name: str, src: str) -> nbformat: @@ -26,9 +26,11 @@ def open_nb(name: str, src: str) -> nbformat: :param src: source directory :return: notebook object """ - print('Reading...', end=' ') - nb = nbformat.read('{src}/{name}/{name}.ipynb'.format(name=name, src=src), as_version=4) - print('OK', end=' ') + print("Reading...", end=" ") + nb = nbformat.read( + "{src}/{name}/{name}.ipynb".format(name=name, src=src), as_version=4 + ) + print("OK", end=" ") return nb @@ -41,9 +43,9 @@ def execute(nb: nbformat, name: str, src: str) -> nbformat: :param src: notebook source directory (for setup context) :return: notebook object with computed and stored output widget state """ - print('Executing...', end=' ') - ep.preprocess(nb, {'metadata': {'path': '%s/%s/' % (src, name)}}) - print('OK', end=' ') + print("Executing...", end=" ") + ep.preprocess(nb, {"metadata": {"path": "%s/%s/" % (src, name)}}) + print("OK", end=" ") return nb @@ -56,11 +58,11 @@ def copy_image(name: str, export: str, src: str): :param src: source directory :return: None """ - src = '%s/%s' % (src, name) - dest = '%s/%s' % (export, name) - images = [f for f in os.listdir(src) if f.split('.')[-1] in ['png']] + src = "%s/%s" % (src, name) + dest = "%s/%s" % (export, name) + images = [f for f in os.listdir(src) if f.split(".")[-1] in ["png"]] for img in images: - os.rename('%s/%s' % (src, img), '%s/%s' % (dest, img)) + os.rename("%s/%s" % (src, img), "%s/%s" % (dest, img)) def to_export(nb: nbformat, name: str, export: str): @@ -72,17 +74,17 @@ def to_export(nb: nbformat, name: str, export: str): :param export: directory to export :return: None """ - print('Exporting...', end=' ') + print("Exporting...", end=" ") rst, _ = exporter.from_notebook_node(nb) - path = '%s/%s' % (export, name) + path = "%s/%s" % (export, name) if not os.path.exists(path): os.makedirs(path) - with open('%s/%s.rst' % (path, name), 'w') as f: + with open("%s/%s.rst" % (path, name), "w") as f: f.write(rst) - print('OK', end=' ') + print("OK", end=" ") def list_notebook(src: str) -> List[str]: @@ -92,16 +94,20 @@ def list_notebook(src: str) -> List[str]: :return: """ dirs = os.listdir(src) - return [d for d in dirs if os.path.isfile('{src}/{name}/{name}.ipynb'.format(name=d, src=src))] + return [ + d + for d in dirs + if os.path.isfile("{src}/{name}/{name}.ipynb".format(name=d, src=src)) + ] -@click.command('Check and export notebooks') -@click.option('--src', nargs=1, help='Notebook directory') -@click.option('--check', nargs=1, help='check notebook according to result file given') -@click.option('--export', nargs=1, help='export notebooks to directory given') +@click.command("Check and export notebooks") +@click.option("--src", nargs=1, help="Notebook directory") +@click.option("--check", nargs=1, help="check notebook according to result file given") +@click.option("--export", nargs=1, help="export notebooks to directory given") def main(src: str, check: str, export: str): for name in list_notebook(src): - print('{:30}'.format(name), ':', end='') + print("{:30}".format(name), ":", end="") nb = open_nb(name, src) nb = execute(nb, name, src) if check: @@ -109,8 +115,8 @@ def main(src: str, check: str, export: str): if export: to_export(nb, name, export) copy_image(name, export, src) - print('') + print("") -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/setup.py b/setup.py index f82a515..fa74102 100644 --- a/setup.py +++ b/setup.py @@ -4,8 +4,8 @@ with open("README.md", "r") as fh: long_description = fh.read() -with open('requirements.txt', 'r') as f: - dependencies = f.read().split('\n') +with open("requirements.txt", "r") as f: + dependencies = f.read().split("\n") setuptools.setup( name="hadar", @@ -23,5 +23,5 @@ "License :: OSI Approved :: Apache Software License", "Operating System :: OS Independent", ], - python_requires='>=3.6', -) \ No newline at end of file + python_requires=">=3.6", +) diff --git a/tests/__init__.py b/tests/__init__.py index 84711aa..f76a769 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -4,4 +4,3 @@ # If a copy of the Apache License, version 2.0 was not distributed with this file, you can obtain one at http://www.apache.org/licenses/LICENSE-2.0. # SPDX-License-Identifier: Apache-2.0 # This file is part of hadar-simulator, a python adequacy library for everyone. - diff --git a/tests/analyzer/__init__.py b/tests/analyzer/__init__.py index 84711aa..f76a769 100644 --- a/tests/analyzer/__init__.py +++ b/tests/analyzer/__init__.py @@ -4,4 +4,3 @@ # If a copy of the Apache License, version 2.0 was not distributed with this file, you can obtain one at http://www.apache.org/licenses/LICENSE-2.0. # SPDX-License-Identifier: Apache-2.0 # This file is part of hadar-simulator, a python adequacy library for everyone. - diff --git a/tests/analyzer/test_result.py b/tests/analyzer/test_result.py index 9843afb..9155b33 100644 --- a/tests/analyzer/test_result.py +++ b/tests/analyzer/test_result.py @@ -13,78 +13,157 @@ from hadar import LPOptimizer from hadar.analyzer.result import Index, ResultAnalyzer, IntIndex from hadar.optimizer.domain.input import Study -from hadar.optimizer.domain.output import OutputConsumption, OutputLink, OutputNode, OutputProduction, Result, OutputNetwork, \ - OutputStorage, OutputConverter +from hadar.optimizer.domain.output import ( + OutputConsumption, + OutputLink, + OutputNode, + OutputProduction, + Result, + OutputNetwork, + OutputStorage, + OutputConverter, +) class TestIndex(unittest.TestCase): - def test_no_parameters(self): - self.assertEqual(True, Index(column='i').all) + self.assertEqual(True, Index(column="i").all) def test_on_element(self): - i = Index(column='i', index='fr') + i = Index(column="i", index="fr") self.assertEqual(False, i.all) - self.assertEqual(('fr',), i.index) + self.assertEqual(("fr",), i.index) def test_list(self): - i = Index(column='i', index=['fr', 'be']) + i = Index(column="i", index=["fr", "be"]) self.assertEqual(False, i.all) - self.assertEqual(('fr', 'be'), i.index) + self.assertEqual(("fr", "be"), i.index) def test_filter(self): - i = Index(column='i', index=['fr', 'be']) - df = pd.DataFrame(data={'i': ['it', 'fr', 'fr', 'be', 'de', 'it', 'be'], - 'a': [0, 1, 2, 3, 4, 5, 6]}) - - exp = pd.Series(data=[False, True, True, True, False, False, True], index=[0, 1, 2, 3, 4, 5, 6], name='i') + i = Index(column="i", index=["fr", "be"]) + df = pd.DataFrame( + data={ + "i": ["it", "fr", "fr", "be", "de", "it", "be"], + "a": [0, 1, 2, 3, 4, 5, 6], + } + ) + + exp = pd.Series( + data=[False, True, True, True, False, False, True], + index=[0, 1, 2, 3, 4, 5, 6], + name="i", + ) pd.testing.assert_series_equal(exp, i.filter(df)) class TestIntIndex(unittest.TestCase): - def test_range(self): - i = IntIndex('i', index=slice(2, 6)) + i = IntIndex("i", index=slice(2, 6)) self.assertEqual(False, i.all) self.assertEqual((2, 3, 4, 5), i.index) def test_list(self): - i = IntIndex('i', index=[2, 6]) + i = IntIndex("i", index=[2, 6]) self.assertEqual(False, i.all) self.assertEqual((2, 6), i.index) class TestConsumptionAnalyzer(unittest.TestCase): def setUp(self) -> None: - self.study = Study(horizon=3, nb_scn=2)\ - .network()\ - .node('a')\ - .consumption(cost=10 ** 3, quantity=[[120, 12, 12], [12, 120, 120]], name='load')\ - .consumption(cost=10 ** 3, quantity=[[130, 13, 13], [13, 130, 130]], name='car')\ - .node('b')\ - .consumption(cost=10 ** 3, quantity=[[120, 12, 12], [12, 120, 120]], name='load')\ + self.study = ( + Study(horizon=3, nb_scn=2) + .network() + .node("a") + .consumption( + cost=10 ** 3, quantity=[[120, 12, 12], [12, 120, 120]], name="load" + ) + .consumption( + cost=10 ** 3, quantity=[[130, 13, 13], [13, 130, 130]], name="car" + ) + .node("b") + .consumption( + cost=10 ** 3, quantity=[[120, 12, 12], [12, 120, 120]], name="load" + ) .build() + ) out = { - 'a': OutputNode(consumptions=[OutputConsumption(quantity=[[20, 2, 2], [2, 20, 20]], name='load'), - OutputConsumption(quantity=[[30, 3, 3], [3, 30, 30]], name='car')], - productions=[], storages=[], links=[]), - 'b': OutputNode(consumptions=[OutputConsumption(quantity=[[20, 2, 2], [2, 20, 20]], name='load')], - productions=[], storages=[], links=[]) + "a": OutputNode( + consumptions=[ + OutputConsumption(quantity=[[20, 2, 2], [2, 20, 20]], name="load"), + OutputConsumption(quantity=[[30, 3, 3], [3, 30, 30]], name="car"), + ], + productions=[], + storages=[], + links=[], + ), + "b": OutputNode( + consumptions=[ + OutputConsumption(quantity=[[20, 2, 2], [2, 20, 20]], name="load") + ], + productions=[], + storages=[], + links=[], + ), } - self.result = Result(networks={'default': OutputNetwork(nodes=out)}, converters={}) + self.result = Result( + networks={"default": OutputNetwork(nodes=out)}, converters={} + ) def test_build_consumption(self): # Expected - exp = pd.DataFrame(data={'cost': [10 ** 3] * 18, - 'asked': [120, 12, 12, 12, 120, 120, 130, 13, 13, 13, 130, 130, 120, 12, 12, 12, 120, 120], - 'given': [20, 2, 2, 2, 20, 20, 30, 3, 3, 3, 30, 30, 20, 2, 2, 2, 20, 20], - 'name': ['load'] * 6 + ['car'] * 6 + ['load'] * 6, - 'node': ['a'] * 12 + ['b'] * 6, - 'network': ['default'] * 18, - 't': [0, 1, 2] * 6, - 'scn': [0, 0, 0, 1, 1, 1] * 3}, dtype=float) + exp = pd.DataFrame( + data={ + "cost": [10 ** 3] * 18, + "asked": [ + 120, + 12, + 12, + 12, + 120, + 120, + 130, + 13, + 13, + 13, + 130, + 130, + 120, + 12, + 12, + 12, + 120, + 120, + ], + "given": [ + 20, + 2, + 2, + 2, + 20, + 20, + 30, + 3, + 3, + 3, + 30, + 30, + 20, + 2, + 2, + 2, + 20, + 20, + ], + "name": ["load"] * 6 + ["car"] * 6 + ["load"] * 6, + "node": ["a"] * 12 + ["b"] * 6, + "network": ["default"] * 18, + "t": [0, 1, 2] * 6, + "scn": [0, 0, 0, 1, 1, 1] * 3, + }, + dtype=float, + ) cons = ResultAnalyzer._build_consumption(self.study, self.result) @@ -92,55 +171,100 @@ def test_build_consumption(self): def test_aggregate_cons(self): # Expected - index = pd.Index(data=[0, 1, 2], dtype=float, name='t') - exp_cons = pd.DataFrame(data={'asked': [120, 12, 12], - 'cost': [10 ** 3] * 3, - 'given': [20, 2, 2]}, dtype=float, index=index) + index = pd.Index(data=[0, 1, 2], dtype=float, name="t") + exp_cons = pd.DataFrame( + data={"asked": [120, 12, 12], "cost": [10 ** 3] * 3, "given": [20, 2, 2]}, + dtype=float, + index=index, + ) # Test agg = ResultAnalyzer(study=self.study, result=self.result) - cons = agg.network().scn(0).node('a').consumption('load').time() + cons = agg.network().scn(0).node("a").consumption("load").time() pd.testing.assert_frame_equal(exp_cons, cons) def test_get_elements_inside(self): agg = ResultAnalyzer(study=self.study, result=self.result) - np.testing.assert_array_equal((2, 0, 0, 0, 0, 0), agg.get_elements_inside('a')) - np.testing.assert_array_equal((1, 0, 0, 0, 0, 0), agg.get_elements_inside('b')) + np.testing.assert_array_equal((2, 0, 0, 0, 0, 0), agg.get_elements_inside("a")) + np.testing.assert_array_equal((1, 0, 0, 0, 0, 0), agg.get_elements_inside("b")) class TestProductionAnalyzer(unittest.TestCase): def setUp(self) -> None: - self.study = Study(horizon=3, nb_scn=2)\ - .network()\ - .node('a')\ - .production(cost=10, quantity=[[130, 13, 13], [13, 130, 130]], name='prod')\ - .node('b')\ - .production(cost=20, quantity=[[110, 11, 11], [11, 110, 110]], name='prod')\ - .production(cost=20, quantity=[[120, 12, 12], [12, 120, 120]], name='nuclear') \ + self.study = ( + Study(horizon=3, nb_scn=2) + .network() + .node("a") + .production(cost=10, quantity=[[130, 13, 13], [13, 130, 130]], name="prod") + .node("b") + .production(cost=20, quantity=[[110, 11, 11], [11, 110, 110]], name="prod") + .production( + cost=20, quantity=[[120, 12, 12], [12, 120, 120]], name="nuclear" + ) .build() + ) out = { - 'a': OutputNode(productions=[OutputProduction(quantity=[[30, 3, 3], [3, 30, 30]], name='prod')], - consumptions=[], storages=[], links=[]), - - 'b': OutputNode(productions=[OutputProduction(quantity=[[10, 1, 1], [1, 10, 10]], name='prod'), - OutputProduction(quantity=[[20, 2, 2], [2, 20, 20]], name='nuclear')], - consumptions=[], storages=[], links=[]) + "a": OutputNode( + productions=[ + OutputProduction(quantity=[[30, 3, 3], [3, 30, 30]], name="prod") + ], + consumptions=[], + storages=[], + links=[], + ), + "b": OutputNode( + productions=[ + OutputProduction(quantity=[[10, 1, 1], [1, 10, 10]], name="prod"), + OutputProduction( + quantity=[[20, 2, 2], [2, 20, 20]], name="nuclear" + ), + ], + consumptions=[], + storages=[], + links=[], + ), } - self.result = Result(networks={'default': OutputNetwork(nodes=out)}, converters={}) + self.result = Result( + networks={"default": OutputNetwork(nodes=out)}, converters={} + ) def test_build_production(self): # Expected - exp = pd.DataFrame(data={'cost': [10] * 6 + [20] * 12, - 'avail': [130, 13, 13, 13, 130, 130, 110, 11, 11, 11, 110, 110, 120, 12, 12, 12, 120, 120], - 'used': [30, 3, 3, 3, 30, 30, 10, 1, 1, 1, 10, 10, 20, 2, 2, 2, 20, 20], - 'name': ['prod'] * 12 + ['nuclear'] * 6, - 'node': ['a'] * 6 + ['b'] * 12, - 'network': ['default'] * 18, - 't': [0, 1, 2] * 6, - 'scn': [0, 0, 0, 1, 1, 1] * 3}, dtype=float) + exp = pd.DataFrame( + data={ + "cost": [10] * 6 + [20] * 12, + "avail": [ + 130, + 13, + 13, + 13, + 130, + 130, + 110, + 11, + 11, + 11, + 110, + 110, + 120, + 12, + 12, + 12, + 120, + 120, + ], + "used": [30, 3, 3, 3, 30, 30, 10, 1, 1, 1, 10, 10, 20, 2, 2, 2, 20, 20], + "name": ["prod"] * 12 + ["nuclear"] * 6, + "node": ["a"] * 6 + ["b"] * 12, + "network": ["default"] * 18, + "t": [0, 1, 2] * 6, + "scn": [0, 0, 0, 1, 1, 1] * 3, + }, + dtype=float, + ) prod = ResultAnalyzer._build_production(self.study, self.result) @@ -148,118 +272,172 @@ def test_build_production(self): def test_aggregate_prod(self): # Expected - index = pd.MultiIndex.from_tuples((('a', 'prod', 0.0), ('a', 'prod', 1.0), ('a', 'prod', 2,0), - ('b', 'prod', 0.0), ('b', 'prod', 1.0), ('b', 'prod', 2,0)), - names=['node', 'name', 't'], ) - exp_cons = pd.DataFrame(data={'avail': [130, 13, 13, 110, 11, 11], - 'cost': [10, 10, 10, 20, 20, 20], - 'used': [30, 3, 3, 10, 1, 1]}, dtype=float, index=index) + index = pd.MultiIndex.from_tuples( + ( + ("a", "prod", 0.0), + ("a", "prod", 1.0), + ("a", "prod", 2, 0), + ("b", "prod", 0.0), + ("b", "prod", 1.0), + ("b", "prod", 2, 0), + ), + names=["node", "name", "t"], + ) + exp_cons = pd.DataFrame( + data={ + "avail": [130, 13, 13, 110, 11, 11], + "cost": [10, 10, 10, 20, 20, 20], + "used": [30, 3, 3, 10, 1, 1], + }, + dtype=float, + index=index, + ) # Test agg = ResultAnalyzer(study=self.study, result=self.result) - cons = agg.network().scn(0).node(['a', 'b']).production('prod').time() + cons = agg.network().scn(0).node(["a", "b"]).production("prod").time() pd.testing.assert_frame_equal(exp_cons, cons) def test_get_elements_inside(self): agg = ResultAnalyzer(study=self.study, result=self.result) - np.testing.assert_array_equal((0, 1, 0, 0, 0, 0), agg.get_elements_inside('a')) - np.testing.assert_array_equal((0, 2, 0, 0, 0, 0), agg.get_elements_inside('b')) + np.testing.assert_array_equal((0, 1, 0, 0, 0, 0), agg.get_elements_inside("a")) + np.testing.assert_array_equal((0, 2, 0, 0, 0, 0), agg.get_elements_inside("b")) class TestStorageAnalyzer(unittest.TestCase): def setUp(self) -> None: - self.study = Study(horizon=3, nb_scn=2)\ - .network()\ - .node('b')\ - .storage(name='store', capacity=100, flow_in=10, flow_out=20, cost=1) \ + self.study = ( + Study(horizon=3, nb_scn=2) + .network() + .node("b") + .storage(name="store", capacity=100, flow_in=10, flow_out=20, cost=1) .build() + ) out = { - 'b': OutputNode(storages=[OutputStorage(name='store', capacity=[[10, 1, 1], [1, 10, 10]], - flow_out=[[20, 2, 2], [2, 20, 20]], - flow_in=[[30, 3, 3], [3, 30, 30]])], - consumptions=[], productions=[], links=[]) + "b": OutputNode( + storages=[ + OutputStorage( + name="store", + capacity=[[10, 1, 1], [1, 10, 10]], + flow_out=[[20, 2, 2], [2, 20, 20]], + flow_in=[[30, 3, 3], [3, 30, 30]], + ) + ], + consumptions=[], + productions=[], + links=[], + ) } - self.result = Result(networks={'default': OutputNetwork(nodes=out)}, converters={}) + self.result = Result( + networks={"default": OutputNetwork(nodes=out)}, converters={} + ) def test_build_storage(self): # Expected - exp = pd.DataFrame(data={'max_capacity': [100] * 6, - 'capacity': [10, 1, 1, 1, 10, 10], - 'max_flow_in': [10] * 6, - 'flow_in': [30, 3, 3, 3, 30, 30], - 'max_flow_out': [20] * 6, - 'flow_out': [20, 2, 2, 2, 20, 20], - 'cost': [1] * 6, - 'init_capacity': [0] * 6, - 'eff': [.99] * 6, - 'name': ['store'] * 6, - 'node': ['b'] * 6, - 'network': ['default'] * 6, - 't': [0, 1, 2] * 2, - 'scn': [0, 0, 0, 1, 1, 1]}, dtype=float) + exp = pd.DataFrame( + data={ + "max_capacity": [100] * 6, + "capacity": [10, 1, 1, 1, 10, 10], + "max_flow_in": [10] * 6, + "flow_in": [30, 3, 3, 3, 30, 30], + "max_flow_out": [20] * 6, + "flow_out": [20, 2, 2, 2, 20, 20], + "cost": [1] * 6, + "init_capacity": [0] * 6, + "eff": [0.99] * 6, + "name": ["store"] * 6, + "node": ["b"] * 6, + "network": ["default"] * 6, + "t": [0, 1, 2] * 2, + "scn": [0, 0, 0, 1, 1, 1], + }, + dtype=float, + ) stor = ResultAnalyzer._build_storage(self.study, self.result) pd.testing.assert_frame_equal(exp, stor, check_dtype=False) def test_aggregate_stor(self): # Expected - index = pd.MultiIndex.from_tuples((('b', 'store', 0), ('b', 'store', 1), ('b', 'store', 2)), - names=['node', 'name', 't'], ) - exp_stor = pd.DataFrame(data={'capacity': [10, 1, 1], - 'cost': [1, 1, 1], - 'eff': [.99] * 3, - 'flow_in': [30, 3, 3], - 'flow_out': [20, 2, 2], - 'init_capacity': [0] * 3, - 'max_capacity': [100] * 3, - 'max_flow_in': [10] * 3, - 'max_flow_out': [20] * 3}, index=index) + index = pd.MultiIndex.from_tuples( + (("b", "store", 0), ("b", "store", 1), ("b", "store", 2)), + names=["node", "name", "t"], + ) + exp_stor = pd.DataFrame( + data={ + "capacity": [10, 1, 1], + "cost": [1, 1, 1], + "eff": [0.99] * 3, + "flow_in": [30, 3, 3], + "flow_out": [20, 2, 2], + "init_capacity": [0] * 3, + "max_capacity": [100] * 3, + "max_flow_in": [10] * 3, + "max_flow_out": [20] * 3, + }, + index=index, + ) # Test agg = ResultAnalyzer(study=self.study, result=self.result) - stor = agg.network().scn(0).node().storage('store').time() + stor = agg.network().scn(0).node().storage("store").time() pd.testing.assert_frame_equal(exp_stor, stor, check_dtype=False) def test_get_elements_inside(self): agg = ResultAnalyzer(study=self.study, result=self.result) - np.testing.assert_array_equal((0, 0, 1, 0, 0, 0), agg.get_elements_inside('b')) + np.testing.assert_array_equal((0, 0, 1, 0, 0, 0), agg.get_elements_inside("b")) class TestLinkAnalyzer(unittest.TestCase): def setUp(self) -> None: - self.study = Study(horizon=3, nb_scn=2)\ - .network()\ - .node('a')\ - .node('b')\ - .node('c')\ - .link(src='a', dest='b', quantity=[[110, 11, 11], [11, 110, 110]], cost=2)\ - .link(src='a', dest='c', quantity=[[120, 12, 12], [12, 120, 120]], cost=2)\ + self.study = ( + Study(horizon=3, nb_scn=2) + .network() + .node("a") + .node("b") + .node("c") + .link(src="a", dest="b", quantity=[[110, 11, 11], [11, 110, 110]], cost=2) + .link(src="a", dest="c", quantity=[[120, 12, 12], [12, 120, 120]], cost=2) .build() + ) blank_node = OutputNode(consumptions=[], productions=[], storages=[], links=[]) out = { - 'a': OutputNode(consumptions=[], productions=[], storages=[], - links=[OutputLink(dest='b', quantity=[[10, 1, 1], [1, 10, 10]]), - OutputLink(dest='c', quantity=[[20, 2, 2], [2, 20, 20]])]), - - 'b': blank_node, 'c': blank_node + "a": OutputNode( + consumptions=[], + productions=[], + storages=[], + links=[ + OutputLink(dest="b", quantity=[[10, 1, 1], [1, 10, 10]]), + OutputLink(dest="c", quantity=[[20, 2, 2], [2, 20, 20]]), + ], + ), + "b": blank_node, + "c": blank_node, } - self.result = Result(networks={'default': OutputNetwork(nodes=out)}, converters={}) + self.result = Result( + networks={"default": OutputNetwork(nodes=out)}, converters={} + ) def test_build_link(self): # Expected - exp = pd.DataFrame(data={'cost': [2] * 12, - 'avail': [110, 11, 11, 11, 110, 110, 120, 12, 12, 12, 120, 120], - 'used': [10, 1, 1, 1, 10, 10, 20, 2, 2, 2, 20, 20], - 'node': ['a'] * 12, - 'dest': ['b'] * 6 + ['c'] * 6, - 'network': ['default'] * 12, - 't': [0, 1, 2] * 4, - 'scn': [0, 0, 0, 1, 1, 1] * 2}, dtype=float) + exp = pd.DataFrame( + data={ + "cost": [2] * 12, + "avail": [110, 11, 11, 11, 110, 110, 120, 12, 12, 12, 120, 120], + "used": [10, 1, 1, 1, 10, 10, 20, 2, 2, 2, 20, 20], + "node": ["a"] * 12, + "dest": ["b"] * 6 + ["c"] * 6, + "network": ["default"] * 12, + "t": [0, 1, 2] * 4, + "scn": [0, 0, 0, 1, 1, 1] * 2, + }, + dtype=float, + ) link = ResultAnalyzer._build_link(self.study, self.result) @@ -267,55 +445,81 @@ def test_build_link(self): def test_aggregate_link(self): # Expected - index = pd.MultiIndex.from_tuples((('b', 0.0), ('b', 1.0), ('b', 2,0), - ('c', 0.0), ('c', 1.0), ('c', 2,0)), - names=['dest', 't'], ) - exp_link = pd.DataFrame(data={'avail': [110, 11, 11, 120, 12, 12], - 'cost': [2, 2, 2, 2, 2, 2], - 'used': [10, 1, 1, 20, 2, 2]}, dtype=float, index=index) + index = pd.MultiIndex.from_tuples( + (("b", 0.0), ("b", 1.0), ("b", 2, 0), ("c", 0.0), ("c", 1.0), ("c", 2, 0)), + names=["dest", "t"], + ) + exp_link = pd.DataFrame( + data={ + "avail": [110, 11, 11, 120, 12, 12], + "cost": [2, 2, 2, 2, 2, 2], + "used": [10, 1, 1, 20, 2, 2], + }, + dtype=float, + index=index, + ) agg = ResultAnalyzer(study=self.study, result=self.result) - link = agg.network().scn(0).node('a').link(['b', 'c']).time() + link = agg.network().scn(0).node("a").link(["b", "c"]).time() pd.testing.assert_frame_equal(exp_link, link) def test_balance(self): agg = ResultAnalyzer(study=self.study, result=self.result) - np.testing.assert_array_equal([[30, 3, 3], [3, 30, 30]], agg.get_balance(node='a')) - np.testing.assert_array_equal([[-10, -1, -1], [-1, -10, -10]], agg.get_balance(node='b')) + np.testing.assert_array_equal( + [[30, 3, 3], [3, 30, 30]], agg.get_balance(node="a") + ) + np.testing.assert_array_equal( + [[-10, -1, -1], [-1, -10, -10]], agg.get_balance(node="b") + ) def test_get_elements_inside(self): agg = ResultAnalyzer(study=self.study, result=self.result) - np.testing.assert_array_equal((0, 0, 0, 2, 0, 0), agg.get_elements_inside('a')) + np.testing.assert_array_equal((0, 0, 0, 2, 0, 0), agg.get_elements_inside("a")) class TestConverterAnalyzer(unittest.TestCase): def setUp(self) -> None: - self.study = Study(horizon=3, nb_scn=2)\ - .network()\ - .node('a')\ - .to_converter(name='conv', ratio=2)\ - .network('elec').node('a')\ - .converter(name='conv', to_network='elec', to_node='a', max=10, cost=1)\ + self.study = ( + Study(horizon=3, nb_scn=2) + .network() + .node("a") + .to_converter(name="conv", ratio=2) + .network("elec") + .node("a") + .converter(name="conv", to_network="elec", to_node="a", max=10, cost=1) .build() + ) - conv = OutputConverter(name='conv', flow_src={('default', 'a'): [[10, 1, 1], [1, 10, 10]]}, flow_dest=[[20, 2, 2], [2, 20, 20]]) + conv = OutputConverter( + name="conv", + flow_src={("default", "a"): [[10, 1, 1], [1, 10, 10]]}, + flow_dest=[[20, 2, 2], [2, 20, 20]], + ) blank_node = OutputNode(consumptions=[], productions=[], storages=[], links=[]) - self.result = Result(networks={'default': OutputNetwork(nodes={'a': blank_node}), - 'elec': OutputNetwork(nodes={'a': blank_node})}, - converters={'conv': conv}) + self.result = Result( + networks={ + "default": OutputNetwork(nodes={"a": blank_node}), + "elec": OutputNetwork(nodes={"a": blank_node}), + }, + converters={"conv": conv}, + ) def test_build_dest_converter(self): # Expected - exp = pd.DataFrame(data={'name': ['conv'] * 6, - 'network': ['elec'] * 6, - 'node': ['a'] * 6, - 'flow': [20, 2, 2, 2, 20, 20], - 'cost': [1] * 6, - 'max': [10] * 6, - 't': [0, 1, 2] * 2, - 'scn': [0, 0, 0, 1, 1, 1]}) + exp = pd.DataFrame( + data={ + "name": ["conv"] * 6, + "network": ["elec"] * 6, + "node": ["a"] * 6, + "flow": [20, 2, 2, 2, 20, 20], + "cost": [1] * 6, + "max": [10] * 6, + "t": [0, 1, 2] * 2, + "scn": [0, 0, 0, 1, 1, 1], + } + ) conv = ResultAnalyzer._build_dest_converter(self.study, self.result) @@ -323,76 +527,85 @@ def test_build_dest_converter(self): def test_build_src_converter(self): # Expected - exp = pd.DataFrame(data={'name': ['conv'] * 6, - 'network': ['default'] * 6, - 'node': ['a'] * 6, - 'ratio': [2] * 6, - 'flow': [10, 1, 1, 1, 10, 10], - 'max': [5] * 6, - 't': [0, 1, 2] * 2, - 'scn': [0, 0, 0, 1, 1, 1]}) + exp = pd.DataFrame( + data={ + "name": ["conv"] * 6, + "network": ["default"] * 6, + "node": ["a"] * 6, + "ratio": [2] * 6, + "flow": [10, 1, 1, 1, 10, 10], + "max": [5] * 6, + "t": [0, 1, 2] * 2, + "scn": [0, 0, 0, 1, 1, 1], + } + ) conv = ResultAnalyzer._build_src_converter(self.study, self.result) pd.testing.assert_frame_equal(exp, conv, check_dtype=False) - def test_aggregate_to_conv(self): # Expected - exp_conv = pd.DataFrame(data={'flow': [10, 1, 1], - 'max': [5] * 3, - 'ratio': [2] * 3}, index=pd.Index([0, 1, 2], name='t')) + exp_conv = pd.DataFrame( + data={"flow": [10, 1, 1], "max": [5] * 3, "ratio": [2] * 3}, + index=pd.Index([0, 1, 2], name="t"), + ) agg = ResultAnalyzer(study=self.study, result=self.result) - conv = agg.network().scn(0).node('a').to_converter('conv').time() + conv = agg.network().scn(0).node("a").to_converter("conv").time() pd.testing.assert_frame_equal(exp_conv, conv, check_dtype=False) def test_aggregate_from_conv(self): # Expected - exp_conv = pd.DataFrame(data={'cost': [1] * 3, - 'flow': [20, 2, 2], - 'max': [10] * 3}, index=pd.Index([0, 1, 2], name='t')) + exp_conv = pd.DataFrame( + data={"cost": [1] * 3, "flow": [20, 2, 2], "max": [10] * 3}, + index=pd.Index([0, 1, 2], name="t"), + ) agg = ResultAnalyzer(study=self.study, result=self.result) - conv = agg.network('elec').scn(0).node('a').from_converter('conv').time() + conv = agg.network("elec").scn(0).node("a").from_converter("conv").time() pd.testing.assert_frame_equal(exp_conv, conv, check_dtype=False) def test_get_elements_inside(self): agg = ResultAnalyzer(study=self.study, result=self.result) - np.testing.assert_array_equal((0, 0, 0, 0, 1, 0), agg.get_elements_inside('a')) - np.testing.assert_array_equal((0, 0, 0, 0, 0, 1), agg.get_elements_inside('a', network='elec')) + np.testing.assert_array_equal((0, 0, 0, 0, 1, 0), agg.get_elements_inside("a")) + np.testing.assert_array_equal( + (0, 0, 0, 0, 0, 1), agg.get_elements_inside("a", network="elec") + ) class TestAnalyzer(unittest.TestCase): def setUp(self) -> None: - self.study = Study(horizon=1)\ - .network()\ - .node('a')\ - .consumption(cost=10 ** 3, quantity=100, name='car')\ - .production(cost=10, quantity=70, name='prod')\ - .node('b')\ - .production(cost=20, quantity=70, name='nuclear') \ - .storage(name='store', capacity=100, flow_in=10, flow_out=20, cost=-1) \ - .to_converter(name='conv', ratio=2) \ - .link(src='b', dest='a', quantity=110, cost=2)\ - .network('elec')\ - .node('a')\ - .consumption(cost=10 ** 3, quantity=20, name='load')\ - .converter(name='conv', to_network='elec', to_node='a', max=10, cost=1)\ + self.study = ( + Study(horizon=1) + .network() + .node("a") + .consumption(cost=10 ** 3, quantity=100, name="car") + .production(cost=10, quantity=70, name="prod") + .node("b") + .production(cost=20, quantity=70, name="nuclear") + .storage(name="store", capacity=100, flow_in=10, flow_out=20, cost=-1) + .to_converter(name="conv", ratio=2) + .link(src="b", dest="a", quantity=110, cost=2) + .network("elec") + .node("a") + .consumption(cost=10 ** 3, quantity=20, name="load") + .converter(name="conv", to_network="elec", to_node="a", max=10, cost=1) .build() + ) optim = LPOptimizer() self.result = optim.solve(self.study) def test_cost(self): agg = ResultAnalyzer(study=self.study, result=self.result) - np.testing.assert_array_equal(700, agg.get_cost(node='a')) - np.testing.assert_array_equal(760, agg.get_cost(node='b')) - np.testing.assert_array_equal(10010, agg.get_cost(node='a', network='elec')) + np.testing.assert_array_equal(700, agg.get_cost(node="a")) + np.testing.assert_array_equal(760, agg.get_cost(node="b")) + np.testing.assert_array_equal(10010, agg.get_cost(node="a", network="elec")) def test_rac(self): agg = ResultAnalyzer(study=self.study, result=self.result) np.testing.assert_array_equal(35, agg.get_rac()) - np.testing.assert_array_equal(-10, agg.get_rac(network='elec')) + np.testing.assert_array_equal(-10, agg.get_rac(network="elec")) diff --git a/tests/optimizer/__init__.py b/tests/optimizer/__init__.py index 84711aa..f76a769 100644 --- a/tests/optimizer/__init__.py +++ b/tests/optimizer/__init__.py @@ -4,4 +4,3 @@ # If a copy of the Apache License, version 2.0 was not distributed with this file, you can obtain one at http://www.apache.org/licenses/LICENSE-2.0. # SPDX-License-Identifier: Apache-2.0 # This file is part of hadar-simulator, a python adequacy library for everyone. - diff --git a/tests/optimizer/domain/__init__.py b/tests/optimizer/domain/__init__.py index 84711aa..f76a769 100644 --- a/tests/optimizer/domain/__init__.py +++ b/tests/optimizer/domain/__init__.py @@ -4,4 +4,3 @@ # If a copy of the Apache License, version 2.0 was not distributed with this file, you can obtain one at http://www.apache.org/licenses/LICENSE-2.0. # SPDX-License-Identifier: Apache-2.0 # This file is part of hadar-simulator, a python adequacy library for everyone. - diff --git a/tests/optimizer/domain/test_input.py b/tests/optimizer/domain/test_input.py index 6062f78..13022d6 100644 --- a/tests/optimizer/domain/test_input.py +++ b/tests/optimizer/domain/test_input.py @@ -7,188 +7,273 @@ import json import unittest -from hadar.optimizer.domain.input import Study, Consumption, Production, Link, Storage, Converter +from hadar.optimizer.domain.input import ( + Study, + Consumption, + Production, + Link, + Storage, + Converter, +) from hadar.optimizer.domain.numeric import NumericalValueFactory class TestStudy(unittest.TestCase): def setUp(self) -> None: - self.study = Study(horizon=1) \ - .network() \ - .node('a') \ - .consumption(name='load', cost=20, quantity=10) \ - .production(name='nuclear', cost=20, quantity=10) \ - .to_converter(name='converter', ratio=1)\ - .node('b') \ - .link(src='b', dest='a', cost=20, quantity=10) \ - .network('gas')\ - .node('b')\ - .production(name='nuclear', cost=20, quantity=10)\ - .storage(name='store', capacity=100, flow_in=10, flow_out=10, cost=1, init_capacity=4, eff=0.1)\ - .node('a')\ - .consumption(name='load', cost=20, quantity=10)\ - .link(src='b', dest='a', cost=20, quantity=10) \ - .converter(name='converter', to_network='gas', to_node='b', cost=10, max=10) \ + self.study = ( + Study(horizon=1) + .network() + .node("a") + .consumption(name="load", cost=20, quantity=10) + .production(name="nuclear", cost=20, quantity=10) + .to_converter(name="converter", ratio=1) + .node("b") + .link(src="b", dest="a", cost=20, quantity=10) + .network("gas") + .node("b") + .production(name="nuclear", cost=20, quantity=10) + .storage( + name="store", + capacity=100, + flow_in=10, + flow_out=10, + cost=1, + init_capacity=4, + eff=0.1, + ) + .node("a") + .consumption(name="load", cost=20, quantity=10) + .link(src="b", dest="a", cost=20, quantity=10) + .converter(name="converter", to_network="gas", to_node="b", cost=10, max=10) .build() + ) - self.factory = NumericalValueFactory(horizon=self.study.horizon, nb_scn=self.study.nb_scn) + self.factory = NumericalValueFactory( + horizon=self.study.horizon, nb_scn=self.study.nb_scn + ) def test_create_study(self): - c = Consumption(name='load', cost=self.factory.create(20), quantity=self.factory.create(10)) - p = Production(name='nuclear', cost=self.factory.create(20), quantity=self.factory.create(10)) - s = Storage(name='store', capacity=self.factory.create(100), flow_in=self.factory.create(10), - flow_out=self.factory.create(10), cost=self.factory.create(1), init_capacity=4, eff=self.factory.create(0.1)) - l = Link(dest='a', cost=self.factory.create(20), quantity=self.factory.create(10)) - v = Converter(name='converter', src_ratios={('default', 'a'): self.factory.create(1)}, dest_network='gas', - dest_node='b', cost=self.factory.create(10), max=self.factory.create(10)) - - self.assertEqual(c, self.study.networks['default'].nodes['a'].consumptions[0]) - self.assertEqual(p, self.study.networks['default'].nodes['a'].productions[0]) - self.assertEqual(l, self.study.networks['default'].nodes['b'].links[0]) - - self.assertEqual(c, self.study.networks['gas'].nodes['a'].consumptions[0]) - self.assertEqual(p, self.study.networks['gas'].nodes['b'].productions[0]) - self.assertEqual(s, self.study.networks['gas'].nodes['b'].storages[0]) - self.assertEqual(l, self.study.networks['gas'].nodes['b'].links[0]) - - self.assertEqual(v, self.study.converters['converter']) + c = Consumption( + name="load", cost=self.factory.create(20), quantity=self.factory.create(10) + ) + p = Production( + name="nuclear", + cost=self.factory.create(20), + quantity=self.factory.create(10), + ) + s = Storage( + name="store", + capacity=self.factory.create(100), + flow_in=self.factory.create(10), + flow_out=self.factory.create(10), + cost=self.factory.create(1), + init_capacity=4, + eff=self.factory.create(0.1), + ) + l = Link( + dest="a", cost=self.factory.create(20), quantity=self.factory.create(10) + ) + v = Converter( + name="converter", + src_ratios={("default", "a"): self.factory.create(1)}, + dest_network="gas", + dest_node="b", + cost=self.factory.create(10), + max=self.factory.create(10), + ) + + self.assertEqual(c, self.study.networks["default"].nodes["a"].consumptions[0]) + self.assertEqual(p, self.study.networks["default"].nodes["a"].productions[0]) + self.assertEqual(l, self.study.networks["default"].nodes["b"].links[0]) + + self.assertEqual(c, self.study.networks["gas"].nodes["a"].consumptions[0]) + self.assertEqual(p, self.study.networks["gas"].nodes["b"].productions[0]) + self.assertEqual(s, self.study.networks["gas"].nodes["b"].storages[0]) + self.assertEqual(l, self.study.networks["gas"].nodes["b"].links[0]) + + self.assertEqual(v, self.study.converters["converter"]) self.assertEqual(1, self.study.horizon) def test_wrong_production_quantity(self): def test(): - study = Study(horizon=1) \ - .network().node('fr').production(name='solar', cost=1, quantity=-10).build() + study = ( + Study(horizon=1) + .network() + .node("fr") + .production(name="solar", cost=1, quantity=-10) + .build() + ) self.assertRaises(ValueError, test) def test_wrong_production_name(self): def test(): - study = Study(horizon=1) \ - .network()\ - .node('fr')\ - .production(name='solar', cost=1, quantity=-10)\ - .production(name='solar', cost=1, quantity=-10)\ + study = ( + Study(horizon=1) + .network() + .node("fr") + .production(name="solar", cost=1, quantity=-10) + .production(name="solar", cost=1, quantity=-10) .build() + ) self.assertRaises(ValueError, test) def test_wrong_consumption_quantity(self): def test(): - study = Study(horizon=1) \ - .network().node('fr').consumption(name='load', cost=1, quantity=-10).build() + study = ( + Study(horizon=1) + .network() + .node("fr") + .consumption(name="load", cost=1, quantity=-10) + .build() + ) self.assertRaises(ValueError, test) def test_wrong_consumption_name(self): def test(): - study = Study(horizon=1) \ - .network()\ - .node('fr')\ - .consumption(name='load', cost=1, quantity=-10)\ - .consumption(name='load', cost=1, quantity=-10)\ + study = ( + Study(horizon=1) + .network() + .node("fr") + .consumption(name="load", cost=1, quantity=-10) + .consumption(name="load", cost=1, quantity=-10) .build() + ) def test_wrong_storage_flow(self): def test_in(): - study = Study(horizon=1)\ - .network().node('fr')\ - .storage(name='store', capacity=1, flow_in=-1, flow_out=1)\ + study = ( + Study(horizon=1) + .network() + .node("fr") + .storage(name="store", capacity=1, flow_in=-1, flow_out=1) .build() + ) def test_out(): - study = Study(horizon=1)\ - .network().node('fr')\ - .storage(name='store', capacity=1, flow_in=1, flow_out=-1)\ + study = ( + Study(horizon=1) + .network() + .node("fr") + .storage(name="store", capacity=1, flow_in=1, flow_out=-1) .build() + ) + self.assertRaises(ValueError, test_in) self.assertRaises(ValueError, test_out) def test_wrong_storage_capacity(self): def test_capacity(): - study = Study(horizon=1)\ - .network().node('fr')\ - .storage(name='store', capacity=-1, flow_in=1, flow_out=1)\ + study = ( + Study(horizon=1) + .network() + .node("fr") + .storage(name="store", capacity=-1, flow_in=1, flow_out=1) .build() + ) def test_init_capacity(): - study = Study(horizon=1)\ - .network().node('fr')\ - .storage(name='store', capacity=1, flow_in=1, flow_out=1, init_capacity=-1)\ + study = ( + Study(horizon=1) + .network() + .node("fr") + .storage( + name="store", capacity=1, flow_in=1, flow_out=1, init_capacity=-1 + ) .build() + ) + self.assertRaises(ValueError, test_capacity) self.assertRaises(ValueError, test_init_capacity) def test_wrong_storage_eff(self): def test(): - study = Study(horizon=1)\ - .network().node('fr')\ - .storage(name='store', capacity=1, flow_in=1, flow_out=1, eff=-1)\ + study = ( + Study(horizon=1) + .network() + .node("fr") + .storage(name="store", capacity=1, flow_in=1, flow_out=1, eff=-1) .build() + ) self.assertRaises(ValueError, test) def test_wrong_link_quantity(self): def test(): - study = Study(horizon=1) \ - .network()\ - .node('fr')\ - .node('be')\ - .link(src='fr', dest='be', cost=10, quantity=-10)\ + study = ( + Study(horizon=1) + .network() + .node("fr") + .node("be") + .link(src="fr", dest="be", cost=10, quantity=-10) .build() + ) self.assertRaises(ValueError, test) def test_wrong_link_dest_not_node(self): def test(): - study = Study(horizon=1) \ - .network() \ - .node('fr') \ - .node('be') \ - .link(src='fr', dest='it', cost=10, quantity=10) \ + study = ( + Study(horizon=1) + .network() + .node("fr") + .node("be") + .link(src="fr", dest="it", cost=10, quantity=10) .build() + ) self.assertRaises(ValueError, test) def test_wrong_link_dest_not_unique(self): def test(): - study = Study(horizon=1) \ - .network() \ - .node('fr') \ - .node('be') \ - .link(src='fr', dest='be', cost=10, quantity=10) \ - .link(src='fr', dest='be', cost=10, quantity=10) \ + study = ( + Study(horizon=1) + .network() + .node("fr") + .node("be") + .link(src="fr", dest="be", cost=10, quantity=10) + .link(src="fr", dest="be", cost=10, quantity=10) .build() + ) self.assertRaises(ValueError, test) def test_wrong_converter_dest(self): def test_network(): - study = Study(horizon=1)\ - .network('elec')\ - .node('a')\ - .converter(name='conv', to_network='gas', to_node='a', max=1)\ + study = ( + Study(horizon=1) + .network("elec") + .node("a") + .converter(name="conv", to_network="gas", to_node="a", max=1) .build() + ) def test_node(): - study = Study(horizon=1)\ - .network('gas')\ - .node('a')\ - .converter(name='conv', to_network='gas', to_node='b', max=1)\ + study = ( + Study(horizon=1) + .network("gas") + .node("a") + .converter(name="conv", to_network="gas", to_node="b", max=1) .build() + ) self.assertRaises(ValueError, test_network) self.assertRaises(ValueError, test_node) def test_wrong_converter_src(self): def test(): - study = Study(horizon=1)\ - .network()\ - .node('a')\ - .to_converter(name='conv', ratio=1)\ - .to_converter(name='conv', ratio=2)\ - .converter(name='conv', to_node='', to_network='', max=1)\ + study = ( + Study(horizon=1) + .network() + .node("a") + .to_converter(name="conv", ratio=1) + .to_converter(name="conv", ratio=2) + .converter(name="conv", to_node="", to_network="", max=1) .build() + ) self.assertRaises(ValueError, test) @@ -197,4 +282,4 @@ def test_serialization(self): j = json.dumps(d) s = json.loads(j) s = Study.from_json(s) - self.assertEqual(self.study, s) \ No newline at end of file + self.assertEqual(self.study, s) diff --git a/tests/optimizer/domain/test_numeric.py b/tests/optimizer/domain/test_numeric.py index f7c7e45..4160636 100644 --- a/tests/optimizer/domain/test_numeric.py +++ b/tests/optimizer/domain/test_numeric.py @@ -8,7 +8,13 @@ import unittest import numpy as np -from hadar.optimizer.domain.numeric import NumericalValueFactory, ScalarNumericalValue, MatrixNumericalValue, RowNumericValue, ColumnNumericValue +from hadar.optimizer.domain.numeric import ( + NumericalValueFactory, + ScalarNumericalValue, + MatrixNumericalValue, + RowNumericValue, + ColumnNumericValue, +) class TestNumericalValue(unittest.TestCase): @@ -49,4 +55,6 @@ def test_column(self): self.assertEqual(2, v[2, 3]) self.assertRaises(IndexError, lambda: v[3, 1]) self.assertRaises(IndexError, lambda: v[1, 5]) - np.testing.assert_array_equal([0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2], v.flatten()) \ No newline at end of file + np.testing.assert_array_equal( + [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2], v.flatten() + ) diff --git a/tests/optimizer/domain/test_output.py b/tests/optimizer/domain/test_output.py index b93316b..27f8a1b 100644 --- a/tests/optimizer/domain/test_output.py +++ b/tests/optimizer/domain/test_output.py @@ -12,13 +12,35 @@ class TestResult(unittest.TestCase): def test_json(self): - result = Result(networks={'default': OutputNetwork(nodes={'a': OutputNode( - consumptions=[OutputConsumption(name='load', quantity=[[1]])], - productions=[OutputProduction(name='prod', quantity=[[1]])], - links=[OutputLink(dest='b', quantity=[[1]])], - storages=[OutputStorage(name='cell', capacity=[[1]], flow_in=[[1]], flow_out=[[1]])])})}, - converters={'cell': OutputConverter(name='conv', flow_src={('elec', 'b'): [[1]]}, flow_dest=[[1]])}) + result = Result( + networks={ + "default": OutputNetwork( + nodes={ + "a": OutputNode( + consumptions=[ + OutputConsumption(name="load", quantity=[[1]]) + ], + productions=[OutputProduction(name="prod", quantity=[[1]])], + links=[OutputLink(dest="b", quantity=[[1]])], + storages=[ + OutputStorage( + name="cell", + capacity=[[1]], + flow_in=[[1]], + flow_out=[[1]], + ) + ], + ) + } + ) + }, + converters={ + "cell": OutputConverter( + name="conv", flow_src={("elec", "b"): [[1]]}, flow_dest=[[1]] + ) + }, + ) string = json.dumps(result.to_json()) r = Result.from_json(json.loads(string)) - self.assertEqual(result, r) \ No newline at end of file + self.assertEqual(result, r) diff --git a/tests/optimizer/it/__init__.py b/tests/optimizer/it/__init__.py index 84711aa..f76a769 100644 --- a/tests/optimizer/it/__init__.py +++ b/tests/optimizer/it/__init__.py @@ -4,4 +4,3 @@ # If a copy of the Apache License, version 2.0 was not distributed with this file, you can obtain one at http://www.apache.org/licenses/LICENSE-2.0. # SPDX-License-Identifier: Apache-2.0 # This file is part of hadar-simulator, a python adequacy library for everyone. - diff --git a/tests/optimizer/it/test_optimizer.py b/tests/optimizer/it/test_optimizer.py index d68afc5..5d8f79a 100644 --- a/tests/optimizer/it/test_optimizer.py +++ b/tests/optimizer/it/test_optimizer.py @@ -8,12 +8,20 @@ import unittest import hadar as hd -from hadar.optimizer.domain.output import OutputLink, OutputNode, OutputNetwork, OutputProduction, OutputConsumption, OutputStorage, OutputConverter, Result +from hadar.optimizer.domain.output import ( + OutputLink, + OutputNode, + OutputNetwork, + OutputProduction, + OutputConsumption, + OutputStorage, + OutputConverter, + Result, +) from tests.utils import assert_result class TestOptimizer(unittest.TestCase): - def setUp(self) -> None: self.optimizer = hd.LPOptimizer() @@ -35,27 +43,37 @@ def test_merit_order(self): | gas: 5 | :return: """ - study = hd.Study(horizon=3, nb_scn=2)\ - .network()\ - .node('a')\ - .consumption(name='load', cost=10 ** 6, quantity=[[30, 6, 6], [6, 30, 30]])\ - .production(name='nuclear', cost=20, quantity=[[15, 3, 3], [3, 15, 15]])\ - .production(name='solar', cost=10, quantity=[[10, 2, 2], [2, 10, 10]])\ - .production(name='oil', cost=30, quantity=[[10, 2, 2], [2, 10, 10]])\ + study = ( + hd.Study(horizon=3, nb_scn=2) + .network() + .node("a") + .consumption(name="load", cost=10 ** 6, quantity=[[30, 6, 6], [6, 30, 30]]) + .production(name="nuclear", cost=20, quantity=[[15, 3, 3], [3, 15, 15]]) + .production(name="solar", cost=10, quantity=[[10, 2, 2], [2, 10, 10]]) + .production(name="oil", cost=30, quantity=[[10, 2, 2], [2, 10, 10]]) .build() + ) nodes_expected = dict() - nodes_expected['a'] = OutputNode( - consumptions=[OutputConsumption(quantity=[[30, 6, 6], [6, 30, 30]], name='load')], + nodes_expected["a"] = OutputNode( + consumptions=[ + OutputConsumption(quantity=[[30, 6, 6], [6, 30, 30]], name="load") + ], productions=[ - OutputProduction(name='nuclear', quantity=[[15, 3, 3], [3, 15, 15]]), - OutputProduction(name='solar', quantity=[[10, 2, 2], [2, 10, 10]]), - OutputProduction(name='oil', quantity=[[5, 1, 1], [1, 5, 5]])], + OutputProduction(name="nuclear", quantity=[[15, 3, 3], [3, 15, 15]]), + OutputProduction(name="solar", quantity=[[10, 2, 2], [2, 10, 10]]), + OutputProduction(name="oil", quantity=[[5, 1, 1], [1, 5, 5]]), + ], storages=[], - links=[]) + links=[], + ) res = self.optimizer.solve(study) - assert_result(self, Result(networks={'default': OutputNetwork(nodes_expected)}, converters={}), res) + assert_result( + self, + Result(networks={"default": OutputNetwork(nodes_expected)}, converters={}), + res, + ) def test_exchange_two_nodes(self): """ @@ -73,32 +91,40 @@ def test_exchange_two_nodes(self): :return: """ # Input - study = hd.Study(horizon=2)\ - .network()\ - .node('a')\ - .consumption(cost=10 ** 6, quantity=[20, 200], name='load')\ - .production(cost=10, quantity=[30, 300], name='prod')\ - .node('b')\ - .consumption(cost=10 ** 6, quantity=[20, 200], name='load')\ - .production(cost=20, quantity=[10, 100], name='prod')\ - .link(src='a', dest='b', quantity=[10, 100], cost=2)\ + study = ( + hd.Study(horizon=2) + .network() + .node("a") + .consumption(cost=10 ** 6, quantity=[20, 200], name="load") + .production(cost=10, quantity=[30, 300], name="prod") + .node("b") + .consumption(cost=10 ** 6, quantity=[20, 200], name="load") + .production(cost=20, quantity=[10, 100], name="prod") + .link(src="a", dest="b", quantity=[10, 100], cost=2) .build() + ) nodes_expected = {} - nodes_expected['a'] = OutputNode( - consumptions=[OutputConsumption(quantity=[[20, 200]], name='load')], - productions=[OutputProduction(quantity=[[30, 300]], name='prod')], + nodes_expected["a"] = OutputNode( + consumptions=[OutputConsumption(quantity=[[20, 200]], name="load")], + productions=[OutputProduction(quantity=[[30, 300]], name="prod")], storages=[], - links=[OutputLink(dest='b', quantity=[[10, 100]])]) + links=[OutputLink(dest="b", quantity=[[10, 100]])], + ) - nodes_expected['b'] = OutputNode( - consumptions=[OutputConsumption(quantity=[[20, 200]], name='load')], - productions=[OutputProduction(quantity=[[10, 100]], name='prod')], + nodes_expected["b"] = OutputNode( + consumptions=[OutputConsumption(quantity=[[20, 200]], name="load")], + productions=[OutputProduction(quantity=[[10, 100]], name="prod")], storages=[], - links=[]) + links=[], + ) res = self.optimizer.solve(study) - assert_result(self, Result(networks={'default': OutputNetwork(nodes_expected)}, converters={}), res) + assert_result( + self, + Result(networks={"default": OutputNetwork(nodes_expected)}, converters={}), + res, + ) def test_exchange_two_concurrent_nodes(self): """ @@ -121,44 +147,55 @@ def test_exchange_two_concurrent_nodes(self): | nuclear: 0 | :return: """ - study = hd.Study(horizon=1)\ - .network()\ - .node('a')\ - .consumption(cost=10 ** 6, quantity=10, name='load')\ - .production(cost=10, quantity=30, name='nuclear')\ - .node('b')\ - .consumption(cost=10 ** 6, quantity=10, name='load')\ - .production(cost=20, quantity=10, name='nuclear')\ - .node('c')\ - .consumption(cost=10 ** 6, quantity=10, name='load')\ - .production(cost=20, quantity=10, name='nuclear')\ - .link(src='a', dest='b', quantity=20, cost=2)\ - .link(src='a', dest='c', quantity=20, cost=2)\ + study = ( + hd.Study(horizon=1) + .network() + .node("a") + .consumption(cost=10 ** 6, quantity=10, name="load") + .production(cost=10, quantity=30, name="nuclear") + .node("b") + .consumption(cost=10 ** 6, quantity=10, name="load") + .production(cost=20, quantity=10, name="nuclear") + .node("c") + .consumption(cost=10 ** 6, quantity=10, name="load") + .production(cost=20, quantity=10, name="nuclear") + .link(src="a", dest="b", quantity=20, cost=2) + .link(src="a", dest="c", quantity=20, cost=2) .build() + ) nodes_expected = {} - nodes_expected['a'] = OutputNode( - consumptions=[OutputConsumption(quantity=[[10]], name='load')], - productions=[OutputProduction(quantity=[[30]], name='nuclear')], + nodes_expected["a"] = OutputNode( + consumptions=[OutputConsumption(quantity=[[10]], name="load")], + productions=[OutputProduction(quantity=[[30]], name="nuclear")], storages=[], - links=[OutputLink(dest='b', quantity=[[10]]), - OutputLink(dest='c', quantity=[[10]])]) - - nodes_expected['b'] = OutputNode( - consumptions=[OutputConsumption(quantity=[[10]], name='load')], - productions=[OutputProduction(quantity=[[0]], name='nuclear')], + links=[ + OutputLink(dest="b", quantity=[[10]]), + OutputLink(dest="c", quantity=[[10]]), + ], + ) + + nodes_expected["b"] = OutputNode( + consumptions=[OutputConsumption(quantity=[[10]], name="load")], + productions=[OutputProduction(quantity=[[0]], name="nuclear")], storages=[], - links=[]) + links=[], + ) - nodes_expected['c'] = OutputNode( - consumptions=[OutputConsumption(quantity=[[10]], name='load')], - productions=[OutputProduction(quantity=[[0]], name='nuclear')], + nodes_expected["c"] = OutputNode( + consumptions=[OutputConsumption(quantity=[[10]], name="load")], + productions=[OutputProduction(quantity=[[0]], name="nuclear")], storages=[], - links=[]) + links=[], + ) res = self.optimizer.solve(study) - assert_result(self, Result(networks={'default': OutputNetwork(nodes_expected)}, converters={}), res) + assert_result( + self, + Result(networks={"default": OutputNetwork(nodes_expected)}, converters={}), + res, + ) def test_exchange_link_saturation(self): """ @@ -173,35 +210,49 @@ def test_exchange_link_saturation(self): :return: """ - study = hd.Study(horizon=1)\ - .network()\ - .node('a').production(cost=10, quantity=[30], name='nuclear')\ - .node('b').consumption(cost=10 ** 6, quantity=[10], name='load')\ - .node('c').consumption(cost=10 ** 6, quantity=[20], name='load')\ - .link(src='a', dest='b', quantity=[20], cost=2)\ - .link(src='b', dest='c', quantity=[15], cost=2)\ + study = ( + hd.Study(horizon=1) + .network() + .node("a") + .production(cost=10, quantity=[30], name="nuclear") + .node("b") + .consumption(cost=10 ** 6, quantity=[10], name="load") + .node("c") + .consumption(cost=10 ** 6, quantity=[20], name="load") + .link(src="a", dest="b", quantity=[20], cost=2) + .link(src="b", dest="c", quantity=[15], cost=2) .build() + ) nodes_expected = {} - nodes_expected['a'] = OutputNode(productions=[OutputProduction(quantity=[[20]], name='nuclear')], - links=[OutputLink(dest='b', quantity=[[20]])], - storages=[], consumptions=[]) + nodes_expected["a"] = OutputNode( + productions=[OutputProduction(quantity=[[20]], name="nuclear")], + links=[OutputLink(dest="b", quantity=[[20]])], + storages=[], + consumptions=[], + ) - nodes_expected['b'] = OutputNode( - consumptions=[OutputConsumption(quantity=[[10]], name='load')], - links=[OutputLink(dest='c', quantity=[[10]])], + nodes_expected["b"] = OutputNode( + consumptions=[OutputConsumption(quantity=[[10]], name="load")], + links=[OutputLink(dest="c", quantity=[[10]])], storages=[], - productions=[]) + productions=[], + ) - nodes_expected['c'] = OutputNode( - consumptions=[OutputConsumption(quantity=[[10]], name='load')], + nodes_expected["c"] = OutputNode( + consumptions=[OutputConsumption(quantity=[[10]], name="load")], productions=[], storages=[], - links=[]) + links=[], + ) res = self.optimizer.solve(study) - assert_result(self, Result(networks={'default': OutputNetwork(nodes_expected)}, converters={}), res) + assert_result( + self, + Result(networks={"default": OutputNetwork(nodes_expected)}, converters={}), + res, + ) def test_consumer_cancel_exchange(self): """ @@ -219,44 +270,52 @@ def test_consumer_cancel_exchange(self): :return: """ - study = hd.Study(horizon=1)\ - .network()\ - .node('a')\ - .consumption(cost=10 ** 6, quantity=10, name='load')\ - .production(cost=10, quantity=20, name='nuclear')\ - .node('b')\ - .consumption(cost=10 ** 6, quantity=5, name='load')\ - .production(cost=20, quantity=15, name='nuclear')\ - .node('c')\ - .consumption(cost=10 ** 6, quantity=20, name='load')\ - .production(cost=10, quantity=10, name='nuclear')\ - .link(src='a', dest='b', quantity=20, cost=2)\ - .link(src='b', dest='c', quantity=20, cost=2)\ + study = ( + hd.Study(horizon=1) + .network() + .node("a") + .consumption(cost=10 ** 6, quantity=10, name="load") + .production(cost=10, quantity=20, name="nuclear") + .node("b") + .consumption(cost=10 ** 6, quantity=5, name="load") + .production(cost=20, quantity=15, name="nuclear") + .node("c") + .consumption(cost=10 ** 6, quantity=20, name="load") + .production(cost=10, quantity=10, name="nuclear") + .link(src="a", dest="b", quantity=20, cost=2) + .link(src="b", dest="c", quantity=20, cost=2) .build() + ) nodes_expected = {} - nodes_expected['a'] = OutputNode( - consumptions=[OutputConsumption(quantity=[[10]], name='load')], - productions=[OutputProduction(quantity=[[20]], name='nuclear')], + nodes_expected["a"] = OutputNode( + consumptions=[OutputConsumption(quantity=[[10]], name="load")], + productions=[OutputProduction(quantity=[[20]], name="nuclear")], storages=[], - links=[OutputLink(dest='b', quantity=[[10]])]) + links=[OutputLink(dest="b", quantity=[[10]])], + ) - nodes_expected['b'] = OutputNode( - consumptions=[OutputConsumption(quantity=[[5]], name='load')], - productions=[OutputProduction(quantity=[[5]], name='nuclear')], + nodes_expected["b"] = OutputNode( + consumptions=[OutputConsumption(quantity=[[5]], name="load")], + productions=[OutputProduction(quantity=[[5]], name="nuclear")], storages=[], - links=[OutputLink(dest='c', quantity=[[10]])]) + links=[OutputLink(dest="c", quantity=[[10]])], + ) - nodes_expected['c'] = OutputNode( - consumptions=[OutputConsumption(quantity=[[20]], name='load')], - productions=[OutputProduction(quantity=[[10]], name='nuclear')], + nodes_expected["c"] = OutputNode( + consumptions=[OutputConsumption(quantity=[[20]], name="load")], + productions=[OutputProduction(quantity=[[10]], name="nuclear")], storages=[], - links=[]) + links=[], + ) res = self.optimizer.solve(study) - assert_result(self, Result(networks={'default': OutputNetwork(nodes_expected)}, converters={}), res) - + assert_result( + self, + Result(networks={"default": OutputNetwork(nodes_expected)}, converters={}), + res, + ) def test_many_links_on_node(self): """ @@ -285,38 +344,51 @@ def test_many_links_on_node(self): :return: """ - study = hd.Study(horizon=2)\ - .network()\ - .node('a')\ - .consumption(cost=10 ** 6, quantity=10, name='load')\ - .production(cost=80, quantity=20, name='gas')\ - .node('b')\ - .consumption(cost=10 ** 6, quantity=[15, 25], name='load')\ - .node('c')\ - .production(cost=50, quantity=30, name='nuclear')\ - .link(src='a', dest='b', quantity=20, cost=10)\ - .link(src='c', dest='a', quantity=20, cost=10)\ - .link(src='c', dest='b', quantity=15, cost=10)\ + study = ( + hd.Study(horizon=2) + .network() + .node("a") + .consumption(cost=10 ** 6, quantity=10, name="load") + .production(cost=80, quantity=20, name="gas") + .node("b") + .consumption(cost=10 ** 6, quantity=[15, 25], name="load") + .node("c") + .production(cost=50, quantity=30, name="nuclear") + .link(src="a", dest="b", quantity=20, cost=10) + .link(src="c", dest="a", quantity=20, cost=10) + .link(src="c", dest="b", quantity=15, cost=10) .build() - + ) nodes_expected = {} - nodes_expected['a'] = OutputNode( - consumptions=[OutputConsumption(quantity=[[10, 10]], name='load')], - productions=[OutputProduction(quantity=[[0, 5]], name='gas')], - storages=[], links=[OutputLink(dest='b', quantity=[[0, 10]])]) + nodes_expected["a"] = OutputNode( + consumptions=[OutputConsumption(quantity=[[10, 10]], name="load")], + productions=[OutputProduction(quantity=[[0, 5]], name="gas")], + storages=[], + links=[OutputLink(dest="b", quantity=[[0, 10]])], + ) - nodes_expected['b'] = OutputNode( - consumptions=[OutputConsumption(quantity=[[15, 25]], name='load')], - storages=[], productions=[], links=[]) + nodes_expected["b"] = OutputNode( + consumptions=[OutputConsumption(quantity=[[15, 25]], name="load")], + storages=[], + productions=[], + links=[], + ) - nodes_expected['c'] = OutputNode( - productions=[OutputProduction(quantity=[[25, 30]], name='nuclear')], - storages=[], links=[], consumptions=[]) + nodes_expected["c"] = OutputNode( + productions=[OutputProduction(quantity=[[25, 30]], name="nuclear")], + storages=[], + links=[], + consumptions=[], + ) res = self.optimizer.solve(study) - assert_result(self, Result(networks={'default': OutputNetwork(nodes_expected)}, converters={}), res) + assert_result( + self, + Result(networks={"default": OutputNetwork(nodes_expected)}, converters={}), + res, + ) def test_storage(self): """ @@ -327,63 +399,117 @@ def test_storage(self): :return: """ - study = hd.Study(horizon=4)\ - .network()\ - .node('a')\ - .production(name='nuclear', cost=20, quantity=[10, 10, 10, 0]) \ - .node('b')\ - .consumption(name='load', cost=10 ** 6, quantity=[20, 10, 0, 10]) \ - .storage(name='cell', capacity=30, flow_in=20, flow_out=20, - init_capacity=15, eff=.5)\ - .link(src='a', dest='b', cost=1, quantity=10)\ + study = ( + hd.Study(horizon=4) + .network() + .node("a") + .production(name="nuclear", cost=20, quantity=[10, 10, 10, 0]) + .node("b") + .consumption(name="load", cost=10 ** 6, quantity=[20, 10, 0, 10]) + .storage( + name="cell", + capacity=30, + flow_in=20, + flow_out=20, + init_capacity=15, + eff=0.5, + ) + .link(src="a", dest="b", cost=1, quantity=10) .build() + ) nodes_expected = dict() - nodes_expected['a'] = OutputNode( - productions=[OutputProduction(quantity=[[10, 10, 10, 0]], name='nuclear')], - storages=[], consumptions=[], links=[OutputLink(dest='b', quantity=[[10, 10, 10, 0]])]) - - nodes_expected['b'] = OutputNode( - consumptions=[OutputConsumption(quantity=[[20, 10, 0, 10]], name='load')], - storages=[OutputStorage(name='cell', capacity=[[5, 5, 10, 0]], - flow_in=[[0, 0, 10, 0]], flow_out=[[10, 0, 0, 10]])], - productions=[], links=[]) + nodes_expected["a"] = OutputNode( + productions=[OutputProduction(quantity=[[10, 10, 10, 0]], name="nuclear")], + storages=[], + consumptions=[], + links=[OutputLink(dest="b", quantity=[[10, 10, 10, 0]])], + ) + + nodes_expected["b"] = OutputNode( + consumptions=[OutputConsumption(quantity=[[20, 10, 0, 10]], name="load")], + storages=[ + OutputStorage( + name="cell", + capacity=[[5, 5, 10, 0]], + flow_in=[[0, 0, 10, 0]], + flow_out=[[10, 0, 0, 10]], + ) + ], + productions=[], + links=[], + ) res = self.optimizer.solve(study) - assert_result(self, Result(networks={'default': OutputNetwork(nodes_expected)}, converters={}), res) + assert_result( + self, + Result(networks={"default": OutputNetwork(nodes_expected)}, converters={}), + res, + ) def test_multi_energies(self): - study = hd.Study(horizon=1)\ - .network('elec')\ - .node('a')\ - .consumption(name='load', cost=10**6, quantity=10)\ - .network('gas')\ - .node('b')\ - .production(name='central', cost=10, quantity=50)\ - .to_converter(name='conv', ratio=0.8)\ - .network('coat')\ - .node('c')\ - .production(name='central', cost=10, quantity=50)\ - .to_converter(name='conv', ratio=0.5)\ - .converter(name='conv', to_network='elec', to_node='a', max=50)\ + study = ( + hd.Study(horizon=1) + .network("elec") + .node("a") + .consumption(name="load", cost=10 ** 6, quantity=10) + .network("gas") + .node("b") + .production(name="central", cost=10, quantity=50) + .to_converter(name="conv", ratio=0.8) + .network("coat") + .node("c") + .production(name="central", cost=10, quantity=50) + .to_converter(name="conv", ratio=0.5) + .converter(name="conv", to_network="elec", to_node="a", max=50) .build() + ) networks_expected = dict() - networks_expected['elec'] = OutputNetwork(nodes={'a': OutputNode( - consumptions=[OutputConsumption(quantity=[[10]], name='load')], - storages=[], productions=[], links=[])}) - - networks_expected['gas'] = OutputNetwork(nodes={'b': OutputNode( - productions=[OutputProduction(quantity=[[12.5]], name='central')], - storages=[], consumptions=[], links=[])}) - - networks_expected['coat'] = OutputNetwork(nodes={'c': OutputNode( - productions=[OutputProduction(quantity=[[20]], name='central')], - storages=[], consumptions=[], links=[])}) - - converter_expected = OutputConverter(name='conv', flow_src={('gas', 'b'): [[12.5]], ('coat', 'c'): [[20]]}, flow_dest=[[10]]) + networks_expected["elec"] = OutputNetwork( + nodes={ + "a": OutputNode( + consumptions=[OutputConsumption(quantity=[[10]], name="load")], + storages=[], + productions=[], + links=[], + ) + } + ) + + networks_expected["gas"] = OutputNetwork( + nodes={ + "b": OutputNode( + productions=[OutputProduction(quantity=[[12.5]], name="central")], + storages=[], + consumptions=[], + links=[], + ) + } + ) + + networks_expected["coat"] = OutputNetwork( + nodes={ + "c": OutputNode( + productions=[OutputProduction(quantity=[[20]], name="central")], + storages=[], + consumptions=[], + links=[], + ) + } + ) + + converter_expected = OutputConverter( + name="conv", + flow_src={("gas", "b"): [[12.5]], ("coat", "c"): [[20]]}, + flow_dest=[[10]], + ) res = self.optimizer.solve(study) - assert_result(self, Result(networks=networks_expected, converters={'conv': converter_expected}), res) \ No newline at end of file + assert_result( + self, + Result(networks=networks_expected, converters={"conv": converter_expected}), + res, + ) diff --git a/tests/optimizer/lp/__init__.py b/tests/optimizer/lp/__init__.py index 84711aa..f76a769 100644 --- a/tests/optimizer/lp/__init__.py +++ b/tests/optimizer/lp/__init__.py @@ -4,4 +4,3 @@ # If a copy of the Apache License, version 2.0 was not distributed with this file, you can obtain one at http://www.apache.org/licenses/LICENSE-2.0. # SPDX-License-Identifier: Apache-2.0 # This file is part of hadar-simulator, a python adequacy library for everyone. - diff --git a/tests/optimizer/lp/ortools_mock.py b/tests/optimizer/lp/ortools_mock.py index 49198ed..871272a 100644 --- a/tests/optimizer/lp/ortools_mock.py +++ b/tests/optimizer/lp/ortools_mock.py @@ -48,7 +48,7 @@ class MockSolver(Solver): def __init__(self): pass - def NumVar(self, min: float, max: float, name: str = ''): + def NumVar(self, min: float, max: float, name: str = ""): return MockNumVar(min, max, name) def Objective(self) -> MockObjective: @@ -64,4 +64,4 @@ def EnableOutput(self): pass def ExportModelAsLpFormat(self, toggle: bool): - return '' + return "" diff --git a/tests/optimizer/lp/test_mapper.py b/tests/optimizer/lp/test_mapper.py index 3427a25..ae7db85 100644 --- a/tests/optimizer/lp/test_mapper.py +++ b/tests/optimizer/lp/test_mapper.py @@ -8,10 +8,25 @@ import unittest from hadar.optimizer.domain.input import Study -from hadar.optimizer.lp.domain import LPLink, LPConsumption, LPProduction, LPNode, LPStorage, LPConverter +from hadar.optimizer.lp.domain import ( + LPLink, + LPConsumption, + LPProduction, + LPNode, + LPStorage, + LPConverter, +) from hadar.optimizer.lp.mapper import InputMapper, OutputMapper -from hadar.optimizer.domain.output import OutputConsumption, OutputLink, OutputNode, OutputProduction, Result, OutputNetwork, \ - OutputStorage, OutputConverter +from hadar.optimizer.domain.output import ( + OutputConsumption, + OutputLink, + OutputNode, + OutputProduction, + Result, + OutputNetwork, + OutputStorage, + OutputConverter, +) from tests.optimizer.lp.ortools_mock import MockSolver, MockNumVar from tests.utils import assert_result @@ -19,264 +34,531 @@ class TestInputMapper(unittest.TestCase): def test_map_consumption(self): # Input - study = Study(horizon=2, nb_scn=2) \ - .network()\ - .node('a')\ - .consumption(name='load', quantity=[[10, 1], [20, 2]], cost=[[.01, .1], [.02, .2]])\ + study = ( + Study(horizon=2, nb_scn=2) + .network() + .node("a") + .consumption( + name="load", + quantity=[[10, 1], [20, 2]], + cost=[[0.01, 0.1], [0.02, 0.2]], + ) .build() + ) s = MockSolver() mapper = InputMapper(solver=s, study=study) # Expected - suffix = 'inside network=default on node=a at t=0 for scn=0' - out_cons_0 = [LPConsumption(name='load', cost=.01, quantity=10, variable=MockNumVar(0, 10, 'lol=load %s' % suffix))] - out_node_0 = LPNode(consumptions=out_cons_0, productions=[], storages=[], links=[]) - - self.assertEqual(out_node_0, mapper.get_node_var(network='default', node='a', t=0, scn=0)) - - suffix = 'inside network=default on node=a at t=1 for scn=1' - out_cons_1 = [LPConsumption(name='load', cost=.2, quantity=2, variable=MockNumVar(0, 2, 'lol=load %s' % suffix))] - out_node_1 = LPNode(consumptions=out_cons_1, productions=[], storages=[], links=[]) - - self.assertEqual(out_node_1, mapper.get_node_var(network='default', node='a', t=1, scn=1)) + suffix = "inside network=default on node=a at t=0 for scn=0" + out_cons_0 = [ + LPConsumption( + name="load", + cost=0.01, + quantity=10, + variable=MockNumVar(0, 10, "lol=load %s" % suffix), + ) + ] + out_node_0 = LPNode( + consumptions=out_cons_0, productions=[], storages=[], links=[] + ) + + self.assertEqual( + out_node_0, mapper.get_node_var(network="default", node="a", t=0, scn=0) + ) + + suffix = "inside network=default on node=a at t=1 for scn=1" + out_cons_1 = [ + LPConsumption( + name="load", + cost=0.2, + quantity=2, + variable=MockNumVar(0, 2, "lol=load %s" % suffix), + ) + ] + out_node_1 = LPNode( + consumptions=out_cons_1, productions=[], storages=[], links=[] + ) + + self.assertEqual( + out_node_1, mapper.get_node_var(network="default", node="a", t=1, scn=1) + ) def test_map_production(self): # Input - study = Study(horizon=2, nb_scn=2) \ - .network() \ - .node('a') \ - .production(name='nuclear', quantity=[[12, 2], [21, 20]], cost=[[0.12, 0.2], [0.21, 0.02]]) \ + study = ( + Study(horizon=2, nb_scn=2) + .network() + .node("a") + .production( + name="nuclear", + quantity=[[12, 2], [21, 20]], + cost=[[0.12, 0.2], [0.21, 0.02]], + ) .build() + ) s = MockSolver() mapper = InputMapper(solver=s, study=study) # Expected - suffix = 'inside network=default on node=a at t=0 for scn=0' - out_prod_0 = [LPProduction(name='nuclear', cost=0.12, quantity=12, variable=MockNumVar(0, 12.0, 'prod=nuclear %s' % suffix))] - out_node_0 = LPNode(consumptions=[], productions=out_prod_0, storages=[], links=[]) - - self.assertEqual(out_node_0, mapper.get_node_var(network='default', node='a', t=0, scn=0)) - - suffix = 'inside network=default on node=a at t=1 for scn=1' - - out_prod_1 = [LPProduction(name='nuclear', cost=.02, quantity=20, variable=MockNumVar(0, 20.0, 'prod=nuclear %s' % suffix))] - out_node_1 = LPNode(consumptions=[], productions=out_prod_1, storages=[], links=[]) - - self.assertEqual(out_node_1, mapper.get_node_var(network='default', node='a', t=1, scn=1)) + suffix = "inside network=default on node=a at t=0 for scn=0" + out_prod_0 = [ + LPProduction( + name="nuclear", + cost=0.12, + quantity=12, + variable=MockNumVar(0, 12.0, "prod=nuclear %s" % suffix), + ) + ] + out_node_0 = LPNode( + consumptions=[], productions=out_prod_0, storages=[], links=[] + ) + + self.assertEqual( + out_node_0, mapper.get_node_var(network="default", node="a", t=0, scn=0) + ) + + suffix = "inside network=default on node=a at t=1 for scn=1" + + out_prod_1 = [ + LPProduction( + name="nuclear", + cost=0.02, + quantity=20, + variable=MockNumVar(0, 20.0, "prod=nuclear %s" % suffix), + ) + ] + out_node_1 = LPNode( + consumptions=[], productions=out_prod_1, storages=[], links=[] + ) + + self.assertEqual( + out_node_1, mapper.get_node_var(network="default", node="a", t=1, scn=1) + ) def test_map_storage(self): # Input - study = Study(horizon=2, nb_scn=2) \ - .network()\ - .node('a')\ - .storage(name='cell', capacity=10, flow_in=1, flow_out=1, cost=1, init_capacity=2, eff=.9) \ + study = ( + Study(horizon=2, nb_scn=2) + .network() + .node("a") + .storage( + name="cell", + capacity=10, + flow_in=1, + flow_out=1, + cost=1, + init_capacity=2, + eff=0.9, + ) .build() + ) s = MockSolver() mapper = InputMapper(solver=s, study=study) # Expected - suffix = 'inside network=default on node=a at t=0 for scn=0' - out_stor_0 = [LPStorage(name='cell', capacity=10, var_capacity=MockNumVar(0, 10, 'storage_capacity=cell %s' % suffix), - flow_in=1, var_flow_in=MockNumVar(0, 1, 'storage_flow_in=cell %s' % suffix), - flow_out=1, var_flow_out=MockNumVar(0, 1, 'storage_flow_out=cell %s' % suffix), - cost=1, init_capacity=2, eff=.9)] - out_node_0 = LPNode(consumptions=[], productions=[], storages=out_stor_0, links=[]) - - self.assertEqual(out_node_0, mapper.get_node_var(network='default', node='a', t=0, scn=0)) - - suffix = 'inside network=default on node=a at t=1 for scn=1' - out_stor_1 = [LPStorage(name='cell', capacity=10, var_capacity=MockNumVar(0, 10, 'storage_capacity=cell %s' % suffix), - flow_in=1, var_flow_in=MockNumVar(0, 1, 'storage_flow_in=cell %s' % suffix), - flow_out=1, var_flow_out=MockNumVar(0, 1, 'storage_flow_out=cell %s' % suffix), - cost=1, init_capacity=2, eff=.9)] - out_node_1 = LPNode(consumptions=[], productions=[], storages=out_stor_1, links=[]) - - self.assertEqual(out_node_1, mapper.get_node_var(network='default', node='a', t=1, scn=1)) + suffix = "inside network=default on node=a at t=0 for scn=0" + out_stor_0 = [ + LPStorage( + name="cell", + capacity=10, + var_capacity=MockNumVar(0, 10, "storage_capacity=cell %s" % suffix), + flow_in=1, + var_flow_in=MockNumVar(0, 1, "storage_flow_in=cell %s" % suffix), + flow_out=1, + var_flow_out=MockNumVar(0, 1, "storage_flow_out=cell %s" % suffix), + cost=1, + init_capacity=2, + eff=0.9, + ) + ] + out_node_0 = LPNode( + consumptions=[], productions=[], storages=out_stor_0, links=[] + ) + + self.assertEqual( + out_node_0, mapper.get_node_var(network="default", node="a", t=0, scn=0) + ) + + suffix = "inside network=default on node=a at t=1 for scn=1" + out_stor_1 = [ + LPStorage( + name="cell", + capacity=10, + var_capacity=MockNumVar(0, 10, "storage_capacity=cell %s" % suffix), + flow_in=1, + var_flow_in=MockNumVar(0, 1, "storage_flow_in=cell %s" % suffix), + flow_out=1, + var_flow_out=MockNumVar(0, 1, "storage_flow_out=cell %s" % suffix), + cost=1, + init_capacity=2, + eff=0.9, + ) + ] + out_node_1 = LPNode( + consumptions=[], productions=[], storages=out_stor_1, links=[] + ) + + self.assertEqual( + out_node_1, mapper.get_node_var(network="default", node="a", t=1, scn=1) + ) def test_map_links(self): # Input - study = Study(horizon=2, nb_scn=2) \ - .network()\ - .node('a')\ - .node('be')\ - .link(src='a', dest='be', quantity=[[10, 3], [20, 30]], cost=[[.01, .3], [.02, .03]])\ + study = ( + Study(horizon=2, nb_scn=2) + .network() + .node("a") + .node("be") + .link( + src="a", + dest="be", + quantity=[[10, 3], [20, 30]], + cost=[[0.01, 0.3], [0.02, 0.03]], + ) .build() + ) s = MockSolver() mapper = InputMapper(solver=s, study=study) # Expected - suffix = 'inside network=default on node=a at t=0 for scn=0' - out_link_0 = [LPLink(src='a', dest='be', cost=.01, quantity=10, variable=MockNumVar(0, 10.0, 'link=be %s' % suffix))] - out_node_0 = LPNode(consumptions=[], productions=[], storages=[], links=out_link_0) - - self.assertEqual(out_node_0, mapper.get_node_var(network='default', node='a', t=0, scn=0)) - - suffix = 'inside network=default on node=a at t=1 for scn=1' - out_link_1 = [LPLink(src='a', dest='be', cost=.03, quantity=30, variable=MockNumVar(0, 30.0, 'link=be %s' % suffix))] - out_node_1 = LPNode(consumptions=[], productions=[], storages=[],links=out_link_1) - - self.assertEqual(out_node_1, mapper.get_node_var(network='default', node='a', t=1, scn=1)) + suffix = "inside network=default on node=a at t=0 for scn=0" + out_link_0 = [ + LPLink( + src="a", + dest="be", + cost=0.01, + quantity=10, + variable=MockNumVar(0, 10.0, "link=be %s" % suffix), + ) + ] + out_node_0 = LPNode( + consumptions=[], productions=[], storages=[], links=out_link_0 + ) + + self.assertEqual( + out_node_0, mapper.get_node_var(network="default", node="a", t=0, scn=0) + ) + + suffix = "inside network=default on node=a at t=1 for scn=1" + out_link_1 = [ + LPLink( + src="a", + dest="be", + cost=0.03, + quantity=30, + variable=MockNumVar(0, 30.0, "link=be %s" % suffix), + ) + ] + out_node_1 = LPNode( + consumptions=[], productions=[], storages=[], links=out_link_1 + ) + + self.assertEqual( + out_node_1, mapper.get_node_var(network="default", node="a", t=1, scn=1) + ) def test_map_converter(self): # Mock s = MockSolver() # Input - study = Study(horizon=1)\ - .network('gas')\ - .node('a')\ - .to_converter(name='conv', ratio=.5)\ - .network()\ - .node('b')\ - .converter(name='conv', to_network='default', to_node='b', max=100)\ + study = ( + Study(horizon=1) + .network("gas") + .node("a") + .to_converter(name="conv", ratio=0.5) + .network() + .node("b") + .converter(name="conv", to_network="default", to_node="b", max=100) .build() + ) mapper = InputMapper(solver=s, study=study) # Expected - suffix = 'at t=0 for scn=0' - out_conv_0 = LPConverter(name='conv', src_ratios={('gas', 'a'): 0.5}, dest_network='default', dest_node='b', - cost=0, max=100, - var_flow_dest=MockNumVar(0, 100, 'flow_dest conv %s' % suffix), - var_flow_src={('gas', 'a'): MockNumVar(0, 200, 'flow_src conv gas:a %s' % suffix)}) - - self.assertEqual(out_conv_0, mapper.get_conv_var(name='conv', t=0, scn=0)) + suffix = "at t=0 for scn=0" + out_conv_0 = LPConverter( + name="conv", + src_ratios={("gas", "a"): 0.5}, + dest_network="default", + dest_node="b", + cost=0, + max=100, + var_flow_dest=MockNumVar(0, 100, "flow_dest conv %s" % suffix), + var_flow_src={ + ("gas", "a"): MockNumVar(0, 200, "flow_src conv gas:a %s" % suffix) + }, + ) + + self.assertEqual(out_conv_0, mapper.get_conv_var(name="conv", t=0, scn=0)) class TestOutputMapper(unittest.TestCase): def test_map_consumption(self): # Input - study = Study(horizon=2, nb_scn=2) \ - .network()\ - .node('a')\ - .consumption(name='load', quantity=[[10, 1], [20, 2]], cost=[[.01, .1], [.02, .2]])\ + study = ( + Study(horizon=2, nb_scn=2) + .network() + .node("a") + .consumption( + name="load", + quantity=[[10, 1], [20, 2]], + cost=[[0.01, 0.1], [0.02, 0.2]], + ) .build() + ) mapper = OutputMapper(study=study) - out_cons_0 = [LPConsumption(name='load', cost=.01, quantity=10, variable=5)] - mapper.set_node_var(network='default', node='a', t=0, scn=0, - vars=LPNode(consumptions=out_cons_0, productions=[], storages=[], links=[])) - - out_cons_1 = [LPConsumption(name='load', cost=.2, quantity=20, variable=5)] - mapper.set_node_var(network='default', node='a', t=1, scn=1, - vars=LPNode(consumptions=out_cons_1, productions=[], storages=[], links=[])) + out_cons_0 = [LPConsumption(name="load", cost=0.01, quantity=10, variable=5)] + mapper.set_node_var( + network="default", + node="a", + t=0, + scn=0, + vars=LPNode(consumptions=out_cons_0, productions=[], storages=[], links=[]), + ) + + out_cons_1 = [LPConsumption(name="load", cost=0.2, quantity=20, variable=5)] + mapper.set_node_var( + network="default", + node="a", + t=1, + scn=1, + vars=LPNode(consumptions=out_cons_1, productions=[], storages=[], links=[]), + ) # Expected - cons = OutputConsumption(name='load', quantity=[[5, 0], [0, 15]]) - nodes = {'a': OutputNode(consumptions=[cons], productions=[], storages=[], links=[])} - expected = Result(networks={'default': OutputNetwork(nodes=nodes)}, converters={}) + cons = OutputConsumption(name="load", quantity=[[5, 0], [0, 15]]) + nodes = { + "a": OutputNode(consumptions=[cons], productions=[], storages=[], links=[]) + } + expected = Result( + networks={"default": OutputNetwork(nodes=nodes)}, converters={} + ) assert_result(self, expected=expected, result=mapper.get_result()) def test_map_production(self): # Input - study = Study(horizon=2, nb_scn=2) \ - .network()\ - .node('a')\ - .production(name='nuclear', quantity=[[12, 2], [21, 20]], cost=[[0.12, 0.2], [0.21, 0.02]]) \ + study = ( + Study(horizon=2, nb_scn=2) + .network() + .node("a") + .production( + name="nuclear", + quantity=[[12, 2], [21, 20]], + cost=[[0.12, 0.2], [0.21, 0.02]], + ) .build() + ) mapper = OutputMapper(study=study) - out_prod_0 = [LPProduction(name='nuclear', cost=.12, quantity=12, variable=12)] - mapper.set_node_var(network='default', node='a', t=0, scn=0, - vars=LPNode(consumptions=[], productions=out_prod_0, storages=[], links=[])) - - out_prod_1 = [LPProduction(name='nuclear', cost=.21, quantity=2, variable=112)] - mapper.set_node_var(network='default', node='a', t=1, scn=1, - vars=LPNode(consumptions=[], productions=out_prod_1, storages=[], links=[])) + out_prod_0 = [LPProduction(name="nuclear", cost=0.12, quantity=12, variable=12)] + mapper.set_node_var( + network="default", + node="a", + t=0, + scn=0, + vars=LPNode(consumptions=[], productions=out_prod_0, storages=[], links=[]), + ) + + out_prod_1 = [LPProduction(name="nuclear", cost=0.21, quantity=2, variable=112)] + mapper.set_node_var( + network="default", + node="a", + t=1, + scn=1, + vars=LPNode(consumptions=[], productions=out_prod_1, storages=[], links=[]), + ) # Expected - prod = OutputProduction(name='nuclear', quantity=[[12, 0], [0, 112]]) - nodes = {'a': OutputNode(consumptions=[], productions=[prod], storages=[], links=[])} - expected = Result(networks={'default': OutputNetwork(nodes=nodes)}, converters={}) + prod = OutputProduction(name="nuclear", quantity=[[12, 0], [0, 112]]) + nodes = { + "a": OutputNode(consumptions=[], productions=[prod], storages=[], links=[]) + } + expected = Result( + networks={"default": OutputNetwork(nodes=nodes)}, converters={} + ) assert_result(self, expected=expected, result=mapper.get_result()) def test_map_storage(self): # Input - study = Study(horizon=2, nb_scn=2) \ - .network()\ - .node('a')\ - .storage(name='cell', capacity=10, flow_in=1, flow_out=1, cost=1, init_capacity=2, eff=.9) \ + study = ( + Study(horizon=2, nb_scn=2) + .network() + .node("a") + .storage( + name="cell", + capacity=10, + flow_in=1, + flow_out=1, + cost=1, + init_capacity=2, + eff=0.9, + ) .build() + ) mapper = OutputMapper(study=study) - out_stor_0 = [LPStorage(name='cell', capacity=10, flow_in=1, flow_out=1, init_capacity=2, eff=.9, cost=1, - var_capacity=5, var_flow_in=2, var_flow_out=4)] - mapper.set_node_var(network='default', node='a', t=0, scn=0, - vars=LPNode(consumptions=[], productions=[], storages=out_stor_0, links=[])) - - out_stor_1 = [LPStorage(name='cell', capacity=10, flow_in=1, flow_out=1, init_capacity=2, eff=.9, cost=1, - var_capacity=55, var_flow_in=22, var_flow_out=44)] - mapper.set_node_var(network='default', node='a', t=1, scn=1, - vars=LPNode(consumptions=[], productions=[], storages=out_stor_1, links=[])) + out_stor_0 = [ + LPStorage( + name="cell", + capacity=10, + flow_in=1, + flow_out=1, + init_capacity=2, + eff=0.9, + cost=1, + var_capacity=5, + var_flow_in=2, + var_flow_out=4, + ) + ] + mapper.set_node_var( + network="default", + node="a", + t=0, + scn=0, + vars=LPNode(consumptions=[], productions=[], storages=out_stor_0, links=[]), + ) + + out_stor_1 = [ + LPStorage( + name="cell", + capacity=10, + flow_in=1, + flow_out=1, + init_capacity=2, + eff=0.9, + cost=1, + var_capacity=55, + var_flow_in=22, + var_flow_out=44, + ) + ] + mapper.set_node_var( + network="default", + node="a", + t=1, + scn=1, + vars=LPNode(consumptions=[], productions=[], storages=out_stor_1, links=[]), + ) # Expected - stor = OutputStorage(name='cell', capacity=[[5, 0], [0, 55]], flow_in=[[2, 0], [0, 22]], flow_out=[[4, 0], [0, 44]]) - nodes = {'a': OutputNode(consumptions=[], productions=[], storages=[stor], links=[])} - expected = Result(networks={'default': OutputNetwork(nodes=nodes)}, converters={}) + stor = OutputStorage( + name="cell", + capacity=[[5, 0], [0, 55]], + flow_in=[[2, 0], [0, 22]], + flow_out=[[4, 0], [0, 44]], + ) + nodes = { + "a": OutputNode(consumptions=[], productions=[], storages=[stor], links=[]) + } + expected = Result( + networks={"default": OutputNetwork(nodes=nodes)}, converters={} + ) assert_result(self, expected=expected, result=mapper.get_result()) def test_map_link(self): # Input - study = Study(horizon=2, nb_scn=2) \ - .network()\ - .node('a')\ - .node('be')\ - .link(src='a', dest='be', quantity=[[10, 3], [20, 30]], cost=[[.01, .3], [.02, .03]])\ + study = ( + Study(horizon=2, nb_scn=2) + .network() + .node("a") + .node("be") + .link( + src="a", + dest="be", + quantity=[[10, 3], [20, 30]], + cost=[[0.01, 0.3], [0.02, 0.03]], + ) .build() + ) mapper = OutputMapper(study=study) - out_link_0 = [LPLink(src='a', dest='be', cost=.01, quantity=10, variable=8)] - mapper.set_node_var(network='default', node='a', t=0, scn=0, - vars=LPNode(consumptions=[], productions=[], storages=[], links=out_link_0)) - - out_link_1 = [LPLink(src='a', dest='be', cost=.02, quantity=10, variable=18)] - mapper.set_node_var(network='default', node='a', t=1, scn=1, - vars=LPNode(consumptions=[], productions=[], storages=[], links=out_link_1)) + out_link_0 = [LPLink(src="a", dest="be", cost=0.01, quantity=10, variable=8)] + mapper.set_node_var( + network="default", + node="a", + t=0, + scn=0, + vars=LPNode(consumptions=[], productions=[], storages=[], links=out_link_0), + ) + + out_link_1 = [LPLink(src="a", dest="be", cost=0.02, quantity=10, variable=18)] + mapper.set_node_var( + network="default", + node="a", + t=1, + scn=1, + vars=LPNode(consumptions=[], productions=[], storages=[], links=out_link_1), + ) # Expected - link = OutputLink(dest='be', quantity=[[8, 0], [0, 18]]) - nodes = {'a': OutputNode(consumptions=[], productions=[], storages=[], links=[link]), - 'be': OutputNode(consumptions=[], productions=[], storages=[], links=[])} - expected = Result(networks={'default': OutputNetwork(nodes=nodes)}, converters={}) + link = OutputLink(dest="be", quantity=[[8, 0], [0, 18]]) + nodes = { + "a": OutputNode(consumptions=[], productions=[], storages=[], links=[link]), + "be": OutputNode(consumptions=[], productions=[], storages=[], links=[]), + } + expected = Result( + networks={"default": OutputNetwork(nodes=nodes)}, converters={} + ) assert_result(self, expected=expected, result=mapper.get_result()) def test_map_converter(self): # Input - study = Study(horizon=1)\ - .network('gas')\ - .node('a')\ - .to_converter(name='conv', ratio=.5)\ - .network()\ - .node('b')\ - .converter(name='conv', to_network='default', to_node='b', max=100)\ + study = ( + Study(horizon=1) + .network("gas") + .node("a") + .to_converter(name="conv", ratio=0.5) + .network() + .node("b") + .converter(name="conv", to_network="default", to_node="b", max=100) .build() + ) # Expected - exp = OutputConverter(name='conv', flow_src={('gas', 'a'): [[200]]}, flow_dest=[[100]]) + exp = OutputConverter( + name="conv", flow_src={("gas", "a"): [[200]]}, flow_dest=[[100]] + ) blank_node = OutputNode(consumptions=[], productions=[], storages=[], links=[]) mapper = OutputMapper(study=study) - vars = LPConverter(name='conv', src_ratios={('gas', 'a'): 0.5}, dest_network='default', dest_node='b', - cost=0, max=100, var_flow_dest=100, var_flow_src={('gas', 'a'): 200}) - mapper.set_converter_var(name='conv', t=0, scn=0, vars=vars) + vars = LPConverter( + name="conv", + src_ratios={("gas", "a"): 0.5}, + dest_network="default", + dest_node="b", + cost=0, + max=100, + var_flow_dest=100, + var_flow_src={("gas", "a"): 200}, + ) + mapper.set_converter_var(name="conv", t=0, scn=0, vars=vars) res = mapper.get_result() - self.assertEqual(Result(networks={'gas': OutputNetwork(nodes={'a': blank_node}), - 'default': OutputNetwork(nodes={'b': blank_node})}, - converters={'conv': exp}), res) - + self.assertEqual( + Result( + networks={ + "gas": OutputNetwork(nodes={"a": blank_node}), + "default": OutputNetwork(nodes={"b": blank_node}), + }, + converters={"conv": exp}, + ), + res, + ) diff --git a/tests/optimizer/lp/test_optimizer.py b/tests/optimizer/lp/test_optimizer.py index e39d3ae..3037693 100644 --- a/tests/optimizer/lp/test_optimizer.py +++ b/tests/optimizer/lp/test_optimizer.py @@ -10,37 +10,94 @@ import msgpack from hadar.optimizer.domain.input import Study -from hadar.optimizer.lp.domain import LPConsumption, LPProduction, LPLink, LPNode, LPStorage, \ - LPConverter, LPTimeStep, LPNetwork +from hadar.optimizer.lp.domain import ( + LPConsumption, + LPProduction, + LPLink, + LPNode, + LPStorage, + LPConverter, + LPTimeStep, + LPNetwork, +) from hadar.optimizer.lp.mapper import InputMapper, OutputMapper -from hadar.optimizer.lp.optimizer import ObjectiveBuilder, AdequacyBuilder, _solve_batch, StorageBuilder, \ - ConverterMixBuilder +from hadar.optimizer.lp.optimizer import ( + ObjectiveBuilder, + AdequacyBuilder, + _solve_batch, + StorageBuilder, + ConverterMixBuilder, +) from hadar.optimizer.lp.optimizer import solve_lp -from hadar.optimizer.domain.output import OutputConsumption, OutputNode, Result, OutputNetwork, OutputConverter -from tests.optimizer.lp.ortools_mock import MockConstraint, MockNumVar, MockObjective, MockSolver +from hadar.optimizer.domain.output import ( + OutputConsumption, + OutputNode, + Result, + OutputNetwork, + OutputConverter, +) +from tests.optimizer.lp.ortools_mock import ( + MockConstraint, + MockNumVar, + MockObjective, + MockSolver, +) class TestObjectiveBuilder(unittest.TestCase): - def test_add_node(self): # Mock objective = MockObjective() solver = MockSolver() # Input - consumptions = [LPConsumption(name='load', quantity=10, cost=10, variable=MockNumVar(0, 10, 'load'))] - productions = [LPProduction(name='solar', quantity=10, cost=20, variable=MockNumVar(0, 20, 'solar'))] - storages = [LPStorage(name='cell', capacity=10, var_capacity=MockNumVar(0, 10, 'cell_capacity'), cost=1, - flow_in=1, var_flow_in=MockNumVar(0, 1, 'cell_flow_in'), - flow_out=10, var_flow_out=MockNumVar(0, 10, 'cell_flow_out'), - init_capacity=2, eff=1.2 - )] - links = [LPLink(src='fr', dest='be', quantity=10, cost=30, variable=MockNumVar(0, 30, 'be'))] - node = LPNode(consumptions=consumptions, productions=productions, storages=storages, links=links) + consumptions = [ + LPConsumption( + name="load", quantity=10, cost=10, variable=MockNumVar(0, 10, "load") + ) + ] + productions = [ + LPProduction( + name="solar", quantity=10, cost=20, variable=MockNumVar(0, 20, "solar") + ) + ] + storages = [ + LPStorage( + name="cell", + capacity=10, + var_capacity=MockNumVar(0, 10, "cell_capacity"), + cost=1, + flow_in=1, + var_flow_in=MockNumVar(0, 1, "cell_flow_in"), + flow_out=10, + var_flow_out=MockNumVar(0, 10, "cell_flow_out"), + init_capacity=2, + eff=1.2, + ) + ] + links = [ + LPLink( + src="fr", + dest="be", + quantity=10, + cost=30, + variable=MockNumVar(0, 30, "be"), + ) + ] + node = LPNode( + consumptions=consumptions, + productions=productions, + storages=storages, + links=links, + ) # Expected - coeffs = {MockNumVar(0, 10, 'load'): 10, MockNumVar(0, 20, 'solar'): 20, MockNumVar(0, 30, 'be'): 30, - MockNumVar(0, 10, 'cell_capacity'): 1} + coeffs = { + MockNumVar(0, 10, "load"): 10, + MockNumVar(0, 20, "solar"): 20, + MockNumVar(0, 30, "be"): 30, + MockNumVar(0, 10, "cell_capacity"): 1, + } expected = MockObjective(min=True, coeffs=coeffs) # Test @@ -55,12 +112,21 @@ def test_add_converter(self): solver = MockSolver() # Input - conv = LPConverter(name='conv', src_ratios={('gas', 'a'): 0.5}, dest_network='default', dest_node='b', - cost=10, max=100, var_flow_dest=MockNumVar(0, 100, 'flow_dest conv %s'), - var_flow_src={('gas', 'a'): MockNumVar(0, 200, 'flow_src conv gas:a %s')}) + conv = LPConverter( + name="conv", + src_ratios={("gas", "a"): 0.5}, + dest_network="default", + dest_node="b", + cost=10, + max=100, + var_flow_dest=MockNumVar(0, 100, "flow_dest conv %s"), + var_flow_src={("gas", "a"): MockNumVar(0, 200, "flow_src conv gas:a %s")}, + ) # Expected - expected = MockObjective(min=True, coeffs={MockNumVar(0, 100, 'flow_dest conv %s'): 10}) + expected = MockObjective( + min=True, coeffs={MockNumVar(0, 100, "flow_dest conv %s"): 10} + ) # Test builder = ObjectiveBuilder(solver=solver) @@ -71,59 +137,106 @@ def test_add_converter(self): class TestAdequacyBuilder(unittest.TestCase): - def test_add_node(self): # Mock solver = MockSolver() # Input - fr_consumptions = [LPConsumption(name='load', quantity=10, cost=10, variable=MockNumVar(0, 10, 'load'))] - fr_productions = [LPProduction(name='solar', quantity=10, cost=20, variable=MockNumVar(0, 20, 'solar'))] - fr_storages = [LPStorage(name='cell', capacity=10, var_capacity=MockNumVar(0, 10, 'cell_capacity'), cost=1, - flow_in=1, var_flow_in=MockNumVar(0, 1, 'cell_flow_in'), - flow_out=10, var_flow_out=MockNumVar(0, 10, 'cell_flow_out'), - init_capacity=2, eff=1.2)] - fr_links = [LPLink(src='fr', dest='be', quantity=10, cost=30, variable=MockNumVar(0, 30, 'be'))] - fr_node = LPNode(consumptions=fr_consumptions, productions=fr_productions, storages=fr_storages, links=fr_links) + fr_consumptions = [ + LPConsumption( + name="load", quantity=10, cost=10, variable=MockNumVar(0, 10, "load") + ) + ] + fr_productions = [ + LPProduction( + name="solar", quantity=10, cost=20, variable=MockNumVar(0, 20, "solar") + ) + ] + fr_storages = [ + LPStorage( + name="cell", + capacity=10, + var_capacity=MockNumVar(0, 10, "cell_capacity"), + cost=1, + flow_in=1, + var_flow_in=MockNumVar(0, 1, "cell_flow_in"), + flow_out=10, + var_flow_out=MockNumVar(0, 10, "cell_flow_out"), + init_capacity=2, + eff=1.2, + ) + ] + fr_links = [ + LPLink( + src="fr", + dest="be", + quantity=10, + cost=30, + variable=MockNumVar(0, 30, "be"), + ) + ] + fr_node = LPNode( + consumptions=fr_consumptions, + productions=fr_productions, + storages=fr_storages, + links=fr_links, + ) be_node = LPNode(consumptions=[], productions=[], storages=[], links=[]) # Expected - fr_coeffs = {MockNumVar(0, 10, 'load'): 1, MockNumVar(0, 20, 'solar'): 1, - MockNumVar(0, 1, 'cell_flow_in'): -1, MockNumVar(0, 10, 'cell_flow_out'): 1, - MockNumVar(0, 30, 'be'): -1} + fr_coeffs = { + MockNumVar(0, 10, "load"): 1, + MockNumVar(0, 20, "solar"): 1, + MockNumVar(0, 1, "cell_flow_in"): -1, + MockNumVar(0, 10, "cell_flow_out"): 1, + MockNumVar(0, 30, "be"): -1, + } fr_constraint = MockConstraint(10, 10, coeffs=fr_coeffs) - be_coeffs = {MockNumVar(0, 30, 'be'): 1} + be_coeffs = {MockNumVar(0, 30, "be"): 1} be_constraint = MockConstraint(0, 0, coeffs=be_coeffs) # Test builder = AdequacyBuilder(solver=solver) - builder.add_node(name_network='default', name_node='fr', node=fr_node, t=0) - builder.add_node(name_network='default', name_node='be', node=be_node, t=0) + builder.add_node(name_network="default", name_node="fr", node=fr_node, t=0) + builder.add_node(name_network="default", name_node="be", node=be_node, t=0) builder.build() - self.assertEqual(fr_constraint, builder.constraints[(0, 'default', 'fr')]) - self.assertEqual(be_constraint, builder.constraints[(0, 'default', 'be')]) + self.assertEqual(fr_constraint, builder.constraints[(0, "default", "fr")]) + self.assertEqual(be_constraint, builder.constraints[(0, "default", "be")]) def test_add_converter(self): # Mock solver = MockSolver() # Input - conv = LPConverter(name='conv', src_ratios={('gas', 'a'): 0.5}, dest_network='default', dest_node='b', - cost=10, max=100, var_flow_dest=MockNumVar(0, 100, 'flow_dest conv %s'), - var_flow_src={('gas', 'a'): MockNumVar(0, 200, 'flow_src conv gas:a %s')}) + conv = LPConverter( + name="conv", + src_ratios={("gas", "a"): 0.5}, + dest_network="default", + dest_node="b", + cost=10, + max=100, + var_flow_dest=MockNumVar(0, 100, "flow_dest conv %s"), + var_flow_src={("gas", "a"): MockNumVar(0, 200, "flow_src conv gas:a %s")}, + ) adequacy = AdequacyBuilder(solver=solver) - adequacy.constraints[(0, 'gas', 'a')] = MockConstraint(10, 10, coeffs={}) - adequacy.constraints[(0, 'default', 'b')] = MockConstraint(10, 10, coeffs={}) + adequacy.constraints[(0, "gas", "a")] = MockConstraint(10, 10, coeffs={}) + adequacy.constraints[(0, "default", "b")] = MockConstraint(10, 10, coeffs={}) # Test adequacy.add_converter(conv=conv, t=0) - self.assertEqual({MockNumVar(0, 100, 'flow_dest conv %s'): 1}, adequacy.constraints[(0, 'default', 'b')].coeffs) - self.assertEqual({MockNumVar(0, 200, 'flow_src conv gas:a %s'): -1}, adequacy.constraints[(0, 'gas', 'a')].coeffs) + self.assertEqual( + {MockNumVar(0, 100, "flow_dest conv %s"): 1}, + adequacy.constraints[(0, "default", "b")].coeffs, + ) + self.assertEqual( + {MockNumVar(0, 200, "flow_src conv gas:a %s"): -1}, + adequacy.constraints[(0, "gas", "a")].coeffs, + ) class TestStorageBuilder(unittest.TestCase): @@ -132,51 +245,78 @@ def test_t0(self): solver = MockSolver() # Input - c0 = MockNumVar(0, 10, 'cell_capacity') - storages = [LPStorage(name='cell', capacity=10, var_capacity=c0, cost=1, - flow_in=1, var_flow_in=MockNumVar(0, 1, 'cell_flow_in'), - flow_out=10, var_flow_out=MockNumVar(0, 10, 'cell_flow_out'), - init_capacity=2, eff=1.2)] + c0 = MockNumVar(0, 10, "cell_capacity") + storages = [ + LPStorage( + name="cell", + capacity=10, + var_capacity=c0, + cost=1, + flow_in=1, + var_flow_in=MockNumVar(0, 1, "cell_flow_in"), + flow_out=10, + var_flow_out=MockNumVar(0, 10, "cell_flow_out"), + init_capacity=2, + eff=1.2, + ) + ] node = LPNode(consumptions=[], productions=[], storages=storages, links=[]) # Expected - coeffs = {MockNumVar(0, 1, 'cell_flow_in'): -1.2, MockNumVar(0, 10, 'cell_flow_out'): 1, - c0: 1} + coeffs = { + MockNumVar(0, 1, "cell_flow_in"): -1.2, + MockNumVar(0, 10, "cell_flow_out"): 1, + c0: 1, + } constraint = MockConstraint(2, 2, coeffs=coeffs) # Test builder = StorageBuilder(solver=solver) - res = builder.add_node(name_network='default', name_node='fr', node=node, t=0) + res = builder.add_node(name_network="default", name_node="fr", node=node, t=0) self.assertEqual(constraint, res) - self.assertEqual(builder.capacities[(0, 'default', 'fr', 'cell')], c0) + self.assertEqual(builder.capacities[(0, "default", "fr", "cell")], c0) def test(self): # Mock solver = MockSolver() # Input - storages = [LPStorage(name='cell', capacity=10, var_capacity=MockNumVar(0, 10, 'cell_capacity at 1'), cost=1, - flow_in=1, var_flow_in=MockNumVar(0, 1, 'cell_flow_in'), - flow_out=10, var_flow_out=MockNumVar(0, 10, 'cell_flow_out'), - init_capacity=2, eff=1.2)] + storages = [ + LPStorage( + name="cell", + capacity=10, + var_capacity=MockNumVar(0, 10, "cell_capacity at 1"), + cost=1, + flow_in=1, + var_flow_in=MockNumVar(0, 1, "cell_flow_in"), + flow_out=10, + var_flow_out=MockNumVar(0, 10, "cell_flow_out"), + init_capacity=2, + eff=1.2, + ) + ] node = LPNode(consumptions=[], productions=[], storages=storages, links=[]) - c0 = MockNumVar(0, 11, 'cell_capacity at 0') - c1 = MockNumVar(0, 10, 'cell_capacity at 1') + c0 = MockNumVar(0, 11, "cell_capacity at 0") + c1 = MockNumVar(0, 10, "cell_capacity at 1") # Expected - coeffs = {MockNumVar(0, 1, 'cell_flow_in'): -1.2, MockNumVar(0, 10, 'cell_flow_out'): 1, - c0: -1, c1: 1} + coeffs = { + MockNumVar(0, 1, "cell_flow_in"): -1.2, + MockNumVar(0, 10, "cell_flow_out"): 1, + c0: -1, + c1: 1, + } constraint = MockConstraint(0, 0, coeffs=coeffs) # Test builder = StorageBuilder(solver=solver) - builder.capacities[(0, 'default', 'fr', 'cell')] = c0 - res = builder.add_node(name_network='default', name_node='fr', node=node, t=1) + builder.capacities[(0, "default", "fr", "cell")] = c0 + res = builder.add_node(name_network="default", name_node="fr", node=node, t=1) self.assertEqual(constraint, res) - self.assertEqual(c1, builder.capacities[(1, 'default', 'fr', 'cell')]) + self.assertEqual(c1, builder.capacities[(1, "default", "fr", "cell")]) class TestConverterMixBuilder(unittest.TestCase): @@ -185,13 +325,26 @@ def test(self): solver = MockSolver() # Input - conv = LPConverter(name='conv', src_ratios={('gas', 'a'): 0.5}, dest_network='default', dest_node='b', - cost=10, max=100, var_flow_dest=MockNumVar(0, 100, 'flow_dest conv %s'), - var_flow_src={('gas', 'a'): MockNumVar(0, 200, 'flow_src conv gas:a %s')}) + conv = LPConverter( + name="conv", + src_ratios={("gas", "a"): 0.5}, + dest_network="default", + dest_node="b", + cost=10, + max=100, + var_flow_dest=MockNumVar(0, 100, "flow_dest conv %s"), + var_flow_src={("gas", "a"): MockNumVar(0, 200, "flow_src conv gas:a %s")}, + ) # Expected - expected = MockConstraint(0, 0, coeffs={MockNumVar(0, 100, 'flow_dest conv %s'): -1, - MockNumVar(0, 200, 'flow_src conv gas:a %s'): 0.5}) + expected = MockConstraint( + 0, + 0, + coeffs={ + MockNumVar(0, 100, "flow_dest conv %s"): -1, + MockNumVar(0, 200, "flow_src conv gas:a %s"): 0.5, + }, + ) # Test builder = ConverterMixBuilder(solver=solver) @@ -202,14 +355,17 @@ def test(self): class TestSolve(unittest.TestCase): def test_solve_batch(self): # Input - study = Study(horizon=1, nb_scn=1) \ - .network()\ - .node('a')\ - .consumption(name='load', cost=10, quantity=10)\ - .to_converter(name='conv')\ - .network('gas').node('b')\ - .converter(name='conv', to_network='gas', to_node='b', max=10, cost=1)\ + study = ( + Study(horizon=1, nb_scn=1) + .network() + .node("a") + .consumption(name="load", cost=10, quantity=10) + .to_converter(name="conv") + .network("gas") + .node("b") + .converter(name="conv", to_network="gas", to_node="b", max=10, cost=1) .build() + ) # Mock solver = MockSolver() @@ -233,52 +389,96 @@ def test_solve_batch(self): mix.add_converter = MagicMock() mix.build = MagicMock() - in_cons = LPConsumption(name='load', quantity=10, cost=10, variable=MockNumVar(0, 10, 'load')) + in_cons = LPConsumption( + name="load", quantity=10, cost=10, variable=MockNumVar(0, 10, "load") + ) var_node = LPNode(consumptions=[in_cons], productions=[], storages=[], links=[]) empty_node = LPNode(consumptions=[], productions=[], storages=[], links=[]) - var_conv = LPConverter(name='conv', src_ratios={('default', 'a'): .5}, - var_flow_src={('default', 'a'): MockNumVar(0, 10, 'conv src')}, - dest_network='gas', dest_node='b', max=10, cost=1, - var_flow_dest=MockNumVar(0, 10, 'conv dest')) + var_conv = LPConverter( + name="conv", + src_ratios={("default", "a"): 0.5}, + var_flow_src={("default", "a"): MockNumVar(0, 10, "conv src")}, + dest_network="gas", + dest_node="b", + max=10, + cost=1, + var_flow_dest=MockNumVar(0, 10, "conv dest"), + ) def side_effect(network, node, t, scn): - return var_node if network == 'default' and node == 'a' else empty_node + return var_node if network == "default" and node == "a" else empty_node + in_mapper = InputMapper(solver=solver, study=study) in_mapper.get_node_var = Mock(side_effect=side_effect) - exp_var_conv = LPConverter(name='conv', src_ratios={('default', 'a'): .5}, max=10, cost=1, - var_flow_src={('default', 'a'): MockNumVar(0, 10, 'conv src')}, - dest_network='gas', dest_node='b', var_flow_dest=MockNumVar(0, 10, 'conv dest')) + exp_var_conv = LPConverter( + name="conv", + src_ratios={("default", "a"): 0.5}, + max=10, + cost=1, + var_flow_src={("default", "a"): MockNumVar(0, 10, "conv src")}, + dest_network="gas", + dest_node="b", + var_flow_dest=MockNumVar(0, 10, "conv dest"), + ) in_mapper.get_conv_var = Mock(return_value=exp_var_conv) # Expected - in_cons = LPConsumption(name='load', quantity=10, cost=10, variable=10) - exp_var_node = LPNode(consumptions=[in_cons], productions=[], storages=[], links=[]) - exp_var_conv = LPConverter(name='conv', src_ratios={('default', 'a'): .5}, - var_flow_src={('default', 'a'): 10}, - dest_network='gas', dest_node='b', max=10, cost=1, - var_flow_dest=10) - - expected = LPTimeStep(networks={'default': LPNetwork(nodes={'a': exp_var_node}), - 'gas': LPNetwork(nodes={'b': empty_node})}, - converters={'conv': exp_var_conv}) + in_cons = LPConsumption(name="load", quantity=10, cost=10, variable=10) + exp_var_node = LPNode( + consumptions=[in_cons], productions=[], storages=[], links=[] + ) + exp_var_conv = LPConverter( + name="conv", + src_ratios={("default", "a"): 0.5}, + var_flow_src={("default", "a"): 10}, + dest_network="gas", + dest_node="b", + max=10, + cost=1, + var_flow_dest=10, + ) + + expected = LPTimeStep( + networks={ + "default": LPNetwork(nodes={"a": exp_var_node}), + "gas": LPNetwork(nodes={"b": empty_node}), + }, + converters={"conv": exp_var_conv}, + ) # Test - res = _solve_batch((study, 0, solver, objective, adequacy, storage, mix, in_mapper)) - res, t_mod, t_sol = msgpack.unpackb(res, use_list=False, raw=False) + res = _solve_batch( + (study, 0, solver, objective, adequacy, storage, mix, in_mapper) + ) + res, t_mod, t_sol = msgpack.unpackb(res, use_list=False, raw=False) self.assertEqual([expected], [LPTimeStep.from_json(r) for r in res]) self.assertTrue(t_mod > 0) self.assertTrue(t_sol > 0) - in_mapper.get_node_var.assert_has_calls([call(network='default', node='a', t=0, scn=0), - call(network='gas', node='b', t=0, scn=0)]) - adequacy.add_node.assert_has_calls([call(name_network='default', name_node='a', t=0, node=var_node), - call(name_network='gas', name_node='b', t=0, node=empty_node)]) - storage.add_node.assert_has_calls([call(name_network='default', name_node='a', t=0, node=var_node), - call(name_network='gas', name_node='b', t=0, node=empty_node)]) + in_mapper.get_node_var.assert_has_calls( + [ + call(network="default", node="a", t=0, scn=0), + call(network="gas", node="b", t=0, scn=0), + ] + ) + adequacy.add_node.assert_has_calls( + [ + call(name_network="default", name_node="a", t=0, node=var_node), + call(name_network="gas", name_node="b", t=0, node=empty_node), + ] + ) + storage.add_node.assert_has_calls( + [ + call(name_network="default", name_node="a", t=0, node=var_node), + call(name_network="gas", name_node="b", t=0, node=empty_node), + ] + ) mix.add_converter.assert_called_with(conv=var_conv) - objective.add_node.assert_has_calls([call(node=var_node), call(node=empty_node)]) + objective.add_node.assert_has_calls( + [call(node=var_node), call(node=empty_node)] + ) objective.add_converter(conv=var_conv) objective.build.assert_called_with() @@ -290,24 +490,35 @@ def side_effect(network, node, t, scn): def test_solve(self): # Input - study = Study(horizon=1, nb_scn=1) \ - .network('gas').node('a')\ - .consumption(name='load', cost=10, quantity=10)\ - .to_converter(name='conv', ratio=0.5)\ - .network().node('b')\ - .converter(name='conv', to_network='default', to_node='b', max=10, cost=1)\ + study = ( + Study(horizon=1, nb_scn=1) + .network("gas") + .node("a") + .consumption(name="load", cost=10, quantity=10) + .to_converter(name="conv", ratio=0.5) + .network() + .node("b") + .converter(name="conv", to_network="default", to_node="b", max=10, cost=1) .build() + ) # Expected - out_node = OutputNode(consumptions=[OutputConsumption(name='load', quantity=[0])], - productions=[], storages=[], links=[]) - out_conv = OutputConverter(name='conv', flow_src={('gas', 'a'): [0]}, flow_dest=[0]) - exp_result = Result(networks={'gas': OutputNetwork(nodes={'a': out_node})}, - converters={'conv': out_conv}) + out_node = OutputNode( + consumptions=[OutputConsumption(name="load", quantity=[0])], + productions=[], + storages=[], + links=[], + ) + out_conv = OutputConverter( + name="conv", flow_src={("gas", "a"): [0]}, flow_dest=[0] + ) + exp_result = Result( + networks={"gas": OutputNetwork(nodes={"a": out_node})}, + converters={"conv": out_conv}, + ) # Mock - out_mapper = OutputMapper(study=study) out_mapper.set_node_var = MagicMock() out_mapper.set_converter_var = MagicMock() @@ -317,7 +528,12 @@ def test_solve(self): res = solve_lp(study, out_mapper) self.assertEqual(exp_result, res) - out_mapper.set_node_var.assert_has_calls([call(network='gas', node='a', t=0, scn=0, vars=ANY), - call(network='default', node='b', t=0, scn=0, vars=ANY)]) - out_mapper.set_converter_var.assert_called_with(name='conv', t=0, scn=0, vars=ANY) - + out_mapper.set_node_var.assert_has_calls( + [ + call(network="gas", node="a", t=0, scn=0, vars=ANY), + call(network="default", node="b", t=0, scn=0, vars=ANY), + ] + ) + out_mapper.set_converter_var.assert_called_with( + name="conv", t=0, scn=0, vars=ANY + ) diff --git a/tests/optimizer/remote/__init__.py b/tests/optimizer/remote/__init__.py index 84711aa..f76a769 100644 --- a/tests/optimizer/remote/__init__.py +++ b/tests/optimizer/remote/__init__.py @@ -4,4 +4,3 @@ # If a copy of the Apache License, version 2.0 was not distributed with this file, you can obtain one at http://www.apache.org/licenses/LICENSE-2.0. # SPDX-License-Identifier: Apache-2.0 # This file is part of hadar-simulator, a python adequacy library for everyone. - diff --git a/tests/optimizer/remote/test_optimizer.py b/tests/optimizer/remote/test_optimizer.py index 3394081..9809f80 100644 --- a/tests/optimizer/remote/test_optimizer.py +++ b/tests/optimizer/remote/test_optimizer.py @@ -11,34 +11,47 @@ from hadar import RemoteOptimizer from hadar.optimizer.domain.input import Study -from hadar.optimizer.domain.output import Result, OutputConsumption, OutputNode, OutputNetwork +from hadar.optimizer.domain.output import ( + Result, + OutputConsumption, + OutputNode, + OutputNetwork, +) from hadar.optimizer.remote.optimizer import check_code class MockSchedulerServer(BaseHTTPRequestHandler): def do_POST(self): - assert self.path == '/api/v1/study?token=' + assert self.path == "/api/v1/study?token=" - content_length = int(self.headers['Content-Length']) + content_length = int(self.headers["Content-Length"]) data = json.loads(self.rfile.read(content_length).decode()) assert isinstance(Study.from_json(data), Study) self.send_response(200) - body = json.dumps({'job': 123, 'status': 'QUEUED', 'progress': 1}).encode() - self.send_header('Content-Length', str(len(body))) + body = json.dumps({"job": 123, "status": "QUEUED", "progress": 1}).encode() + self.send_header("Content-Length", str(len(body))) self.end_headers() self.wfile.write(body) def do_GET(self): - assert '/api/v1/result/123?token=' == self.path - - nodes = {'a': OutputNode(consumptions=[OutputConsumption(quantity=[0], name='load')], - productions=[], storages=[], links=[])} - res = Result(networks={'default': OutputNetwork(nodes=nodes)}, converters={}) + assert "/api/v1/result/123?token=" == self.path + + nodes = { + "a": OutputNode( + consumptions=[OutputConsumption(quantity=[0], name="load")], + productions=[], + storages=[], + links=[], + ) + } + res = Result(networks={"default": OutputNetwork(nodes=nodes)}, converters={}) self.send_response(200) - body = json.dumps({'job': 123, 'status': 'TERMINATED', 'result': res.to_json()}).encode() - self.send_header('Content-Length', str(len(body))) + body = json.dumps( + {"job": 123, "status": "TERMINATED", "result": res.to_json()} + ).encode() + self.send_header("Content-Length", str(len(body))) self.end_headers() self.wfile.write(body) @@ -50,20 +63,33 @@ def handle_twice(handle_request): class RemoteOptimizerTest(unittest.TestCase): def setUp(self) -> None: - self.study = Study(horizon=1) \ - .network().node('a').consumption(cost=0, quantity=[0], name='load').build() - - nodes = {'a': OutputNode(consumptions=[OutputConsumption(quantity=[0], name='load')], - productions=[], storages=[], links=[])} - self.result = Result(networks={'default': OutputNetwork(nodes=nodes)}, converters={}) + self.study = ( + Study(horizon=1) + .network() + .node("a") + .consumption(cost=0, quantity=[0], name="load") + .build() + ) + + nodes = { + "a": OutputNode( + consumptions=[OutputConsumption(quantity=[0], name="load")], + productions=[], + storages=[], + links=[], + ) + } + self.result = Result( + networks={"default": OutputNetwork(nodes=nodes)}, converters={} + ) def test_job_terminated(self): # Start server - httpd = HTTPServer(('localhost', 6984), MockSchedulerServer) + httpd = HTTPServer(("localhost", 6984), MockSchedulerServer) server = threading.Thread(None, handle_twice, None, (httpd.handle_request,)) server.start() - optim = RemoteOptimizer(url='http://localhost:6984') + optim = RemoteOptimizer(url="http://localhost:6984") res = optim.solve(self.study) self.assertEqual(self.result, res) diff --git a/tests/utils.py b/tests/utils.py index d8fbd12..570cdc9 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -13,52 +13,108 @@ def assert_result(self, expected: Result, result: Result): for name_network, network in expected.networks.items(): if name_network not in result.networks.keys(): - self.fail('Network {} expected but not'.format(name_network)) + self.fail("Network {} expected but not".format(name_network)) for name_node, node in network.nodes.items(): if name_node not in result.networks[name_network].nodes.keys(): - self.fail('Node {} expected but not'.format(name_node)) + self.fail("Node {} expected but not".format(name_node)) res = result.networks[name_network].nodes[name_node] # Consumptions for cons_expected, cons_res in zip(node.consumptions, res.consumptions): - self.assertEqual(cons_expected.name, cons_res.name, - "Consumption for node {} has different name".format(name_node)) - np.testing.assert_array_equal(cons_expected.quantity, cons_res.quantity, - 'Consumption {} for node {} has different quantity'.format(cons_expected.name, name_node)) + self.assertEqual( + cons_expected.name, + cons_res.name, + "Consumption for node {} has different name".format(name_node), + ) + np.testing.assert_array_equal( + cons_expected.quantity, + cons_res.quantity, + "Consumption {} for node {} has different quantity".format( + cons_expected.name, name_node + ), + ) # Productions for prod_expected, prod_res in zip(node.productions, res.productions): - self.assertEqual(prod_expected.name, prod_res.name, - "Production for node {} has different name".format(name_node)) - np.testing.assert_array_equal(prod_expected.quantity, prod_res.quantity, - 'Production {} for node {} has different quantity'.format(prod_expected.name, name_node)) + self.assertEqual( + prod_expected.name, + prod_res.name, + "Production for node {} has different name".format(name_node), + ) + np.testing.assert_array_equal( + prod_expected.quantity, + prod_res.quantity, + "Production {} for node {} has different quantity".format( + prod_expected.name, name_node + ), + ) # Storage for stor_expected, stor_res in zip(node.storages, res.storages): - self.assertEqual(stor_expected.name, stor_res.name, - 'Storage for node {} has different name'.format(name_node)) - np.testing.assert_array_almost_equal(stor_expected.flow_in, stor_res.flow_in, 4, - 'Storage {} for node {} has different flow in'.format(stor_res.name, name_node)) - np.testing.assert_array_almost_equal(stor_expected.flow_out, stor_res.flow_out, 4, - 'Storage {} for node {} has different flow out'.format(stor_res.name, name_node)) - np.testing.assert_array_almost_equal(stor_expected.capacity, stor_res.capacity, 4, - 'Storage {} for node {} has different capacity'.format(stor_res.name, name_node)) + self.assertEqual( + stor_expected.name, + stor_res.name, + "Storage for node {} has different name".format(name_node), + ) + np.testing.assert_array_almost_equal( + stor_expected.flow_in, + stor_res.flow_in, + 4, + "Storage {} for node {} has different flow in".format( + stor_res.name, name_node + ), + ) + np.testing.assert_array_almost_equal( + stor_expected.flow_out, + stor_res.flow_out, + 4, + "Storage {} for node {} has different flow out".format( + stor_res.name, name_node + ), + ) + np.testing.assert_array_almost_equal( + stor_expected.capacity, + stor_res.capacity, + 4, + "Storage {} for node {} has different capacity".format( + stor_res.name, name_node + ), + ) # Links for link_expected, link_res in zip(node.links, res.links): - self.assertEqual(link_expected.dest, link_res.dest, - "Link for node {} has different name".format(name_node)) - np.testing.assert_array_equal(link_expected.quantity, link_res.quantity, - 'Link {} for node {} has different quantity'.format(link_expected.dest, name_node)) + self.assertEqual( + link_expected.dest, + link_res.dest, + "Link for node {} has different name".format(name_node), + ) + np.testing.assert_array_equal( + link_expected.quantity, + link_res.quantity, + "Link {} for node {} has different quantity".format( + link_expected.dest, name_node + ), + ) # Converter for name, exp in expected.converters.items(): - self.assertTrue(name in result.converters, 'Converter {} not in result'.format(name)) + self.assertTrue( + name in result.converters, "Converter {} not in result".format(name) + ) for src, flow in exp.flow_src.items(): - self.assertTrue(src in result.converters[name].flow_src, 'Converter {} has not src {} in result'.format(name, src)) - np.testing.assert_array_equal(flow, result.converters[name].flow_src[src], - 'converter {} as different source {}'.format(name, src)) + self.assertTrue( + src in result.converters[name].flow_src, + "Converter {} has not src {} in result".format(name, src), + ) + np.testing.assert_array_equal( + flow, + result.converters[name].flow_src[src], + "converter {} as different source {}".format(name, src), + ) - np.testing.assert_array_equal(exp.flow_dest, result.converters[name].flow_dest, - 'Converter {} has different flow dest'.format(name)) + np.testing.assert_array_equal( + exp.flow_dest, + result.converters[name].flow_dest, + "Converter {} has different flow dest".format(name), + ) diff --git a/tests/viewer/__init__.py b/tests/viewer/__init__.py index 84711aa..f76a769 100644 --- a/tests/viewer/__init__.py +++ b/tests/viewer/__init__.py @@ -4,4 +4,3 @@ # If a copy of the Apache License, version 2.0 was not distributed with this file, you can obtain one at http://www.apache.org/licenses/LICENSE-2.0. # SPDX-License-Identifier: Apache-2.0 # This file is part of hadar-simulator, a python adequacy library for everyone. - diff --git a/tests/viewer/test_html.py b/tests/viewer/test_html.py index be6637d..2abcb46 100644 --- a/tests/viewer/test_html.py +++ b/tests/viewer/test_html.py @@ -21,132 +21,159 @@ class TestHTMLPlotting(unittest.TestCase): def setUp(self) -> None: - self.study = Study(horizon=3, nb_scn=2)\ - .network()\ - .node('a')\ - .consumption(cost=10 ** 6, quantity=[[20, 10, 2], [10, 5, 3]], name='load')\ - .consumption(cost=10 ** 6, quantity=[[30, 15, 3], [15, 7, 2]], name='car')\ - .production(cost=10, quantity=[[60, 30, 5], [30, 15, 3]], name='prod')\ - .node('b')\ - .consumption(cost=10 ** 6, quantity=[[40, 20, 2], [20, 10, 1]], name='load')\ - .production(cost=20, quantity=[[10, 5, 1], [5, 3, 1]], name='prod')\ - .production(cost=30, quantity=[[20, 10, 2], [10, 5, 1]], name='nuclear')\ - .link(src='a', dest='b', quantity=[[10, 10, 10], [5, 5, 5]], cost=2)\ + self.study = ( + Study(horizon=3, nb_scn=2) + .network() + .node("a") + .consumption(cost=10 ** 6, quantity=[[20, 10, 2], [10, 5, 3]], name="load") + .consumption(cost=10 ** 6, quantity=[[30, 15, 3], [15, 7, 2]], name="car") + .production(cost=10, quantity=[[60, 30, 5], [30, 15, 3]], name="prod") + .node("b") + .consumption(cost=10 ** 6, quantity=[[40, 20, 2], [20, 10, 1]], name="load") + .production(cost=20, quantity=[[10, 5, 1], [5, 3, 1]], name="prod") + .production(cost=30, quantity=[[20, 10, 2], [10, 5, 1]], name="nuclear") + .link(src="a", dest="b", quantity=[[10, 10, 10], [5, 5, 5]], cost=2) .build() + ) optimizer = LPOptimizer() self.result = optimizer.solve(study=self.study) self.agg = ResultAnalyzer(self.study, self.result) - self.plot = HTMLPlotting(agg=self.agg, unit_symbol='MW', time_start='2020-02-01', time_end='2020-02-02', - node_coord={'a': [2.33, 48.86], 'b': [4.38, 50.83]}) + self.plot = HTMLPlotting( + agg=self.agg, + unit_symbol="MW", + time_start="2020-02-01", + time_end="2020-02-02", + node_coord={"a": [2.33, 48.86], "b": [4.38, 50.83]}, + ) self.hash = hashlib.sha3_256() def test_network(self): fig = self.plot.network().map(t=0, scn=0, zoom=1.6) # Used this line to plot map: plot(fig) - self.assert_fig_hash('49d81d1457b2ac78e1fc6ae4c1fc6215b8a0bbe4', fig) + self.assert_fig_hash("49d81d1457b2ac78e1fc6ae4c1fc6215b8a0bbe4", fig) fig = self.plot.network().rac_matrix() - self.assert_fig_hash('2b87a4e781e9eeb532f5d2b091c474bb0de625fd', fig) + self.assert_fig_hash("2b87a4e781e9eeb532f5d2b091c474bb0de625fd", fig) def test_node(self): - fig = self.plot.network().node('a').stack(scn=0) - self.assert_fig_hash('d9f9f004b98ca62be934d69d4fd0c1a302512242', fig) + fig = self.plot.network().node("a").stack(scn=0) + self.assert_fig_hash("d9f9f004b98ca62be934d69d4fd0c1a302512242", fig) def test_consumption(self): - fig = self.plot.network().node('a').consumption('load').timeline() - self.assert_fig_hash('ba776202b252c9df5c81ca869b2e2d85e56e5589', fig) + fig = self.plot.network().node("a").consumption("load").timeline() + self.assert_fig_hash("ba776202b252c9df5c81ca869b2e2d85e56e5589", fig) - fig = self.plot.network().node('a').consumption('load').monotone(scn=0) - self.assert_fig_hash('1ffa51a52b066aab8cabb817c11fd1272549eb9d', fig) + fig = self.plot.network().node("a").consumption("load").monotone(scn=0) + self.assert_fig_hash("1ffa51a52b066aab8cabb817c11fd1272549eb9d", fig) - fig = self.plot.network().node('a').consumption('load').gaussian(scn=0) - self.assert_fig_hash('4f3676a65cde6c268233679e1d0e6207df62764d', fig) + fig = self.plot.network().node("a").consumption("load").gaussian(scn=0) + self.assert_fig_hash("4f3676a65cde6c268233679e1d0e6207df62764d", fig) def test_production(self): - fig = self.plot.network().node('b').production('nuclear').timeline() - self.assert_fig_hash('33baf5d01fda12b6a2d025abf8421905fc24abe1', fig) + fig = self.plot.network().node("b").production("nuclear").timeline() + self.assert_fig_hash("33baf5d01fda12b6a2d025abf8421905fc24abe1", fig) - fig = self.plot.network().node('b').production('nuclear').monotone(t=0) - self.assert_fig_hash('e059878aac45330810578482df8c3d19261f7f75', fig) + fig = self.plot.network().node("b").production("nuclear").monotone(t=0) + self.assert_fig_hash("e059878aac45330810578482df8c3d19261f7f75", fig) - fig = self.plot.network().node('b').production('nuclear').gaussian(t=0) + fig = self.plot.network().node("b").production("nuclear").gaussian(t=0) # Fail devops self.assert_fig_hash('45ffe15df1d72829ebe2283c9c4b65ee8465c978', fig) def test_link(self): - fig = self.plot.network().node('a').link('b').timeline() - self.assert_fig_hash('97f413ea2fa9908abebf381ec588a7e60b906884', fig) + fig = self.plot.network().node("a").link("b").timeline() + self.assert_fig_hash("97f413ea2fa9908abebf381ec588a7e60b906884", fig) - fig = self.plot.network().node('a').link('b').monotone(scn=0) - self.assert_fig_hash('08b0e0d8414bee2c5083a298af00fe86d0eba6b0', fig) + fig = self.plot.network().node("a").link("b").monotone(scn=0) + self.assert_fig_hash("08b0e0d8414bee2c5083a298af00fe86d0eba6b0", fig) - fig = self.plot.network().node('a').link('b').gaussian(scn=0) - self.assert_fig_hash('5151ade23440beeea9ff144245f81b057c0fa2cd', fig) + fig = self.plot.network().node("a").link("b").gaussian(scn=0) + self.assert_fig_hash("5151ade23440beeea9ff144245f81b057c0fa2cd", fig) def test_storage(self): - study = Study(horizon=4)\ - .network()\ - .node('a')\ - .production(name='nuclear', cost=20, quantity=[10, 10, 10, 0]) \ - .node('b')\ - .consumption(name='load', cost=10 ** 6, quantity=[20, 10, 0, 10]) \ - .storage(name='cell', capacity=30, flow_in=10, flow_out=10, init_capacity=15, eff=.5) \ - .link(src='a', dest='b', cost=1, quantity=10)\ + study = ( + Study(horizon=4) + .network() + .node("a") + .production(name="nuclear", cost=20, quantity=[10, 10, 10, 0]) + .node("b") + .consumption(name="load", cost=10 ** 6, quantity=[20, 10, 0, 10]) + .storage( + name="cell", + capacity=30, + flow_in=10, + flow_out=10, + init_capacity=15, + eff=0.5, + ) + .link(src="a", dest="b", cost=1, quantity=10) .build() + ) optimizer = LPOptimizer() res = optimizer.solve(study) - plot = HTMLPlotting(agg=ResultAnalyzer(study, res), unit_symbol='MW', time_start='2020-02-01', time_end='2020-02-02') + plot = HTMLPlotting( + agg=ResultAnalyzer(study, res), + unit_symbol="MW", + time_start="2020-02-01", + time_end="2020-02-02", + ) - fig = plot.network().node('b').stack() - self.assert_fig_hash('94760e8b7d07704cfe4132a918b4075f5f594d69', fig) + fig = plot.network().node("b").stack() + self.assert_fig_hash("94760e8b7d07704cfe4132a918b4075f5f594d69", fig) - fig = plot.network().node('b').storage('cell').candles(scn=0) - self.assert_fig_hash('594ae603876c2d1bc91899e89d6de50bf37071ee', fig) + fig = plot.network().node("b").storage("cell").candles(scn=0) + self.assert_fig_hash("594ae603876c2d1bc91899e89d6de50bf37071ee", fig) - fig = plot.network().node('b').storage('cell').monotone(scn=0) - self.assert_fig_hash('f020d7954b2fa2245001a4b34530d65ddbd87382', fig) + fig = plot.network().node("b").storage("cell").monotone(scn=0) + self.assert_fig_hash("f020d7954b2fa2245001a4b34530d65ddbd87382", fig) def test_converter(self): - study = Study(horizon=2)\ - .network('elec')\ - .node('a')\ - .consumption(name='load', cost=10**6, quantity=[10, 30])\ - .network('gas')\ - .node('b')\ - .production(name='central', cost=10, quantity=50)\ - .to_converter(name='conv', ratio=0.8)\ - .network('coat')\ - .node('c')\ - .production(name='central', cost=10, quantity=60)\ - .to_converter(name='conv', ratio=0.5)\ - .converter(name='conv', to_network='elec', to_node='a', max=50)\ + study = ( + Study(horizon=2) + .network("elec") + .node("a") + .consumption(name="load", cost=10 ** 6, quantity=[10, 30]) + .network("gas") + .node("b") + .production(name="central", cost=10, quantity=50) + .to_converter(name="conv", ratio=0.8) + .network("coat") + .node("c") + .production(name="central", cost=10, quantity=60) + .to_converter(name="conv", ratio=0.5) + .converter(name="conv", to_network="elec", to_node="a", max=50) .build() + ) optim = LPOptimizer() res = optim.solve(study) - plot = HTMLPlotting(agg=ResultAnalyzer(study, res), unit_symbol='MW', time_start='2020-02-01', - time_end='2020-02-02') + plot = HTMLPlotting( + agg=ResultAnalyzer(study, res), + unit_symbol="MW", + time_start="2020-02-01", + time_end="2020-02-02", + ) - fig = plot.network('elec').node('a').stack() - self.assert_fig_hash('0969b8b1bde6695a4c8cc78fdc5a42928f7af956', fig) + fig = plot.network("elec").node("a").stack() + self.assert_fig_hash("0969b8b1bde6695a4c8cc78fdc5a42928f7af956", fig) - fig = plot.network('gas').node('b').stack() - self.assert_fig_hash('d9a5c9f13c932048f1bcb22ec849a7a4e79b577b', fig) + fig = plot.network("gas").node("b").stack() + self.assert_fig_hash("d9a5c9f13c932048f1bcb22ec849a7a4e79b577b", fig) - fig = plot.network('elec').node('a').from_converter('conv').timeline() - self.assert_fig_hash('5a42ce7a62c12c092631f0a9b63f807ada94ed79', fig) + fig = plot.network("elec").node("a").from_converter("conv").timeline() + self.assert_fig_hash("5a42ce7a62c12c092631f0a9b63f807ada94ed79", fig) - fig = plot.network('gas').node('b').to_converter('conv').timeline() - self.assert_fig_hash('77de14a806dff91a118d395b3e0d998335d64cd7', fig) + fig = plot.network("gas").node("b").to_converter("conv").timeline() + self.assert_fig_hash("77de14a806dff91a118d395b3e0d998335d64cd7", fig) - fig = plot.network('gas').node('b').to_converter('conv').monotone(scn=0) - self.assert_fig_hash('3f6ac9f5e1c8ca611d39b7c62f527e4bfd5a573a', fig) + fig = plot.network("gas").node("b").to_converter("conv").monotone(scn=0) + self.assert_fig_hash("3f6ac9f5e1c8ca611d39b7c62f527e4bfd5a573a", fig) - fig = plot.network('elec').node('a').from_converter('conv').gaussian(scn=0) - self.assert_fig_hash('32a6e175600822c833a9b7f3008aa35230b0b646', fig) + fig = plot.network("elec").node("a").from_converter("conv").gaussian(scn=0) + self.assert_fig_hash("32a6e175600822c833a9b7f3008aa35230b0b646", fig) def assert_fig_hash(self, expected: str, fig: go.Figure): # if sys.platform != 'darwin' or (ma, mi) != (3, 7): # We only test graphics for MacOS, there are little change with other distrib @@ -159,8 +186,10 @@ def assert_fig_hash(self, expected: str, fig: go.Figure): @staticmethod def get_html(fig: go.Figure) -> bytes: - html = plot(fig, include_plotlyjs=False, include_mathjax=False, output_type='div') + html = plot( + fig, include_plotlyjs=False, include_mathjax=False, output_type="div" + ) # plotly use a random id. We need to extract it and replace it by constant # uuid can be find at ...