diff --git a/micro_manager/adaptivity/adaptivity.py b/micro_manager/adaptivity/adaptivity.py index 44e2e2ee..ec9b31b0 100644 --- a/micro_manager/adaptivity/adaptivity.py +++ b/micro_manager/adaptivity/adaptivity.py @@ -5,6 +5,7 @@ import numpy as np from math import exp from typing import Callable +from warnings import warn class AdaptivityCalculator: @@ -84,7 +85,13 @@ def _update_active_sims( _is_sim_active : numpy array Updated 1D array having state (active or inactive) of each micro simulation """ - self._coarse_tol = self._coarse_const * self._refine_const * np.amax(similarity_dists) + max_similarity_dist = np.amax(similarity_dists) + + if max_similarity_dist == 0.0: + warn("All similarity distances are zero, probably because all the data for adaptivity is the same. Coarsening tolerance will be manually set to minimum float number.") + self._coarse_tol = sys.float_info.min + else: + self._coarse_tol = self._coarse_const * self._refine_const * max_similarity_dist _is_sim_active = np.copy(is_sim_active) # Input is_sim_active is not longer used after this point diff --git a/micro_manager/adaptivity/global_adaptivity.py b/micro_manager/adaptivity/global_adaptivity.py index 5ffaa949..c217b8a6 100644 --- a/micro_manager/adaptivity/global_adaptivity.py +++ b/micro_manager/adaptivity/global_adaptivity.py @@ -105,11 +105,15 @@ def compute_adaptivity( is_sim_active = self._update_active_sims(similarity_dists, is_sim_active_nm1) is_sim_active, sim_is_associated_to = self._update_inactive_sims( - similarity_dists, is_sim_active_nm1, sim_is_associated_to_nm1, micro_sims) + similarity_dists, is_sim_active, sim_is_associated_to_nm1, micro_sims) + + print("sim_is_associated_to: {}".format(sim_is_associated_to)) sim_is_associated_to = self._associate_inactive_to_active( similarity_dists, is_sim_active, sim_is_associated_to) + print("sim_is_associated_to: {}".format(sim_is_associated_to)) + self._logger.info( "{} active simulations, {} inactive simulations".format( np.count_nonzero( diff --git a/micro_manager/adaptivity/local_adaptivity.py b/micro_manager/adaptivity/local_adaptivity.py index 2f82c877..cd465a0b 100644 --- a/micro_manager/adaptivity/local_adaptivity.py +++ b/micro_manager/adaptivity/local_adaptivity.py @@ -61,7 +61,7 @@ def compute_adaptivity( is_sim_active = self._update_active_sims(similarity_dists, is_sim_active_nm1) is_sim_active, sim_is_associated_to = self._update_inactive_sims( - similarity_dists, is_sim_active_nm1, sim_is_associated_to_nm1, micro_sims) + similarity_dists, is_sim_active, sim_is_associated_to_nm1, micro_sims) sim_is_associated_to = self._associate_inactive_to_active( similarity_dists, is_sim_active, sim_is_associated_to) diff --git a/tests/unit/test_adaptivity_parallel.py b/tests/unit/test_adaptivity_parallel.py index d00e5276..2f1b2a4e 100644 --- a/tests/unit/test_adaptivity_parallel.py +++ b/tests/unit/test_adaptivity_parallel.py @@ -74,6 +74,63 @@ def get_state(self): elif self._rank == 1: self.assertTrue(np.array_equal([2, 2, 2], dummy_micro_sims[1].get_state())) + def test_update_all_active_sims_global_adaptivity(self): + """ + Test functionality to calculate adaptivity when all simulations are active, for a global adaptivity setting. + Run this test in parallel using MPI with 2 ranks. + """ + if self._rank == 0: + global_ids = [0, 1, 2] + data_for_adaptivity = {"data1": [1.0, 1.0, 1.0], "data2": [13.0, 13.0, 13.0]} + elif self._rank == 1: + global_ids = [3, 4] + data_for_adaptivity = {"data1": [1.0, 1.0], "data2": [13.0, 13.0]} + + similarity_dists = np.zeros((5, 5)) + is_sim_active = np.array([True, True, True, True, True]) + sim_is_associated_to = [-2, -2, -2, -2, -2] + expected_is_sim_active = np.array([False, False, False, False, True]) + expected_sim_is_associated_to = [4, 4, 4, 4, -2] + + configurator = MagicMock() + configurator.get_adaptivity_hist_param = MagicMock(return_value=0.1) + configurator.get_adaptivity_refining_const = MagicMock(return_value=0.05) + configurator.get_adaptivity_coarsening_const = MagicMock(return_value=0.2) + configurator.get_adaptivity_similarity_measure = MagicMock(return_value="L2rel") + adaptivity_controller = GlobalAdaptivityCalculator( + configurator, + MagicMock(), + 5, + global_ids, + rank=self._rank, + comm=self._comm) + + adaptivity_controller._adaptivity_data_names = {"data1": "scalar", "data2": "scalar"} + + class MicroSimulation(): + def __init__(self, global_id) -> None: + self._global_id = global_id + self._state = [global_id] * 3 + + def get_global_id(self): + return self._global_id + + def set_state(self, state): + self._state = state + + def get_state(self): + return self._state.copy() + + dummy_micro_sims = [] + for i in global_ids: + dummy_micro_sims.append(MicroSimulation(i)) + + _, is_sim_active, sim_is_associated_to = adaptivity_controller.compute_adaptivity( + 0.1, dummy_micro_sims, similarity_dists, is_sim_active, sim_is_associated_to, data_for_adaptivity) + + self.assertTrue(np.array_equal(expected_is_sim_active, is_sim_active)) + self.assertTrue(np.array_equal(expected_sim_is_associated_to, sim_is_associated_to)) + 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.