Skip to content

Commit

Permalink
ci(plotting): update autotests with plots to use new pytest --plot ho…
Browse files Browse the repository at this point in the history
…ok (#2089)

* ci(plotting): update autotest plotting

* describe plot hook in developer doc

* cleanup

* reword
  • Loading branch information
langevin-usgs authored Dec 5, 2024
1 parent fe1ff54 commit 9f49296
Show file tree
Hide file tree
Showing 17 changed files with 164 additions and 233 deletions.
10 changes: 8 additions & 2 deletions DEVELOPER.md
Original file line number Diff line number Diff line change
Expand Up @@ -763,23 +763,29 @@ def check_output(idx, test):
e = expected[idx]
...

def plot_output(idx, test):
import matplotlib.pyplot as plt
...

@pytest.mark.parametrize("idx, name", enumerate(cases))
def test_mf6model(idx, name, function_tmpdir, targets):
def test_mf6model(idx, name, function_tmpdir, targets, plot):
test = TestFramework(
name=name,
workspace=function_tmpdir,
targets=targets,
build=lambda t: build_models(idx, t),
check=lambda t: check_output(idx, t),
plot=lambda t: plot_output(idx, t) if plot else None,
compare=None,
)
test.run()
```

The framework has two hooks:
The framework has three hooks:

- `build`: construct one or more MF6 simulations and/or non-MF6 models with FloPy
- `check`: evaluate simulation/model output
- `plot`: make one or more plots of simulation/model output

A test script conventionally contains one or more test cases, fed to the test function as `idx, name` pairs. `idx` can be used to index parameter values or expected results for a specific test case. The test case `name` is useful for model/subdirectory naming, etc.

Expand Down
10 changes: 3 additions & 7 deletions autotest/test_chf_dfw_beg2022.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,7 @@ def build_models(idx, test):
return sim, None


def make_plot(test, mfsim):
print("making plots...")
def plot_output(idx, test):
import matplotlib.pyplot as plt

hecras = data_path / "hecras0125.csv.cmp"
Expand Down Expand Up @@ -251,10 +250,6 @@ def check_output(idx, test):
# get MFSimulation from test
sim = test.sims[0]

makeplot = False
if makeplot:
make_plot(test, sim)

# assign name
name = "chfmodel"

Expand Down Expand Up @@ -304,12 +299,13 @@ def check_output(idx, test):

@pytest.mark.developmode
@pytest.mark.parametrize("idx, name", enumerate(cases))
def test_mf6model(idx, name, function_tmpdir, targets):
def test_mf6model(idx, name, function_tmpdir, targets, plot):
test = TestFramework(
name=name,
workspace=function_tmpdir,
build=lambda t: build_models(idx, t),
check=lambda t: check_output(idx, t),
plot=lambda t: plot_output(idx, t) if plot else None,
targets=targets,
)
test.run()
9 changes: 3 additions & 6 deletions autotest/test_chf_dfw_swrt2.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ def build_models(idx, test):
return sim, None


def make_plot(test, mfsim):
def plot_output(idx, test):
print("making plots...")
import matplotlib.pyplot as plt

Expand Down Expand Up @@ -203,10 +203,6 @@ def check_output(idx, test):
ws = test.workspace
mfsim = flopy.mf6.MFSimulation.load(sim_ws=ws)

makeplot = False
if makeplot:
make_plot(test, mfsim)

# read binary stage file
fpth = test.workspace / f"{chfname}.stage"
sobj = flopy.utils.HeadFile(fpth, precision="double", text="STAGE")
Expand Down Expand Up @@ -243,12 +239,13 @@ def check_output(idx, test):

@pytest.mark.developmode
@pytest.mark.parametrize("idx, name", enumerate(cases))
def test_mf6model(idx, name, function_tmpdir, targets):
def test_mf6model(idx, name, function_tmpdir, targets, plot):
test = TestFramework(
name=name,
workspace=function_tmpdir,
build=lambda t: build_models(idx, t),
check=lambda t: check_output(idx, t),
plot=lambda t: plot_output(idx, t) if plot else None,
targets=targets,
)
test.run()
10 changes: 3 additions & 7 deletions autotest/test_chf_dfw_swrt2b.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,7 @@ def build_models(idx, test):
return sim, None


def make_plot(test, mfsim):
print("making plots...")
def plot_output(idx, test):
import matplotlib.pyplot as plt

fpth = test.workspace / "chf_model.obs.csv"
Expand Down Expand Up @@ -207,10 +206,6 @@ def check_output(idx, test):
ws = test.workspace
mfsim = flopy.mf6.MFSimulation.load(sim_ws=ws)

makeplot = False
if makeplot:
make_plot(test, mfsim)

# read binary stage file
fpth = test.workspace / f"{chfname}.stage"
sobj = flopy.utils.HeadFile(fpth, precision="double", text="STAGE")
Expand All @@ -229,12 +224,13 @@ def check_output(idx, test):

@pytest.mark.developmode
@pytest.mark.parametrize("idx, name", enumerate(cases))
def test_mf6model(idx, name, function_tmpdir, targets):
def test_mf6model(idx, name, function_tmpdir, targets, plot):
test = TestFramework(
name=name,
workspace=function_tmpdir,
build=lambda t: build_models(idx, t),
check=lambda t: check_output(idx, t),
plot=lambda t: plot_output(idx, t) if plot else None,
targets=targets,
)
test.run()
17 changes: 8 additions & 9 deletions autotest/test_chf_dis.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,16 @@ def add_chf_model_disv1d(sim):
return


def make_plot(test, mfsim, stage, idx):
print("making plots...")
def plot_output(idx, test):
import matplotlib.pyplot as plt

mfsim = test.sims[0]
chf = mfsim.chf[0]

stage = chf.output.stage().get_data().reshape((nodes,))

pmv = flopy.plot.PlotMapView(model=chf)
pmv.plot_array(stage, masked_values=[3e30])
pmv.plot_array(stage, masked_values=[3e30]) # not working yet
pmv.plot_grid()

fname = test.workspace / "results.png"
Expand Down Expand Up @@ -201,20 +204,16 @@ def check_output(idx, test):
assert stage[idomain == 1].max() == 1.0, "maximum stage should be 1.0"
assert stage[idomain == 1].min() == 0.5, "minimum stage should be 0.5"

makeplot = False
if makeplot:
# PlotMapView not working yet for disv1d
make_plot(test, mfsim, stage.flatten(), idx)


@pytest.mark.developmode
@pytest.mark.parametrize("idx, name", enumerate(cases))
def test_mf6model(idx, name, function_tmpdir, targets):
def test_mf6model(idx, name, function_tmpdir, targets, plot):
test = TestFramework(
name=name,
workspace=function_tmpdir,
build=lambda t: build_models(idx, t),
check=lambda t: check_output(idx, t),
plot=lambda t: plot_output(idx, t) if plot else None,
targets=targets,
)
test.run()
16 changes: 7 additions & 9 deletions autotest/test_chf_dis_fdc.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
angrot = 25.0

idomain = np.ones((nodes,), dtype=int)
idomain[3:6] = 0
h0 = 0.5
h1 = 1.0
rough = [0.035, 0.35]
Expand Down Expand Up @@ -145,11 +144,14 @@ def add_chf_model_disv1d(sim):
return


def make_plot(test, mfsim, stage, idx):
print("making plots...")
def plot_output(idx, test):
import matplotlib.pyplot as plt

mfsim = test.sims[0]
chf = mfsim.chf[0]

stage = chf.output.stage().get_data().reshape((nodes,))

pmv = flopy.plot.PlotMapView(model=chf)
pmv.plot_array(stage, masked_values=[3e30]) # not working yet
pmv.plot_grid()
Expand Down Expand Up @@ -241,20 +243,16 @@ def get_cond_n(depth, width, rough, dhds):
print(f"Simulated flow is {flow_sim} cubic meters per seconds")
assert np.allclose(flow, flow_sim), "known flow and simulated flow not the same"

makeplot = False
if makeplot:
# PlotMapView not working yet for disv1d
make_plot(test, mfsim, stage.flatten(), idx)


@pytest.mark.developmode
@pytest.mark.parametrize("idx, name", enumerate(cases))
def test_mf6model(idx, name, function_tmpdir, targets):
def test_mf6model(idx, name, function_tmpdir, targets, plot):
test = TestFramework(
name=name,
workspace=function_tmpdir,
build=lambda t: build_models(idx, t),
check=lambda t: check_output(idx, t),
plot=lambda t: plot_output(idx, t) if plot else None,
targets=targets,
)
test.run()
69 changes: 22 additions & 47 deletions autotest/test_gwt_buy_solute_heat.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,36 +322,23 @@ def build_models(idx, test):
return sim, None


def make_plot(sim):
print("making plots...")
name = sim.name
ws = sim.workspace
sim = flopy.mf6.MFSimulation.load(sim_ws=ws)
def plot_output(idx, test):
import matplotlib.pyplot as plt

ws = test.workspace
sim = test.sims[0]
gwfname = "flow"
gwtsname = "salinity"
gwthname = "temperature"
gwf = sim.get_model(gwfname)
gwts = sim.get_model(gwtsname)
gwth = sim.get_model(gwthname)

fname = gwtsname + ".ucn"
fname = os.path.join(ws, fname)
cobj = flopy.utils.HeadFile(fname, text="CONCENTRATION") # , precision='double')
conc = cobj.get_alldata()

fname = gwthname + ".ucn"
fname = os.path.join(ws, fname)
tobj = flopy.utils.HeadFile(fname, text="CONCENTRATION") # , precision='double')
temperature = tobj.get_alldata()

fname = gwfname + ".buy.bin"
fname = os.path.join(ws, fname)
dobj = flopy.utils.HeadFile(fname, text="DENSITY") # , precision='double')
dense = dobj.get_alldata()
conc = gwts.output.concentration().get_alldata()
temperature = gwth.output.concentration().get_alldata()
dense = gwf.buy.output.density().get_alldata()

idxtime = -1

import matplotlib.pyplot as plt
alpha = 1.0

fig = plt.figure(figsize=(10, 10))
nplotrows = 3
Expand All @@ -361,7 +348,7 @@ def make_plot(sim):
pxs.plot_bc(ftype="WEL")
pxs.plot_bc(ftype="GHB")
a = conc[idxtime]
pa = pxs.plot_array(a, cmap="jet", alpha=0.25)
pa = pxs.plot_array(a, cmap="jet", alpha=alpha)
cs = pxs.contour_array(a, levels=35.0 * np.array([0.01, 0.5, 0.99]), colors="y")
plt.colorbar(pa, shrink=0.5)
ax.set_title("SALINITY")
Expand All @@ -372,7 +359,7 @@ def make_plot(sim):
pxs.plot_bc(ftype="WEL")
pxs.plot_bc(ftype="GHB")
a = temperature[idxtime]
pa = pxs.plot_array(a, cmap="jet", alpha=0.25)
pa = pxs.plot_array(a, cmap="jet", alpha=alpha)
cs = pxs.contour_array(a, levels=5 + 20.0 * np.array([0.01, 0.5, 0.99]), colors="y")
plt.colorbar(pa, shrink=0.5)
ax.set_title("TEMPERATURE")
Expand All @@ -383,43 +370,31 @@ def make_plot(sim):
pxs.plot_bc(ftype="WEL")
pxs.plot_bc(ftype="GHB")
a = dense[idxtime]
pa = pxs.plot_array(a, cmap="jet", alpha=0.25)
pa = pxs.plot_array(a, cmap="jet", alpha=alpha)
# cs = pxs.contour_array(a, levels=5+20.*np.array([0.01, .5, 0.99]),
# colors='y')
plt.colorbar(pa, shrink=0.5)
ax.set_title("DENSITY")

plt.draw()
fname = os.path.join(ws, gwtsname + ".png")
fname = os.path.join(ws, "results.png")
plt.savefig(fname)

return


def check_output(idx, test):
makeplot = False
if makeplot:
make_plot(test)

ws = test.workspace
sim = test.sims[0]
gwfname = "flow"
gwtsname = "salinity"
gwthname = "temperature"

fname = gwfname + ".buy.bin"
fname = os.path.join(ws, fname)
dobj = flopy.utils.HeadFile(fname, text="DENSITY") # , precision='double')
dense = dobj.get_alldata()

fname = gwtsname + ".ucn"
fname = os.path.join(ws, fname)
cobj = flopy.utils.HeadFile(fname, text="CONCENTRATION") # , precision='double')
conc = cobj.get_alldata()

fname = gwthname + ".ucn"
fname = os.path.join(ws, fname)
tobj = flopy.utils.HeadFile(fname, text="CONCENTRATION") # , precision='double')
temperature = tobj.get_alldata()
gwf = sim.get_model(gwfname)
gwts = sim.get_model(gwtsname)
gwth = sim.get_model(gwthname)
conc = gwts.output.concentration().get_alldata()
temperature = gwth.output.concentration().get_alldata()
dense = gwf.buy.output.density().get_alldata()

# density is lagged, so use c and t from previous timestep
c = conc[-2]
Expand All @@ -440,14 +415,14 @@ def check_output(idx, test):
assert False, "density is not correct"


@pytest.mark.slow
@pytest.mark.parametrize("idx, name", enumerate(cases))
def test_mf6model(idx, name, function_tmpdir, targets):
def test_mf6model(idx, name, function_tmpdir, targets, plot):
test = TestFramework(
name=name,
workspace=function_tmpdir,
targets=targets,
build=lambda t: build_models(idx, t),
check=lambda t: check_output(idx, t),
plot=lambda t: plot_output(idx, t) if plot else None,
)
test.run()
Loading

0 comments on commit 9f49296

Please sign in to comment.