From 79323955451448cba9e4e92d56fe9706ed013dda Mon Sep 17 00:00:00 2001 From: avdudchenko <33663878+avdudchenko@users.noreply.github.com> Date: Mon, 20 Oct 2025 18:16:41 -0400 Subject: [PATCH 1/6] added option to provide dict instead of yaml directly --- src/parameter_sweep/loop_tool/loop_tool.py | 35 ++++++++++----- .../loop_tool/tests/test_loop_tool.py | 44 +++++++++++++++++++ 2 files changed, 67 insertions(+), 12 deletions(-) diff --git a/src/parameter_sweep/loop_tool/loop_tool.py b/src/parameter_sweep/loop_tool/loop_tool.py index 31cbe6f..23501a3 100644 --- a/src/parameter_sweep/loop_tool/loop_tool.py +++ b/src/parameter_sweep/loop_tool/loop_tool.py @@ -35,7 +35,7 @@ def get_working_dir(): class loopTool: def __init__( self, - loop_file, + loop_configuration, solver=None, build_function=None, initialize_function=None, @@ -56,7 +56,7 @@ def __init__( Loop tool class that runs iterative paramter sweeps Arguments: - loop_file : .yaml config file that contains iterative loops to run + loop_configuration : .yaml file or dict that contains iterative loops solver : solver to use in model, default uses watertap solver build_function : function to build unit model initialize_function : function for initialization of the unit model @@ -76,7 +76,7 @@ def __init__( use as many workers as specified to run through all loop options in parallel. """ - self.loop_file = loop_file + self.loop_configuration = loop_configuration self.solver = solver self.build_function = build_function @@ -132,8 +132,10 @@ def build_run_dict(self): """ This builds the dict that will be used for simulations """ - - loop_dict = ParameterSweepReader()._yaml_to_dict(self.loop_file) + if isinstance(self.loop_configuration, dict): + loop_dict = self.loop_configuration + else: + loop_dict = ParameterSweepReader()._yaml_to_dict(self.loop_configuration) self.sweep_directory = {} for key, loop in loop_dict.items(): self.check_dict_keys(loop) @@ -160,6 +162,7 @@ def build_run_dict(self): self.save_dir, self.h5_directory, ) + # assert False def check_dict_keys(self, test_dict): """used to test supported key in provided .yaml file""" @@ -247,8 +250,8 @@ def get_loop_key(self, loop, loop_type): def build_sweep_directories( self, loop, loop_type, sweep_directory, cur_dir, cur_h5_dir ): - """this creats the loop directory dict, which is then used to run - the paramter sweep""" + """this creates the loop directory dict, which is then used to run + the parameter sweep""" if loop_type != None: loop_type_recursive = self.get_loop_type(loop) loop_key_current = self.get_loop_key(loop, loop_type) @@ -308,7 +311,12 @@ def build_sweep_directories( "original_options_dict": copy.deepcopy(self.options), } } - + print( + "val", + sweep_directory[loop_value]["simulation_setup"][ + "build_defaults" + ], + ) return sweep_directory, cur_dir def update_dir_path(self, cur_dir, key, value): @@ -483,8 +491,9 @@ def find_execution_configs( for key, value in sweep_directory.items(): if key != "simulation_setup": self.find_execution_configs(value) + else: - self.execution_list.append(value) + self.execution_list.append(copy.deepcopy(value)) def execute_param_sweep_run(self, value): """this executes the parameter sweep @@ -508,7 +517,7 @@ def setup_param_sweep(self, value): tool, resets any of prior options""" self.init_sim_options() self.options = value["original_options_dict"] - self.build_default = value["build_defaults"] + self.build_defaults = value["build_defaults"] self.optimize_defaults = value["optimize_defaults"] self.init_defaults = value["init_defaults"] @@ -555,9 +564,11 @@ def build_sim_kwargs(self): ) self.build_outputs_kwargs = self.options.get("build_outputs_kwargs", None) # generated combined build kwargs (default + loop) - self.combined_build_defaults = {} # self.build_default + self.combined_build_defaults = {} # self.build_defaults self.combined_build_defaults.update(self.options.get("build_defaults", {})) - self.combined_build_defaults.update(self.build_default) + print("build_defaults", self.build_defaults) + self.combined_build_defaults.update(self.build_defaults) + print(self.combined_build_defaults) # generated combined optimize kwargs (default + loop) self.combined_optimize_defaults = {} self.combined_optimize_defaults.update( diff --git a/src/parameter_sweep/loop_tool/tests/test_loop_tool.py b/src/parameter_sweep/loop_tool/tests/test_loop_tool.py index 61ac74a..5822b5a 100644 --- a/src/parameter_sweep/loop_tool/tests/test_loop_tool.py +++ b/src/parameter_sweep/loop_tool/tests/test_loop_tool.py @@ -9,6 +9,7 @@ # information, respectively. These files are also available online at the URL # "https://github.com/watertap-org/watertap/" ################################################################################# +from parameter_sweep.reader import ParameterSweepReader import pytest import os import numpy as np @@ -99,6 +100,38 @@ def loop_sweep_setup(): return lp, expected_run_dict +@pytest.fixture() +def loop_sweep_setup_from_dict(): + dict_setup = ParameterSweepReader()._yaml_to_dict( + _this_file_path + "/test_sweep.yaml" + ) + + lp = loopTool( + dict_setup, + build_function=ro_setup.ro_build, + initialize_function=ro_setup.ro_init, + optimize_function=ro_setup.ro_solve, + saving_dir=_this_file_path, + save_name="ro_with_erd", + execute_simulations=False, + number_of_subprocesses=1, + ) + lp.build_run_dict() + """ used to generate test file""" + # with open("test_expected_sweep_directory.yaml", "w") as file: + # documents = yaml.dump(lp.sweep_directory, file) + if has_mpi_peer_processes() == False or ( + has_mpi_peer_processes() and get_mpi_comm_process().Get_rank() == 0 + ): + with open( + _this_file_path + "/test_expected_sweep_directory.yaml", "r" + ) as infile: + expected_run_dict = yaml.safe_load(infile) + else: + expected_run_dict = None + return lp, expected_run_dict + + @pytest.fixture() def loop_sweep_setup_with_workers(): lp = loopTool( @@ -208,6 +241,17 @@ def test_sweep_setup(loop_sweep_setup): assert diff_dict_check(lp.sweep_directory, expected_run_dict) +@pytest.mark.component +def test_sweep_setup_from_dict(loop_sweep_setup_from_dict): + if has_mpi_peer_processes() == False or ( + has_mpi_peer_processes() and get_mpi_comm_process().Get_rank() == 0 + ): + lp, expected_run_dict = loop_sweep_setup_from_dict + lp.build_run_dict() + + assert diff_dict_check(lp.sweep_directory, expected_run_dict) + + @pytest.mark.component def test_diff_setup(loop_diff_setup): if has_mpi_peer_processes() == False or ( From c61d469f18ba51e83235e5bb53da6446d656aea9 Mon Sep 17 00:00:00 2001 From: Kinshuk Panda <7632244+k1nshuk@users.noreply.github.com> Date: Sun, 23 Nov 2025 10:16:11 -0700 Subject: [PATCH 2/6] Apply suggestions from code review Co-authored-by: Adam Atia --- src/parameter_sweep/loop_tool/loop_tool.py | 1 - src/parameter_sweep/loop_tool/tests/test_loop_tool.py | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/parameter_sweep/loop_tool/loop_tool.py b/src/parameter_sweep/loop_tool/loop_tool.py index 23501a3..c319435 100644 --- a/src/parameter_sweep/loop_tool/loop_tool.py +++ b/src/parameter_sweep/loop_tool/loop_tool.py @@ -162,7 +162,6 @@ def build_run_dict(self): self.save_dir, self.h5_directory, ) - # assert False def check_dict_keys(self, test_dict): """used to test supported key in provided .yaml file""" diff --git a/src/parameter_sweep/loop_tool/tests/test_loop_tool.py b/src/parameter_sweep/loop_tool/tests/test_loop_tool.py index 5822b5a..bcde6fb 100644 --- a/src/parameter_sweep/loop_tool/tests/test_loop_tool.py +++ b/src/parameter_sweep/loop_tool/tests/test_loop_tool.py @@ -118,8 +118,6 @@ def loop_sweep_setup_from_dict(): ) lp.build_run_dict() """ used to generate test file""" - # with open("test_expected_sweep_directory.yaml", "w") as file: - # documents = yaml.dump(lp.sweep_directory, file) if has_mpi_peer_processes() == False or ( has_mpi_peer_processes() and get_mpi_comm_process().Get_rank() == 0 ): From f94617b05e40750bcced26ae2537baa8f493e49a Mon Sep 17 00:00:00 2001 From: avdudchenko <33663878+avdudchenko@users.noreply.github.com> Date: Wed, 26 Nov 2025 14:58:32 -0500 Subject: [PATCH 3/6] Update loop_tool.py --- src/parameter_sweep/loop_tool/loop_tool.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/parameter_sweep/loop_tool/loop_tool.py b/src/parameter_sweep/loop_tool/loop_tool.py index c319435..68f021b 100644 --- a/src/parameter_sweep/loop_tool/loop_tool.py +++ b/src/parameter_sweep/loop_tool/loop_tool.py @@ -310,12 +310,6 @@ def build_sweep_directories( "original_options_dict": copy.deepcopy(self.options), } } - print( - "val", - sweep_directory[loop_value]["simulation_setup"][ - "build_defaults" - ], - ) return sweep_directory, cur_dir def update_dir_path(self, cur_dir, key, value): @@ -490,7 +484,6 @@ def find_execution_configs( for key, value in sweep_directory.items(): if key != "simulation_setup": self.find_execution_configs(value) - else: self.execution_list.append(copy.deepcopy(value)) From 4f21fe82eb6b4bbaa11d9bec5d4cdadd0d7df2a3 Mon Sep 17 00:00:00 2001 From: avdudchenko <33663878+avdudchenko@users.noreply.github.com> Date: Wed, 26 Nov 2025 16:27:19 -0500 Subject: [PATCH 4/6] added 3.12 --- .github/workflows/checks.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 82255b6..4c1a2f0 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -51,6 +51,7 @@ jobs: - "3.9" - "3.10" - "3.11" + - "3.12" os: - linux - win64 @@ -60,10 +61,10 @@ jobs: - os: win64 os-version: windows-2022 - install-mode: dev - python-version: "3.11" # choice of Python version is arbitrary among those in matrix + python-version: "3.12" # choice of Python version is arbitrary among those in matrix coverage: "true" - install-mode: dev - python-version: "3.11" + python-version: "3.12" mpi: "true" steps: From d8c15ca1d1f08c6c7ed375ddb11433f808ef1bb3 Mon Sep 17 00:00:00 2001 From: avdudchenko <33663878+avdudchenko@users.noreply.github.com> Date: Mon, 1 Dec 2025 11:14:31 -0500 Subject: [PATCH 5/6] Revert "added 3.12" This reverts commit 4f21fe82eb6b4bbaa11d9bec5d4cdadd0d7df2a3. --- .github/workflows/checks.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 4c1a2f0..82255b6 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -51,7 +51,6 @@ jobs: - "3.9" - "3.10" - "3.11" - - "3.12" os: - linux - win64 @@ -61,10 +60,10 @@ jobs: - os: win64 os-version: windows-2022 - install-mode: dev - python-version: "3.12" # choice of Python version is arbitrary among those in matrix + python-version: "3.11" # choice of Python version is arbitrary among those in matrix coverage: "true" - install-mode: dev - python-version: "3.12" + python-version: "3.11" mpi: "true" steps: From 874f4b360414f9bed9a99fb3fe2046e90b5086cf Mon Sep 17 00:00:00 2001 From: avdudchenko <33663878+avdudchenko@users.noreply.github.com> Date: Tue, 2 Dec 2025 11:58:32 -0500 Subject: [PATCH 6/6] Update checks.yml --- .github/workflows/checks.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 82255b6..94a6762 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -60,10 +60,10 @@ jobs: - os: win64 os-version: windows-2022 - install-mode: dev - python-version: "3.11" # choice of Python version is arbitrary among those in matrix + python-version: "3.10" # choice of Python version is arbitrary among those in matrix coverage: "true" - install-mode: dev - python-version: "3.11" + python-version: "3.10" mpi: "true" steps: