Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move adaptivity CPU time output from preCICE export to metrics logging #149

Merged
merged 4 commits into from
Feb 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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

- Move adaptivity CPU time output from preCICE export to metrics logging https://github.com/precice/micro-manager/pull/149
- Fix bug in the domain decomposition which was returning incorrect bounding box limits for the decomposition of `[2, 2, 1]` and similar https://github.com/precice/micro-manager/pull/146
- Fix bug in calling of the adaptivity computation for explicit coupling scenarios https://github.com/precice/micro-manager/pull/145
- Fix bug in handling of vector data returned by the MicroSimulation `solve()` method, for scenarios with adaptivity https://github.com/precice/micro-manager/pull/143
Expand Down
3 changes: 0 additions & 3 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ Parameter | Description
`refining_constant` | Refining constant $$ C_r $$, set as $$ 0 =< C_r < 1 $$.
`every_implicit_iteration` | If True, adaptivity is calculated in every implicit iteration. <br> If False, adaptivity is calculated once at the start of the time window and then reused in every implicit time iteration.
`similarity_measure`| Similarity measure to be used for adaptivity. Can be either `L1`, `L2`, `L1rel` or `L2rel`. By default, `L1` is used. The `rel` variants calculate the respective relative norms. This parameter is *optional*.
`output_cpu_time` | Write CPU time of the adaptivity computation to preCICE, to be exported. This parameter is *optional*.

The primary tuning parameters for adaptivity are the history parameter $$ \Lambda $$, the coarsening constant $$ C_c $$, and the refining constant $$ C_r $$. Their effects can be interpreted as:

Expand Down Expand Up @@ -171,8 +170,6 @@ The Micro Manager uses the output functionality of preCICE, hence these data set
</participant>
```

If the parameter `output_cpu_time` in `adaptivity_settings` is set to `True`, a scalar data field `adaptivity_cpu_time` needs to be added in the same way as described above.

## Interpolate a crashed micro simulation

If the optional dependency `sklearn` is installed, the Micro Manager will derive the output of a crashed micro simulation by interpolating outputs from similar simulations. To enable this, set
Expand Down
3 changes: 0 additions & 3 deletions examples/precice-config-adaptivity.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
<data:scalar name="solve_cpu_time"/>
<data:scalar name="active_state"/>
<data:scalar name="active_steps"/>
<data:scalar name="adaptivity_cpu_time"/>

<mesh name="macro-mesh" dimensions="3">
<use-data name="macro-scalar-data"/>
Expand All @@ -23,7 +22,6 @@
<use-data name="solve_cpu_time"/>
<use-data name="active_state"/>
<use-data name="active_steps"/>
<use-data name="adaptivity_cpu_time"/>
</mesh>

<participant name="Macro-dummy">
Expand All @@ -43,7 +41,6 @@
<write-data name="solve_cpu_time" mesh="macro-mesh"/>
<write-data name="active_state" mesh="macro-mesh"/>
<write-data name="active_steps" mesh="macro-mesh"/>
<write-data name="adaptivity_cpu_time" mesh="macro-mesh"/>
</participant>

<m2n:sockets acceptor="Micro-Manager" connector="Macro-dummy"/>
Expand Down
7 changes: 5 additions & 2 deletions micro_manager/adaptivity/global_adaptivity.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,25 +179,28 @@ def get_full_field_micro_output(self, micro_output: list) -> list:

return micro_sims_output

def log_metrics(self, n: int) -> None:
def log_metrics(self, n: int, adaptivity_cpu_time: float) -> None:
"""
Log metrics for global adaptivity.

Parameters
----------
n : int
Time step count at which the metrics are logged
adaptivity_cpu_time : float
CPU time taken for adaptivity calculation
"""
global_active_sims = np.count_nonzero(self._is_sim_active)
global_inactive_sims = np.count_nonzero(self._is_sim_active == False)

self._metrics_logger.log_info_one_rank(
"{},{},{},{},{}".format(
"{},{},{},{},{},{}".format(
n,
np.mean(global_active_sims),
np.mean(global_inactive_sims),
np.max(global_active_sims),
np.max(global_inactive_sims),
adaptivity_cpu_time,
)
)

Expand Down
7 changes: 5 additions & 2 deletions micro_manager/adaptivity/local_adaptivity.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,14 +138,16 @@ def get_full_field_micro_output(self, micro_output: list) -> list:

return micro_sims_output

def log_metrics(self, n: int) -> None:
def log_metrics(self, n: int, adaptivity_cpu_time: float) -> None:
"""
Log metrics for local adaptivity.

Parameters
----------
n : int
Current time step
adaptivity_cpu_time : float
CPU time taken for adaptivity calculation
"""
# MPI Gather is necessary as local adaptivity only stores local data
local_active_sims = np.count_nonzero(self._is_sim_active)
Expand All @@ -155,12 +157,13 @@ def log_metrics(self, n: int) -> None:
global_inactive_sims = self._comm.gather(local_inactive_sims)

self._metrics_logger.log_info_one_rank(
"{},{},{},{},{}".format(
"{},{},{},{},{},{}".format(
n,
np.mean(global_active_sims),
np.mean(global_inactive_sims),
np.max(global_active_sims),
np.max(global_inactive_sims),
adaptivity_cpu_time,
)
)

Expand Down
41 changes: 0 additions & 41 deletions micro_manager/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,6 @@ def __init__(self, config_file_name):
self._adaptivity_every_implicit_iteration = False
self._adaptivity_similarity_measure = "L1"
self._adaptivity_output_n = 1
self._adaptivity_output_cpu_time = False
self._adaptivity_output_mem_usage = False

# Snapshot information
self._parameter_file_name = None
Expand Down Expand Up @@ -246,34 +244,6 @@ def read_json_micro_manager(self):
self._write_data_names.append("active_state")
self._write_data_names.append("active_steps")

try:
if (
self._data["simulation_params"]["adaptivity_settings"][
"output_cpu_time"
]
== "True"
):
self._adaptivity_output_cpu_time = True
self._write_data_names.append("adaptivity_cpu_time")
except BaseException:
self._logger.log_info_one_rank(
"Micro Manager will not output CPU time of the adaptivity computation."
)

try:
if (
self._data["simulation_params"]["adaptivity_settings"][
"output_mem_usage"
]
== "True"
):
self._adaptivity_output_mem_usage = True
self._write_data_names.append("adaptivity_mem_usage")
except BaseException:
self._logger.log_info_one_rank(
"Micro Manager will not output CPU time of the adaptivity computation."
)

if "interpolate_crash" in self._data["simulation_params"]:
if self._data["simulation_params"]["interpolate_crash"] == "True":
self._interpolate_crash = True
Expand Down Expand Up @@ -547,17 +517,6 @@ def is_adaptivity_required_in_every_implicit_iteration(self):
"""
return self._adaptivity_every_implicit_iteration

def output_adaptivity_cpu_time(self):
"""
Check if CPU time of the adaptivity computation needs to be output.

Returns
-------
adaptivity_cpu_time : bool
True if CPU time of the adaptivity computation needs to be output, False otherwise.
"""
return self._adaptivity_output_cpu_time

def get_micro_dt(self):
"""
Get the size of the micro time window.
Expand Down
32 changes: 5 additions & 27 deletions micro_manager/micro_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,8 @@ def __init__(self, config_file: str) -> None:
self._adaptivity_in_every_implicit_step = (
self._config.is_adaptivity_required_in_every_implicit_iteration()
)
self._micro_sims_active_steps = None

self._adaptivity_output_n = self._config.get_adaptivity_output_n()
self._output_adaptivity_cpu_time = self._config.output_adaptivity_cpu_time()

# Define the preCICE Participant
self._participant = precice.Participant(
Expand Down Expand Up @@ -202,10 +200,7 @@ def solve(self) -> None:

micro_sims_output, adaptivity_time = micro_sim_solve(micro_sims_input, dt)

if self._output_adaptivity_cpu_time:
adaptivity_cpu_time += adaptivity_time
for i in range(self._local_number_of_sims):
micro_sims_output[i]["adaptivity_cpu_time"] = adaptivity_cpu_time
adaptivity_cpu_time += adaptivity_time

# Check if more than a certain percentage of the micro simulations have crashed and terminate if threshold is exceeded
if self._interpolate_crashed_sims:
Expand Down Expand Up @@ -263,7 +258,7 @@ def solve(self) -> None:
and n % self._adaptivity_output_n == 0
and self._rank == 0
):
self._adaptivity_controller.log_metrics(n)
self._adaptivity_controller.log_metrics(n, adaptivity_cpu_time)

self._logger.log_info_one_rank("Time window {} converged.".format(n))

Expand Down Expand Up @@ -704,26 +699,7 @@ def _solve_micro_simulations_with_adaptivity(
tuple
A tuple of micro_sims_output (list of Dicts) and adaptivity computation CPU time.
"""
adaptivity_cpu_time = 0.0

if self._adaptivity_in_every_implicit_step:
start_time = time.process_time()
self._adaptivity_controller.compute_adaptivity(
dt,
self._micro_sims,
self._data_for_adaptivity,
)
end_time = time.process_time()

adaptivity_cpu_time = end_time - start_time

active_sim_ids = self._adaptivity_controller.get_active_sim_ids()

for active_id in active_sim_ids:
self._micro_sims_active_steps[active_id] += 1

active_sim_ids = self._adaptivity_controller.get_active_sim_ids()
inactive_sim_ids = self._adaptivity_controller.get_inactive_sim_ids()

micro_sims_output = [0] * self._local_number_of_sims

Expand Down Expand Up @@ -798,7 +774,9 @@ def _solve_micro_simulations_with_adaptivity(
)
end_time = time.process_time()

adaptivity_cpu_time += end_time - start_time
adaptivity_cpu_time = end_time - start_time

inactive_sim_ids = self._adaptivity_controller.get_inactive_sim_ids()

# Resolve micro sim output data for inactive simulations
for inactive_id in inactive_sim_ids:
Expand Down
3 changes: 0 additions & 3 deletions tests/integration/test_unit_cube/precice-config.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
<data:scalar name="macro-data-1" />
<data:scalar name="active_state" />
<data:scalar name="active_steps" />
<data:scalar name="adaptivity_cpu_time" />
<data:scalar name="solve_cpu_time" />

<mesh name="macro-cube-mesh" dimensions="3">
Expand All @@ -18,7 +17,6 @@
<use-data name="macro-data-1" />
<use-data name="active_state" />
<use-data name="active_steps" />
<use-data name="adaptivity_cpu_time" />
<use-data name="solve_cpu_time" />
</mesh>

Expand All @@ -36,7 +34,6 @@
<write-data name="micro-data-2" mesh="macro-cube-mesh" />
<write-data name="active_state" mesh="macro-cube-mesh" />
<write-data name="active_steps" mesh="macro-cube-mesh" />
<write-data name="adaptivity_cpu_time" mesh="macro-cube-mesh" />
<write-data name="solve_cpu_time" mesh="macro-cube-mesh" />
<export:vtu directory="output" />
</participant>
Expand Down