Skip to content

Commit

Permalink
Reintroduce initialize function in the micro simulation API (#79)
Browse files Browse the repository at this point in the history
* Reintroduce initialize() function optionally in the micro simulation API, and use its data for adaptivity

* Check if initialize() method exists, and if yes, run it

* Check is_sim_active

* Remove print statement

* Use dict given by initialize() as it is

* Rewrite documentation in parallel tests

* Set initialization condition for not one just all ranks

* Formatting
  • Loading branch information
IshaanDesai authored Mar 13, 2024
1 parent e75b541 commit e7db6f3
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 16 deletions.
10 changes: 10 additions & 0 deletions docs/micro-simulation-convert-to-library.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ class MicroSimulation: # Name is fixed
ID of the simulation instance, that the Micro Manager has set for it.
"""

def initialize(self) -> dict:
"""
Initialize the micro simulation and return initial data which will be used in computing adaptivity before the first time step.
Returns
-------
initial_data : dict
Dictionary with names of initial data as keys and the initial data itself as values.
"""

def solve(self, macro_data: dict, dt: float) -> dict:
"""
Solve one time step of the micro simulation for transient problems or solve until steady state for steady-state problems.
Expand Down
51 changes: 39 additions & 12 deletions micro_manager/micro_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import time
from copy import deepcopy
from typing import Dict
from warnings import warn

from .config import Config
from .micro_simulation import create_simulation_class
Expand Down Expand Up @@ -133,26 +134,27 @@ def solve(self) -> None:
"""
t, n = 0, 0
t_checkpoint, n_checkpoint = 0, 0
similarity_dists_cp = None
is_sim_active_cp = None
sim_is_associated_to_cp = None
sim_states_cp = [None] * self._local_number_of_sims

if self._is_adaptivity_on:
similarity_dists = np.zeros(
(self._number_of_sims_for_adaptivity,
self._number_of_sims_for_adaptivity))

# Start adaptivity calculation with all sims inactive
is_sim_active = np.array([False] * self._number_of_sims_for_adaptivity)
# Start adaptivity calculation with all sims active
is_sim_active = np.array([True] * self._number_of_sims_for_adaptivity)

# Activate the first one (a random choice)
is_sim_active[0] = True
# Active sims do not have an associated sim
sim_is_associated_to = np.full((self._number_of_sims_for_adaptivity), -2, dtype=np.intc)

# Associate all sims to the one active sim
sim_is_associated_to = np.zeros((self._number_of_sims_for_adaptivity), dtype=np.intc)
sim_is_associated_to[0] = -2 # An active sim does not have an associated sim

similarity_dists_cp = None
is_sim_active_cp = None
sim_is_associated_to_cp = None
sim_states_cp = [None] * self._local_number_of_sims
# If micro simulations have been initialized, compute adaptivity based on initial data
if self._micro_sims_init:
# Compute adaptivity based on initial data of micro sims
similarity_dists, is_sim_active, sim_is_associated_to = self._adaptivity_controller.compute_adaptivity(
self._dt, self._micro_sims, similarity_dists, is_sim_active, sim_is_associated_to, self._data_for_adaptivity)

while self._participant.is_coupling_ongoing():
# Write a checkpoint
Expand Down Expand Up @@ -338,6 +340,31 @@ def _initialize(self) -> None:

self._micro_sims_active_steps = np.zeros(self._local_number_of_sims)

self._micro_sims_init = False # DECLARATION

# Get initial data from micro simulations if initialize() method exists
if hasattr(micro_problem, 'initialize') and callable(getattr(micro_problem, 'initialize')):
if self._is_adaptivity_on:
self._micro_sims_init = True
initial_micro_output = self._micro_sims[0].initialize() # Call initialize() of the first simulation
if initial_micro_output is None: # Check if the detected initialize() method returns any data
warn("The initialize() call of the Micro simulation has not returned any initial data."
" The initialize call is stopped.")
self._micro_sims_init = False
else:
# Save initial data from first micro simulation as we anyway have it
for name in initial_micro_output.keys():
self._data_for_adaptivity[name][0] = initial_micro_output[name]

# Gather initial data from the rest of the micro simulations
for i in range(1, self._local_number_of_sims):
initial_micro_output = self._micro_sims[i].initialize()
for name in self._adaptivity_micro_data_names:
self._data_for_adaptivity[name][i] = initial_micro_output[name]
else:
self._logger.info(
"Micro simulation has the method initialize(), but it is not called, because adaptivity is off.")

self._micro_sims_have_output = False
if hasattr(micro_problem, 'output') and callable(getattr(micro_problem, 'output')):
self._micro_sims_have_output = True
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/precice.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# This file mocks pyprecice, the Python bindings for preCICE, and is used _only_ for unit testing the Micro Manager.
# This file mocks pyprecice, the Python bindings for preCICE, and is used _only_ for testing the Micro Manager.
from typing import Any
import numpy as np

Expand Down
6 changes: 3 additions & 3 deletions tests/unit/test_adaptivity_parallel.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def setUp(self):

def test_update_inactive_sims_global_adaptivity(self):
"""
Test functionality to update inactive simulations in a particular setting, for a global adaptivity setting.
Test functionality to update inactive simulations in a particular setting.
Run this test in parallel using MPI with 2 ranks.
"""
if self._rank == 0:
Expand Down Expand Up @@ -76,7 +76,7 @@ def get_state(self):

def test_update_all_active_sims_global_adaptivity(self):
"""
Test functionality to calculate adaptivity when all simulations are active, for a global adaptivity setting.
Test functionality to calculate adaptivity when all simulations are active.
Run this test in parallel using MPI with 2 ranks.
"""
if self._rank == 0:
Expand Down Expand Up @@ -133,7 +133,7 @@ def get_state(self):

def test_communicate_micro_output(self):
"""
Test functionality to communicate micro output from active sims to their associated inactive sims, for a global adaptivity setting.
Test functionality to communicate micro output from active sims to their associated inactive sims.
Run this test in parallel using MPI with 2 ranks.
"""
output_0 = {"data0.1": 1.0, "data0.2": [1.0, 2.0]}
Expand Down

0 comments on commit e7db6f3

Please sign in to comment.