1
1
"""
2
- CPU implementation of backend methods for freezing (singular and time-dependent immersion freezing)
2
+ CPU implementation of backend methods for homogeneous freezing and
3
+ heterogeneous freezing (singular and time-dependent immersion freezing)
3
4
"""
4
5
5
6
from functools import cached_property
12
13
from ...impl_common .freezing_attributes import (
13
14
SingularAttributes ,
14
15
TimeDependentAttributes ,
16
+ TimeDependentHomogeneousAttributes ,
15
17
)
16
18
17
19
18
20
class FreezingMethods (BackendMethods ):
19
- def __init__ (self ):
20
- BackendMethods .__init__ (self )
21
- unfrozen_and_saturated = self .formulae .trivia .unfrozen_and_saturated
22
- frozen_and_above_freezing_point = (
23
- self .formulae .trivia .frozen_and_above_freezing_point
24
- )
25
-
26
- @numba .njit (** {** self .default_jit_flags , "parallel" : False })
27
- def _freeze (water_mass , i ):
28
- water_mass [i ] = - 1 * water_mass [i ]
21
+ @cached_property
22
+ def _freeze (self ):
23
+ @numba .njit (** {** self .default_jit_flags , ** {"parallel" : False }})
24
+ def body (signed_water_mass , i ):
25
+ signed_water_mass [i ] = - 1 * signed_water_mass [i ]
29
26
# TODO #599: change thd (latent heat)!
30
27
31
- @numba .njit (** {** self .default_jit_flags , "parallel" : False })
32
- def _thaw (water_mass , i ):
33
- water_mass [i ] = - 1 * water_mass [i ]
28
+ return body
29
+
30
+ @cached_property
31
+ def _thaw (self ):
32
+ @numba .njit (** {** self .default_jit_flags , ** {"parallel" : False }})
33
+ def body (signed_water_mass , i ):
34
+ signed_water_mass [i ] = - 1 * signed_water_mass [i ]
34
35
# TODO #599: change thd (latent heat)!
35
36
37
+ return body
38
+
39
+ @cached_property
40
+ def _freeze_singular_body (self ):
41
+ _thaw = self ._thaw
42
+ _freeze = self ._freeze
43
+ frozen_and_above_freezing_point = (
44
+ self .formulae .trivia .frozen_and_above_freezing_point
45
+ )
46
+ unfrozen_and_saturated = self .formulae .trivia .unfrozen_and_saturated
47
+
36
48
@numba .njit (** self .default_jit_flags )
37
- def freeze_singular_body (
38
- attributes , temperature , relative_humidity , cell , thaw
39
- ):
49
+ def body (attributes , temperature , relative_humidity , cell , thaw ):
40
50
n_sd = len (attributes .freezing_temperature )
41
51
for i in numba .prange (n_sd ): # pylint: disable=not-an-iterable
42
52
if attributes .freezing_temperature [i ] == 0 :
@@ -53,13 +63,21 @@ def freeze_singular_body(
53
63
):
54
64
_freeze (attributes .signed_water_mass , i )
55
65
56
- self . freeze_singular_body = freeze_singular_body
66
+ return body
57
67
68
+ @cached_property
69
+ def _freeze_time_dependent_body (self ):
70
+ _thaw = self ._thaw
71
+ _freeze = self ._freeze
72
+ frozen_and_above_freezing_point = (
73
+ self .formulae .trivia .frozen_and_above_freezing_point
74
+ )
75
+ unfrozen_and_saturated = self .formulae .trivia .unfrozen_and_saturated
58
76
j_het = self .formulae .heterogeneous_ice_nucleation_rate .j_het
59
77
prob_zero_events = self .formulae .trivia .poissonian_avoidance_function
60
78
61
79
@numba .njit (** self .default_jit_flags )
62
- def freeze_time_dependent_body ( # pylint: disable=too-many-arguments
80
+ def body ( # pylint: disable=too-many-arguments
63
81
rand ,
64
82
attributes ,
65
83
timestep ,
@@ -90,12 +108,69 @@ def freeze_time_dependent_body( # pylint: disable=too-many-arguments
90
108
if rand [i ] < prob :
91
109
_freeze (attributes .signed_water_mass , i )
92
110
93
- self .freeze_time_dependent_body = freeze_time_dependent_body
111
+ return body
112
+
113
+ @cached_property
114
+ def _freeze_time_dependent_homogeneous_body (self ):
115
+ _thaw = self ._thaw
116
+ _freeze = self ._freeze
117
+ frozen_and_above_freezing_point = (
118
+ self .formulae .trivia .frozen_and_above_freezing_point
119
+ )
120
+ unfrozen_and_ice_saturated = self .formulae .trivia .unfrozen_and_ice_saturated
121
+ j_hom = self .formulae .homogeneous_ice_nucleation_rate .j_hom
122
+ prob_zero_events = self .formulae .trivia .poissonian_avoidance_function
123
+ d_a_w_ice_within_range = (
124
+ self .formulae .homogeneous_ice_nucleation_rate .d_a_w_ice_within_range
125
+ )
126
+ d_a_w_ice_maximum = (
127
+ self .formulae .homogeneous_ice_nucleation_rate .d_a_w_ice_maximum
128
+ )
129
+
130
+ @numba .njit (** self .default_jit_flags )
131
+ def body ( # pylint: disable=unused-argument,too-many-arguments
132
+ rand ,
133
+ attributes ,
134
+ timestep ,
135
+ cell ,
136
+ a_w_ice ,
137
+ temperature ,
138
+ relative_humidity_ice ,
139
+ thaw ,
140
+ ):
141
+
142
+ n_sd = len (attributes .signed_water_mass )
143
+ for i in numba .prange (n_sd ): # pylint: disable=not-an-iterable
144
+ cell_id = cell [i ]
145
+ if thaw and frozen_and_above_freezing_point (
146
+ attributes .signed_water_mass [i ], temperature [cell_id ]
147
+ ):
148
+ _thaw (attributes .signed_water_mass , i )
149
+ elif unfrozen_and_ice_saturated (
150
+ attributes .signed_water_mass [i ], relative_humidity_ice [cell_id ]
151
+ ):
152
+ d_a_w_ice = (relative_humidity_ice [cell_id ] - 1.0 ) * a_w_ice [
153
+ cell_id
154
+ ]
155
+
156
+ if d_a_w_ice_within_range (d_a_w_ice ):
157
+ d_a_w_ice = d_a_w_ice_maximum (d_a_w_ice )
158
+ rate_assuming_constant_temperature_within_dt = (
159
+ j_hom (temperature [cell_id ], d_a_w_ice )
160
+ * attributes .volume [i ]
161
+ )
162
+ prob = 1 - prob_zero_events (
163
+ r = rate_assuming_constant_temperature_within_dt , dt = timestep
164
+ )
165
+ if rand [i ] < prob :
166
+ _freeze (attributes .signed_water_mass , i )
167
+
168
+ return body
94
169
95
170
def freeze_singular (
96
171
self , * , attributes , temperature , relative_humidity , cell , thaw : bool
97
172
):
98
- self .freeze_singular_body (
173
+ self ._freeze_singular_body (
99
174
SingularAttributes (
100
175
freezing_temperature = attributes .freezing_temperature .data ,
101
176
signed_water_mass = attributes .signed_water_mass .data ,
@@ -118,7 +193,7 @@ def freeze_time_dependent(
118
193
relative_humidity ,
119
194
thaw : bool ,
120
195
):
121
- self .freeze_time_dependent_body (
196
+ self ._freeze_time_dependent_body (
122
197
rand .data ,
123
198
TimeDependentAttributes (
124
199
immersed_surface_area = attributes .immersed_surface_area .data ,
@@ -132,6 +207,32 @@ def freeze_time_dependent(
132
207
thaw = thaw ,
133
208
)
134
209
210
+ def freeze_time_dependent_homogeneous (
211
+ self ,
212
+ * ,
213
+ rand ,
214
+ attributes ,
215
+ timestep ,
216
+ cell ,
217
+ a_w_ice ,
218
+ temperature ,
219
+ relative_humidity_ice ,
220
+ thaw : bool ,
221
+ ):
222
+ self ._freeze_time_dependent_homogeneous_body (
223
+ rand .data ,
224
+ TimeDependentHomogeneousAttributes (
225
+ volume = attributes .volume .data ,
226
+ signed_water_mass = attributes .signed_water_mass .data ,
227
+ ),
228
+ timestep ,
229
+ cell .data ,
230
+ a_w_ice .data ,
231
+ temperature .data ,
232
+ relative_humidity_ice .data ,
233
+ thaw = thaw ,
234
+ )
235
+
135
236
@cached_property
136
237
def _record_freezing_temperatures_body (self ):
137
238
ff = self .formulae_flattened
0 commit comments