Skip to content

Commit ad807ec

Browse files
authored
fix(prt): fix default release timing (MODFLOW-ORG#2847)
PRT was described as configuring a single release at the beginning of the simulation by default, but a release was in fact scheduled for the first time step of every stress period. Fix the default release behavior so a single release occurs at the beginning of the simulation.
1 parent 359b56c commit ad807ec

4 files changed

Lines changed: 45 additions & 13 deletions

File tree

Binary file not shown.

autotest/test_prt_release_timing.py

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,20 @@
5656
f"{simname}multi", # FIRST in period 1, ALL in period 2, FIRST in period 3
5757
# test explicit release time and period-block release on a time step boundary
5858
f"{simname}bndy", # RELEASETIMES: 1.0; FIRST in period 2 (also t=1.0)
59+
# test default release (no period block, no release times) with multiple periods
60+
f"{simname}dflt", # no config: should release only at t=0 despite 3 periods
5961
]
6062

6163

6264
def get_perioddata(name, periods=1) -> Optional[dict]:
6365
opt = []
64-
if "sgl" in name or "dbl" in name or "open" in name or "tol" in name:
66+
if (
67+
"sgl" in name
68+
or "dbl" in name
69+
or "open" in name
70+
or "tol" in name
71+
or "dflt" in name
72+
):
6573
return None
6674
if "bndy" in name:
6775
return {
@@ -111,10 +119,10 @@ def build_prt_sim(name, gwf_ws, prt_ws, mf6):
111119
)
112120

113121
# create tdis package
114-
# 3 periods for fill-forward, multi-period, and boundary, 1 period for others
122+
# 3 periods for fill-forward, multi-period, boundary, and default, 1 for others
115123
nper = (
116124
3
117-
if ("fill" in name or "multi" in name or "bndy" in name)
125+
if ("fill" in name or "multi" in name or "bndy" in name or "dflt" in name)
118126
else FlopyReadmeCase.nper
119127
)
120128
if "multi" in name:
@@ -136,7 +144,7 @@ def build_prt_sim(name, gwf_ws, prt_ws, mf6):
136144
FlopyReadmeCase.tsmult,
137145
), # Period 2: 1 time step
138146
]
139-
elif "fill" in name or "bndy" in name:
147+
elif "fill" in name or "bndy" in name or "dflt" in name:
140148
perioddata = [
141149
(
142150
FlopyReadmeCase.perlen,
@@ -335,8 +343,13 @@ def build_models(test):
335343
test.name, test.workspace, test.targets["mf6"]
336344
)
337345

338-
# For fill-forward, multi-period, and boundary, update GWF to use 3 periods
339-
if "fill" in test.name or "multi" in test.name or "bndy" in test.name:
346+
# For fill-forward, multi-period, boundary, and default, update GWF to use 3 periods
347+
if (
348+
"fill" in test.name
349+
or "multi" in test.name
350+
or "bndy" in test.name
351+
or "dflt" in test.name
352+
):
340353
tdis = gwf_sim.get_package("tdis")
341354
tdis.nper = 3
342355
if "multi" in test.name:
@@ -457,7 +470,7 @@ def check_output(test, snapshot):
457470
# Multi-period tests use 3 periods, others use 1
458471
nper = (
459472
3
460-
if ("fill" in name or "multi" in name or "bndy" in name)
473+
if ("fill" in name or "multi" in name or "bndy" in name or "dflt" in name)
461474
else FlopyReadmeCase.nper
462475
)
463476
check_budget_data(
@@ -539,6 +552,12 @@ def check_output(test, snapshot):
539552
expected_kpers = [1, 2]
540553
assert unique_kpers == expected_kpers
541554

555+
# check default release case: no config at all, 3 stress periods.
556+
# particles should be released exactly once at t=0 (start of simulation).
557+
if "dflt" in name:
558+
release_times = sorted(mf6_pls["trelease"].unique())
559+
assert release_times == [0.0]
560+
542561
# convert mf6 pathlines to mp7 format
543562
mf6_pls = to_mp7_pathlines(mf6_pls)
544563

@@ -582,6 +601,15 @@ def check_output(test, snapshot):
582601
# have been tracked under the prior period's flow
583602
# system, the next shouldn't "get credit" for it.
584603
assert len(mf6_pls) == len(mp7_pls) - 9
604+
elif "dflt" in name:
605+
# Each particle terminates exactly at a cell face, so MF6 emits a
606+
# FEATEXIT (from the outgoing cell) and a TERMINATE (in the entering
607+
# cell) at identical (x,y,z,t). Sorting by (particleid, time) alone
608+
# leaves those two records in an arbitrary order that differs between
609+
# MF6 and MP7. Add node as a tiebreaker so both are ordered the same.
610+
mf6_pls.sort_values(by=["particleid", "time", "node"], inplace=True)
611+
mp7_pls.sort_values(by=["particleid", "time", "node"], inplace=True)
612+
assert np.allclose(mf6_pls, mp7_pls, atol=1e-3)
585613
else:
586614
# the rest of the cases should match mp7 results,
587615
# with duplicate times debounced in "dupe"/"tol".

doc/ReleaseNotes/develop.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,9 @@ description = "Fix the PRT PRP package's DRAPE option's behavior. A draped parti
7777
[[items]]
7878
section = "fixes"
7979
subsection = "basic"
80-
description = "Previously, GWF model output files could only be referenced by a single coupled model's FMI package. This might be necessary for certain configurations where multiple transport models or particle tracking models in the same simulation need flow information from a previous GWF simulation. Referencing the same GWF output files from multiple coupled models would cause a crash. Fix file-opening logic to allow multiple coupled models to refer to the same GWF model's output files."
80+
description = "Previously, GWF model output files could only be referenced by a single coupled model's FMI package. This might be necessary for certain configurations where multiple transport models or particle tracking models in the same simulation need flow information from a previous GWF simulation. Referencing the same GWF output files from multiple coupled models would cause a crash. Fix file-opening logic to allow multiple coupled models to refer to the same GWF model's output files."
81+
82+
[[items]]
83+
section = "fixes"
84+
subsection = "model"
85+
description = "PRT was described as configuring a single release at the beginning of the simulation by default, but a release was in fact scheduled for the first time step of every stress period. Fix the default release behavior so a single release occurs at the beginning of the simulation."

src/Model/ParticleTracking/prt-prp.f90

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -752,11 +752,10 @@ subroutine prp_rp(this)
752752
! If the user hasn't provided any release settings (neither
753753
! explicit release times, release time frequency, or period
754754
! block release settings), default to a single release at the
755-
! start of the first period's first time step.
756-
! Store default configuration; advance() will be called in prp_ad().
757-
if (allocated(this%period_block_lines)) deallocate (this%period_block_lines)
758-
allocate (this%period_block_lines(1))
759-
this%period_block_lines(1) = "FIRST"
755+
! start of the simulation (t=0). Add t=0 directly to the time
756+
! selection rather than time step selection because the latter
757+
! would fill forward, releasing at the start of every period.
758+
call this%schedule%time_select%extend([DZERO])
760759
return
761760
else if (iper /= kper) then
762761
return

0 commit comments

Comments
 (0)