Skip to content

Commit

Permalink
Set micro simulation dt in the configuration (#112)
Browse files Browse the repository at this point in the history
* Add option for the user to provide initial time window size of the micro simulation

* Put config parameter micro_time_window_size in coupling_params group

* Paasing dt correctly

* Fix unit tests

* Fix crash handling tests

* Add CHANGELOG entry

* Use micro_dt instead of micro_time_window_size

* Use dt=0 when reading initial data
  • Loading branch information
IshaanDesai authored Jun 11, 2024
1 parent 0202253 commit 26dd92d
Show file tree
Hide file tree
Showing 18 changed files with 75 additions and 40 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## latest

- Set time step of micro simulation in the configuration, and use it in the coupling https://github.com/precice/micro-manager/pull/112
- Add a base class called `MicroManager` with minimal API and member function definitions, rename the existing `MicroManager` class to `MicroManagerCoupling` https://github.com/precice/micro-manager/pull/111
- Handle calling `initialize()` function of micro simulations written in languages other than Python https://github.com/precice/micro-manager/pull/110
- Check if initial data returned from the micro simulation is the data that the adaptivity computation requires https://github.com/precice/micro-manager/pull/109
Expand Down
4 changes: 3 additions & 1 deletion docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ 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"}
"write_data_names": {"porosity": "scalar", "conductivity": "vector"},
"micro_time_window_size": 1.0
},
"simulation_params": {
"macro_domain_bounds": [0.0, 1.0, 0.0, 1.0, 0.0, 1.0],
Expand All @@ -41,6 +42,7 @@ 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

Expand Down
3 changes: 2 additions & 1 deletion examples/micro-manager-cpp-adaptivity-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"config_file_name": "precice-config-adaptivity.xml",
"macro_mesh_name": "macro-mesh",
"read_data_names": {"macro-scalar-data": "scalar", "macro-vector-data": "vector"},
"write_data_names": {"micro-scalar-data": "scalar", "micro-vector-data": "vector"}
"write_data_names": {"micro-scalar-data": "scalar", "micro-vector-data": "vector"},
"micro_dt": 1.0
},
"simulation_params": {
"macro_domain_bounds": [0.0, 25.0, 0.0, 25.0, 0.0, 25.0],
Expand Down
3 changes: 2 additions & 1 deletion examples/micro-manager-cpp-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"config_file_name": "precice-config.xml",
"macro_mesh_name": "macro-mesh",
"read_data_names": {"macro-scalar-data": "scalar", "macro-vector-data": "vector"},
"write_data_names": {"micro-scalar-data": "scalar", "micro-vector-data": "vector"}
"write_data_names": {"micro-scalar-data": "scalar", "micro-vector-data": "vector"},
"micro_dt": 1.0
},
"simulation_params": {
"macro_domain_bounds": [0.0, 25.0, 0.0, 25.0, 0.0, 25.0]
Expand Down
3 changes: 2 additions & 1 deletion examples/micro-manager-python-adaptivity-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"config_file_name": "precice-config-adaptivity.xml",
"macro_mesh_name": "macro-mesh",
"read_data_names": {"macro-scalar-data": "scalar", "macro-vector-data": "vector"},
"write_data_names": {"micro-scalar-data": "scalar", "micro-vector-data": "vector"}
"write_data_names": {"micro-scalar-data": "scalar", "micro-vector-data": "vector"},
"micro_dt": 1.0
},
"simulation_params": {
"macro_domain_bounds": [0.0, 25.0, 0.0, 25.0, 0.0, 25.0],
Expand Down
3 changes: 2 additions & 1 deletion examples/micro-manager-python-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"config_file_name": "precice-config.xml",
"macro_mesh_name": "macro-mesh",
"read_data_names": {"macro-scalar-data": "scalar", "macro-vector-data": "vector"},
"write_data_names": {"micro-scalar-data": "scalar", "micro-vector-data": "vector"}
"write_data_names": {"micro-scalar-data": "scalar", "micro-vector-data": "vector"},
"micro_dt": 1.0
},
"simulation_params": {
"macro_domain_bounds": [0.0, 25.0, 0.0, 25.0, 0.0, 25.0]
Expand Down
14 changes: 14 additions & 0 deletions micro_manager/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def __init__(self, logger, config_filename):
self._macro_mesh_name = None
self._read_data_names = dict()
self._write_data_names = dict()
self._micro_dt = None

self._macro_domain_bounds = None
self._ranks_per_axis = None
Expand Down Expand Up @@ -114,6 +115,8 @@ def read_json(self, config_filename):
"No read data names provided. Micro manager will only write data to preCICE."
)

self._micro_dt = data["coupling_params"]["micro_dt"]

self._macro_domain_bounds = data["simulation_params"]["macro_domain_bounds"]

try:
Expand Down Expand Up @@ -431,3 +434,14 @@ def is_adaptivity_required_in_every_implicit_iteration(self):
True if adaptivity needs to be calculated in every time iteration, False otherwise.
"""
return self._adaptivity_every_implicit_iteration

def get_micro_dt(self):
"""
Get the size of the micro time window.
Returns
-------
micro_time_window : float
Size of the micro time window.
"""
return self._micro_dt
51 changes: 28 additions & 23 deletions micro_manager/micro_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ def __init__(self, config_file: str) -> None:
self._crash_threshold = 0.2
self._number_of_nearest_neighbors = 4

self._dt = 0
self._mesh_vertex_ids = None # IDs of macro vertices as set by preCICE
self._micro_n_out = self._config.get_micro_output_n()

Expand Down Expand Up @@ -117,6 +116,8 @@ def solve(self) -> None:
sim_is_associated_to_cp = None
sim_states_cp = [None] * self._local_number_of_sims

dt = min(self._participant.get_max_time_step_size(), self._micro_dt)

if self._is_adaptivity_on:
similarity_dists = np.zeros(
(
Expand All @@ -140,7 +141,7 @@ def solve(self) -> None:
is_sim_active,
sim_is_associated_to,
) = self._adaptivity_controller.compute_adaptivity(
self._dt,
dt,
self._micro_sims,
similarity_dists,
is_sim_active,
Expand All @@ -150,9 +151,7 @@ def solve(self) -> None:

while self._participant.is_coupling_ongoing():

self._dt = (
self._participant.get_max_time_step_size()
) # ask preCICE at beginning of time step for allowed time step size
dt = min(self._participant.get_max_time_step_size(), self._micro_dt)

# Write a checkpoint
if self._participant.requires_writing_checkpoint():
Expand All @@ -168,7 +167,7 @@ def solve(self) -> None:
is_sim_active,
sim_is_associated_to,
) = self._adaptivity_controller.compute_adaptivity(
self._dt,
dt,
self._micro_sims,
similarity_dists,
is_sim_active,
Expand Down Expand Up @@ -197,7 +196,7 @@ def solve(self) -> None:
for active_id in active_sim_ids:
self._micro_sims_active_steps[active_id] += 1

micro_sims_input = self._read_data_from_precice()
micro_sims_input = self._read_data_from_precice(dt)

if self._is_adaptivity_on:
if self._adaptivity_in_every_implicit_step:
Expand All @@ -206,7 +205,7 @@ def solve(self) -> None:
is_sim_active,
sim_is_associated_to,
) = self._adaptivity_controller.compute_adaptivity(
self._dt,
dt,
self._micro_sims,
similarity_dists,
is_sim_active,
Expand All @@ -230,10 +229,10 @@ def solve(self) -> None:
self._micro_sims_active_steps[active_id] += 1

micro_sims_output = self._solve_micro_simulations_with_adaptivity(
micro_sims_input, is_sim_active, sim_is_associated_to
micro_sims_input, is_sim_active, sim_is_associated_to, dt
)
else:
micro_sims_output = self._solve_micro_simulations(micro_sims_input)
micro_sims_output = self._solve_micro_simulations(micro_sims_input, dt)

# Check if more than a certain percentage of the micro simulations have crashed and terminate if threshold is exceeded
crashed_sims_on_all_ranks = np.zeros(self._size, dtype=np.int64)
Expand All @@ -257,11 +256,11 @@ def solve(self) -> None:

self._write_data_to_precice(micro_sims_output)

t += self._dt # increase internal time when time step is done.
t += dt # increase internal time when time step is done.
n += 1 # increase counter
self._participant.advance(
self._dt
) # notify preCICE that time step of size self._dt is complete
dt
) # notify preCICE that time step of size dt is complete

# Revert micro simulations to their last checkpoints if required
if self._participant.requires_reading_checkpoint():
Expand Down Expand Up @@ -427,7 +426,7 @@ def initialize(self) -> None:
self._micro_sims_init = False # DECLARATION

# Read initial data from preCICE, if it is available
initial_data = self._read_data_from_precice()
initial_data = self._read_data_from_precice(dt=0)

if not initial_data:
is_initial_data_available = False
Expand Down Expand Up @@ -556,16 +555,19 @@ def initialize(self) -> None:
):
self._micro_sims_have_output = True

self._dt = self._participant.get_max_time_step_size()

# ***************
# Private methods
# ***************

def _read_data_from_precice(self) -> list:
def _read_data_from_precice(self, dt) -> list:
"""
Read data from preCICE.
Parameters
----------
dt : float
Time step size at which data is to be read from preCICE.
Returns
-------
local_read_data : list
Expand All @@ -579,7 +581,7 @@ def _read_data_from_precice(self) -> list:
read_data.update(
{
name: self._participant.read_data(
self._macro_mesh_name, name, self._mesh_vertex_ids, self._dt
self._macro_mesh_name, name, self._mesh_vertex_ids, dt
)
}
)
Expand Down Expand Up @@ -621,7 +623,7 @@ def _write_data_to_precice(self, data: list) -> None:
self._macro_mesh_name, dname, [], np.array([])
)

def _solve_micro_simulations(self, micro_sims_input: list) -> list:
def _solve_micro_simulations(self, micro_sims_input: list, dt: float) -> list:
"""
Solve all micro simulations and assemble the micro simulations outputs in a list of dicts format.
Expand All @@ -630,6 +632,8 @@ def _solve_micro_simulations(self, micro_sims_input: list) -> list:
micro_sims_input : list
List of dicts in which keys are names of data and the values are the data which are required inputs to
solve a micro simulation.
dt : float
Time step size.
Returns
-------
Expand All @@ -645,9 +649,7 @@ def _solve_micro_simulations(self, micro_sims_input: list) -> list:
# Attempt to solve the micro simulation
try:
start_time = time.time()
micro_sims_output[count] = sim.solve(
micro_sims_input[count], self._dt
)
micro_sims_output[count] = sim.solve(micro_sims_input[count], dt)
end_time = time.time()
# Write solve time of the macro simulation if required and the simulation has not crashed
if self._is_micro_solve_time_required:
Expand Down Expand Up @@ -689,6 +691,7 @@ def _solve_micro_simulations_with_adaptivity(
micro_sims_input: list,
is_sim_active: np.ndarray,
sim_is_associated_to: np.ndarray,
dt: float,
) -> list:
"""
Solve all micro simulations and assemble the micro simulations outputs in a list of dicts format.
Expand All @@ -702,6 +705,8 @@ def _solve_micro_simulations_with_adaptivity(
1D array having state (active or inactive) of each micro simulation
sim_is_associated_to : numpy array
1D array with values of associated simulations of inactive simulations. Active simulations have None
dt : float
Time step size.
Returns
-------
Expand Down Expand Up @@ -741,7 +746,7 @@ def _solve_micro_simulations_with_adaptivity(
try:
start_time = time.time()
micro_sims_output[active_id] = self._micro_sims[active_id].solve(
micro_sims_input[active_id], self._dt
micro_sims_input[active_id], dt
)
end_time = time.time()
# Write solve time of the macro simulation if required and the simulation has not crashed
Expand Down
2 changes: 2 additions & 0 deletions micro_manager/micro_manager_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ def __init__(self, config_file):
self._logger.info("Provided configuration file: {}".format(config_file))
self._config = Config(self._logger, config_file)

self._micro_dt = self._config.get_micro_dt()

def initialize(self):
"""
Initialize micro simulations. Not implemented
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"config_file_name": "precice-config.xml",
"macro_mesh_name": "macro-cube-mesh",
"read_data_names": {"macro-scalar-data": "scalar", "macro-vector-data": "vector"},
"write_data_names": {"micro-scalar-data": "scalar", "micro-vector-data": "vector"}
"write_data_names": {"micro-scalar-data": "scalar", "micro-vector-data": "vector"},
"micro_dt": 1.0
},
"simulation_params": {
"macro_domain_bounds": [0, 1, 0, 1, 0, 1],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"config_file_name": "precice-config.xml",
"macro_mesh_name": "macro-cube-mesh",
"read_data_names": {"macro-scalar-data": "scalar", "macro-vector-data": "vector"},
"write_data_names": {"micro-scalar-data": "scalar", "micro-vector-data": "vector"}
"write_data_names": {"micro-scalar-data": "scalar", "micro-vector-data": "vector"},
"micro_dt": 1.0
},
"simulation_params": {
"macro_domain_bounds": [0, 1, 0, 1, 0, 1],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"config_file_name": "precice-config.xml",
"macro_mesh_name": "macro-cube-mesh",
"read_data_names": {"macro-scalar-data": "scalar", "macro-vector-data": "vector"},
"write_data_names": {"micro-scalar-data": "scalar", "micro-vector-data": "vector"}
"write_data_names": {"micro-scalar-data": "scalar", "micro-vector-data": "vector"},
"micro_dt": 1.0
},
"simulation_params": {
"macro_domain_bounds": [0, 1, 0, 1, 0, 1],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"config_file_name": "precice-config.xml",
"macro_mesh_name": "macro-cube-mesh",
"read_data_names": {"macro-scalar-data": "scalar", "macro-vector-data": "vector"},
"write_data_names": {"micro-scalar-data": "scalar", "micro-vector-data": "vector"}
"write_data_names": {"micro-scalar-data": "scalar", "micro-vector-data": "vector"},
"micro_dt": 1.0
},
"simulation_params": {
"macro_domain_bounds": [0, 1, 0, 1, 0, 1],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"config_file_name": "precice-config.xml",
"macro_mesh_name": "macro-cube-mesh",
"read_data_names": {"macro-scalar-data": "scalar", "macro-vector-data": "vector"},
"write_data_names": {"micro-scalar-data": "scalar", "micro-vector-data": "vector"}
"write_data_names": {"micro-scalar-data": "scalar", "micro-vector-data": "vector"},
"micro_dt": 1.0
},
"simulation_params": {
"macro_domain_bounds": [0, 1, 0, 1, 0, 1],
Expand Down
3 changes: 2 additions & 1 deletion tests/unit/micro-manager-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"config_file_name": "dummy-config.xml",
"macro_mesh_name": "dummy-macro-mesh",
"read_data_names": {"macro-scalar-data": "scalar", "macro-vector-data": "vector"},
"write_data_names": {"micro-scalar-data": "scalar", "micro-vector-data": "vector"}
"write_data_names": {"micro-scalar-data": "scalar", "micro-vector-data": "vector"},
"micro_dt": 0.1
},
"simulation_params": {
"macro_domain_bounds": [0.0, 25.0, 0.0, 25.0, 0.0, 25.0],
Expand Down
3 changes: 2 additions & 1 deletion tests/unit/micro-manager-config_crash.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"config_file_name": "dummy-config.xml",
"macro_mesh_name": "dummy-macro-mesh",
"read_data_names": {"macro-scalar-data": "scalar", "macro-vector-data": "vector"},
"write_data_names": {"micro-scalar-data": "scalar", "micro-vector-data": "vector"}
"write_data_names": {"micro-scalar-data": "scalar", "micro-vector-data": "vector"},
"micro_dt": 1.0
},
"simulation_params": {
"macro_domain_bounds": [0.0, 25.0, 0.0, 25.0, 0.0, 25.0],
Expand Down
6 changes: 3 additions & 3 deletions tests/unit/test_micro_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def test_initialization(self):
manager = micro_manager.MicroManagerCoupling("micro-manager-config.json")
manager.initialize()

self.assertEqual(manager._dt, 0.1) # from Interface.initialize
self.assertEqual(manager._micro_dt, 0.1) # from Interface.initialize
self.assertEqual(manager._global_number_of_sims, 4)
self.assertListEqual(manager._macro_bounds, self.macro_bounds)
self.assertListEqual(manager._mesh_vertex_ids.tolist(), [0, 1, 2, 3])
Expand All @@ -85,7 +85,7 @@ def test_read_write_data_from_precice(self):
manager = micro_manager.MicroManagerCoupling("micro-manager-config.json")

manager._write_data_to_precice(self.fake_write_data)
read_data = manager._read_data_from_precice()
read_data = manager._read_data_from_precice(1.0)

for data, fake_data in zip(read_data, self.fake_read_data):
self.assertEqual(data["macro-scalar-data"], 1)
Expand All @@ -105,7 +105,7 @@ def test_solve_micro_sims(self):
manager._micro_sims = [MicroSimulation(i) for i in range(4)]
manager._micro_sims_active_steps = np.zeros(4, dtype=np.int32)

micro_sims_output = manager._solve_micro_simulations(self.fake_read_data)
micro_sims_output = manager._solve_micro_simulations(self.fake_read_data, 1.0)

for data, fake_data in zip(micro_sims_output, self.fake_write_data):
self.assertEqual(data["micro-scalar-data"], 2)
Expand Down
Loading

0 comments on commit 26dd92d

Please sign in to comment.