Accessing MODFLOW 6 Output

This tutorial shows how to access output from MODFLOW 6 models and packages by using the built in .output attribute on any MODFLOW 6 model or package object

[1]:
# ## Package import
import flopy
import os
import platform
import numpy as np
[2]:
# ## Load a simple demonstration model
exe_name = "mf6"
if platform.system().lower() == "windows":
    exe_name += ".exe"
ws = os.path.abspath(os.path.dirname(""))
if os.path.split(ws)[-1] == "modflow6output":
    sim_ws = os.path.join(ws, "..", "..", "data", "mf6", "test001e_UZF_3lay")
else:
    sim_ws = os.path.join(
        ws, "..", "..", "examples", "data", "mf6", "test001e_UZF_3lay"
    )
# load the model
sim = flopy.mf6.MFSimulation.load(
    sim_ws=sim_ws, exe_name=exe_name, verbosity_level=0,
)
# change the simulation path, rewrite the files, and run the model
sim_ws = os.path.join("..", "..", "..", "autotest", "temp")
sim.set_sim_path(sim_ws)
sim.write_simulation(silent=True)
sim.run_simulation(silent=True)
[2]:
(True, [])

Get output using the .output attribute

The output attribute dynamically generates methods for each package based on the available output options within that package. A list of all available outputs are:

head() Method to get the HeadFile object for the model. Accessed from the model object or the OC package object
budget() Method to get the CellBudgetFile object for the model. Accessed from the model object or the OC package object
zonebudget() Method to get the ZoneBudget6 object for the model. Accessed from the model object or the OC package object
obs() Method to get observation file data in the form of a MF6Obs object. Accessed from any package that allows observations.
csv() Method to get csv output data in the form of a CsvFile object. Example files are inner and outer iteration files from IMS
package_convergence() Method to get csv based package convergence information from packages such as SFR, LAK, UZF, and MAW. Returns a CsvFile object
stage() Method to get binary stage file output from the SFR and LAK packages
concentration() Method to get the binary concentration file output from a groundwater transport model. Accessed from the model object or the OC package object
cim() Method to get immobile concentration output from the CIM package
density() Method to get density file output from the BUY package

Get head file and cell budget file outputs

The head file output and cell budget file output can be loaded from either the model object or the OC package object.

[3]:
ml = sim.get_model("gwf_1")
[4]:
bud = ml.output.budget()
bud.get_data(idx=0, full3D=True)
[4]:
[array([[[ 0.,  0.,  0.,  0., -0.,  0.,  0.,  0., -0.,  0.,  0.,  0.,
          -0.,  0.,  0.,  0., -0.,  0.,  0.,  0., -0.,  0.,  0.,  0.,
          -0.,  0.,  0.,  0., -0.,  0.,  0.,  0., -0.,  0.,  0.,  0.,
          -0.,  0.,  0., -0.,  0.,  0.,  0., -0., -0.,  0.,  0.,  0.,
          -0., -0.,  0.,  0.,  0., -0., -0.,  0.,  0.,  0., -0., -0.,
           0.,  0.,  0., -0., -0.,  0.,  0.,  0., -0., -0.,  0.,  0.,
           0., -0., -0.,  0.,  0.,  0., -0., -0.,  0.,  0.,  0., -0.,
          -0.,  0.,  0., -0.,  0.,  0., -0., -0.,  0.,  0., -0., -0.,
           0.,  0., -0., -0.,  0.,  0., -0., -0.,  0.,  0., -0., -0.,
           0.,  0., -0., -0.,  0.,  0., -0., -0.,  0.,  0., -0., -0.,
           0.,  0., -0., -0.]]])]
[5]:
hds = ml.output.head()
hds.get_data()
[5]:
array([[[-25.        , -24.93660487, -24.88816332, -24.85548043,
         -24.83902108, -24.83902108, -24.85548043, -24.88816332,
         -24.93660487, -25.        ]],

       [[-25.        , -24.93660487, -24.88816332, -24.85548043,
         -24.83902108, -24.83902108, -24.85548043, -24.88816332,
         -24.93660487, -25.        ]],

       [[-25.        , -24.93660487, -24.88816332, -24.85548043,
         -24.83902108, -24.83902108, -24.85548043, -24.88816332,
         -24.93660487, -25.        ]]])
[6]:
bud = ml.oc.output.budget()
bud.get_data(idx=0, full3D=True)
[6]:
[array([[[ 0.,  0.,  0.,  0., -0.,  0.,  0.,  0., -0.,  0.,  0.,  0.,
          -0.,  0.,  0.,  0., -0.,  0.,  0.,  0., -0.,  0.,  0.,  0.,
          -0.,  0.,  0.,  0., -0.,  0.,  0.,  0., -0.,  0.,  0.,  0.,
          -0.,  0.,  0., -0.,  0.,  0.,  0., -0., -0.,  0.,  0.,  0.,
          -0., -0.,  0.,  0.,  0., -0., -0.,  0.,  0.,  0., -0., -0.,
           0.,  0.,  0., -0., -0.,  0.,  0.,  0., -0., -0.,  0.,  0.,
           0., -0., -0.,  0.,  0.,  0., -0., -0.,  0.,  0.,  0., -0.,
          -0.,  0.,  0., -0.,  0.,  0., -0., -0.,  0.,  0., -0., -0.,
           0.,  0., -0., -0.,  0.,  0., -0., -0.,  0.,  0., -0., -0.,
           0.,  0., -0., -0.,  0.,  0., -0., -0.,  0.,  0., -0., -0.,
           0.,  0., -0., -0.]]])]
[7]:
hds = ml.oc.output.head()
hds.get_data()
[7]:
array([[[-25.        , -24.93660487, -24.88816332, -24.85548043,
         -24.83902108, -24.83902108, -24.85548043, -24.88816332,
         -24.93660487, -25.        ]],

       [[-25.        , -24.93660487, -24.88816332, -24.85548043,
         -24.83902108, -24.83902108, -24.85548043, -24.88816332,
         -24.93660487, -25.        ]],

       [[-25.        , -24.93660487, -24.88816332, -24.85548043,
         -24.83902108, -24.83902108, -24.85548043, -24.88816332,
         -24.93660487, -25.        ]]])

Get output associated with a specific package

The .output attribute is tied to the package object and allows the user to get the output types specified in the MODFLOW 6 package. Here is an example with a UZF package that has UZF budget file output, package convergence output, and observation data.

[8]:
uzf = ml.uzf
uzf_bud = uzf.output.budget()
uzf_bud.get_data(idx=0)
[8]:
[rec.array([( 1,  9,  0., 100000.), ( 9,  1, -0., 100000.),
            ( 2, 10,  0., 100000.), (10,  2, -0., 100000.),
            ( 3, 11,  0., 100000.), (11,  3, -0., 100000.),
            ( 4, 12,  0., 100000.), (12,  4, -0., 100000.),
            ( 5, 13,  0., 100000.), (13,  5, -0., 100000.),
            ( 6, 14,  0., 100000.), (14,  6, -0., 100000.),
            ( 7, 15,  0., 100000.), (15,  7, -0., 100000.),
            ( 8, 16,  0., 100000.), (16,  8, -0., 100000.),
            ( 9, 17,  0., 100000.), (17,  9, -0., 100000.),
            (10, 18,  0., 100000.), (18, 10, -0., 100000.),
            (11, 19,  0., 100000.), (19, 11, -0., 100000.),
            (12, 20,  0., 100000.), (20, 12, -0., 100000.),
            (13, 21,  0., 100000.), (21, 13, -0., 100000.),
            (14, 22,  0., 100000.), (22, 14, -0., 100000.),
            (15, 23,  0., 100000.), (23, 15, -0., 100000.),
            (16, 24,  0., 100000.), (24, 16, -0., 100000.)],
           dtype=[('node', '<i4'), ('node2', '<i4'), ('q', '<f8'), ('FLOW-AREA', '<f8')])]
[9]:
uzf_conv = uzf.output.package_convergence()
if uzf_conv is not None:
    uzf_conv.data[0:10]
[10]:
uzf_obs = uzf.output.obs()
uzf_obs.data[0:10]
[10]:
rec.array([( 2., 0.05, 0.05, 0.), ( 4., 0.05, 0.05, 0.),
           ( 6., 0.05, 0.05, 0.), ( 8., 0.05, 0.05, 0.),
           (10., 0.05, 0.05, 0.), (12., 0.05, 0.05, 0.),
           (14., 0.05, 0.05, 0.), (16., 0.05, 0.05, 0.),
           (18., 0.05, 0.05, 0.), (20., 0.05, 0.05, 0.)],
          dtype=[('totim', '<f8'), ('ID3_DPTH80', '<f8'), ('ID3_DPTH240', '<f8'), ('ID3_RCH', '<f8')])

Check which output types are available in a package

The .output attribute also has a methods() function that returns a list of available output functions for a given package. Here are a couple of examples

[11]:
print("UZF package: ", uzf.output.methods())
print("Model object: ", ml.output.methods())
print("OC package: ", ml.oc.output.methods())
print("DIS package: ", ml.dis.output.methods())
UZF package:  ['zonebudget()', 'budget()', 'package_convergence()', 'obs()']
Model object:  ['zonebudget()', 'budget()', 'head()']
OC package:  ['zonebudget()', 'budget()', 'head()']
DIS package:  None

Managing multiple observation and csv file outputs in the same package

For many packages, multiple observation output files can be used. The obs() and csv() functions allow the user to specify a observation file or csv file name. If no name is specified, the obs() and csv() methods will return the first file that is listed in the package.

[12]:
output = ml.obs[0].output
obs_names = output.obs_names
output.obs(f=obs_names[0]).data[0:10]
[12]:
rec.array([( 2., 0.05, 0.05, 0.), ( 4., 0.05, 0.05, 0.),
           ( 6., 0.05, 0.05, 0.), ( 8., 0.05, 0.05, 0.),
           (10., 0.05, 0.05, 0.), (12., 0.05, 0.05, 0.),
           (14., 0.05, 0.05, 0.), (16., 0.05, 0.05, 0.),
           (18., 0.05, 0.05, 0.), (20., 0.05, 0.05, 0.)],
          dtype=[('totim', '<f8'), ('ID3_DPTH80', '<f8'), ('ID3_DPTH240', '<f8'), ('ID3_RCH', '<f8')])

Creating and running ZoneBudget for MF6

For the model and many packages, zonebudget can be run on the cell budget file. The .output method allows the user to easily build a ZoneBudget6 instance, then run the model, and view output. First we’ll build a layered zone array, then build and run zonebudget

[13]:
zarr = np.ones(ml.modelgrid.shape, dtype=int)
for i in range(1, 4):
    zarr[i - 1] *= i
[14]:
zonbud = ml.output.zonebudget(zarr)
zonbud.change_model_ws(sim_ws)
zonbud.write_input()
zonbud.run_model()
FloPy is using the following executable to run the model: /home/runner/.local/bin/zbud6
                              ZONEBUDGET Version 6
                             U.S. GEOLOGICAL SURVEY
                            VERSION 6.2.2 07/30/2021
...........................................................................................

Normal Termination
[14]:
(True, [])
[15]:
df = zonbud.get_dataframes(net=True)
df = df.reset_index()
df
[15]:
totim name ZONE_1 ZONE_2 ZONE_3
0 2.0 ZONE_0 0.0 0.000000e+00 0.000000e+00
1 2.0 ZONE_1 0.0 0.000000e+00 0.000000e+00
2 2.0 ZONE_2 0.0 0.000000e+00 0.000000e+00
3 2.0 ZONE_3 0.0 0.000000e+00 0.000000e+00
4 4.0 ZONE_0 0.0 0.000000e+00 0.000000e+00
... ... ... ... ... ...
355 2520.0 ZONE_3 0.0 1.705303e-09 0.000000e+00
356 2560.0 ZONE_0 0.0 0.000000e+00 0.000000e+00
357 2560.0 ZONE_1 0.0 0.000000e+00 0.000000e+00
358 2560.0 ZONE_2 0.0 0.000000e+00 1.136868e-09
359 2560.0 ZONE_3 0.0 -1.136868e-09 0.000000e+00

360 rows × 5 columns