From d66c000a201a59aedfa10d8459253d14ecabf816 Mon Sep 17 00:00:00 2001 From: Torben Schiz <49746900+tjwsch@users.noreply.github.com> Date: Thu, 8 Aug 2024 14:33:57 +0200 Subject: [PATCH 1/2] Add snapshot computation docs and improve micro manager docs (#116) * Add snapshot docs and update micro manager docs * Add snapshot configuration docs * Adapt documentation * Update postprocessing description * Remove next step * Apply suggestions from code review Co-authored-by: Ishaan Desai * Move snapshot mention to -what can it do?- --------- Co-authored-by: Ishaan Desai --- docs/README.md | 8 ++- docs/configuration.md | 6 +- docs/installation.md | 1 + docs/running.md | 2 +- docs/snapshot_configuration.md | 106 +++++++++++++++++++++++++++++++++ 5 files changed, 118 insertions(+), 5 deletions(-) create mode 100644 docs/snapshot_configuration.md diff --git a/docs/README.md b/docs/README.md index 02837369..f919e3e6 100644 --- a/docs/README.md +++ b/docs/README.md @@ -19,11 +19,17 @@ The Micro Manager couples many micro simulations with one macro simulation. This - ... running micro simulations in parallel using MPI. - ... adaptively activating and deactivating micro simulations based on a similarity calculation. +The Micro Manager can also compute snapshots of micro simulations given macro input parameters in an offline manner without preCICE. + ## Documentation -To use the Micro Manager for a macro-micro coupling, your micro simulation code needs to be in a library format with a specific class name and functions with specific names. For a macro-micro coupled problem, the macro simulation code is coupled to preCICE directly. The section [couple your code](couple-your-code-overview.html) of the preCICE documentation gives more details on coupling existing codes. To setup a macro-micro coupled simulation using the Micro Manager, follow these steps: +To use the Micro Manager for a macro-micro coupling, your micro simulation code needs to be in a library format with a specific class name and functions with specific names. For a macro-micro coupled problem, the macro simulation code is coupled to preCICE directly. The section [couple your code](couple-your-code-overview.html) of the preCICE documentation gives more details on coupling existing codes. To set up a macro-micro coupled simulation using the Micro Manager, follow these steps: - [Installation](tooling-micro-manager-installation.html) - [Preparing micro simulation](tooling-micro-manager-prepare-micro-simulation.html) - [Configuration](tooling-micro-manager-configuration.html) - [Running](tooling-micro-manager-running.html) + +To compute snapshots in an offline manner your simulation code also needs to be in a library format with a specific class name and functions with specific names. To set up a snapshot computation using the Micro Manager, follow these steps: + +- [Snapshot computation](tooling-micro-manager-snapshot-configuration.html) diff --git a/docs/configuration.md b/docs/configuration.md index 4a215ebe..60346362 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -16,11 +16,11 @@ The Micro Manager is configured with a JSON file. An example configuration file "config_file_name": "precice-config.xml", "macro_mesh_name": "macro-mesh", "read_data_names": {"temperature": "scalar", "heat-flux": "vector"}, - "write_data_names": {"porosity": "scalar", "conductivity": "vector"}, - "micro_time_window_size": 1.0 + "write_data_names": {"porosity": "scalar", "conductivity": "vector"} }, "simulation_params": { "macro_domain_bounds": [0.0, 1.0, 0.0, 1.0, 0.0, 1.0], + "micro_dt": 1.0 }, "diagnostics": { "output_micro_sim_solve_time": "True" @@ -42,7 +42,6 @@ Parameter | Description `macro_mesh_name` | Name of the macro mesh as stated in the preCICE configuration. `read_data_names` | A Python dictionary with the names of the data to be read from preCICE as keys and `"scalar"` or `"vector"` as values depending on the nature of the data. `write_data_names` | A Python dictionary with the names of the data to be written to preCICE as keys and `"scalar"` or `"vector"` as values depending on the nature of the data. -`micro_dt` | Initial time window size (dt) of the micro simulation. ## Simulation Parameters @@ -51,6 +50,7 @@ Parameter | Description `macro_domain_bounds`| Minimum and maximum bounds of the macro-domain, having the format `[xmin, xmax, ymin, ymax, zmin, zmax]` in 3D and `[xmin, xmax, ymin, ymax]` in 2D. Domain decomposition parameters | See section on [domain decomposition](#domain-decomposition). But default, the Micro Manager assumes that it will be run in serial. Adaptivity parameters | See section on [adaptivity](#adaptivity). By default, adaptivity is disabled. +`micro_dt` | Initial time window size (dt) of the micro simulation. ## Diagnostics diff --git a/docs/installation.md b/docs/installation.md index 8c3d1423..bb13435d 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -40,6 +40,7 @@ Ensure that the following dependencies are installed: #### Optional dependencies * [sklearn](https://scikit-learn.org/stable/index.html) +* [h5py](https://www.h5py.org/) (required for snapshot computations) #### Clone the Micro Manager diff --git a/docs/running.md b/docs/running.md index 392ef17b..ee6fe6aa 100644 --- a/docs/running.md +++ b/docs/running.md @@ -17,6 +17,6 @@ The Micro Manager can also be run in parallel mpiexec -n micro-manager-precice micro-manager-config.json ``` -## What Happens When a Micro Simulation Crashes? +### What happens when a micro simulation crashes? If a micro simulation crashes and the Micro Manager is configured to [interpolate a crashed micro simulation](tooling-micro-manager-configuration.html/#Interpolate-a-crashed-micro-simulation), the Micro Manager attempts to continue running. The error message from the micro simulation, along with the macro location are logged in the Micro Manager log file. The Micro Manager continues the simulation run even if a micro simulation crashes. Results of the crashed micro simulation are generated by interpolating results of a certain number of similar running simulations. The [inverse distance weighed](https://en.wikipedia.org/wiki/Inverse_distance_weighting) method is used. If more than 20% of global micro simulations crash or if locally no neighbors are available for interpolation, the Micro Manager terminates. diff --git a/docs/snapshot_configuration.md b/docs/snapshot_configuration.md new file mode 100644 index 00000000..842fdb64 --- /dev/null +++ b/docs/snapshot_configuration.md @@ -0,0 +1,106 @@ +--- +title: Snapshot Computation +permalink: tooling-micro-manager-snapshot-configuration.html +keywords: tooling, macro-micro, two-scale, snapshot +summary: Set up the Micro Manager snapshot computation. +--- + +## Installation + +To use the Micro Manager for snapshot computation, the dependency `h5py` is necessary. To install `micro-manager-precice` with `h5py`, run + +```bash +pip install --user micro-manager-precice[snapshot] +``` + +If you have already installed `micro-manager-precice`, you can install `h5py` separately by running + +```bash +pip install --user h5py +``` + +## Preparation + +Prepare your micro simulation for the Micro Manager snapshot computation by following the instructions in the [preparation guide](tooling-micro-manager-preparation.html). + +Note: The `initialize()` method is not supported for the snapshot computation. + +## Configuration + +Configure the snapshot computation functionality with a JSON file. An example configuration file is + +```json +{ + "micro_file_name": "python-dummy/micro_dummy", + "coupling_params": { + "parameter_file_name": "parameter.hdf5", + "read_data_names": {"macro-scalar-data": "scalar", "macro-vector-data": "vector"}, + "write_data_names": {"micro-scalar-data": "scalar", "micro-vector-data": "vector"}, + }, + "simulation_params": { + "micro_dt": 1.0, + }, + "snapshot_params": { + "post_processing_file_name": "snapshot_postprocessing" + }, + "diagnostics": { + "output_micro_sim_solve_time": "True" + } +} +``` + +This example configuration file is in [`examples/snapshot-config.json`](https://github.com/precice/micro-manager/tree/develop/examples/snapshot-config.json). + +The path to the file containing the Python importable micro simulation class is specified in the `micro_file_name` parameter. If the file is not in the working directory, give the relative path. + +There are four main sections in the configuration file, the `coupling_params`, the `simulations_params`, the `snapshot_params` and the optional `diagnostics`. + +## Coupling Parameters + +Parameter | Description +--- | --- +`parameter_file_name` | Path to the HDF5 file containing the parameter space from the current working directory. Each macro parameter must be given as a dataset. Macro data for the same micro simulation should have the same index in the first dimension. The name must correspond to the names given in the config file. +`read_data_names` | A Python dictionary with the names of the data to be read from preCICE as keys and `"scalar"` or `"vector"` as values depending on the nature of the data. +`write_data_names` | A Python dictionary with the names of the data to be written to the database as keys and `"scalar"` or `"vector"` as values depending on the nature of the data. + +## Simulation Parameters + +Parameter | Description +--- | --- +`micro_dt` | Initial time window size (dt) of the micro simulation. Must be set even if the micro simulation is time-independent. + +## Snapshot Parameters + +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. + +## Diagnostics + +Parameter | Description +--- | --- +`output_micro_sim_solve_time` | If `True`, the Micro Manager writes the wall clock time of the `solve()` function of each micro simulation to the database. + +## Running + +Run the snapshot computation directly from the terminal by adding the `--snapshot` argument to the Micro Manager executable, and by providing the path to the configuration file as an input argument in the following way + +```bash +micro-manager-precice --snapshot snapshot-config.json +``` + +Run the snapshot computation in parallel by + +```bash +mpiexec -n micro-manager-precice --snapshot snapshot-config.json +``` + +where `` is the number of processes used. + +### Results + +The results of the snapshot computation are written into `output/` in HDF5-format. Each parameter is stored in a separate dataset. The dataset names correspond to the names specified in the configuration file. The first dimension of the datasets corresponds to the macro parameter index. + +### What happens when a micro simulation crashes during snapshot computation? + +If the computation of a snapshot fails, the snapshot is skipped. 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 2/2] 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 ce331b89..e23d13ec 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 842fdb64..c2648a6d 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 3cd4a3c3..b6eb7cd4 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 7afc77eb..3e2be751 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 015d10b7..e076a16e 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 ca09b65b..68bde45e 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__":