diff --git a/autotest/test_gwf_disv_uzf.py b/autotest/test_gwf_disv_uzf.py index 28e22c641be..787c821642a 100644 --- a/autotest/test_gwf_disv_uzf.py +++ b/autotest/test_gwf_disv_uzf.py @@ -14,7 +14,7 @@ import numpy as np import pytest from flopy.utils.gridutil import get_disv_kwargs -from framework import TestFramework +from framework import DNODATA, TestFramework cases = ["disv_with_uzf"] nlay = 5 @@ -109,20 +109,21 @@ uzf_spd.update({t: spd}) -# Work up the GHB boundary +# Work up the GHB / GHBG boundary ghb_ids = [(ncol - 1) + i * ncol for i in range(nrow)] ghb_spd = [] +abhead = np.full((nlay, ncpl), DNODATA, dtype=float) +acond = np.full((nlay, ncpl), DNODATA, dtype=float) cond = 1e4 for k in np.arange(3, 5, 1): for i in ghb_ids: ghb_spd.append([(k, i), 14.0, cond]) + abhead[k, i] = 14.0 + acond[k, i] = cond -def build_models(idx, test): - name = cases[idx] - +def get_model(ws, name, array_input=False): # build MODFLOW 6 files - ws = test.workspace sim = flopy.mf6.MFSimulation( sim_name=name, version="mf6", exe_name="mf6", sim_ws=ws ) @@ -171,7 +172,12 @@ def build_models(idx, test): sto = flopy.mf6.ModflowGwfsto(gwf, iconvert=1, ss=1e-5, sy=0.2, transient=True) # general-head boundary - ghb = flopy.mf6.ModflowGwfghb(gwf, print_flows=True, stress_period_data=ghb_spd) + if array_input: + ghb = flopy.mf6.ModflowGwfghbg( + gwf, print_flows=True, maxbound=20, bhead=abhead, cond=acond + ) + else: + ghb = flopy.mf6.ModflowGwfghb(gwf, print_flows=True, stress_period_data=ghb_spd) # unsaturated-zone flow etobs = [] @@ -220,18 +226,18 @@ def build_models(idx, test): obs_dict = {f"{name}.obs.csv": obs_lst} obs = flopy.mf6.ModflowUtlobs(gwf, pname="head_obs", digits=20, continuous=obs_dict) - return sim, None + return sim -def check_output(idx, test): +def check_output(ws, name): # Next, get the binary printed heads - fpth = os.path.join(test.workspace, test.name + ".hds") + fpth = os.path.join(ws, name + ".hds") hobj = flopy.utils.HeadFile(fpth, precision="double") hds = hobj.get_alldata() hds = hds.reshape((np.sum(nstp), 5, 10, 10)) # Get the MF6 cell-by-cell fluxes - bpth = os.path.join(test.workspace, test.name + ".cbc") + bpth = os.path.join(ws, name + ".cbc") bobj = flopy.utils.CellBudgetFile(bpth, precision="double") bobj.get_unique_record_names() # ' STO-SS' @@ -249,7 +255,7 @@ def check_output(idx, test): gwet = gwetv.reshape((np.sum(nstp), 5, 10, 10)) # Also retrieve the binary UZET output - uzpth = os.path.join(test.workspace, test.name + ".uzf.bud") + uzpth = os.path.join(ws, name + ".uzf.bud") uzobj = flopy.utils.CellBudgetFile(uzpth, precision="double") uzobj.get_unique_record_names() # b' FLOW-JA-FACE', @@ -353,7 +359,33 @@ def check_output(idx, test): print("Finished running checks") +def build_models(idx, test): + # build MODFLOW 6 files + ws = test.workspace + name = cases[idx] + sim = get_model(ws, name) + + # build comparison array_input model + ws = os.path.join(test.workspace, "mf6") + mc = get_model(ws, name, array_input=True) + + return sim, mc + + +def check_outputs(idx, test): + name = cases[idx] + + # check output MODFLOW 6 files + ws = test.workspace + check_output(ws, name) + + # check output comparison array_input model + ws = os.path.join(test.workspace, "mf6") + check_output(ws, name) + + @pytest.mark.slow +@pytest.mark.developmode @pytest.mark.parametrize("idx, name", enumerate(cases)) def test_mf6model(idx, name, function_tmpdir, targets): test = TestFramework( @@ -361,6 +393,7 @@ def test_mf6model(idx, name, function_tmpdir, targets): workspace=function_tmpdir, targets=targets, build=lambda t: build_models(idx, t), - check=lambda t: check_output(idx, t), + check=lambda t: check_outputs(idx, t), + compare="mf6", ) test.run() diff --git a/autotest/test_gwf_sfr_inactive02.py b/autotest/test_gwf_sfr_inactive02.py index 4b80ff47c87..41858dedbb8 100644 --- a/autotest/test_gwf_sfr_inactive02.py +++ b/autotest/test_gwf_sfr_inactive02.py @@ -1,20 +1,19 @@ # Test evap in SFR reaches (no interaction with gwf) +import os import flopy import numpy as np import pytest -from framework import TestFramework +from framework import DNODATA, TestFramework HDRY, HNOFLO = -1e30, 1e30 cases = ["sfr-inactive02"] -def build_models(idx, test): +def get_model(ws, name, array_input=False): # Base simulation and model name and workspace - ws = test.workspace - name = cases[idx] length_units = "m" time_units = "sec" @@ -66,7 +65,15 @@ def build_models(idx, test): icelltype=1, # >0 means saturated thickness varies with computed head ) flopy.mf6.ModflowGwfic(gwf, strt=1.0) - flopy.mf6.ModflowGwfghb(gwf, stress_period_data=[((0, 0, 0), 1.0, 1e6)]) + if array_input: + # if False: + bhead = np.full(nlay * nrow * ncol, DNODATA, dtype=float) + cond = np.full(nlay * nrow * ncol, DNODATA, dtype=float) + bhead[0] = 1.0 + cond[0] = 1e6 + flopy.mf6.ModflowGwfghbg(gwf, maxbound=1, bhead=bhead, cond=cond) + else: + flopy.mf6.ModflowGwfghb(gwf, stress_period_data=[((0, 0, 0), 1.0, 1e6)]) # sfr data nreaches = 4 @@ -116,7 +123,7 @@ def build_models(idx, test): print_stage=True, print_flows=True, print_input=True, - stage_filerecord=f"{name}.sfr.hds", + stage_filerecord=f"{name}.sfr.stg", budget_filerecord=f"{name}.sfr.cbc", length_conversion=1.0, time_conversion=1.0, @@ -150,11 +157,11 @@ def build_models(idx, test): saverecord=[("head", "all"), ("budget", "all")], ) - return sim, None + return sim -def check_output(idx, test): - sim = flopy.mf6.MFSimulation.load(sim_ws=test.workspace) +def check_output(ws, name): + sim = flopy.mf6.MFSimulation.load(sim_ws=ws) gwf = sim.get_model() sfr = gwf.get_package("SFR-1") stage = sfr.output.stage().get_alldata().squeeze() @@ -214,6 +221,32 @@ def check_output(idx, test): ) +def build_models(idx, test): + # build MODFLOW 6 files + ws = test.workspace + name = cases[idx] + sim = get_model(ws, name) + + # build comparison array_input model + ws = os.path.join(test.workspace, "mf6") + mc = get_model(ws, name, array_input=True) + + return sim, mc + + +def check_outputs(idx, test): + name = cases[idx] + + # check output MODFLOW 6 files + ws = test.workspace + check_output(ws, name) + + # check output comparison array_input model + ws = os.path.join(test.workspace, "mf6") + check_output(ws, name) + + +@pytest.mark.developmode @pytest.mark.parametrize("idx, name", enumerate(cases)) def test_mf6model(idx, name, function_tmpdir, targets): test = TestFramework( @@ -221,6 +254,7 @@ def test_mf6model(idx, name, function_tmpdir, targets): workspace=function_tmpdir, targets=targets, build=lambda t: build_models(idx, t), - check=lambda t: check_output(idx, t), + check=lambda t: check_outputs(idx, t), + compare="mf6", ) test.run() diff --git a/autotest/test_gwf_uzf01.py b/autotest/test_gwf_uzf01.py index 35ccb1adf2f..78fb72eec3b 100644 --- a/autotest/test_gwf_uzf01.py +++ b/autotest/test_gwf_uzf01.py @@ -8,7 +8,7 @@ import flopy import numpy as np import pytest -from framework import TestFramework +from framework import DNODATA, TestFramework cases = ["gwf_uzf01a"] nlay, nrow, ncol = 100, 1, 1 @@ -16,9 +16,7 @@ crs = "EPSG:26916" -def build_models(idx, test): - name = cases[idx] - +def get_model(ws, name, array_input=False): perlen = [500.0] nper = len(perlen) nstp = [10] @@ -39,7 +37,6 @@ def build_models(idx, test): tdis_rc.append((perlen[i], nstp[i], tsmult[i])) # build MODFLOW 6 files - ws = test.workspace sim = flopy.mf6.MFSimulation( sim_name=name, version="mf6", exe_name="mf6", sim_ws=ws ) @@ -104,16 +101,40 @@ def build_models(idx, test): transient={0: True}, ) - # ghb - ghbspdict = { - 0: [[(nlay - 1, 0, 0), 1.5, 1.0]], - } - ghb = flopy.mf6.ModflowGwfghb( - gwf, + # ghb / ghbg + if array_input: + ghb_obs = {f"{name}.ghb.obs.csv": [("100_1_1", "GHB", (99, 0, 0))]} + bhead = np.full(nlay * nrow * ncol, DNODATA, dtype=float) + cond = np.full(nlay * nrow * ncol, DNODATA, dtype=float) + bhead[nlay - 1] = 1.5 + cond[nlay - 1] = 1.0 + ghb = flopy.mf6.ModflowGwfghbg( + gwf, + print_input=True, + print_flows=True, + maxbound=1, + bhead=bhead, + cond=cond, + save_flows=False, + ) + else: + ghb_obs = {f"{name}.ghb.obs.csv": [("100_1_1", "GHB", (99, 0, 0))]} + ghbspdict = { + 0: [[(nlay - 1, 0, 0), 1.5, 1.0]], + } + ghb = flopy.mf6.ModflowGwfghb( + gwf, + print_input=True, + print_flows=True, + stress_period_data=ghbspdict, + save_flows=False, + ) + + ghb.obs.initialize( + filename=f"{name}.ghb.obs", + digits=20, print_input=True, - print_flows=True, - stress_period_data=ghbspdict, - save_flows=False, + continuous=ghb_obs, ) # note: for specifying lake number, use fortran indexing! @@ -174,13 +195,10 @@ def build_models(idx, test): obs_dict = {f"{name}.obs.csv": obs_lst} obs = flopy.mf6.ModflowUtlobs(gwf, pname="head_obs", digits=20, continuous=obs_dict) - return sim, None + return sim -def check_output(idx, test): - name = test.name - ws = test.workspace - +def check_output(ws, name): # check binary grid file fname = os.path.join(ws, name + ".dis.grb") grbobj = flopy.mf6.utils.MfGrdFile(fname) @@ -228,13 +246,40 @@ def check_output(idx, test): ) +def build_models(idx, test): + # build MODFLOW 6 files + ws = test.workspace + name = cases[idx] + sim = get_model(ws, name) + + # build comparison array_input model + ws = os.path.join(test.workspace, "mf6") + mc = get_model(ws, name, array_input=True) + + return sim, mc + + +def check_outputs(idx, test): + name = cases[idx] + + # check output MODFLOW 6 files + ws = test.workspace + check_output(ws, name) + + # check output comparison array_input model + ws = os.path.join(test.workspace, "mf6") + check_output(ws, name) + + +@pytest.mark.developmode @pytest.mark.parametrize("idx, name", enumerate(cases)) def test_mf6model(idx, name, function_tmpdir, targets): test = TestFramework( name=name, workspace=function_tmpdir, build=lambda t: build_models(idx, t), - check=lambda t: check_output(idx, t), + check=lambda t: check_outputs(idx, t), targets=targets, + compare="mf6", ) test.run() diff --git a/autotest/test_gwf_vsc01.py b/autotest/test_gwf_vsc01.py index 6ed2adf66ab..170945794ee 100644 --- a/autotest/test_gwf_vsc01.py +++ b/autotest/test_gwf_vsc01.py @@ -12,7 +12,7 @@ import flopy import numpy as np import pytest -from framework import TestFramework +from framework import DNODATA, TestFramework cases = ["no-vsc01-bnd", "vsc01-bnd", "no-vsc01-k"] hyd_cond = [1205.49396942506, 864.0] # Hydraulic conductivity (m/d) @@ -55,9 +55,8 @@ hclose, rclose, relax = 1e-10, 1e-6, 0.97 -def build_models(idx, test): +def get_model(idx, ws, array_input=False): # Base simulation and model name and workspace - ws = test.workspace name = cases[idx] print(f"Building model...{name}") @@ -118,7 +117,7 @@ def build_models(idx, test): # Instantiating VSC if viscosity_on[idx]: # Instantiate viscosity (VSC) package - vsc_filerecord = f"{gwfname}.vsc.bin" + vsc_filerecord = f"{gwfname}.vsc.vscb" vsc_pd = [(0, 0.0, 20.0, gwtname, "temperature")] flopy.mf6.ModflowGwfvsc( gwf, @@ -136,15 +135,33 @@ def build_models(idx, test): # Instantiating GHB ghbcond = hydraulic_conductivity[idx] * delv * delc / (0.5 * delr) - ghbspd = [ - [(0, i, ncol - 1), top, ghbcond, initial_temperature] for i in range(nrow) - ] - flopy.mf6.ModflowGwfghb( - gwf, - stress_period_data=ghbspd, - pname="GHB-1", - auxiliary="temperature", - ) + if array_input: + bhead = {0: np.full((nlay, nrow, ncol), DNODATA, dtype=float)} + cond = {0: np.full((nlay, nrow, ncol), DNODATA, dtype=float)} + temp = {0: np.full((nlay, nrow, ncol), DNODATA, dtype=float)} + for i in range(nrow): + bhead[0][0, i, ncol - 1] = top + cond[0][0, i, ncol - 1] = ghbcond + temp[0][0, i, ncol - 1] = initial_temperature + flopy.mf6.ModflowGwfghbg( + gwf, + maxbound=nrow, + pname="GHB-1", + auxiliary="temperature", + bhead=bhead, + cond=cond, + aux=temp, + ) + else: + ghbspd = [ + [(0, i, ncol - 1), top, ghbcond, initial_temperature] for i in range(nrow) + ] + flopy.mf6.ModflowGwfghb( + gwf, + stress_period_data=ghbspd, + pname="GHB-1", + auxiliary="temperature", + ) # Instantiating CHD chdspd = [[(0, i, 0), 2.0, initial_temperature] for i in range(nrow)] @@ -240,16 +257,16 @@ def build_models(idx, test): sim, exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname ) - return sim, None + return sim -def check_output(idx, test): +def check_output(idx, ws, array_input=False): # read flow results from model name = cases[idx] gwfname = "gwf-" + name fname = gwfname + ".bud" - fname = os.path.join(test.workspace, fname) + fname = os.path.join(ws, fname) assert os.path.isfile(fname) budobj = flopy.utils.CellBudgetFile(fname, precision="double") outbud = budobj.get_data(text=" GHB") @@ -298,8 +315,8 @@ def check_output(idx, test): ) # Ensure that binary output file is readable (has the correct header) - vsc_filerecord = f"{gwfname}.vsc.bin" - fname = os.path.join(test.workspace, vsc_filerecord) + vsc_filerecord = f"{gwfname}.vsc.vscb" + fname = os.path.join(ws, vsc_filerecord) if os.path.isfile(fname): vscobj = flopy.utils.HeadFile(fname, precision="double", text="VISCOSITY") try: @@ -310,13 +327,37 @@ def check_output(idx, test): print("Binary viscosity output file was not read successfully") +def build_models(idx, test): + # build MODFLOW 6 files + ws = test.workspace + sim = get_model(idx, ws) + + # build comparison array_input model + ws = os.path.join(test.workspace, "mf6") + mc = get_model(idx, ws, array_input=True) + + return sim, mc + + +def check_outputs(idx, test): + # check output MODFLOW 6 files + ws = test.workspace + check_output(idx, ws) + + # check output comparison array_input model + ws = os.path.join(test.workspace, "mf6") + check_output(idx, ws, array_input=True) + + +@pytest.mark.developmode @pytest.mark.parametrize("idx, name", enumerate(cases)) def test_mf6model(idx, name, function_tmpdir, targets): test = TestFramework( name=name, workspace=function_tmpdir, build=lambda t: build_models(idx, t), - check=lambda t: check_output(idx, t), + check=lambda t: check_outputs(idx, t), targets=targets, + compare="mf6", ) test.run() diff --git a/autotest/test_gwt_henry_nr.py b/autotest/test_gwt_henry_nr.py index 1d507a5e2d0..ac0b51b60d6 100644 --- a/autotest/test_gwt_henry_nr.py +++ b/autotest/test_gwt_henry_nr.py @@ -12,7 +12,7 @@ import flopy import numpy as np import pytest -from framework import TestFramework +from framework import DNODATA, TestFramework cases = ["henrynr01"] @@ -67,10 +67,7 @@ def sinfunc(a, b, c, d, x): return a * np.sin(b * (x - c)) + d -def build_models(idx, test): - ws = test.workspace - name = cases[idx] - +def get_model(ws, name, array_input=False): nrow = 1 delr = lx / ncol delc = 1.0 @@ -167,25 +164,52 @@ def build_models(idx, test): sealevelts = [sealevel] + list( sinfunc(amplitude, frequency * 2 * np.pi, 0, sealevel, times) ) - ghbspd = {} drnspd = {} + if array_input: + bheadspd = {} + ghbcondspd = {} + ghbauxspd = {} + else: + ghbspd = {} for kper in range(nper): if kper == 0: sl = sealevel else: sl = sealevelts[kper] - ghblist = [] + sl = np.round(sl, decimals=8) drnlist = [] + if array_input: + bhead = np.full((nlay, nrow, ncol), DNODATA, dtype=float) + ghbcond = np.full((nlay, nrow, ncol), DNODATA, dtype=float) + ghbconc = np.full((nlay, nrow, ncol), DNODATA, dtype=float) + ghbdens = np.full((nlay, nrow, ncol), DNODATA, dtype=float) + else: + ghblist = [] + ghbbnd = 0 + drnbnd = 0 for k, i, j in zip(kidx, iidx, jidx): zcell = zcellcenters[k, i, j] cond = 864.0 * (delz * delc) / (0.5 * delr) if zcell > sl: drnlist.append([(k, i, j), zcell, 864.0, 0.0]) + drnbnd += 1 + else: + if array_input: + bhead[k, i, j] = sl + ghbcond[k, i, j] = 864.0 + ghbconc[k, i, j] = 35.0 + ghbdens[k, i, j] = 1024.5 + else: + ghblist.append([(k, i, j), sl, 864.0, 35.0, 1024.5]) + ghbbnd += 1 + if ghbbnd > 0: + if array_input: + bheadspd[kper] = bhead + ghbcondspd[kper] = ghbcond + ghbauxspd[kper] = [ghbconc, ghbdens] else: - ghblist.append([(k, i, j), sl, 864.0, 35.0, 1024.5]) - if len(ghblist) > 0: - ghbspd[kper] = ghblist - if len(drnlist) > 0: + ghbspd[kper] = ghblist + if drnbnd > 0: drnspd[kper] = drnlist # drn @@ -199,16 +223,30 @@ def build_models(idx, test): auxiliary="CONCENTRATION", ) - # ghb - ghb1 = flopy.mf6.ModflowGwfghb( - gwf, - stress_period_data=ghbspd, - print_input=True, - print_flows=True, - save_flows=False, - pname="GHB-1", - auxiliary=["CONCENTRATION", "DENSITY"], - ) + # ghb / ghbg + if array_input: + ghb1 = flopy.mf6.ModflowGwfghbg( + gwf, + print_input=True, + print_flows=True, + save_flows=False, + maxbound=20, + pname="GHB-1", + auxiliary=["CONCENTRATION", "DENSITY"], + bhead=bheadspd, + cond=ghbcondspd, + aux=ghbauxspd, + ) + else: + ghb1 = flopy.mf6.ModflowGwfghb( + gwf, + stress_period_data=ghbspd, + print_input=True, + print_flows=True, + save_flows=False, + pname="GHB-1", + auxiliary=["CONCENTRATION", "DENSITY"], + ) wellist1 = [] qwell = 5.7024 * wellfact @@ -338,7 +376,7 @@ def build_models(idx, test): filename=f"{name}.gwfgwt", ) - return sim, None + return sim def get_patch_collection(modelgrid, head, conc, cmap="jet", zorder=None): @@ -453,10 +491,7 @@ def plot_output(idx, test): plt.savefig(fname, bbox_inches="tight") -def check_output(idx, test): - name = test.name - ws = test.workspace - sim = test.sims[0] +def check_output(ws, name, sim): gwfname = "gwf_" + name gwtname = "gwt_" + name gwf = sim.get_model(gwfname) @@ -503,7 +538,34 @@ def check_output(idx, test): assert np.allclose(hsim, hans, atol=1.0e-3), errmsg +def build_models(idx, test): + # build MODFLOW 6 files + ws = test.workspace + name = cases[idx] + sim = get_model(ws, name) + + # build comparison array_input model + ws = os.path.join(test.workspace, "mf6") + mc = get_model(ws, name, array_input=True) + + return sim, mc + + +def check_outputs(idx, test): + name = cases[idx] + sim = test.sims[0] + + # check output MODFLOW 6 files + ws = test.workspace + check_output(ws, name, sim) + + # check output comparison array_input model + ws = os.path.join(test.workspace, "mf6") + check_output(ws, name, sim) + + @pytest.mark.slow +@pytest.mark.developmode @pytest.mark.parametrize("idx, name", enumerate(cases)) def test_mf6model(idx, name, function_tmpdir, targets, plot): test = TestFramework( @@ -511,7 +573,8 @@ def test_mf6model(idx, name, function_tmpdir, targets, plot): workspace=function_tmpdir, targets=targets, build=lambda t: build_models(idx, t), - check=lambda t: check_output(idx, t), + check=lambda t: check_outputs(idx, t), plot=lambda t: plot_output(idx, t) if plot else None, + compare="mf6", ) test.run() diff --git a/autotest/test_netcdf_gwf_disv.py b/autotest/test_netcdf_gwf_disv.py index d0fbb20eca4..9b1795c2f47 100644 --- a/autotest/test_netcdf_gwf_disv.py +++ b/autotest/test_netcdf_gwf_disv.py @@ -38,7 +38,7 @@ ) -def build_models(idx, test, export, gridded_input): +def build_models(idx, test, gridded_input): from test_gwf_disv import build_models as build sim, dummy = build(idx, test) @@ -51,8 +51,7 @@ def build_models(idx, test, export, gridded_input): name = cases[idx] - if export == "ugrid": - gwf.name_file.nc_mesh2d_filerecord = f"{name}.nc" + gwf.name_file.nc_mesh2d_filerecord = f"{name}.nc" # netcdf config ncf = flopy.mf6.ModflowUtlncf( @@ -77,7 +76,7 @@ def build_models(idx, test, export, gridded_input): return sim, dummy -def check_output(idx, test, export, gridded_input): +def check_output(idx, test, gridded_input): from test_gwf_disv import check_output as check name = test.name @@ -101,16 +100,15 @@ def check_output(idx, test, export, gridded_input): if gridded_input == "netcdf": # re-run the simulation with model netcdf input input_fname = f"{name}.nc" - nc_fname = f"{name}.{export}.nc" + nc_fname = f"{name}.ugrid.nc" os.rename(test.workspace / input_fname, test.workspace / nc_fname) - if export == "ugrid": - fileout_tag = "NETCDF_MESH2D" + fileout_tag = "NETCDF_MESH2D" with open(test.workspace / f"{name}.nam", "w") as f: f.write("BEGIN options\n") f.write(f" {fileout_tag} FILEOUT {name}.nc\n") - f.write(f" NETCDF FILEIN {name}.{export}.nc\n") + f.write(f" NETCDF FILEIN {name}.ugrid.nc\n") f.write("END options\n\n") f.write("BEGIN packages\n") f.write(f" DISV6 {name}.disv disv\n") @@ -244,15 +242,14 @@ def check_output(idx, test, export, gridded_input): @pytest.mark.netcdf @pytest.mark.parametrize("idx, name", enumerate(cases)) -@pytest.mark.parametrize("export", ["ugrid"]) @pytest.mark.parametrize("gridded_input", ["ascii", "netcdf"]) -def test_mf6model(idx, name, function_tmpdir, targets, export, gridded_input): +def test_mf6model(idx, name, function_tmpdir, targets, gridded_input): test = TestFramework( name=name, workspace=function_tmpdir, targets=targets, - build=lambda t: build_models(idx, t, export, gridded_input), - check=lambda t: check_output(idx, t, export, gridded_input), + build=lambda t: build_models(idx, t, gridded_input), + check=lambda t: check_output(idx, t, gridded_input), compare=None, ) test.run() diff --git a/autotest/test_netcdf_gwf_disv_uzf.py b/autotest/test_netcdf_gwf_disv_uzf.py new file mode 100644 index 00000000000..0b5b9464f67 --- /dev/null +++ b/autotest/test_netcdf_gwf_disv_uzf.py @@ -0,0 +1,193 @@ +""" +NetCDF test version of test_gwf_disv_uzf. The primary aim is to test +that GHBG package NetCDF array input (bhead and cond) gives the same +results as test_gwf_disv_uzf list based (GHB) and array based (GHBG) +ascii input runs. This test compares heads in the the NetCDF file to +those in the FloPy binary output head file. +""" + +# Imports + +import os +from pathlib import Path + +import numpy as np +import pytest + +try: + import flopy +except: + msg = "Error. FloPy package is not available.\n" + msg += "Try installing using the following command:\n" + msg += " pip install flopy" + raise Exception(msg) + +from framework import TestFramework +from test_gwf_disv_uzf import cases + +xa = pytest.importorskip("xarray") +xu = pytest.importorskip("xugrid") +nc = pytest.importorskip("netCDF4") + + +def build_models(idx, test): + from test_gwf_disv_uzf import build_models as build + + sim, mc = build(idx, test) + gwf = mc.gwf[0] + gwf.get_package("GHBG_0").export_array_netcdf = True + + name = cases[idx] + + gwf.name_file.nc_mesh2d_filerecord = f"{name}.nc" + + return sim, mc + + +def check_output(idx, test): + from test_gwf_disv_uzf import check_output as check + + name = test.name + ws = Path(test.workspace / "mf6") + + # check outputs of GHB / GHBG ascii input runs + check(test.workspace, name) + check(ws, name) + + # verify format of generated netcdf file + with nc.Dataset(ws / f"{name}.nc") as ds: + assert ds.data_model == "NETCDF4" + + # re-run the simulation with model netcdf input + input_fname = f"{name}.nc" + nc_fname = f"{name}.ugrid.nc" + os.rename(ws / input_fname, ws / nc_fname) + + fileout_tag = "NETCDF_MESH2D" + + with open(ws / f"{name}.nam", "w") as f: + f.write("BEGIN options\n") + f.write(" SAVE_FLOWS\n") + f.write(" NEWTON\n") + f.write(f" {fileout_tag} FILEOUT {name}.nc\n") + f.write(f" NETCDF FILEIN {name}.ugrid.nc\n") + f.write("END options\n\n") + f.write("BEGIN packages\n") + f.write(f" DISV6 {name}.disv disv\n") + f.write(f" IC6 {name}.ic ic\n") + f.write(f" NPF6 {name}.npf npf\n") + f.write(f" STO6 {name}.sto sto\n") + f.write(f" GHB6 {name}.ghbg ghbg_0\n") + f.write(f" UZF6 {name}.uzf uzf_0\n") + f.write(f" OC6 {name}.oc oc\n") + f.write(f" OBS6 {name}.obs head_obs\n") + f.write("END packages\n") + + with open(ws / f"{name}.ghbg", "w") as f: + f.write("BEGIN options\n") + f.write(" READARRAYGRID\n") + f.write(" PRINT_INPUT\n") + f.write(" PRINT_FLOWS\n") + f.write("END options\n\n") + f.write("BEGIN dimensions\n") + f.write(" MAXBOUND 20\n") + f.write("END dimensions\n\n") + f.write("BEGIN period 1\n") + f.write(" bhead NETCDF\n") + f.write(" cond NETCDF\n") + f.write("END period 1\n") + + success, buff = flopy.run_model( + test.targets["mf6"], + ws / "mfsim.nam", + model_ws=ws, + report=True, + ) + + assert success + test.success = success + + # check netcdf input based run + check(ws, test.name) + + # compare head files for original + # list based and netcdf input runs + ext = ["hds"] + text = ["head"] + names = [test.name] + for i, e in enumerate(ext): + fpth1 = os.path.join( + test.workspace, + f"{names[i]}.{e}", + ) + fpth2 = os.path.join(ws, f"{names[i]}.{e}") + fout = os.path.join( + ws, + f"{names[i]}.{e}.cmp.out", + ) + success_tst = flopy.utils.compare.compare_heads( + None, + None, + text=f"{text[i]}", + outfile=fout, + files1=fpth1, + files2=fpth2, + difftol=True, + ) + msg = f"initial {text[i]} comparison success = {success_tst}" + if success_tst: + test.success = True + print(msg) + else: + test.success = False + assert success_tst, msg + + # now compare heads in head file and + # netcdf export for netcdf input run + try: + # load heads + fpth = os.path.join(ws, f"{name}.hds") + hobj = flopy.utils.HeadFile(fpth, precision="double") + heads = hobj.get_alldata() + except: + assert False, f'could not load headfile data from "{fpth}"' + + # open dataset + nc_fpth = os.path.join(ws, f"{name}.nc") + ds = xu.open_dataset(nc_fpth) + xds = ds.ugrid.to_dataset() + + # Compare NetCDF head arrays with binary headfile + gwf = test.sims[0].gwf[0] + dis = getattr(gwf, "dis") + tdis = getattr(test.sims[0], "tdis") + nper = getattr(tdis, "nper").data + nlay = getattr(dis, "nlay").data + pd = getattr(tdis, "perioddata").array + kstp = 0 + for i in range(nper): + for j in range(int(pd[i][1])): + rec = hobj.get_data(kstpkper=(j, i)) + for l in range(nlay): + assert np.allclose( + np.array(rec[l]).ravel(), + xds[f"head_l{l + 1}"][kstp, :].data, + ), f"NetCDF-head comparison failure in timestep {kstp + 1}" + kstp += 1 + + +@pytest.mark.netcdf +@pytest.mark.developmode +@pytest.mark.parametrize( + "idx, name", + list(enumerate(cases)), +) +def test_mf6model(idx, name, function_tmpdir, targets): + test = TestFramework( + name=name, + workspace=function_tmpdir, + build=lambda t: build_models(idx, t), + check=lambda t: check_output(idx, t), + targets=targets, + ) + test.run() diff --git a/autotest/test_netcdf_gwf_rch01.py b/autotest/test_netcdf_gwf_rch01.py index 1a5c8fcfb22..8bf060387f5 100644 --- a/autotest/test_netcdf_gwf_rch01.py +++ b/autotest/test_netcdf_gwf_rch01.py @@ -198,20 +198,17 @@ def check_output(idx, test, export, gridded_input): irch = getattr(rch, "irch").array recharge = getattr(rch, "recharge").array if export == "ugrid": - rl1 = xds["rcha_0_recharge_l1_p1"].data.flatten() - rl2 = xds["rcha_0_recharge_l2_p1"].data.flatten() + r = xds["rcha_0_recharge"].data.flatten() elif export == "structured": - rl1 = xds["rcha_0_recharge_p1"].data[0].flatten() - rl2 = xds["rcha_0_recharge_p1"].data[1].flatten() + r = xds["rcha_0_recharge"].data[0].flatten() if idx == 1: assert np.allclose( np.array(irch).flatten() + 1, - xds["rcha_0_irch_p1"].data, + xds["rcha_0_irch"].data, ), "NetCDF-irch comparison failure" - rarr = np.where(~np.isnan(rl1), rl1, rl2) assert np.allclose( np.array(recharge).flatten(), - rarr, + r, ), "NetCDF-recharge comparison failure" vlist = [ diff --git a/autotest/test_netcdf_gwf_rch03.py b/autotest/test_netcdf_gwf_rch03.py index 341d7eaee63..199be957729 100644 --- a/autotest/test_netcdf_gwf_rch03.py +++ b/autotest/test_netcdf_gwf_rch03.py @@ -200,19 +200,16 @@ def check_output(idx, test, export, gridded_input): irch = getattr(rch, "irch").array recharge = getattr(rch, "recharge").array if export == "ugrid": - rl1 = xds["rcha_0_recharge_l1_p1"].data.flatten() - rl2 = xds["rcha_0_recharge_l2_p1"].data.flatten() + r = xds["rcha_0_recharge"].data.flatten() elif export == "structured": - rl1 = xds["rcha_0_recharge_p1"].data[0].flatten() - rl2 = xds["rcha_0_recharge_p1"].data[1].flatten() + r = xds["rcha_0_recharge"].data[0].flatten() assert np.allclose( np.array(irch).flatten() + 1, - xds["rcha_0_irch_p1"].data, + xds["rcha_0_irch"].data.flatten(), ), "NetCDF-irch comparison failure" - rarr = np.where(~np.isnan(rl1), rl1, rl2) assert np.allclose( np.array(recharge).flatten(), - rarr, + r, ), "NetCDF-recharge comparison failure" vlist = [ diff --git a/autotest/test_netcdf_gwf_uzf01.py b/autotest/test_netcdf_gwf_uzf01.py new file mode 100644 index 00000000000..321d9e3b23d --- /dev/null +++ b/autotest/test_netcdf_gwf_uzf01.py @@ -0,0 +1,212 @@ +""" +NetCDF test version of test_gwf_uzf01. The primary aim is to test +that GHBG package NetCDF array input (bhead and cond) gives the same +results as test_gwf_uzf01 list based (GHB) and array based (GHBG) +ascii input runs. This test compares heads in the the NetCDF file +to those in the FloPy binary output head file. +""" + +# Imports + +import os +from pathlib import Path + +import numpy as np +import pytest + +try: + import flopy +except: + msg = "Error. FloPy package is not available.\n" + msg += "Try installing using the following command:\n" + msg += " pip install flopy" + raise Exception(msg) + +from framework import TestFramework +from test_gwf_uzf01 import cases + +xa = pytest.importorskip("xarray") +xu = pytest.importorskip("xugrid") +nc = pytest.importorskip("netCDF4") + + +def build_models(idx, test, export): + from test_gwf_uzf01 import build_models as build + + name = cases[idx] + + sim, mc = build(idx, test) + gwf = mc.gwf[0] + ghbg = gwf.get_package("GHBG_0") + ghbg.export_array_netcdf = True + + if export == "ugrid": + gwf.name_file.nc_mesh2d_filerecord = f"{name}.nc" + elif export == "structured": + gwf.name_file.nc_structured_filerecord = f"{name}.nc" + + return sim, mc + + +def check_output(idx, test, export): + from test_gwf_uzf01 import check_output as check + + name = test.name + ws = Path(test.workspace / "mf6") + + # check outputs of GHB / GHBG ascii input runs + check(test.workspace, name) + check(ws, name) + + # verify format of generated netcdf file + with nc.Dataset(ws / f"{name}.nc") as ds: + assert ds.data_model == "NETCDF4" + + # re-run the simulation with model netcdf input + input_fname = f"{name}.nc" + nc_fname = f"{name}.{export}.nc" + os.rename(ws / input_fname, ws / nc_fname) + + if export == "ugrid": + fileout_tag = "NETCDF_MESH2D" + elif export == "structured": + fileout_tag = "NETCDF_STRUCTURED" + + with open(ws / f"{name}.nam", "w") as f: + f.write("BEGIN options\n") + f.write(" SAVE_FLOWS\n") + f.write(" NEWTON UNDER_RELAXATION\n") + f.write(f" {fileout_tag} FILEOUT {name}.nc\n") + f.write(f" NETCDF FILEIN {name}.{export}.nc\n") + f.write("END options\n\n") + f.write("BEGIN packages\n") + f.write(f" DIS6 {name}.dis dis\n") + f.write(f" IC6 {name}.ic ic\n") + f.write(f" NPF6 {name}.npf npf\n") + f.write(f" STO6 {name}.sto sto\n") + f.write(f" GHB6 {name}.ghbg ghbg_0\n") + f.write(f" UZF6 {name}.uzf uzf_0\n") + f.write(f" OC6 {name}.oc oc\n") + f.write(f" OBS6 {name}.obs head_obs\n") + f.write("END packages\n") + + with open(ws / f"{name}.ghbg", "w") as f: + f.write("BEGIN options\n") + f.write(" READARRAYGRID\n") + f.write(" PRINT_INPUT\n") + f.write(" PRINT_FLOWS\n") + f.write(" OBS6 FILEIN gwf_uzf01a.ghb.obs\n") + f.write("END options\n\n") + f.write("BEGIN dimensions\n") + f.write(" MAXBOUND 1\n") + f.write("END dimensions\n\n") + f.write("BEGIN period 1\n") + f.write(" bhead NETCDF\n") + f.write(" cond NETCDF\n") + f.write("END period 1\n") + + success, buff = flopy.run_model( + test.targets["mf6"], + ws / "mfsim.nam", + model_ws=ws, + report=True, + ) + + assert success + test.success = success + + # check netcdf input based run + check(ws, test.name) + + # compare head files for original + # list based and netcdf input runs + ext = ["hds"] + text = ["head"] + names = [test.name] + for i, e in enumerate(ext): + fpth1 = os.path.join( + test.workspace, + f"{names[i]}.{e}", + ) + fpth2 = os.path.join(ws, f"{names[i]}.{e}") + fout = os.path.join( + ws, + f"{names[i]}.{e}.cmp.out", + ) + success_tst = flopy.utils.compare.compare_heads( + None, + None, + text=f"{text[i]}", + outfile=fout, + files1=fpth1, + files2=fpth2, + difftol=True, + ) + msg = f"initial {text[i]} comparison success = {success_tst}" + if success_tst: + test.success = True + print(msg) + else: + test.success = False + assert success_tst, msg + + # now compare heads in head file and + # netcdf export for netcdf input run + try: + # load heads + fpth = os.path.join(ws, f"{name}.hds") + hobj = flopy.utils.HeadFile(fpth, precision="double") + heads = hobj.get_alldata() + except: + assert False, f'could not load headfile data from "{fpth}"' + + # open dataset + nc_fpth = os.path.join(ws, f"{name}.nc") + if export == "ugrid": + ds = xu.open_dataset(nc_fpth) + xds = ds.ugrid.to_dataset() + elif export == "structured": + xds = xa.open_dataset(nc_fpth) + + # Compare NetCDF head arrays with binary headfile + gwf = test.sims[0].gwf[0] + dis = getattr(gwf, "dis") + tdis = getattr(test.sims[0], "tdis") + nper = getattr(tdis, "nper").data + nlay = getattr(dis, "nlay").data + pd = getattr(tdis, "perioddata").array + kstp = 0 + for i in range(nper): + for j in range(int(pd[i][1])): + rec = hobj.get_data(kstpkper=(j, i)) + if export == "ugrid": + for l in range(nlay): + assert np.allclose( + np.array(rec[l]).ravel(), + xds[f"head_l{l + 1}"][kstp, :].data, + ), f"NetCDF-head comparison failure in timestep {kstp + 1}" + kstp += 1 + elif export == "structured": + assert np.allclose( + np.array(rec), + xds["head"][kstp, :].data, + ), f"NetCDF-head comparison failure in timestep {kstp + 1}" + kstp += 1 + + +@pytest.mark.netcdf +@pytest.mark.developmode +@pytest.mark.parametrize( + "idx, name", + list(enumerate(cases)), +) +@pytest.mark.parametrize("export", ["ugrid", "structured"]) +def test_mf6model(idx, name, function_tmpdir, targets, export): + test = TestFramework( + name=name, + workspace=function_tmpdir, + build=lambda t: build_models(idx, t, export), + check=lambda t: check_output(idx, t, export), + targets=targets, + ) + test.run() diff --git a/autotest/test_netcdf_gwf_vsc01.py b/autotest/test_netcdf_gwf_vsc01.py new file mode 100644 index 00000000000..4a89275e894 --- /dev/null +++ b/autotest/test_netcdf_gwf_vsc01.py @@ -0,0 +1,211 @@ +""" +NetCDF test version of test_gwf_vsc01. The primary aim is to test +that GHBG package NetCDF array input (bhead, cond, and temperature +auxiliary arrays) gives the same results as test_gwf_vsc01 list based +(GHB) and array based (GHBG) ascii input runs. This test compares +heads in the the NetCDF file to those in the FloPy binary output +head file. +""" + +# Imports + +import os +from pathlib import Path + +import numpy as np +import pytest + +try: + import flopy +except: + msg = "Error. FloPy package is not available.\n" + msg += "Try installing using the following command:\n" + msg += " pip install flopy" + raise Exception(msg) + +from framework import TestFramework +from test_gwf_vsc01 import cases, viscosity_on + +xa = pytest.importorskip("xarray") +xu = pytest.importorskip("xugrid") +nc = pytest.importorskip("netCDF4") + + +def build_models(idx, test, export): + from test_gwf_vsc01 import build_models as build + + sim, mc = build(idx, test) + # mc.tdis.start_date_time = "2041-01-01T00:00:00-05:00" + gwf = mc.gwf[0] + gwf.get_package("GHB-1").export_array_netcdf = True + + name = "gwf-" + cases[idx] + + if export == "ugrid": + gwf.name_file.nc_mesh2d_filerecord = f"{name}.nc" + elif export == "structured": + gwf.name_file.nc_structured_filerecord = f"{name}.nc" + + return sim, mc + + +def check_output(idx, test, export): + from test_gwf_vsc01 import check_output as check + + name = "gwf-" + test.name + ws = Path(test.workspace / "mf6") + + # check outputs of GHB / GHBG ascii input runs + check(idx, test.workspace, array_input=False) + check(idx, ws, array_input=True) + + # verify format of generated netcdf file + with nc.Dataset(ws / f"{name}.nc") as ds: + assert ds.data_model == "NETCDF4" + + # re-run the simulation with model netcdf input + input_fname = f"{name}.nc" + nc_fname = f"{name}.{export}.nc" + os.rename(ws / input_fname, ws / nc_fname) + + if export == "ugrid": + fileout_tag = "NETCDF_MESH2D" + elif export == "structured": + fileout_tag = "NETCDF_STRUCTURED" + + with open(ws / f"{name}.nam", "w") as f: + f.write("BEGIN options\n") + f.write(" SAVE_FLOWS\n") + f.write(f" {fileout_tag} FILEOUT {name}.nc\n") + f.write(f" NETCDF FILEIN {name}.{export}.nc\n") + f.write("END options\n\n") + f.write("BEGIN packages\n") + f.write(f" DIS6 {name}.dis dis\n") + f.write(f" NPF6 {name}.npf npf\n") + f.write(f" IC6 {name}.ic ic\n") + if viscosity_on[idx]: + f.write(f" VSC6 {name}.vsc vsc\n") + f.write(f" GHB6 {name}.ghbg ghb-1\n") + f.write(f" CHD6 {name}.chd chd-1\n") + f.write(f" OC6 {name}.oc oc\n") + f.write("END packages\n") + + with open(ws / f"{name}.ghbg", "w") as f: + f.write("BEGIN options\n") + f.write(" READARRAYGRID\n") + f.write(" auxiliary TEMPERATURE\n") + f.write("END options\n\n") + f.write("BEGIN dimensions\n") + f.write(" MAXBOUND 10\n") + f.write("END dimensions\n\n") + f.write("BEGIN period 1\n") + f.write(" bhead NETCDF\n") + f.write(" cond NETCDF\n") + f.write(" TEMPERATURE NETCDF\n") + f.write("END period 1\n") + + success, buff = flopy.run_model( + test.targets["mf6"], + ws / "mfsim.nam", + model_ws=ws, + report=True, + ) + + assert success + test.success = success + + # check netcdf input based run + check(idx, ws, array_input=True) + + # compare head files for original + # list based and netcdf input runs + ext = ["hds", "ucn"] + text = ["head", "concentration"] + names = [name, "gwt-" + test.name] + for i, e in enumerate(ext): + fpth1 = os.path.join( + test.workspace, + f"{names[i]}.{e}", + ) + fpth2 = os.path.join(ws, f"{names[i]}.{e}") + fout = os.path.join( + ws, + f"{names[i]}.{e}.cmp.out", + ) + success_tst = flopy.utils.compare.compare_heads( + None, + None, + text=f"{text[i]}", + outfile=fout, + files1=fpth1, + files2=fpth2, + difftol=True, + ) + msg = f"initial {text[i]} comparison success = {success_tst}" + if success_tst: + test.success = True + print(msg) + else: + test.success = False + assert success_tst, msg + + # now compare heads in head file and + # netcdf export for netcdf input run + try: + # load heads + fpth = os.path.join(ws, f"{name}.hds") + hobj = flopy.utils.HeadFile(fpth, precision="double") + heads = hobj.get_alldata() + except: + assert False, f'could not load headfile data from "{fpth}"' + + # open dataset + nc_fpth = os.path.join(ws, f"{name}.nc") + if export == "ugrid": + ds = xu.open_dataset(nc_fpth) + xds = ds.ugrid.to_dataset() + elif export == "structured": + xds = xa.open_dataset(nc_fpth) + + # Compare NetCDF head arrays with binary headfile + gwf = test.sims[0].gwf[0] + dis = getattr(gwf, "dis") + tdis = getattr(test.sims[0], "tdis") + nper = getattr(tdis, "nper").data + nlay = getattr(dis, "nlay").data + pd = getattr(tdis, "perioddata").array + kstp = 0 + for i in range(nper): + for j in range(int(pd[i][1])): + rec = hobj.get_data(kstpkper=(j, i)) + if export == "ugrid": + for l in range(nlay): + assert np.allclose( + np.array(rec[l]).ravel(), + xds[f"head_l{l + 1}"][kstp, :].data, + ), f"NetCDF-head comparison failure in timestep {kstp + 1}" + kstp += 1 + elif export == "structured": + assert np.allclose( + np.array(rec), + xds["head"][kstp, :].data, + ), f"NetCDF-head comparison failure in timestep {kstp + 1}" + kstp += 1 + + +@pytest.mark.netcdf +@pytest.mark.developmode +@pytest.mark.parametrize( + "idx, name", + list(enumerate(cases)), +) +@pytest.mark.parametrize("export", ["ugrid", "structured"]) +def test_mf6model(idx, name, function_tmpdir, targets, export): + test = TestFramework( + name=name, + workspace=function_tmpdir, + build=lambda t: build_models(idx, t, export), + check=lambda t: check_output(idx, t, export), + targets=targets, + ) + test.run() diff --git a/autotest/test_netcdf_gwf_vsc03_sfr.py b/autotest/test_netcdf_gwf_vsc03_sfr.py index 0b2a4342f31..52336f8a848 100644 --- a/autotest/test_netcdf_gwf_vsc03_sfr.py +++ b/autotest/test_netcdf_gwf_vsc03_sfr.py @@ -225,15 +225,11 @@ def check_output(idx, test, export, gridded_input): irch = getattr(rch, "irch").array recharge = getattr(rch, "recharge").array aux = getattr(rch, "aux").array - if export == "ugrid": - rarr = xds["rcha-1_recharge_l1_p1"].data.flatten() - auxarr = xds["rcha-1_auxvar_l1_p1a1"].data.flatten() - elif export == "structured": - rarr = xds["rcha-1_recharge_p1"].data[0].flatten() - auxarr = xds["rcha-1_auxvar_p1a1"].data[0].flatten() + rarr = xds["rcha-1_recharge"].data[0].flatten() + auxarr = xds["rcha-1_temperature"][0].data.flatten() assert np.allclose( np.array(irch[0]).flatten() + 1, - xds["rcha-1_irch_p1"].data, + xds["rcha-1_irch"][0].data.flatten(), ), "NetCDF-irch comparison failure" assert np.allclose( np.array(recharge[0]).flatten(), diff --git a/autotest/test_netcdf_gwt_henry_nr.py b/autotest/test_netcdf_gwt_henry_nr.py new file mode 100644 index 00000000000..91a70bc39dc --- /dev/null +++ b/autotest/test_netcdf_gwt_henry_nr.py @@ -0,0 +1,221 @@ +""" +NetCDF test version of test_gwt_henry_nr. The primary aim is to test +that GHBG package NetCDF array input (bhead, cond, concentration and +density auxiliary arrays) gives the same results as test_gwt_henry_nr +list based (GHB) and array based (GHBG) ascii input runs. This test +compares heads in the the NetCDF file to those in the FloPy binary +output head file. +""" + +# Imports + +import os +import shutil +from pathlib import Path + +import numpy as np +import pytest + +try: + import flopy +except: + msg = "Error. FloPy package is not available.\n" + msg += "Try installing using the following command:\n" + msg += " pip install flopy" + raise Exception(msg) + +from framework import TestFramework +from test_gwt_henry_nr import cases + +xa = pytest.importorskip("xarray") +xu = pytest.importorskip("xugrid") +nc = pytest.importorskip("netCDF4") + + +def build_models(idx, test, export): + from test_gwt_henry_nr import build_models as build + + sim, mc = build(idx, test) + # mc.tdis.start_date_time = "2041-01-01T00:00:00-05:00" + gwf = mc.gwf[0] + gwf.get_package("GHB-1").export_array_netcdf = True + + name = "gwf_" + cases[idx] + + if export == "ugrid": + gwf.name_file.nc_mesh2d_filerecord = f"{name}.nc" + elif export == "structured": + gwf.name_file.nc_structured_filerecord = f"{name}.nc" + + return sim, mc + + +def check_output(idx, test, export): + from test_gwt_henry_nr import check_output as check + + name = "gwf_" + test.name + ghbg_ws = Path(test.workspace / "mf6") + ws = Path(test.workspace / "mf6" / "netcdf") + shutil.copytree(ghbg_ws, ws) + + # check outputs of GHB / GHBG ascii input runs + check(test.workspace, test.name, test.sims[0]) + # check(ws, test.name, test.sims[0]) + check(ghbg_ws, test.name, test.sims[0]) + + # verify format of generated netcdf file + with nc.Dataset(ws / f"{name}.nc") as ds: + assert ds.data_model == "NETCDF4" + + # re-run the simulation with model netcdf input + input_fname = f"{name}.nc" + nc_fname = f"{name}.{export}.nc" + os.rename(ws / input_fname, ws / nc_fname) + + if export == "ugrid": + fileout_tag = "NETCDF_MESH2D" + elif export == "structured": + fileout_tag = "NETCDF_STRUCTURED" + + with open(ws / f"{name}.nam", "w") as f: + f.write("BEGIN options\n") + f.write(" NEWTON\n") + f.write(f" {fileout_tag} FILEOUT {name}.nc\n") + f.write(f" NETCDF FILEIN {name}.{export}.nc\n") + f.write("END options\n\n") + f.write("BEGIN packages\n") + f.write(f" DIS6 {name}.dis dis\n") + f.write(f" IC6 {name}.ic ic\n") + f.write(f" NPF6 {name}.npf npf\n") + f.write(f" STO6 {name}.sto sto\n") + f.write(f" BUY6 {name}.buy buy\n") + f.write(f" DRN6 {name}.drn drn-1\n") + f.write(f" GHB6 {name}.ghbg ghb-1\n") + f.write(f" WEL6 {name}.wel wel-1\n") + f.write(f" OC6 {name}.oc oc\n") + f.write("END packages\n") + + with open(ws / f"{name}.ghbg", "w") as f: + f.write("BEGIN options\n") + f.write(" READARRAYGRID\n") + f.write(" auxiliary CONCENTRATION DENSITY\n") + f.write(" PRINT_INPUT\n") + f.write(" PRINT_FLOWS\n") + f.write("END options\n\n") + f.write("BEGIN dimensions\n") + f.write(" MAXBOUND 20\n") + f.write("END dimensions\n\n") + for i in range(1001): + f.write(f"BEGIN period {i + 1}\n") + f.write(" bhead NETCDF\n") + f.write(" cond NETCDF\n") + f.write(" concentration NETCDF\n") + f.write(" density NETCDF\n") + f.write(f"END period {i + 1}\n\n") + + success, buff = flopy.run_model( + test.targets["mf6"], + ws / "mfsim.nam", + model_ws=ws, + report=True, + ) + + assert success + test.success = success + + # check netcdf input based run + check(ws, test.name, test.sims[0]) + + # compare head files for original + # ascii and netcdf input runs + ext = ["hds", "ucn"] + text = ["head", "concentration"] + names = [name, "gwt_" + test.name] + for i, e in enumerate(ext): + fpth1 = os.path.join( + ghbg_ws, + f"{names[i]}.{e}", + ) + fpth2 = os.path.join(ws, f"{names[i]}.{e}") + fout = os.path.join( + ws, + f"{names[i]}.{e}.cmp.out", + ) + success_tst = flopy.utils.compare.compare_heads( + None, + None, + text=f"{text[i]}", + outfile=fout, + files1=fpth1, + files2=fpth2, + difftol=True, + ) + msg = f"initial {text[i]} comparison success = {success_tst}" + if success_tst: + test.success = True + print(msg) + else: + test.success = False + assert success_tst, msg + + # now compare heads in head file and + # netcdf export for netcdf input run + try: + # load heads + fpth = os.path.join(ws, f"{name}.hds") + hobj = flopy.utils.HeadFile(fpth, precision="double") + heads = hobj.get_alldata() + except: + assert False, f'could not load headfile data from "{fpth}"' + + # open dataset + nc_fpth = os.path.join(ws, f"{name}.nc") + if export == "ugrid": + ds = xu.open_dataset(nc_fpth) + xds = ds.ugrid.to_dataset() + elif export == "structured": + xds = xa.open_dataset(nc_fpth) + + # Compare NetCDF head arrays with binary headfile + gwf = test.sims[0].gwf[0] + dis = getattr(gwf, "dis") + tdis = getattr(test.sims[0], "tdis") + nper = getattr(tdis, "nper").data + nlay = getattr(dis, "nlay").data + pd = getattr(tdis, "perioddata").array + kstp = 0 + for i in range(nper): + for j in range(int(pd[i][1])): + rec = hobj.get_data(kstpkper=(j, i)) + if export == "ugrid": + for l in range(nlay): + assert np.allclose( + np.array(rec[l]).ravel(), + xds[f"head_l{l + 1}"][kstp, :].fillna(1.00000000e30).data, + ), f"NetCDF-head comparison failure in timestep {kstp + 1}" + kstp += 1 + elif export == "structured": + assert np.allclose( + np.array(rec), + xds["head"][kstp, :].fillna(1.00000000e30).data, + ), f"NetCDF-head comparison failure in timestep {kstp + 1}" + kstp += 1 + + +@pytest.mark.slow +@pytest.mark.netcdf +@pytest.mark.developmode +@pytest.mark.parametrize( + "idx, name", + list(enumerate(cases)), +) +@pytest.mark.parametrize("export", ["ugrid", "structured"]) +def test_mf6model(idx, name, function_tmpdir, targets, export): + test = TestFramework( + name=name, + workspace=function_tmpdir, + build=lambda t: build_models(idx, t, export), + check=lambda t: check_output(idx, t, export), + targets=targets, + ) + test.run() diff --git a/doc/mf6io/mf6ivar/dfn/gwf-ghbg.dfn b/doc/mf6io/mf6ivar/dfn/gwf-ghbg.dfn new file mode 100644 index 00000000000..f64486dcf7a --- /dev/null +++ b/doc/mf6io/mf6ivar/dfn/gwf-ghbg.dfn @@ -0,0 +1,178 @@ +# --------------------- gwf ghbg options --------------------- +# flopy multi-package +# package-type stress-package + +block options +name readarraygrid +type keyword +reader urword +optional false +longname use array-based grid input +description indicates that array-based grid input will be used for the general-head boundary package. This keyword must be specified to use array-based grid input. When READARRAYGRID is specified, values must be provided for every cell within a model grid, even those cells that have an IDOMAIN value less than one. Values assigned to cells with IDOMAIN values less than one are not used and have no effect on simulation results. No data cells should contain the value DNODATA (3.0E+30). +default_value True + +block options +name auxiliary +type string +shape (naux) +reader urword +optional true +longname keyword to specify aux variables +description REPLACE auxnames {'{#1}': 'Groundwater Flow'} + +block options +name auxmultname +type string +shape +reader urword +optional true +longname name of auxiliary variable for multiplier +description REPLACE auxmultname {'{#1}': 'general-head boundary conductance'} + +block options +name print_input +type keyword +reader urword +optional true +longname print input to listing file +description REPLACE print_input {'{#1}': 'general-head boundary'} +mf6internal iprpak + +block options +name print_flows +type keyword +reader urword +optional true +longname print calculated flows to listing file +description REPLACE print_flows {'{#1}': 'general-head boundary'} +mf6internal iprflow + +block options +name save_flows +type keyword +reader urword +optional true +longname save GHBG flows to budget file +description REPLACE save_flows {'{#1}': 'general-head boundary'} +mf6internal ipakcb + +block options +name obs_filerecord +type record obs6 filein obs6_filename +shape +reader urword +tagged true +optional true +longname +description + +block options +name obs6 +type keyword +shape +in_record true +reader urword +tagged true +optional false +longname obs keyword +description keyword to specify that record corresponds to an observations file. + +block options +name filein +type keyword +shape +in_record true +reader urword +tagged true +optional false +longname file keyword +description keyword to specify that an input filename is expected next. + +block options +name obs6_filename +type string +preserve_case true +in_record true +tagged false +reader urword +optional false +longname obs6 input filename +description REPLACE obs6_filename {'{#1}': 'General-Head Boundary'} + +block options +name mover +type keyword +tagged true +reader urword +optional true +longname +description REPLACE mover {'{#1}': 'General-Head Boundary'} + +block options +name export_array_netcdf +type keyword +reader urword +optional true +mf6internal export_nc +longname export array variables to netcdf output files. +description keyword that specifies input griddata arrays should be written to the model output netcdf file. +extended true + +# --------------------- gwf ghbg dimensions --------------------- + +block dimensions +name maxbound +type integer +reader urword +optional false +longname maximum number of general-head boundaries in any stress period +description REPLACE maxbound {'{#1}': 'general-head boundary'} + +# --------------------- gwf ghbg period --------------------- + +block period +name iper +type integer +block_variable True +in_record true +tagged false +shape +valid +reader urword +optional false +longname stress period number +description REPLACE iper {} + +block period +name bhead +type double precision +shape (nodes) +reader readarray +layered true +netcdf true +longname boundary head +description is the boundary head. +default_value 3.e30 + +block period +name cond +type double precision +shape (nodes) +reader readarray +layered true +netcdf true +longname boundary conductance +description is the hydraulic conductance of the interface between the aquifer cell and the boundary. +default_value 3.e30 + +block period +name aux +type double precision +shape (nodes) +reader readarray +layered true +netcdf true +optional true +longname general-head boundary auxiliary variable iaux +description is an array of values for auxiliary variable aux(iaux), where iaux is a value from 1 to naux, and aux(iaux) must be listed as part of the auxiliary variables. A separate array can be specified for each auxiliary variable. If an array is not specified for an auxiliary variable, then a value of zero is assigned. If the value specified here for the auxiliary variable is the same as auxmultname, then the boundary head array will be multiplied by this array. +mf6internal auxvar diff --git a/make/makefile b/make/makefile index 97726af3b66..f6c71870589 100644 --- a/make/makefile +++ b/make/makefile @@ -31,22 +31,23 @@ SOURCEDIR24=../src/Timing SOURCEDIR25=../src/Utilities SOURCEDIR26=../src/Utilities/ArrayRead SOURCEDIR27=../src/Utilities/Export -SOURCEDIR28=../src/Utilities/Idm -SOURCEDIR29=../src/Utilities/Idm/mf6blockfile -SOURCEDIR30=../src/Utilities/Idm/netcdf -SOURCEDIR31=../src/Utilities/Libraries -SOURCEDIR32=../src/Utilities/Libraries/blas -SOURCEDIR33=../src/Utilities/Libraries/daglib -SOURCEDIR34=../src/Utilities/Libraries/rcm -SOURCEDIR35=../src/Utilities/Libraries/sparsekit -SOURCEDIR36=../src/Utilities/Libraries/sparskit2 -SOURCEDIR37=../src/Utilities/Matrix -SOURCEDIR38=../src/Utilities/Memory -SOURCEDIR39=../src/Utilities/Observation -SOURCEDIR40=../src/Utilities/OutputControl -SOURCEDIR41=../src/Utilities/Performance -SOURCEDIR42=../src/Utilities/TimeSeries -SOURCEDIR43=../src/Utilities/Vector +SOURCEDIR28=../src/Utilities/Export/tmp +SOURCEDIR29=../src/Utilities/Idm +SOURCEDIR30=../src/Utilities/Idm/mf6blockfile +SOURCEDIR31=../src/Utilities/Idm/netcdf +SOURCEDIR32=../src/Utilities/Libraries +SOURCEDIR33=../src/Utilities/Libraries/blas +SOURCEDIR34=../src/Utilities/Libraries/daglib +SOURCEDIR35=../src/Utilities/Libraries/rcm +SOURCEDIR36=../src/Utilities/Libraries/sparsekit +SOURCEDIR37=../src/Utilities/Libraries/sparskit2 +SOURCEDIR38=../src/Utilities/Matrix +SOURCEDIR39=../src/Utilities/Memory +SOURCEDIR40=../src/Utilities/Observation +SOURCEDIR41=../src/Utilities/OutputControl +SOURCEDIR42=../src/Utilities/Performance +SOURCEDIR43=../src/Utilities/TimeSeries +SOURCEDIR44=../src/Utilities/Vector VPATH = \ ${SOURCEDIR1} \ @@ -91,7 +92,8 @@ ${SOURCEDIR39} \ ${SOURCEDIR40} \ ${SOURCEDIR41} \ ${SOURCEDIR42} \ -${SOURCEDIR43} +${SOURCEDIR43} \ +${SOURCEDIR44} .SUFFIXES: .f90 .F90 .o @@ -173,6 +175,7 @@ $(OBJDIR)/gwf-npfidm.o \ $(OBJDIR)/gwf-namidm.o \ $(OBJDIR)/gwf-icidm.o \ $(OBJDIR)/gwf-ghbidm.o \ +$(OBJDIR)/gwf-ghbgidm.o \ $(OBJDIR)/gwf-evtidm.o \ $(OBJDIR)/gwf-evtaidm.o \ $(OBJDIR)/gwf-drnidm.o \ @@ -287,7 +290,6 @@ $(OBJDIR)/SfrCrossSectionUtils.o \ $(OBJDIR)/TernarySolveTrack.o \ $(OBJDIR)/SubcellTri.o \ $(OBJDIR)/Method.o \ -$(OBJDIR)/MethodCell.o \ $(OBJDIR)/SubcellRect.o \ $(OBJDIR)/VirtualBase.o \ $(OBJDIR)/STLVecInt.o \ @@ -318,6 +320,7 @@ $(OBJDIR)/gwf-drn.o \ $(OBJDIR)/IndexMap.o \ $(OBJDIR)/ArrayReaderBase.o \ $(OBJDIR)/MethodSubcellPool.o \ +$(OBJDIR)/MethodCell.o \ $(OBJDIR)/CellPoly.o \ $(OBJDIR)/CellRectQuad.o \ $(OBJDIR)/CellRect.o \ @@ -471,8 +474,9 @@ $(OBJDIR)/NumericalSolution.o \ $(OBJDIR)/MappedMemory.o \ $(OBJDIR)/NCModel.o \ $(OBJDIR)/Mf6FileStoInput.o \ -$(OBJDIR)/Mf6FileListInput.o \ -$(OBJDIR)/Mf6FileGridInput.o \ +$(OBJDIR)/Mf6FileList.o \ +$(OBJDIR)/Mf6FileLayerArray.o \ +$(OBJDIR)/Mf6FileGridArray.o \ $(OBJDIR)/prt.o \ $(OBJDIR)/olf.o \ $(OBJDIR)/chf.o \ diff --git a/msvs/mf6core.vfproj b/msvs/mf6core.vfproj index d9eb6c77695..442825324d1 100644 --- a/msvs/mf6core.vfproj +++ b/msvs/mf6core.vfproj @@ -175,6 +175,7 @@ + @@ -511,8 +512,9 @@ - - + + + diff --git a/src/Idm/gwf-ghbgidm.f90 b/src/Idm/gwf-ghbgidm.f90 new file mode 100644 index 00000000000..cc1a685ed10 --- /dev/null +++ b/src/Idm/gwf-ghbgidm.f90 @@ -0,0 +1,394 @@ +! ** Do Not Modify! MODFLOW 6 system generated file. ** +module GwfGhbgInputModule + use ConstantsModule, only: LENVARNAME + use InputDefinitionModule, only: InputParamDefinitionType, & + InputBlockDefinitionType + private + public gwf_ghbg_param_definitions + public gwf_ghbg_aggregate_definitions + public gwf_ghbg_block_definitions + public GwfGhbgParamFoundType + public gwf_ghbg_multi_package + public gwf_ghbg_subpackages + + type GwfGhbgParamFoundType + logical :: readarraygrid = .false. + logical :: auxiliary = .false. + logical :: auxmultname = .false. + logical :: iprpak = .false. + logical :: iprflow = .false. + logical :: ipakcb = .false. + logical :: obs_filerecord = .false. + logical :: obs6 = .false. + logical :: filein = .false. + logical :: obs6_filename = .false. + logical :: mover = .false. + logical :: export_nc = .false. + logical :: maxbound = .false. + logical :: bhead = .false. + logical :: cond = .false. + logical :: auxvar = .false. + end type GwfGhbgParamFoundType + + logical :: gwf_ghbg_multi_package = .true. + + character(len=16), parameter :: & + gwf_ghbg_subpackages(*) = & + [ & + ' ' & + ] + + type(InputParamDefinitionType), parameter :: & + gwfghbg_readarraygrid = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'GHBG', & ! subcomponent + 'OPTIONS', & ! block + 'READARRAYGRID', & ! tag name + 'READARRAYGRID', & ! fortran variable + 'KEYWORD', & ! type + '', & ! shape + 'use array-based grid input', & ! longname + .true., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false., & ! layered + .false. & ! timeseries + ) + + type(InputParamDefinitionType), parameter :: & + gwfghbg_auxiliary = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'GHBG', & ! subcomponent + 'OPTIONS', & ! block + 'AUXILIARY', & ! tag name + 'AUXILIARY', & ! fortran variable + 'STRING', & ! type + 'NAUX', & ! shape + 'keyword to specify aux variables', & ! longname + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false., & ! layered + .false. & ! timeseries + ) + + type(InputParamDefinitionType), parameter :: & + gwfghbg_auxmultname = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'GHBG', & ! subcomponent + 'OPTIONS', & ! block + 'AUXMULTNAME', & ! tag name + 'AUXMULTNAME', & ! fortran variable + 'STRING', & ! type + '', & ! shape + 'name of auxiliary variable for multiplier', & ! longname + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false., & ! layered + .false. & ! timeseries + ) + + type(InputParamDefinitionType), parameter :: & + gwfghbg_iprpak = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'GHBG', & ! subcomponent + 'OPTIONS', & ! block + 'PRINT_INPUT', & ! tag name + 'IPRPAK', & ! fortran variable + 'KEYWORD', & ! type + '', & ! shape + 'print input to listing file', & ! longname + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false., & ! layered + .false. & ! timeseries + ) + + type(InputParamDefinitionType), parameter :: & + gwfghbg_iprflow = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'GHBG', & ! subcomponent + 'OPTIONS', & ! block + 'PRINT_FLOWS', & ! tag name + 'IPRFLOW', & ! fortran variable + 'KEYWORD', & ! type + '', & ! shape + 'print calculated flows to listing file', & ! longname + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false., & ! layered + .false. & ! timeseries + ) + + type(InputParamDefinitionType), parameter :: & + gwfghbg_ipakcb = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'GHBG', & ! subcomponent + 'OPTIONS', & ! block + 'SAVE_FLOWS', & ! tag name + 'IPAKCB', & ! fortran variable + 'KEYWORD', & ! type + '', & ! shape + 'save GHBG flows to budget file', & ! longname + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false., & ! layered + .false. & ! timeseries + ) + + type(InputParamDefinitionType), parameter :: & + gwfghbg_obs_filerecord = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'GHBG', & ! subcomponent + 'OPTIONS', & ! block + 'OBS_FILERECORD', & ! tag name + 'OBS_FILERECORD', & ! fortran variable + 'RECORD OBS6 FILEIN OBS6_FILENAME', & ! type + '', & ! shape + '', & ! longname + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false., & ! layered + .false. & ! timeseries + ) + + type(InputParamDefinitionType), parameter :: & + gwfghbg_obs6 = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'GHBG', & ! subcomponent + 'OPTIONS', & ! block + 'OBS6', & ! tag name + 'OBS6', & ! fortran variable + 'KEYWORD', & ! type + '', & ! shape + 'obs keyword', & ! longname + .true., & ! required + .true., & ! multi-record + .false., & ! preserve case + .false., & ! layered + .false. & ! timeseries + ) + + type(InputParamDefinitionType), parameter :: & + gwfghbg_filein = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'GHBG', & ! subcomponent + 'OPTIONS', & ! block + 'FILEIN', & ! tag name + 'FILEIN', & ! fortran variable + 'KEYWORD', & ! type + '', & ! shape + 'file keyword', & ! longname + .true., & ! required + .true., & ! multi-record + .false., & ! preserve case + .false., & ! layered + .false. & ! timeseries + ) + + type(InputParamDefinitionType), parameter :: & + gwfghbg_obs6_filename = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'GHBG', & ! subcomponent + 'OPTIONS', & ! block + 'OBS6_FILENAME', & ! tag name + 'OBS6_FILENAME', & ! fortran variable + 'STRING', & ! type + '', & ! shape + 'obs6 input filename', & ! longname + .true., & ! required + .true., & ! multi-record + .true., & ! preserve case + .false., & ! layered + .false. & ! timeseries + ) + + type(InputParamDefinitionType), parameter :: & + gwfghbg_mover = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'GHBG', & ! subcomponent + 'OPTIONS', & ! block + 'MOVER', & ! tag name + 'MOVER', & ! fortran variable + 'KEYWORD', & ! type + '', & ! shape + '', & ! longname + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false., & ! layered + .false. & ! timeseries + ) + + type(InputParamDefinitionType), parameter :: & + gwfghbg_export_nc = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'GHBG', & ! subcomponent + 'OPTIONS', & ! block + 'EXPORT_ARRAY_NETCDF', & ! tag name + 'EXPORT_NC', & ! fortran variable + 'KEYWORD', & ! type + '', & ! shape + 'export array variables to netcdf output files.', & ! longname + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false., & ! layered + .false. & ! timeseries + ) + + type(InputParamDefinitionType), parameter :: & + gwfghbg_maxbound = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'GHBG', & ! subcomponent + 'DIMENSIONS', & ! block + 'MAXBOUND', & ! tag name + 'MAXBOUND', & ! fortran variable + 'INTEGER', & ! type + '', & ! shape + 'maximum number of general-head boundaries in any stress period', & ! longname + .true., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false., & ! layered + .false. & ! timeseries + ) + + type(InputParamDefinitionType), parameter :: & + gwfghbg_bhead = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'GHBG', & ! subcomponent + 'PERIOD', & ! block + 'BHEAD', & ! tag name + 'BHEAD', & ! fortran variable + 'DOUBLE1D', & ! type + 'NODES', & ! shape + 'boundary head', & ! longname + .true., & ! required + .false., & ! multi-record + .false., & ! preserve case + .true., & ! layered + .false. & ! timeseries + ) + + type(InputParamDefinitionType), parameter :: & + gwfghbg_cond = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'GHBG', & ! subcomponent + 'PERIOD', & ! block + 'COND', & ! tag name + 'COND', & ! fortran variable + 'DOUBLE1D', & ! type + 'NODES', & ! shape + 'boundary conductance', & ! longname + .true., & ! required + .false., & ! multi-record + .false., & ! preserve case + .true., & ! layered + .false. & ! timeseries + ) + + type(InputParamDefinitionType), parameter :: & + gwfghbg_auxvar = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'GHBG', & ! subcomponent + 'PERIOD', & ! block + 'AUX', & ! tag name + 'AUXVAR', & ! fortran variable + 'DOUBLE2D', & ! type + 'NAUX NODES', & ! shape + 'general-head boundary auxiliary variable iaux', & ! longname + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .true., & ! layered + .false. & ! timeseries + ) + + type(InputParamDefinitionType), parameter :: & + gwf_ghbg_param_definitions(*) = & + [ & + gwfghbg_readarraygrid, & + gwfghbg_auxiliary, & + gwfghbg_auxmultname, & + gwfghbg_iprpak, & + gwfghbg_iprflow, & + gwfghbg_ipakcb, & + gwfghbg_obs_filerecord, & + gwfghbg_obs6, & + gwfghbg_filein, & + gwfghbg_obs6_filename, & + gwfghbg_mover, & + gwfghbg_export_nc, & + gwfghbg_maxbound, & + gwfghbg_bhead, & + gwfghbg_cond, & + gwfghbg_auxvar & + ] + + type(InputParamDefinitionType), parameter :: & + gwf_ghbg_aggregate_definitions(*) = & + [ & + InputParamDefinitionType & + ( & + '', & ! component + '', & ! subcomponent + '', & ! block + '', & ! tag name + '', & ! fortran variable + '', & ! type + '', & ! shape + '', & ! longname + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false., & ! layered + .false. & ! timeseries + ) & + ] + + type(InputBlockDefinitionType), parameter :: & + gwf_ghbg_block_definitions(*) = & + [ & + InputBlockDefinitionType( & + 'OPTIONS', & ! blockname + .true., & ! required + .false., & ! aggregate + .false. & ! block_variable + ), & + InputBlockDefinitionType( & + 'DIMENSIONS', & ! blockname + .true., & ! required + .false., & ! aggregate + .false. & ! block_variable + ), & + InputBlockDefinitionType( & + 'PERIOD', & ! blockname + .true., & ! required + .false., & ! aggregate + .true. & ! block_variable + ) & + ] + +end module GwfGhbgInputModule diff --git a/src/Idm/selector/IdmGwfDfnSelector.f90 b/src/Idm/selector/IdmGwfDfnSelector.f90 index bf9998308c7..ed1a3ef704b 100644 --- a/src/Idm/selector/IdmGwfDfnSelector.f90 +++ b/src/Idm/selector/IdmGwfDfnSelector.f90 @@ -14,6 +14,7 @@ module IdmGwfDfnSelectorModule use GwfEvtInputModule use GwfEvtaInputModule use GwfGhbInputModule + use GwfGhbgInputModule use GwfIcInputModule use GwfNpfInputModule use GwfRchInputModule @@ -74,6 +75,8 @@ function gwf_param_definitions(subcomponent) result(input_definition) call set_param_pointer(input_definition, gwf_evta_param_definitions) case ('GHB') call set_param_pointer(input_definition, gwf_ghb_param_definitions) + case ('GHBG') + call set_param_pointer(input_definition, gwf_ghbg_param_definitions) case ('IC') call set_param_pointer(input_definition, gwf_ic_param_definitions) case ('NPF') @@ -116,6 +119,8 @@ function gwf_aggregate_definitions(subcomponent) result(input_definition) call set_param_pointer(input_definition, gwf_evta_aggregate_definitions) case ('GHB') call set_param_pointer(input_definition, gwf_ghb_aggregate_definitions) + case ('GHBG') + call set_param_pointer(input_definition, gwf_ghbg_aggregate_definitions) case ('IC') call set_param_pointer(input_definition, gwf_ic_aggregate_definitions) case ('NPF') @@ -158,6 +163,8 @@ function gwf_block_definitions(subcomponent) result(input_definition) call set_block_pointer(input_definition, gwf_evta_block_definitions) case ('GHB') call set_block_pointer(input_definition, gwf_ghb_block_definitions) + case ('GHBG') + call set_block_pointer(input_definition, gwf_ghbg_block_definitions) case ('IC') call set_block_pointer(input_definition, gwf_ic_block_definitions) case ('NPF') @@ -199,6 +206,8 @@ function gwf_idm_multi_package(subcomponent) result(multi_package) multi_package = gwf_evta_multi_package case ('GHB') multi_package = gwf_ghb_multi_package + case ('GHBG') + multi_package = gwf_ghbg_multi_package case ('IC') multi_package = gwf_ic_multi_package case ('NPF') @@ -243,6 +252,8 @@ function gwf_idm_subpackages(subcomponent) result(subpackages) call set_subpkg_pointer(subpackages, gwf_evta_subpackages) case ('GHB') call set_subpkg_pointer(subpackages, gwf_ghb_subpackages) + case ('GHBG') + call set_subpkg_pointer(subpackages, gwf_ghbg_subpackages) case ('IC') call set_subpkg_pointer(subpackages, gwf_ic_subpackages) case ('NPF') @@ -285,6 +296,8 @@ function gwf_idm_integrated(subcomponent) result(integrated) integrated = .true. case ('GHB') integrated = .true. + case ('GHBG') + integrated = .true. case ('IC') integrated = .true. case ('NPF') diff --git a/src/Model/GroundWaterFlow/gwf-evt.f90 b/src/Model/GroundWaterFlow/gwf-evt.f90 index 5565ac16ecd..9305a082d55 100644 --- a/src/Model/GroundWaterFlow/gwf-evt.f90 +++ b/src/Model/GroundWaterFlow/gwf-evt.f90 @@ -372,7 +372,7 @@ subroutine evt_rp(this) ! if (this%read_as_arrays) then ! - ! -- update nodelist based on IRCH input + ! -- update nodelist based on IEVT input call nodelist_update(this%nodelist, this%nbound, this%maxbound, & this%dis, this%input_mempath) ! diff --git a/src/Model/GroundWaterFlow/gwf-ghb.f90 b/src/Model/GroundWaterFlow/gwf-ghb.f90 index 117fe87d0a9..5cc3aca77ba 100644 --- a/src/Model/GroundWaterFlow/gwf-ghb.f90 +++ b/src/Model/GroundWaterFlow/gwf-ghb.f90 @@ -1,5 +1,5 @@ module ghbmodule - use KindModule, only: DP, I4B + use KindModule, only: DP, I4B, LGP use ConstantsModule, only: DZERO, LENFTYPE, LENPACKAGENAME use SimVariablesModule, only: errmsg use SimModule, only: count_errors, store_error, store_error_filename @@ -100,36 +100,34 @@ subroutine ghb_options(this) ! -- modules use MemoryManagerExtModule, only: mem_set_value use CharacterStringModule, only: CharacterStringType - use GwfGhbInputModule, only: GwfGhbParamFoundType ! -- dummy class(GhbType), intent(inout) :: this ! -- local - type(GwfGhbParamFoundType) :: found + logical(LGP) :: found_mover ! ! -- source base class options call this%BndExtType%source_options() ! ! -- source options from input context - call mem_set_value(this%imover, 'MOVER', this%input_mempath, found%mover) + call mem_set_value(this%imover, 'MOVER', this%input_mempath, found_mover) ! ! -- log ghb specific options - call this%log_ghb_options(found) + call this%log_ghb_options(found_mover) end subroutine ghb_options !> @brief Log options specific to GhbType !< - subroutine log_ghb_options(this, found) + subroutine log_ghb_options(this, found_mover) ! -- modules - use GwfGhbInputModule, only: GwfGhbParamFoundType ! -- dummy class(GhbType), intent(inout) :: this !< BndExtType object - type(GwfGhbParamFoundType), intent(in) :: found + logical(LGP), intent(in) :: found_mover ! ! -- log found options write (this%iout, '(/1x,a)') 'PROCESSING '//trim(adjustl(this%text)) & //' OPTIONS' ! - if (found%mover) then + if (found_mover) then write (this%iout, '(4x,A)') 'MOVER OPTION ENABLED' end if ! diff --git a/src/Model/ModelUtilities/BoundaryPackageExt.f90 b/src/Model/ModelUtilities/BoundaryPackageExt.f90 index 17102607c36..3799a29ae12 100644 --- a/src/Model/ModelUtilities/BoundaryPackageExt.f90 +++ b/src/Model/ModelUtilities/BoundaryPackageExt.f90 @@ -31,8 +31,11 @@ module BndExtModule ! -- characters ! -- scalars integer(I4B), pointer :: iper + logical(LGP), pointer :: readarraygrid + logical(LGP), pointer :: readarraylayer ! -- arrays - integer(I4B), dimension(:, :), pointer, contiguous :: cellid => null() + integer(I4B), dimension(:, :), pointer, contiguous :: cellid => null() !< input user cellid list + integer(I4B), dimension(:), pointer, contiguous :: nodeulist => null() !< input user nodelist contains procedure :: bnd_df => bndext_df procedure :: bnd_rp => bndext_rp @@ -134,22 +137,48 @@ subroutine bndext_rp(this) class(BndExtType), intent(inout) :: this !< BndExtType object ! -- local variables logical(LGP) :: found - integer(I4B) :: n + integer(I4B) :: n, noder, nodeuser + character(len=LINELENGTH) :: nodestr ! if (this%iper /= kper) return ! ! -- copy nbound from input context call mem_set_value(this%nbound, 'NBOUND', this%input_mempath, & found) - ! - ! -- convert cellids to node numbers - call this%nodelist_update() - ! - ! -- update boundname string list - if (this%inamedbound /= 0) then - do n = 1, size(this%boundname_cst) - this%boundname(n) = this%boundname_cst(n) + + if (this%readarraygrid) then + ! -- Set the nodelist + do n = 1, this%nbound + nodeuser = this%nodeulist(n) + noder = this%dis%get_nodenumber(nodeuser, 1) + if (noder >= 0) then + this%nodelist(n) = noder + else + call this%dis%nodeu_to_string(n, nodestr) + write (errmsg, *) & + ' Cell is outside active grid domain: '// & + trim(adjustl(nodestr)) + call store_error(errmsg) + end if end do + ! + ! -- exit if errors were found + if (count_errors() > 0) then + write (errmsg, *) count_errors(), ' errors encountered.' + call store_error(errmsg) + call store_error_filename(this%input_fname) + end if + else + ! + ! -- convert cellids to node numbers + call this%nodelist_update() + ! + ! -- update boundname string list + if (this%inamedbound /= 0) then + do n = 1, size(this%boundname_cst) + this%boundname(n) = this%boundname_cst(n) + end do + end if end if end subroutine bndext_rp @@ -163,6 +192,7 @@ subroutine bndext_da(this) ! ! -- deallocate checkin paths call mem_deallocate(this%cellid, 'CELLID', this%memoryPath) + call mem_deallocate(this%nodeulist, 'NODEULIST', this%memoryPath) call mem_deallocate(this%boundname_cst, 'BOUNDNAME_IDM', this%memoryPath) call mem_deallocate(this%auxvar, 'AUXVAR_IDM', this%memoryPath) ! @@ -171,6 +201,10 @@ subroutine bndext_da(this) call mem_setptr(this%auxvar, 'AUXVAR', this%memoryPath) ! ! -- scalars + deallocate (this%readarraygrid) + deallocate (this%readarraylayer) + nullify (this%readarraygrid) + nullify (this%readarraylayer) nullify (this%iper) ! ! -- deallocate @@ -194,6 +228,7 @@ subroutine bndext_allocate_scalars(this) class(BndExtType) :: this !< BndExtType object ! -- local variables character(len=LENMEMPATH) :: input_mempath + logical(LGP) :: found ! ! -- set memory path input_mempath = create_mem_path(this%name_model, this%packName, idm_context) @@ -201,8 +236,28 @@ subroutine bndext_allocate_scalars(this) ! -- allocate base BndType scalars call this%BndType%allocate_scalars() ! - ! -- set pointers to period input data scalars + ! -- set IPER pointer call mem_setptr(this%iper, 'IPER', input_mempath) + + ! -- allocate internal scalars + allocate (this%readarraygrid) + allocate (this%readarraylayer) + + ! -- initialize internal scalars + this%readarraygrid = .false. + this%readarraylayer = .false. + + ! -- update internal scalars based on user input + call mem_set_value(this%readarraygrid, 'READARRAYGRID', input_mempath, found) + call mem_set_value(this%readarraylayer, 'READARRAYLAYER', & + input_mempath, found) + + ! -- no packages currently use READARRAYLAYER + if (this%readarraylayer) then + write (errmsg, '(a)') 'READARRAYLAYER is not currently supported.' + call store_error(errmsg) + call store_error_filename(this%input_fname) + end if end subroutine bndext_allocate_scalars !> @ brief Allocate package arrays @@ -226,11 +281,14 @@ subroutine bndext_allocate_arrays(this, nodelist, auxvar) ! ! -- set input context pointers call mem_setptr(this%cellid, 'CELLID', this%input_mempath) + call mem_setptr(this%nodeulist, 'NODEULIST', this%input_mempath) call mem_setptr(this%boundname_cst, 'BOUNDNAME', this%input_mempath) ! ! -- checkin input context pointers call mem_checkin(this%cellid, 'CELLID', this%memoryPath, & 'CELLID', this%input_mempath) + call mem_checkin(this%nodeulist, 'NODEULIST', this%memoryPath, & + 'NODEULIST', this%input_mempath) call mem_checkin(this%boundname_cst, LENBOUNDNAME, 'BOUNDNAME_IDM', & this%memoryPath, 'BOUNDNAME', this%input_mempath) ! diff --git a/src/Utilities/Export/DisNCMesh.f90 b/src/Utilities/Export/DisNCMesh.f90 index 3396a37c61d..18976d9f5af 100644 --- a/src/Utilities/Export/DisNCMesh.f90 +++ b/src/Utilities/Export/DisNCMesh.f90 @@ -9,7 +9,7 @@ module MeshDisModelModule use KindModule, only: DP, I4B, LGP use ConstantsModule, only: LINELENGTH, LENBIGLINE, LENCOMPONENTNAME, & - LENMEMPATH + LENMEMPATH, DNODATA, DZERO use SimVariablesModule, only: errmsg use SimModule, only: store_error, store_error_filename use MemoryManagerModule, only: mem_setptr @@ -17,8 +17,8 @@ module MeshDisModelModule use CharacterStringModule, only: CharacterStringType use MeshModelModule, only: Mesh2dModelType, MeshNCDimIdType, MeshNCVarIdType, & ncvar_chunk, ncvar_deflate, ncvar_gridmap, & - ncvar_mf6attr, export_varname - use NCModelExportModule, only: export_longname + ncvar_mf6attr + use NCModelExportModule, only: export_longname, export_varname use DisModule, only: DisType use NetCDFCommonModule, only: nf_verify use netcdf @@ -38,9 +38,7 @@ module MeshDisModelModule procedure :: df procedure :: step procedure :: export_input_array - procedure :: package_step_ilayer procedure :: package_step - procedure :: export_layer_3d procedure :: define_dim procedure :: add_mesh_data end type Mesh2dDisExportType @@ -66,6 +64,7 @@ subroutine dis_export_init(this, modelname, modeltype, modelfname, nc_fname, & ! allocate var_id arrays allocate (this%var_ids%dependent(this%nlay)) + allocate (this%var_ids%export(this%nlay)) ! initialize base class call this%mesh_init(modelname, modeltype, modelfname, nc_fname, disenum, & @@ -98,6 +97,8 @@ subroutine df(this) ! define the dependent variable call this%define_dependent() end if + ! define period input arrays + call this%df_export() ! exit define mode call nf_verify(nf90_enddef(this%ncid), this%nc_fname) ! create mesh @@ -115,9 +116,10 @@ end subroutine df subroutine step(this) use ConstantsModule, only: DHNOFLO use TdisModule, only: totim + use NetCDFCommonModule, only: ixstp class(Mesh2dDisExportType), intent(inout) :: this real(DP), dimension(:), pointer, contiguous :: dbl1d - integer(I4B) :: n, k, nvals + integer(I4B) :: n, k, nvals, istp integer(I4B), dimension(2) :: dis_shape real(DP), dimension(:, :), pointer, contiguous :: dbl2d @@ -125,8 +127,8 @@ subroutine step(this) nullify (dbl1d) nullify (dbl2d) - ! increment step - this%stepcnt = this%stepcnt + 1 + ! set global step index + istp = ixstp() dis_shape(1) = this%dis%ncol * this%dis%nrow dis_shape(2) = this%dis%nlay @@ -158,14 +160,14 @@ subroutine step(this) ! extend array with step data call nf_verify(nf90_put_var(this%ncid, & this%var_ids%dependent(k), dbl2d(:, k), & - start=(/1, this%stepcnt/), & + start=(/1, istp/), & count=(/(this%dis%ncol * this%dis%nrow), 1/)), & this%nc_fname) end do ! write to time coordinate variable call nf_verify(nf90_put_var(this%ncid, this%var_ids%time, & - totim, start=(/this%stepcnt/)), & + totim, start=(/istp/)), & this%nc_fname) ! update file call nf_verify(nf90_sync(this%ncid), this%nc_fname) @@ -176,39 +178,25 @@ subroutine step(this) nullify (dbl2d) end subroutine step - !> @brief netcdf export package dynamic input with ilayer index variable + !> @brief netcdf export package dynamic input !< - subroutine package_step_ilayer(this, export_pkg, ilayer_varname, ilayer) - use ConstantsModule, only: DNODATA, DZERO + subroutine package_step(this, export_pkg) use TdisModule, only: kper use DefinitionSelectModule, only: get_param_definition_type use NCModelExportModule, only: ExportPackageType class(Mesh2dDisExportType), intent(inout) :: this class(ExportPackageType), pointer, intent(in) :: export_pkg - character(len=*), intent(in) :: ilayer_varname - integer(I4B), intent(in) :: ilayer type(InputParamDefinitionType), pointer :: idt integer(I4B), dimension(:), pointer, contiguous :: int1d - real(DP), dimension(:), pointer, contiguous :: dbl1d + real(DP), dimension(:), pointer, contiguous :: dbl1d, nodes real(DP), dimension(:, :), pointer, contiguous :: dbl2d - integer(I4B), dimension(:), pointer, contiguous :: ialayer - real(DP), dimension(:), contiguous, pointer :: dbl1d_ptr - character(len=LINELENGTH) :: nc_varname, input_attr - integer(I4B) :: n, iparam, nvals - logical(LGP) :: ilayer_read + character(len=LINELENGTH) :: nc_tag + integer(I4B) :: iaux, iparam, nvals + integer(I4B) :: k, n + integer(I4B), pointer :: nbound ! initialize - nullify (ialayer) - ilayer_read = .false. - - ! set pointer to ilayer variable - call mem_setptr(ialayer, export_pkg%param_names(ilayer), & - export_pkg%mf6_input%mempath) - - ! check if layer index variable was read - if (export_pkg%param_reads(ilayer)%invar == 1) then - ilayer_read = .true. - end if + iaux = 0 ! export defined period input do iparam = 1, export_pkg%nparam @@ -221,120 +209,107 @@ subroutine package_step_ilayer(this, export_pkg, ilayer_varname, ilayer) export_pkg%mf6_input%component_type, & export_pkg%mf6_input%subcomponent_type, & 'PERIOD', export_pkg%param_names(iparam), '') - ! set variable name and input string - nc_varname = trim(export_pkg%mf6_input%subcomponent_name)//'_'// & - trim(idt%mf6varname) - input_attr = this%input_attribute(export_pkg%mf6_input%subcomponent_name, & - idt) + + ! set variable input tag + nc_tag = this%input_attribute(export_pkg%mf6_input%subcomponent_name, & + idt) + ! export arrays select case (idt%datatype) case ('INTEGER1D') call mem_setptr(int1d, idt%mf6varname, export_pkg%mf6_input%mempath) - call nc_export_int1d(this%ncid, this%dim_ids, this%x_dim, this%y_dim, & - this%var_ids, this%dis, int1d, nc_varname, & + this%var_ids%export(1) = export_pkg%varids_param(iparam, 1) + call nc_export_int1d(int1d, this%ncid, this%dim_ids, this%x_dim, & + this%y_dim, this%var_ids, this%dis, idt, & + export_pkg%mf6_input%mempath, nc_tag, & export_pkg%mf6_input%subcomponent_name, & - idt%tagname, this%gridmap_name, idt%shape, & - idt%longname, input_attr, this%deflate, & - this%shuffle, this%chunk_face, kper, this%nc_fname) + this%gridmap_name, this%deflate, this%shuffle, & + this%chunk_face, kper, this%nc_fname) case ('DOUBLE1D') call mem_setptr(dbl1d, idt%mf6varname, export_pkg%mf6_input%mempath) - call this%export_layer_3d(export_pkg, idt, ilayer_read, ialayer, & - dbl1d, nc_varname, input_attr) + select case (idt%shape) + case ('NCPL') + this%var_ids%export(1) = export_pkg%varids_param(iparam, 1) + call nc_export_dbl1d(dbl1d, this%ncid, this%dim_ids, this%x_dim, & + this%y_dim, this%var_ids, this%dis, idt, & + export_pkg%mf6_input%mempath, nc_tag, & + export_pkg%mf6_input%subcomponent_name, & + this%gridmap_name, this%deflate, this%shuffle, & + this%chunk_face, kper, iaux, this%nc_fname) + case ('NODES') + nvals = this%dis%nodesuser + allocate (nodes(nvals)) + nodes = DNODATA + do k = 1, this%dis%nlay + this%var_ids%export(k) = export_pkg%varids_param(iparam, k) + end do + call mem_setptr(dbl1d, idt%mf6varname, export_pkg%mf6_input%mempath) + call mem_setptr(int1d, 'NODEULIST', export_pkg%mf6_input%mempath) + call mem_setptr(nbound, 'NBOUND', export_pkg%mf6_input%mempath) + do n = 1, nbound + nodes(int1d(n)) = dbl1d(n) + end do + call nc_export_dbl1d(nodes, this%ncid, this%dim_ids, this%x_dim, & + this%y_dim, this%var_ids, this%dis, idt, & + export_pkg%mf6_input%mempath, nc_tag, & + export_pkg%mf6_input%subcomponent_name, & + this%gridmap_name, this%deflate, this%shuffle, & + this%chunk_face, kper, iaux, this%nc_fname) + deallocate (nodes) + case default + end select case ('DOUBLE2D') call mem_setptr(dbl2d, idt%mf6varname, export_pkg%mf6_input%mempath) - nvals = this%dis%ncol * this%dis%nrow - - do n = 1, size(dbl2d, dim=1) !naux - dbl1d_ptr(1:nvals) => dbl2d(n, :) - if (all(dbl1d_ptr == DZERO)) then - else - call this%export_layer_3d(export_pkg, idt, ilayer_read, ialayer, & - dbl1d_ptr, nc_varname, input_attr, n) - end if - end do + select case (idt%shape) + case ('NAUX NCPL') + nvals = this%dis%nrow * this%dis%ncol + allocate (nodes(nvals)) + do iaux = 1, size(dbl2d, dim=1) !naux + this%var_ids%export(1) = export_pkg%varids_aux(iaux, 1) + do n = 1, nvals + nodes(n) = dbl2d(iaux, n) + end do + call nc_export_dbl1d(nodes, this%ncid, this%dim_ids, this%x_dim, & + this%y_dim, this%var_ids, this%dis, idt, & + export_pkg%mf6_input%mempath, nc_tag, & + export_pkg%mf6_input%subcomponent_name, & + this%gridmap_name, this%deflate, this%shuffle, & + this%chunk_face, kper, iaux, this%nc_fname) + end do + deallocate (nodes) + case ('NAUX NODES') + nvals = this%dis%nodesuser + allocate (nodes(nvals)) + call mem_setptr(int1d, 'NODEULIST', export_pkg%mf6_input%mempath) + call mem_setptr(nbound, 'NBOUND', export_pkg%mf6_input%mempath) + do iaux = 1, size(dbl2d, dim=1) ! naux + nodes = DNODATA + do k = 1, this%dis%nlay + this%var_ids%export(k) = export_pkg%varids_aux(iaux, k) + end do + do n = 1, nbound + nodes(int1d(n)) = dbl2d(iaux, n) + end do + call nc_export_dbl1d(nodes, this%ncid, this%dim_ids, this%x_dim, & + this%y_dim, this%var_ids, this%dis, idt, & + export_pkg%mf6_input%mempath, nc_tag, & + export_pkg%mf6_input%subcomponent_name, & + this%gridmap_name, this%deflate, this%shuffle, & + this%chunk_face, kper, iaux, this%nc_fname) + + end do + deallocate (nodes) + case default + end select case default - errmsg = 'EXPORT ilayaer unsupported datatype='//trim(idt%datatype) - call store_error(errmsg, .true.) + ! no-op, no other datatypes exported end select end do - ! synchronize file - call nf_verify(nf90_sync(this%ncid), this%nc_fname) - end subroutine package_step_ilayer - - !> @brief netcdf export package dynamic input - !< - subroutine package_step(this, export_pkg) - use NCModelExportModule, only: ExportPackageType - class(Mesh2dDisExportType), intent(inout) :: this - class(ExportPackageType), pointer, intent(in) :: export_pkg - errmsg = 'NetCDF period export not supported for model='// & - trim(this%modelname)//', package='// & - trim(export_pkg%mf6_input%subcomponent_name) - call store_error(errmsg, .true.) - ! synchronize file call nf_verify(nf90_sync(this%ncid), this%nc_fname) end subroutine package_step - !> @brief export layer variable as full grid - !< - subroutine export_layer_3d(this, export_pkg, idt, ilayer_read, ialayer, & - dbl1d, nc_varname, input_attr, iaux) - use ConstantsModule, only: DNODATA, DZERO - use NCModelExportModule, only: ExportPackageType - class(Mesh2dDisExportType), intent(inout) :: this - class(ExportPackageType), pointer, intent(in) :: export_pkg - type(InputParamDefinitionType), pointer, intent(in) :: idt - logical(LGP), intent(in) :: ilayer_read - integer(I4B), dimension(:), pointer, contiguous, intent(in) :: ialayer - real(DP), dimension(:), pointer, contiguous, intent(in) :: dbl1d - character(len=*), intent(in) :: nc_varname - character(len=*), intent(in) :: input_attr - integer(I4B), optional, intent(in) :: iaux - real(DP), dimension(:, :, :), pointer, contiguous :: dbl3d - integer(I4B) :: n, i, j, k, nvals, idxaux - real(DP), dimension(:, :), contiguous, pointer :: dbl2d_ptr - - ! initialize - idxaux = 0 - if (present(iaux)) then - idxaux = iaux - end if - - allocate (dbl3d(export_pkg%mshape(3), export_pkg%mshape(2), & - export_pkg%mshape(1))) - - if (ilayer_read) then - do k = 1, size(dbl3d, dim=3) - n = 0 - do i = 1, size(dbl3d, dim=2) - do j = 1, size(dbl3d, dim=1) - n = n + 1 - if (ialayer(n) == k) then - dbl3d(j, i, k) = dbl1d(n) - else - dbl3d(j, i, k) = DNODATA - end if - end do - end do - end do - else - dbl3d = DNODATA - nvals = export_pkg%mshape(3) * export_pkg%mshape(2) - dbl2d_ptr(1:export_pkg%mshape(3), 1:export_pkg%mshape(2)) => dbl1d(1:nvals) - dbl3d(:, :, 1) = dbl2d_ptr(:, :) - end if - - call nc_export_dbl3d(this%ncid, this%dim_ids, this%var_ids, this%dis, dbl3d, & - nc_varname, export_pkg%mf6_input%subcomponent_name, & - idt%tagname, this%gridmap_name, idt%shape, & - idt%longname, input_attr, this%deflate, this%shuffle, & - this%chunk_face, export_pkg%iper, idxaux, this%nc_fname) - - deallocate (dbl3d) - end subroutine export_layer_3d - !> @brief netcdf export an input array !< subroutine export_input_array(this, pkgtype, pkgname, mempath, idt) @@ -349,60 +324,53 @@ subroutine export_input_array(this, pkgtype, pkgname, mempath, idt) real(DP), dimension(:), pointer, contiguous :: dbl1d real(DP), dimension(:, :), pointer, contiguous :: dbl2d real(DP), dimension(:, :, :), pointer, contiguous :: dbl3d - character(len=LINELENGTH) :: nc_varname, input_attr + character(len=LINELENGTH) :: nc_tag integer(I4B) :: iper, iaux iper = 0 iaux = 0 - ! set package base name - nc_varname = trim(pkgname)//'_'//trim(idt%mf6varname) - ! put input attributes - input_attr = this%input_attribute(pkgname, idt) + ! set package input tag + nc_tag = this%input_attribute(pkgname, idt) select case (idt%datatype) case ('INTEGER1D') call mem_setptr(int1d, idt%mf6varname, mempath) - call nc_export_int1d(this%ncid, this%dim_ids, this%x_dim, this%y_dim, & - this%var_ids, this%dis, int1d, nc_varname, pkgname, & - idt%tagname, this%gridmap_name, idt%shape, & - idt%longname, input_attr, this%deflate, this%shuffle, & - this%chunk_face, iper, this%nc_fname) + call nc_export_int1d(int1d, this%ncid, this%dim_ids, this%x_dim, & + this%y_dim, this%var_ids, this%dis, idt, mempath, & + nc_tag, pkgname, this%gridmap_name, this%deflate, & + this%shuffle, this%chunk_face, iper, this%nc_fname) case ('INTEGER2D') call mem_setptr(int2d, idt%mf6varname, mempath) - call nc_export_int2d(this%ncid, this%dim_ids, this%var_ids, this%dis, & - int2d, nc_varname, pkgname, idt%tagname, & - this%gridmap_name, idt%shape, idt%longname, & - input_attr, this%deflate, this%shuffle, & + call nc_export_int2d(int2d, this%ncid, this%dim_ids, this%var_ids, & + this%dis, idt, mempath, nc_tag, pkgname, & + this%gridmap_name, this%deflate, this%shuffle, & this%chunk_face, this%nc_fname) case ('INTEGER3D') call mem_setptr(int3d, idt%mf6varname, mempath) - call nc_export_int3d(this%ncid, this%dim_ids, this%var_ids, this%dis, & - int3d, nc_varname, pkgname, idt%tagname, & - this%gridmap_name, idt%shape, idt%longname, & - input_attr, this%deflate, this%shuffle, & + call nc_export_int3d(int3d, this%ncid, this%dim_ids, this%var_ids, & + this%dis, idt, mempath, nc_tag, pkgname, & + this%gridmap_name, this%deflate, this%shuffle, & this%chunk_face, this%nc_fname) case ('DOUBLE1D') call mem_setptr(dbl1d, idt%mf6varname, mempath) - call nc_export_dbl1d(this%ncid, this%dim_ids, this%x_dim, this%y_dim, & - this%var_ids, this%dis, dbl1d, nc_varname, pkgname, & - idt%tagname, this%gridmap_name, idt%shape, & - idt%longname, input_attr, this%deflate, this%shuffle, & - this%chunk_face, this%nc_fname) + call nc_export_dbl1d(dbl1d, this%ncid, this%dim_ids, this%x_dim, & + this%y_dim, this%var_ids, this%dis, idt, mempath, & + nc_tag, pkgname, this%gridmap_name, this%deflate, & + this%shuffle, this%chunk_face, iper, iaux, & + this%nc_fname) case ('DOUBLE2D') call mem_setptr(dbl2d, idt%mf6varname, mempath) - call nc_export_dbl2d(this%ncid, this%dim_ids, this%var_ids, this%dis, & - dbl2d, nc_varname, pkgname, idt%tagname, & - this%gridmap_name, idt%shape, idt%longname, & - input_attr, this%deflate, this%shuffle, & + call nc_export_dbl2d(dbl2d, this%ncid, this%dim_ids, this%var_ids, & + this%dis, idt, mempath, nc_tag, pkgname, & + this%gridmap_name, this%deflate, this%shuffle, & this%chunk_face, this%nc_fname) case ('DOUBLE3D') call mem_setptr(dbl3d, idt%mf6varname, mempath) - call nc_export_dbl3d(this%ncid, this%dim_ids, this%var_ids, this%dis, & - dbl3d, nc_varname, pkgname, idt%tagname, & - this%gridmap_name, idt%shape, idt%longname, & - input_attr, this%deflate, this%shuffle, & - this%chunk_face, iper, iaux, this%nc_fname) + call nc_export_dbl3d(dbl3d, this%ncid, this%dim_ids, this%var_ids, & + this%dis, idt, mempath, nc_tag, pkgname, & + this%gridmap_name, this%deflate, this%shuffle, & + this%chunk_face, this%nc_fname) case default ! no-op, no other datatypes exported end select @@ -411,28 +379,24 @@ end subroutine export_input_array !> @brief netcdf export define dimensions !< subroutine define_dim(this) - use ConstantsModule, only: MVALIDATE - use SimVariablesModule, only: isim_mode class(Mesh2dDisExportType), intent(inout) :: this ! time - if (isim_mode /= MVALIDATE) then - call nf_verify(nf90_def_dim(this%ncid, 'time', this%totnstp, & - this%dim_ids%time), this%nc_fname) - call nf_verify(nf90_def_var(this%ncid, 'time', NF90_DOUBLE, & - this%dim_ids%time, this%var_ids%time), & - this%nc_fname) - call nf_verify(nf90_put_att(this%ncid, this%var_ids%time, 'calendar', & - 'standard'), this%nc_fname) - call nf_verify(nf90_put_att(this%ncid, this%var_ids%time, 'units', & - this%datetime), this%nc_fname) - call nf_verify(nf90_put_att(this%ncid, this%var_ids%time, 'axis', 'T'), & - this%nc_fname) - call nf_verify(nf90_put_att(this%ncid, this%var_ids%time, 'standard_name', & - 'time'), this%nc_fname) - call nf_verify(nf90_put_att(this%ncid, this%var_ids%time, 'long_name', & - 'time'), this%nc_fname) - end if + call nf_verify(nf90_def_dim(this%ncid, 'time', this%totnstp, & + this%dim_ids%time), this%nc_fname) + call nf_verify(nf90_def_var(this%ncid, 'time', NF90_DOUBLE, & + this%dim_ids%time, this%var_ids%time), & + this%nc_fname) + call nf_verify(nf90_put_att(this%ncid, this%var_ids%time, 'calendar', & + 'standard'), this%nc_fname) + call nf_verify(nf90_put_att(this%ncid, this%var_ids%time, 'units', & + this%datetime), this%nc_fname) + call nf_verify(nf90_put_att(this%ncid, this%var_ids%time, 'axis', 'T'), & + this%nc_fname) + call nf_verify(nf90_put_att(this%ncid, this%var_ids%time, 'standard_name', & + 'time'), this%nc_fname) + call nf_verify(nf90_put_att(this%ncid, this%var_ids%time, 'long_name', & + 'time'), this%nc_fname) ! mesh call nf_verify(nf90_def_dim(this%ncid, 'nmesh_node', & @@ -595,163 +559,179 @@ end subroutine add_mesh_data !> @brief netcdf export 1D integer !< - subroutine nc_export_int1d(ncid, dim_ids, x_dim, y_dim, var_ids, dis, p_mem, & - nc_varname, pkgname, tagname, gridmap_name, & - shapestr, longname, nc_tag, deflate, shuffle, & - chunk_face, iper, nc_fname) + subroutine nc_export_int1d(p_mem, ncid, dim_ids, x_dim, y_dim, var_ids, dis, & + idt, mempath, nc_tag, pkgname, gridmap_name, & + deflate, shuffle, chunk_face, iper, nc_fname) + use NetCDFCommonModule, only: ixstp + integer(I4B), dimension(:), pointer, contiguous, intent(in) :: p_mem integer(I4B), intent(in) :: ncid type(MeshNCDimIdType), intent(inout) :: dim_ids integer(I4B), intent(in) :: x_dim integer(I4B), intent(in) :: y_dim type(MeshNCVarIdType), intent(inout) :: var_ids type(DisType), pointer, intent(in) :: dis - integer(I4B), dimension(:), pointer, contiguous, intent(in) :: p_mem - character(len=*), intent(in) :: nc_varname + type(InputParamDefinitionType), pointer :: idt + character(len=*), intent(in) :: mempath + character(len=*), intent(in) :: nc_tag character(len=*), intent(in) :: pkgname - character(len=*), intent(in) :: tagname character(len=*), intent(in) :: gridmap_name - character(len=*), intent(in) :: shapestr - character(len=*), intent(in) :: longname - character(len=*), intent(in) :: nc_tag integer(I4B), intent(in) :: deflate integer(I4B), intent(in) :: shuffle integer(I4B), intent(in) :: chunk_face integer(I4B), intent(in) :: iper character(len=*), intent(in) :: nc_fname - integer(I4B), dimension(3) :: dis_shape - integer(I4B), dimension(1) :: layer_shape integer(I4B), dimension(:, :, :), pointer, contiguous :: int3d integer(I4B), dimension(:), pointer, contiguous :: int1d - integer(I4B) :: axis_dim, nvals, k + integer(I4B) :: axis_dim, nvals, k, istp integer(I4B), dimension(:), allocatable :: var_id - character(len=LINELENGTH) :: longname_l, varname_l - - if (shapestr == 'NROW' .or. & - shapestr == 'NCOL' .or. & - shapestr == 'NCPL') then - - select case (shapestr) - case ('NROW') - axis_dim = y_dim - case ('NCOL') - axis_dim = x_dim - case ('NCPL') - axis_dim = dim_ids%nmesh_face - end select - - ! set names - varname_l = export_varname(nc_varname, layer=0, iper=iper) - longname_l = export_longname(longname, pkgname, tagname, layer=0, iper=iper) - - allocate (var_id(1)) + character(len=LINELENGTH) :: longname, varname - ! reenter define mode and create variable - call nf_verify(nf90_redef(ncid), nc_fname) - call nf_verify(nf90_def_var(ncid, varname_l, NF90_INT, & - (/axis_dim/), var_id(1)), & - nc_fname) + if (idt%shape == 'NROW' .or. & + idt%shape == 'NCOL' .or. & + idt%shape == 'NCPL' .or. & + idt%shape == 'NAUX NCPL') then - ! NROW/NCOL shapes use default chunking - call ncvar_deflate(ncid, var_id(1), deflate, shuffle, nc_fname) + if (iper == 0) then - ! put attr - call nf_verify(nf90_put_att(ncid, var_id(1), '_FillValue', & - (/NF90_FILL_INT/)), nc_fname) - call nf_verify(nf90_put_att(ncid, var_id(1), 'long_name', & - longname_l), nc_fname) + select case (idt%shape) + case ('NROW') + axis_dim = y_dim + case ('NCOL') + axis_dim = x_dim + case ('NCPL', 'NAUX NCPL') + axis_dim = dim_ids%nmesh_face + end select - ! add mf6 attr - call ncvar_mf6attr(ncid, var_id(1), 0, iper, 0, nc_tag, nc_fname) - - ! exit define mode and write data - call nf_verify(nf90_enddef(ncid), nc_fname) - call nf_verify(nf90_put_var(ncid, var_id(1), p_mem), & - nc_fname) - - else - allocate (var_id(dis%nlay)) - - ! reenter define mode and create variable - call nf_verify(nf90_redef(ncid), nc_fname) - do k = 1, dis%nlay ! set names - varname_l = export_varname(nc_varname, layer=k, iper=iper) - longname_l = export_longname(longname, pkgname, tagname, layer=k, & - iper=iper) + varname = export_varname(pkgname, idt%tagname, mempath) + longname = export_longname(idt%longname, pkgname, idt%tagname, mempath) - call nf_verify(nf90_def_var(ncid, varname_l, NF90_INT, & - (/dim_ids%nmesh_face/), var_id(k)), & + allocate (var_id(1)) + + ! reenter define mode and create variable + call nf_verify(nf90_redef(ncid), nc_fname) + call nf_verify(nf90_def_var(ncid, varname, NF90_INT, & + (/axis_dim/), var_id(1)), & nc_fname) - ! apply chunking parameters - call ncvar_chunk(ncid, var_id(k), chunk_face, nc_fname) - ! defalte and shuffle - call ncvar_deflate(ncid, var_id(k), deflate, shuffle, nc_fname) + ! NROW/NCOL shapes use default chunking + call ncvar_deflate(ncid, var_id(1), deflate, shuffle, nc_fname) ! put attr - call nf_verify(nf90_put_att(ncid, var_id(k), '_FillValue', & + call nf_verify(nf90_put_att(ncid, var_id(1), '_FillValue', & (/NF90_FILL_INT/)), nc_fname) - call nf_verify(nf90_put_att(ncid, var_id(k), 'long_name', & - longname_l), nc_fname) + call nf_verify(nf90_put_att(ncid, var_id(1), 'long_name', & + longname), nc_fname) - ! add grid mapping and mf6 attr - call ncvar_gridmap(ncid, var_id(k), gridmap_name, nc_fname) - call ncvar_mf6attr(ncid, var_id(k), k, iper, 0, nc_tag, nc_fname) - end do + ! add mf6 attr + call ncvar_mf6attr(ncid, var_id(1), 0, 0, nc_tag, nc_fname) + + ! exit define mode and write data + call nf_verify(nf90_enddef(ncid), nc_fname) + call nf_verify(nf90_put_var(ncid, var_id(1), p_mem), & + nc_fname) + else + istp = ixstp() + nvals = dis%nrow * dis%ncol + call nf_verify(nf90_put_var(ncid, & + var_ids%export(1), p_mem, & + start=(/1, istp/), & + count=(/nvals, 1/)), nc_fname) + end if + else ! reshape input - dis_shape(1) = dis%ncol - dis_shape(2) = dis%nrow - dis_shape(3) = dis%nlay - nvals = product(dis_shape) - int3d(1:dis_shape(1), 1:dis_shape(2), 1:dis_shape(3)) => p_mem(1:nvals) - - ! exit define mode and write data - call nf_verify(nf90_enddef(ncid), nc_fname) - layer_shape(1) = dis%nrow * dis%ncol - do k = 1, dis%nlay - int1d(1:layer_shape(1)) => int3d(:, :, k) - call nf_verify(nf90_put_var(ncid, var_id(k), int1d), nc_fname) - end do + int3d(1:dis%ncol, 1:dis%nrow, 1:dis%nlay) => p_mem(1:dis%nodesuser) + + ! set nvals as ncpl + nvals = dis%nrow * dis%ncol + + if (iper == 0) then + ! not a timeseries, create variables and write griddata + allocate (var_id(dis%nlay)) + + ! reenter define mode and create variable + call nf_verify(nf90_redef(ncid), nc_fname) + do k = 1, dis%nlay + ! set names + varname = export_varname(pkgname, idt%tagname, mempath, & + layer=k) + longname = export_longname(idt%longname, pkgname, idt%tagname, & + mempath, layer=k) + + call nf_verify(nf90_def_var(ncid, varname, NF90_INT, & + (/dim_ids%nmesh_face/), var_id(k)), & + nc_fname) + + ! apply chunking parameters + call ncvar_chunk(ncid, var_id(k), chunk_face, nc_fname) + ! deflate and shuffle + call ncvar_deflate(ncid, var_id(k), deflate, shuffle, nc_fname) + + ! put attr + call nf_verify(nf90_put_att(ncid, var_id(k), '_FillValue', & + (/NF90_FILL_INT/)), nc_fname) + call nf_verify(nf90_put_att(ncid, var_id(k), 'long_name', & + longname), nc_fname) + + ! add grid mapping and mf6 attr + call ncvar_gridmap(ncid, var_id(k), gridmap_name, nc_fname) + call ncvar_mf6attr(ncid, var_id(k), k, 0, nc_tag, nc_fname) + end do + + ! exit define mode and write data + call nf_verify(nf90_enddef(ncid), nc_fname) + do k = 1, dis%nlay + int1d(1:nvals) => int3d(:, :, k) + call nf_verify(nf90_put_var(ncid, var_id(k), int1d), nc_fname) + end do - ! cleanup - deallocate (var_id) + ! cleanup + deallocate (var_id) + else + ! timeseries, add period data + istp = ixstp() + do k = 1, dis%nlay + int1d(1:nvals) => int3d(:, :, k) + call nf_verify(nf90_put_var(ncid, & + var_ids%export(k), int1d, & + start=(/1, istp/), & + count=(/nvals, 1/)), nc_fname) + end do + end if end if end subroutine nc_export_int1d !> @brief netcdf export 2D integer !< - subroutine nc_export_int2d(ncid, dim_ids, var_ids, dis, p_mem, nc_varname, & - pkgname, tagname, gridmap_name, shapestr, longname, & - nc_tag, deflate, shuffle, chunk_face, nc_fname) + subroutine nc_export_int2d(p_mem, ncid, dim_ids, var_ids, dis, idt, mempath, & + nc_tag, pkgname, gridmap_name, deflate, shuffle, & + chunk_face, nc_fname) + integer(I4B), dimension(:, :), pointer, contiguous, intent(in) :: p_mem integer(I4B), intent(in) :: ncid type(MeshNCDimIdType), intent(inout) :: dim_ids type(MeshNCVarIdType), intent(inout) :: var_ids type(DisType), pointer, intent(in) :: dis - integer(I4B), dimension(:, :), pointer, contiguous, intent(in) :: p_mem - character(len=*), intent(in) :: nc_varname + type(InputParamDefinitionType), pointer :: idt + character(len=*), intent(in) :: mempath + character(len=*), intent(in) :: nc_tag character(len=*), intent(in) :: pkgname - character(len=*), intent(in) :: tagname character(len=*), intent(in) :: gridmap_name - character(len=*), intent(in) :: shapestr - character(len=*), intent(in) :: longname - character(len=*), intent(in) :: nc_tag integer(I4B), intent(in) :: deflate integer(I4B), intent(in) :: shuffle integer(I4B), intent(in) :: chunk_face character(len=*), intent(in) :: nc_fname - integer(I4B) :: var_id + integer(I4B) :: var_id, nvals integer(I4B), dimension(:), pointer, contiguous :: int1d - integer(I4B), dimension(1) :: layer_shape - character(len=LINELENGTH) :: longname_l, varname_l + character(len=LINELENGTH) :: longname, varname ! set names - varname_l = export_varname(nc_varname) - longname_l = export_longname(longname, pkgname, tagname, 0) + varname = export_varname(pkgname, idt%tagname, mempath) + longname = export_longname(idt%longname, pkgname, idt%tagname, mempath) ! reenter define mode and create variable call nf_verify(nf90_redef(ncid), nc_fname) - call nf_verify(nf90_def_var(ncid, varname_l, NF90_INT, & + call nf_verify(nf90_def_var(ncid, varname, NF90_INT, & (/dim_ids%nmesh_face/), var_id), & nc_fname) @@ -764,45 +744,42 @@ subroutine nc_export_int2d(ncid, dim_ids, var_ids, dis, p_mem, nc_varname, & call nf_verify(nf90_put_att(ncid, var_id, '_FillValue', & (/NF90_FILL_INT/)), nc_fname) call nf_verify(nf90_put_att(ncid, var_id, 'long_name', & - longname_l), nc_fname) + longname), nc_fname) ! add grid mapping and mf6 attr call ncvar_gridmap(ncid, var_id, gridmap_name, nc_fname) - call ncvar_mf6attr(ncid, var_id, 0, 0, 0, nc_tag, nc_fname) + call ncvar_mf6attr(ncid, var_id, 0, 0, nc_tag, nc_fname) ! exit define mode and write data call nf_verify(nf90_enddef(ncid), nc_fname) - layer_shape(1) = dis%nrow * dis%ncol - int1d(1:layer_shape(1)) => p_mem + nvals = dis%nrow * dis%ncol + int1d(1:nvals) => p_mem call nf_verify(nf90_put_var(ncid, var_id, int1d), nc_fname) end subroutine nc_export_int2d !> @brief netcdf export 3D integer !< - subroutine nc_export_int3d(ncid, dim_ids, var_ids, dis, p_mem, nc_varname, & - pkgname, tagname, gridmap_name, shapestr, longname, & - nc_tag, deflate, shuffle, chunk_face, nc_fname) + subroutine nc_export_int3d(p_mem, ncid, dim_ids, var_ids, dis, idt, mempath, & + nc_tag, pkgname, gridmap_name, deflate, shuffle, & + chunk_face, nc_fname) + integer(I4B), dimension(:, :, :), pointer, contiguous, intent(in) :: p_mem integer(I4B), intent(in) :: ncid type(MeshNCDimIdType), intent(inout) :: dim_ids type(MeshNCVarIdType), intent(inout) :: var_ids type(DisType), pointer, intent(in) :: dis - integer(I4B), dimension(:, :, :), pointer, contiguous, intent(in) :: p_mem - character(len=*), intent(in) :: nc_varname + type(InputParamDefinitionType), pointer :: idt + character(len=*), intent(in) :: mempath + character(len=*), intent(in) :: nc_tag character(len=*), intent(in) :: pkgname - character(len=*), intent(in) :: tagname character(len=*), intent(in) :: gridmap_name - character(len=*), intent(in) :: shapestr - character(len=*), intent(in) :: longname - character(len=*), intent(in) :: nc_tag integer(I4B), intent(in) :: deflate integer(I4B), intent(in) :: shuffle integer(I4B), intent(in) :: chunk_face character(len=*), intent(in) :: nc_fname integer(I4B), dimension(:), allocatable :: var_id integer(I4B), dimension(:), pointer, contiguous :: int1d - character(len=LINELENGTH) :: longname_l, varname_l - integer(I4B), dimension(1) :: layer_shape - integer(I4B) :: k + character(len=LINELENGTH) :: longname, varname + integer(I4B) :: k, nvals allocate (var_id(dis%nlay)) @@ -810,10 +787,11 @@ subroutine nc_export_int3d(ncid, dim_ids, var_ids, dis, p_mem, nc_varname, & call nf_verify(nf90_redef(ncid), nc_fname) do k = 1, dis%nlay ! set names - varname_l = export_varname(nc_varname, layer=k) - longname_l = export_longname(longname, pkgname, tagname, k) + varname = export_varname(pkgname, idt%tagname, mempath, layer=k) + longname = export_longname(idt%longname, pkgname, idt%tagname, & + mempath, layer=k) - call nf_verify(nf90_def_var(ncid, varname_l, NF90_INT, & + call nf_verify(nf90_def_var(ncid, varname, NF90_INT, & (/dim_ids%nmesh_face/), var_id(k)), & nc_fname) @@ -826,18 +804,18 @@ subroutine nc_export_int3d(ncid, dim_ids, var_ids, dis, p_mem, nc_varname, & call nf_verify(nf90_put_att(ncid, var_id(k), '_FillValue', & (/NF90_FILL_INT/)), nc_fname) call nf_verify(nf90_put_att(ncid, var_id(k), 'long_name', & - longname_l), nc_fname) + longname), nc_fname) ! add grid mapping and mf6 attr call ncvar_gridmap(ncid, var_id(k), gridmap_name, nc_fname) - call ncvar_mf6attr(ncid, var_id(k), k, 0, 0, nc_tag, nc_fname) + call ncvar_mf6attr(ncid, var_id(k), k, 0, nc_tag, nc_fname) end do ! exit define mode and write data call nf_verify(nf90_enddef(ncid), nc_fname) - layer_shape(1) = dis%nrow * dis%ncol + nvals = dis%nrow * dis%ncol do k = 1, dis%nlay - int1d(1:layer_shape(1)) => p_mem(:, :, k) + int1d(1:nvals) => p_mem(:, :, k) call nf_verify(nf90_put_var(ncid, var_id(k), int1d), nc_fname) end do @@ -847,161 +825,186 @@ end subroutine nc_export_int3d !> @brief netcdf export 1D double !< - subroutine nc_export_dbl1d(ncid, dim_ids, x_dim, y_dim, var_ids, dis, p_mem, & - nc_varname, pkgname, tagname, gridmap_name, & - shapestr, longname, nc_tag, deflate, shuffle, & - chunk_face, nc_fname) + subroutine nc_export_dbl1d(p_mem, ncid, dim_ids, x_dim, y_dim, var_ids, dis, & + idt, mempath, nc_tag, pkgname, gridmap_name, & + deflate, shuffle, chunk_face, iper, iaux, nc_fname) + use NetCDFCommonModule, only: ixstp + real(DP), dimension(:), pointer, contiguous, intent(in) :: p_mem integer(I4B), intent(in) :: ncid type(MeshNCDimIdType), intent(inout) :: dim_ids integer(I4B), intent(in) :: x_dim integer(I4B), intent(in) :: y_dim - type(MeshNCVarIdType), intent(inout) :: var_ids + type(MeshNCVarIdType), intent(in) :: var_ids type(DisType), pointer, intent(in) :: dis - real(DP), dimension(:), pointer, contiguous, intent(in) :: p_mem - character(len=*), intent(in) :: nc_varname + type(InputParamDefinitionType), pointer :: idt + character(len=*), intent(in) :: mempath + character(len=*), intent(in) :: nc_tag character(len=*), intent(in) :: pkgname - character(len=*), intent(in) :: tagname character(len=*), intent(in) :: gridmap_name - character(len=*), intent(in) :: shapestr - character(len=*), intent(in) :: longname - character(len=*), intent(in) :: nc_tag integer(I4B), intent(in) :: deflate integer(I4B), intent(in) :: shuffle integer(I4B), intent(in) :: chunk_face + integer(I4B), intent(in) :: iper + integer(I4B), intent(in) :: iaux character(len=*), intent(in) :: nc_fname - integer(I4B), dimension(3) :: dis_shape - integer(I4B), dimension(1) :: layer_shape real(DP), dimension(:, :, :), pointer, contiguous :: dbl3d real(DP), dimension(:), pointer, contiguous :: dbl1d - integer(I4B) :: axis_dim, nvals, k - integer(I4B), dimension(:), allocatable :: var_id - character(len=LINELENGTH) :: longname_l, varname_l - - if (shapestr == 'NROW' .or. & - shapestr == 'NCOL') then ! .or. & - !shapestr == 'NCPL') then - - select case (shapestr) - case ('NROW') - axis_dim = y_dim - case ('NCOL') - axis_dim = x_dim - !case ('NCPL') - ! axis_dim = dim_ids%nmesh_face - end select - - ! set names - varname_l = export_varname(nc_varname) - longname_l = export_longname(longname, pkgname, tagname, 0) - - allocate (var_id(1)) - - ! reenter define mode and create variable - call nf_verify(nf90_redef(ncid), nc_fname) - call nf_verify(nf90_def_var(ncid, varname_l, NF90_DOUBLE, & - (/axis_dim/), var_id(1)), & - nc_fname) - - ! NROW/NCOL shapes use default chunking - call ncvar_deflate(ncid, var_id(1), deflate, shuffle, nc_fname) + integer(I4B) :: axis_dim, nvals, k, istp + integer(NF90_INT), dimension(:), allocatable :: var_id + character(len=LINELENGTH) :: longname, varname + + if (idt%shape == 'NROW' .or. & + idt%shape == 'NCOL' .or. & + idt%shape == 'NCPL' .or. & + idt%shape == 'NAUX NCPL') then + + if (iper == 0) then + + select case (idt%shape) + case ('NROW') + axis_dim = y_dim + case ('NCOL') + axis_dim = x_dim + case ('NCPL', 'NAUX NCPL') + axis_dim = dim_ids%nmesh_face + end select - ! put attr - call nf_verify(nf90_put_att(ncid, var_id(1), '_FillValue', & - (/NF90_FILL_DOUBLE/)), nc_fname) - call nf_verify(nf90_put_att(ncid, var_id(1), 'long_name', & - longname_l), nc_fname) - - ! add mf6 attr - call ncvar_mf6attr(ncid, var_id(1), 0, 0, 0, nc_tag, nc_fname) - - ! exit define mode and write data - call nf_verify(nf90_enddef(ncid), nc_fname) - call nf_verify(nf90_put_var(ncid, var_id(1), p_mem), & - nc_fname) - - else - allocate (var_id(dis%nlay)) - - ! reenter define mode and create variable - call nf_verify(nf90_redef(ncid), nc_fname) - do k = 1, dis%nlay ! set names - varname_l = export_varname(nc_varname, layer=k) - longname_l = export_longname(longname, pkgname, tagname, k) + varname = export_varname(pkgname, idt%tagname, mempath, iaux=iaux) + longname = export_longname(idt%longname, pkgname, idt%tagname, & + mempath, iaux=iaux) - call nf_verify(nf90_def_var(ncid, varname_l, NF90_DOUBLE, & - (/dim_ids%nmesh_face/), var_id(k)), & + allocate (var_id(1)) + + ! reenter define mode and create variable + call nf_verify(nf90_redef(ncid), nc_fname) + call nf_verify(nf90_def_var(ncid, varname, NF90_DOUBLE, & + (/axis_dim/), var_id(1)), & nc_fname) - ! apply chunking parameters - call ncvar_chunk(ncid, var_id(k), chunk_face, nc_fname) - ! defalte and shuffle - call ncvar_deflate(ncid, var_id(k), deflate, shuffle, nc_fname) + ! NROW/NCOL shapes use default chunking + call ncvar_deflate(ncid, var_id(1), deflate, shuffle, nc_fname) ! put attr - call nf_verify(nf90_put_att(ncid, var_id(k), '_FillValue', & + call nf_verify(nf90_put_att(ncid, var_id(1), '_FillValue', & (/NF90_FILL_DOUBLE/)), nc_fname) - call nf_verify(nf90_put_att(ncid, var_id(k), 'long_name', & - longname_l), nc_fname) + call nf_verify(nf90_put_att(ncid, var_id(1), 'long_name', & + longname), nc_fname) - ! add grid mapping and mf6 attr - call ncvar_gridmap(ncid, var_id(k), gridmap_name, nc_fname) - call ncvar_mf6attr(ncid, var_id(k), k, 0, 0, nc_tag, nc_fname) - end do + ! add mf6 attr + call ncvar_mf6attr(ncid, var_id(1), 0, iaux, nc_tag, nc_fname) + ! exit define mode and write data + call nf_verify(nf90_enddef(ncid), nc_fname) + call nf_verify(nf90_put_var(ncid, var_id(1), p_mem), & + nc_fname) + else + istp = ixstp() + nvals = dis%nrow * dis%ncol + call nf_verify(nf90_put_var(ncid, & + var_ids%export(1), p_mem, & + start=(/1, istp/), & + count=(/nvals, 1/)), nc_fname) + end if + + else ! reshape input - dis_shape(1) = dis%ncol - dis_shape(2) = dis%nrow - dis_shape(3) = dis%nlay - nvals = product(dis_shape) - dbl3d(1:dis_shape(1), 1:dis_shape(2), 1:dis_shape(3)) => p_mem(1:nvals) - - ! exit define mode and write data - call nf_verify(nf90_enddef(ncid), nc_fname) - layer_shape(1) = dis%nrow * dis%ncol - do k = 1, dis%nlay - dbl1d(1:layer_shape(1)) => dbl3d(:, :, k) - call nf_verify(nf90_put_var(ncid, var_id(k), dbl1d), nc_fname) - end do + dbl3d(1:dis%ncol, 1:dis%nrow, 1:dis%nlay) => p_mem(1:dis%nodesuser) + + ! set nvals as ncpl + nvals = dis%nrow * dis%ncol + + if (iper == 0) then + ! not a timeseries, create variables and write griddata + + ! allocate local variable id storage + allocate (var_id(dis%nlay)) + + ! reenter define mode and create layer variables + call nf_verify(nf90_redef(ncid), nc_fname) + do k = 1, dis%nlay + ! set names + varname = export_varname(pkgname, idt%tagname, mempath, layer=k, & + iaux=iaux) + longname = export_longname(idt%longname, pkgname, idt%tagname, & + mempath, layer=k, iaux=iaux) + + ! create layer variable + call nf_verify(nf90_def_var(ncid, varname, NF90_DOUBLE, & + (/dim_ids%nmesh_face/), var_id(k)), & + nc_fname) + + ! apply chunking parameters + call ncvar_chunk(ncid, var_id(k), chunk_face, nc_fname) + ! deflate and shuffle + call ncvar_deflate(ncid, var_id(k), deflate, shuffle, nc_fname) + + ! put attr + call nf_verify(nf90_put_att(ncid, var_id(k), '_FillValue', & + (/NF90_FILL_DOUBLE/)), nc_fname) + call nf_verify(nf90_put_att(ncid, var_id(k), 'long_name', & + longname), nc_fname) + + ! add grid mapping and mf6 attr + call ncvar_gridmap(ncid, var_id(k), gridmap_name, nc_fname) + call ncvar_mf6attr(ncid, var_id(k), k, iaux, nc_tag, nc_fname) + end do - ! cleanup - deallocate (var_id) + ! exit define mode + call nf_verify(nf90_enddef(ncid), nc_fname) + + ! write layer data + do k = 1, dis%nlay + dbl1d(1:nvals) => dbl3d(:, :, k) + call nf_verify(nf90_put_var(ncid, var_id(k), dbl1d), nc_fname) + end do + + ! cleanup + deallocate (var_id) + else + ! timeseries, add period data + istp = ixstp() + do k = 1, dis%nlay + dbl1d(1:nvals) => dbl3d(:, :, k) + call nf_verify(nf90_put_var(ncid, & + var_ids%export(k), dbl1d, & + start=(/1, istp/), & + count=(/nvals, 1/)), nc_fname) + end do + end if end if end subroutine nc_export_dbl1d !> @brief netcdf export 2D double !< - subroutine nc_export_dbl2d(ncid, dim_ids, var_ids, dis, p_mem, nc_varname, & - pkgname, tagname, gridmap_name, shapestr, longname, & - nc_tag, deflate, shuffle, chunk_face, nc_fname) + subroutine nc_export_dbl2d(p_mem, ncid, dim_ids, var_ids, dis, idt, mempath, & + nc_tag, pkgname, gridmap_name, deflate, shuffle, & + chunk_face, nc_fname) + real(DP), dimension(:, :), pointer, contiguous, intent(in) :: p_mem integer(I4B), intent(in) :: ncid type(MeshNCDimIdType), intent(inout) :: dim_ids type(MeshNCVarIdType), intent(inout) :: var_ids type(DisType), pointer, intent(in) :: dis - real(DP), dimension(:, :), pointer, contiguous, intent(in) :: p_mem - character(len=*), intent(in) :: nc_varname + type(InputParamDefinitionType), pointer :: idt + character(len=*), intent(in) :: mempath + character(len=*), intent(in) :: nc_tag character(len=*), intent(in) :: pkgname - character(len=*), intent(in) :: tagname character(len=*), intent(in) :: gridmap_name - character(len=*), intent(in) :: shapestr - character(len=*), intent(in) :: longname - character(len=*), intent(in) :: nc_tag integer(I4B), intent(in) :: deflate integer(I4B), intent(in) :: shuffle integer(I4B), intent(in) :: chunk_face character(len=*), intent(in) :: nc_fname - integer(I4B) :: var_id - character(len=LINELENGTH) :: longname_l, varname_l + integer(I4B) :: var_id, nvals + character(len=LINELENGTH) :: longname, varname real(DP), dimension(:), pointer, contiguous :: dbl1d - integer(I4B), dimension(1) :: layer_shape ! set names - varname_l = export_varname(nc_varname) - longname_l = export_longname(longname, pkgname, tagname, 0) + varname = export_varname(pkgname, idt%tagname, mempath) + longname = export_longname(idt%longname, pkgname, idt%tagname, mempath) ! reenter define mode and create variable call nf_verify(nf90_redef(ncid), nc_fname) - call nf_verify(nf90_def_var(ncid, varname_l, NF90_DOUBLE, & + call nf_verify(nf90_def_var(ncid, varname, NF90_DOUBLE, & (/dim_ids%nmesh_face/), var_id), & nc_fname) @@ -1014,56 +1017,45 @@ subroutine nc_export_dbl2d(ncid, dim_ids, var_ids, dis, p_mem, nc_varname, & call nf_verify(nf90_put_att(ncid, var_id, '_FillValue', & (/NF90_FILL_DOUBLE/)), nc_fname) call nf_verify(nf90_put_att(ncid, var_id, 'long_name', & - longname_l), nc_fname) + longname), nc_fname) ! add grid mapping and mf6 attr call ncvar_gridmap(ncid, var_id, gridmap_name, nc_fname) - call ncvar_mf6attr(ncid, var_id, 0, 0, 0, nc_tag, nc_fname) + call ncvar_mf6attr(ncid, var_id, 0, 0, nc_tag, nc_fname) ! exit define mode and write data call nf_verify(nf90_enddef(ncid), nc_fname) - layer_shape(1) = dis%nrow * dis%ncol - dbl1d(1:layer_shape(1)) => p_mem + nvals = dis%nrow * dis%ncol + dbl1d(1:nvals) => p_mem call nf_verify(nf90_put_var(ncid, var_id, dbl1d), nc_fname) end subroutine nc_export_dbl2d !> @brief netcdf export 3D double !< - subroutine nc_export_dbl3d(ncid, dim_ids, var_ids, dis, p_mem, nc_varname, & - pkgname, tagname, gridmap_name, shapestr, longname, & - nc_tag, deflate, shuffle, chunk_face, iper, iaux, & - nc_fname) - use ConstantsModule, only: DNODATA + subroutine nc_export_dbl3d(p_mem, ncid, dim_ids, var_ids, dis, idt, mempath, & + nc_tag, pkgname, gridmap_name, deflate, shuffle, & + chunk_face, nc_fname) + real(DP), dimension(:, :, :), pointer, contiguous, intent(in) :: p_mem integer(I4B), intent(in) :: ncid type(MeshNCDimIdType), intent(inout) :: dim_ids type(MeshNCVarIdType), intent(inout) :: var_ids type(DisType), pointer, intent(in) :: dis - real(DP), dimension(:, :, :), pointer, contiguous, intent(in) :: p_mem - character(len=*), intent(in) :: nc_varname + type(InputParamDefinitionType), pointer :: idt + character(len=*), intent(in) :: mempath + character(len=*), intent(in) :: nc_tag character(len=*), intent(in) :: pkgname - character(len=*), intent(in) :: tagname character(len=*), intent(in) :: gridmap_name - character(len=*), intent(in) :: shapestr - character(len=*), intent(in) :: longname - character(len=*), intent(in) :: nc_tag integer(I4B), intent(in) :: deflate integer(I4B), intent(in) :: shuffle integer(I4B), intent(in) :: chunk_face - integer(I4B), intent(in) :: iper - integer(I4B), intent(in) :: iaux character(len=*), intent(in) :: nc_fname integer(I4B), dimension(:), allocatable :: var_id real(DP), dimension(:), pointer, contiguous :: dbl1d - character(len=LINELENGTH) :: longname_l, varname_l - integer(I4B), dimension(1) :: layer_shape - integer(I4B) :: k - real(DP) :: fill_value + character(len=LINELENGTH) :: longname, varname + integer(I4B) :: k, nvals - if (iper > 0) then - fill_value = DNODATA - else - fill_value = NF90_FILL_DOUBLE - end if + ! set nvals as ncpl + nvals = dis%nrow * dis%ncol allocate (var_id(dis%nlay)) @@ -1071,10 +1063,11 @@ subroutine nc_export_dbl3d(ncid, dim_ids, var_ids, dis, p_mem, nc_varname, & call nf_verify(nf90_redef(ncid), nc_fname) do k = 1, dis%nlay ! set names - varname_l = export_varname(nc_varname, layer=k, iper=iper, iaux=iaux) - longname_l = export_longname(longname, pkgname, tagname, layer=k, iper=iper) + varname = export_varname(pkgname, idt%tagname, mempath, layer=k) + longname = export_longname(idt%longname, pkgname, idt%tagname, & + mempath, layer=k) - call nf_verify(nf90_def_var(ncid, varname_l, NF90_DOUBLE, & + call nf_verify(nf90_def_var(ncid, varname, NF90_DOUBLE, & (/dim_ids%nmesh_face/), var_id(k)), & nc_fname) @@ -1085,21 +1078,19 @@ subroutine nc_export_dbl3d(ncid, dim_ids, var_ids, dis, p_mem, nc_varname, & ! put attr call nf_verify(nf90_put_att(ncid, var_id(k), '_FillValue', & - (/fill_value/)), nc_fname) + (/NF90_FILL_DOUBLE/)), nc_fname) call nf_verify(nf90_put_att(ncid, var_id(k), 'long_name', & - longname_l), nc_fname) + longname), nc_fname) ! add grid mapping and mf6 attr call ncvar_gridmap(ncid, var_id(k), gridmap_name, nc_fname) - call ncvar_mf6attr(ncid, var_id(k), k, iper, iaux, nc_tag, nc_fname) - !end if + call ncvar_mf6attr(ncid, var_id(k), k, 0, nc_tag, nc_fname) end do ! exit define mode and write data call nf_verify(nf90_enddef(ncid), nc_fname) - layer_shape(1) = dis%nrow * dis%ncol do k = 1, dis%nlay - dbl1d(1:layer_shape(1)) => p_mem(:, :, k) + dbl1d(1:nvals) => p_mem(:, :, k) call nf_verify(nf90_put_var(ncid, var_id(k), dbl1d), nc_fname) end do diff --git a/src/Utilities/Export/DisNCStructured.f90 b/src/Utilities/Export/DisNCStructured.f90 index 403a243ad25..5f7ee126892 100644 --- a/src/Utilities/Export/DisNCStructured.f90 +++ b/src/Utilities/Export/DisNCStructured.f90 @@ -9,13 +9,14 @@ module DisNCStructuredModule use KindModule, only: DP, I4B, LGP use ConstantsModule, only: LINELENGTH, LENBIGLINE, LENCOMPONENTNAME, & - LENMEMPATH, LENVARNAME, DNODATA, DZERO + LENMEMPATH, DNODATA, DZERO use SimVariablesModule, only: errmsg, warnmsg use SimModule, only: store_error, store_warning, store_error_filename use MemoryManagerModule, only: mem_setptr use InputDefinitionModule, only: InputParamDefinitionType use CharacterStringModule, only: CharacterStringType - use NCModelExportModule, only: NCBaseModelExportType, export_longname + use NCModelExportModule, only: NCBaseModelExportType, export_varname, & + export_longname use DisModule, only: DisType use NetCDFCommonModule, only: nf_verify use netcdf @@ -45,6 +46,7 @@ module DisNCStructuredModule integer(I4B) :: z_bnds !< z boundaries 2D array integer(I4B) :: latitude !< latitude 2D array integer(I4B) :: longitude !< longitude 2D array + integer(I4B) :: export !< in scope export contains end type StructuredNCVarIdType @@ -64,12 +66,13 @@ module DisNCStructuredModule procedure :: init => dis_export_init procedure :: destroy => dis_export_destroy procedure :: df + procedure :: df_export procedure :: step procedure :: export_input_array + procedure :: export_df + procedure :: create_timeseries procedure :: export_input_arrays - procedure :: package_step_ilayer procedure :: package_step - procedure :: export_layer_3d procedure :: add_pkg_data procedure :: add_global_att procedure :: define_dim @@ -220,6 +223,8 @@ subroutine df(this) ! define the dependent variable call this%define_dependent() end if + ! define period input arrays + call this%df_export() ! exit define mode call nf_verify(nf90_enddef(this%ncid), this%nc_fname) ! add data locations @@ -234,16 +239,31 @@ subroutine df(this) call nf_verify(nf90_sync(this%ncid), this%nc_fname) end subroutine df + !> @brief define timeseries input variables + !< + subroutine df_export(this) + use NCModelExportModule, only: ExportPackageType + class(DisNCStructuredType), intent(inout) :: this + class(ExportPackageType), pointer :: export_pkg + integer(I4B) :: idx + do idx = 1, this%pkglist%Count() + export_pkg => this%get(idx) + call this%export_df(export_pkg) + end do + end subroutine df_export + !> @brief netcdf export step !< subroutine step(this) use ConstantsModule, only: DHNOFLO use TdisModule, only: totim + use NetCDFCommonModule, only: ixstp class(DisNCStructuredType), intent(inout) :: this real(DP), dimension(:), pointer, contiguous :: dbl1d - integer(I4B) :: n + integer(I4B) :: n, istp - this%stepcnt = this%stepcnt + 1 + ! set global step index + istp = ixstp() if (size(this%dis%nodeuser) < & size(this%dis%nodereduced)) then @@ -257,7 +277,7 @@ subroutine step(this) ! write step data to dependent variable call nf_verify(nf90_put_var(this%ncid, & this%var_ids%dependent, dbl1d, & - start=(/1, 1, 1, this%stepcnt/), & + start=(/1, 1, 1, istp/), & count=(/this%dis%ncol, & this%dis%nrow, & this%dis%nlay, 1/)), & @@ -267,7 +287,7 @@ subroutine step(this) ! write step data to dependent variable call nf_verify(nf90_put_var(this%ncid, & this%var_ids%dependent, this%x, & - start=(/1, 1, 1, this%stepcnt/), & + start=(/1, 1, 1, istp/), & count=(/this%dis%ncol, & this%dis%nrow, & this%dis%nlay, 1/)), & @@ -276,7 +296,7 @@ subroutine step(this) ! write to time coordinate variable call nf_verify(nf90_put_var(this%ncid, this%var_ids%time, & - totim, start=(/this%stepcnt/)), & + totim, start=(/istp/)), & this%nc_fname) ! synchronize file @@ -297,7 +317,7 @@ subroutine export_input_array(this, pkgtype, pkgname, mempath, idt) real(DP), dimension(:), pointer, contiguous :: dbl1d real(DP), dimension(:, :), pointer, contiguous :: dbl2d real(DP), dimension(:, :, :), pointer, contiguous :: dbl3d - character(len=LINELENGTH) :: nc_varname, input_attr + character(len=LINELENGTH) :: nc_tag integer(I4B) :: iper, iaux ! initialize @@ -305,63 +325,188 @@ subroutine export_input_array(this, pkgtype, pkgname, mempath, idt) iaux = 0 ! set variable name and input attribute string - nc_varname = export_varname(pkgname, idt) - input_attr = this%input_attribute(pkgname, idt) + nc_tag = this%input_attribute(pkgname, idt) select case (idt%datatype) case ('INTEGER1D') call mem_setptr(int1d, idt%mf6varname, mempath) - call nc_export_array(this%ncid, this%dim_ids, this%var_ids, this%dis, & - int1d, nc_varname, pkgname, idt%tagname, & - idt%shape, idt%longname, input_attr, & + call nc_export_array(int1d, this%ncid, this%dim_ids, this%var_ids, & + this%dis, idt, mempath, nc_tag, pkgname, & this%gridmap_name, this%latlon, this%deflate, & this%shuffle, this%chunk_z, this%chunk_y, & this%chunk_x, iper, this%nc_fname) case ('INTEGER2D') call mem_setptr(int2d, idt%mf6varname, mempath) - call nc_export_array(this%ncid, this%dim_ids, this%var_ids, this%dis, & - int2d, nc_varname, pkgname, idt%tagname, & - idt%shape, idt%longname, input_attr, & + call nc_export_array(int2d, this%ncid, this%dim_ids, this%var_ids, & + this%dis, idt, mempath, nc_tag, pkgname, & this%gridmap_name, this%latlon, this%deflate, & this%shuffle, this%chunk_z, this%chunk_y, & this%chunk_x, this%nc_fname) case ('INTEGER3D') call mem_setptr(int3d, idt%mf6varname, mempath) - call nc_export_array(this%ncid, this%dim_ids, this%var_ids, this%dis, & - int3d, nc_varname, pkgname, idt%tagname, & - idt%shape, idt%longname, input_attr, & + call nc_export_array(int3d, this%ncid, this%dim_ids, this%var_ids, & + this%dis, idt, mempath, nc_tag, pkgname, & this%gridmap_name, this%latlon, this%deflate, & this%shuffle, this%chunk_z, this%chunk_y, & this%chunk_x, this%nc_fname) case ('DOUBLE1D') call mem_setptr(dbl1d, idt%mf6varname, mempath) - call nc_export_array(this%ncid, this%dim_ids, this%var_ids, this%dis, & - dbl1d, nc_varname, pkgname, idt%tagname, & - idt%shape, idt%longname, input_attr, & + call nc_export_array(dbl1d, this%ncid, this%dim_ids, this%var_ids, & + this%dis, idt, mempath, nc_tag, pkgname, & this%gridmap_name, this%latlon, this%deflate, & this%shuffle, this%chunk_z, this%chunk_y, & - this%chunk_x, iper, this%nc_fname) + this%chunk_x, iper, iaux, this%nc_fname) case ('DOUBLE2D') call mem_setptr(dbl2d, idt%mf6varname, mempath) - call nc_export_array(this%ncid, this%dim_ids, this%var_ids, this%dis, & - dbl2d, nc_varname, pkgname, idt%tagname, & - idt%shape, idt%longname, input_attr, & + call nc_export_array(dbl2d, this%ncid, this%dim_ids, this%var_ids, & + this%dis, idt, mempath, nc_tag, pkgname, & this%gridmap_name, this%latlon, this%deflate, & this%shuffle, this%chunk_z, this%chunk_y, & this%chunk_x, this%nc_fname) case ('DOUBLE3D') call mem_setptr(dbl3d, idt%mf6varname, mempath) - call nc_export_array(this%ncid, this%dim_ids, this%var_ids, this%dis, & - dbl3d, nc_varname, pkgname, idt%tagname, & - idt%shape, idt%longname, input_attr, & + call nc_export_array(dbl3d, this%ncid, this%dim_ids, this%var_ids, & + this%dis, idt, mempath, nc_tag, pkgname, & this%gridmap_name, this%latlon, this%deflate, & this%shuffle, this%chunk_z, this%chunk_y, & - this%chunk_x, iper, iaux, this%nc_fname) + this%chunk_x, this%nc_fname) case default ! no-op, no other datatypes exported end select end subroutine export_input_array + !> @brief define export package + !< + subroutine export_df(this, export_pkg) + use NCModelExportModule, only: ExportPackageType + use DefinitionSelectModule, only: get_param_definition_type + class(DisNCStructuredType), intent(inout) :: this + class(ExportPackageType), pointer, intent(in) :: export_pkg + type(InputParamDefinitionType), pointer :: idt + integer(I4B) :: iparam, iaux + + ! export defined period input + do iparam = 1, export_pkg%nparam + ! initialize + iaux = 0 + ! set input definition + idt => & + get_param_definition_type(export_pkg%mf6_input%param_dfns, & + export_pkg%mf6_input%component_type, & + export_pkg%mf6_input%subcomponent_type, & + 'PERIOD', export_pkg%param_names(iparam), '') + select case (idt%shape) + case ('NCPL', 'NODES') + call this%create_timeseries(idt, iparam, iaux, export_pkg) + case ('NAUX NCPL', 'NAUX NODES') + do iaux = 1, export_pkg%naux + call this%create_timeseries(idt, iparam, iaux, export_pkg) + end do + case default + end select + end do + end subroutine export_df + + !> @brief create timeseries export variable + !< + subroutine create_timeseries(this, idt, iparam, iaux, export_pkg) + use NCModelExportModule, only: ExportPackageType + class(DisNCStructuredType), intent(inout) :: this + type(InputParamDefinitionType), pointer, intent(in) :: idt + integer(I4B), intent(in) :: iparam + integer(I4B), intent(in) :: iaux + class(ExportPackageType), pointer, intent(in) :: export_pkg + character(len=LINELENGTH) :: varname, longname, nc_tag + integer(I4B) :: varid + + ! set variable input tag + nc_tag = this%input_attribute(export_pkg%mf6_input%subcomponent_name, & + idt) + + ! set names + varname = export_varname(export_pkg%mf6_input%subcomponent_name, & + idt%tagname, export_pkg%mf6_input%mempath, & + iaux=iaux) + longname = export_longname(idt%longname, & + export_pkg%mf6_input%subcomponent_name, & + idt%tagname, export_pkg%mf6_input%mempath, & + iaux=iaux) + + ! create the netcdf timeseries variable + select case (idt%datatype) + case ('DOUBLE1D', 'DOUBLE2D') + if (idt%shape == 'NCPL' .or. & + idt%shape == 'NAUX NCPL') then + call nf_verify(nf90_def_var(this%ncid, varname, NF90_DOUBLE, & + (/this%dim_ids%x, & + this%dim_ids%y, & + this%dim_ids%time/), varid), & + this%nc_fname) + else + call nf_verify(nf90_def_var(this%ncid, varname, NF90_DOUBLE, & + (/this%dim_ids%x, & + this%dim_ids%y, & + this%dim_ids%z, & + this%dim_ids%time/), varid), & + this%nc_fname) + end if + call nf_verify(nf90_put_att(this%ncid, varid, & + '_FillValue', (/DNODATA/)), & + this%nc_fname) + case ('INTEGER1D') + if (idt%shape == 'NCPL' .or. & + idt%shape == 'NAUX NCPL') then + call nf_verify(nf90_def_var(this%ncid, varname, NF90_INT, & + (/this%dim_ids%x, & + this%dim_ids%y, & + this%dim_ids%time/), varid), & + this%nc_fname) + else + call nf_verify(nf90_def_var(this%ncid, varname, NF90_INT, & + (/this%dim_ids%x, & + this%dim_ids%y, & + this%dim_ids%z, & + this%dim_ids%time/), varid), & + this%nc_fname) + end if + call nf_verify(nf90_put_att(this%ncid, varid, & + '_FillValue', (/NF90_FILL_INT/)), & + this%nc_fname) + end select + + ! apply chunking parameters + if (this%chunking_active) then + call nf_verify(nf90_def_var_chunking(this%ncid, & + varid, & + NF90_CHUNKED, & + (/this%chunk_x, this%chunk_y, & + this%chunk_z, this%chunk_time/)), & + this%nc_fname) + end if + + ! deflate and shuffle + call ncvar_deflate(this%ncid, varid, this%deflate, & + this%shuffle, this%nc_fname) + + ! variable attributes + call nf_verify(nf90_put_att(this%ncid, varid, & + 'units', this%lenunits), this%nc_fname) + call nf_verify(nf90_put_att(this%ncid, varid, & + 'long_name', longname), this%nc_fname) + + ! add grid mapping and mf6 attr + call ncvar_gridmap(this%ncid, varid, this%gridmap_name, this%latlon, & + this%nc_fname) + call ncvar_mf6attr(this%ncid, varid, iaux, nc_tag, this%nc_fname) + + ! store variable id + if (idt%tagname == 'AUX') then + export_pkg%varids_aux(iaux, 1) = varid + else + export_pkg%varids_param(iparam, 1) = varid + end if + end subroutine create_timeseries + !> @brief write package gridded input data !< subroutine export_input_arrays(this, pkgtype, pkgname, mempath, param_dfns) @@ -388,38 +533,24 @@ subroutine export_input_arrays(this, pkgtype, pkgname, mempath, param_dfns) end do end subroutine export_input_arrays - !> @brief netcdf export package dynamic input with ilayer index variable + !> @brief netcdf export package dynamic input !< - subroutine package_step_ilayer(this, export_pkg, ilayer_varname, ilayer) + subroutine package_step(this, export_pkg) use TdisModule, only: kper - use NCModelExportModule, only: ExportPackageType use DefinitionSelectModule, only: get_param_definition_type + use NCModelExportModule, only: ExportPackageType class(DisNCStructuredType), intent(inout) :: this class(ExportPackageType), pointer, intent(in) :: export_pkg - character(len=*), intent(in) :: ilayer_varname - integer(I4B), intent(in) :: ilayer type(InputParamDefinitionType), pointer :: idt integer(I4B), dimension(:), pointer, contiguous :: int1d - real(DP), dimension(:), pointer, contiguous :: dbl1d + real(DP), dimension(:), pointer, contiguous :: dbl1d, nodes real(DP), dimension(:, :), pointer, contiguous :: dbl2d - integer(I4B), dimension(:), pointer, contiguous :: ialayer - real(DP), dimension(:), contiguous, pointer :: dbl1d_ptr - character(len=LINELENGTH) :: nc_varname, input_attr - integer(I4B) :: n, iparam, nvals - logical(LGP) :: ilayer_read + character(len=LINELENGTH) :: nc_tag + integer(I4B) :: iaux, iparam, nvals, n + integer(I4B), pointer :: nbound ! initialize - nullify (ialayer) - ilayer_read = .false. - - ! set pointer to ilayer variable - call mem_setptr(ialayer, export_pkg%param_names(ilayer), & - export_pkg%mf6_input%mempath) - - ! check if layer index variable was read - if (export_pkg%param_reads(ilayer)%invar == 1) then - ilayer_read = .true. - end if + iaux = 0 ! export defined period input do iparam = 1, export_pkg%nparam @@ -431,102 +562,96 @@ subroutine package_step_ilayer(this, export_pkg, ilayer_varname, ilayer) get_param_definition_type(export_pkg%mf6_input%param_dfns, & export_pkg%mf6_input%component_type, & export_pkg%mf6_input%subcomponent_type, & - 'PERIOD', export_pkg%param_names(iparam), & - this%nc_fname) - ! set variable name and input attrs - nc_varname = export_varname(export_pkg%mf6_input%subcomponent_name, idt, & - iper=kper) - input_attr = this%input_attribute(export_pkg%mf6_input%subcomponent_name, & - idt) + 'PERIOD', export_pkg%param_names(iparam), '') + + ! set variable input tag + nc_tag = this%input_attribute(export_pkg%mf6_input%subcomponent_name, & + idt) + ! export arrays select case (idt%datatype) case ('INTEGER1D') call mem_setptr(int1d, idt%mf6varname, export_pkg%mf6_input%mempath) - call nc_export_array(this%ncid, this%dim_ids, this%var_ids, this%dis, & - int1d, nc_varname, & - export_pkg%mf6_input%subcomponent_name, & - idt%tagname, idt%shape, idt%longname, input_attr, & + this%var_ids%export = export_pkg%varids_param(iparam, 1) + call nc_export_array(int1d, this%ncid, this%dim_ids, this%var_ids, & + this%dis, idt, export_pkg%mf6_input%mempath, & + nc_tag, export_pkg%mf6_input%subcomponent_name, & this%gridmap_name, this%latlon, this%deflate, & this%shuffle, this%chunk_z, this%chunk_y, & - this%chunk_x, export_pkg%iper, this%nc_fname) + this%chunk_x, kper, this%nc_fname) case ('DOUBLE1D') call mem_setptr(dbl1d, idt%mf6varname, export_pkg%mf6_input%mempath) - call this%export_layer_3d(export_pkg, idt, ilayer_read, ialayer, & - dbl1d, nc_varname, input_attr) + this%var_ids%export = export_pkg%varids_param(iparam, 1) + select case (idt%shape) + case ('NCPL') + call nc_export_array(dbl1d, this%ncid, this%dim_ids, this%var_ids, & + this%dis, idt, export_pkg%mf6_input%mempath, & + nc_tag, export_pkg%mf6_input%subcomponent_name, & + this%gridmap_name, this%latlon, this%deflate, & + this%shuffle, this%chunk_z, this%chunk_y, & + this%chunk_x, kper, iaux, this%nc_fname) + case ('NODES') + nvals = this%dis%nodesuser + allocate (nodes(nvals)) + nodes = DNODATA + call mem_setptr(dbl1d, idt%mf6varname, export_pkg%mf6_input%mempath) + call mem_setptr(int1d, 'NODEULIST', export_pkg%mf6_input%mempath) + call mem_setptr(nbound, 'NBOUND', export_pkg%mf6_input%mempath) + do n = 1, nbound + nodes(int1d(n)) = dbl1d(n) + end do + call nc_export_array(nodes, this%ncid, this%dim_ids, this%var_ids, & + this%dis, idt, export_pkg%mf6_input%mempath, & + nc_tag, export_pkg%mf6_input%subcomponent_name, & + this%gridmap_name, this%latlon, this%deflate, & + this%shuffle, this%chunk_z, this%chunk_y, & + this%chunk_x, kper, iaux, this%nc_fname) + deallocate (nodes) + case default + end select case ('DOUBLE2D') call mem_setptr(dbl2d, idt%mf6varname, export_pkg%mf6_input%mempath) - nvals = this%dis%ncol * this%dis%nrow - do n = 1, size(dbl2d, dim=1) ! naux - dbl1d_ptr(1:nvals) => dbl2d(n, :) - if (all(dbl1d_ptr == DZERO)) then - else - call this%export_layer_3d(export_pkg, idt, ilayer_read, ialayer, & - dbl1d_ptr, nc_varname, input_attr, n) - end if - end do - case default - errmsg = 'EXPORT ilayer unsupported datatype='//trim(idt%datatype) - call store_error(errmsg, .true.) - end select - end do - - ! synchronize file - call nf_verify(nf90_sync(this%ncid), this%nc_fname) - end subroutine package_step_ilayer - - !> @brief netcdf export package dynamic input - !< - subroutine package_step(this, export_pkg) - use TdisModule, only: kper - use NCModelExportModule, only: ExportPackageType - use DefinitionSelectModule, only: get_param_definition_type - class(DisNCStructuredType), intent(inout) :: this - class(ExportPackageType), pointer, intent(in) :: export_pkg - integer(I4B), dimension(:), pointer, contiguous :: int1d - real(DP), dimension(:), pointer, contiguous :: dbl1d - type(InputParamDefinitionType), pointer :: idt - character(len=LINELENGTH) :: nc_varname, input_attr - integer(I4B) :: iparam - - do iparam = 1, export_pkg%nparam - ! set input definition - idt => get_param_definition_type(export_pkg%mf6_input%param_dfns, & - export_pkg%mf6_input%component_type, & - export_pkg%mf6_input%subcomponent_type, & - 'PERIOD', export_pkg%param_names(iparam), & - this%nc_fname) - - ! set variable name and input attribute string - nc_varname = export_varname(export_pkg%mf6_input%subcomponent_name, idt, & - iper=kper) - input_attr = this%input_attribute(export_pkg%mf6_input%subcomponent_name, & - idt) + select case (idt%shape) + case ('NAUX NCPL') + nvals = this%dis%nrow * this%dis%ncol + allocate (nodes(nvals)) + do iaux = 1, size(dbl2d, dim=1) !naux + this%var_ids%export = export_pkg%varids_aux(iaux, 1) + do n = 1, nvals + nodes(n) = dbl2d(iaux, n) + end do + call nc_export_array(nodes, this%ncid, this%dim_ids, this%var_ids, & + this%dis, idt, export_pkg%mf6_input%mempath, & + nc_tag, export_pkg%mf6_input%subcomponent_name, & + this%gridmap_name, this%latlon, this%deflate, & + this%shuffle, this%chunk_z, this%chunk_y, & + this%chunk_x, kper, iaux, this%nc_fname) + end do + deallocate (nodes) + case ('NAUX NODES') + nvals = this%dis%nodesuser + allocate (nodes(nvals)) + call mem_setptr(int1d, 'NODEULIST', export_pkg%mf6_input%mempath) + call mem_setptr(nbound, 'NBOUND', export_pkg%mf6_input%mempath) + do iaux = 1, size(dbl2d, dim=1) ! naux + nodes = DNODATA + this%var_ids%export = export_pkg%varids_aux(iaux, 1) + do n = 1, nbound + nodes(int1d(n)) = dbl2d(iaux, n) + end do + call nc_export_array(nodes, this%ncid, this%dim_ids, this%var_ids, & + this%dis, idt, export_pkg%mf6_input%mempath, & + nc_tag, export_pkg%mf6_input%subcomponent_name, & + this%gridmap_name, this%latlon, this%deflate, & + this%shuffle, this%chunk_z, this%chunk_y, & + this%chunk_x, kper, iaux, this%nc_fname) - ! export arrays - select case (idt%datatype) - case ('INTEGER1D') - call mem_setptr(int1d, export_pkg%param_names(iparam), & - export_pkg%mf6_input%mempath) - call nc_export_array(this%ncid, this%dim_ids, this%var_ids, this%dis, & - int1d, nc_varname, & - export_pkg%mf6_input%subcomponent_name, & - idt%tagname, idt%shape, idt%longname, input_attr, & - this%gridmap_name, this%latlon, this%deflate, & - this%shuffle, this%chunk_z, this%chunk_y, & - this%chunk_x, kper, this%nc_fname) - case ('DOUBLE1D') - call mem_setptr(dbl1d, export_pkg%param_names(iparam), & - export_pkg%mf6_input%mempath) - call nc_export_array(this%ncid, this%dim_ids, this%var_ids, this%dis, & - dbl1d, nc_varname, & - export_pkg%mf6_input%subcomponent_name, & - idt%tagname, idt%shape, idt%longname, input_attr, & - this%gridmap_name, this%latlon, this%deflate, & - this%shuffle, this%chunk_z, this%chunk_y, & - this%chunk_x, kper, this%nc_fname) + end do + deallocate (nodes) + case default + end select case default - errmsg = 'EXPORT unsupported datatype='//trim(idt%datatype) - call store_error(errmsg, .true.) + ! no-op, no other datatypes exported end select end do @@ -534,67 +659,6 @@ subroutine package_step(this, export_pkg) call nf_verify(nf90_sync(this%ncid), this%nc_fname) end subroutine package_step - !> @brief export layer variable as full grid - !< - subroutine export_layer_3d(this, export_pkg, idt, ilayer_read, ialayer, & - dbl1d, nc_varname, input_attr, iaux) - use TdisModule, only: kper - use NCModelExportModule, only: ExportPackageType - class(DisNCStructuredType), intent(inout) :: this - class(ExportPackageType), pointer, intent(in) :: export_pkg - type(InputParamDefinitionType), pointer, intent(in) :: idt - logical(LGP), intent(in) :: ilayer_read - integer(I4B), dimension(:), pointer, contiguous, intent(in) :: ialayer - real(DP), dimension(:), pointer, contiguous, intent(in) :: dbl1d - character(len=*), intent(inout) :: nc_varname - character(len=*), intent(in) :: input_attr - integer(I4B), optional, intent(in) :: iaux - real(DP), dimension(:, :, :), pointer, contiguous :: dbl3d - integer(I4B) :: n, i, j, k, nvals, idxaux - real(DP), dimension(:, :), contiguous, pointer :: dbl2d_ptr - - ! initialize - idxaux = 0 - if (present(iaux)) then - nc_varname = export_varname(export_pkg%mf6_input%subcomponent_name, & - idt, iper=kper, iaux=iaux) - idxaux = iaux - end if - - allocate (dbl3d(export_pkg%mshape(3), export_pkg%mshape(2), & - export_pkg%mshape(1))) - - if (ilayer_read) then - do k = 1, size(dbl3d, dim=3) - n = 0 - do i = 1, size(dbl3d, dim=2) - do j = 1, size(dbl3d, dim=1) - n = n + 1 - if (ialayer(n) == k) then - dbl3d(j, i, k) = dbl1d(n) - else - dbl3d(j, i, k) = DNODATA - end if - end do - end do - end do - else - dbl3d = DNODATA - nvals = export_pkg%mshape(3) * export_pkg%mshape(2) - dbl2d_ptr(1:export_pkg%mshape(3), 1:export_pkg%mshape(2)) => dbl1d(1:nvals) - dbl3d(:, :, 1) = dbl2d_ptr(:, :) - end if - - call nc_export_array(this%ncid, this%dim_ids, this%var_ids, this%dis, dbl3d, & - nc_varname, export_pkg%mf6_input%subcomponent_name, & - idt%tagname, idt%shape, idt%longname, input_attr, & - this%gridmap_name, this%latlon, this%deflate, & - this%shuffle, this%chunk_z, this%chunk_y, this%chunk_x, & - export_pkg%iper, idxaux, this%nc_fname) - - deallocate (dbl3d) - end subroutine export_layer_3d - !> @brief determine packages to write gridded input !< subroutine add_pkg_data(this) @@ -661,7 +725,7 @@ subroutine add_global_att(this) ! source (MODFLOW 6) call nf_verify(nf90_put_att(this%ncid, NF90_GLOBAL, 'source', & this%annotation%source), this%nc_fname) - ! export type (MODFLOW 6) + ! grid type (MODFLOW 6) call nf_verify(nf90_put_att(this%ncid, NF90_GLOBAL, 'modflow_grid', & this%annotation%grid), this%nc_fname) ! MODFLOW 6 model type @@ -679,8 +743,6 @@ end subroutine add_global_att !> @brief netcdf export define dimensions !< subroutine define_dim(this) - use ConstantsModule, only: MVALIDATE - use SimVariablesModule, only: isim_mode class(DisNCStructuredType), intent(inout) :: this ! bound dim @@ -688,24 +750,22 @@ subroutine define_dim(this) this%nc_fname) ! Time - if (isim_mode /= MVALIDATE) then - call nf_verify(nf90_def_dim(this%ncid, 'time', this%totnstp, & - this%dim_ids%time), this%nc_fname) - call nf_verify(nf90_def_var(this%ncid, 'time', NF90_DOUBLE, & - this%dim_ids%time, this%var_ids%time), & - this%nc_fname) - call nf_verify(nf90_put_att(this%ncid, this%var_ids%time, 'calendar', & - 'standard'), this%nc_fname) - call nf_verify(nf90_put_att(this%ncid, this%var_ids%time, 'units', & - this%datetime), this%nc_fname) - call nf_verify(nf90_put_att(this%ncid, this%var_ids%time, 'axis', 'T'), & - this%nc_fname) - !call nf_verify(nf90_put_att(ncid, var_ids%time, 'bounds', 'time_bnds'), this%nc_fname) - call nf_verify(nf90_put_att(this%ncid, this%var_ids%time, 'standard_name', & - 'time'), this%nc_fname) - call nf_verify(nf90_put_att(this%ncid, this%var_ids%time, 'long_name', & - 'time'), this%nc_fname) - end if + call nf_verify(nf90_def_dim(this%ncid, 'time', this%totnstp, & + this%dim_ids%time), this%nc_fname) + call nf_verify(nf90_def_var(this%ncid, 'time', NF90_DOUBLE, & + this%dim_ids%time, this%var_ids%time), & + this%nc_fname) + call nf_verify(nf90_put_att(this%ncid, this%var_ids%time, 'calendar', & + 'standard'), this%nc_fname) + call nf_verify(nf90_put_att(this%ncid, this%var_ids%time, 'units', & + this%datetime), this%nc_fname) + call nf_verify(nf90_put_att(this%ncid, this%var_ids%time, 'axis', 'T'), & + this%nc_fname) + !call nf_verify(nf90_put_att(ncid, var_ids%time, 'bounds', 'time_bnds'), this%nc_fname) + call nf_verify(nf90_put_att(this%ncid, this%var_ids%time, 'standard_name', & + 'time'), this%nc_fname) + call nf_verify(nf90_put_att(this%ncid, this%var_ids%time, 'long_name', & + 'time'), this%nc_fname) ! Z dimension call nf_verify(nf90_def_dim(this%ncid, 'z', this%dis%nlay, this%dim_ids%z), & @@ -1025,22 +1085,17 @@ end subroutine ncvar_gridmap !> @brief put variable internal modflow6 attributes !< - subroutine ncvar_mf6attr(ncid, varid, iper, iaux, nc_tag, nc_fname) + subroutine ncvar_mf6attr(ncid, varid, iaux, nc_tag, nc_fname) integer(I4B), intent(in) :: ncid integer(I4B), intent(in) :: varid - integer(I4B), intent(in) :: iper integer(I4B), intent(in) :: iaux character(len=*), intent(in) :: nc_tag character(len=*), intent(in) :: nc_fname if (nc_tag /= '') then - call nf_verify(nf90_put_att(ncid, varid, 'modflow6_input', & + call nf_verify(nf90_put_att(ncid, varid, 'modflow_input', & nc_tag), nc_fname) - if (iper > 0) then - call nf_verify(nf90_put_att(ncid, varid, 'modflow6_iper', & - iper), nc_fname) - end if if (iaux > 0) then - call nf_verify(nf90_put_att(ncid, varid, 'modflow6_iaux', & + call nf_verify(nf90_put_att(ncid, varid, 'modflow_iaux', & iaux), nc_fname) end if end if @@ -1048,21 +1103,19 @@ end subroutine ncvar_mf6attr !> @brief netcdf export 1D integer !< - subroutine nc_export_int1d(ncid, dim_ids, var_ids, dis, p_mem, nc_varname, & - pkgname, tagname, shapestr, longname, nc_tag, & - gridmap_name, latlon, deflate, shuffle, chunk_z, & - chunk_y, chunk_x, iper, nc_fname) + subroutine nc_export_int1d(p_mem, ncid, dim_ids, var_ids, dis, idt, mempath, & + nc_tag, pkgname, gridmap_name, latlon, deflate, & + shuffle, chunk_z, chunk_y, chunk_x, iper, nc_fname) + use NetCDFCommonModule, only: ixstp + integer(I4B), dimension(:), pointer, contiguous, intent(in) :: p_mem integer(I4B), intent(in) :: ncid type(StructuredNCDimIdType), intent(inout) :: dim_ids type(StructuredNCVarIdType), intent(inout) :: var_ids type(DisType), pointer, intent(in) :: dis - integer(I4B), dimension(:), pointer, contiguous, intent(in) :: p_mem - character(len=*), intent(in) :: nc_varname - character(len=*), intent(in) :: pkgname - character(len=*), intent(in) :: tagname - character(len=*), intent(in) :: shapestr - character(len=*), intent(in) :: longname + type(InputParamDefinitionType), pointer, intent(in) :: idt + character(len=*), intent(in) :: mempath character(len=*), intent(in) :: nc_tag + character(len=*), intent(in) :: pkgname character(len=*), intent(in) :: gridmap_name logical(LGP), intent(in) :: latlon integer(I4B), intent(in) :: deflate @@ -1072,94 +1125,114 @@ subroutine nc_export_int1d(ncid, dim_ids, var_ids, dis, p_mem, nc_varname, & integer(I4B), intent(in) :: chunk_x integer(I4B), intent(in) :: iper character(len=*), intent(in) :: nc_fname - integer(I4B) :: var_id, axis_sz - character(len=LINELENGTH) :: longname_l - - if (shapestr == 'NROW' .or. & - shapestr == 'NCOL' .or. & - shapestr == 'NCPL') then - - select case (shapestr) - case ('NROW') - axis_sz = dim_ids%y - case ('NCOL') - axis_sz = dim_ids%x - case ('NCPL') - axis_sz = dim_ids%ncpl - end select - - longname_l = export_longname(longname, pkgname, tagname, layer=0, iper=iper) - - ! reenter define mode and create variable - call nf_verify(nf90_redef(ncid), nc_fname) - call nf_verify(nf90_def_var(ncid, nc_varname, NF90_INT, & - (/axis_sz/), var_id), & - nc_fname) - - ! NROW/NCOL shapes use default chunking - call ncvar_deflate(ncid, var_id, deflate, shuffle, nc_fname) - - ! put attr - call nf_verify(nf90_put_att(ncid, var_id, '_FillValue', & - (/NF90_FILL_INT/)), nc_fname) - call nf_verify(nf90_put_att(ncid, var_id, 'long_name', & - longname_l), nc_fname) - - ! add mf6 attr - call ncvar_mf6attr(ncid, var_id, iper, 0, nc_tag, nc_fname) - - ! exit define mode and write data - call nf_verify(nf90_enddef(ncid), nc_fname) - call nf_verify(nf90_put_var(ncid, var_id, p_mem), & - nc_fname) + integer(I4B) :: var_id, axis_sz, istp + character(len=LINELENGTH) :: varname, longname + + varname = export_varname(pkgname, idt%tagname, mempath) + + if (idt%shape == 'NROW' .or. & + idt%shape == 'NCOL' .or. & + idt%shape == 'NCPL' .or. & + idt%shape == 'NAUX NCPL') then + + if (iper == 0) then + select case (idt%shape) + case ('NROW') + axis_sz = dim_ids%y + case ('NCOL') + axis_sz = dim_ids%x + case ('NCPL', 'NAUX NCPL') + axis_sz = dim_ids%ncpl + end select + + longname = export_longname(idt%longname, pkgname, idt%tagname, mempath) + + ! reenter define mode and create variable + call nf_verify(nf90_redef(ncid), nc_fname) + call nf_verify(nf90_def_var(ncid, varname, NF90_INT, & + (/axis_sz/), var_id), & + nc_fname) + + ! NROW/NCOL shapes use default chunking + call ncvar_deflate(ncid, var_id, deflate, shuffle, nc_fname) + + ! put attr + call nf_verify(nf90_put_att(ncid, var_id, '_FillValue', & + (/NF90_FILL_INT/)), nc_fname) + call nf_verify(nf90_put_att(ncid, var_id, 'long_name', & + longname), nc_fname) + + ! add mf6 attr + call ncvar_mf6attr(ncid, var_id, 0, nc_tag, nc_fname) + + ! exit define mode and write data + call nf_verify(nf90_enddef(ncid), nc_fname) + call nf_verify(nf90_put_var(ncid, var_id, p_mem), & + nc_fname) + else + ! timeseries + istp = ixstp() + call nf_verify(nf90_put_var(ncid, & + var_ids%export, p_mem, & + start=(/1, istp/), & + count=(/dis%ncol, dis%nrow, 1/)), nc_fname) + end if else - ! reenter define mode and create variable - call nf_verify(nf90_redef(ncid), nc_fname) - call nf_verify(nf90_def_var(ncid, nc_varname, NF90_INT, & - (/dim_ids%x, dim_ids%y, dim_ids%z/), var_id), & - nc_fname) - ! apply chunking parameters - call ncvar_chunk3d(ncid, var_id, chunk_x, chunk_y, chunk_z, nc_fname) - ! deflate and shuffle - call ncvar_deflate(ncid, var_id, deflate, shuffle, nc_fname) - - ! put attr - call nf_verify(nf90_put_att(ncid, var_id, '_FillValue', & - (/NF90_FILL_INT/)), nc_fname) - call nf_verify(nf90_put_att(ncid, var_id, 'long_name', & - longname), nc_fname) - - ! add grid mapping and mf6 attr - call ncvar_gridmap(ncid, var_id, gridmap_name, latlon, nc_fname) - call ncvar_mf6attr(ncid, var_id, 0, 0, nc_tag, nc_fname) - - ! exit define mode and write data - call nf_verify(nf90_enddef(ncid), nc_fname) - call nf_verify(nf90_put_var(ncid, var_id, p_mem, start=(/1, 1, 1/), & - count=(/dis%ncol, dis%nrow, dis%nlay/)), & - nc_fname) + if (iper == 0) then + ! reenter define mode and create variable + call nf_verify(nf90_redef(ncid), nc_fname) + call nf_verify(nf90_def_var(ncid, varname, NF90_INT, & + (/dim_ids%x, dim_ids%y, dim_ids%z/), & + var_id), nc_fname) + + ! apply chunking parameters + call ncvar_chunk3d(ncid, var_id, chunk_x, chunk_y, chunk_z, nc_fname) + ! deflate and shuffle + call ncvar_deflate(ncid, var_id, deflate, shuffle, nc_fname) + + ! put attr + call nf_verify(nf90_put_att(ncid, var_id, '_FillValue', & + (/NF90_FILL_INT/)), nc_fname) + call nf_verify(nf90_put_att(ncid, var_id, 'long_name', & + idt%longname), nc_fname) + + ! add grid mapping and mf6 attr + call ncvar_gridmap(ncid, var_id, gridmap_name, latlon, nc_fname) + call ncvar_mf6attr(ncid, var_id, 0, nc_tag, nc_fname) + + ! exit define mode and write data + call nf_verify(nf90_enddef(ncid), nc_fname) + call nf_verify(nf90_put_var(ncid, var_id, p_mem, start=(/1, 1, 1/), & + count=(/dis%ncol, dis%nrow, dis%nlay/)), & + nc_fname) + else + ! timeseries + istp = ixstp() + call nf_verify(nf90_put_var(ncid, & + var_ids%export, p_mem, & + start=(/1, 1, 1, istp/), & + count=(/dis%ncol, dis%nrow, dis%nlay, 1/)), & + nc_fname) + end if end if end subroutine nc_export_int1d !> @brief netcdf export 2D integer !< - subroutine nc_export_int2d(ncid, dim_ids, var_ids, dis, p_mem, nc_varname, & - pkgname, tagname, shapestr, longname, nc_tag, & - gridmap_name, latlon, deflate, shuffle, chunk_z, & - chunk_y, chunk_x, nc_fname) + subroutine nc_export_int2d(p_mem, ncid, dim_ids, var_ids, dis, idt, mempath, & + nc_tag, pkgname, gridmap_name, latlon, deflate, & + shuffle, chunk_z, chunk_y, chunk_x, nc_fname) + integer(I4B), dimension(:, :), pointer, contiguous, intent(in) :: p_mem integer(I4B), intent(in) :: ncid type(StructuredNCDimIdType), intent(inout) :: dim_ids type(StructuredNCVarIdType), intent(inout) :: var_ids type(DisType), pointer, intent(in) :: dis - integer(I4B), dimension(:, :), pointer, contiguous, intent(in) :: p_mem - character(len=*), intent(in) :: nc_varname - character(len=*), intent(in) :: pkgname - character(len=*), intent(in) :: tagname - character(len=*), intent(in) :: shapestr - character(len=*), intent(in) :: longname + type(InputParamDefinitionType), pointer, intent(in) :: idt + character(len=*), intent(in) :: mempath character(len=*), intent(in) :: nc_tag + character(len=*), intent(in) :: pkgname character(len=*), intent(in) :: gridmap_name logical(LGP), intent(in) :: latlon integer(I4B), intent(in) :: deflate @@ -1168,11 +1241,14 @@ subroutine nc_export_int2d(ncid, dim_ids, var_ids, dis, p_mem, nc_varname, & integer(I4B), intent(in) :: chunk_y integer(I4B), intent(in) :: chunk_x character(len=*), intent(in) :: nc_fname + character(len=LINELENGTH) :: varname integer(I4B) :: var_id + varname = export_varname(pkgname, idt%tagname, mempath) + ! reenter define mode and create variable call nf_verify(nf90_redef(ncid), nc_fname) - call nf_verify(nf90_def_var(ncid, nc_varname, NF90_INT, & + call nf_verify(nf90_def_var(ncid, varname, NF90_INT, & (/dim_ids%x, dim_ids%y/), var_id), & nc_fname) @@ -1185,11 +1261,11 @@ subroutine nc_export_int2d(ncid, dim_ids, var_ids, dis, p_mem, nc_varname, & call nf_verify(nf90_put_att(ncid, var_id, '_FillValue', & (/NF90_FILL_INT/)), nc_fname) call nf_verify(nf90_put_att(ncid, var_id, 'long_name', & - longname), nc_fname) + idt%longname), nc_fname) ! add grid mapping and mf6 attr call ncvar_gridmap(ncid, var_id, gridmap_name, latlon, nc_fname) - call ncvar_mf6attr(ncid, var_id, 0, 0, nc_tag, nc_fname) + call ncvar_mf6attr(ncid, var_id, 0, nc_tag, nc_fname) ! exit define mode and write data call nf_verify(nf90_enddef(ncid), nc_fname) @@ -1200,21 +1276,18 @@ end subroutine nc_export_int2d !> @brief netcdf export 3D integer !< - subroutine nc_export_int3d(ncid, dim_ids, var_ids, dis, p_mem, nc_varname, & - pkgname, tagname, shapestr, longname, nc_tag, & - gridmap_name, latlon, deflate, shuffle, chunk_z, & - chunk_y, chunk_x, nc_fname) + subroutine nc_export_int3d(p_mem, ncid, dim_ids, var_ids, dis, idt, mempath, & + nc_tag, pkgname, gridmap_name, latlon, deflate, & + shuffle, chunk_z, chunk_y, chunk_x, nc_fname) + integer(I4B), dimension(:, :, :), pointer, contiguous, intent(in) :: p_mem integer(I4B), intent(in) :: ncid type(StructuredNCDimIdType), intent(inout) :: dim_ids type(StructuredNCVarIdType), intent(inout) :: var_ids type(DisType), pointer, intent(in) :: dis - integer(I4B), dimension(:, :, :), pointer, contiguous, intent(in) :: p_mem - character(len=*), intent(in) :: nc_varname - character(len=*), intent(in) :: pkgname - character(len=*), intent(in) :: tagname - character(len=*), intent(in) :: shapestr - character(len=*), intent(in) :: longname + type(InputParamDefinitionType), pointer, intent(in) :: idt + character(len=*), intent(in) :: mempath character(len=*), intent(in) :: nc_tag + character(len=*), intent(in) :: pkgname character(len=*), intent(in) :: gridmap_name logical(LGP), intent(in) :: latlon integer(I4B), intent(in) :: deflate @@ -1223,11 +1296,14 @@ subroutine nc_export_int3d(ncid, dim_ids, var_ids, dis, p_mem, nc_varname, & integer(I4B), intent(in) :: chunk_y integer(I4B), intent(in) :: chunk_x character(len=*), intent(in) :: nc_fname + character(len=LINELENGTH) :: varname integer(I4B) :: var_id + varname = export_varname(pkgname, idt%tagname, mempath) + ! reenter define mode and create variable call nf_verify(nf90_redef(ncid), nc_fname) - call nf_verify(nf90_def_var(ncid, nc_varname, NF90_INT, & + call nf_verify(nf90_def_var(ncid, varname, NF90_INT, & (/dim_ids%x, dim_ids%y, dim_ids%z/), var_id), & nc_fname) @@ -1240,11 +1316,11 @@ subroutine nc_export_int3d(ncid, dim_ids, var_ids, dis, p_mem, nc_varname, & call nf_verify(nf90_put_att(ncid, var_id, '_FillValue', & (/NF90_FILL_INT/)), nc_fname) call nf_verify(nf90_put_att(ncid, var_id, 'long_name', & - longname), nc_fname) + idt%longname), nc_fname) ! add grid mapping and mf6 attr call ncvar_gridmap(ncid, var_id, gridmap_name, latlon, nc_fname) - call ncvar_mf6attr(ncid, var_id, 0, 0, nc_tag, nc_fname) + call ncvar_mf6attr(ncid, var_id, 0, nc_tag, nc_fname) ! exit define mode and write data call nf_verify(nf90_enddef(ncid), nc_fname) @@ -1255,22 +1331,20 @@ end subroutine nc_export_int3d !> @brief netcdf export 1D double !< - subroutine nc_export_dbl1d(ncid, dim_ids, var_ids, dis, p_mem, nc_varname, & - pkgname, tagname, shapestr, longname, nc_tag, & - gridmap_name, latlon, deflate, shuffle, chunk_z, & - chunk_y, chunk_x, iper, nc_fname) - use ConstantsModule, only: DNODATA + subroutine nc_export_dbl1d(p_mem, ncid, dim_ids, var_ids, dis, idt, mempath, & + nc_tag, pkgname, gridmap_name, latlon, deflate, & + shuffle, chunk_z, chunk_y, chunk_x, iper, iaux, & + nc_fname) + use NetCDFCommonModule, only: ixstp + real(DP), dimension(:), pointer, contiguous, intent(in) :: p_mem integer(I4B), intent(in) :: ncid type(StructuredNCDimIdType), intent(inout) :: dim_ids type(StructuredNCVarIdType), intent(inout) :: var_ids type(DisType), pointer, intent(in) :: dis - real(DP), dimension(:), pointer, contiguous, intent(in) :: p_mem - character(len=*), intent(in) :: nc_varname - character(len=*), intent(in) :: pkgname - character(len=*), intent(in) :: tagname - character(len=*), intent(in) :: shapestr - character(len=*), intent(in) :: longname + type(InputParamDefinitionType), pointer, intent(in) :: idt + character(len=*), intent(in) :: mempath character(len=*), intent(in) :: nc_tag + character(len=*), intent(in) :: pkgname character(len=*), intent(in) :: gridmap_name logical(LGP), intent(in) :: latlon integer(I4B), intent(in) :: deflate @@ -1279,102 +1353,120 @@ subroutine nc_export_dbl1d(ncid, dim_ids, var_ids, dis, p_mem, nc_varname, & integer(I4B), intent(in) :: chunk_y integer(I4B), intent(in) :: chunk_x integer(I4B), intent(in) :: iper + integer(I4B), intent(in) :: iaux character(len=*), intent(in) :: nc_fname - integer(I4B) :: var_id, axis_sz - real(DP) :: fill_value - character(len=LINELENGTH) :: longname_l - - if (shapestr == 'NROW' .or. & - shapestr == 'NCOL' .or. & - shapestr == 'NCPL') then - - select case (shapestr) - case ('NROW') - axis_sz = dim_ids%y - case ('NCOL') - axis_sz = dim_ids%x - case ('NCPL') - axis_sz = dim_ids%ncpl - end select - - ! reenter define mode and create variable - call nf_verify(nf90_redef(ncid), nc_fname) - call nf_verify(nf90_def_var(ncid, nc_varname, NF90_DOUBLE, & - (/axis_sz/), var_id), & - nc_fname) - - ! NROW/NCOL shapes use default chunking - call ncvar_deflate(ncid, var_id, deflate, shuffle, nc_fname) - - ! put attr - call nf_verify(nf90_put_att(ncid, var_id, '_FillValue', & - (/NF90_FILL_DOUBLE/)), nc_fname) - call nf_verify(nf90_put_att(ncid, var_id, 'long_name', & - longname), nc_fname) - - ! add mf6 attr - call ncvar_mf6attr(ncid, var_id, 0, 0, nc_tag, nc_fname) - - ! exit define mode and write data - call nf_verify(nf90_enddef(ncid), nc_fname) - call nf_verify(nf90_put_var(ncid, var_id, p_mem), & - nc_fname) - - else - if (iper > 0) then - fill_value = DNODATA + integer(I4B) :: var_id, axis_sz, istp + character(len=LINELENGTH) :: varname, longname + + if (idt%shape == 'NROW' .or. & + idt%shape == 'NCOL' .or. & + idt%shape == 'NCPL' .or. & + idt%shape == 'NAUX NCPL') then + + if (iper == 0) then + select case (idt%shape) + case ('NROW') + axis_sz = dim_ids%y + case ('NCOL') + axis_sz = dim_ids%x + case ('NCPL', 'NAUX NCPL') + axis_sz = dim_ids%ncpl + end select + + varname = export_varname(pkgname, idt%tagname, mempath) + longname = export_longname(idt%longname, pkgname, idt%tagname, mempath, & + iaux=iaux) + + ! reenter define mode and create variable + call nf_verify(nf90_redef(ncid), nc_fname) + call nf_verify(nf90_def_var(ncid, varname, NF90_DOUBLE, & + (/axis_sz/), var_id), & + nc_fname) + + ! NROW/NCOL shapes use default chunking + call ncvar_deflate(ncid, var_id, deflate, shuffle, nc_fname) + + ! put attr + call nf_verify(nf90_put_att(ncid, var_id, '_FillValue', & + (/NF90_FILL_DOUBLE/)), nc_fname) + call nf_verify(nf90_put_att(ncid, var_id, 'long_name', & + longname), nc_fname) + + ! add mf6 attr + call ncvar_mf6attr(ncid, var_id, iaux, nc_tag, nc_fname) + + ! exit define mode and write data + call nf_verify(nf90_enddef(ncid), nc_fname) + call nf_verify(nf90_put_var(ncid, var_id, p_mem), & + nc_fname) else - fill_value = NF90_FILL_DOUBLE + ! timeseries + istp = ixstp() + call nf_verify(nf90_put_var(ncid, & + var_ids%export, p_mem, & + start=(/1, istp/), & + count=(/dis%ncol, dis%nrow, 1/)), nc_fname) end if - longname_l = export_longname(longname, pkgname, tagname, layer=0, iper=iper) - - ! reenter define mode and create variable - call nf_verify(nf90_redef(ncid), nc_fname) - call nf_verify(nf90_def_var(ncid, nc_varname, NF90_DOUBLE, & - (/dim_ids%x, dim_ids%y, dim_ids%z/), var_id), & - nc_fname) + else - ! apply chunking parameters - call ncvar_chunk3d(ncid, var_id, chunk_x, chunk_y, chunk_z, nc_fname) - ! deflate and shuffle - call ncvar_deflate(ncid, var_id, deflate, shuffle, nc_fname) - - ! put attr - call nf_verify(nf90_put_att(ncid, var_id, '_FillValue', & - (/fill_value/)), nc_fname) - call nf_verify(nf90_put_att(ncid, var_id, 'long_name', & - longname_l), nc_fname) - - ! add grid mapping and mf6 attr - call ncvar_gridmap(ncid, var_id, gridmap_name, latlon, nc_fname) - call ncvar_mf6attr(ncid, var_id, iper, 0, nc_tag, nc_fname) - - ! exit define mode and write data - call nf_verify(nf90_enddef(ncid), nc_fname) - call nf_verify(nf90_put_var(ncid, var_id, p_mem, start=(/1, 1, 1/), & - count=(/dis%ncol, dis%nrow, dis%nlay/)), & - nc_fname) + if (iper == 0) then + varname = export_varname(pkgname, idt%tagname, mempath, iaux=iaux) + longname = export_longname(idt%longname, pkgname, idt%tagname, mempath, & + iaux=iaux) + + ! reenter define mode and create variable + call nf_verify(nf90_redef(ncid), nc_fname) + call nf_verify(nf90_def_var(ncid, varname, NF90_DOUBLE, & + (/dim_ids%x, dim_ids%y, dim_ids%z/), & + var_id), nc_fname) + + ! apply chunking parameters + call ncvar_chunk3d(ncid, var_id, chunk_x, chunk_y, chunk_z, nc_fname) + ! deflate and shuffle + call ncvar_deflate(ncid, var_id, deflate, shuffle, nc_fname) + + ! put attr + call nf_verify(nf90_put_att(ncid, var_id, '_FillValue', & + (/NF90_FILL_DOUBLE/)), nc_fname) + call nf_verify(nf90_put_att(ncid, var_id, 'long_name', & + longname), nc_fname) + + ! add grid mapping and mf6 attr + call ncvar_gridmap(ncid, var_id, gridmap_name, latlon, nc_fname) + call ncvar_mf6attr(ncid, var_id, iaux, nc_tag, nc_fname) + + ! exit define mode and write data + call nf_verify(nf90_enddef(ncid), nc_fname) + call nf_verify(nf90_put_var(ncid, var_id, p_mem, start=(/1, 1, 1/), & + count=(/dis%ncol, dis%nrow, dis%nlay/)), & + nc_fname) + else + ! timeseries + istp = ixstp() + call nf_verify(nf90_put_var(ncid, & + var_ids%export, p_mem, & + start=(/1, 1, 1, istp/), & + count=(/dis%ncol, dis%nrow, dis%nlay, 1/)), & + nc_fname) + end if end if end subroutine nc_export_dbl1d !> @brief netcdf export 2D double !< - subroutine nc_export_dbl2d(ncid, dim_ids, var_ids, dis, p_mem, nc_varname, & - pkgname, tagname, shapestr, longname, nc_tag, & - gridmap_name, latlon, deflate, shuffle, chunk_z, & - chunk_y, chunk_x, nc_fname) + subroutine nc_export_dbl2d(p_mem, ncid, dim_ids, var_ids, dis, idt, mempath, & + nc_tag, pkgname, gridmap_name, latlon, deflate, & + shuffle, chunk_z, chunk_y, chunk_x, nc_fname) + real(DP), dimension(:, :), pointer, contiguous, intent(in) :: p_mem integer(I4B), intent(in) :: ncid type(StructuredNCDimIdType), intent(inout) :: dim_ids type(StructuredNCVarIdType), intent(inout) :: var_ids type(DisType), pointer, intent(in) :: dis - real(DP), dimension(:, :), pointer, contiguous, intent(in) :: p_mem - character(len=*), intent(in) :: nc_varname - character(len=*), intent(in) :: pkgname - character(len=*), intent(in) :: tagname - character(len=*), intent(in) :: shapestr - character(len=*), intent(in) :: longname + type(InputParamDefinitionType), pointer, intent(in) :: idt + character(len=*), intent(in) :: mempath character(len=*), intent(in) :: nc_tag + character(len=*), intent(in) :: pkgname character(len=*), intent(in) :: gridmap_name logical(LGP), intent(in) :: latlon integer(I4B), intent(in) :: deflate @@ -1383,11 +1475,14 @@ subroutine nc_export_dbl2d(ncid, dim_ids, var_ids, dis, p_mem, nc_varname, & integer(I4B), intent(in) :: chunk_y integer(I4B), intent(in) :: chunk_x character(len=*), intent(in) :: nc_fname + character(len=LINELENGTH) :: varname integer(I4B) :: var_id + varname = export_varname(pkgname, idt%tagname, mempath) + ! reenter define mode and create variable call nf_verify(nf90_redef(ncid), nc_fname) - call nf_verify(nf90_def_var(ncid, nc_varname, NF90_DOUBLE, & + call nf_verify(nf90_def_var(ncid, varname, NF90_DOUBLE, & (/dim_ids%x, dim_ids%y/), var_id), & nc_fname) @@ -1400,11 +1495,11 @@ subroutine nc_export_dbl2d(ncid, dim_ids, var_ids, dis, p_mem, nc_varname, & call nf_verify(nf90_put_att(ncid, var_id, '_FillValue', & (/NF90_FILL_DOUBLE/)), nc_fname) call nf_verify(nf90_put_att(ncid, var_id, 'long_name', & - longname), nc_fname) + idt%longname), nc_fname) ! add grid mapping and mf6 attr call ncvar_gridmap(ncid, var_id, gridmap_name, latlon, nc_fname) - call ncvar_mf6attr(ncid, var_id, 0, 0, nc_tag, nc_fname) + call ncvar_mf6attr(ncid, var_id, 0, nc_tag, nc_fname) ! exit define mode and write data call nf_verify(nf90_enddef(ncid), nc_fname) @@ -1415,22 +1510,18 @@ end subroutine nc_export_dbl2d !> @brief netcdf export 3D double !< - subroutine nc_export_dbl3d(ncid, dim_ids, var_ids, dis, p_mem, nc_varname, & - pkgname, tagname, shapestr, longname, nc_tag, & - gridmap_name, latlon, deflate, shuffle, chunk_z, & - chunk_y, chunk_x, iper, iaux, nc_fname) - use ConstantsModule, only: DNODATA + subroutine nc_export_dbl3d(p_mem, ncid, dim_ids, var_ids, dis, idt, mempath, & + nc_tag, pkgname, gridmap_name, latlon, deflate, & + shuffle, chunk_z, chunk_y, chunk_x, nc_fname) + real(DP), dimension(:, :, :), pointer, contiguous, intent(in) :: p_mem integer(I4B), intent(in) :: ncid type(StructuredNCDimIdType), intent(inout) :: dim_ids type(StructuredNCVarIdType), intent(inout) :: var_ids type(DisType), pointer, intent(in) :: dis - real(DP), dimension(:, :, :), pointer, contiguous, intent(in) :: p_mem - character(len=*), intent(in) :: nc_varname - character(len=*), intent(in) :: pkgname - character(len=*), intent(in) :: tagname - character(len=*), intent(in) :: shapestr - character(len=*), intent(in) :: longname + type(InputParamDefinitionType), pointer, intent(in) :: idt + character(len=*), intent(in) :: mempath character(len=*), intent(in) :: nc_tag + character(len=*), intent(in) :: pkgname character(len=*), intent(in) :: gridmap_name logical(LGP), intent(in) :: latlon integer(I4B), intent(in) :: deflate @@ -1438,24 +1529,16 @@ subroutine nc_export_dbl3d(ncid, dim_ids, var_ids, dis, p_mem, nc_varname, & integer(I4B), intent(in) :: chunk_z integer(I4B), intent(in) :: chunk_y integer(I4B), intent(in) :: chunk_x - integer(I4B), intent(in) :: iper - integer(I4B), intent(in) :: iaux character(len=*), intent(in) :: nc_fname integer(I4B) :: var_id - real(DP) :: fill_value - character(len=LINELENGTH) :: longname_l + character(len=LINELENGTH) :: varname, longname - if (iper > 0) then - fill_value = DNODATA - else - fill_value = NF90_FILL_DOUBLE - end if - - longname_l = export_longname(longname, pkgname, tagname, layer=0, iper=iper) + varname = export_varname(pkgname, idt%tagname, mempath) + longname = export_longname(idt%longname, pkgname, idt%tagname, mempath) ! reenter define mode and create variable call nf_verify(nf90_redef(ncid), nc_fname) - call nf_verify(nf90_def_var(ncid, nc_varname, NF90_DOUBLE, & + call nf_verify(nf90_def_var(ncid, varname, NF90_DOUBLE, & (/dim_ids%x, dim_ids%y, dim_ids%z/), var_id), & nc_fname) @@ -1466,13 +1549,13 @@ subroutine nc_export_dbl3d(ncid, dim_ids, var_ids, dis, p_mem, nc_varname, & ! put attr call nf_verify(nf90_put_att(ncid, var_id, '_FillValue', & - (/fill_value/)), nc_fname) + (/NF90_FILL_DOUBLE/)), nc_fname) call nf_verify(nf90_put_att(ncid, var_id, 'long_name', & - longname_l), nc_fname) + longname), nc_fname) ! add grid mapping and mf6 attr call ncvar_gridmap(ncid, var_id, gridmap_name, latlon, nc_fname) - call ncvar_mf6attr(ncid, var_id, iper, iaux, nc_tag, nc_fname) + call ncvar_mf6attr(ncid, var_id, 0, nc_tag, nc_fname) ! exit define mode and write data call nf_verify(nf90_enddef(ncid), nc_fname) @@ -1481,30 +1564,4 @@ subroutine nc_export_dbl3d(ncid, dim_ids, var_ids, dis, p_mem, nc_varname, & nc_fname) end subroutine nc_export_dbl3d - !> @brief build netcdf variable name - !< - function export_varname(pkgname, idt, iper, iaux) result(varname) - use InputOutputModule, only: lowcase - character(len=*), intent(in) :: pkgname - type(InputParamDefinitionType), pointer, intent(in) :: idt - integer(I4B), optional, intent(in) :: iper - integer(I4B), optional, intent(in) :: iaux - character(len=LINELENGTH) :: varname - character(len=LINELENGTH) :: pname, vname - pname = pkgname - vname = idt%mf6varname - call lowcase(pname) - call lowcase(vname) - if (present(iper)) then - if (present(iaux)) then - write (varname, '(a,i0,a,i0)') trim(pname)//'_'//trim(vname)// & - '_p', iper, 'a', iaux - else - write (varname, '(a,i0)') trim(pname)//'_'//trim(vname)//'_p', iper - end if - else - varname = trim(pname)//'_'//trim(vname) - end if - end function export_varname - end module DisNCStructuredModule diff --git a/src/Utilities/Export/DisvNCMesh.f90 b/src/Utilities/Export/DisvNCMesh.f90 index 43e44e89b43..81d79d6d818 100644 --- a/src/Utilities/Export/DisvNCMesh.f90 +++ b/src/Utilities/Export/DisvNCMesh.f90 @@ -9,7 +9,7 @@ module MeshDisvModelModule use KindModule, only: DP, I4B, LGP use ConstantsModule, only: LINELENGTH, LENBIGLINE, LENCOMPONENTNAME, & - LENMEMPATH + LENMEMPATH, DNODATA, DZERO use SimVariablesModule, only: errmsg use SimModule, only: store_error, store_error_filename use MemoryManagerModule, only: mem_setptr @@ -17,8 +17,8 @@ module MeshDisvModelModule use CharacterStringModule, only: CharacterStringType use MeshModelModule, only: Mesh2dModelType, MeshNCDimIdType, MeshNCVarIdType, & ncvar_chunk, ncvar_deflate, ncvar_gridmap, & - ncvar_mf6attr, export_varname - use NCModelExportModule, only: export_longname + ncvar_mf6attr + use NCModelExportModule, only: export_longname, export_varname use DisvModule, only: DisvType use NetCDFCommonModule, only: nf_verify use netcdf @@ -36,9 +36,7 @@ module MeshDisvModelModule procedure :: df procedure :: step procedure :: export_input_array - procedure :: package_step_ilayer procedure :: package_step - procedure :: export_layer_2d procedure :: define_dim procedure :: add_mesh_data end type Mesh2dDisvExportType @@ -64,6 +62,7 @@ subroutine disv_export_init(this, modelname, modeltype, modelfname, nc_fname, & ! allocate var_id arrays allocate (this%var_ids%dependent(this%nlay)) + allocate (this%var_ids%export(this%nlay)) ! initialize base class call this%mesh_init(modelname, modeltype, modelfname, nc_fname, disenum, & @@ -96,6 +95,8 @@ subroutine df(this) ! define the dependent variable call this%define_dependent() end if + ! define period input arrays + call this%df_export() ! exit define mode call nf_verify(nf90_enddef(this%ncid), this%nc_fname) ! create mesh @@ -113,9 +114,10 @@ end subroutine df subroutine step(this) use ConstantsModule, only: DHNOFLO use TdisModule, only: totim + use NetCDFCommonModule, only: ixstp class(Mesh2dDisvExportType), intent(inout) :: this real(DP), dimension(:), pointer, contiguous :: dbl1d - integer(I4B) :: n, k, nvals + integer(I4B) :: n, k, nvals, istp integer(I4B), dimension(2) :: dis_shape real(DP), dimension(:, :), pointer, contiguous :: dbl2d @@ -123,8 +125,8 @@ subroutine step(this) nullify (dbl1d) nullify (dbl2d) - ! increment step - this%stepcnt = this%stepcnt + 1 + ! set global step index + istp = ixstp() dis_shape(1) = this%disv%ncpl dis_shape(2) = this%disv%nlay @@ -156,14 +158,14 @@ subroutine step(this) ! extend array with step data call nf_verify(nf90_put_var(this%ncid, & this%var_ids%dependent(k), dbl2d(:, k), & - start=(/1, this%stepcnt/), & + start=(/1, istp/), & count=(/this%disv%ncpl, 1/)), & this%nc_fname) end do ! write to time coordinate variable call nf_verify(nf90_put_var(this%ncid, this%var_ids%time, & - totim, start=(/this%stepcnt/)), & + totim, start=(/istp/)), & this%nc_fname) ! update file @@ -175,39 +177,25 @@ subroutine step(this) nullify (dbl2d) end subroutine step - !> @brief netcdf export package dynamic input with ilayer index variable + !> @brief netcdf export package dynamic input !< - subroutine package_step_ilayer(this, export_pkg, ilayer_varname, ilayer) - use ConstantsModule, only: DNODATA, DZERO + subroutine package_step(this, export_pkg) use TdisModule, only: kper use DefinitionSelectModule, only: get_param_definition_type use NCModelExportModule, only: ExportPackageType class(Mesh2dDisvExportType), intent(inout) :: this class(ExportPackageType), pointer, intent(in) :: export_pkg - character(len=*), intent(in) :: ilayer_varname - integer(I4B), intent(in) :: ilayer type(InputParamDefinitionType), pointer :: idt integer(I4B), dimension(:), pointer, contiguous :: int1d - real(DP), dimension(:), pointer, contiguous :: dbl1d + real(DP), dimension(:), pointer, contiguous :: dbl1d, nodes real(DP), dimension(:, :), pointer, contiguous :: dbl2d - integer(I4B), dimension(:), pointer, contiguous :: ialayer - real(DP), dimension(:), contiguous, pointer :: dbl1d_ptr - character(len=LINELENGTH) :: nc_varname, input_attr - integer(I4B) :: n, iparam, nvals - logical(LGP) :: ilayer_read + character(len=LINELENGTH) :: nc_tag + integer(I4B) :: iaux, iparam, nvals + integer(I4B) :: k, n + integer(I4B), pointer :: nbound ! initialize - nullify (ialayer) - ilayer_read = .false. - - ! set pointer to ilayer variable - call mem_setptr(ialayer, export_pkg%param_names(ilayer), & - export_pkg%mf6_input%mempath) - - ! check if layer index variable was read - if (export_pkg%param_reads(ilayer)%invar == 1) then - ilayer_read = .true. - end if + iaux = 0 ! export defined period input do iparam = 1, export_pkg%nparam @@ -221,114 +209,100 @@ subroutine package_step_ilayer(this, export_pkg, ilayer_varname, ilayer) export_pkg%mf6_input%subcomponent_type, & 'PERIOD', export_pkg%param_names(iparam), '') - ! set variable name and input string - nc_varname = trim(export_pkg%mf6_input%subcomponent_name)//'_'// & - trim(idt%mf6varname) - input_attr = this%input_attribute(export_pkg%mf6_input%subcomponent_name, & - idt) + ! set variable input tag + nc_tag = this%input_attribute(export_pkg%mf6_input%subcomponent_name, & + idt) ! export arrays select case (idt%datatype) case ('INTEGER1D') call mem_setptr(int1d, idt%mf6varname, export_pkg%mf6_input%mempath) - call nc_export_int1d(this%ncid, this%dim_ids, this%var_ids, this%disv, & - int1d, nc_varname, & - export_pkg%mf6_input%subcomponent_name, & - idt%tagname, this%gridmap_name, idt%shape, & - idt%longname, input_attr, this%deflate, & - this%shuffle, this%chunk_face, kper, this%nc_fname) + this%var_ids%export(1) = export_pkg%varids_param(iparam, 1) + call nc_export_int1d(int1d, this%ncid, this%dim_ids, this%var_ids, & + this%disv, idt, export_pkg%mf6_input%mempath, & + nc_tag, export_pkg%mf6_input%subcomponent_name, & + this%gridmap_name, this%deflate, this%shuffle, & + this%chunk_face, kper, this%nc_fname) case ('DOUBLE1D') call mem_setptr(dbl1d, idt%mf6varname, export_pkg%mf6_input%mempath) - call this%export_layer_2d(export_pkg, idt, ilayer_read, ialayer, & - dbl1d, nc_varname, input_attr) + select case (idt%shape) + case ('NCPL') + this%var_ids%export(1) = export_pkg%varids_param(iparam, 1) + call nc_export_dbl1d(dbl1d, this%ncid, this%dim_ids, this%var_ids, & + this%disv, idt, export_pkg%mf6_input%mempath, & + nc_tag, export_pkg%mf6_input%subcomponent_name, & + this%gridmap_name, this%deflate, this%shuffle, & + this%chunk_face, kper, iaux, this%nc_fname) + case ('NODES') + nvals = this%disv%nodesuser + allocate (nodes(nvals)) + nodes = DNODATA + do k = 1, this%disv%nlay + this%var_ids%export(k) = export_pkg%varids_param(iparam, k) + end do + call mem_setptr(dbl1d, idt%mf6varname, export_pkg%mf6_input%mempath) + call mem_setptr(int1d, 'NODEULIST', export_pkg%mf6_input%mempath) + call mem_setptr(nbound, 'NBOUND', export_pkg%mf6_input%mempath) + do n = 1, nbound + nodes(int1d(n)) = dbl1d(n) + end do + call nc_export_dbl1d(nodes, this%ncid, this%dim_ids, this%var_ids, & + this%disv, idt, export_pkg%mf6_input%mempath, & + nc_tag, export_pkg%mf6_input%subcomponent_name, & + this%gridmap_name, this%deflate, this%shuffle, & + this%chunk_face, kper, iaux, this%nc_fname) + deallocate (nodes) + case default + end select case ('DOUBLE2D') call mem_setptr(dbl2d, idt%mf6varname, export_pkg%mf6_input%mempath) - nvals = this%disv%ncpl - do n = 1, size(dbl2d, dim=1) !naux - dbl1d_ptr(1:nvals) => dbl2d(n, :) - if (all(dbl1d_ptr == DZERO)) then - else - call this%export_layer_2d(export_pkg, idt, ilayer_read, ialayer, & - dbl1d_ptr, nc_varname, input_attr, n) - end if - end do + select case (idt%shape) + case ('NAUX NCPL') + nvals = this%disv%ncpl + allocate (nodes(nvals)) + do iaux = 1, size(dbl2d, dim=1) !naux + this%var_ids%export(1) = export_pkg%varids_aux(iaux, 1) + do n = 1, nvals + nodes(n) = dbl2d(iaux, n) + end do + call nc_export_dbl1d(dbl1d, this%ncid, this%dim_ids, this%var_ids, & + this%disv, idt, export_pkg%mf6_input%mempath, & + nc_tag, export_pkg%mf6_input%subcomponent_name, & + this%gridmap_name, this%deflate, this%shuffle, & + this%chunk_face, kper, iaux, this%nc_fname) + end do + deallocate (nodes) + case ('NAUX NODES') + nvals = this%disv%nodesuser + allocate (nodes(nvals)) + call mem_setptr(int1d, 'NODEULIST', export_pkg%mf6_input%mempath) + call mem_setptr(nbound, 'NBOUND', export_pkg%mf6_input%mempath) + do iaux = 1, size(dbl2d, dim=1) ! naux + nodes = DNODATA + do k = 1, this%disv%nlay + this%var_ids%export(k) = export_pkg%varids_aux(iaux, k) + end do + do n = 1, nbound + nodes(int1d(n)) = dbl2d(iaux, n) + end do + call nc_export_dbl1d(nodes, this%ncid, this%dim_ids, this%var_ids, & + this%disv, idt, export_pkg%mf6_input%mempath, & + nc_tag, export_pkg%mf6_input%subcomponent_name, & + this%gridmap_name, this%deflate, this%shuffle, & + this%chunk_face, kper, iaux, this%nc_fname) + end do + deallocate (nodes) + case default + end select case default - errmsg = 'EXPORT ilayer unsupported datatype='//trim(idt%datatype) - call store_error(errmsg, .true.) + ! no-op, no other datatypes exported end select end do - ! synchronize file - call nf_verify(nf90_sync(this%ncid), this%nc_fname) - end subroutine package_step_ilayer - - !> @brief netcdf export package dynamic input - !< - subroutine package_step(this, export_pkg) - use NCModelExportModule, only: ExportPackageType - class(Mesh2dDisvExportType), intent(inout) :: this - class(ExportPackageType), pointer, intent(in) :: export_pkg - errmsg = 'NetCDF period export not supported for model='// & - trim(this%modelname)//', package='// & - trim(export_pkg%mf6_input%subcomponent_name) - call store_error(errmsg, .true.) ! synchronize file call nf_verify(nf90_sync(this%ncid), this%nc_fname) end subroutine package_step - !> @brief export layer variable as full grid - !< - subroutine export_layer_2d(this, export_pkg, idt, ilayer_read, ialayer, & - dbl1d, nc_varname, input_attr, iaux) - use ConstantsModule, only: DNODATA, DZERO - use NCModelExportModule, only: ExportPackageType - class(Mesh2dDisvExportType), intent(inout) :: this - class(ExportPackageType), pointer, intent(in) :: export_pkg - type(InputParamDefinitionType), pointer, intent(in) :: idt - logical(LGP), intent(in) :: ilayer_read - integer(I4B), dimension(:), pointer, contiguous, intent(in) :: ialayer - real(DP), dimension(:), pointer, contiguous, intent(in) :: dbl1d - character(len=*), intent(in) :: nc_varname - character(len=*), intent(in) :: input_attr - integer(I4B), optional, intent(in) :: iaux - real(DP), dimension(:, :), pointer, contiguous :: dbl2d - integer(I4B) :: n, j, k, idxaux - - ! initialize - idxaux = 0 - if (present(iaux)) then - idxaux = iaux - end if - - allocate (dbl2d(export_pkg%mshape(2), export_pkg%mshape(1))) - - if (ilayer_read) then - do k = 1, size(dbl2d, dim=2) - n = 0 - do j = 1, size(dbl2d, dim=1) - n = n + 1 - if (ialayer(n) == k) then - dbl2d(j, k) = dbl1d(n) - else - dbl2d(j, k) = DNODATA - end if - end do - end do - else - dbl2d = DNODATA - dbl2d(:, 1) = dbl1d(:) - end if - - call nc_export_dbl2d(this%ncid, this%dim_ids, this%var_ids, this%disv, & - dbl2d, nc_varname, & - export_pkg%mf6_input%subcomponent_name, idt%tagname, & - this%gridmap_name, idt%shape, idt%longname, input_attr, & - this%deflate, this%shuffle, this%chunk_face, & - export_pkg%iper, idxaux, this%nc_fname) - - deallocate (dbl2d) - end subroutine export_layer_2d - !> @brief netcdf export an input array !< subroutine export_input_array(this, pkgtype, pkgname, mempath, idt) @@ -341,46 +315,40 @@ subroutine export_input_array(this, pkgtype, pkgname, mempath, idt) integer(I4B), dimension(:, :), pointer, contiguous :: int2d real(DP), dimension(:), pointer, contiguous :: dbl1d real(DP), dimension(:, :), pointer, contiguous :: dbl2d - character(len=LINELENGTH) :: nc_varname, input_attr + character(len=LINELENGTH) :: nc_tag integer(I4B) :: iper, iaux iper = 0 iaux = 0 - ! set package base name - nc_varname = trim(pkgname)//'_'//trim(idt%mf6varname) - ! put input attributes - input_attr = this%input_attribute(pkgname, idt) + ! set variable input tag + nc_tag = this%input_attribute(pkgname, idt) select case (idt%datatype) case ('INTEGER1D') call mem_setptr(int1d, idt%mf6varname, mempath) - call nc_export_int1d(this%ncid, this%dim_ids, this%var_ids, this%disv, & - int1d, nc_varname, pkgname, idt%tagname, & - this%gridmap_name, idt%shape, idt%longname, & - input_attr, this%deflate, this%shuffle, & + call nc_export_int1d(int1d, this%ncid, this%dim_ids, this%var_ids, & + this%disv, idt, mempath, nc_tag, pkgname, & + this%gridmap_name, this%deflate, this%shuffle, & this%chunk_face, iper, this%nc_fname) case ('INTEGER2D') call mem_setptr(int2d, idt%mf6varname, mempath) - call nc_export_int2d(this%ncid, this%dim_ids, this%var_ids, this%disv, & - int2d, nc_varname, pkgname, idt%tagname, & - this%gridmap_name, idt%shape, idt%longname, & - input_attr, this%deflate, this%shuffle, & + call nc_export_int2d(int2d, this%ncid, this%dim_ids, this%var_ids, & + this%disv, idt, mempath, nc_tag, pkgname, & + this%gridmap_name, this%deflate, this%shuffle, & this%chunk_face, this%nc_fname) case ('DOUBLE1D') call mem_setptr(dbl1d, idt%mf6varname, mempath) - call nc_export_dbl1d(this%ncid, this%dim_ids, this%var_ids, this%disv, & - dbl1d, nc_varname, pkgname, idt%tagname, & - this%gridmap_name, idt%shape, idt%longname, & - input_attr, this%deflate, this%shuffle, & - this%chunk_face, this%nc_fname) + call nc_export_dbl1d(dbl1d, this%ncid, this%dim_ids, this%var_ids, & + this%disv, idt, mempath, nc_tag, pkgname, & + this%gridmap_name, this%deflate, this%shuffle, & + this%chunk_face, iper, iaux, this%nc_fname) case ('DOUBLE2D') call mem_setptr(dbl2d, idt%mf6varname, mempath) - call nc_export_dbl2d(this%ncid, this%dim_ids, this%var_ids, this%disv, & - dbl2d, nc_varname, pkgname, idt%tagname, & - this%gridmap_name, idt%shape, idt%longname, & - input_attr, this%deflate, this%shuffle, & - this%chunk_face, iper, iaux, this%nc_fname) + call nc_export_dbl2d(dbl2d, this%ncid, this%dim_ids, this%var_ids, & + this%disv, idt, mempath, nc_tag, pkgname, & + this%gridmap_name, this%deflate, this%shuffle, & + this%chunk_face, this%nc_fname) case default ! no-op, no other datatypes exported end select @@ -389,8 +357,6 @@ end subroutine export_input_array !> @brief netcdf export define dimensions !< subroutine define_dim(this) - use ConstantsModule, only: MVALIDATE - use SimVariablesModule, only: isim_mode class(Mesh2dDisvExportType), intent(inout) :: this integer(I4B), dimension(:), contiguous, pointer :: ncvert @@ -398,23 +364,21 @@ subroutine define_dim(this) call mem_setptr(ncvert, 'NCVERT', this%dis_mempath) ! time - if (isim_mode /= MVALIDATE) then - call nf_verify(nf90_def_dim(this%ncid, 'time', this%totnstp, & - this%dim_ids%time), this%nc_fname) - call nf_verify(nf90_def_var(this%ncid, 'time', NF90_DOUBLE, & - this%dim_ids%time, this%var_ids%time), & - this%nc_fname) - call nf_verify(nf90_put_att(this%ncid, this%var_ids%time, 'calendar', & - 'standard'), this%nc_fname) - call nf_verify(nf90_put_att(this%ncid, this%var_ids%time, 'units', & - this%datetime), this%nc_fname) - call nf_verify(nf90_put_att(this%ncid, this%var_ids%time, 'axis', 'T'), & - this%nc_fname) - call nf_verify(nf90_put_att(this%ncid, this%var_ids%time, 'standard_name', & - 'time'), this%nc_fname) - call nf_verify(nf90_put_att(this%ncid, this%var_ids%time, 'long_name', & - 'time'), this%nc_fname) - end if + call nf_verify(nf90_def_dim(this%ncid, 'time', this%totnstp, & + this%dim_ids%time), this%nc_fname) + call nf_verify(nf90_def_var(this%ncid, 'time', NF90_DOUBLE, & + this%dim_ids%time, this%var_ids%time), & + this%nc_fname) + call nf_verify(nf90_put_att(this%ncid, this%var_ids%time, 'calendar', & + 'standard'), this%nc_fname) + call nf_verify(nf90_put_att(this%ncid, this%var_ids%time, 'units', & + this%datetime), this%nc_fname) + call nf_verify(nf90_put_att(this%ncid, this%var_ids%time, 'axis', 'T'), & + this%nc_fname) + call nf_verify(nf90_put_att(this%ncid, this%var_ids%time, 'standard_name', & + 'time'), this%nc_fname) + call nf_verify(nf90_put_att(this%ncid, this%var_ids%time, 'long_name', & + 'time'), this%nc_fname) ! mesh call nf_verify(nf90_def_dim(this%ncid, 'nmesh_node', this%disv%nvert, & @@ -570,137 +534,154 @@ end subroutine add_mesh_data !> @brief netcdf export 1D integer array !< - subroutine nc_export_int1d(ncid, dim_ids, var_ids, dis, p_mem, nc_varname, & - pkgname, tagname, gridmap_name, shapestr, longname, & - nc_tag, deflate, shuffle, chunk_face, iper, nc_fname) + subroutine nc_export_int1d(p_mem, ncid, dim_ids, var_ids, disv, idt, mempath, & + nc_tag, pkgname, gridmap_name, deflate, shuffle, & + chunk_face, iper, nc_fname) + use NetCDFCommonModule, only: ixstp + integer(I4B), dimension(:), pointer, contiguous, intent(in) :: p_mem integer(I4B), intent(in) :: ncid type(MeshNCDimIdType), intent(inout) :: dim_ids type(MeshNCVarIdType), intent(inout) :: var_ids - type(DisvType), pointer, intent(in) :: dis - integer(I4B), dimension(:), pointer, contiguous, intent(in) :: p_mem - character(len=*), intent(in) :: nc_varname + type(DisvType), pointer, intent(in) :: disv + type(InputParamDefinitionType), pointer :: idt + character(len=*), intent(in) :: mempath + character(len=*), intent(in) :: nc_tag character(len=*), intent(in) :: pkgname - character(len=*), intent(in) :: tagname character(len=*), intent(in) :: gridmap_name - character(len=*), intent(in) :: shapestr - character(len=*), intent(in) :: longname - character(len=*), intent(in) :: nc_tag integer(I4B), intent(in) :: deflate integer(I4B), intent(in) :: shuffle integer(I4B), intent(in) :: chunk_face integer(I4B), intent(in) :: iper character(len=*), intent(in) :: nc_fname - integer(I4B), dimension(2) :: dis_shape + integer(I4B), dimension(:), pointer, contiguous :: int1d integer(I4B), dimension(:, :), pointer, contiguous :: int2d - integer(I4B) :: axis_sz, nvals, k + integer(I4B) :: axis_sz, k, istp integer(I4B), dimension(:), allocatable :: var_id - character(len=LINELENGTH) :: longname_l, varname_l - - if (shapestr == 'NCPL') then - ! set names - varname_l = export_varname(nc_varname) - longname_l = export_longname(longname, pkgname, tagname, layer=0, iper=iper) + character(len=LINELENGTH) :: longname, varname - allocate (var_id(1)) - axis_sz = dim_ids%nmesh_face - - ! reenter define mode and create variable - call nf_verify(nf90_redef(ncid), nc_fname) - call nf_verify(nf90_def_var(ncid, varname_l, NF90_INT, & - (/axis_sz/), var_id(1)), & - nc_fname) - - ! apply chunking parameters - call ncvar_chunk(ncid, var_id(1), chunk_face, nc_fname) - ! deflate and shuffle - call ncvar_deflate(ncid, var_id(1), deflate, shuffle, nc_fname) - - ! put attr - call nf_verify(nf90_put_att(ncid, var_id(1), '_FillValue', & - (/NF90_FILL_INT/)), nc_fname) - call nf_verify(nf90_put_att(ncid, var_id(1), 'long_name', & - longname_l), nc_fname) - - ! add grid mapping and mf6 attr - call ncvar_gridmap(ncid, var_id(1), gridmap_name, nc_fname) - call ncvar_mf6attr(ncid, var_id(1), 0, iper, 0, nc_tag, nc_fname) - - ! exit define mode and write data - call nf_verify(nf90_enddef(ncid), nc_fname) - call nf_verify(nf90_put_var(ncid, var_id(1), p_mem), & - nc_fname) + if (idt%shape == 'NCPL' .or. & + idt%shape == 'NAUX NCPL') then - else - allocate (var_id(dis%nlay)) - - ! reenter define mode and create variable - call nf_verify(nf90_redef(ncid), nc_fname) - do k = 1, dis%nlay + if (iper == 0) then ! set names - varname_l = export_varname(nc_varname, layer=k, iper=iper) - longname_l = export_longname(longname, pkgname, tagname, layer=k, & - iper=iper) + varname = export_varname(pkgname, idt%tagname, mempath) + longname = export_longname(idt%longname, pkgname, idt%tagname, mempath) + + allocate (var_id(1)) + axis_sz = dim_ids%nmesh_face - call nf_verify(nf90_def_var(ncid, varname_l, NF90_INT, & - (/dim_ids%nmesh_face/), var_id(k)), & + ! reenter define mode and create variable + call nf_verify(nf90_redef(ncid), nc_fname) + call nf_verify(nf90_def_var(ncid, varname, NF90_INT, & + (/axis_sz/), var_id(1)), & nc_fname) ! apply chunking parameters - call ncvar_chunk(ncid, var_id(k), chunk_face, nc_fname) - ! defalte and shuffle - call ncvar_deflate(ncid, var_id(k), deflate, shuffle, nc_fname) + call ncvar_chunk(ncid, var_id(1), chunk_face, nc_fname) + ! deflate and shuffle + call ncvar_deflate(ncid, var_id(1), deflate, shuffle, nc_fname) ! put attr - call nf_verify(nf90_put_att(ncid, var_id(k), '_FillValue', & + call nf_verify(nf90_put_att(ncid, var_id(1), '_FillValue', & (/NF90_FILL_INT/)), nc_fname) - call nf_verify(nf90_put_att(ncid, var_id(k), 'long_name', & - longname_l), nc_fname) + call nf_verify(nf90_put_att(ncid, var_id(1), 'long_name', & + longname), nc_fname) ! add grid mapping and mf6 attr - call ncvar_gridmap(ncid, var_id(k), gridmap_name, nc_fname) - call ncvar_mf6attr(ncid, var_id(k), k, iper, 0, nc_tag, nc_fname) - end do + call ncvar_gridmap(ncid, var_id(1), gridmap_name, nc_fname) + call ncvar_mf6attr(ncid, var_id(1), 0, 0, nc_tag, nc_fname) - ! reshape input - dis_shape(1) = dis%ncpl - dis_shape(2) = dis%nlay - nvals = product(dis_shape) - int2d(1:dis_shape(1), 1:dis_shape(2)) => p_mem(1:nvals) + ! exit define mode and write data + call nf_verify(nf90_enddef(ncid), nc_fname) + call nf_verify(nf90_put_var(ncid, var_id(1), p_mem), & + nc_fname) + else + ! timeseries + istp = ixstp() + call nf_verify(nf90_put_var(ncid, & + var_ids%export(1), p_mem, & + start=(/1, istp/), & + count=(/disv%ncpl, 1/)), nc_fname) + end if - ! exit define mode and write data - call nf_verify(nf90_enddef(ncid), nc_fname) - do k = 1, dis%nlay - call nf_verify(nf90_put_var(ncid, var_id(k), int2d(:, k)), nc_fname) - end do + else - ! cleanup - deallocate (var_id) + int2d(1:disv%ncpl, 1:disv%nlay) => p_mem(1:disv%nodesuser) + + if (iper == 0) then + allocate (var_id(disv%nlay)) + + ! reenter define mode and create variable + call nf_verify(nf90_redef(ncid), nc_fname) + do k = 1, disv%nlay + ! set names + varname = export_varname(pkgname, idt%tagname, mempath, layer=k) + longname = export_longname(idt%longname, pkgname, idt%tagname, & + mempath, layer=k) + + call nf_verify(nf90_def_var(ncid, varname, NF90_INT, & + (/dim_ids%nmesh_face/), var_id(k)), & + nc_fname) + + ! apply chunking parameters + call ncvar_chunk(ncid, var_id(k), chunk_face, nc_fname) + ! deflate and shuffle + call ncvar_deflate(ncid, var_id(k), deflate, shuffle, nc_fname) + + ! put attr + call nf_verify(nf90_put_att(ncid, var_id(k), '_FillValue', & + (/NF90_FILL_INT/)), nc_fname) + call nf_verify(nf90_put_att(ncid, var_id(k), 'long_name', & + longname), nc_fname) + + ! add grid mapping and mf6 attr + call ncvar_gridmap(ncid, var_id(k), gridmap_name, nc_fname) + call ncvar_mf6attr(ncid, var_id(k), k, 0, nc_tag, nc_fname) + end do + + ! exit define mode and write data + call nf_verify(nf90_enddef(ncid), nc_fname) + do k = 1, disv%nlay + call nf_verify(nf90_put_var(ncid, var_id(k), int2d(:, k)), nc_fname) + end do + + ! cleanup + deallocate (var_id) + else + ! timeseries, add period data + istp = ixstp() + do k = 1, disv%nlay + int1d(1:disv%ncpl) => int2d(:, k) + call nf_verify(nf90_put_var(ncid, & + var_ids%export(k), int1d, & + start=(/1, istp/), & + count=(/disv%ncpl, 1/)), nc_fname) + end do + end if end if end subroutine nc_export_int1d !> @brief netcdf export 2D integer array !< - subroutine nc_export_int2d(ncid, dim_ids, var_ids, disv, p_mem, nc_varname, & - pkgname, tagname, gridmap_name, shapestr, longname, & - nc_tag, deflate, shuffle, chunk_face, nc_fname) + subroutine nc_export_int2d(p_mem, ncid, dim_ids, var_ids, disv, idt, mempath, & + nc_tag, pkgname, gridmap_name, deflate, shuffle, & + chunk_face, nc_fname) + integer(I4B), dimension(:, :), pointer, contiguous, intent(in) :: p_mem integer(I4B), intent(in) :: ncid type(MeshNCDimIdType), intent(inout) :: dim_ids type(MeshNCVarIdType), intent(inout) :: var_ids type(DisvType), pointer, intent(in) :: disv - integer(I4B), dimension(:, :), pointer, contiguous, intent(in) :: p_mem - character(len=*), intent(in) :: nc_varname + type(InputParamDefinitionType), pointer :: idt + character(len=*), intent(in) :: mempath + character(len=*), intent(in) :: nc_tag character(len=*), intent(in) :: pkgname - character(len=*), intent(in) :: tagname character(len=*), intent(in) :: gridmap_name - character(len=*), intent(in) :: shapestr - character(len=*), intent(in) :: longname - character(len=*), intent(in) :: nc_tag integer(I4B), intent(in) :: deflate integer(I4B), intent(in) :: shuffle integer(I4B), intent(in) :: chunk_face character(len=*), intent(in) :: nc_fname integer(I4B), dimension(:), allocatable :: var_id - character(len=LINELENGTH) :: longname_l, varname_l + character(len=LINELENGTH) :: longname, varname integer(I4B) :: k allocate (var_id(disv%nlay)) @@ -709,10 +690,11 @@ subroutine nc_export_int2d(ncid, dim_ids, var_ids, disv, p_mem, nc_varname, & call nf_verify(nf90_redef(ncid), nc_fname) do k = 1, disv%nlay ! set names - varname_l = export_varname(nc_varname, layer=k) - longname_l = export_longname(longname, pkgname, tagname, k) + varname = export_varname(pkgname, idt%tagname, mempath, layer=k) + longname = export_longname(idt%longname, pkgname, idt%tagname, & + mempath, layer=k) - call nf_verify(nf90_def_var(ncid, varname_l, NF90_INT, & + call nf_verify(nf90_def_var(ncid, varname, NF90_INT, & (/dim_ids%nmesh_face/), var_id(k)), & nc_fname) @@ -725,11 +707,11 @@ subroutine nc_export_int2d(ncid, dim_ids, var_ids, disv, p_mem, nc_varname, & call nf_verify(nf90_put_att(ncid, var_id(k), '_FillValue', & (/NF90_FILL_INT/)), nc_fname) call nf_verify(nf90_put_att(ncid, var_id(k), 'long_name', & - longname_l), nc_fname) + longname), nc_fname) ! add grid mapping and mf6 attr call ncvar_gridmap(ncid, var_id(k), gridmap_name, nc_fname) - call ncvar_mf6attr(ncid, var_id(k), k, 0, 0, nc_tag, nc_fname) + call ncvar_mf6attr(ncid, var_id(k), k, 0, nc_tag, nc_fname) end do ! exit define mode and write data @@ -743,147 +725,159 @@ end subroutine nc_export_int2d !> @brief netcdf export 1D double array !< - subroutine nc_export_dbl1d(ncid, dim_ids, var_ids, dis, p_mem, nc_varname, & - pkgname, tagname, gridmap_name, shapestr, longname, & - nc_tag, deflate, shuffle, chunk_face, nc_fname) + subroutine nc_export_dbl1d(p_mem, ncid, dim_ids, var_ids, disv, idt, mempath, & + nc_tag, pkgname, gridmap_name, deflate, shuffle, & + chunk_face, iper, iaux, nc_fname) + use NetCDFCommonModule, only: ixstp + real(DP), dimension(:), pointer, contiguous, intent(in) :: p_mem integer(I4B), intent(in) :: ncid type(MeshNCDimIdType), intent(inout) :: dim_ids type(MeshNCVarIdType), intent(inout) :: var_ids - type(DisvType), pointer, intent(in) :: dis - real(DP), dimension(:), pointer, contiguous, intent(in) :: p_mem - character(len=*), intent(in) :: nc_varname + type(DisvType), pointer, intent(in) :: disv + type(InputParamDefinitionType), pointer :: idt + character(len=*), intent(in) :: mempath + character(len=*), intent(in) :: nc_tag character(len=*), intent(in) :: pkgname - character(len=*), intent(in) :: tagname character(len=*), intent(in) :: gridmap_name - character(len=*), intent(in) :: shapestr - character(len=*), intent(in) :: longname - character(len=*), intent(in) :: nc_tag integer(I4B), intent(in) :: deflate integer(I4B), intent(in) :: shuffle integer(I4B), intent(in) :: chunk_face + integer(I4B), intent(in) :: iper + integer(I4B), intent(in) :: iaux character(len=*), intent(in) :: nc_fname - integer(I4B), dimension(2) :: dis_shape + real(DP), dimension(:), pointer, contiguous :: dbl1d real(DP), dimension(:, :), pointer, contiguous :: dbl2d - integer(I4B) :: axis_sz, nvals, k + integer(I4B) :: axis_sz, k, istp integer(I4B), dimension(:), allocatable :: var_id - character(len=LINELENGTH) :: longname_l, varname_l - - if (shapestr == 'NCPL') then - ! set names - varname_l = export_varname(nc_varname) - longname_l = export_longname(longname, pkgname, tagname, 0) - - allocate (var_id(1)) - axis_sz = dim_ids%nmesh_face - - ! reenter define mode and create variable - call nf_verify(nf90_redef(ncid), nc_fname) - call nf_verify(nf90_def_var(ncid, varname_l, NF90_DOUBLE, & - (/axis_sz/), var_id(1)), & - nc_fname) + character(len=LINELENGTH) :: longname, varname - ! apply chunking parameters - call ncvar_chunk(ncid, var_id(1), chunk_face, nc_fname) - ! deflate and shuffle - call ncvar_deflate(ncid, var_id(1), deflate, shuffle, nc_fname) + if (idt%shape == 'NCPL' .or. & + idt%shape == 'NAUX NCPL') then - ! put attr - call nf_verify(nf90_put_att(ncid, var_id(1), '_FillValue', & - (/NF90_FILL_DOUBLE/)), nc_fname) - call nf_verify(nf90_put_att(ncid, var_id(1), 'long_name', & - longname_l), nc_fname) - - ! add grid mapping and mf6 attr - call ncvar_gridmap(ncid, var_id(1), gridmap_name, nc_fname) - call ncvar_mf6attr(ncid, var_id(1), 0, 0, 0, nc_tag, nc_fname) - - ! exit define mode and write data - call nf_verify(nf90_enddef(ncid), nc_fname) - call nf_verify(nf90_put_var(ncid, var_id(1), p_mem), & - nc_fname) - - else - allocate (var_id(dis%nlay)) - - ! reenter define mode and create variable - call nf_verify(nf90_redef(ncid), nc_fname) - do k = 1, dis%nlay + if (iper == 0) then ! set names - varname_l = export_varname(nc_varname, layer=k) - longname_l = export_longname(longname, pkgname, tagname, k) - - call nf_verify(nf90_def_var(ncid, varname_l, NF90_DOUBLE, & - (/dim_ids%nmesh_face/), var_id(k)), & + varname = export_varname(pkgname, idt%tagname, mempath, & + iaux=iaux) + longname = export_longname(idt%longname, pkgname, idt%tagname, & + mempath, iaux=iaux) + + allocate (var_id(1)) + axis_sz = dim_ids%nmesh_face + + ! reenter define mode and create variable + call nf_verify(nf90_redef(ncid), nc_fname) + call nf_verify(nf90_def_var(ncid, varname, NF90_DOUBLE, & + (/axis_sz/), var_id(1)), & nc_fname) ! apply chunking parameters - call ncvar_chunk(ncid, var_id(k), chunk_face, nc_fname) + call ncvar_chunk(ncid, var_id(1), chunk_face, nc_fname) ! deflate and shuffle - call ncvar_deflate(ncid, var_id(k), deflate, shuffle, nc_fname) + call ncvar_deflate(ncid, var_id(1), deflate, shuffle, nc_fname) ! put attr - call nf_verify(nf90_put_att(ncid, var_id(k), '_FillValue', & + call nf_verify(nf90_put_att(ncid, var_id(1), '_FillValue', & (/NF90_FILL_DOUBLE/)), nc_fname) - call nf_verify(nf90_put_att(ncid, var_id(k), 'long_name', & - longname_l), nc_fname) + call nf_verify(nf90_put_att(ncid, var_id(1), 'long_name', & + longname), nc_fname) ! add grid mapping and mf6 attr - call ncvar_gridmap(ncid, var_id(k), gridmap_name, nc_fname) - call ncvar_mf6attr(ncid, var_id(k), k, 0, 0, nc_tag, nc_fname) - end do + call ncvar_gridmap(ncid, var_id(1), gridmap_name, nc_fname) + call ncvar_mf6attr(ncid, var_id(1), 0, iaux, nc_tag, nc_fname) - ! reshape input - dis_shape(1) = dis%ncpl - dis_shape(2) = dis%nlay - nvals = product(dis_shape) - dbl2d(1:dis_shape(1), 1:dis_shape(2)) => p_mem(1:nvals) + ! exit define mode and write data + call nf_verify(nf90_enddef(ncid), nc_fname) + call nf_verify(nf90_put_var(ncid, var_id(1), p_mem), & + nc_fname) + else + ! timeseries + istp = ixstp() + call nf_verify(nf90_put_var(ncid, & + var_ids%export(1), p_mem, & + start=(/1, istp/), & + count=(/disv%ncpl, 1/)), nc_fname) + end if - ! exit define mode and write data - call nf_verify(nf90_enddef(ncid), nc_fname) - do k = 1, dis%nlay - call nf_verify(nf90_put_var(ncid, var_id(k), dbl2d(:, k)), nc_fname) - end do + else - ! cleanup - deallocate (var_id) + dbl2d(1:disv%ncpl, 1:disv%nlay) => p_mem(1:disv%nodesuser) + + if (iper == 0) then + allocate (var_id(disv%nlay)) + + ! reenter define mode and create variable + call nf_verify(nf90_redef(ncid), nc_fname) + do k = 1, disv%nlay + ! set names + varname = export_varname(pkgname, idt%tagname, mempath, layer=k, & + iaux=iaux) + longname = export_longname(idt%longname, pkgname, idt%tagname, & + mempath, layer=k, iaux=iaux) + + call nf_verify(nf90_def_var(ncid, varname, NF90_DOUBLE, & + (/dim_ids%nmesh_face/), var_id(k)), & + nc_fname) + + ! apply chunking parameters + call ncvar_chunk(ncid, var_id(k), chunk_face, nc_fname) + ! deflate and shuffle + call ncvar_deflate(ncid, var_id(k), deflate, shuffle, nc_fname) + + ! put attr + call nf_verify(nf90_put_att(ncid, var_id(k), '_FillValue', & + (/NF90_FILL_DOUBLE/)), nc_fname) + call nf_verify(nf90_put_att(ncid, var_id(k), 'long_name', & + longname), nc_fname) + + ! add grid mapping and mf6 attr + call ncvar_gridmap(ncid, var_id(k), gridmap_name, nc_fname) + call ncvar_mf6attr(ncid, var_id(k), k, iaux, nc_tag, nc_fname) + end do + + ! exit define mode and write data + call nf_verify(nf90_enddef(ncid), nc_fname) + do k = 1, disv%nlay + call nf_verify(nf90_put_var(ncid, var_id(k), dbl2d(:, k)), nc_fname) + end do + + ! cleanup + deallocate (var_id) + else + ! timeseries, add period data + istp = ixstp() + do k = 1, disv%nlay + dbl1d(1:disv%ncpl) => dbl2d(:, k) + call nf_verify(nf90_put_var(ncid, & + var_ids%export(k), dbl1d, & + start=(/1, istp/), & + count=(/disv%ncpl, 1/)), nc_fname) + end do + end if end if end subroutine nc_export_dbl1d !> @brief netcdf export 2D double array !< - subroutine nc_export_dbl2d(ncid, dim_ids, var_ids, disv, p_mem, nc_varname, & - pkgname, tagname, gridmap_name, shapestr, longname, & - nc_tag, deflate, shuffle, chunk_face, iper, iaux, & - nc_fname) - use ConstantsModule, only: DNODATA + subroutine nc_export_dbl2d(p_mem, ncid, dim_ids, var_ids, disv, idt, mempath, & + nc_tag, pkgname, gridmap_name, deflate, shuffle, & + chunk_face, nc_fname) + real(DP), dimension(:, :), pointer, contiguous, intent(in) :: p_mem integer(I4B), intent(in) :: ncid type(MeshNCDimIdType), intent(inout) :: dim_ids type(MeshNCVarIdType), intent(inout) :: var_ids type(DisvType), pointer, intent(in) :: disv - real(DP), dimension(:, :), pointer, contiguous, intent(in) :: p_mem - character(len=*), intent(in) :: nc_varname + type(InputParamDefinitionType), pointer :: idt + character(len=*), intent(in) :: mempath + character(len=*), intent(in) :: nc_tag character(len=*), intent(in) :: pkgname - character(len=*), intent(in) :: tagname character(len=*), intent(in) :: gridmap_name - character(len=*), intent(in) :: shapestr - character(len=*), intent(in) :: longname - character(len=*), intent(in) :: nc_tag integer(I4B), intent(in) :: deflate integer(I4B), intent(in) :: shuffle integer(I4B), intent(in) :: chunk_face - integer(I4B), intent(in) :: iper - integer(I4B), intent(in) :: iaux character(len=*), intent(in) :: nc_fname integer(I4B), dimension(:), allocatable :: var_id - character(len=LINELENGTH) :: longname_l, varname_l + character(len=LINELENGTH) :: longname, varname integer(I4B) :: k - real(DP) :: fill_value - - if (iper > 0) then - fill_value = DNODATA - else - fill_value = NF90_FILL_DOUBLE - end if allocate (var_id(disv%nlay)) @@ -891,10 +885,11 @@ subroutine nc_export_dbl2d(ncid, dim_ids, var_ids, disv, p_mem, nc_varname, & call nf_verify(nf90_redef(ncid), nc_fname) do k = 1, disv%nlay ! set names - varname_l = export_varname(nc_varname, layer=k, iper=iper, iaux=iaux) - longname_l = export_longname(longname, pkgname, tagname, layer=k, iper=iper) + varname = export_varname(pkgname, idt%tagname, mempath, layer=k) + longname = export_longname(idt%longname, pkgname, idt%tagname, & + mempath, layer=k) - call nf_verify(nf90_def_var(ncid, varname_l, NF90_DOUBLE, & + call nf_verify(nf90_def_var(ncid, varname, NF90_DOUBLE, & (/dim_ids%nmesh_face/), var_id(k)), & nc_fname) @@ -905,13 +900,13 @@ subroutine nc_export_dbl2d(ncid, dim_ids, var_ids, disv, p_mem, nc_varname, & ! put attr call nf_verify(nf90_put_att(ncid, var_id(k), '_FillValue', & - (/fill_value/)), nc_fname) + (/NF90_FILL_DOUBLE/)), nc_fname) call nf_verify(nf90_put_att(ncid, var_id(k), 'long_name', & - longname_l), nc_fname) + longname), nc_fname) ! add grid mapping and mf6 attr call ncvar_gridmap(ncid, var_id(k), gridmap_name, nc_fname) - call ncvar_mf6attr(ncid, var_id(k), k, iper, iaux, nc_tag, nc_fname) + call ncvar_mf6attr(ncid, var_id(k), k, 0, nc_tag, nc_fname) end do ! exit define mode and write data diff --git a/src/Utilities/Export/MeshNCModel.f90 b/src/Utilities/Export/MeshNCModel.f90 index 3a7fb58e3e6..894344af186 100644 --- a/src/Utilities/Export/MeshNCModel.f90 +++ b/src/Utilities/Export/MeshNCModel.f90 @@ -14,7 +14,8 @@ module MeshModelModule use MemoryManagerModule, only: mem_setptr use InputDefinitionModule, only: InputParamDefinitionType use CharacterStringModule, only: CharacterStringType - use NCModelExportModule, only: NCBaseModelExportType + use NCModelExportModule, only: export_longname, export_varname, & + NCBaseModelExportType use NetCDFCommonModule, only: nf_verify use netcdf @@ -26,7 +27,6 @@ module MeshModelModule public :: ncvar_deflate public :: ncvar_gridmap public :: ncvar_mf6attr - public :: export_varname !> @brief type for storing model export dimension ids !< @@ -51,6 +51,7 @@ module MeshModelModule integer(I4B) :: mesh_face_ybnds !< mesh faces 2D y bounds array integer(I4B) :: mesh_face_nodes !< mesh faces 2D nodes array integer(I4B) :: time !< time coordinate variable + integer(I4B), dimension(:), allocatable :: export !< in scope layer export integer(I4B), dimension(:), allocatable :: dependent !< layered dependent variables array contains end type MeshNCVarIdType @@ -65,6 +66,9 @@ module MeshModelModule contains procedure :: mesh_init procedure :: mesh_destroy + procedure :: df_export + procedure :: export_df + procedure :: create_timeseries procedure :: add_global_att procedure(nc_array_export_if), deferred :: export_input_array procedure :: export_input_arrays @@ -77,7 +81,7 @@ module MeshModelModule !< abstract interface subroutine nc_array_export_if(this, pkgtype, pkgname, mempath, idt) - import MeshModelType, InputParamDefinitionType, LGP + import MeshModelType, InputParamDefinitionType class(MeshModelType), intent(inout) :: this character(len=*), intent(in) :: pkgtype character(len=*), intent(in) :: pkgname @@ -155,6 +159,157 @@ subroutine mesh_destroy(this) nullify (this%chunk_face) end subroutine mesh_destroy + !> @brief define timeseries input variables + !< + subroutine df_export(this) + use NCModelExportModule, only: ExportPackageType + class(MeshModelType), intent(inout) :: this + class(ExportPackageType), pointer :: export_pkg + integer(I4B) :: idx + do idx = 1, this%pkglist%Count() + export_pkg => this%get(idx) + call this%export_df(export_pkg) + end do + end subroutine df_export + + !> @brief define export package + !< + subroutine export_df(this, export_pkg) + use NCModelExportModule, only: ExportPackageType + use DefinitionSelectModule, only: get_param_definition_type + class(MeshModelType), intent(inout) :: this + class(ExportPackageType), pointer, intent(in) :: export_pkg + type(InputParamDefinitionType), pointer :: idt + integer(I4B) :: iparam, iaux, layer + + ! export defined period input + do iparam = 1, export_pkg%nparam + ! initialize + iaux = 0 + layer = 0 + ! set input definition + idt => & + get_param_definition_type(export_pkg%mf6_input%param_dfns, & + export_pkg%mf6_input%component_type, & + export_pkg%mf6_input%subcomponent_type, & + 'PERIOD', export_pkg%param_names(iparam), '') + + select case (idt%shape) + case ('NCPL') + call this%create_timeseries(idt, iparam, iaux, layer, export_pkg) + case ('NODES') + do layer = 1, this%nlay + call this%create_timeseries(idt, iparam, iaux, layer, export_pkg) + end do + case ('NAUX NCPL') + do iaux = 1, export_pkg%naux + call this%create_timeseries(idt, iparam, iaux, layer, export_pkg) + end do + case ('NAUX NODES') + do iaux = 1, export_pkg%naux + do layer = 1, this%nlay + call this%create_timeseries(idt, iparam, iaux, layer, export_pkg) + end do + end do + case default + end select + end do + end subroutine export_df + + !> @brief create timeseries export variable + !< + subroutine create_timeseries(this, idt, iparam, iaux, layer, export_pkg) + use ConstantsModule, only: DNODATA + use NCModelExportModule, only: ExportPackageType + class(MeshModelType), intent(inout) :: this + type(InputParamDefinitionType), pointer, intent(in) :: idt + integer(I4B), intent(in) :: iparam + integer(I4B), intent(in) :: iaux + integer(I4B), intent(in) :: layer + class(ExportPackageType), pointer, intent(in) :: export_pkg + character(len=LINELENGTH) :: varname, longname, nc_tag + integer(I4B) :: varid + + ! set variable input tag + nc_tag = this%input_attribute(export_pkg%mf6_input%subcomponent_name, & + idt) + + ! set names + varname = export_varname(export_pkg%mf6_input%subcomponent_name, & + idt%tagname, export_pkg%mf6_input%mempath, & + layer=layer, iaux=iaux) + longname = export_longname(idt%longname, & + export_pkg%mf6_input%subcomponent_name, & + idt%tagname, export_pkg%mf6_input%mempath, & + layer=layer, iaux=iaux) + + ! create the netcdf dependent layer variable + select case (idt%datatype) + case ('DOUBLE1D', 'DOUBLE2D') + call nf_verify(nf90_def_var(this%ncid, varname, NF90_DOUBLE, & + (/this%dim_ids%nmesh_face, & + this%dim_ids%time/), & + varid), & + this%nc_fname) + call nf_verify(nf90_put_att(this%ncid, varid, & + '_FillValue', (/DNODATA/)), & + this%nc_fname) + case ('INTEGER1D') + call nf_verify(nf90_def_var(this%ncid, varname, NF90_INT, & + (/this%dim_ids%nmesh_face, & + this%dim_ids%time/), & + varid), & + this%nc_fname) + call nf_verify(nf90_put_att(this%ncid, varid, & + '_FillValue', (/NF90_FILL_INT/)), & + this%nc_fname) + end select + + ! apply chunking parameters + if (this%chunking_active) then + call nf_verify(nf90_def_var_chunking(this%ncid, & + varid, & + NF90_CHUNKED, & + (/this%chunk_face, & + this%chunk_time/)), & + this%nc_fname) + end if + + ! deflate and shuffle + call ncvar_deflate(this%ncid, varid, this%deflate, & + this%shuffle, this%nc_fname) + + ! assign variable attributes + call nf_verify(nf90_put_att(this%ncid, varid, & + 'units', this%lenunits), this%nc_fname) + call nf_verify(nf90_put_att(this%ncid, varid, & + 'long_name', longname), this%nc_fname) + call nf_verify(nf90_put_att(this%ncid, varid, & + 'mesh', this%mesh_name), this%nc_fname) + call nf_verify(nf90_put_att(this%ncid, varid, & + 'location', 'face'), this%nc_fname) + + ! add grid mapping and mf6 attr + call ncvar_gridmap(this%ncid, varid, & + this%gridmap_name, this%nc_fname) + call ncvar_mf6attr(this%ncid, varid, layer, iaux, nc_tag, this%nc_fname) + + ! store variable id + if (idt%tagname == 'AUX') then + if (layer > 0) then + export_pkg%varids_aux(iaux, layer) = varid + else + export_pkg%varids_aux(iaux, 1) = varid + end if + else + if (layer > 0) then + export_pkg%varids_param(iparam, layer) = varid + else + export_pkg%varids_param(iparam, 1) = varid + end if + end if + end subroutine create_timeseries + !> @brief create file (group) attributes !< subroutine add_global_att(this) @@ -165,9 +320,15 @@ subroutine add_global_att(this) ! source (MODFLOW 6) call nf_verify(nf90_put_att(this%ncid, NF90_GLOBAL, 'source', & this%annotation%source), this%nc_fname) - ! export type (MODFLOW 6) + ! grid type (MODFLOW 6) call nf_verify(nf90_put_att(this%ncid, NF90_GLOBAL, 'modflow_grid', & this%annotation%grid), this%nc_fname) + ! mesh type (MODFLOW 6) + if (this%annotation%mesh /= '') then + call nf_verify(nf90_put_att(this%ncid, NF90_GLOBAL, 'mesh', & + this%annotation%mesh), this%nc_fname) + + end if ! MODFLOW 6 model type call nf_verify(nf90_put_att(this%ncid, NF90_GLOBAL, 'modflow_model', & this%annotation%model), this%nc_fname) @@ -546,61 +707,25 @@ end subroutine ncvar_gridmap !> @brief put variable internal attributes !< - subroutine ncvar_mf6attr(ncid, varid, layer, iper, iaux, nc_tag, nc_fname) + subroutine ncvar_mf6attr(ncid, varid, layer, iaux, nc_tag, nc_fname) integer(I4B), intent(in) :: ncid integer(I4B), intent(in) :: varid integer(I4B), intent(in) :: layer - integer(I4B), intent(in) :: iper integer(I4B), intent(in) :: iaux character(len=*), intent(in) :: nc_tag character(len=*), intent(in) :: nc_fname if (nc_tag /= '') then - call nf_verify(nf90_put_att(ncid, varid, 'modflow6_input', & + call nf_verify(nf90_put_att(ncid, varid, 'modflow_input', & nc_tag), nc_fname) if (layer > 0) then - call nf_verify(nf90_put_att(ncid, varid, 'modflow6_layer', & + call nf_verify(nf90_put_att(ncid, varid, 'layer', & layer), nc_fname) end if - if (iper > 0) then - call nf_verify(nf90_put_att(ncid, varid, 'modflow6_iper', & - iper), nc_fname) - end if if (iaux > 0) then - call nf_verify(nf90_put_att(ncid, varid, 'modflow6_iaux', & + call nf_verify(nf90_put_att(ncid, varid, 'modflow_iaux', & iaux), nc_fname) end if end if end subroutine ncvar_mf6attr - !> @brief build netcdf variable name - !< - function export_varname(varname, layer, iper, iaux) result(vname) - use InputOutputModule, only: lowcase - character(len=*), intent(in) :: varname - integer(I4B), optional, intent(in) :: layer - integer(I4B), optional, intent(in) :: iper - integer(I4B), optional, intent(in) :: iaux - character(len=LINELENGTH) :: vname - vname = '' - if (varname /= '') then - vname = varname - call lowcase(vname) - if (present(layer)) then - if (layer > 0) then - write (vname, '(a,i0)') trim(vname)//'_l', layer - end if - end if - if (present(iper)) then - if (iper > 0) then - write (vname, '(a,i0)') trim(vname)//'_p', iper - end if - end if - if (present(iaux)) then - if (iaux > 0) then - write (vname, '(a,i0)') trim(vname)//'a', iaux - end if - end if - end if - end function export_varname - end module MeshModelModule diff --git a/src/Utilities/Export/NCExportCreate.f90 b/src/Utilities/Export/NCExportCreate.f90 index a525be78dca..ed3e18b9f5f 100644 --- a/src/Utilities/Export/NCExportCreate.f90 +++ b/src/Utilities/Export/NCExportCreate.f90 @@ -144,7 +144,8 @@ subroutine create_export_pkglist(pkglist, loaders, iout) use InputLoadTypeModule, only: ModelDynamicPkgsType use InputLoadTypeModule, only: DynamicPkgLoadBaseType use AsciiInputLoadTypeModule, only: AsciiDynamicPkgLoadBaseType - use Mf6FileGridInputModule, only: BoundGridInputType + use LayerArrayLoadModule, only: LayerArrayLoadType + use GridArrayLoadModule, only: GridArrayLoadType use IdmMf6FileModule, only: Mf6FileDynamicPkgLoadType type(ListType), intent(inout) :: pkglist type(ModelDynamicPkgsType), pointer, intent(in) :: loaders @@ -154,7 +155,7 @@ subroutine create_export_pkglist(pkglist, loaders, iout) type(ExportPackageType), pointer :: export_pkg integer(I4B), pointer :: export_arrays class(*), pointer :: obj - logical(LGP) :: found + logical(LGP) :: found, readasarrays integer(I4B) :: n ! create list of in scope loaders @@ -170,16 +171,27 @@ subroutine create_export_pkglist(pkglist, loaders, iout) call mem_set_value(export_arrays, 'EXPORT_NC', & dynamic_pkg%mf6_input%mempath, found) - if (export_arrays > 0 .and. dynamic_pkg%readasarrays) then + readasarrays = (dynamic_pkg%readarraylayer .or. dynamic_pkg%readarraygrid) + if (export_arrays > 0 .and. readasarrays) then select type (dynamic_pkg) type is (Mf6FileDynamicPkgLoadType) rp_loader => dynamic_pkg%rp_loader select type (rp_loader) - type is (BoundGridInputType) + type is (LayerArrayLoadType) ! create the export object allocate (export_pkg) call export_pkg%init(rp_loader%mf6_input, & rp_loader%bound_context%mshape, & + rp_loader%bound_context%naux, & + rp_loader%param_names, rp_loader%nparam) + obj => export_pkg + call pkglist%add(obj) + type is (GridArrayLoadType) + ! create the export object + allocate (export_pkg) + call export_pkg%init(rp_loader%mf6_input, & + rp_loader%bound_context%mshape, & + rp_loader%bound_context%naux, & rp_loader%param_names, rp_loader%nparam) obj => export_pkg call pkglist%add(obj) diff --git a/src/Utilities/Export/NCModel.f90 b/src/Utilities/Export/NCModel.f90 index e2d3558a4a5..2d29fbf77fc 100644 --- a/src/Utilities/Export/NCModel.f90 +++ b/src/Utilities/Export/NCModel.f90 @@ -24,7 +24,7 @@ module NCModelExportModule public :: NCExportAnnotation public :: ExportPackageType public :: NETCDF_UNDEF, NETCDF_STRUCTURED, NETCDF_MESH2D - public :: export_longname + public :: export_longname, export_varname !> @brief netcdf export types enumerator !< @@ -38,10 +38,13 @@ module NCModelExportModule type(ModflowInputType) :: mf6_input !< description of modflow6 input character(len=LINELENGTH), dimension(:), allocatable :: param_names !< dynamic param tagnames type(ReadStateVarType), dimension(:), allocatable :: param_reads !< param read states + integer(I4B), dimension(:, :), allocatable :: varids_param + integer(I4B), dimension(:, :), allocatable :: varids_aux integer(I4B), dimension(:), pointer, contiguous :: mshape => null() !< model shape integer(I4B), pointer :: iper !< most recent package rp load integer(I4B) :: iper_export !< most recent period of netcdf package export integer(I4B) :: nparam !< number of in scope params + integer(I4B) :: naux !< number of auxiliary variables contains procedure :: init => epkg_init procedure :: destroy => epkg_destroy @@ -52,6 +55,7 @@ module NCModelExportModule type :: NCExportAnnotation character(len=LINELENGTH) :: title !< file scoped title attribute character(len=LINELENGTH) :: model !< file scoped model attribute + character(len=LINELENGTH) :: mesh !< mesh type character(len=LINELENGTH) :: grid !< grid type character(len=LINELENGTH) :: history !< file scoped history attribute character(len=LINELENGTH) :: source !< file scoped source attribute @@ -82,7 +86,6 @@ module NCModelExportModule real(DP), dimension(:), pointer, contiguous :: x !< dependent variable pointer integer(I4B) :: disenum !< type of discretization integer(I4B) :: ncid !< netcdf file descriptor - integer(I4B) :: stepcnt !< simulation step count integer(I4B) :: totnstp !< simulation total number of steps integer(I4B), pointer :: deflate !< variable deflate level integer(I4B), pointer :: shuffle !< variable shuffle filter @@ -103,9 +106,9 @@ module NCModelExportModule contains procedure :: export_input procedure(model_define), deferred :: df + procedure(package_export), deferred :: export_df procedure(model_step), deferred :: step procedure(package_export), deferred :: package_step - procedure(package_export_ilayer), deferred :: package_step_ilayer end type NCBaseModelExportType !> @brief abstract interfaces for model netcdf export type @@ -138,7 +141,7 @@ subroutine package_export_ilayer(this, export_pkg, ilayer_varname, & !> @brief initialize dynamic package export object !< - subroutine epkg_init(this, mf6_input, mshape, param_names, & + subroutine epkg_init(this, mf6_input, mshape, naux, param_names, & nparam) use SimVariablesModule, only: idm_context use MemoryManagerModule, only: mem_setptr @@ -147,6 +150,7 @@ subroutine epkg_init(this, mf6_input, mshape, param_names, & class(ExportPackageType), intent(inout) :: this type(ModflowInputType), intent(in) :: mf6_input integer(I4B), dimension(:), pointer, contiguous, intent(in) :: mshape !< model shape + integer(I4B), intent(in) :: naux character(len=LINELENGTH), dimension(:), allocatable, & intent(in) :: param_names integer(I4B), intent(in) :: nparam @@ -158,6 +162,7 @@ subroutine epkg_init(this, mf6_input, mshape, param_names, & this%mf6_input = mf6_input this%mshape => mshape this%nparam = nparam + this%naux = naux this%iper_export = 0 input_mempath = create_mem_path(component=mf6_input%component_name, & @@ -167,6 +172,8 @@ subroutine epkg_init(this, mf6_input, mshape, param_names, & ! allocate param arrays allocate (this%param_names(nparam)) allocate (this%param_reads(nparam)) + allocate (this%varids_param(nparam, mshape(1))) + allocate (this%varids_aux(naux, mshape(1))) ! set param arrays do n = 1, nparam @@ -190,18 +197,20 @@ end subroutine epkg_destroy !> @brief set netcdf file scoped attributes !< - subroutine set(this, modelname, modeltype, modelfname, nctype) + subroutine set(this, modelname, modeltype, modelfname, nctype, disenum) use VersionModule, only: VERSION class(NCExportAnnotation), intent(inout) :: this character(len=*), intent(in) :: modelname character(len=*), intent(in) :: modeltype character(len=*), intent(in) :: modelfname integer(I4B), intent(in) :: nctype + integer(I4B), intent(in) :: disenum character(len=LINELENGTH) :: fullname integer :: values(8) this%title = '' this%model = '' + this%mesh = '' this%grid = '' this%history = '' this%source = '' @@ -238,11 +247,16 @@ subroutine set(this, modelname, modeltype, modelfname, nctype) this%title = trim(this%title)//' array input' end if - ! set export type + ! set mesh type if (nctype == NETCDF_MESH2D) then - this%grid = 'LAYERED MESH' - else if (nctype == NETCDF_STRUCTURED) then + this%mesh = 'LAYERED' + end if + + ! set grid type + if (disenum == DIS) then this%grid = 'STRUCTURED' + else if (disenum == DISV) then + this%grid = 'VERTEX' end if ! model description string @@ -263,7 +277,7 @@ end subroutine set !< subroutine export_init(this, modelname, modeltype, modelfname, nc_fname, & disenum, nctype, iout) - use TdisModule, only: datetime0, nstp + use TdisModule, only: datetime0, nstp, inats use MemoryManagerModule, only: mem_setptr use MemoryHelperModule, only: create_mem_path use MemoryManagerExtModule, only: mem_set_value @@ -300,7 +314,6 @@ subroutine export_init(this, modelname, modeltype, modelfname, nc_fname, & this%lenunits = '' this%disenum = disenum this%ncid = 0 - this%stepcnt = 0 this%totnstp = 0 this%deflate = -1 this%shuffle = 0 @@ -310,7 +323,7 @@ subroutine export_init(this, modelname, modeltype, modelfname, nc_fname, & this%chunking_active = .false. ! set file scoped attributes - call this%annotation%set(modelname, modeltype, modelfname, nctype) + call this%annotation%set(modelname, modeltype, modelfname, nctype, disenum) ! set dependent variable basename select case (modeltype) @@ -373,6 +386,14 @@ subroutine export_init(this, modelname, modeltype, modelfname, nc_fname, & this%datetime = 'days since 1970-01-01T00:00:00' end if + ! Set error and exit if ATS is on + if (inats > 0) then + errmsg = 'Adaptive time stepping not currently supported & + &with NetCDF exports.' + call store_error(errmsg) + call store_error_filename(modelfname) + end if + ! set total nstp this%totnstp = sum(nstp) end subroutine export_init @@ -395,7 +416,7 @@ function export_get(this, idx) result(res) end if end function export_get - !> @brief build modflow6_input attribute string + !> @brief build modflow_input attribute string !< function input_attribute(this, pkgname, idt) result(attr) use InputOutputModule, only: lowcase @@ -408,21 +429,68 @@ function input_attribute(this, pkgname, idt) result(attr) attr = '' if (this%input_attr > 0) then attr = trim(this%modelname)//memPathSeparator//trim(pkgname)// & - memPathSeparator//trim(idt%mf6varname) + memPathSeparator//trim(idt%tagname) end if end function input_attribute + !> @brief build netcdf variable name + !< + function export_varname(pkgname, tagname, mempath, layer, iaux) & + result(varname) + use MemoryManagerModule, only: mem_setptr + use CharacterStringModule, only: CharacterStringType + use InputOutputModule, only: lowcase + character(len=*), intent(in) :: pkgname + character(len=*), intent(in) :: tagname + character(len=*), intent(in) :: mempath + integer(I4B), optional, intent(in) :: layer + integer(I4B), optional, intent(in) :: iaux + character(len=LINELENGTH) :: varname + type(CharacterStringType), dimension(:), pointer, & + contiguous :: auxnames + character(len=LINELENGTH) :: pname, vname + vname = tagname + pname = pkgname + + if (present(iaux)) then + if (iaux > 0) then + if (tagname == 'AUX') then + ! reset vname to auxiliary variable name + call mem_setptr(auxnames, 'AUXILIARY', mempath) + vname = auxnames(iaux) + end if + end if + end if + + call lowcase(vname) + call lowcase(pname) + varname = trim(pname)//'_'//trim(vname) + + if (present(layer)) then + if (layer > 0) then + !write (varname, '(a,i0)') trim(varname)//'_L', layer + write (varname, '(a,i0)') trim(varname)//'_l', layer + end if + end if + end function export_varname + !> @brief build netcdf variable longname !< - function export_longname(longname, pkgname, tagname, layer, iper) result(lname) + function export_longname(longname, pkgname, tagname, mempath, layer, iaux) & + result(lname) + use MemoryManagerModule, only: mem_setptr + use CharacterStringModule, only: CharacterStringType use InputOutputModule, only: lowcase character(len=*), intent(in) :: longname character(len=*), intent(in) :: pkgname character(len=*), intent(in) :: tagname - integer(I4B), intent(in) :: layer - integer(I4B), optional, intent(in) :: iper + character(len=*), intent(in) :: mempath + integer(I4B), optional, intent(in) :: layer + integer(I4B), optional, intent(in) :: iaux character(len=LINELENGTH) :: lname - character(len=LINELENGTH) :: pname, vname + type(CharacterStringType), dimension(:), pointer, & + contiguous :: auxnames + character(len=LINELENGTH) :: pname, vname, auxname pname = pkgname vname = tagname call lowcase(pname) @@ -432,12 +500,22 @@ function export_longname(longname, pkgname, tagname, layer, iper) result(lname) else lname = longname end if - if (layer > 0) then - write (lname, '(a,i0)') trim(lname)//' layer=', layer + + if (present(iaux)) then + if (iaux > 0) then + if (tagname == 'AUX') then + ! reset vname to auxiliary variable name + call mem_setptr(auxnames, 'AUXILIARY', mempath) + auxname = auxnames(iaux) + call lowcase(auxname) + lname = trim(lname)//' '//trim(auxname) + end if + end if end if - if (present(iper)) then - if (iper > 0) then - write (lname, '(a,i0)') trim(lname)//' period=', iper + + if (present(layer)) then + if (layer > 0) then + write (lname, '(a,i0)') trim(lname)//' layer=', layer end if end if end function export_longname @@ -446,12 +524,9 @@ end function export_longname !< subroutine export_input(this) use TdisModule, only: kper - use ArrayHandlersModule, only: ifind class(NCBaseModelExportType), intent(inout) :: this - integer(I4B) :: idx, ilayer + integer(I4B) :: idx class(ExportPackageType), pointer :: export_pkg - character(len=LENVARNAME) :: ilayer_varname - do idx = 1, this%pkglist%Count() export_pkg => this%get(idx) ! last loaded data is not current period @@ -460,22 +535,8 @@ subroutine export_input(this) if (export_pkg%iper_export >= export_pkg%iper) cycle ! set exported iper export_pkg%iper_export = export_pkg%iper - - ! initialize ilayer - ilayer = 0 - - ! set expected ilayer index variable name - ilayer_varname = 'I'//trim(export_pkg%mf6_input%subcomponent_type(1:3)) - - ! is ilayer variable in param name list - ilayer = ifind(export_pkg%param_names, ilayer_varname) - - ! layer index variable is required to be first defined in period block - if (ilayer == 1) then - call this%package_step_ilayer(export_pkg, ilayer_varname, ilayer) - else - call this%package_step(export_pkg) - end if + ! update export package + call this%package_step(export_pkg) end do end subroutine export_input diff --git a/src/Utilities/Idm/BoundInputContext.f90 b/src/Utilities/Idm/BoundInputContext.f90 index c30ed6a9e98..2e14b4cedef 100644 --- a/src/Utilities/Idm/BoundInputContext.f90 +++ b/src/Utilities/Idm/BoundInputContext.f90 @@ -43,6 +43,7 @@ module BoundInputContextModule integer(I4B), pointer :: iprpak => null() ! print input option integer(I4B), pointer :: nbound => null() !< number of bounds in period integer(I4B), pointer :: ncpl => null() !< number of cells per layer + integer(I4B) :: nodes type(CharacterStringType), dimension(:), pointer, & contiguous :: auxname_cst => null() !< array of auxiliary names type(CharacterStringType), dimension(:), pointer, & @@ -50,7 +51,9 @@ module BoundInputContextModule real(DP), dimension(:, :), pointer, & contiguous :: auxvar => null() !< auxiliary variable array integer(I4B), dimension(:), pointer, contiguous :: mshape => null() !< model shape - logical(LGP) :: readasarrays !< grid or list based input + logical(LGP) :: readasarrays !< grid or layer array input + logical(LGP) :: readarraylayer !< array layer reader + logical(LGP) :: readarraygrid !< array grid reader type(DynamicPackageParamsType) :: package_params type(ModflowInputType) :: mf6_input !< description of input contains @@ -69,13 +72,16 @@ module BoundInputContextModule !> @brief create boundary input context !! !< - subroutine create(this, mf6_input, readasarrays) + subroutine create(this, mf6_input, readarraygrid, readarraylayer) class(BoundInputContextType) :: this type(ModflowInputType), intent(in) :: mf6_input - logical(LGP), intent(in) :: readasarrays + logical(LGP), intent(in) :: readarraygrid + logical(LGP), intent(in) :: readarraylayer this%mf6_input = mf6_input - this%readasarrays = readasarrays + this%readarraygrid = readarraygrid + this%readarraylayer = readarraylayer + this%readasarrays = readarraygrid .or. readarraylayer ! create the dynamic package input context call this%allocate_scalars() @@ -126,6 +132,9 @@ subroutine allocate_scalars(this) this%ncpl = this%mshape(2) * this%mshape(3) end if + ! set total user nodes + this%nodes = product(this%mshape) + ! initialize package params object call this%package_params%init(this%mf6_input, 'PERIOD', this%readasarrays, & this%naux, this%inamedbound) @@ -141,6 +150,7 @@ subroutine allocate_arrays(this) use MemoryManagerExtModule, only: mem_set_value class(BoundInputContextType) :: this integer(I4B), dimension(:, :), pointer, contiguous :: cellid + integer(I4B), dimension(:), pointer, contiguous :: nodeulist ! set auxname_cst and iauxmultcol if (this%naux > 0) then @@ -155,6 +165,11 @@ subroutine allocate_arrays(this) call mem_allocate(cellid, 0, 0, 'CELLID', this%mf6_input%mempath) end if + ! allocate nodeulist + if (.not. this%readarraygrid) then + call mem_allocate(nodeulist, 0, 'NODEULIST', this%mf6_input%mempath) + end if + ! set pointer to BOUNDNAME call mem_setptr(this%boundname_cst, 'BOUNDNAME', this%mf6_input%mempath) @@ -237,7 +252,7 @@ subroutine array_params_create(this, params, nparam, input_name) integer(I4B), intent(in) :: nparam character(len=*), intent(in) :: input_name type(InputParamDefinitionType), pointer :: idt - integer(I4B) :: iparam + integer(I4B) :: iparam, asize ! allocate dfn input params do iparam = 1, nparam @@ -247,24 +262,32 @@ subroutine array_params_create(this, params, nparam, input_name) this%mf6_input%component_type, & this%mf6_input%subcomponent_type, & 'PERIOD', params(iparam), '') - if (idt%blockname == 'PERIOD') then - select case (idt%datatype) - case ('INTEGER1D') - call allocate_param_int1d(this%ncpl, idt%mf6varname, & - this%mf6_input%mempath) - case ('DOUBLE1D') - call allocate_param_dbl1d(this%ncpl, idt%mf6varname, & - this%mf6_input%mempath) - case ('DOUBLE2D') - call allocate_param_dbl2d(this%naux, this%ncpl, idt%mf6varname, & - this%mf6_input%mempath) - case default - errmsg = 'IDM unimplemented. BoundInputContext::array_params_create & - &datatype='//trim(idt%datatype) - call store_error(errmsg) - call store_error_filename(input_name) - end select - end if + + select case (idt%shape) + case ('NCPL', 'NAUX NCPL') + asize = this%ncpl + case ('NODES', 'NAUX NODES') + asize = this%maxbound + case default + asize = 0 + end select + + select case (idt%datatype) + case ('INTEGER1D') + call allocate_param_int1d(asize, idt%mf6varname, & + this%mf6_input%mempath) + case ('DOUBLE1D') + call allocate_param_dbl1d(asize, idt%mf6varname, & + this%mf6_input%mempath) + case ('DOUBLE2D') + call allocate_param_dbl2d(this%naux, asize, idt%mf6varname, & + this%mf6_input%mempath) + case default + errmsg = 'IDM unimplemented. BoundInputContext::array_params_create & + &datatype='//trim(idt%datatype) + call store_error(errmsg) + call store_error_filename(input_name) + end select end do end subroutine array_params_create diff --git a/src/Utilities/Idm/InputLoadType.f90 b/src/Utilities/Idm/InputLoadType.f90 index 204f7791eba..381f9593577 100644 --- a/src/Utilities/Idm/InputLoadType.f90 +++ b/src/Utilities/Idm/InputLoadType.f90 @@ -82,7 +82,8 @@ module InputLoadTypeModule character(len=LINELENGTH) :: component_input_name !< component input name, e.g. model name file character(len=LINELENGTH) :: input_name !< input name, e.g. package *.chd file character(len=LINELENGTH), dimension(:), allocatable :: param_names !< dynamic param tagnames - logical(LGP) :: readasarrays !< is this array based input + logical(LGP) :: readarraylayer + logical(LGP) :: readarraygrid integer(I4B) :: iperblock !< index of period block on block definition list integer(I4B) :: iout !< inunit number for logging integer(I4B) :: nparam !< number of in scope params @@ -349,11 +350,14 @@ subroutine dynamic_init(this, mf6_input, component_name, component_input_name, & integer(I4B), intent(in) :: iperblock integer(I4B), intent(in) :: iout type(InputParamDefinitionType), pointer :: idt + integer(I4B) :: iparam this%mf6_input = mf6_input this%component_name = component_name this%component_input_name = component_input_name this%input_name = input_name + this%readarraylayer = .false. + this%readarraygrid = .false. this%iperblock = iperblock this%nparam = 0 this%iout = iout @@ -369,8 +373,24 @@ subroutine dynamic_init(this, mf6_input, component_name, component_input_name, & call store_error_filename(this%input_name) end if - ! set readasarrays - this%readasarrays = (.not. mf6_input%block_dfns(iperblock)%aggregate) + ! set readarraylayer and readarraygrid + if (mf6_input%block_dfns(iperblock)%aggregate) then + ! no-op, list based input + else + do iparam = 1, size(mf6_input%param_dfns) + idt => mf6_input%param_dfns(iparam) + if (idt%blockname == 'OPTIONS') then + select case (idt%tagname) + case ('READARRAYLAYER', 'READASARRAYS') + this%readarraylayer = .true. + case ('READARRAYGRID') + this%readarraygrid = .true. + case default + ! no-op + end select + end if + end do + end if end subroutine dynamic_init !> @brief dynamic package loader define diff --git a/src/Utilities/Idm/ModflowInput.f90 b/src/Utilities/Idm/ModflowInput.f90 index ac463b6e63f..8f52da4b2ca 100644 --- a/src/Utilities/Idm/ModflowInput.f90 +++ b/src/Utilities/Idm/ModflowInput.f90 @@ -99,7 +99,7 @@ function update_sc_type(filetype, filename, component_type, subcomponent_type) & character(len=LENPACKAGETYPE) :: sc_type sc_type = subcomponent_type select case (subcomponent_type) - case ('RCH', 'EVT', 'SCP') + case ('RCH', 'EVT', 'SCP', 'GHB') sc_type = read_as_arrays(filetype, filename, component_type, & subcomponent_type) case default @@ -138,10 +138,15 @@ function read_as_arrays(filetype, filename, component_type, subcomponent_type) & call parser%GetNextLine(endOfBlock) if (endOfBlock) exit call parser%GetStringCaps(keyword) - if (keyword == 'READASARRAYS') then + select case (keyword) + case ('READASARRAYS') write (sc_type, '(a)') trim(subcomponent_type)//'A' - exit - end if + case ('READARRAYLAYER') + write (sc_type, '(a)') trim(subcomponent_type)//'L' + case ('READARRAYGRID') + write (sc_type, '(a)') trim(subcomponent_type)//'G' + case default + end select end do end if diff --git a/src/Utilities/Idm/mf6blockfile/IdmMf6File.f90 b/src/Utilities/Idm/mf6blockfile/IdmMf6File.f90 index 360fcd47701..7bcef6795ec 100644 --- a/src/Utilities/Idm/mf6blockfile/IdmMf6File.f90 +++ b/src/Utilities/Idm/mf6blockfile/IdmMf6File.f90 @@ -14,7 +14,7 @@ module IdmMf6FileModule use ConstantsModule, only: LINELENGTH use SimModule, only: store_error, store_error_filename use BlockParserModule, only: BlockParserType - use ModflowInputModule, only: ModflowInputType, getModflowInput + use ModflowInputModule, only: ModflowInputType use InputLoadTypeModule, only: StaticPkgLoadBaseType, DynamicPkgLoadBaseType use AsciiInputLoadTypeModule, only: AsciiDynamicPkgLoadBaseType use NCFileVarsModule, only: NCPackageVarsType @@ -150,7 +150,6 @@ subroutine dynamic_init(this, mf6_input, component_name, component_input_name, & input_name, iperblock, iout) use MemoryManagerModule, only: mem_allocate use InputDefinitionModule, only: InputParamDefinitionType - use DefinitionSelectModule, only: get_param_definition_type class(Mf6FileDynamicPkgLoadType), intent(inout) :: this type(ModflowInputType), intent(in) :: mf6_input character(len=*), intent(in) :: component_name @@ -268,24 +267,43 @@ end subroutine dynamic_read_ionper !> @brief allocate a dynamic loader based on load context !< subroutine dynamic_create_loader(this) - use Mf6FileGridInputModule, only: BoundGridInputType - use Mf6FileListInputModule, only: BoundListInputType + use LayerArrayLoadModule, only: LayerArrayLoadType + use GridArrayLoadModule, only: GridArrayLoadType + use ListLoadModule, only: ListLoadType use Mf6FileStoInputModule, only: StoInputType + use DevFeatureModule, only: dev_feature class(Mf6FileDynamicPkgLoadType), intent(inout) :: this - class(BoundListInputType), pointer :: bndlist_loader - class(BoundGridInputType), pointer :: bndgrid_loader + class(ListLoadType), pointer :: list_loader + class(GridArrayLoadType), pointer :: arrgrid_loader + class(LayerArrayLoadType), pointer :: arrlayer_loader class(StoInputType), pointer :: sto_loader ! allocate and set loader if (this%mf6_input%subcomponent_type == 'STO') then allocate (sto_loader) this%rp_loader => sto_loader - else if (this%readasarrays) then - allocate (bndgrid_loader) - this%rp_loader => bndgrid_loader + else if (this%readarraylayer) then + select case (this%mf6_input%subcomponent_type) + case ('EVTA', 'RCHA') + ! no-op + case default + call dev_feature('Input file "'//trim(this%input_name)// & + '" READARRAYLAYER option is still under development, install the & + &nightly build or compile from source with IDEVELOPMODE = 1.', & + this%iout) + end select + allocate (arrlayer_loader) + this%rp_loader => arrlayer_loader + else if (this%readarraygrid) then + call dev_feature('Input file "'//trim(this%input_name)// & + '" READARRAYGRID option is still under development, install the & + &nightly build or compile from source with IDEVELOPMODE = 1.', & + this%iout) + allocate (arrgrid_loader) + this%rp_loader => arrgrid_loader else - allocate (bndlist_loader) - this%rp_loader => bndlist_loader + allocate (list_loader) + this%rp_loader => list_loader end if ! set nc_vars pointer diff --git a/src/Utilities/Idm/mf6blockfile/LoadMf6File.f90 b/src/Utilities/Idm/mf6blockfile/LoadMf6File.f90 index 5545e03ed54..486207d3c57 100644 --- a/src/Utilities/Idm/mf6blockfile/LoadMf6File.f90 +++ b/src/Utilities/Idm/mf6blockfile/LoadMf6File.f90 @@ -26,7 +26,7 @@ module LoadMf6FileModule use InputDefinitionModule, only: InputParamDefinitionType use DefinitionSelectModule, only: get_param_definition_type, & get_aggregate_definition_type - use ModflowInputModule, only: ModflowInputType, getModflowInput + use ModflowInputModule, only: ModflowInputType use MemoryManagerModule, only: mem_allocate, mem_setptr use MemoryHelperModule, only: create_mem_path use StructArrayModule, only: StructArrayType diff --git a/src/Utilities/Idm/mf6blockfile/Mf6FileGridArray.f90 b/src/Utilities/Idm/mf6blockfile/Mf6FileGridArray.f90 new file mode 100644 index 00000000000..cf6691847dc --- /dev/null +++ b/src/Utilities/Idm/mf6blockfile/Mf6FileGridArray.f90 @@ -0,0 +1,312 @@ +!> @brief This module contains the GridArrayLoadModule +!! +!! This module contains the routines for reading period block +!! array based input associated with the full grid, such as +!! with the GHBA package. +!! +!< +module GridArrayLoadModule + + use KindModule, only: I4B, DP, LGP + use ConstantsModule, only: DZERO, IZERO, LINELENGTH, LENVARNAME, & + LENTIMESERIESNAME, LENAUXNAME + use SimVariablesModule, only: errmsg + use SimModule, only: store_error, store_error_filename + use InputDefinitionModule, only: InputParamDefinitionType + use MemoryManagerModule, only: mem_allocate, mem_setptr + use CharacterStringModule, only: CharacterStringType + use BlockParserModule, only: BlockParserType + use ModflowInputModule, only: ModflowInputType + use BoundInputContextModule, only: BoundInputContextType, ReadStateVarType + use AsciiInputLoadTypeModule, only: AsciiDynamicPkgLoadBaseType + + implicit none + private + public :: GridArrayLoadType + + !> @brief Ascii grid based dynamic loader type + !< + type, extends(AsciiDynamicPkgLoadBaseType) :: GridArrayLoadType + type(ReadStateVarType), dimension(:), allocatable :: param_reads !< read states for current load + type(BoundInputContextType) :: bound_context + integer(I4B), dimension(:), pointer, contiguous :: nodeulist + contains + procedure :: ainit + procedure :: df + procedure :: ad + procedure :: rp + procedure :: destroy + procedure :: reset + procedure :: params_alloc + procedure :: param_load + end type GridArrayLoadType + +contains + + subroutine ainit(this, mf6_input, component_name, & + component_input_name, input_name, & + iperblock, parser, iout) + use MemoryManagerModule, only: get_isize + use BlockParserModule, only: BlockParserType + use LoadMf6FileModule, only: LoadMf6FileType + class(GridArrayLoadType), intent(inout) :: this + type(ModflowInputType), intent(in) :: mf6_input + character(len=*), intent(in) :: component_name + character(len=*), intent(in) :: component_input_name + character(len=*), intent(in) :: input_name + integer(I4B), intent(in) :: iperblock + type(BlockParserType), pointer, intent(inout) :: parser + integer(I4B), intent(in) :: iout + type(LoadMf6FileType) :: loader + + ! initialize base type + call this%DynamicPkgLoadType%init(mf6_input, component_name, & + component_input_name, & + input_name, iperblock, iout) + ! initialize + this%iout = iout + + ! load static input + call loader%load(parser, mf6_input, this%nc_vars, this%input_name, iout) + + ! initialize input context memory + call this%bound_context%create(mf6_input, & + readarraygrid=.true., & + readarraylayer=.false.) + + ! allocate user nodelist + call mem_allocate(this%nodeulist, this%bound_context%maxbound, & + 'NODEULIST', mf6_input%mempath) + + ! allocate dfn params + call this%params_alloc() + end subroutine ainit + + subroutine df(this) + class(GridArrayLoadType), intent(inout) :: this + end subroutine df + + subroutine ad(this) + class(GridArrayLoadType), intent(inout) :: this + end subroutine ad + + subroutine rp(this, parser) + use BlockParserModule, only: BlockParserType + use InputDefinitionModule, only: InputParamDefinitionType + use DefinitionSelectModule, only: get_param_definition_type + use ArrayHandlersModule, only: ifind + use SourceCommonModule, only: ifind_charstr + use IdmLoggerModule, only: idm_log_header, idm_log_close, idm_log_var + class(GridArrayLoadType), intent(inout) :: this + type(BlockParserType), pointer, intent(inout) :: parser + logical(LGP) :: endOfBlock, netcdf, layered + character(len=LINELENGTH) :: keyword, param_tag + type(InputParamDefinitionType), pointer :: idt + integer(I4B) :: iaux + + ! reset for this period + call this%reset() + + ! log lst file header + call idm_log_header(this%mf6_input%component_name, & + this%mf6_input%subcomponent_name, this%iout) + + ! read array block + do + ! initialize + iaux = 0 + netcdf = .false. + layered = .false. + + ! read next line + call parser%GetNextLine(endOfBlock) + if (endOfBlock) exit + ! read param_tag + call parser%GetStringCaps(param_tag) + + ! is param tag an auxvar? + iaux = ifind_charstr(this%bound_context%auxname_cst, param_tag) + + ! any auvxar corresponds to the definition tag 'AUX' + if (iaux > 0) param_tag = 'AUX' + + ! set input definition + idt => get_param_definition_type(this%mf6_input%param_dfns, & + this%mf6_input%component_type, & + this%mf6_input%subcomponent_type, & + 'PERIOD', param_tag, this%input_name) + ! look for Layered and NetCDF keywords + call parser%GetStringCaps(keyword) + if (keyword == 'LAYERED' .and. idt%layered) then + layered = .true. + else if (keyword == 'NETCDF') then + netcdf = .true. + end if + + ! read and load the parameter + call this%param_load(parser, idt, this%mf6_input%mempath, layered, & + netcdf, iaux) + end do + + ! log lst file header + call idm_log_close(this%mf6_input%component_name, & + this%mf6_input%subcomponent_name, this%iout) + end subroutine rp + + subroutine destroy(this) + use MemoryManagerModule, only: mem_deallocate + class(GridArrayLoadType), intent(inout) :: this + call mem_deallocate(this%nodeulist) + end subroutine destroy + + subroutine reset(this) + use ConstantsModule, only: DNODATA + class(GridArrayLoadType), intent(inout) :: this + integer(I4B) :: n, m + + this%bound_context%nbound = 0 + + do n = 1, this%nparam + ! reset read state + this%param_reads(n)%invar = 0 + end do + + ! explicitly reset auxvar array each period + do m = 1, this%bound_context%maxbound + do n = 1, this%bound_context%naux + this%bound_context%auxvar(n, m) = DZERO + end do + end do + end subroutine reset + + subroutine params_alloc(this) + class(GridArrayLoadType), intent(inout) :: this + character(len=LENVARNAME) :: rs_varname + integer(I4B), pointer :: intvar + integer(I4B) :: iparam + + ! set in scope param names + call this%bound_context%bound_params(this%param_names, this%nparam, & + this%input_name) + call this%bound_context%allocate_arrays() + + ! allocate and set param_reads pointer array + allocate (this%param_reads(this%nparam)) + + ! store read state variable pointers + do iparam = 1, this%nparam + ! allocate and store name of read state variable + rs_varname = this%bound_context%rsv_alloc(this%param_names(iparam)) + call mem_setptr(intvar, rs_varname, this%mf6_input%mempath) + this%param_reads(iparam)%invar => intvar + this%param_reads(iparam)%invar = 0 + end do + end subroutine params_alloc + + subroutine param_load(this, parser, idt, mempath, layered, netcdf, iaux) + use TdisModule, only: kper + use ConstantsModule, only: DNODATA + use ArrayHandlersModule, only: ifind + use InputDefinitionModule, only: InputParamDefinitionType + use DefinitionSelectModule, only: get_param_definition_type + use Double1dReaderModule, only: read_dbl1d + use Double2dReaderModule, only: read_dbl2d + use LayeredArrayReaderModule, only: read_dbl1d_layered + use LoadNCInputModule, only: netcdf_read_array + use SourceCommonModule, only: get_shape_from_string, get_layered_shape + use IdmLoggerModule, only: idm_log_var + class(GridArrayLoadType), intent(inout) :: this + type(BlockParserType), intent(in) :: parser + type(InputParamDefinitionType), intent(in) :: idt + character(len=*), intent(in) :: mempath + logical(LGP), intent(in) :: layered + logical(LGP), intent(in) :: netcdf + real(DP), dimension(:), pointer, contiguous :: dbl1d, nodes + real(DP), dimension(:, :), pointer, contiguous :: dbl2d + integer(I4B), dimension(:), allocatable :: layer_shape + integer(I4B) :: iaux, iparam, n, nlay, nnode + + nnode = 0 + + select case (idt%datatype) + case ('DOUBLE1D') + call mem_setptr(dbl1d, idt%mf6varname, mempath) + allocate (nodes(this%bound_context%nodes)) + if (netcdf) then + call netcdf_read_array(nodes, this%bound_context%mshape, idt, & + this%mf6_input, this%nc_vars, this%input_name, & + this%iout, kper) + else if (layered) then + call get_layered_shape(this%bound_context%mshape, nlay, layer_shape) + call read_dbl1d_layered(parser, nodes, idt%mf6varname, nlay, layer_shape) + else + call read_dbl1d(parser, nodes, idt%mf6varname) + end if + + call idm_log_var(nodes, idt%tagname, mempath, this%iout) + + do n = 1, this%bound_context%nodes + if (nodes(n) /= DNODATA) then + nnode = nnode + 1 + dbl1d(nnode) = nodes(n) + if (this%bound_context%nbound == 0) then + this%nodeulist(nnode) = n + else if (this%nodeulist(nnode) /= n) then + write (errmsg, '(a,i0)') 'Grid input position mismatch param='// & + trim(idt%tagname)//', period=', kper + call store_error(errmsg) + call store_error_filename(this%input_name) + end if + end if + end do + deallocate (nodes) + case ('DOUBLE2D') + call mem_setptr(dbl2d, idt%mf6varname, mempath) + allocate (nodes(this%bound_context%nodes)) + + if (netcdf) then + call netcdf_read_array(nodes, this%bound_context%mshape, idt, & + this%mf6_input, this%nc_vars, this%input_name, & + this%iout, kper, iaux) + else if (layered) then + call get_layered_shape(this%bound_context%mshape, nlay, layer_shape) + call read_dbl1d_layered(parser, nodes, idt%mf6varname, nlay, layer_shape) + else + call read_dbl1d(parser, nodes, idt%mf6varname) + end if + + call idm_log_var(nodes, idt%tagname, mempath, this%iout) + + do n = 1, this%bound_context%nodes + if (nodes(n) /= DNODATA) then + nnode = nnode + 1 + dbl2d(iaux, nnode) = nodes(n) + if (this%bound_context%nbound == 0) then + this%nodeulist(nnode) = n + else if (this%nodeulist(nnode) /= n) then + write (errmsg, '(a,i0)') 'Grid input position mismatch param='// & + trim(idt%tagname)//', period=', kper + call store_error(errmsg) + call store_error_filename(this%input_name) + end if + end if + end do + deallocate (nodes) + case default + errmsg = 'IDM unimplemented. GridArrayLoad::param_load & + &datatype='//trim(idt%datatype) + call store_error(errmsg) + call store_error_filename(this%input_name) + end select + + ! set nbound + if (this%bound_context%nbound == 0) this%bound_context%nbound = nnode + + ! if param is tracked set read state + iparam = ifind(this%param_names, idt%tagname) + if (iparam > 0) then + this%param_reads(iparam)%invar = 1 + end if + end subroutine param_load + +end module GridArrayLoadModule diff --git a/src/Utilities/Idm/mf6blockfile/Mf6FileGridInput.f90 b/src/Utilities/Idm/mf6blockfile/Mf6FileLayerArray.f90 similarity index 85% rename from src/Utilities/Idm/mf6blockfile/Mf6FileGridInput.f90 rename to src/Utilities/Idm/mf6blockfile/Mf6FileLayerArray.f90 index 5ceb05cf97b..5ad47a1654c 100644 --- a/src/Utilities/Idm/mf6blockfile/Mf6FileGridInput.f90 +++ b/src/Utilities/Idm/mf6blockfile/Mf6FileLayerArray.f90 @@ -1,10 +1,11 @@ -!> @brief This module contains the Mf6FileGridInputModule +!> @brief This module contains the LayerArrayLoadModule !! !! This module contains the routines for reading period block -!! array based input. +!! array based input that is associated with a layer and an +!! layer index array, such as with the EVTA and RCHA packages. !! !< -module Mf6FileGridInputModule +module LayerArrayLoadModule use KindModule, only: I4B, DP, LGP use ConstantsModule, only: DZERO, IZERO, LINELENGTH, LENVARNAME, & @@ -15,7 +16,7 @@ module Mf6FileGridInputModule use MemoryManagerModule, only: mem_allocate, mem_reallocate, mem_setptr use CharacterStringModule, only: CharacterStringType use BlockParserModule, only: BlockParserType - use ModflowInputModule, only: ModflowInputType, getModflowInput + use ModflowInputModule, only: ModflowInputType use BoundInputContextModule, only: BoundInputContextType, ReadStateVarType use TimeArraySeriesManagerModule, only: TimeArraySeriesManagerType, & tasmanager_cr @@ -23,11 +24,11 @@ module Mf6FileGridInputModule implicit none private - public :: BoundGridInputType + public :: LayerArrayLoadType - !> @brief Ascii grid based dynamic loader type + !> @brief Ascii array layer dynamic loader type !< - type, extends(AsciiDynamicPkgLoadBaseType) :: BoundGridInputType + type, extends(AsciiDynamicPkgLoadBaseType) :: LayerArrayLoadType integer(I4B) :: tas_active !< Are TAS6 inputs defined type(CharacterStringType), dimension(:), contiguous, & pointer :: aux_tasnames !< array of AUXVAR TAS names @@ -37,28 +38,28 @@ module Mf6FileGridInputModule type(TimeArraySeriesManagerType), pointer :: tasmanager !< TAS manager type(BoundInputContextType) :: bound_context contains - procedure :: ainit => bndgrid_init - procedure :: df => bndgrid_df - procedure :: ad => bndgrid_ad - procedure :: rp => bndgrid_rp - procedure :: destroy => bndgrid_destroy - procedure :: reset => bndgrid_reset + procedure :: ainit + procedure :: df + procedure :: ad + procedure :: rp + procedure :: destroy + procedure :: reset procedure :: init_charstr1d - procedure :: params_alloc => bndgrid_params_alloc - procedure :: param_load => bndgrid_param_load - procedure :: tas_arrays_alloc => bndgrid_tas_arrays_alloc - procedure :: tas_links_create => bndgrid_tas_links_create - end type BoundGridInputType + procedure :: params_alloc + procedure :: param_load + procedure :: tas_arrays_alloc + procedure :: tas_links_create + end type LayerArrayLoadType contains - subroutine bndgrid_init(this, mf6_input, component_name, & - component_input_name, input_name, & - iperblock, parser, iout) + subroutine ainit(this, mf6_input, component_name, & + component_input_name, input_name, & + iperblock, parser, iout) use MemoryManagerModule, only: get_isize use BlockParserModule, only: BlockParserType use LoadMf6FileModule, only: LoadMf6FileType - class(BoundGridInputType), intent(inout) :: this + class(LayerArrayLoadType), intent(inout) :: this type(ModflowInputType), intent(in) :: mf6_input character(len=*), intent(in) :: component_name character(len=*), intent(in) :: component_input_name @@ -103,26 +104,28 @@ subroutine bndgrid_init(this, mf6_input, component_name, & end if ! initialize input context memory - call this%bound_context%create(mf6_input, this%readasarrays) + call this%bound_context%create(mf6_input, & + readarraygrid=.false., & + readarraylayer=.true.) ! allocate dfn params call this%params_alloc() ! allocate memory for storing TAS strings call this%tas_arrays_alloc() - end subroutine bndgrid_init + end subroutine ainit - subroutine bndgrid_df(this) - class(BoundGridInputType), intent(inout) :: this !< Mf6FileGridInputType + subroutine df(this) + class(LayerArrayLoadType), intent(inout) :: this call this%tasmanager%tasmanager_df() - end subroutine bndgrid_df + end subroutine df - subroutine bndgrid_ad(this) - class(BoundGridInputType), intent(inout) :: this !< Mf6FileGridInputType + subroutine ad(this) + class(LayerArrayLoadType), intent(inout) :: this call this%tasmanager%ad() - end subroutine bndgrid_ad + end subroutine ad - subroutine bndgrid_rp(this, parser) + subroutine rp(this, parser) use MemoryManagerModule, only: mem_setptr use BlockParserModule, only: BlockParserType use InputDefinitionModule, only: InputParamDefinitionType @@ -130,7 +133,7 @@ subroutine bndgrid_rp(this, parser) use ArrayHandlersModule, only: ifind use SourceCommonModule, only: ifind_charstr use IdmLoggerModule, only: idm_log_header, idm_log_close, idm_log_var - class(BoundGridInputType), intent(inout) :: this !< Mf6FileGridInputType + class(LayerArrayLoadType), intent(inout) :: this type(BlockParserType), pointer, intent(inout) :: parser logical(LGP) :: endOfBlock, netcdf character(len=LINELENGTH) :: keyword, param_tag @@ -215,19 +218,19 @@ subroutine bndgrid_rp(this, parser) ! log lst file header call idm_log_close(this%mf6_input%component_name, & this%mf6_input%subcomponent_name, this%iout) - end subroutine bndgrid_rp + end subroutine rp - subroutine bndgrid_destroy(this) - class(BoundGridInputType), intent(inout) :: this !< Mf6FileGridInputType + subroutine destroy(this) + class(LayerArrayLoadType), intent(inout) :: this ! ! deallocate tasmanager call this%tasmanager%da() deallocate (this%tasmanager) nullify (this%tasmanager) - end subroutine bndgrid_destroy + end subroutine destroy - subroutine bndgrid_reset(this) - class(BoundGridInputType), intent(inout) :: this !< BoundGridInputType + subroutine reset(this) + class(LayerArrayLoadType), intent(inout) :: this integer(I4B) :: n, m if (this%tas_active /= 0) then @@ -249,11 +252,11 @@ subroutine bndgrid_reset(this) this%bound_context%auxvar(n, m) = DZERO end do end do - end subroutine bndgrid_reset + end subroutine reset subroutine init_charstr1d(this, varname, input_name) use MemoryManagerModule, only: mem_setptr - class(BoundGridInputType) :: this + class(LayerArrayLoadType) :: this character(len=*), intent(in) :: varname character(len=*), intent(in) :: input_name type(CharacterStringType), dimension(:), pointer, & @@ -265,8 +268,8 @@ subroutine init_charstr1d(this, varname, input_name) end do end subroutine init_charstr1d - subroutine bndgrid_params_alloc(this) - class(BoundGridInputType), intent(inout) :: this !< BoundGridInputType + subroutine params_alloc(this) + class(LayerArrayLoadType), intent(inout) :: this character(len=LENVARNAME) :: rs_varname integer(I4B), pointer :: intvar integer(I4B) :: iparam @@ -287,9 +290,9 @@ subroutine bndgrid_params_alloc(this) this%param_reads(iparam)%invar => intvar this%param_reads(iparam)%invar = 0 end do - end subroutine bndgrid_params_alloc + end subroutine params_alloc - subroutine bndgrid_param_load(this, parser, idt, mempath, netcdf, iaux) + subroutine param_load(this, parser, idt, mempath, netcdf, iaux) use TdisModule, only: kper use MemoryManagerModule, only: mem_setptr use ArrayHandlersModule, only: ifind @@ -300,7 +303,7 @@ subroutine bndgrid_param_load(this, parser, idt, mempath, netcdf, iaux) use Integer1dReaderModule, only: read_int1d use LoadNCInputModule, only: netcdf_read_array use IdmLoggerModule, only: idm_log_var - class(BoundGridInputType), intent(inout) :: this !< BoundGridInputType + class(LayerArrayLoadType), intent(inout) :: this type(BlockParserType), intent(in) :: parser type(InputParamDefinitionType), intent(in) :: idt character(len=*), intent(in) :: mempath @@ -348,7 +351,7 @@ subroutine bndgrid_param_load(this, parser, idt, mempath, netcdf, iaux) call idm_log_var(dbl1d, idt%tagname, mempath, this%iout) deallocate (dbl1d) case default - errmsg = 'IDM unimplemented. Mf6FileGridInput::param_load & + errmsg = 'IDM unimplemented. LayerArrayLoad::param_load & &datatype='//trim(idt%datatype) call store_error(errmsg) call store_error_filename(this%input_name) @@ -359,11 +362,11 @@ subroutine bndgrid_param_load(this, parser, idt, mempath, netcdf, iaux) if (iparam > 0) then this%param_reads(iparam)%invar = 1 end if - end subroutine bndgrid_param_load + end subroutine param_load - subroutine bndgrid_tas_arrays_alloc(this) + subroutine tas_arrays_alloc(this) use MemoryManagerModule, only: mem_allocate - class(BoundGridInputType), intent(inout) :: this !< BoundGridInputType + class(LayerArrayLoadType), intent(inout) :: this ! count params other than AUX if (this%tas_active /= 0) then @@ -380,13 +383,13 @@ subroutine bndgrid_tas_arrays_alloc(this) call mem_allocate(this%param_tasnames, LENTIMESERIESNAME, 0, & 'PARAMTASNAME', this%mf6_input%mempath) end if - end subroutine bndgrid_tas_arrays_alloc + end subroutine tas_arrays_alloc ! FLUX and SFAC are handled in model context - subroutine bndgrid_tas_links_create(this, inunit) + subroutine tas_links_create(this, inunit) use InputDefinitionModule, only: InputParamDefinitionType use DefinitionSelectModule, only: get_param_definition_type - class(BoundGridInputType), intent(inout) :: this !< BoundGridInputType + class(LayerArrayLoadType), intent(inout) :: this integer(I4B), intent(in) :: inunit type(InputParamDefinitionType), pointer :: idt ! non-contiguous because a slice of bound is passed @@ -440,6 +443,6 @@ subroutine bndgrid_tas_links_create(this, inunit) end if end if end do - end subroutine bndgrid_tas_links_create + end subroutine tas_links_create -end module Mf6FileGridInputModule +end module LayerArrayLoadModule diff --git a/src/Utilities/Idm/mf6blockfile/Mf6FileListInput.f90 b/src/Utilities/Idm/mf6blockfile/Mf6FileList.f90 similarity index 79% rename from src/Utilities/Idm/mf6blockfile/Mf6FileListInput.f90 rename to src/Utilities/Idm/mf6blockfile/Mf6FileList.f90 index e3906f1d3f5..feb77a7422f 100644 --- a/src/Utilities/Idm/mf6blockfile/Mf6FileListInput.f90 +++ b/src/Utilities/Idm/mf6blockfile/Mf6FileList.f90 @@ -1,17 +1,17 @@ -!> @brief This module contains the Mf6FileListInputModule +!> @brief This module contains the ListLoadModule !! !! This module contains the routines for reading period block !! list based input. !! !< -module Mf6FileListInputModule +module ListLoadModule use KindModule, only: I4B, DP, LGP use ConstantsModule, only: LINELENGTH, LENBOUNDNAME use InputDefinitionModule, only: InputParamDefinitionType use MemoryManagerModule, only: mem_setptr use CharacterStringModule, only: CharacterStringType - use ModflowInputModule, only: ModflowInputType, getModflowInput + use ModflowInputModule, only: ModflowInputType use TimeSeriesManagerModule, only: TimeSeriesManagerType, tsmanager_cr use StructArrayModule, only: StructArrayType, constructStructArray, & destructStructArray @@ -20,7 +20,7 @@ module Mf6FileListInputModule implicit none private - public :: BoundListInputType + public :: ListLoadType !> @brief Boundary package list loader. !! @@ -29,35 +29,35 @@ module Mf6FileListInputModule !! read and prepare (RP) routines. !! !< - type, extends(AsciiDynamicPkgLoadBaseType) :: BoundListInputType + type, extends(AsciiDynamicPkgLoadBaseType) :: ListLoadType type(TimeSeriesManagerType), pointer :: tsmanager => null() type(StructArrayType), pointer :: structarray => null() type(BoundInputContextType) :: bound_context integer(I4B) :: ts_active integer(I4B) :: iboundname contains - procedure :: ainit => bndlist_init - procedure :: df => bndlist_df - procedure :: ad => bndlist_ad - procedure :: reset => bndlist_reset - procedure :: rp => bndlist_rp - procedure :: destroy => bndlist_destroy - procedure :: ts_link_bnd => bndlist_ts_link_bnd - procedure :: ts_link_aux => bndlist_ts_link_aux - procedure :: ts_link => bndlist_ts_link - procedure :: ts_update => bndlist_ts_update - procedure :: create_structarray => bndlist_create_structarray - end type BoundListInputType + procedure :: ainit + procedure :: df + procedure :: ad + procedure :: reset + procedure :: rp + procedure :: destroy + procedure :: ts_link_bnd + procedure :: ts_link_aux + procedure :: ts_link + procedure :: ts_update + procedure :: create_structarray + end type ListLoadType contains - subroutine bndlist_init(this, mf6_input, component_name, component_input_name, & - input_name, iperblock, parser, iout) + subroutine ainit(this, mf6_input, component_name, component_input_name, & + input_name, iperblock, parser, iout) use InputOutputModule, only: getunit use MemoryManagerModule, only: get_isize use BlockParserModule, only: BlockParserType use LoadMf6FileModule, only: LoadMf6FileType - class(BoundListInputType), intent(inout) :: this + class(ListLoadType), intent(inout) :: this type(ModflowInputType), intent(in) :: mf6_input character(len=*), intent(in) :: component_name character(len=*), intent(in) :: component_input_name @@ -98,7 +98,9 @@ subroutine bndlist_init(this, mf6_input, component_name, component_input_name, & end if ! initialize package input context - call this%bound_context%create(mf6_input, this%readasarrays) + call this%bound_context%create(mf6_input, & + readarraygrid=.false., & + readarraylayer=.false.) ! store in scope SA cols for list input call this%bound_context%bound_params(this%param_names, this%nparam, & @@ -108,32 +110,32 @@ subroutine bndlist_init(this, mf6_input, component_name, component_input_name, & ! finalize input context setup call this%bound_context%allocate_arrays() - end subroutine bndlist_init + end subroutine ainit - subroutine bndlist_df(this) - class(BoundListInputType), intent(inout) :: this !< ListInputType + subroutine df(this) + class(ListLoadType), intent(inout) :: this ! define tsmanager call this%tsmanager%tsmanager_df() - end subroutine bndlist_df + end subroutine df - subroutine bndlist_ad(this) - class(BoundListInputType), intent(inout) :: this !< ListInputType + subroutine ad(this) + class(ListLoadType), intent(inout) :: this ! advance timeseries call this%tsmanager%ad() - end subroutine bndlist_ad + end subroutine ad - subroutine bndlist_reset(this) - class(BoundListInputType), intent(inout) :: this !< ListInputType + subroutine reset(this) + class(ListLoadType), intent(inout) :: this ! reset tsmanager call this%tsmanager%reset(this%mf6_input%subcomponent_name) - end subroutine bndlist_reset + end subroutine reset - subroutine bndlist_rp(this, parser) + subroutine rp(this, parser) use BlockParserModule, only: BlockParserType use LoadMf6FileModule, only: read_control_record use StructVectorModule, only: StructVectorType use IdmLoggerModule, only: idm_log_header, idm_log_close - class(BoundListInputType), intent(inout) :: this + class(ListLoadType), intent(inout) :: this type(BlockParserType), pointer, intent(inout) :: parser integer(I4B) :: ibinary integer(I4B) :: oc_inunit @@ -165,10 +167,10 @@ subroutine bndlist_rp(this, parser) ! close logging statement call idm_log_close(this%mf6_input%component_name, & this%mf6_input%subcomponent_name, this%iout) - end subroutine bndlist_rp + end subroutine rp - subroutine bndlist_destroy(this) - class(BoundListInputType), intent(inout) :: this !< BoundListInputType + subroutine destroy(this) + class(ListLoadType), intent(inout) :: this ! ! deallocate tsmanager call this%tsmanager%da() @@ -178,13 +180,13 @@ subroutine bndlist_destroy(this) ! deallocate StructArray call destructStructArray(this%structarray) call this%bound_context%destroy() - end subroutine bndlist_destroy + end subroutine destroy - subroutine bndlist_ts_link_bnd(this, structvector, ts_strloc) + subroutine ts_link_bnd(this, structvector, ts_strloc) use TimeSeriesLinkModule, only: TimeSeriesLinkType use TimeSeriesManagerModule, only: read_value_or_time_series use StructVectorModule, only: StructVectorType, TSStringLocType - class(BoundListInputType), intent(inout) :: this + class(ListLoadType), intent(inout) :: this type(StructVectorType), pointer, intent(in) :: structvector type(TSStringLocType), pointer, intent(in) :: ts_strloc real(DP), pointer :: bndElem @@ -213,13 +215,13 @@ subroutine bndlist_ts_link_bnd(this, structvector, ts_strloc) tsLinkBnd%BndName = boundname end if end if - end subroutine bndlist_ts_link_bnd + end subroutine ts_link_bnd - subroutine bndlist_ts_link_aux(this, structvector, ts_strloc) + subroutine ts_link_aux(this, structvector, ts_strloc) use TimeSeriesLinkModule, only: TimeSeriesLinkType use TimeSeriesManagerModule, only: read_value_or_time_series use StructVectorModule, only: StructVectorType, TSStringLocType - class(BoundListInputType), intent(inout) :: this + class(ListLoadType), intent(inout) :: this type(StructVectorType), pointer, intent(in) :: structvector type(TSStringLocType), pointer, intent(in) :: ts_strloc real(DP), pointer :: bndElem @@ -248,13 +250,13 @@ subroutine bndlist_ts_link_aux(this, structvector, ts_strloc) tsLinkAux%BndName = boundname end if end if - end subroutine bndlist_ts_link_aux + end subroutine ts_link_aux - subroutine bndlist_ts_update(this, structarray) + subroutine ts_update(this, structarray) use SimModule, only: count_errors, store_error_filename use StructVectorModule, only: TSStringLocType use StructVectorModule, only: StructVectorType - class(BoundListInputType), intent(inout) :: this + class(ListLoadType), intent(inout) :: this type(StructArrayType), pointer, intent(inout) :: structarray integer(I4B) :: n, m type(TSStringLocType), pointer :: ts_strloc @@ -275,11 +277,11 @@ subroutine bndlist_ts_update(this, structarray) if (count_errors() > 0) then call store_error_filename(this%input_name) end if - end subroutine bndlist_ts_update + end subroutine ts_update - subroutine bndlist_ts_link(this, structvector, ts_strloc) + subroutine ts_link(this, structvector, ts_strloc) use StructVectorModule, only: StructVectorType, TSStringLocType - class(BoundListInputType), intent(inout) :: this + class(ListLoadType), intent(inout) :: this type(StructVectorType), pointer, intent(in) :: structvector type(TSStringLocType), pointer, intent(in) :: ts_strloc select case (structvector%memtype) @@ -289,12 +291,12 @@ subroutine bndlist_ts_link(this, structvector, ts_strloc) call this%ts_link_aux(structvector, ts_strloc) case default end select - end subroutine bndlist_ts_link + end subroutine ts_link - subroutine bndlist_create_structarray(this) + subroutine create_structarray(this) use InputDefinitionModule, only: InputParamDefinitionType use DefinitionSelectModule, only: get_param_definition_type - class(BoundListInputType), intent(inout) :: this + class(ListLoadType), intent(inout) :: this type(InputParamDefinitionType), pointer :: idt integer(I4B) :: icol @@ -315,6 +317,6 @@ subroutine bndlist_create_structarray(this) ! store boundname index when found if (idt%mf6varname == 'BOUNDNAME') this%iboundname = icol end do - end subroutine bndlist_create_structarray + end subroutine create_structarray -end module Mf6FileListInputModule +end module ListLoadModule diff --git a/src/Utilities/Idm/mf6blockfile/Mf6FileStoInput.f90 b/src/Utilities/Idm/mf6blockfile/Mf6FileStoInput.f90 index 2648724f108..16ed3f780a3 100644 --- a/src/Utilities/Idm/mf6blockfile/Mf6FileStoInput.f90 +++ b/src/Utilities/Idm/mf6blockfile/Mf6FileStoInput.f90 @@ -9,7 +9,7 @@ module Mf6FileStoInputModule use ConstantsModule, only: LINELENGTH use InputDefinitionModule, only: InputParamDefinitionType use MemoryManagerModule, only: mem_setptr, mem_allocate - use ModflowInputModule, only: ModflowInputType, getModflowInput + use ModflowInputModule, only: ModflowInputType use AsciiInputLoadTypeModule, only: AsciiDynamicPkgLoadBaseType implicit none diff --git a/src/Utilities/Idm/netcdf/NCArrayReader.f90 b/src/Utilities/Idm/netcdf/NCArrayReader.f90 index 11119dc32fc..fca3773e302 100644 --- a/src/Utilities/Idm/netcdf/NCArrayReader.f90 +++ b/src/Utilities/Idm/netcdf/NCArrayReader.f90 @@ -56,23 +56,34 @@ subroutine nc_array_load_int1d(int1d, mshape, idt, mf6_input, nc_vars, & type(NCPackageVarsType), pointer, intent(in) :: nc_vars character(len=*), intent(in) :: input_fname integer(I4B), intent(in) :: iout - integer(I4B), optional, intent(in) :: kper - integer(I4B) :: varid + integer(I4B), optional, intent(in) :: kper !< flag if set > 0 indicates ts + integer(I4B) :: varid, iper logical(LGP) :: layered + iper = 0 layered = (idt%layered .and. is_layered(nc_vars%grid)) + if (present(kper)) then + iper = kper + end if + if (layered) then - call load_integer1d_layered(int1d, mf6_input, mshape, idt, nc_vars, & - input_fname) + if (iper > 0) then + call load_integer1d_layered_spd(int1d, mf6_input, mshape, idt, nc_vars, & + iper, input_fname) + else + call load_integer1d_layered(int1d, mf6_input, mshape, idt, nc_vars, & + input_fname) + end if else - if (present(kper)) then - varid = nc_vars%varid(idt%mf6varname, period=kper) + if (iper > 0) then + call load_integer1d_spd(int1d, mf6_input, mshape, idt, nc_vars, & + iper, input_fname) else - varid = nc_vars%varid(idt%mf6varname) + varid = nc_vars%varid(idt%tagname) + call load_integer1d_type(int1d, mf6_input, mshape, idt, nc_vars, & + varid, input_fname) end if - call load_integer1d_type(int1d, mf6_input, mshape, idt, nc_vars, & - varid, input_fname) end if end subroutine nc_array_load_int1d @@ -96,7 +107,7 @@ subroutine nc_array_load_int2d(int2d, mshape, idt, mf6_input, nc_vars, & call load_integer2d_layered(int2d, mf6_input, mshape, idt, nc_vars, & input_fname) else - varid = nc_vars%varid(idt%mf6varname) + varid = nc_vars%varid(idt%tagname) call load_integer2d_type(int2d, mf6_input, mshape, idt, nc_vars, & varid, input_fname) end if @@ -122,7 +133,7 @@ subroutine nc_array_load_int3d(int3d, mshape, idt, mf6_input, nc_vars, & call load_integer3d_layered(int3d, mf6_input, mshape, idt, nc_vars, & input_fname) else - varid = nc_vars%varid(idt%mf6varname) + varid = nc_vars%varid(idt%tagname) call load_integer3d_type(int3d, mf6_input, mshape, idt, nc_vars, & varid, input_fname) end if @@ -139,31 +150,32 @@ subroutine nc_array_load_dbl1d(dbl1d, mshape, idt, mf6_input, nc_vars, & type(NCPackageVarsType), pointer, intent(in) :: nc_vars character(len=*), intent(in) :: input_fname integer(I4B), intent(in) :: iout - integer(I4B), optional, intent(in) :: kper + integer(I4B), optional, intent(in) :: kper !< flag if set > 0 indicates ts integer(I4B), optional, intent(in) :: iaux - integer(I4B) :: varid + integer(I4B) :: varid, iper logical(LGP) :: layered + iper = 0 + layered = (idt%layered .and. is_layered(nc_vars%grid)) + if (present(kper)) then - layered = (kper > 0 .and. is_layered(nc_vars%grid)) - else - layered = (idt%layered .and. is_layered(nc_vars%grid)) + iper = kper end if if (layered) then - if (present(kper)) then + if (iper > 0) then call load_double1d_layered_spd(dbl1d, mf6_input, mshape, idt, nc_vars, & - kper, input_fname, iaux) + iper, input_fname, iaux) else call load_double1d_layered(dbl1d, mf6_input, mshape, idt, nc_vars, & input_fname) end if else - if (present(kper)) then + if (iper > 0) then call load_double1d_spd(dbl1d, mf6_input, mshape, idt, nc_vars, & - kper, input_fname, iaux) + iper, input_fname, iaux) else - varid = nc_vars%varid(idt%mf6varname) + varid = nc_vars%varid(idt%tagname) call load_double1d_type(dbl1d, mf6_input, mshape, idt, nc_vars, & varid, input_fname) end if @@ -190,7 +202,7 @@ subroutine nc_array_load_dbl2d(dbl2d, mshape, idt, mf6_input, nc_vars, & call load_double2d_layered(dbl2d, mf6_input, mshape, idt, nc_vars, & input_fname) else - varid = nc_vars%varid(idt%mf6varname) + varid = nc_vars%varid(idt%tagname) call load_double2d_type(dbl2d, mf6_input, mshape, idt, nc_vars, & varid, input_fname) end if @@ -216,7 +228,7 @@ subroutine nc_array_load_dbl3d(dbl3d, mshape, idt, mf6_input, nc_vars, & call load_double3d_layered(dbl3d, mf6_input, mshape, idt, nc_vars, & input_fname) else - varid = nc_vars%varid(idt%mf6varname) + varid = nc_vars%varid(idt%tagname) call load_double3d_type(dbl3d, mf6_input, mshape, idt, nc_vars, & varid, input_fname) end if @@ -265,6 +277,54 @@ subroutine load_integer1d_type(int1d, mf6_input, mshape, idt, nc_vars, & end if end subroutine load_integer1d_type + !> @brief load type 1d double + !< + subroutine load_integer1d_spd(int1d, mf6_input, mshape, idt, nc_vars, & + iper, input_fname) + use ConstantsModule, only: DNODATA + use NetCDFCommonModule, only: ixstp + integer(I4B), dimension(:), contiguous, pointer, intent(in) :: int1d + type(ModflowInputType), intent(in) :: mf6_input + integer(I4B), dimension(:), contiguous, pointer, intent(in) :: mshape + type(InputParamDefinitionType), intent(in) :: idt + type(NCPackageVarsType), pointer, intent(in) :: nc_vars + integer(I4B), intent(in) :: iper + character(len=*), intent(in) :: input_fname + integer(I4B), dimension(:), allocatable :: layer_shape + integer(I4B) :: varid, nlay, ncpl, istp + + istp = ixstp() + + ! set varid + varid = nc_vars%varid(idt%tagname) + + call get_layered_shape(mshape, nlay, layer_shape) + ncpl = product(layer_shape) + + if (size(mshape) == 3) then + select case (idt%shape) + case ('NCPL', 'NAUX NCPL') + if (nc_vars%grid == 'STRUCTURED') then + call nf_verify(nf90_get_var(nc_vars%ncid, varid, int1d, & + start=(/1, 1, istp/), & + count=(/mshape(3), mshape(2), 1/)), & + nc_vars%nc_fname) + else if (nc_vars%grid == 'LAYERED MESH') then + call nf_verify(nf90_get_var(nc_vars%ncid, varid, int1d, & + start=(/1, istp/), count=(/ncpl, 1/)), & + nc_vars%nc_fname) + end if + case ('NODES', 'NAUX NODES') + write (errmsg, '(a,a,a)') & + 'Timeseries netcdf input read not supported for DIS full grid int1d & + &type ('//trim(idt%tagname)//').' + call store_error(errmsg) + call store_error_filename(input_fname) + case default + end select + end if + end subroutine load_integer1d_spd + !> @brief load type 1d integer layered !< subroutine load_integer1d_layered(int1d, mf6_input, mshape, idt, nc_vars, & @@ -288,7 +348,7 @@ subroutine load_integer1d_layered(int1d, mf6_input, mshape, idt, nc_vars, & ncpl = product(layer_shape) index_start = 1 do k = 1, nlay - varid = nc_vars%varid(idt%mf6varname, layer=k) + varid = nc_vars%varid(idt%tagname, layer=k) index_stop = index_start + ncpl - 1 int1d_ptr(1:ncpl) => int1d(index_start:index_stop) call nf_verify(nf90_get_var(nc_vars%ncid, varid, int1d_ptr), & @@ -297,6 +357,43 @@ subroutine load_integer1d_layered(int1d, mf6_input, mshape, idt, nc_vars, & end do end subroutine load_integer1d_layered + !> @brief load type 1d integer layered + !< + subroutine load_integer1d_layered_spd(int1d, mf6_input, mshape, idt, nc_vars, & + iper, input_fname) + use ConstantsModule, only: DNODATA + use NetCDFCommonModule, only: ixstp + integer(I4B), dimension(:), contiguous, pointer, intent(in) :: int1d + type(ModflowInputType), intent(in) :: mf6_input + integer(I4B), dimension(:), contiguous, pointer, intent(in) :: mshape + type(InputParamDefinitionType), intent(in) :: idt + type(NCPackageVarsType), pointer, intent(in) :: nc_vars + integer(I4B), intent(in) :: iper + character(len=*), intent(in) :: input_fname + integer(I4B), dimension(:), allocatable :: layer_shape + integer(I4B) :: nlay, varid + integer(I4B) :: ncpl, nvals, istp + + istp = ixstp() + + call get_layered_shape(mshape, nlay, layer_shape) + nvals = product(mshape) + ncpl = product(layer_shape) + + varid = nc_vars%varid(idt%tagname) + select case (idt%shape) + case ('NCPL', 'NAUX NCPL') + call nf_verify(nf90_get_var(nc_vars%ncid, varid, int1d, & + start=(/1, istp/), count=(/ncpl, 1/)), & + nc_vars%nc_fname) + case ('NODES', 'NAUX NODES') + call nf_verify(nf90_get_var(nc_vars%ncid, varid, int1d, & + start=(/1, istp/), count=(/nvals, 1/)), & + nc_vars%nc_fname) + case default + end select + end subroutine load_integer1d_layered_spd + !> @brief load type 2d integer !< subroutine load_integer2d_type(int2d, mf6_input, mshape, idt, nc_vars, varid, & @@ -352,7 +449,7 @@ subroutine load_integer2d_layered(int2d, mf6_input, mshape, idt, nc_vars, & call get_layered_shape(mshape, nlay, layer_shape) ncpl = layer_shape(1) do k = 1, nlay - varid = nc_vars%varid(idt%mf6varname, layer=k) + varid = nc_vars%varid(idt%tagname, layer=k) int1d_ptr(1:ncpl) => int2d(1:ncpl, k) call nf_verify(nf90_get_var(nc_vars%ncid, varid, int1d_ptr), & nc_vars%nc_fname) @@ -396,7 +493,7 @@ subroutine load_integer3d_layered(int3d, mf6_input, mshape, idt, nc_vars, & ncpl = product(layer_shape) do k = 1, nlay - varid = nc_vars%varid(idt%mf6varname, layer=k) + varid = nc_vars%varid(idt%tagname, layer=k) index_stop = index_start + ncpl - 1 int1d_ptr(1:ncpl) => int3d(:, :, k:k) call nf_verify(nf90_get_var(nc_vars%ncid, varid, int1d_ptr), & @@ -453,6 +550,7 @@ end subroutine load_double1d_type subroutine load_double1d_spd(dbl1d, mf6_input, mshape, idt, nc_vars, & iper, input_fname, iaux) use ConstantsModule, only: DNODATA + use NetCDFCommonModule, only: ixstp real(DP), dimension(:), contiguous, pointer, intent(in) :: dbl1d type(ModflowInputType), intent(in) :: mf6_input integer(I4B), dimension(:), contiguous, pointer, intent(in) :: mshape @@ -461,57 +559,53 @@ subroutine load_double1d_spd(dbl1d, mf6_input, mshape, idt, nc_vars, & integer(I4B), intent(in) :: iper character(len=*), intent(in) :: input_fname integer(I4B), optional, intent(in) :: iaux + integer(I4B), dimension(:), allocatable :: layer_shape real(DP), dimension(:, :, :), contiguous, pointer :: dbl3d - integer(I4B) :: nvals, varid - integer(I4B) :: n, i, j, k + integer(I4B) :: varid, nlay, ncpl, nvals + integer(I4B) :: n, istp ! initialize - nvals = 0 + n = 0 + istp = ixstp() ! set varid if (present(iaux)) then - varid = nc_vars%varid(idt%mf6varname, period=iper, iaux=iaux) + varid = nc_vars%varid(idt%tagname, iaux=iaux) else - varid = nc_vars%varid(idt%mf6varname, period=iper) + varid = nc_vars%varid(idt%tagname) end if - if (idt%shape == 'NODES') then - ! TODO future support - write (errmsg, '(a)') & - 'IDM NetCDF load_double1d_spd NODES var shape not supported => '// & - trim(idt%tagname) - call store_error(errmsg) - call store_error_filename(input_fname) - else if (idt%shape == 'NCPL' .or. idt%shape == 'NAUX NCPL') then - - if (size(mshape) == 3) then - allocate (dbl3d(mshape(3), mshape(2), mshape(1))) - call nf_verify(nf90_get_var(nc_vars%ncid, varid, dbl3d), & - nc_vars%nc_fname) - n = 0 - do k = 1, size(dbl3d, dim=3) - do i = 1, size(dbl3d, dim=2) - do j = 1, size(dbl3d, dim=1) - if (n < size(dbl1d)) then - n = n + 1 - else - n = 1 - end if - if (dbl3d(j, i, k) /= DNODATA) then - dbl1d(n) = dbl3d(j, i, k) - end if - end do - end do - end do + call get_layered_shape(mshape, nlay, layer_shape) + ncpl = product(layer_shape) + nvals = product(mshape) - else if (size(mshape) == 2) then - ! TODO - write (errmsg, '(a)') & - 'IDM NetCDF load_double1d_spd DISV model not supported => '// & - trim(idt%tagname) - call store_error(errmsg) - call store_error_filename(input_fname) - end if + if (size(mshape) == 3) then + select case (idt%shape) + case ('NCPL', 'NAUX NCPL') + if (nc_vars%grid == 'STRUCTURED') then + call nf_verify(nf90_get_var(nc_vars%ncid, varid, dbl1d, & + start=(/1, 1, istp/), & + count=(/mshape(3), mshape(2), 1/)), & + nc_vars%nc_fname) + else if (nc_vars%grid == 'LAYERED MESH') then + call nf_verify(nf90_get_var(nc_vars%ncid, varid, dbl1d, & + start=(/1, istp/), count=(/ncpl, 1/)), & + nc_vars%nc_fname) + end if + case ('NODES', 'NAUX NODES') + if (nc_vars%grid == 'STRUCTURED') then + dbl3d(1:mshape(3), 1:mshape(2), 1:mshape(1)) => dbl1d(1:nvals) + call nf_verify(nf90_get_var(nc_vars%ncid, varid, dbl3d, & + start=(/1, 1, 1, istp/), & + count=(/mshape(3), mshape(2), mshape(1), & + 1/)), nc_vars%nc_fname) + else if (nc_vars%grid == 'LAYERED MESH') then + call nf_verify(nf90_get_var(nc_vars%ncid, varid, dbl1d, & + start=(/1, istp/), count=(/nvals, 1/)), & + nc_vars%nc_fname) + end if + case default + end select end if end subroutine load_double1d_spd @@ -537,7 +631,7 @@ subroutine load_double1d_layered(dbl1d, mf6_input, mshape, idt, nc_vars, & ncpl = product(layer_shape) do k = 1, nlay - varid = nc_vars%varid(idt%mf6varname, layer=k) + varid = nc_vars%varid(idt%tagname, layer=k) index_stop = index_start + ncpl - 1 dbl1d_ptr(1:ncpl) => dbl1d(index_start:index_stop) call nf_verify(nf90_get_var(nc_vars%ncid, varid, dbl1d_ptr), & @@ -551,6 +645,7 @@ end subroutine load_double1d_layered subroutine load_double1d_layered_spd(dbl1d, mf6_input, mshape, idt, nc_vars, & iper, input_fname, iaux) use ConstantsModule, only: DNODATA + use NetCDFCommonModule, only: ixstp real(DP), dimension(:), contiguous, pointer, intent(in) :: dbl1d type(ModflowInputType), intent(in) :: mf6_input integer(I4B), dimension(:), contiguous, pointer, intent(in) :: mshape @@ -561,29 +656,34 @@ subroutine load_double1d_layered_spd(dbl1d, mf6_input, mshape, idt, nc_vars, & integer(I4B), optional, intent(in) :: iaux integer(I4B), dimension(:), allocatable :: layer_shape integer(I4B) :: nlay, varid - integer(I4B) :: k, n, ncpl - integer(I4B) :: index_start, index_stop + integer(I4B) :: k, n, ncpl, idx, istp real(DP), dimension(:), contiguous, pointer :: dbl1d_ptr + istp = ixstp() + call get_layered_shape(mshape, nlay, layer_shape) ncpl = product(layer_shape) allocate (dbl1d_ptr(ncpl)) do k = 1, nlay - index_start = 1 - index_stop = index_start + ncpl - 1 if (present(iaux)) then - varid = nc_vars%varid(idt%mf6varname, layer=k, period=iper, iaux=iaux) + varid = nc_vars%varid(idt%tagname, layer=k, iaux=iaux) else - varid = nc_vars%varid(idt%mf6varname, layer=k, period=iper) + varid = nc_vars%varid(idt%tagname, layer=k) end if - call nf_verify(nf90_get_var(nc_vars%ncid, varid, dbl1d_ptr), & + call nf_verify(nf90_get_var(nc_vars%ncid, varid, dbl1d_ptr, & + start=(/1, istp/), count=(/ncpl, 1/)), & nc_vars%nc_fname) - do n = 1, ncpl - if (dbl1d_ptr(n) /= DNODATA) then + if (idt%shape == 'NODES' .or. idt%shape == 'NAUX NODES') then + do n = 1, ncpl + idx = (k - 1) * ncpl + n + dbl1d(idx) = dbl1d_ptr(n) + end do + else if (idt%shape == 'NCPL' .or. idt%shape == 'NAUX NCPL') then + do n = 1, ncpl dbl1d(n) = dbl1d_ptr(n) - end if - end do + end do + end if end do ! cleanup @@ -645,7 +745,7 @@ subroutine load_double2d_layered(dbl2d, mf6_input, mshape, idt, nc_vars, & call get_layered_shape(mshape, nlay, layer_shape) ncpl = layer_shape(1) do k = 1, nlay - varid = nc_vars%varid(idt%mf6varname, layer=k) + varid = nc_vars%varid(idt%tagname, layer=k) dbl1d_ptr(1:ncpl) => dbl2d(1:ncpl, k) call nf_verify(nf90_get_var(nc_vars%ncid, varid, dbl1d_ptr), & nc_vars%nc_fname) @@ -691,7 +791,7 @@ subroutine load_double3d_layered(dbl3d, mf6_input, mshape, idt, nc_vars, & ncpl = product(layer_shape) index_start = 1 do k = 1, nlay - varid = nc_vars%varid(idt%mf6varname, layer=k) + varid = nc_vars%varid(idt%tagname, layer=k) index_stop = index_start + ncpl - 1 dbl1d_ptr(1:ncpl) => dbl3d(:, :, k:k) call nf_verify(nf90_get_var(nc_vars%ncid, varid, dbl1d_ptr), & diff --git a/src/Utilities/Idm/netcdf/NCContextBuild.f90 b/src/Utilities/Idm/netcdf/NCContextBuild.f90 index 72127e2d3c3..eaae5a420ce 100644 --- a/src/Utilities/Idm/netcdf/NCContextBuild.f90 +++ b/src/Utilities/Idm/netcdf/NCContextBuild.f90 @@ -8,8 +8,8 @@ module NCContextBuildModule use KindModule, only: DP, I4B, LGP use ConstantsModule, only: LINELENGTH, LENCOMPONENTNAME - use SimModule, only: store_error, store_error_filename - use SimVariablesModule, only: errmsg + use SimModule, only: store_error, store_warning, store_error_filename + use SimVariablesModule, only: errmsg, warnmsg use NCFileVarsModule, only: NCFileVarsType use NetCDFCommonModule, only: nf_verify, NETCDF_ATTR_STRLEN use netcdf @@ -63,19 +63,18 @@ subroutine add_package_var(modeltype, modelname, nc_vars, input_name, varid, & character(len=NETCDF_ATTR_STRLEN) :: input_str character(len=LENCOMPONENTNAME) :: c_name, sc_name character(len=LINELENGTH) :: mempath, varname - integer(I4B) :: layer, period, iaux, mf6_layer, mf6_period, mf6_iaux + integer(I4B) :: layer, iaux, mf6_layer, mf6_iaux logical(LGP) :: success ! initialize layer = -1 - period = -1 iaux = -1 varname = '' c_name = '' sc_name = '' ! process mf6_input attribute - if (nf90_get_att(nc_vars%ncid, varid, 'modflow6_input', & + if (nf90_get_att(nc_vars%ncid, varid, 'modflow_input', & input_str) == NF90_NOERR) then ! mf6_input should provide a memory address call split_mem_address(input_str, mempath, varname, success) @@ -89,26 +88,20 @@ subroutine add_package_var(modeltype, modelname, nc_vars, input_name, varid, & call upcase(sc_name) ! check for optional layer attribute if (nf90_get_att(nc_vars%ncid, varid, & - 'modflow6_layer', mf6_layer) == NF90_NOERR) then + 'layer', mf6_layer) == NF90_NOERR) then layer = mf6_layer end if - ! check for optional period attribute + ! check for optional iaux attribute if (nf90_get_att(nc_vars%ncid, varid, & - 'modflow6_iper', mf6_period) == NF90_NOERR) then - period = mf6_period - end if - - ! check for optional period attribute - if (nf90_get_att(nc_vars%ncid, varid, & - 'modflow6_iaux', mf6_iaux) == NF90_NOERR) then + 'modflow_iaux', mf6_iaux) == NF90_NOERR) then iaux = mf6_iaux end if ! add the variable to netcdf description - call nc_vars%add(sc_name, varname, layer, period, iaux, varid) + call nc_vars%add(sc_name, varname, layer, iaux, varid) else - errmsg = 'NetCDF variable invalid modflow6_input attribute: "'// & + errmsg = 'NetCDF variable invalid modflow_input attribute: "'// & trim(input_str)//'".' call store_error(errmsg) call store_error_filename(nc_vars%nc_fname) @@ -119,23 +112,42 @@ end subroutine add_package_var !> @brief verify global attribute modflow_grid is present and return value !< function verify_global_attr(modeltype, modelname, input_name, nc_fname, ncid) & - result(grid) + result(nctype) use InputOutputModule, only: lowcase, upcase character(len=*), intent(in) :: modeltype character(len=*), intent(in) :: modelname character(len=*), intent(in) :: input_name character(len=*), intent(in) :: nc_fname integer(I4B), intent(in) :: ncid - character(len=NETCDF_ATTR_STRLEN) :: grid + character(len=NETCDF_ATTR_STRLEN) :: grid, mesh, nctype ! initialize grid grid = '' + mesh = '' + nctype = '' ! verify expected mf6_modeltype file attribute if (nf90_get_att(ncid, NF90_GLOBAL, "modflow_grid", & grid) == NF90_NOERR) then - ! set grid to upper case call upcase(grid) + if (nf90_get_att(ncid, NF90_GLOBAL, "mesh", & + mesh) == NF90_NOERR) then + call upcase(mesh) + if (mesh == 'LAYERED') then + nctype = 'LAYERED MESH' + else + errmsg = 'NetCDF unsupported mesh type: "'//trim(mesh)//'".' + call store_error(errmsg) + call store_error_filename(nc_fname) + end if + else if (grid == 'STRUCTURED') then + nctype = 'STRUCTURED' + else if (grid == 'VERTEX' .or. grid == 'LAYERED MESH') then + warnmsg = 'Verify "modflow_grid" and "mesh" global & + &attributes in file: '//trim(nc_fname) + call store_warning(warnmsg) + nctype = 'LAYERED MESH' + end if else errmsg = 'NetCDF input file global attribute "modflow_grid" not found.' call store_error(errmsg) diff --git a/src/Utilities/Idm/netcdf/NCFileVars.f90 b/src/Utilities/Idm/netcdf/NCFileVars.f90 index a7cee0273d1..cfb32af5ada 100644 --- a/src/Utilities/Idm/netcdf/NCFileVars.f90 +++ b/src/Utilities/Idm/netcdf/NCFileVars.f90 @@ -37,7 +37,6 @@ module NCFileVarsModule character(LINELENGTH) :: pkgname !< package name character(LINELENGTH) :: tagname !< tag name integer(I4B) :: layer !< variable layer - integer(I4B) :: period !< variable period integer(I4B) :: iaux !< variable aux index integer(I4B) :: varid !< NC file variable id contains @@ -70,11 +69,10 @@ end subroutine ncvars_init !> @brief return a netcdf variable id for a package tagname !< - function ncvars_varid(this, tagname, layer, period, iaux) result(varid) + function ncvars_varid(this, tagname, layer, iaux) result(varid) class(NCPackageVarsType) :: this character(len=*), intent(in) :: tagname integer(I4B), optional :: layer - integer(I4B), optional :: period integer(I4B), optional :: iaux integer(I4B) :: varid integer(I4B) :: n, l, p, a @@ -91,10 +89,6 @@ function ncvars_varid(this, tagname, layer, period, iaux) result(varid) l = layer end if - ! set search period if provided - if (present(period)) then - p = period - end if ! set search iaux if provided if (present(iaux)) then a = iaux @@ -104,7 +98,6 @@ function ncvars_varid(this, tagname, layer, period, iaux) result(varid) nc_var => ncvar_get(this%nc_vars, n) if (nc_var%tagname == tagname .and. & nc_var%layer == l .and. & - nc_var%period == p .and. & nc_var%iaux == a) then varid = nc_var%varid end if @@ -116,10 +109,7 @@ function ncvars_varid(this, tagname, layer, period, iaux) result(varid) write (errmsg, '(a)') & 'NetCDF variable not found, tagname="'//trim(tagname)//'"' if (present(layer)) then - write (errmsg, '(a,i0)') trim(errmsg)//', ilayer=', layer - end if - if (present(period)) then - write (errmsg, '(a,i0)') trim(errmsg)//', period=', period + write (errmsg, '(a,i0)') trim(errmsg)//', layer=', layer end if if (present(iaux)) then write (errmsg, '(a,i0)') trim(errmsg)//', iaux=', iaux @@ -185,13 +175,12 @@ end subroutine fv_init !> @brief add netcdf modflow6 input variable to list !< - subroutine fv_add(this, pkgname, tagname, layer, period, iaux, varid) + subroutine fv_add(this, pkgname, tagname, layer, iaux, varid) use ArrayHandlersModule, only: expandarray class(NCFileVarsType) :: this character(len=*), intent(in) :: pkgname character(len=*), intent(in) :: tagname integer(I4B), intent(in) :: layer - integer(I4B), intent(in) :: period integer(I4B), intent(in) :: iaux integer(I4B), intent(in) :: varid class(NCFileMf6VarType), pointer :: invar @@ -201,7 +190,6 @@ subroutine fv_add(this, pkgname, tagname, layer, period, iaux, varid) invar%pkgname = pkgname invar%tagname = tagname invar%layer = layer - invar%period = period invar%iaux = iaux invar%varid = varid obj => invar @@ -241,7 +229,6 @@ subroutine create_varlists(this, modelname, pkgname, nc_vars) nc_var%pkgname = invar%pkgname nc_var%tagname = invar%tagname nc_var%layer = invar%layer - nc_var%period = invar%period nc_var%iaux = invar%iaux nc_var%varid = invar%varid obj => nc_var diff --git a/src/Utilities/Idm/netcdf/NetCDFCommon.f90 b/src/Utilities/Idm/netcdf/NetCDFCommon.f90 index 42bf9953d3a..077011652f9 100644 --- a/src/Utilities/Idm/netcdf/NetCDFCommon.f90 +++ b/src/Utilities/Idm/netcdf/NetCDFCommon.f90 @@ -17,6 +17,7 @@ module NetCDFCommonModule public :: NETCDF_MAX_DIM public :: NETCDF_ATTR_STRLEN public :: nf_verify + public :: ixstp integer(I4B), parameter :: NETCDF_MAX_DIM = 6 integer(I4B), parameter :: NETCDF_ATTR_STRLEN = 80 @@ -107,4 +108,17 @@ subroutine nf_verify(res, nc_fname) end if end subroutine nf_verify + !> @brief step index for timeseries data + !< + function ixstp() + use TdisModule, only: kstp, kper, nstp + integer(I4B) :: n, ixstp + ixstp = kstp + if (kper > 1) then + do n = 1, kper - 1 + ixstp = ixstp + nstp(n) + end do + end if + end function ixstp + end module NetCDFCommonModule diff --git a/src/meson.build b/src/meson.build index a2a43008cbd..55d80a403a6 100644 --- a/src/meson.build +++ b/src/meson.build @@ -65,6 +65,7 @@ modflow_sources = files( 'Idm' / 'gwf-evtidm.f90', 'Idm' / 'gwf-evtaidm.f90', 'Idm' / 'gwf-ghbidm.f90', + 'Idm' / 'gwf-ghbgidm.f90', 'Idm' / 'gwf-icidm.f90', 'Idm' / 'gwf-namidm.f90', 'Idm' / 'gwf-npfidm.f90', @@ -341,8 +342,9 @@ modflow_sources = files( 'Utilities' / 'Idm' / 'mf6blockfile' / 'AsciiInputLoadType.f90', 'Utilities' / 'Idm' / 'mf6blockfile' / 'IdmMf6File.f90', 'Utilities' / 'Idm' / 'mf6blockfile' / 'LoadMf6File.f90', - 'Utilities' / 'Idm' / 'mf6blockfile' / 'Mf6FileGridInput.f90', - 'Utilities' / 'Idm' / 'mf6blockfile' / 'Mf6FileListInput.f90', + 'Utilities' / 'Idm' / 'mf6blockfile' / 'Mf6FileGridArray.f90', + 'Utilities' / 'Idm' / 'mf6blockfile' / 'Mf6FileLayerArray.f90', + 'Utilities' / 'Idm' / 'mf6blockfile' / 'Mf6FileList.f90', 'Utilities' / 'Idm' / 'mf6blockfile' / 'Mf6FileStoInput.f90', 'Utilities' / 'Idm' / 'mf6blockfile' / 'LoadNCInput.F90', 'Utilities' / 'Idm' / 'mf6blockfile' / 'StructArray.f90', diff --git a/utils/idmloader/dfns.txt b/utils/idmloader/dfns.txt index 13737805a86..dd441d657fb 100644 --- a/utils/idmloader/dfns.txt +++ b/utils/idmloader/dfns.txt @@ -9,6 +9,7 @@ gwf-drn.dfn gwf-evt.dfn gwf-evta.dfn gwf-ghb.dfn +gwf-ghbg.dfn gwf-ic.dfn gwf-npf.dfn gwf-rch.dfn diff --git a/utils/idmloader/scripts/dfn2f90.py b/utils/idmloader/scripts/dfn2f90.py index acf7bec1749..e28c12f7ed5 100644 --- a/utils/idmloader/scripts/dfn2f90.py +++ b/utils/idmloader/scripts/dfn2f90.py @@ -366,13 +366,13 @@ def _set_blk_param_strs(self, blockname, component, subcomponent): shape = shape.replace(")", "") shape = shape.replace(",", "") shape = shape.upper() - if shape == "NCOL*NROW; NCPL": - # grid array input syntax - if mf6vn == "AUXVAR": - # for grid, set AUX as DOUBLE2D + if mf6vn == "AUXVAR": + if shape == "NCOL*NROW; NCPL": shape = "NAUX NCPL" - else: - shape = "NCPL" + elif shape == "NODES": + shape = "NAUX NODES" + elif shape == "NCOL*NROW; NCPL": + shape = "NCPL" shapelist = shape.strip().split() ndim = len(shapelist)