1212
1313
1414class AdaptivityCalculator :
15- def __init__ (self , configurator , rank ) -> None :
15+ def __init__ (self , configurator , rank , nsims ) -> None :
1616 """
1717 Class constructor.
1818
@@ -22,6 +22,8 @@ def __init__(self, configurator, rank) -> None:
2222 Object which has getter functions to get parameters defined in the configuration file.
2323 rank : int
2424 Rank of the MPI communicator.
25+ nsims : int
26+ Number of micro simulations.
2527 """
2628 self ._refine_const = configurator .get_adaptivity_refining_const ()
2729 self ._coarse_const = configurator .get_adaptivity_coarsening_const ()
@@ -36,6 +38,23 @@ def __init__(self, configurator, rank) -> None:
3638
3739 self ._rank = rank
3840
41+ # similarity_dists: 2D array having similarity distances between each micro simulation pair
42+ # This matrix is modified in place via the function update_similarity_dists
43+ # NOTE: Data type restricted to float32 to save memory. Remove this restriction if higher precision is needed.
44+ self ._similarity_dists = np .zeros ((nsims , nsims ), dtype = np .float32 )
45+
46+ self ._max_similarity_dist = 0.0
47+
48+ # is_sim_active: 1D array having state (active or inactive) of each micro simulation
49+ # Start adaptivity calculation with all sims active
50+ # This array is modified in place via the function update_active_sims and update_inactive_sims
51+ self ._is_sim_active = np .array ([True ] * nsims , dtype = np .bool_ )
52+
53+ # sim_is_associated_to: 1D array with values of associated simulations of inactive simulations. Active simulations have None
54+ # Active sims do not have an associated sim
55+ # This array is modified in place via the function associate_inactive_to_active
56+ self ._sim_is_associated_to = np .full ((nsims ), - 2 , dtype = np .intc )
57+
3958 self ._just_deactivated : list [int ] = []
4059
4160 self ._similarity_measure = self ._get_similarity_measure (
@@ -69,29 +88,19 @@ def __init__(self, configurator, rank) -> None:
6988 csv_logger = True ,
7089 )
7190
72- def _get_similarity_dists (
73- self , dt : float , similarity_dists : np .ndarray , data : dict
74- ) -> np .ndarray :
91+ def _update_similarity_dists (self , dt : float , data : dict ) -> None :
7592 """
7693 Calculate metric which determines if two micro simulations are similar enough to have one of them deactivated.
7794
7895 Parameters
7996 ----------
8097 dt : float
8198 Current time step
82- similarity_dists : numpy array
83- 2D array having similarity distances between each micro simulation pair
8499 data : dict
85100 Data to be used in similarity distance calculation
86-
87- Returns
88- -------
89- similarity_dists : numpy array
90- Updated 2D array having similarity distances between each micro simulation pair
91101 """
92- _similarity_dists = np . copy ( similarity_dists )
102+ self . _similarity_dists = exp ( - self . _hist_param * dt ) * self . _similarity_dists
93103
94- data_diff = np .zeros_like (_similarity_dists )
95104 for name in data .keys ():
96105 data_vals = np .array (data [name ])
97106 if data_vals .ndim == 1 :
@@ -100,97 +109,56 @@ def _get_similarity_dists(
100109 # The axis is later reduced with a norm.
101110 data_vals = np .expand_dims (data_vals , axis = 1 )
102111
103- data_diff += self ._similarity_measure (data_vals )
112+ self . _similarity_dists += dt * self ._similarity_measure (data_vals )
104113
105- return exp ( - self ._hist_param * dt ) * _similarity_dists + dt * data_diff
114+ self ._max_similarity_dist = np . amax ( self . _similarity_dists )
106115
107- def _update_active_sims (
108- self , similarity_dists : np .ndarray , is_sim_active : np .ndarray
109- ) -> np .ndarray :
116+ def _update_active_sims (self ) -> None :
110117 """
111118 Update set of active micro simulations. Active micro simulations are compared to each other
112119 and if found similar, one of them is deactivated.
113-
114- Parameters
115- ----------
116- similarity_dists : numpy array
117- 2D array having similarity distances between each micro simulation pair
118- is_sim_active : numpy array
119- 1D array having state (active or inactive) of each micro simulation
120-
121- Returns
122- -------
123- _is_sim_active : numpy array
124- Updated 1D array having state (active or inactive) of each micro simulation
125120 """
126- max_similarity_dist = np .amax (similarity_dists )
127-
128- if max_similarity_dist == 0.0 :
121+ if self ._max_similarity_dist == 0.0 :
129122 warn (
130123 "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."
131124 )
132125 self ._coarse_tol = sys .float_info .min
133126 else :
134127 self ._coarse_tol = (
135- self ._coarse_const * self ._refine_const * max_similarity_dist
128+ self ._coarse_const * self ._refine_const * self . _max_similarity_dist
136129 )
137130
138- _is_sim_active = np .copy (
139- is_sim_active
140- ) # Input is_sim_active is not longer used after this point
141-
142131 # Update the set of active micro sims
143- for i in range (_is_sim_active .size ):
144- if _is_sim_active [i ]: # if sim is active
145- if self ._check_for_deactivation (i , similarity_dists , _is_sim_active ):
146- _is_sim_active [i ] = False
132+ for i in range (self . _is_sim_active .size ):
133+ if self . _is_sim_active [i ]: # if sim is active
134+ if self ._check_for_deactivation (i , self . _is_sim_active ):
135+ self . _is_sim_active [i ] = False
147136 self ._just_deactivated .append (i )
148137
149- return _is_sim_active
150-
151- def _associate_inactive_to_active (
152- self ,
153- similarity_dists : np .ndarray ,
154- is_sim_active : np .ndarray ,
155- sim_is_associated_to : np .ndarray ,
156- ) -> np .ndarray :
138+ def _associate_inactive_to_active (self ) -> None :
157139 """
158140 Associate inactive micro simulations to most similar active micro simulation.
159-
160- Parameters
161- ----------
162- similarity_dists : numpy array
163- 2D array having similarity distances between each micro simulation pair
164- is_sim_active : numpy array
165- 1D array having state (active or inactive) of each micro simulation
166- sim_is_associated_to : numpy array
167- 1D array with values of associated simulations of inactive simulations. Active simulations have None
168-
169- Returns
170- -------
171- _sim_is_associated_to : numpy array
172- 1D array with values of associated simulations of inactive simulations. Active simulations have None
173141 """
174- active_ids = np .where (is_sim_active )[0 ]
175- inactive_ids = np .where (is_sim_active == False )[0 ]
142+ active_ids = np .where (self . _is_sim_active )[0 ]
143+ inactive_ids = np .where (self . _is_sim_active == False )[0 ]
176144
177- _sim_is_associated_to = np .copy (sim_is_associated_to )
145+ # Start with a large distance to trigger the search for the most similar active sim
146+ dist_min_start_value = 2 * self ._max_similarity_dist
178147
179148 # Associate inactive micro sims to active micro sims
180149 for inactive_id in inactive_ids :
181- dist_min = sys .float_info .max
150+ # Begin with a large distance to trigger the search for the most similar active sim
151+ dist_min = dist_min_start_value
182152 for active_id in active_ids :
183153 # Find most similar active sim for every inactive sim
184- if similarity_dists [inactive_id , active_id ] < dist_min :
154+ if self . _similarity_dists [inactive_id , active_id ] < dist_min :
185155 associated_active_id = active_id
186- dist_min = similarity_dists [inactive_id , active_id ]
187-
188- _sim_is_associated_to [inactive_id ] = associated_active_id
156+ dist_min = self ._similarity_dists [inactive_id , active_id ]
189157
190- return _sim_is_associated_to
158+ self . _sim_is_associated_to [ inactive_id ] = associated_active_id
191159
192160 def _check_for_activation (
193- self , inactive_id : int , similarity_dists : np . ndarray , is_sim_active : np .ndarray
161+ self , inactive_id : int , is_sim_active : np .ndarray
194162 ) -> bool :
195163 """
196164 Check if an inactive simulation needs to be activated.
@@ -199,8 +167,6 @@ def _check_for_activation(
199167 ----------
200168 inactive_id : int
201169 ID of inactive simulation which is checked for activation.
202- similarity_dists : numpy array
203- 2D array having similarity distances between each micro simulation pair.
204170 is_sim_active : numpy array
205171 1D array having state (active or inactive) of each micro simulation.
206172
@@ -211,13 +177,13 @@ def _check_for_activation(
211177 """
212178 active_sim_ids = np .where (is_sim_active )[0 ]
213179
214- dists = similarity_dists [inactive_id , active_sim_ids ]
180+ dists = self . _similarity_dists [inactive_id , active_sim_ids ]
215181
216182 # If inactive sim is not similar to any active sim, activate it
217183 return min (dists ) > self ._ref_tol
218184
219185 def _check_for_deactivation (
220- self , active_id : int , similarity_dists : np . ndarray , is_sim_active : np .ndarray
186+ self , active_id : int , is_sim_active : np .ndarray
221187 ) -> bool :
222188 """
223189 Check if an active simulation needs to be deactivated.
@@ -226,8 +192,6 @@ def _check_for_deactivation(
226192 ----------
227193 active_id : int
228194 ID of active simulation which is checked for deactivation.
229- similarity_dists : numpy array
230- 2D array having similarity distances between each micro simulation pair.
231195 is_sim_active : numpy array
232196 1D array having state (active or inactive) of each micro simulation.
233197
@@ -241,7 +205,7 @@ def _check_for_deactivation(
241205 for active_id_2 in active_sim_ids :
242206 if active_id != active_id_2 : # don't compare active sim to itself
243207 # If active sim is similar to another active sim, deactivate it
244- if similarity_dists [active_id , active_id_2 ] < self ._coarse_tol :
208+ if self . _similarity_dists [active_id , active_id_2 ] < self ._coarse_tol :
245209 return True
246210 return False
247211
0 commit comments