From 89f6a638fef0c2d70389ee9c278a541ea06b2952 Mon Sep 17 00:00:00 2001 From: Torben Schiz <49746900+tjwsch@users.noreply.github.com> Date: Tue, 13 Aug 2024 10:36:01 +0200 Subject: [PATCH] Snapshot: Add possibility to have only one micro simulation object (#123) * Allow to compute snapshots on single object * Update snapshot documentation and CHANGELOG * Apply suggestions from code review Co-authored-by: Ishaan Desai * Add note when to use a single object --------- Co-authored-by: Ishaan Desai --- CHANGELOG.md | 1 + docs/snapshot_configuration.md | 1 + micro_manager/config.py | 20 ++++++++++++++++++++ micro_manager/snapshot/snapshot.py | 17 +++++++++++++---- tests/unit/snapshot-config.json | 3 ++- tests/unit/test_snapshot_computation.py | 4 +--- 6 files changed, 38 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce331b8..e23d13e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## latest +- Add option to use only one micro simulation object in the snapshot computation https://github.com/precice/micro-manager/pull/123 - Explicitly check if time window has converged using the API function `is_time_window_complete()` https://github.com/precice/micro-manager/pull/118 - Add `MicroManagerSnapshot` enabling snapshot computation and storage of microdata in HDF5 format https://github.com/precice/micro-manager/pull/101 - Make `sklearn` an optional dependency diff --git a/docs/snapshot_configuration.md b/docs/snapshot_configuration.md index 842fdb6..c2648a6 100644 --- a/docs/snapshot_configuration.md +++ b/docs/snapshot_configuration.md @@ -74,6 +74,7 @@ Parameter | Description Parameter | Description --- | --- `post_processing_file_name`| Path to the post-processing Python script from the current working directory. Providing a post-processing script is optional. The script must contain a class `PostProcessing` with a method `postprocessing(sim_output)` that takes the simulation output as an argument. The method can be used to post-process the simulation output before writing it to the database. +`initialize_once` | If `True`, only one micro simulation is initialized and solved for all macro inputs per rank. If `False` a new micro simulation is initialized and solved for each macro input in the parameter space. Default is `False`. This option can be True if the micro simulation is not history-dependent and the same setup is shared across all micro simulations. ## Diagnostics diff --git a/micro_manager/config.py b/micro_manager/config.py index 3cd4a3c..b6eb7cd 100644 --- a/micro_manager/config.py +++ b/micro_manager/config.py @@ -53,6 +53,7 @@ def __init__(self, logger, config_filename): # Snapshot information self._parameter_file_name = None self._postprocessing_file_name = None + self._initialize_once = False self._output_micro_sim_time = False @@ -301,6 +302,14 @@ def read_json_snapshot(self): "No diagnostics data is defined. Snapshot computation will not output any diagnostics data." ) + try: + if self._data["snapshot_params"]["initialize_once"] == "True": + self._initialize_once = True + except BaseException: + self._logger.info( + "For each snapshot a new micro simulation object will be created" + ) + def get_config_file_name(self): """ Get the name of the JSON configuration file. @@ -544,3 +553,14 @@ def interpolate_crashed_micro_sim(self): True if crashed micro simulations need to be interpolated, False otherwise. """ return self._interpolate_crash + + def create_single_sim_object(self): + """ + Check if multiple snapshots can be computed on a single micro simulation object. + + Returns + ------- + initialize_once : bool + True if initialization is done only once, False otherwise. + """ + return self._initialize_once diff --git a/micro_manager/snapshot/snapshot.py b/micro_manager/snapshot/snapshot.py index 7afc77e..3e2be75 100644 --- a/micro_manager/snapshot/snapshot.py +++ b/micro_manager/snapshot/snapshot.py @@ -40,6 +40,9 @@ def __init__(self, config_file: str) -> None: self._parameter_file = self._config.get_parameter_file_name() # Get name of pos-processing script self._post_processing_file_name = self._config.get_postprocessing_file_name() + + # Check if simulation object can be re-used. + self._initialize_once = self._config.create_single_sim_object() # Collect crashed indices self._crashed_snapshots = [] # Declaration @@ -58,10 +61,16 @@ def solve(self) -> None: # Loop over all macro parameters for elems in range(self._local_number_of_sims): - # Create micro simulation object - self._micro_sims = create_simulation_class(self._micro_problem)( - self._global_ids_of_local_sims[elems] - ) + # initialize micro simulation + if elems == 0: + self._micro_sims = create_simulation_class(self._micro_problem)( + self._global_ids_of_local_sims[0] + ) + else: + if not self._initialize_once: + self._micro_sims = create_simulation_class(self._micro_problem)( + self._global_ids_of_local_sims[elems] + ) micro_sims_input = self._macro_parameters[elems] # Solve micro simulation diff --git a/tests/unit/snapshot-config.json b/tests/unit/snapshot-config.json index 015d10b..e076a16 100644 --- a/tests/unit/snapshot-config.json +++ b/tests/unit/snapshot-config.json @@ -9,6 +9,7 @@ "micro_dt": 1.0 }, "snapshot_params": { - "post_processing_file_name": "snapshot_post_processing" + "post_processing_file_name": "snapshot_post_processing", + "initialize_once": "True" } } diff --git a/tests/unit/test_snapshot_computation.py b/tests/unit/test_snapshot_computation.py index ca09b65..68bde45 100644 --- a/tests/unit/test_snapshot_computation.py +++ b/tests/unit/test_snapshot_computation.py @@ -11,9 +11,6 @@ class MicroSimulation: def __init__(self, sim_id): self.very_important_value = 0 - def initialize(self): - pass - def solve(self, macro_data, dt): assert macro_data["macro-scalar-data"] == 1 assert macro_data["macro-vector-data"].tolist() == [0, 1, 2] @@ -149,6 +146,7 @@ def test_config(self): self.assertDictEqual(config._read_data_names, self.fake_read_data_names) self.assertDictEqual(config._write_data_names, self.fake_write_data_names) self.assertEqual(config._postprocessing_file_name, "snapshot_post_processing") + self.assertTrue(config._initialize_once) if __name__ == "__main__":