Skip to content

Commit e40f102

Browse files
wpbonelliwpbonelli
authored andcommitted
feat(prp): support local, offset and transformed coords
1 parent baf4300 commit e40f102

26 files changed

Lines changed: 932 additions & 560 deletions
Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
"""
2+
Tests ability to transform release point coordinates from
3+
global, local, or local offset coordinate representations
4+
to model coordinates, as well as to transform output data
5+
from model to global cooordinates.
6+
7+
The grid is a 10x10 square with a single layer,
8+
the same flow system shown on the FloPy readme.
9+
10+
Test cases are defined for each coordinate system option.
11+
These are:
12+
13+
- local_xy
14+
- local_xy_offset
15+
- dev_global_xy
16+
17+
"""
18+
19+
from pathlib import Path
20+
21+
import flopy
22+
import matplotlib.cm as cm
23+
import matplotlib.pyplot as plt
24+
import numpy as np
25+
import pandas as pd
26+
import pytest
27+
from flopy.utils import PathlineFile
28+
from flopy.utils.binaryfile import HeadFile
29+
from flopy.utils.gridintersect import GridIntersect
30+
from shapely.geometry import Point
31+
from framework import TestFramework
32+
from prt_test_utils import (
33+
FlopyReadmeCase,
34+
all_equal,
35+
check_budget_data,
36+
check_track_data,
37+
get_model_name,
38+
get_partdata,
39+
has_default_boundnames,
40+
DEFAULT_EXIT_SOLVE_TOL,
41+
)
42+
43+
simname = "prtcrd"
44+
cases = [f"{simname}mdl", f"{simname}lcl", f"{simname}ofs"] # todo global
45+
nodes = list(range(100))
46+
47+
48+
def get_start_points():
49+
return np.add(
50+
np.transpose(
51+
np.array(np.meshgrid(range(10), range(10))).reshape(2, -1)
52+
),
53+
0.5,
54+
)
55+
56+
57+
def get_prp(prt):
58+
gi = GridIntersect(prt.modelgrid, method="vertex", rtree=True)
59+
if "mdl" in prt.name:
60+
startpts = get_start_points()
61+
releasepts = [
62+
(i, (0, *gi.intersect(Point(rpt))[0].cellids), *rpt, 0.5)
63+
for i, rpt in enumerate(startpts)
64+
]
65+
elif "lcl" in prt.name:
66+
releasepts = [
67+
(nn, tuple([*prt.modelgrid.get_lrc([nn])[0]]), 0.5, 0.5, 0.5)
68+
for nn in nodes
69+
]
70+
elif "ofs" in prt.name:
71+
releasepts = [
72+
(nn, tuple([*prt.modelgrid.get_lrc([nn])[0]]), 0.0, 0.0, 0.0)
73+
for nn in nodes
74+
]
75+
elif "gbl" in prt.name:
76+
# todo global
77+
pass
78+
79+
prp_track_file = f"{prt.name}_prt.prp.trk"
80+
prp_track_csv_file = f"{prt.name}_prt.prp.trk.csv"
81+
return flopy.mf6.ModflowPrtprp(
82+
prt,
83+
pname="prp1",
84+
filename=f"{prt.name}_1.prp",
85+
nreleasepts=len(releasepts),
86+
packagedata=releasepts,
87+
perioddata={0: ["FIRST"]},
88+
track_filerecord=[prp_track_file],
89+
trackcsv_filerecord=[prp_track_csv_file],
90+
local_xy="lcl" in prt.name,
91+
local_xy_offset="ofs" in prt.name,
92+
exit_solve_tolerance=DEFAULT_EXIT_SOLVE_TOL,
93+
extend_tracking=True,
94+
)
95+
96+
97+
def build_prt_sim(name, gwf_ws, prt_ws, mf6):
98+
# create simulation
99+
sim = flopy.mf6.MFSimulation(
100+
sim_name=name,
101+
exe_name=mf6,
102+
version="mf6",
103+
sim_ws=prt_ws,
104+
)
105+
106+
# create tdis package
107+
flopy.mf6.modflow.mftdis.ModflowTdis(
108+
sim,
109+
pname="tdis",
110+
time_units="DAYS",
111+
nper=FlopyReadmeCase.nper,
112+
perioddata=[
113+
(
114+
FlopyReadmeCase.perlen,
115+
FlopyReadmeCase.nstp,
116+
FlopyReadmeCase.tsmult,
117+
)
118+
],
119+
)
120+
121+
# create prt model
122+
prt_name = get_model_name(name, "prt")
123+
prt = flopy.mf6.ModflowPrt(sim, modelname=prt_name, save_flows=True)
124+
125+
# create prt discretization
126+
flopy.mf6.modflow.mfgwfdis.ModflowGwfdis(
127+
prt,
128+
pname="dis",
129+
nlay=FlopyReadmeCase.nlay,
130+
nrow=FlopyReadmeCase.nrow,
131+
ncol=FlopyReadmeCase.ncol,
132+
)
133+
134+
# create mip package
135+
flopy.mf6.ModflowPrtmip(
136+
prt, pname="mip", porosity=FlopyReadmeCase.porosity
137+
)
138+
139+
# create prp package
140+
prp = get_prp(prt)
141+
142+
# create output control package
143+
prt_budget_file = f"{prt_name}.bud"
144+
prt_track_file = f"{prt_name}.trk"
145+
prt_track_csv_file = f"{prt_name}.trk.csv"
146+
flopy.mf6.ModflowPrtoc(
147+
prt,
148+
pname="oc",
149+
budget_filerecord=[prt_budget_file],
150+
track_filerecord=[prt_track_file],
151+
trackcsv_filerecord=[prt_track_csv_file],
152+
saverecord=[("BUDGET", "ALL")],
153+
)
154+
155+
# create the flow model interface
156+
gwf_name = get_model_name(name, "gwf")
157+
gwf_budget_file = gwf_ws / f"{gwf_name}.bud"
158+
gwf_head_file = gwf_ws / f"{gwf_name}.hds"
159+
flopy.mf6.ModflowPrtfmi(
160+
prt,
161+
packagedata=[
162+
("GWFHEAD", gwf_head_file),
163+
("GWFBUDGET", gwf_budget_file),
164+
],
165+
)
166+
167+
# add explicit model solution
168+
ems = flopy.mf6.ModflowEms(
169+
sim,
170+
pname="ems",
171+
filename=f"{prt_name}.ems",
172+
)
173+
sim.register_solution_package(ems, [prt.name])
174+
175+
return sim
176+
177+
178+
def build_models(idx, test):
179+
gwf_ws = test.workspace / "gwf"
180+
prt_ws = test.workspace / "prt"
181+
gwf_sim = FlopyReadmeCase.get_gwf_sim(
182+
test.name, gwf_ws, test.targets["mf6"]
183+
)
184+
prt_sim = build_prt_sim(test.name, gwf_ws, prt_ws, test.targets["mf6"])
185+
return gwf_sim, prt_sim
186+
187+
188+
def check_output(idx, test):
189+
name = test.name
190+
gwf_ws = test.workspace
191+
prt_ws = test.workspace / "prt"
192+
gwf_sim, prt_sim = test.sims[:2]
193+
gwf = gwf_sim.get_model()
194+
prt = prt_sim.get_model()
195+
hds = gwf.output.head().get_data()
196+
mg = gwf.modelgrid
197+
pathlines = pd.read_csv(prt_ws / f"{prt.name}.trk.csv")
198+
startpts = pathlines[pathlines.ireason == 0]
199+
endpts = pathlines[pathlines.ireason == 3]
200+
201+
# check start points
202+
assert np.allclose(
203+
np.sort(startpts[["x", "y"]].to_numpy(), axis=0),
204+
np.sort(np.array(get_start_points()), axis=0),
205+
)
206+
207+
# setup plot
208+
plot_data = False
209+
if plot_data:
210+
fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(10, 10))
211+
for a in ax:
212+
a.set_aspect("equal")
213+
214+
# plot pathline in map view
215+
pmv = flopy.plot.PlotMapView(modelgrid=mg, ax=ax[0])
216+
pmv.plot_grid()
217+
pmv.plot_array(hds[0], alpha=0.1, cmap="jet")
218+
pmv.plot_pathline(pathlines)
219+
220+
# view/save plot
221+
plt.show()
222+
plt.savefig(gwf_ws / f"test_{simname}.png")
223+
224+
225+
@pytest.mark.parametrize("idx, name", enumerate(cases))
226+
def test_mf6model(idx, name, function_tmpdir, targets):
227+
test = TestFramework(
228+
name=name,
229+
workspace=function_tmpdir,
230+
build=lambda t: build_models(idx, t),
231+
check=lambda t: check_output(idx, t),
232+
targets=targets,
233+
compare=None,
234+
)
235+
test.run()

autotest/test_prt_fmi.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
"""
22
Tests ability to run a GWF model then a PRT model
33
in separate simulations via flow model interface,
4-
as well as
54
65
The grid is a 10x10 square with a single layer,
76
the same flow system shown on the FloPy readme.

doc/ReleaseNotes/develop.tex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
\item An array out of bounds error for Z-displacement output in inactive cells has been fixed in the CSUB package. Depending on the combination of platform and compiler used to build the program, this could result in crashes.
3333
\item Initialize a few uninitialized variables in the CSUB package. Depending on the combination of platform and compiler used to build the program, this could result in different program behaviour.
3434
\item Add a warning if saving convergence data for the CSUB package when delay beds are not included in a simulation. Also modified the convergence output data so that it is clear that DVMAX and DSTORAGEMAX data and locations are not calculated in this case (by writing `-\,-' to the output file).
35-
35+
\item Previously the PRT model's PRP package required release points to be specified in the model coordinate system (except for the z coordinate via the LOCAL\_Z option). PRT also previously reported pathlines in the model coordinate system. The PRT model now supports coordinate transformations for release point input and pathline output via keyword options for the PRP package, while preserving the existing default model coordinate system. Release point x and y coordinates may now be specified for structured grids with reference to the local rectilinear cell (with coordinates scaled to the unit interval) via the LOCAL\_XY keyword option. The LOCAL\_XY\_OFFSET option, supported for structured or unstructured grids, can be used to locate release point x and y coordinates at an offset from the cell center (with no distance rescaling). A development option DEV\_GLOBAL\_XY is also provided, enabling transformation of release points from (and pathline points to) the global coordinate system for georeferenced grids.
3636
% \item xxx
3737
\end{itemize}
3838

doc/mf6io/mf6ivar/dfn/prt-prp.dfn

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,31 @@ type keyword
4040
reader urword
4141
optional true
4242
longname whether to use local z coordinates
43-
description indicates that ``zrpt'' defines the local z coordinate of the release point within the cell, with value of 0 at the bottom and 1 at the top of the cell. If the cell is partially saturated at release time, the top of the cell is considered to be the water table elevation (the head in the cell) rather than the top defined by the user.
43+
description indicates that ``zrpt'' defines the local z coordinate of the release point within the cell scaled to the unit interval, with value of 0 at the bottom and 1 at the top of the cell. If the cell is partially saturated at release time, the top of the cell is considered to be the water table elevation (the head in the cell) rather than the top defined by the user.
44+
45+
block options
46+
name local_xy
47+
type keyword
48+
reader urword
49+
optional true
50+
longname whether to use local x and y coordinates
51+
description indicates that ``xrpt'' and ``yrpt'' define the local x and y coordinates of the release point within the cell scaled to the unit interval, with value of 0 at the west and south faces and 1 at the east and north faces of the cell. This option may only be used with structured models.
52+
53+
block options
54+
name local_xy_offset
55+
type keyword
56+
reader urword
57+
optional true
58+
longname whether to use local x and y offsets
59+
description indicates that ``xrpt'' and ``rpt'' define the local x and y offsets of the release point within the cell, where the local coordinate system's origin is the cell center and distances are not rescaled. This option may be used with structured or unstructured models.
60+
61+
block options
62+
name dev_global_xy
63+
type keyword
64+
reader urword
65+
optional true
66+
longname whether to transform x and y coordinates
67+
description indicates that ``xrpt'' and ``yrpt'' define global coordinates and should be transformed to the model coordinate system if georeferencing information (origin and rotation) is available on the model grid. By default, release points are assumed to be in model coordinates. If this option is enabled, particle pathlines will also be reported in global coordinates in output files.
4468

4569
block options
4670
name extend_tracking

doc/mf6io/mf6ivar/md/mf6ivar.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1615,9 +1615,12 @@
16151615
| PRT | OC | PERIOD | STEPS | INTEGER (<NSTP) | save for each step specified in STEPS. This keyword may be used in conjunction with other keywords to print or save results for multiple time steps. |
16161616
| PRT | PRP | OPTIONS | BOUNDNAMES | KEYWORD | keyword to indicate that boundary names may be provided with the list of particle release points. |
16171617
| PRT | PRP | OPTIONS | PRINT_INPUT | KEYWORD | keyword to indicate that the list of all model stress package information will be written to the listing file immediately after it is read. |
1618-
| PRT | PRP | OPTIONS | DEV_EXIT_SOLVE_METHOD | INTEGER | the method for iterative solution of particle exit location and time in the generalized Pollock's method. 1 Brent, 2 Chandrupatla. The default is Brent. |
1618+
| PRT | PRP | OPTIONS | DEV_EXIT_SOLVE_METHOD | INTEGER | the method for iterative solution of particle exit location and time in the generalized Pollock's method. 0 default, 1 Brent, 2 Chandrupatla. The default is Brent's method. |
16191619
| PRT | PRP | OPTIONS | EXIT_SOLVE_TOLERANCE | DOUBLE PRECISION | the convergence tolerance for iterative solution of particle exit location and time in the generalized Pollock's method. A value of 0.00001 works well for many problems, but the value that strikes the best balance between accuracy and runtime is problem-dependent. |
1620-
| PRT | PRP | OPTIONS | LOCAL_Z | KEYWORD | indicates that ``zrpt'' defines the local z coordinate of the release point within the cell, with value of 0 at the bottom and 1 at the top of the cell. If the cell is partially saturated at release time, the top of the cell is considered to be the water table elevation (the head in the cell) rather than the top defined by the user. |
1620+
| PRT | PRP | OPTIONS | LOCAL_Z | KEYWORD | indicates that ``zrpt'' defines the local z coordinate of the release point within the cell scaled to the unit interval, with value of 0 at the bottom and 1 at the top of the cell. If the cell is partially saturated at release time, the top of the cell is considered to be the water table elevation (the head in the cell) rather than the top defined by the user. |
1621+
| PRT | PRP | OPTIONS | LOCAL_XY | KEYWORD | indicates that ``xrpt'' and ``yrpt'' define the local x and y coordinates of the release point within the cell scaled to the unit interval, with value of 0 at the west and south faces and 1 at the east and north faces of the cell. This option may only be used with structured models. |
1622+
| PRT | PRP | OPTIONS | LOCAL_XY_OFFSET | KEYWORD | indicates that ``xrpt'' and ``rpt'' define the local x and y offsets of the release point within the cell, where the local coordinate system's origin is the cell center and distances are not rescaled. This option may be used with structured or unstructured models. |
1623+
| PRT | PRP | OPTIONS | DEV_GLOBAL_XY | KEYWORD | indicates that ``xrpt'' and ``yrpt'' define global coordinates and should be transformed to the model coordinate system if georeferencing information (origin and rotation) is available on the model grid. By default, release points are assumed to be in model coordinates. If this option is enabled, particle pathlines will also be reported in global coordinates in output files. |
16211624
| PRT | PRP | OPTIONS | EXTEND_TRACKING | KEYWORD | indicates that particles should be tracked beyond the end of the simulation's final time step (using that time step's flows) until particles terminate or reach a specified stop time. By default, particles are terminated at the end of the simulation's final time step. |
16221625
| PRT | PRP | OPTIONS | TRACK | KEYWORD | keyword to specify that record corresponds to a binary track output file. Each PRP Package may have a distinct binary track output file. |
16231626
| PRT | PRP | OPTIONS | FILEOUT | KEYWORD | keyword to specify that an output filename is expected next. |

doc/mf6io/mf6ivar/tex/prt-prp-desc.tex

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@
99

1010
\item \texttt{exit\_solve\_tolerance}---the convergence tolerance for iterative solution of particle exit location and time in the generalized Pollock's method. A value of 0.00001 works well for many problems, but the value that strikes the best balance between accuracy and runtime is problem-dependent.
1111

12-
\item \texttt{LOCAL\_Z}---indicates that ``zrpt'' defines the local z coordinate of the release point within the cell, with value of 0 at the bottom and 1 at the top of the cell. If the cell is partially saturated at release time, the top of the cell is considered to be the water table elevation (the head in the cell) rather than the top defined by the user.
12+
\item \texttt{LOCAL\_Z}---indicates that ``zrpt'' defines the local z coordinate of the release point within the cell scaled to the unit interval, with value of 0 at the bottom and 1 at the top of the cell. If the cell is partially saturated at release time, the top of the cell is considered to be the water table elevation (the head in the cell) rather than the top defined by the user.
13+
14+
\item \texttt{LOCAL\_XY}---indicates that ``xrpt'' and ``yrpt'' define the local x and y coordinates of the release point within the cell scaled to the unit interval, with value of 0 at the west and south faces and 1 at the east and north faces of the cell. This option may only be used with structured models.
15+
16+
\item \texttt{LOCAL\_XY\_OFFSET}---indicates that ``xrpt'' and ``rpt'' define the local x and y offsets of the release point within the cell, where the local coordinate system's origin is the cell center and distances are not rescaled. This option may be used with structured or unstructured models.
1317

1418
\item \texttt{EXTEND\_TRACKING}---indicates that particles should be tracked beyond the end of the simulation's final time step (using that time step's flows) until particles terminate or reach a specified stop time. By default, particles are terminated at the end of the simulation's final time step.
1519

doc/mf6io/mf6ivar/tex/prt-prp-options.dat

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ BEGIN OPTIONS
33
[PRINT_INPUT]
44
EXIT_SOLVE_TOLERANCE <exit_solve_tolerance>
55
[LOCAL_Z]
6+
[LOCAL_XY]
7+
[LOCAL_XY_OFFSET]
68
[EXTEND_TRACKING]
79
[TRACK FILEOUT <trackfile>]
810
[TRACKCSV FILEOUT <trackcsvfile>]

make/makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,8 @@ $(OBJDIR)/Particle.o \
232232
$(OBJDIR)/FlowModelInterface.o \
233233
$(OBJDIR)/Cell.o \
234234
$(OBJDIR)/Subcell.o \
235-
$(OBJDIR)/TrackData.o \
235+
$(OBJDIR)/TrackFile.o \
236+
$(OBJDIR)/TrackControl.o \
236237
$(OBJDIR)/TimeSelect.o \
237238
$(OBJDIR)/prt-fmi.o \
238239
$(OBJDIR)/TimeStepSelect.o \

msvs/mf6core.vfproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,8 @@
289289
<File RelativePath="..\src\Model\ModelUtilities\SwfCxsUtils.f90"/>
290290
<File RelativePath="..\src\Model\ModelUtilities\TimeSelect.f90"/>
291291
<File RelativePath="..\src\Model\ModelUtilities\TimeStepSelect.f90"/>
292-
<File RelativePath="..\src\Model\ModelUtilities\TrackData.f90"/>
292+
<File RelativePath="..\src\Model\ModelUtilities\TrackControl.f90"/>
293+
<File RelativePath="..\src\Model\ModelUtilities\TrackFile.f90"/>
293294
<File RelativePath="..\src\Model\ModelUtilities\TspAdvOptions.f90"/>
294295
<File RelativePath="..\src\Model\ModelUtilities\UzfCellGroup.f90"/>
295296
<File RelativePath="..\src\Model\ModelUtilities\VectorInterpolation.f90"/>

0 commit comments

Comments
 (0)