From 0c44a71d4cdc4af35a702b4e418fbf51e9c3277f Mon Sep 17 00:00:00 2001 From: w-bonelli Date: Tue, 10 Oct 2023 14:27:02 -0400 Subject: [PATCH] more test cleanup --- autotest/prt/prt_test_utils.py | 52 +++++++++++---------------- autotest/prt/test_prt_exg01.py | 32 ++++------------- autotest/prt/test_prt_fmi01.py | 15 ++++---- autotest/prt/test_prt_fmi02.py | 17 ++++----- autotest/prt/test_prt_fmi03.py | 41 +++++++--------------- autotest/prt/test_prt_fmi04.py | 38 +++++++------------- autotest/prt/test_prt_fmi05.py | 64 +++++++++++++++------------------- autotest/prt/test_prt_fmi06.py | 20 +++++------ 8 files changed, 105 insertions(+), 174 deletions(-) diff --git a/autotest/prt/prt_test_utils.py b/autotest/prt/prt_test_utils.py index e61805325f0..7edc192a67e 100644 --- a/autotest/prt/prt_test_utils.py +++ b/autotest/prt/prt_test_utils.py @@ -1,20 +1,23 @@ import os from types import SimpleNamespace -from typing import Optional, Tuple, Union +from typing import Optional, Tuple import flopy import numpy as np -import pandas as pd -def all_equal(col, val): - a = col.to_numpy() +def all_equal(series, val): + a = series.to_numpy() return a[0] == val and (a[0] == a).all() def get_gwf_sim( name, ws, mf6 ) -> Tuple[flopy.mf6.MFSimulation, SimpleNamespace]: + """ + Simple GWF simulation for use/modification by PRT tests + """ + # test case context ctx = SimpleNamespace( nlay=1, @@ -30,15 +33,12 @@ def get_gwf_sim( # mp7 release points (cell-local coordinates) releasepts_mp7=[ # node number, localx, localy, localz - # (0-based indexing converted to 1-based for mp7 by flopy) (0, float(f"0.{i + 1}"), float(f"0.{i + 1}"), 0.5) for i in range(9) ], - # expected release points in PRT format; use flopy - # to convert mp7 to prt format then check equality + # PRT release points (cell indices and global coordinates both required) releasepts_prt=[ # particle index, k, i, j, x, y, z - # (0-based indexing converted to 1-based for mf6 by flopy) [i, 0, 0, 0, float(f"0.{i + 1}"), float(f"9.{i + 1}"), 0.5] for i in range(9) ], @@ -119,7 +119,7 @@ def check_track_data( track_hdr: os.PathLike, track_csv: os.PathLike, ): - """Check that track data written to binary, CSV, and budget files are equal.""" + """Check that binary and CSV track files are equal.""" # get dtype from ascii header file dt = get_track_dtype(track_hdr) @@ -135,8 +135,7 @@ def check_track_data( data_bin.shape == data_csv.shape ), f"Binary and CSV track data shapes do not match: {data_bin.shape} != {data_csv.shape}" - # check particle tracks written to all output files are equal - # check each column separately to avoid: + # check each column separately to avoid # TypeError: The DType could not be promoted by for k in data_bin.dtype.names: if k == "name": @@ -184,7 +183,8 @@ def get_model_name(name, mdl): def get_track_dtype(path: os.PathLike): - """Get the dtype of the track data recarray from the ascii header file.""" + """Read a numpy dtype describing particle track + data format from the ascii track header file.""" hdr_lns = open(path).readlines() hdr_lns_spl = [[ll.strip() for ll in l.split(",")] for l in hdr_lns] @@ -192,6 +192,11 @@ def get_track_dtype(path: os.PathLike): def get_ireason_code(output_event): + """ + Map output event to PRT ireason code specifing + the reason a particle track datum was recorded. + """ + return ( 0 if output_event == "RELEASE" @@ -208,6 +213,10 @@ def get_ireason_code(output_event): def get_partdata(grid, rpts): + """ + Make a flopy.modpath.ParticleData from the given grid and release points. + """ + if grid.grid_type == "structured": return flopy.modpath.ParticleData( partlocs=[grid.get_lrc(p[0])[0] for p in rpts], @@ -230,25 +239,6 @@ def get_partdata(grid, rpts): ) -def get_perioddata(name, periods=1, fraction=None) -> Optional[dict]: - if "reft" in name: - return None - opt = [ - "FIRST" - if "frst" in name - else "ALL" - if "all" in name - else ("STEPS", 1) - if "stps" in name - else None - ] - if opt[0] is None: - raise ValueError(f"Invalid period option: {name}") - if fraction is not None: - opt.append(("FRACTION", fraction)) - return {i: opt for i in range(periods)} - - def has_default_boundnames(data): name = [int(n.partition("0")[2]) for n in data["name"].to_numpy()] irpt = data["irpt"].to_numpy() diff --git a/autotest/prt/test_prt_exg01.py b/autotest/prt/test_prt_exg01.py index ed80291bd93..cd1555c1385 100644 --- a/autotest/prt/test_prt_exg01.py +++ b/autotest/prt/test_prt_exg01.py @@ -25,32 +25,14 @@ from flopy.plot.plotutil import to_mp7_pathlines from flopy.utils import PathlineFile from flopy.utils.binaryfile import HeadFile -from prt_test_utils import (all_equal, check_budget_data, check_track_data, - get_gwf_sim, has_default_boundnames) +from prt_test_utils import check_budget_data, check_track_data, get_gwf_sim from framework import TestFramework from simulation import TestSimulation -# simulation/model names simname = "prtexg01" - -# test cases ex = [simname, f"{simname}bnms"] -# release points -releasepts = [ - # index, k, i, j, x, y, z - # (0-based indexing converted to 1-based for mf6 by flopy) - [i, 0, 0, 0, float(f"0.{i + 1}"), float(f"9.{i + 1}"), 0.5] - for i in range(9) -] -releasepts_mp7 = [ - # node number, localx, localy, localz - # (0-based indexing converted to 1-based for mp7 by flopy) - (0, float(f"0.{i + 1}"), float(f"0.{i + 1}"), 0.5) - for i in range(9) -] - # model names def get_model_name(idx, mdl): @@ -80,9 +62,9 @@ def build_sim(idx, ws, mf6): # create prp package rpts = ( - [r + [str(r[0] + 1)] for r in releasepts] + [r + [str(r[0] + 1)] for r in ctx.releasepts_prt] if "bnms" in name - else releasepts + else ctx.releasepts_prt ) flopy.mf6.ModflowPrtprp( prt, @@ -137,10 +119,10 @@ def build_sim(idx, ws, mf6): def build_mp7_sim(ctx, idx, ws, mp7, gwf): partdata = flopy.modpath.ParticleData( - partlocs=[p[0] for p in releasepts_mp7], - localx=[p[1] for p in releasepts_mp7], - localy=[p[2] for p in releasepts_mp7], - localz=[p[3] for p in releasepts_mp7], + partlocs=[p[0] for p in ctx.releasepts_mp7], + localx=[p[1] for p in ctx.releasepts_mp7], + localy=[p[2] for p in ctx.releasepts_mp7], + localz=[p[3] for p in ctx.releasepts_mp7], timeoffset=0, drape=0, ) diff --git a/autotest/prt/test_prt_fmi01.py b/autotest/prt/test_prt_fmi01.py index 461c89921d9..e5f1197fb25 100644 --- a/autotest/prt/test_prt_fmi01.py +++ b/autotest/prt/test_prt_fmi01.py @@ -36,14 +36,17 @@ from flopy.plot.plotutil import to_mp7_pathlines from flopy.utils import PathlineFile from flopy.utils.binaryfile import HeadFile -from prt_test_utils import (all_equal, check_budget_data, check_track_data, - get_gwf_sim, get_model_name, get_partdata, - has_default_boundnames) +from prt_test_utils import ( + all_equal, + check_budget_data, + check_track_data, + get_gwf_sim, + get_model_name, + get_partdata, + has_default_boundnames, +) -# simulation name simname = "prtfmi01" - -# test cases ex = [simname, f"{simname}saws"] diff --git a/autotest/prt/test_prt_fmi02.py b/autotest/prt/test_prt_fmi02.py index 846a00ba250..17fea05db5d 100644 --- a/autotest/prt/test_prt_fmi02.py +++ b/autotest/prt/test_prt_fmi02.py @@ -36,13 +36,14 @@ from flopy.plot.plotutil import to_mp7_pathlines from flopy.utils import PathlineFile from flopy.utils.binaryfile import HeadFile -from prt_test_utils import (check_budget_data, check_track_data, get_gwf_sim, - get_model_name, get_partdata) +from prt_test_utils import ( + check_budget_data, + check_track_data, + get_gwf_sim, + get_model_name, +) -# simulation/model names simname = "prtfmi02" - -# test cases ex = [ f"{simname}all", f"{simname}rel", @@ -50,18 +51,14 @@ f"{simname}tstp", f"{simname}wksk", ] - -# release points releasepts_prt = { "a": [ # index, k, i, j, x, y, z - # (0-based indexing converted to 1-based for mf6 by flopy) [i, 0, 0, 0, float(f"0.{i + 1}"), float(f"9.{i + 1}"), 0.5] for i in range(4) ], "b": [ # index, k, i, j, x, y, z - # (0-based indexing converted to 1-based for mf6 by flopy) [i, 0, 0, 0, float(f"0.{i + 5}"), float(f"9.{i + 5}"), 0.5] for i in range(5) ], @@ -69,13 +66,11 @@ releasepts_mp7 = { "a": [ # node number, localx, localy, localz - # (0-based indexing converted to 1-based for mf6 by flopy) (0, float(f"0.{i + 1}"), float(f"0.{i + 1}"), 0.5) for i in range(4) ], "b": [ # node number, localx, localy, localz - # (0-based indexing converted to 1-based for mf6 by flopy) (0, float(f"0.{i + 5}"), float(f"0.{i + 5}"), 0.5) for i in range(5) ], diff --git a/autotest/prt/test_prt_fmi03.py b/autotest/prt/test_prt_fmi03.py index 90b197485af..c9884fb308e 100644 --- a/autotest/prt/test_prt_fmi03.py +++ b/autotest/prt/test_prt_fmi03.py @@ -37,16 +37,15 @@ from flopy.utils import PathlineFile from flopy.utils.binaryfile import HeadFile from matplotlib.collections import LineCollection -from prt_test_utils import (check_budget_data, check_track_data, get_gwf_sim, - get_model_name) +from prt_test_utils import ( + check_budget_data, + check_track_data, + get_gwf_sim, + get_model_name, +) -# simulation name simname = "prtfmi03" - -# test cases ex = [f"{simname}_l1", f"{simname}_l2"] - -# izone stopzone_cells = [(0, 1, 8), (0, 8, 1)] @@ -57,22 +56,6 @@ def create_izone(nlay, nrow, ncol): return izone -# release points -# todo: define for mp7 first, then use flopy utils to convert to global coords for mf6 prt -releasepts_mp7 = [ - # node number, localx, localy, localz - # (0-based indexing converted to 1-based for mp7 by flopy) - (0, float(f"0.{i + 1}"), float(f"0.{i + 1}"), 0.5) - for i in range(9) -] -releasepts_prt = [ - # particle index, k, i, j, x, y, z - # (0-based indexing converted to 1-based for mf6 by flopy) - (i, 0, 0, 0, float(f"0.{i + 1}"), float(f"9.{i + 1}"), 0.5) - for i in range(9) -] - - def build_prt_sim(ctx, name, ws, mf6): # create simulation sim = flopy.mf6.MFSimulation( @@ -122,8 +105,8 @@ def build_prt_sim(ctx, name, ws, mf6): prt, pname="prp1", filename=f"{prtname}_1.prp", - nreleasepts=len(releasepts_prt), - packagedata=releasepts_prt, + nreleasepts=len(ctx.releasepts_prt), + packagedata=ctx.releasepts_prt, perioddata={0: ["FIRST"]}, istopzone=1, ) @@ -163,10 +146,10 @@ def build_prt_sim(ctx, name, ws, mf6): def build_mp7_sim(ctx, name, ws, mp7, gwf): partdata = flopy.modpath.ParticleData( - partlocs=[p[0] for p in releasepts_mp7], - localx=[p[1] for p in releasepts_mp7], - localy=[p[2] for p in releasepts_mp7], - localz=[p[3] for p in releasepts_mp7], + partlocs=[p[0] for p in ctx.releasepts_mp7], + localx=[p[1] for p in ctx.releasepts_mp7], + localy=[p[2] for p in ctx.releasepts_mp7], + localz=[p[3] for p in ctx.releasepts_mp7], timeoffset=0, drape=0, ) diff --git a/autotest/prt/test_prt_fmi04.py b/autotest/prt/test_prt_fmi04.py index 961e36ff55d..9e1ae1d2173 100644 --- a/autotest/prt/test_prt_fmi04.py +++ b/autotest/prt/test_prt_fmi04.py @@ -35,29 +35,17 @@ from flopy.plot.plotutil import to_mp7_pathlines from flopy.utils import PathlineFile from flopy.utils.binaryfile import HeadFile -from prt_test_utils import (check_budget_data, check_track_data, get_gwf_sim, - get_ireason_code, get_model_name) +from prt_test_utils import ( + check_budget_data, + check_track_data, + get_gwf_sim, + get_ireason_code, + get_model_name, +) -# simulation name simname = "prtfmi04" - -# test cases ex = [simname, f"{simname}saws"] -# release points -releasepts_mp7 = [ - # node number, localx, localy, localz - # (0-based indexing converted to 1-based for mp7 by flopy) - (0, float(f"0.{i + 1}"), float(f"0.{i + 1}"), 0.5) - for i in range(9) -] -releasepts_prt = [ - # particle index, k, i, j, x, y, z - # (0-based indexing converted to 1-based for mf6 by flopy) - (i, 0, 0, 0, float(f"0.{i + 1}"), float(f"9.{i + 1}"), 0.5) - for i in range(9) -] - def build_prt_sim(ctx, name, ws, mf6): # output file names @@ -106,8 +94,8 @@ def build_prt_sim(ctx, name, ws, mf6): prt, pname="prp1", filename=f"{prtname}_1.prp", - nreleasepts=len(releasepts_prt), - packagedata=releasepts_prt, + nreleasepts=len(ctx.releasepts_prt), + packagedata=ctx.releasepts_prt, perioddata={0: ["FIRST"]}, stop_at_weak_sink="saws" in name, ) @@ -145,10 +133,10 @@ def build_mp7_sim(ctx, name, ws, mp7, gwf): mp7_pathline_file = f"{mp7name}.mppth" partdata = flopy.modpath.ParticleData( - partlocs=[p[0] for p in releasepts_mp7], - localx=[p[1] for p in releasepts_mp7], - localy=[p[2] for p in releasepts_mp7], - localz=[p[3] for p in releasepts_mp7], + partlocs=[p[0] for p in ctx.releasepts_mp7], + localx=[p[1] for p in ctx.releasepts_mp7], + localy=[p[2] for p in ctx.releasepts_mp7], + localz=[p[3] for p in ctx.releasepts_mp7], timeoffset=0, drape=0, ) diff --git a/autotest/prt/test_prt_fmi05.py b/autotest/prt/test_prt_fmi05.py index 5f0be45e705..ccc83c3a725 100644 --- a/autotest/prt/test_prt_fmi05.py +++ b/autotest/prt/test_prt_fmi05.py @@ -37,14 +37,16 @@ from flopy.plot.plotutil import to_mp7_pathlines from flopy.utils import PathlineFile from flopy.utils.binaryfile import HeadFile -from prt_test_utils import (all_equal, check_budget_data, check_track_data, - get_gwf_sim, get_model_name, get_perioddata, - has_default_boundnames) +from prt_test_utils import ( + all_equal, + check_budget_data, + check_track_data, + get_gwf_sim, + get_model_name, + get_partdata, +) -# simulation name simname = "prtfmi05" - -# test cases ex = [ # options block options f"{simname}reft", # REFERENCETIME 0.5 @@ -54,34 +56,24 @@ f"{simname}stps", # STEPS 1 FRACTION 0.5 ] -# release points in mp7 format (using local coordinates) -releasepts_mp7 = [ - # node number, localx, localy, localz - # (0-based indexing converted to 1-based for mp7 by flopy) - (0, float(f"0.{i + 1}"), float(f"0.{i + 1}"), 0.5) - for i in range(9) -] - -# expected release points in PRT format; below we will use flopy -# to convert from mp7 to prt format and make sure they are equal -releasepts_prt = [ - # particle index, k, i, j, x, y, z - # (0-based indexing converted to 1-based for mf6 by flopy) - (i, 0, 0, 0, float(f"0.{i + 1}"), float(f"9.{i + 1}"), 0.5) - for i in range(9) -] - -def get_partdata(grid): - return flopy.modpath.ParticleData( - partlocs=[grid.get_lrc(p[0])[0] for p in releasepts_mp7], - structured=True, - localx=[p[1] for p in releasepts_mp7], - localy=[p[2] for p in releasepts_mp7], - localz=[p[3] for p in releasepts_mp7], - timeoffset=0, - drape=0, - ) +def get_perioddata(name, periods=1, fraction=None) -> Optional[dict]: + if "reft" in name: + return None + opt = [ + "FIRST" + if "frst" in name + else "ALL" + if "all" in name + else ("STEPS", 1) + if "stps" in name + else None + ] + if opt[0] is None: + raise ValueError(f"Invalid period option: {name}") + if fraction is not None: + opt.append(("FRACTION", fraction)) + return {i: opt for i in range(periods)} def build_prt_sim(ctx, name, ws, mf6, fraction=None): @@ -119,11 +111,11 @@ def build_prt_sim(ctx, name, ws, mf6, fraction=None): flopy.mf6.ModflowPrtmip(prt, pname="mip", porosity=ctx.porosity) # convert mp7 particledata to prt release points - partdata = get_partdata(prt.modelgrid) + partdata = get_partdata(prt.modelgrid, ctx.releasepts_mp7) releasepts = list(partdata.to_prp(prt.modelgrid)) # check release points match expectation - assert np.allclose(releasepts_prt, releasepts) + assert np.allclose(ctx.releasepts_prt, releasepts) # create prp package prp_track_file = f"{prtname}.prp.trk" @@ -178,7 +170,7 @@ def build_prt_sim(ctx, name, ws, mf6, fraction=None): def build_mp7_sim(ctx, name, ws, mp7, gwf): # convert mp7 particledata to prt release points - partdata = get_partdata(gwf.modelgrid) + partdata = get_partdata(gwf.modelgrid, ctx.releasepts_mp7) # create modpath 7 simulation mp7name = get_model_name(name, "mp7") diff --git a/autotest/prt/test_prt_fmi06.py b/autotest/prt/test_prt_fmi06.py index 30cab70ec2a..f1a90b75003 100644 --- a/autotest/prt/test_prt_fmi06.py +++ b/autotest/prt/test_prt_fmi06.py @@ -4,7 +4,6 @@ from pathlib import Path from pprint import pformat -from typing import Optional import flopy import matplotlib.cm as cm @@ -16,16 +15,16 @@ from flopy.utils import PathlineFile from flopy.utils.binaryfile import HeadFile from flopy.utils.gridutil import get_disv_kwargs -from prt_test_utils import (all_equal, check_budget_data, check_track_data, - get_partdata, has_default_boundnames) +from prt_test_utils import ( + all_equal, + check_budget_data, + check_track_data, + get_partdata, + has_default_boundnames, +) -# simulation name simname = "prtfmi06" - -# test cases -ex = [ - f"{simname}a", -] +ex = [f"{simname}a"] # model info nlay = 1 @@ -57,10 +56,9 @@ botm, ) -# release points in mp7 format (using local coordinates) +# release points in mp7 format releasepts_mp7 = [ # node number, localx, localy, localz - # (0-based indexing converted to 1-based for mp7 by flopy) (i * 10, 0.5, 0.5, 0.5) for i in range(10) ]