From 8210a4dbe776d922b71a5d16458f19800d650588 Mon Sep 17 00:00:00 2001 From: ahalev Date: Sat, 3 Dec 2022 14:51:07 -0800 Subject: [PATCH 01/20] rename fixed/flex/static to fixed/flex/controllable --- src/pymgrid/modules/module_container.py | 26 ++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/pymgrid/modules/module_container.py b/src/pymgrid/modules/module_container.py index e6b5aeed..2a267227 100644 --- a/src/pymgrid/modules/module_container.py +++ b/src/pymgrid/modules/module_container.py @@ -174,23 +174,23 @@ def get_subcontainers(modules): """ :return: List[Tuple] - 3-element tuples of (fixed_flex_static, source_or_sink, container) + 3-element tuples of (fixed_flex_controllable, source_or_sink, container) """ source_sink_keys = ('sources' , 'sinks', 'source_and_sinks') fixed = {k: dict() for k in source_sink_keys} flex = {k: dict() for k in source_sink_keys} - static = {k: dict() for k in source_sink_keys} + controllable = {k: dict() for k in source_sink_keys} module_names = dict() for module in modules: try: # module is a tuple module_name, module = module - fixed_flex_static = module.__class__.module_type[1] + fixed_flex_controllable = module.__class__.module_type[1] except TypeError: # module is a module try: - module_name, fixed_flex_static = module.__class__.module_type + module_name, fixed_flex_controllable = module.__class__.module_type except TypeError: raise NotImplementedError( f'Must define the class attribute module_type for class {module.__class__.__name__}') @@ -201,19 +201,19 @@ def get_subcontainers(modules): source_sink_both = 'source_and_sinks' if module.is_sink and module.is_source else \ 'sources' if module.is_source else 'sinks' - if fixed_flex_static == 'fixed': + if fixed_flex_controllable == 'fixed': d = fixed - elif fixed_flex_static == 'flex': + elif fixed_flex_controllable == 'flex': d = flex - elif fixed_flex_static == 'static': - d = static + elif fixed_flex_controllable == 'controllable': + d = controllable else: - raise TypeError(f'Cannot parse fixed_flex_static from module type {module.__class__.module_type}') + raise TypeError(f'Cannot parse fixed_flex_controllable from module type {module.__class__.module_type}') try: - module_names[module_name] = (fixed_flex_static, source_sink_both) + module_names[module_name] = (fixed_flex_controllable, source_sink_both) except KeyError: - raise NameError(f'Attempted to add module {module_name} of type {(fixed_flex_static, source_sink_both)}, ' + raise NameError(f'Attempted to add module {module_name} of type {(fixed_flex_controllable, source_sink_both)}, ' f'but there is an identically named module of type {module_names[module_name]}.') try: @@ -224,10 +224,10 @@ def get_subcontainers(modules): modules_dict = dict(fixed=fixed, flex=flex, - static=static) + controllable=controllable) containers = {(ffs, source_sink_both): _ModuleSubContainer(modules_dict[ffs][source_sink_both]) - for ffs in ('fixed', 'flex', 'static') + for ffs in ('fixed', 'flex', 'controllable') for source_sink_both in source_sink_keys} return containers From b88257833cb45c34e2ca57c81ab997c63695bca9 Mon Sep 17 00:00:00 2001 From: ahalev Date: Sat, 3 Dec 2022 15:00:17 -0800 Subject: [PATCH 02/20] rename fixed to controllable and static to fixed --- src/pymgrid/microgrid/microgrid.py | 19 +++++++++++++++---- src/pymgrid/modules/base/base_module.py | 8 +++++++- src/pymgrid/modules/battery_module.py | 2 +- src/pymgrid/modules/genset_module.py | 2 +- src/pymgrid/modules/grid_module.py | 2 +- src/pymgrid/modules/load_module.py | 2 +- src/pymgrid/modules/module_container.py | 2 +- 7 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/pymgrid/microgrid/microgrid.py b/src/pymgrid/microgrid/microgrid.py index 162dc694..b3a45e9e 100644 --- a/src/pymgrid/microgrid/microgrid.py +++ b/src/pymgrid/microgrid/microgrid.py @@ -181,11 +181,11 @@ def run(self, control, normalized=True): control_copy = control.copy() microgrid_step = MicrogridStep() - for name, modules in self.static.iterdict(): + for name, modules in self.fixed.iterdict(): for module in modules: microgrid_step.append(name, *module.step(0.0, normalized=False)) - for name, modules in self.fixed.iterdict(): + for name, modules in self.controllable.iterdict(): try: module_controls = control_copy.pop(name) except KeyError: @@ -278,7 +278,7 @@ def sample_action(self, strict_bound=False, sample_flex_modules=False): """ - module_iterator = self._modules.module_dict() if sample_flex_modules else self._modules.fixed.module_dict() + module_iterator = self._modules.module_dict() if sample_flex_modules else self._modules.controllable.module_dict() return {module_name: [module.sample_action(strict_bound=strict_bound) for module in module_list] for module_name, module_list in module_iterator.items() if module_list[0].action_space.shape[0]} @@ -302,7 +302,7 @@ def get_empty_action(self, sample_flex_modules=False): Empty action. """ - module_iterator = self._modules.module_dict() if sample_flex_modules else self._modules.fixed.module_dict() + module_iterator = self._modules.module_dict() if sample_flex_modules else self._modules.controllable.module_dict() return {module_name: [None]*len(module_list) for module_name, module_list in module_iterator.items() if module_list[0].action_space.shape[0]} @@ -484,6 +484,17 @@ def flex(self): """ return self._modules.flex + @property + def controllable(self): + """ + List of all controllable modules in the microgrid. + + Returns + ------- + list of modules + """ + return self._modules.controllable + @property def module_list(self): """ diff --git a/src/pymgrid/modules/base/base_module.py b/src/pymgrid/modules/base/base_module.py index 8a210ab2..6bc90a4a 100644 --- a/src/pymgrid/modules/base/base_module.py +++ b/src/pymgrid/modules/base/base_module.py @@ -241,6 +241,9 @@ def as_source(self, energy_demand): f'module is not a source and ' \ f'can only be called with negative energy.' + if self.module_type[-1] == 'fixed': + return self.update(None, as_source=True) + if energy_demand > self.max_production: if self.raise_errors: self._raise_error(energy_demand, self.max_production, as_source=True) @@ -290,6 +293,9 @@ def as_sink(self, energy_excess): assert energy_excess >= 0 + if self.module_type[-1] == 'fixed': + return self.update(None, as_sink=True) + if energy_excess > self.max_consumption: if self.raise_errors: self._raise_error(energy_excess, self.max_consumption, as_sink=True) @@ -324,7 +330,7 @@ def update(self, external_energy_change, as_source=False, as_sink=False): Parameters ---------- - external_energy_change : float + external_energy_change : float or None Amount of energy to provide or absorb. as_source : bool Whether the module is acting as a source. diff --git a/src/pymgrid/modules/battery_module.py b/src/pymgrid/modules/battery_module.py index bc81999c..c4b68445 100644 --- a/src/pymgrid/modules/battery_module.py +++ b/src/pymgrid/modules/battery_module.py @@ -58,7 +58,7 @@ class BatteryModule(BaseMicrogridModule): If False, actions are clipped to the limit possible. """ - module_type = ('battery', 'fixed') + module_type = ('battery', 'controllable') yaml_tag = f"!BatteryModule" yaml_dumper = yaml.SafeDumper yaml_loader = yaml.SafeLoader diff --git a/src/pymgrid/modules/genset_module.py b/src/pymgrid/modules/genset_module.py index 0bf04911..7bc0a6ac 100644 --- a/src/pymgrid/modules/genset_module.py +++ b/src/pymgrid/modules/genset_module.py @@ -51,7 +51,7 @@ class GensetModule(BaseMicrogridModule): Name of the energy provided by this module, to be used in logging. """ - module_type = 'genset', 'fixed' + module_type = 'genset', 'controllable' yaml_tag = f"!Genset" yaml_dumper = yaml.SafeDumper yaml_loader = yaml.SafeLoader diff --git a/src/pymgrid/modules/grid_module.py b/src/pymgrid/modules/grid_module.py index dcb013c3..8b2a1f27 100644 --- a/src/pymgrid/modules/grid_module.py +++ b/src/pymgrid/modules/grid_module.py @@ -62,7 +62,7 @@ class GridModule(BaseTimeSeriesMicrogridModule): """ - module_type = ('grid', 'fixed') + module_type = ('grid', 'controllable') yaml_tag = u"!GridModule" yaml_loader = yaml.SafeLoader diff --git a/src/pymgrid/modules/load_module.py b/src/pymgrid/modules/load_module.py index bc82dc55..4eab0bb7 100644 --- a/src/pymgrid/modules/load_module.py +++ b/src/pymgrid/modules/load_module.py @@ -48,7 +48,7 @@ class LoadModule(BaseTimeSeriesMicrogridModule): If False, actions are clipped to the limit possible. """ - module_type = ('load', 'static') + module_type = ('load', 'fixed') yaml_tag = u"!LoadModule" yaml_dumper = yaml.SafeDumper yaml_loader = yaml.SafeLoader diff --git a/src/pymgrid/modules/module_container.py b/src/pymgrid/modules/module_container.py index 2a267227..782036fb 100644 --- a/src/pymgrid/modules/module_container.py +++ b/src/pymgrid/modules/module_container.py @@ -177,7 +177,7 @@ def get_subcontainers(modules): 3-element tuples of (fixed_flex_controllable, source_or_sink, container) """ - source_sink_keys = ('sources' , 'sinks', 'source_and_sinks') + source_sink_keys = ('sources', 'sinks', 'source_and_sinks') fixed = {k: dict() for k in source_sink_keys} flex = {k: dict() for k in source_sink_keys} controllable = {k: dict() for k in source_sink_keys} From 0a1a72689219a8d7397224d7fdd3c483d90799f1 Mon Sep 17 00:00:00 2001 From: ahalev Date: Fri, 2 Dec 2022 16:39:00 -0800 Subject: [PATCH 03/20] add retain_modules kwarg --- tests/helpers/modular_microgrid.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/tests/helpers/modular_microgrid.py b/tests/helpers/modular_microgrid.py index 96b527f1..5c2fae87 100644 --- a/tests/helpers/modular_microgrid.py +++ b/tests/helpers/modular_microgrid.py @@ -11,7 +11,7 @@ ) -def get_modular_microgrid(remove_modules=(), additional_modules=None, add_unbalanced_module=True): +def get_modular_microgrid(remove_modules=(), retain_only=None, additional_modules=None, add_unbalanced_module=True): modules = dict( genset=GensetModule(running_min_production=10, running_max_production=50, genset_cost=0.5), @@ -30,11 +30,16 @@ def get_modular_microgrid(remove_modules=(), additional_modules=None, add_unbala grid=GridModule(max_import=100, max_export=0, time_series=np.ones((100, 3)), raise_errors=True) ) - for module in remove_modules: - try: - modules.pop(module) - except KeyError: - raise NameError(f"Module {module} not one of default modules {list(modules.keys())}.") + if retain_only is not None: + modules = {k: v for k, v in modules.items() if k in retain_only} + if remove_modules: + raise RuntimeError('Can pass either remove_modules or retain_only, but not both.') + else: + for module in remove_modules: + try: + modules.pop(module) + except KeyError: + raise NameError(f"Module {module} not one of default modules {list(modules.keys())}.") modules = list(modules.values()) modules.extend(additional_modules if additional_modules else []) From 15aa70a8997acfd8604ae9680f417fa9710b9ffe Mon Sep 17 00:00:00 2001 From: ahalev Date: Fri, 2 Dec 2022 16:39:18 -0800 Subject: [PATCH 04/20] add some additional unittests --- tests/microgrid/test_microgrid.py | 67 +++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/tests/microgrid/test_microgrid.py b/tests/microgrid/test_microgrid.py index 20c0c274..d350785a 100644 --- a/tests/microgrid/test_microgrid.py +++ b/tests/microgrid/test_microgrid.py @@ -1,6 +1,7 @@ import numpy as np from pymgrid import Microgrid +from pymgrid.modules import LoadModule, RenewableModule from tests.helpers.modular_microgrid import get_modular_microgrid from tests.helpers.test_case import TestCase @@ -65,3 +66,69 @@ def test_sample_action_all_modules_populated(self): has_corresponding_action = False self.assertTrue(empty_action_space != has_corresponding_action) # XOR + + +class TestMicrogridLoadPV(TestCase): + def setUp(self): + self.load_ts, self.pv_ts = self.set_ts() + self.microgrid = self.set_microgrid() + + def set_ts(self): + ts = 10 * np.random.rand(100) + return ts, ts + + def set_microgrid(self): + load = LoadModule(time_series=self.load_ts, raise_errors=True) + pv = RenewableModule(time_series=self.pv_ts, raise_errors=True) + return Microgrid([load, pv]) + + def test_populated_correctly(self): + self.assertTrue(hasattr(self.microgrid.modules, 'load')) + self.assertTrue(hasattr(self.microgrid.modules, 'renewable')) + self.assertEqual(len(self.microgrid.modules), 3) # load, pv, unbalanced + + def test_current_load_correct(self): + self.assertEqual(self.microgrid.modules.load[0].current_load, self.load_ts[0]) + + def test_current_pv_correct(self): + self.assertEqual(self.microgrid.modules.renewable[0].current_renewable, self.pv_ts[0]) + + def test_run_one_step(self): + pass + + def test_run_n_steps(self): + for step in range(len(self.load_ts)): + with self.subTest(step=step): + pass + + +class TestMicrogridLoadExcessPV(TestMicrogridLoadPV): + # Same as above but pv is greater than load. + def set_ts(self): + load_ts = 10*np.random.rand(100) + pv_ts = load_ts + 5*np.random.rand(100) + return load_ts, pv_ts + + def test_run_one_step(self): + pass + + def test_run_n_steps(self): + for step in range(len(self.load_ts)): + with self.subTest(step=step): + pass + + +class TestMicrogridPVExcessLoad(TestMicrogridLoadPV): + # Load greater than PV. + def set_ts(self): + pv_ts = 10 * np.random.rand(100) + load_ts = pv_ts + 5 * np.random.rand(100) + return load_ts, pv_ts + + def test_run_one_step(self): + pass + + def test_run_n_steps(self): + for step in range(len(self.load_ts)): + with self.subTest(step=step): + pass From 66b97ffb2ee4eddf5efc0c7f596158f43898d2eb Mon Sep 17 00:00:00 2001 From: ahalev Date: Sat, 3 Dec 2022 14:42:38 -0800 Subject: [PATCH 05/20] new pv-load only tests --- tests/microgrid/test_microgrid.py | 35 ++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/tests/microgrid/test_microgrid.py b/tests/microgrid/test_microgrid.py index d350785a..09743876 100644 --- a/tests/microgrid/test_microgrid.py +++ b/tests/microgrid/test_microgrid.py @@ -1,4 +1,5 @@ import numpy as np +from copy import deepcopy from pymgrid import Microgrid from pymgrid.modules import LoadModule, RenewableModule @@ -94,7 +95,39 @@ def test_current_pv_correct(self): self.assertEqual(self.microgrid.modules.renewable[0].current_renewable, self.pv_ts[0]) def test_run_one_step(self): - pass + microgrid = deepcopy(self.microgrid) + control = self.microgrid.get_empty_action() + self.assertEqual(len(control), 0) + + obs, reward, done, info = microgrid.run(control) + loss_load = self.load_ts[0]-self.pv_ts[0] + loss_load_cost = self.microgrid.modules.balancing[0].loss_load_cost * max(loss_load, 0) + + self.assertEqual(loss_load_cost, -1*reward) + + self.assertEqual(len(microgrid.log), 1) + self.assertTrue(all(module in microgrid.log for module in microgrid.modules.names())) + + load_met = min(self.load_ts[0], self.pv_ts[0]) + loss_load = max(self.load_ts[0] - load_met, 0) + pv_curtailment = max(self.pv_ts[0]-load_met, 0) + + # Checking the log populated correctly. + self.assertEqual(microgrid.log['load', 0, 'load_current'], -1 * self.load_ts[0]) + self.assertEqual(microgrid.log[('load', 0, 'load_met')], load_met) + + self.assertEqual(microgrid.log[('renewable', 0, 'renewable_current')], load_met) + self.assertEqual(microgrid.log[('renewable', 0, 'renewable_used')], load_met) + self.assertEqual(microgrid.log[('renewable', 0, 'pv_curtailment')], pv_curtailment) + + self.assertEqual(microgrid.log[('balancing', 0, 'loss_load')], loss_load) + + self.assertEqual(microgrid.log[('balance', 0, 'reward')], 0.0) + self.assertEqual(microgrid.log[('balance', 0, 'overall_provided_to_microgrid')], load_met) + self.assertEqual(microgrid.log[('balance', 0, 'overall_absorbed_by_microgrid')], load_met) + self.assertEqual(microgrid.log[('balance', 0, 'fixed_provided_to_microgrid')], 0.0) + self.assertEqual(microgrid.log[('balance', 0, 'fixed_absorbed_by_microgrid')], 0.0) + self.assertEqual(microgrid.log[('balance', 0, 'static_absorbed_by_microgrid')], load_met) def test_run_n_steps(self): for step in range(len(self.load_ts)): From e805d8b4a7cee9544f2f508bd91c6544ad060617 Mon Sep 17 00:00:00 2001 From: ahalev Date: Sat, 3 Dec 2022 14:47:12 -0800 Subject: [PATCH 06/20] change key in test --- tests/microgrid/test_microgrid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/microgrid/test_microgrid.py b/tests/microgrid/test_microgrid.py index 09743876..3a13156f 100644 --- a/tests/microgrid/test_microgrid.py +++ b/tests/microgrid/test_microgrid.py @@ -118,7 +118,7 @@ def test_run_one_step(self): self.assertEqual(microgrid.log[('renewable', 0, 'renewable_current')], load_met) self.assertEqual(microgrid.log[('renewable', 0, 'renewable_used')], load_met) - self.assertEqual(microgrid.log[('renewable', 0, 'pv_curtailment')], pv_curtailment) + self.assertEqual(microgrid.log[('renewable', 0, 'curtailment')], pv_curtailment) self.assertEqual(microgrid.log[('balancing', 0, 'loss_load')], loss_load) From efffff513c3e3bfee1fb914dc7b1294a158dd025 Mon Sep 17 00:00:00 2001 From: ahalev Date: Sat, 3 Dec 2022 15:09:40 -0800 Subject: [PATCH 07/20] rename absorbed_by to absorbed_from --- src/pymgrid/microgrid/microgrid.py | 8 ++++++-- tests/microgrid/test_microgrid.py | 9 +++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/pymgrid/microgrid/microgrid.py b/src/pymgrid/microgrid/microgrid.py index b3a45e9e..eef94932 100644 --- a/src/pymgrid/microgrid/microgrid.py +++ b/src/pymgrid/microgrid/microgrid.py @@ -185,6 +185,9 @@ def run(self, control, normalized=True): for module in modules: microgrid_step.append(name, *module.step(0.0, normalized=False)) + fixed_provided, fixed_consumed, _ = microgrid_step.balance() + log_dict = self._get_log_dict(fixed_provided, fixed_consumed, prefix='fixed') + for name, modules in self.controllable.iterdict(): try: module_controls = control_copy.pop(name) @@ -203,7 +206,8 @@ def run(self, control, normalized=True): provided, consumed, _ = microgrid_step.balance() difference = provided - consumed # if difference > 0, have an excess. Try to use flex sinks to dissapate # otherwise, insufficient. Use flex sources to make up - log_dict = self._get_log_dict(provided, consumed, prefix='fixed') + + log_dict = self._get_log_dict(provided-fixed_provided, consumed-fixed_consumed, log_dict=log_dict, prefix='controllable') if len(control_copy) > 0: warn(f'\nIgnoring the following keys in passed control:\n {list(control_copy.keys())}') @@ -250,7 +254,7 @@ def run(self, control, normalized=True): return microgrid_step.output() def _get_log_dict(self, provided_energy, absorbed_energy, log_dict=None, prefix=None): - _log_dict = dict(provided_to_microgrid=provided_energy, absorbed_by_microgrid=absorbed_energy) + _log_dict = dict(provided_to_microgrid=provided_energy, absorbed_from_microgrid=absorbed_energy) _log_dict = {(prefix + '_' + k if prefix is not None else k): v for k, v in _log_dict.items()} if log_dict: _log_dict.update(log_dict) diff --git a/tests/microgrid/test_microgrid.py b/tests/microgrid/test_microgrid.py index 3a13156f..38fdcc6b 100644 --- a/tests/microgrid/test_microgrid.py +++ b/tests/microgrid/test_microgrid.py @@ -124,17 +124,18 @@ def test_run_one_step(self): self.assertEqual(microgrid.log[('balance', 0, 'reward')], 0.0) self.assertEqual(microgrid.log[('balance', 0, 'overall_provided_to_microgrid')], load_met) - self.assertEqual(microgrid.log[('balance', 0, 'overall_absorbed_by_microgrid')], load_met) + self.assertEqual(microgrid.log[('balance', 0, 'overall_absorbed_from_microgrid')], load_met) self.assertEqual(microgrid.log[('balance', 0, 'fixed_provided_to_microgrid')], 0.0) - self.assertEqual(microgrid.log[('balance', 0, 'fixed_absorbed_by_microgrid')], 0.0) - self.assertEqual(microgrid.log[('balance', 0, 'static_absorbed_by_microgrid')], load_met) + self.assertEqual(microgrid.log[('balance', 0, 'fixed_absorbed_from_microgrid')], load_met) + self.assertEqual(microgrid.log[('balance', 0, 'controllable_absorbed_from_microgrid')], 0.0) + self.assertEqual(microgrid.log[('balance', 0, 'controllable_provided_to_microgrid')], 0.0) + def test_run_n_steps(self): for step in range(len(self.load_ts)): with self.subTest(step=step): pass - class TestMicrogridLoadExcessPV(TestMicrogridLoadPV): # Same as above but pv is greater than load. def set_ts(self): From a7160d5f9bd7e059c3df800c8d54e9d36f0b0458 Mon Sep 17 00:00:00 2001 From: ahalev Date: Sun, 4 Dec 2022 16:22:38 -0800 Subject: [PATCH 08/20] add pytest-subtests dependency --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 6cb499cb..7b3618eb 100644 --- a/setup.py +++ b/setup.py @@ -16,6 +16,7 @@ EXTRAS["genset_mpc"] = ["Mosek", "cvxopt"] EXTRAS["dev"] = [ "pytest", + "pytest-subtests", "flake8", "sphinx", "pydata_sphinx_theme", From 9c532794b5b24163e102891053dffc6a51a1462c Mon Sep 17 00:00:00 2001 From: ahalev Date: Sun, 4 Dec 2022 16:23:03 -0800 Subject: [PATCH 09/20] update assertEqual to better handle close but not exact --- tests/helpers/test_case.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/helpers/test_case.py b/tests/helpers/test_case.py index cc860c9f..90fb3a9c 100644 --- a/tests/helpers/test_case.py +++ b/tests/helpers/test_case.py @@ -7,9 +7,8 @@ class TestCase(unittest.TestCase): def assertEqual(self, first, second, msg=None) -> None: try: super().assertEqual(first, second, msg=msg) - except ValueError: + except (ValueError, AssertionError): try: np.testing.assert_equal(first, second, err_msg=msg if msg else '') - except AssertionError as e: - np.testing.assert_allclose(first, second, err_msg=msg if msg else '') - warn(f"Arrays are close but not equal: {e.args[0]}") + except AssertionError: + np.testing.assert_allclose(first, second, rtol=1e-7, atol=1e-10, err_msg=msg if msg else '') From 83940a1f771be3b8626542dbff144cd3ae7852fc Mon Sep 17 00:00:00 2001 From: ahalev Date: Sun, 4 Dec 2022 16:44:34 -0800 Subject: [PATCH 10/20] pass float current_renewable --- src/pymgrid/modules/renewable_module.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pymgrid/modules/renewable_module.py b/src/pymgrid/modules/renewable_module.py index 6125ba75..a7776902 100644 --- a/src/pymgrid/modules/renewable_module.py +++ b/src/pymgrid/modules/renewable_module.py @@ -99,7 +99,7 @@ def current_renewable(self): Renewable production. """ - return self._time_series[self._current_step] + return self._time_series[self._current_step].item() @property def is_source(self): From b5edefa9a2b697af92aa310c53319159912b836e Mon Sep 17 00:00:00 2001 From: ahalev Date: Sun, 4 Dec 2022 17:16:58 -0800 Subject: [PATCH 11/20] change current_renewable accesses to recognize val as float --- src/pymgrid/convert/to_nonmodular_ops.py | 2 +- src/pymgrid/modules/renewable_module.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/pymgrid/convert/to_nonmodular_ops.py b/src/pymgrid/convert/to_nonmodular_ops.py index 0d171d64..9cb8603f 100644 --- a/src/pymgrid/convert/to_nonmodular_ops.py +++ b/src/pymgrid/convert/to_nonmodular_ops.py @@ -91,7 +91,7 @@ def add_pv_params(pv_module, params_dict): _add_to_architecture(params_dict, 'PV') _add_to_parameters(params_dict, PV_rated_power=pv_module.max_act) _add_to_df_actions(params_dict, 'pv_consummed','pv_curtailed','pv') - _add_to_df_status(params_dict, pv=[pv_module.current_renewable.item()]) + _add_to_df_status(params_dict, pv=[pv_module.current_renewable]) _add_to_df_actual_generation(params_dict, 'pv_consummed','pv_curtailed') _add_to_control_dict(params_dict, 'pv_consummed', 'pv_curtailed', 'pv') diff --git a/src/pymgrid/modules/renewable_module.py b/src/pymgrid/modules/renewable_module.py index a7776902..c75fafff 100644 --- a/src/pymgrid/modules/renewable_module.py +++ b/src/pymgrid/modules/renewable_module.py @@ -76,7 +76,8 @@ def update(self, external_energy_change, as_source=False, as_sink=False): assert as_source, f'Class {self.__class__.__name__} can only be used as a source.' assert external_energy_change <= self.current_renewable, f'Cannot provide more than {self.current_renewable}' - info = {'provided_energy': external_energy_change, 'curtailment': self.current_renewable.item()-external_energy_change} + info = {'provided_energy': external_energy_change, + 'curtailment': self.current_renewable-external_energy_change} return 0.0, self._done(), info From f44590118fa80f76a5acf6bcf1ae1552420f1dae Mon Sep 17 00:00:00 2001 From: ahalev Date: Sun, 4 Dec 2022 17:17:13 -0800 Subject: [PATCH 12/20] update microgrid tests --- tests/microgrid/test_microgrid.py | 136 +++++++++++++++++++++--------- 1 file changed, 94 insertions(+), 42 deletions(-) diff --git a/tests/microgrid/test_microgrid.py b/tests/microgrid/test_microgrid.py index 38fdcc6b..fd587d71 100644 --- a/tests/microgrid/test_microgrid.py +++ b/tests/microgrid/test_microgrid.py @@ -1,5 +1,6 @@ import numpy as np -from copy import deepcopy +import pandas as pd + from pymgrid import Microgrid from pymgrid.modules import LoadModule, RenewableModule @@ -72,7 +73,7 @@ def test_sample_action_all_modules_populated(self): class TestMicrogridLoadPV(TestCase): def setUp(self): self.load_ts, self.pv_ts = self.set_ts() - self.microgrid = self.set_microgrid() + self.microgrid, self.n_modules = self.set_microgrid() def set_ts(self): ts = 10 * np.random.rand(100) @@ -81,60 +82,99 @@ def set_ts(self): def set_microgrid(self): load = LoadModule(time_series=self.load_ts, raise_errors=True) pv = RenewableModule(time_series=self.pv_ts, raise_errors=True) - return Microgrid([load, pv]) + return Microgrid([load, pv]), 3 def test_populated_correctly(self): self.assertTrue(hasattr(self.microgrid.modules, 'load')) self.assertTrue(hasattr(self.microgrid.modules, 'renewable')) - self.assertEqual(len(self.microgrid.modules), 3) # load, pv, unbalanced + self.assertEqual(len(self.microgrid.modules), self.n_modules) # load, pv, unbalanced def test_current_load_correct(self): - self.assertEqual(self.microgrid.modules.load[0].current_load, self.load_ts[0]) + try: + current_load = self.microgrid.modules.load.item().current_load + except ValueError: + # More than one load module + current_load = sum(load.current_load for load in self.microgrid.modules.load) + self.assertEqual(current_load, self.load_ts[0]) def test_current_pv_correct(self): - self.assertEqual(self.microgrid.modules.renewable[0].current_renewable, self.pv_ts[0]) + try: + current_renewable = self.microgrid.modules.renewable.item().current_renewable + except ValueError: + # More than one load module + current_renewable = sum(renewable.current_renewable for renewable in self.microgrid.modules.renewable) + self.assertEqual(current_renewable, self.pv_ts[0]) - def test_run_one_step(self): - microgrid = deepcopy(self.microgrid) - control = self.microgrid.get_empty_action() + def test_sample_action(self): + sampled_action = self.microgrid.sample_action() + self.assertEqual(len(sampled_action), 0) + + def test_sample_action_with_flex(self): + sampled_action = self.microgrid.sample_action(sample_flex_modules=True) + self.assertEqual(len(sampled_action), 2) + self.assertIn('renewable', sampled_action) + self.assertIn('balancing', sampled_action) + self.assertEqual(len(sampled_action['renewable']), len(self.microgrid.modules.renewable)) + + def check_step(self, microgrid, step_number=0): + + control = microgrid.get_empty_action() self.assertEqual(len(control), 0) obs, reward, done, info = microgrid.run(control) - loss_load = self.load_ts[0]-self.pv_ts[0] + loss_load = self.load_ts[step_number]-self.pv_ts[step_number] loss_load_cost = self.microgrid.modules.balancing[0].loss_load_cost * max(loss_load, 0) self.assertEqual(loss_load_cost, -1*reward) - self.assertEqual(len(microgrid.log), 1) + self.assertEqual(len(microgrid.log), step_number + 1) self.assertTrue(all(module in microgrid.log for module in microgrid.modules.names())) - load_met = min(self.load_ts[0], self.pv_ts[0]) - loss_load = max(self.load_ts[0] - load_met, 0) - pv_curtailment = max(self.pv_ts[0]-load_met, 0) + load_met = min(self.load_ts[step_number], self.pv_ts[step_number]) + loss_load = max(self.load_ts[step_number] - load_met, 0) + pv_curtailment = max(self.pv_ts[step_number]-load_met, 0) # Checking the log populated correctly. - self.assertEqual(microgrid.log['load', 0, 'load_current'], -1 * self.load_ts[0]) - self.assertEqual(microgrid.log[('load', 0, 'load_met')], load_met) - self.assertEqual(microgrid.log[('renewable', 0, 'renewable_current')], load_met) - self.assertEqual(microgrid.log[('renewable', 0, 'renewable_used')], load_met) - self.assertEqual(microgrid.log[('renewable', 0, 'curtailment')], pv_curtailment) + log_row = microgrid.log.iloc[step_number] + log_entry = lambda module, entry: log_row.loc[pd.IndexSlice[module, :, entry]].sum() + + # Check that there are log entries for all modules of each name + self.assertEqual(log_row['load'].index.get_level_values(0).nunique(), len(microgrid.modules.load)) + + self.assertEqual(log_entry('load', 'load_current'), -1 * self.load_ts[step_number]) + self.assertEqual(log_entry('load', 'load_met'), self.load_ts[step_number]) + + if loss_load == 0: + self.assertEqual(log_entry('load', 'load_met'), load_met) - self.assertEqual(microgrid.log[('balancing', 0, 'loss_load')], loss_load) + self.assertEqual(log_entry('renewable', 'renewable_current'), self.pv_ts[step_number]) + self.assertEqual(log_entry('renewable', 'renewable_used'), load_met) + self.assertEqual(log_entry('renewable', 'curtailment'), pv_curtailment) - self.assertEqual(microgrid.log[('balance', 0, 'reward')], 0.0) - self.assertEqual(microgrid.log[('balance', 0, 'overall_provided_to_microgrid')], load_met) - self.assertEqual(microgrid.log[('balance', 0, 'overall_absorbed_from_microgrid')], load_met) - self.assertEqual(microgrid.log[('balance', 0, 'fixed_provided_to_microgrid')], 0.0) - self.assertEqual(microgrid.log[('balance', 0, 'fixed_absorbed_from_microgrid')], load_met) - self.assertEqual(microgrid.log[('balance', 0, 'controllable_absorbed_from_microgrid')], 0.0) - self.assertEqual(microgrid.log[('balance', 0, 'controllable_provided_to_microgrid')], 0.0) + self.assertEqual(log_entry('balancing', 'loss_load'), loss_load) + self.assertEqual(log_entry('balance', 'reward'), -1 * loss_load_cost) + self.assertEqual(log_entry('balance', 'overall_provided_to_microgrid'), self.load_ts[step_number]) + self.assertEqual(log_entry('balance', 'overall_absorbed_from_microgrid'), self.load_ts[step_number]) + self.assertEqual(log_entry('balance', 'fixed_provided_to_microgrid'), 0.0) + self.assertEqual(log_entry('balance', 'fixed_absorbed_from_microgrid'), self.load_ts[step_number]) + self.assertEqual(log_entry('balance', 'controllable_absorbed_from_microgrid'), 0.0) + self.assertEqual(log_entry('balance', 'controllable_provided_to_microgrid'), 0.0) + + return microgrid + + def test_run_one_step(self): + microgrid = self.microgrid + self.check_step(microgrid=microgrid, step_number=0) def test_run_n_steps(self): + microgrid = self.microgrid for step in range(len(self.load_ts)): with self.subTest(step=step): - pass + microgrid = self.check_step(microgrid=microgrid, step_number=step) + break + class TestMicrogridLoadExcessPV(TestMicrogridLoadPV): # Same as above but pv is greater than load. @@ -143,14 +183,6 @@ def set_ts(self): pv_ts = load_ts + 5*np.random.rand(100) return load_ts, pv_ts - def test_run_one_step(self): - pass - - def test_run_n_steps(self): - for step in range(len(self.load_ts)): - with self.subTest(step=step): - pass - class TestMicrogridPVExcessLoad(TestMicrogridLoadPV): # Load greater than PV. @@ -159,10 +191,30 @@ def set_ts(self): load_ts = pv_ts + 5 * np.random.rand(100) return load_ts, pv_ts - def test_run_one_step(self): - pass - def test_run_n_steps(self): - for step in range(len(self.load_ts)): - with self.subTest(step=step): - pass +class TestMicrogridTwoLoads(TestMicrogridLoadPV): + def set_microgrid(self): + load_1_ts = self.load_ts*(1-np.random.rand(*self.load_ts.shape)) + load_2_ts = self.load_ts - load_1_ts + + assert all(load_1_ts > 0) + assert all(load_2_ts > 0) + + load_1 = LoadModule(time_series=load_1_ts, raise_errors=True) + load_2 = LoadModule(time_series=load_2_ts, raise_errors=True) + pv = RenewableModule(time_series=self.pv_ts, raise_errors=True) + return Microgrid([load_1, load_2, pv]), 4 + + +class TestMicrogridTwoPV(TestMicrogridLoadPV): + def set_microgrid(self): + pv_1_ts = self.pv_ts*(1-np.random.rand(*self.pv_ts.shape)) + pv_2_ts = self.pv_ts - pv_1_ts + + assert all(pv_1_ts > 0) + assert all(pv_2_ts > 0) + + load = LoadModule(time_series=self.load_ts, raise_errors=True) + pv_1 = RenewableModule(time_series=pv_1_ts, raise_errors=True) + pv_2 = RenewableModule(time_series=pv_2_ts) + return Microgrid([load, pv_1, pv_2]), 4 From e8f5d257d7b5e43e91b980a11b95eb320ccda869 Mon Sep 17 00:00:00 2001 From: ahalev Date: Sun, 4 Dec 2022 17:46:13 -0800 Subject: [PATCH 13/20] add type check when falling through to numpy assertions --- tests/helpers/test_case.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/helpers/test_case.py b/tests/helpers/test_case.py index 90fb3a9c..03c19b48 100644 --- a/tests/helpers/test_case.py +++ b/tests/helpers/test_case.py @@ -10,5 +10,8 @@ def assertEqual(self, first, second, msg=None) -> None: except (ValueError, AssertionError): try: np.testing.assert_equal(first, second, err_msg=msg if msg else '') - except AssertionError: - np.testing.assert_allclose(first, second, rtol=1e-7, atol=1e-10, err_msg=msg if msg else '') + except AssertionError as e: + try: + np.testing.assert_allclose(first, second, rtol=1e-7, atol=1e-10, err_msg=msg if msg else '') + except TypeError: + raise e From c06bcf0caa866a236e53c31b5f8a78558fd31c68 Mon Sep 17 00:00:00 2001 From: ahalev Date: Sun, 4 Dec 2022 17:46:31 -0800 Subject: [PATCH 14/20] additional microgrid tests --- tests/microgrid/test_microgrid.py | 42 +++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/tests/microgrid/test_microgrid.py b/tests/microgrid/test_microgrid.py index fd587d71..c358a078 100644 --- a/tests/microgrid/test_microgrid.py +++ b/tests/microgrid/test_microgrid.py @@ -73,7 +73,8 @@ def test_sample_action_all_modules_populated(self): class TestMicrogridLoadPV(TestCase): def setUp(self): self.load_ts, self.pv_ts = self.set_ts() - self.microgrid, self.n_modules = self.set_microgrid() + self.microgrid, self.n_loads, self.n_pvs = self.set_microgrid() + self.n_modules = 1 + self.n_loads + self.n_pvs def set_ts(self): ts = 10 * np.random.rand(100) @@ -82,7 +83,7 @@ def set_ts(self): def set_microgrid(self): load = LoadModule(time_series=self.load_ts, raise_errors=True) pv = RenewableModule(time_series=self.pv_ts, raise_errors=True) - return Microgrid([load, pv]), 3 + return Microgrid([load, pv]), 1, 1 def test_populated_correctly(self): self.assertTrue(hasattr(self.microgrid.modules, 'load')) @@ -114,7 +115,35 @@ def test_sample_action_with_flex(self): self.assertEqual(len(sampled_action), 2) self.assertIn('renewable', sampled_action) self.assertIn('balancing', sampled_action) - self.assertEqual(len(sampled_action['renewable']), len(self.microgrid.modules.renewable)) + self.assertEqual(len(sampled_action['renewable']), self.n_pvs) + + def test_state_dict(self): + sd = self.microgrid.state_dict + self.assertIn('load', sd) + self.assertIn('renewable', sd) + self.assertIn('balancing', sd) + self.assertEqual(len(sd['load']), self.n_loads) + self.assertEqual(len(sd['balancing']), 1) + + def test_state_series(self): + ss = self.microgrid.state_series + self.assertEqual({'load', 'renewable'}, set(ss.index.get_level_values(0))) + self.assertEqual(ss['load'].index.get_level_values(0).nunique(), self.n_loads) + self.assertEqual(ss['renewable'].index.get_level_values(0).nunique(), self.n_pvs) + self.assertEqual(ss['load'].index.get_level_values(0).nunique(), self.n_loads) + + def test_to_nonmodular(self): + if self.n_pvs > 1 or self.n_loads > 1: + with self.assertRaises(ValueError) as e: + self.microgrid.to_nonmodular() + self.assertIn("Cannot convert modular microgrid with multiple modules of same type", e) + + else: + nonmodular = self.microgrid.to_nonmodular() + self.assertTrue(nonmodular.architecture['PV']) + self.assertFalse(nonmodular.architecture['battery']) + self.assertFalse(nonmodular.architecture['grid']) + self.assertFalse(nonmodular.architecture['genset']) def check_step(self, microgrid, step_number=0): @@ -140,7 +169,7 @@ def check_step(self, microgrid, step_number=0): log_entry = lambda module, entry: log_row.loc[pd.IndexSlice[module, :, entry]].sum() # Check that there are log entries for all modules of each name - self.assertEqual(log_row['load'].index.get_level_values(0).nunique(), len(microgrid.modules.load)) + self.assertEqual(log_row['load'].index.get_level_values(0).nunique(), self.n_loads) self.assertEqual(log_entry('load', 'load_current'), -1 * self.load_ts[step_number]) self.assertEqual(log_entry('load', 'load_met'), self.load_ts[step_number]) @@ -173,7 +202,6 @@ def test_run_n_steps(self): for step in range(len(self.load_ts)): with self.subTest(step=step): microgrid = self.check_step(microgrid=microgrid, step_number=step) - break class TestMicrogridLoadExcessPV(TestMicrogridLoadPV): @@ -203,7 +231,7 @@ def set_microgrid(self): load_1 = LoadModule(time_series=load_1_ts, raise_errors=True) load_2 = LoadModule(time_series=load_2_ts, raise_errors=True) pv = RenewableModule(time_series=self.pv_ts, raise_errors=True) - return Microgrid([load_1, load_2, pv]), 4 + return Microgrid([load_1, load_2, pv]), 2, 1 class TestMicrogridTwoPV(TestMicrogridLoadPV): @@ -217,4 +245,4 @@ def set_microgrid(self): load = LoadModule(time_series=self.load_ts, raise_errors=True) pv_1 = RenewableModule(time_series=pv_1_ts, raise_errors=True) pv_2 = RenewableModule(time_series=pv_2_ts) - return Microgrid([load, pv_1, pv_2]), 4 + return Microgrid([load, pv_1, pv_2]), 1, 2 From b013d5c86f6aa1235548ed60f6de8559839147ac Mon Sep 17 00:00:00 2001 From: ahalev Date: Mon, 5 Dec 2022 16:57:20 -0800 Subject: [PATCH 15/20] add microgrid_logger to log additional info --- src/pymgrid/envs/discrete/discrete.py | 3 +-- src/pymgrid/microgrid/microgrid.py | 9 +++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/pymgrid/envs/discrete/discrete.py b/src/pymgrid/envs/discrete/discrete.py index 948decd8..0699f558 100644 --- a/src/pymgrid/envs/discrete/discrete.py +++ b/src/pymgrid/envs/discrete/discrete.py @@ -43,7 +43,6 @@ def __init__(self, overgeneration_cost=overgeneration_cost) self.action_space, self.actions_list = self._get_action_space() - self.log_dict = ModularLogger() def _get_action_space(self): """ @@ -150,7 +149,7 @@ def _get_action(self, action_num): return action def step(self, action): - self.log_dict.log(action=action) + self._microgrid_logger.log(action=action) microgrid_action = self._get_action(action) return super().step(microgrid_action, normalized=False) diff --git a/src/pymgrid/microgrid/microgrid.py b/src/pymgrid/microgrid/microgrid.py index eef94932..e51ce81f 100644 --- a/src/pymgrid/microgrid/microgrid.py +++ b/src/pymgrid/microgrid/microgrid.py @@ -93,6 +93,7 @@ def __init__(self, overgeneration_cost) self._balance_logger = ModularLogger() + self._microgrid_logger = ModularLogger() # log additional information. def _get_unbalanced_energy_module(self, loss_load_cost, @@ -150,7 +151,8 @@ def reset(self): """ return { **{name: [module.reset() for module in module_list] for name, module_list in self.modules.iterdict()}, - **{"balance": self._balance_logger.flush()} + **{"balance": self._balance_logger.flush(), + "other": self._microgrid_logger.flush()} } def run(self, control, normalized=True): @@ -384,9 +386,8 @@ def get_log(self, as_frame=True, drop_singleton_key=False): for key, value in self._balance_logger.to_dict().items(): _log_dict[('balance', 0, key)] = value - if hasattr(self, 'log_dict'): - for key, value in self.log_dict.items(): - _log_dict[(key, '', '')] = value + for key, value in self._microgrid_logger.items(): + _log_dict[(key, 0, '')] = value col_names = ['module_name', 'module_number', 'field'] From 296a19eb9c1b74524903e8b4c52593736f1142f2 Mon Sep 17 00:00:00 2001 From: ahalev Date: Mon, 5 Dec 2022 16:57:53 -0800 Subject: [PATCH 16/20] update discreteEnv for fixed->controllable update --- src/pymgrid/envs/discrete/discrete.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/pymgrid/envs/discrete/discrete.py b/src/pymgrid/envs/discrete/discrete.py index 0699f558..a0021470 100644 --- a/src/pymgrid/envs/discrete/discrete.py +++ b/src/pymgrid/envs/discrete/discrete.py @@ -54,19 +54,19 @@ def _get_action_space(self): :return: """ # n_actions = 2**(self.modules.fixed.) - fixed_sources = [(module.name, module.action_space['unnormalized'].shape[0], n_actions) - for module in self.modules.fixed.sources.iterlist() - for n_actions in range(module.action_space['unnormalized'].shape[0])] + controllable_sources = [(module.name, module.action_space.shape[0], n_actions) + for module in self.modules.controllable.sources.iterlist() + for n_actions in range(module.action_space.shape[0])] - fixed_sources.extend([(module.name, module.action_space['unnormalized'].shape[0], n_actions) - for module in self.modules.fixed.source_and_sinks.iterlist() - for n_actions in range(module.action_space['unnormalized'].shape[0])]) + controllable_sources.extend([(module.name, module.action_space.shape[0], n_actions) + for module in self.modules.controllable.source_and_sinks.iterlist() + for n_actions in range(module.action_space.shape[0])]) - priority_lists = list(permutations(fixed_sources)) + priority_lists = list(permutations(controllable_sources)) n_actions = len(priority_lists) if n_actions > 1000: - warn(f'Microgrid with {len(fixed_sources)} fixed source modules defines large action space with ' + warn(f'Microgrid with {len(controllable_sources)} fixed source modules defines large action space with ' f'{n_actions} elements.') space = Discrete(n_actions) From fc5586858ca6350919452893051aefb832ccebcb Mon Sep 17 00:00:00 2001 From: ahalev Date: Mon, 5 Dec 2022 16:58:30 -0800 Subject: [PATCH 17/20] remove adding load keys to action --- src/pymgrid/envs/discrete/discrete.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/pymgrid/envs/discrete/discrete.py b/src/pymgrid/envs/discrete/discrete.py index a0021470..6ae5123b 100644 --- a/src/pymgrid/envs/discrete/discrete.py +++ b/src/pymgrid/envs/discrete/discrete.py @@ -79,10 +79,6 @@ def _get_action(self, action_num): action = self.get_empty_action() loads, total_load = self._get_load() - for load_module, load in loads.items(): - module_name, module_num = load_module - action[module_name][module_num] = -1.0 * load - renewable = self._get_renewable() assert total_load >= 0 and renewable >= 0 From f907dc802009998b83a26170b74bdcabd90266d7 Mon Sep 17 00:00:00 2001 From: ahalev Date: Mon, 5 Dec 2022 16:58:42 -0800 Subject: [PATCH 18/20] add check to make sure action is populated --- src/pymgrid/envs/discrete/discrete.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/pymgrid/envs/discrete/discrete.py b/src/pymgrid/envs/discrete/discrete.py index 6ae5123b..6c47efd9 100644 --- a/src/pymgrid/envs/discrete/discrete.py +++ b/src/pymgrid/envs/discrete/discrete.py @@ -142,6 +142,10 @@ def _get_action(self, action_num): # If we have, e.g. a genset (with two actions) action[module_name][element_number] = np.array(action[module_name][element_number]) + bad_keys = [k for k, v in action.items() if v is None] + if len(bad_keys): + raise RuntimeError(f'None values found in action, corresponding to keys\n\t{bad_keys}') + return action def step(self, action): From ef8cfd9b26fb91ef576c529c10a559f53bca2ce3 Mon Sep 17 00:00:00 2001 From: ahalev Date: Mon, 5 Dec 2022 16:59:14 -0800 Subject: [PATCH 19/20] update getting action to use scalar max_consumption --- src/pymgrid/envs/discrete/discrete.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pymgrid/envs/discrete/discrete.py b/src/pymgrid/envs/discrete/discrete.py index 6c47efd9..c7056529 100644 --- a/src/pymgrid/envs/discrete/discrete.py +++ b/src/pymgrid/envs/discrete/discrete.py @@ -157,7 +157,7 @@ def _get_load(self): loads = dict() total_load = 0.0 for fixed_sink in self.fixed.sinks.iterlist(): - loads[fixed_sink.name] = fixed_sink.max_consumption.item() + loads[fixed_sink.name] = fixed_sink.max_consumption total_load += fixed_sink.max_consumption return loads, total_load From aa4530e69757ceefb59884357f0e8939d72a37d8 Mon Sep 17 00:00:00 2001 From: ahalev Date: Mon, 5 Dec 2022 16:59:24 -0800 Subject: [PATCH 20/20] refactor get_log --- src/pymgrid/microgrid/microgrid.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/pymgrid/microgrid/microgrid.py b/src/pymgrid/microgrid/microgrid.py index e51ce81f..22209f01 100644 --- a/src/pymgrid/microgrid/microgrid.py +++ b/src/pymgrid/microgrid/microgrid.py @@ -391,19 +391,16 @@ def get_log(self, as_frame=True, drop_singleton_key=False): col_names = ['module_name', 'module_number', 'field'] + df = pd.DataFrame(_log_dict) + df.columns = pd.MultiIndex.from_tuples(df.columns.to_list(), names=col_names) + if drop_singleton_key: - keys_arr = np.array(list(_log_dict.keys())) - module_counters = keys_arr[:, 1].astype(np.int64) - if module_counters.min() == module_counters.max(): - _log_dict = {(key[0], key[2]): value for key, value in _log_dict.items()} - col_names.pop(1) + df.columns = df.columns.remove_unused_levels() if as_frame: - df = pd.DataFrame(_log_dict) - df.columns.set_names(col_names, inplace=True) return df - return _log_dict + return df.to_dict() def get_forecast_horizon(self): """