Skip to content

Commit 626c236

Browse files
authored
fix(prt): fix duplicate particles, tidier release mechanism (#1928)
Introduce a module/type to manage the particle release schedule. This uses the time and time step selection (#1923) types recently added, allowing cleaner release logic in the PRP package. Make some quality of life improvements to the time selection type for easier usage. Add utilities arange and linspace to the math utility module, modeled after the eponymous NumPy functions. Use these in the PRP package to support regularly spaced release times via a new RELEASE_TIME_FREQUENCY option. This includes a few breaking changes, which address correctness and/or do not involve a loss of functionality. 1. Remove the FRACTION period-block release setting option. The RELEASETIMES block (#1989) can achieve the same explicitly. This brings period-block settings to equivalence with (and shares the implementation of) OC settings: - ALL - FIRST - LAST - STEPS - FREQUENCY If FRACTION is provided, the simulation will now fail. Add a removal notice to the DFN which will get picked up at release time by the automation and an entry will be inserted into the deprecations/removals table in the release notes. 2. Clarify the conceptual model for release points and fix some potential issues with the release mechanism. Previously a release was made for the union of explicit release times and period-block settings, even if an explicitly provided release time happened to coincide with a period block release setting's time. This could introduce duplicate particles, which is a bug given that we describe particles as uniquely identifiable via composite key consisting of model ID, PRP ID, release point ID, and release time. Only allow one release from each point at a time — by default within machine tolerance * 10^9, configurable via new RELEASE_TIME_TOLERANCE option. The release schedule is now the union of times explicitly provided in the RELEASETIMES block, regularly spaced times configured via RELEASE_TIME_FREQUENCY, and period-block time settings, where times within the configured tolerance of one another are merged into a single release time.
1 parent a832fdf commit 626c236

37 files changed

+864
-413
lines changed

autotest/TestMathUtil.f90

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
module TestMathUtil
22
use KindModule, only: I4B, DP
3-
use ConstantsModule, only: DNODATA, DZERO
3+
use ConstantsModule, only: DNODATA, DZERO, DONE
44
use testdrive, only: check, error_type, new_unittest, test_failed, &
55
to_string, unittest_type
66
use MathUtilModule, only: f1d, is_close, mod_offset, &
77
zero_ch, zero_br, &
8-
get_perturbation
8+
get_perturbation, &
9+
arange, linspace
910
implicit none
1011
private
1112
public :: collect_mathutil
@@ -25,7 +26,9 @@ subroutine collect_mathutil(testsuite)
2526
new_unittest("zero_br", &
2627
test_zero_br), &
2728
new_unittest("get_perturbation", &
28-
test_get_perturbation) &
29+
test_get_perturbation), &
30+
new_unittest("arange", test_arange), &
31+
new_unittest("linspace", test_linspace) &
2932
]
3033
end subroutine collect_mathutil
3134

@@ -189,14 +192,17 @@ subroutine test_zero_ch(error)
189192
z = zero_ch(-1.0_DP, 1.0_DP, f, 0.001_DP)
190193
call check(error, is_close(z, 0.0_DP, atol=1d-6), &
191194
'expected 0, got: '//to_string(z))
195+
if (allocated(error)) return
192196

193197
z = zero_ch(-4.0_DP, -1.0_DP, f, 0.001_DP)
194198
call check(error, is_close(z, -pi, atol=1d-6), &
195199
'expected -pi, got: '//to_string(z))
200+
if (allocated(error)) return
196201

197202
z = zero_ch(1.0_DP, 4.0_DP, f, 0.001_DP)
198203
call check(error, is_close(z, pi, atol=1d-6), &
199204
'expected pi, got: '//to_string(z))
205+
if (allocated(error)) return
200206
end subroutine test_zero_ch
201207

202208
subroutine test_zero_br(error)
@@ -210,14 +216,17 @@ subroutine test_zero_br(error)
210216
z = zero_br(-1.0_DP, 1.0_DP, f, 0.001_DP)
211217
call check(error, is_close(z, 0.0_DP, atol=1d-6), &
212218
'expected 0, got: '//to_string(z))
219+
if (allocated(error)) return
213220

214221
z = zero_br(-4.0_DP, -1.0_DP, f, 0.001_DP)
215222
call check(error, is_close(z, -pi, atol=1d-6), &
216223
'expected -pi, got: '//to_string(z))
224+
if (allocated(error)) return
217225

218226
z = zero_br(1.0_DP, 4.0_DP, f, 0.001_DP)
219227
call check(error, is_close(z, pi, atol=1d-6), &
220228
'expected pi, got: '//to_string(z))
229+
if (allocated(error)) return
221230
end subroutine test_zero_br
222231

223232
subroutine test_get_perturbation(error)
@@ -231,6 +240,7 @@ subroutine test_get_perturbation(error)
231240
call check(error, &
232241
is_close(v1, v2, atol=1d-12), &
233242
'expected '//to_string(v1)//' got: '//to_string(v2))
243+
if (allocated(error)) return
234244

235245
! test derivative calculation for sin(x) where x=1
236246
x = 1.d0
@@ -240,6 +250,7 @@ subroutine test_get_perturbation(error)
240250
call check(error, &
241251
is_close(v1, v2, atol=1d-5), &
242252
'expected '//to_string(v1)//' got: '//to_string(v2))
253+
if (allocated(error)) return
243254

244255
! test derivative calculation for sin(x) where x=0
245256
x = 0.d0
@@ -249,6 +260,7 @@ subroutine test_get_perturbation(error)
249260
call check(error, &
250261
is_close(v1, v2, atol=1d-5), &
251262
'expected '//to_string(v1)//' got: '//to_string(v2))
263+
if (allocated(error)) return
252264

253265
! test derivative calculation for x ** 2
254266
x = 1.d6
@@ -258,7 +270,48 @@ subroutine test_get_perturbation(error)
258270
call check(error, &
259271
is_close(v1, v2, atol=1d-1), &
260272
'expected '//to_string(v1)//' got: '//to_string(v2))
273+
if (allocated(error)) return
261274

262275
end subroutine test_get_perturbation
263276

277+
subroutine test_arange(error)
278+
type(error_type), allocatable, intent(out) :: error
279+
real(DP), allocatable :: a(:)
280+
integer(I4B) :: i
281+
282+
a = arange(DZERO, 10.0_DP, DONE)
283+
call check(error, size(a) == 10, "wrong size: "//to_string(size(a)))
284+
if (allocated(error)) return
285+
do i = 1, 10
286+
call check(error, is_close(a(i), real(i - 1, DP)))
287+
if (allocated(error)) return
288+
end do
289+
290+
deallocate (a)
291+
292+
a = arange(DZERO, DONE, 0.1_DP)
293+
call check(error, size(a) == 10, "wrong size: "//to_string(size(a)))
294+
if (allocated(error)) return
295+
do i = 1, 10
296+
call check(error, is_close(a(i), real(i - 1, DP) / 10.0_DP))
297+
if (allocated(error)) return
298+
end do
299+
300+
end subroutine test_arange
301+
302+
subroutine test_linspace(error)
303+
type(error_type), allocatable, intent(out) :: error
304+
real(DP), allocatable :: a(:)
305+
integer(I4B) :: i
306+
307+
a = linspace(DONE, 10.0_DP, 10)
308+
call check(error, size(a) == 10)
309+
if (allocated(error)) return
310+
do i = 1, 10
311+
call check(error, is_close(a(i), real(i, DP)))
312+
if (allocated(error)) return
313+
end do
314+
315+
end subroutine test_linspace
316+
264317
end module TestMathUtil

autotest/TestTimeSelect.f90

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,24 @@ subroutine collect_timeselect(testsuite)
1313
type(unittest_type), allocatable, intent(out) :: testsuite(:)
1414
testsuite = [ &
1515
new_unittest("is_increasing", test_is_increasing), &
16-
new_unittest("slice", test_slice) &
16+
new_unittest("select", test_select), &
17+
new_unittest("extend_and_sort", &
18+
test_extend_and_sort) &
1719
]
1820
end subroutine collect_timeselect
1921

2022
subroutine test_is_increasing(error)
2123
type(error_type), allocatable, intent(out) :: error
2224
type(TimeSelectType) :: ts
2325

26+
call ts%init()
2427
call ts%expand(3)
2528

2629
! increasing
2730
ts%times = (/0.0_DP, 1.0_DP, 2.0_DP/)
2831
call check(error, ts%increasing())
2932

30-
! not decreasing
33+
! not decreasing (duplicates)
3134
ts%times = (/0.0_DP, 0.0_DP, 2.0_DP/)
3235
call check(error,.not. ts%increasing())
3336

@@ -36,11 +39,12 @@ subroutine test_is_increasing(error)
3639
call check(error,.not. ts%increasing())
3740
end subroutine
3841

39-
subroutine test_slice(error)
42+
subroutine test_select(error)
4043
type(error_type), allocatable, intent(out) :: error
4144
type(TimeSelectType) :: ts
4245
logical(LGP) :: changed
4346

47+
call ts%init()
4448
call ts%expand(3)
4549
ts%times = (/0.0_DP, 1.0_DP, 2.0_DP/)
4650
call check( &
@@ -107,5 +111,19 @@ subroutine test_slice(error)
107111
"lb ub eq slice failed, got [" &
108112
//to_string(ts%selection(1))//","//to_string(ts%selection(2))//"]")
109113

110-
end subroutine test_slice
114+
end subroutine test_select
115+
116+
subroutine test_extend_and_sort(error)
117+
type(error_type), allocatable, intent(out) :: error
118+
type(TimeSelectType) :: ts
119+
real(DP) :: a(3)
120+
121+
a = (/0.0_DP, 2.0_DP, 1.0_DP/)
122+
123+
call ts%init()
124+
call ts%extend(a)
125+
call check(error, ts%increasing())
126+
127+
end subroutine test_extend_and_sort
128+
111129
end module TestTimeSelect
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

0 commit comments

Comments
 (0)