MODFLOW 6 Tutorial 2: Working with Package Variables

This tutorial shows how to view access and change the underlying package variables for MODFLOW 6 objects in flopy. Interaction with a FloPy MODFLOW 6 model is different from other models, such as MODFLOW-2005, MT3D, and SEAWAT, for example.

Package Import

[1]:
import os
import numpy as np
import matplotlib.pyplot as plt
import flopy

Create Simple Demonstration Model

This tutorial uses a simple demonstration simulation with one GWF Model. The model has 3 layers, 4 rows, and 5 columns. The model is set up to use multiple model layers in order to demonstrate some of the layered functionality in FloPy.

[2]:
name = "tutorial02_mf6"
sim = flopy.mf6.MFSimulation(sim_name=name, sim_ws=".")
flopy.mf6.ModflowTdis(
    sim, nper=10, perioddata=[[365.0, 1, 1.0] for _ in range(10)]
)
flopy.mf6.ModflowIms(sim)
gwf = flopy.mf6.ModflowGwf(sim, modelname=name, save_flows=True)
flopy.mf6.ModflowGwfdis(gwf, nlay=3, nrow=4, ncol=5)
flopy.mf6.ModflowGwfic(gwf)
flopy.mf6.ModflowGwfnpf(gwf, save_specific_discharge=True)
flopy.mf6.ModflowGwfchd(
    gwf, stress_period_data=[[(0, 0, 0), 1.0], [(2, 3, 4), 0.0]]
)
budget_file = name + ".bud"
head_file = name + ".hds"
flopy.mf6.ModflowGwfoc(
    gwf,
    budget_filerecord=budget_file,
    head_filerecord=head_file,
    saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")],
)
print("Done creating simulation.")
Done creating simulation.

Accessing Simulation-Level Packages, Models, and Model Packages

At this point a simulation is available in memory. In this particular case the simulation was created directly using Python code; however, the simulation might also have been loaded from existing model files using the flopy.mf6.MFSimulation.load() function.

Once a MODFLOW 6 simulation is available in memory, the contents of the simulation object can be listed using a simple print command

[3]:
print(sim)
sim_name = tutorial02_mf6
sim_path = /home/runner/work/flopy/flopy/.docs/.working/.
exe_name = mf6.exe

###################
Package mfsim.nam
###################

package_name = mfsim.nam
filename = mfsim.nam
package_type = nam
model_or_simulation_package = simulation
simulation_name = tutorial02_mf6


###################
Package tutorial02_mf6.tdis
###################

package_name = tutorial02_mf6.tdis
filename = tutorial02_mf6.tdis
package_type = tdis
model_or_simulation_package = simulation
simulation_name = tutorial02_mf6


###################
Package ims_-1
###################

package_name = ims_-1
filename = tutorial02_mf6.ims
package_type = ims
model_or_simulation_package = simulation
simulation_name = tutorial02_mf6


@@@@@@@@@@@@@@@@@@@@
Model tutorial02_mf6
@@@@@@@@@@@@@@@@@@@@

name = tutorial02_mf6
model_type = gwf6
version = mf6
model_relative_path = .

###################
Package dis
###################

package_name = dis
filename = tutorial02_mf6.dis
package_type = dis
model_or_simulation_package = model
model_name = tutorial02_mf6


###################
Package ic
###################

package_name = ic
filename = tutorial02_mf6.ic
package_type = ic
model_or_simulation_package = model
model_name = tutorial02_mf6


###################
Package npf
###################

package_name = npf
filename = tutorial02_mf6.npf
package_type = npf
model_or_simulation_package = model
model_name = tutorial02_mf6


###################
Package chd_0
###################

package_name = chd_0
filename = tutorial02_mf6.chd
package_type = chd
model_or_simulation_package = model
model_name = tutorial02_mf6


###################
Package oc
###################

package_name = oc
filename = tutorial02_mf6.oc
package_type = oc
model_or_simulation_package = model
model_name = tutorial02_mf6




Simulation-level packages, models, and model packages are shown from the when printing the simulation object. In this case, you should see the all of the contents of sim and some information about each FloPy object that is part of sim.

To get the tdis package and print the contents, we can do the following

[4]:
tdis = sim.tdis
print(tdis)
package_name = tutorial02_mf6.tdis
filename = tutorial02_mf6.tdis
package_type = tdis
model_or_simulation_package = simulation
simulation_name = tutorial02_mf6

Block dimensions
--------------------
nper
{internal}
(10)


Block perioddata
--------------------
perioddata
{internal}
([(365., 1, 1.) (365., 1, 1.) (365., 1, 1.) (365., 1, 1.) (365., 1, 1.)
 (365., 1, 1.) (365., 1, 1.) (365., 1, 1.) (365., 1, 1.) (365., 1, 1.)])



To get the Iterative Model Solution (IMS) object, we use the following syntax

[5]:
ims = sim.get_package("ims_-1")
print(ims)
package_name = ims_-1
filename = tutorial02_mf6.ims
package_type = ims
model_or_simulation_package = simulation
simulation_name = tutorial02_mf6


Or because there is only one IMS object for this simulation, we can access it as

[6]:
ims = sim.get_package("ims")
print(ims)
package_name = ims_-1
filename = tutorial02_mf6.ims
package_type = ims
model_or_simulation_package = simulation
simulation_name = tutorial02_mf6


When printing the sim object, there is also a simulation package called nam. This package contains the information that is written to the mfsim.nam file, which is the primary file that MODFLOW 6 reads when it first starts

[7]:
nam = sim.get_package("nam")
print(nam)
package_name = mfsim.nam
filename = mfsim.nam
package_type = nam
model_or_simulation_package = simulation
simulation_name = tutorial02_mf6

Block timing
--------------------
tdis6
{internal}
(tutorial02_mf6.tdis)


Block models
--------------------
models
{internal}
([('gwf6', 'tutorial02_mf6.nam', 'tutorial02_mf6')])


Block solutiongroup
--------------------
solutiongroup
{internal}
([('ims6', 'tutorial02_mf6.ims', 'tutorial02_mf6')])



To see the models that are contained within the simulation, we can get a list of their names as follows

[8]:
print(sim.model_names)
odict_keys(['tutorial02_mf6'])

sim.model_names returns the keys of an ordered dictionary, which isn’t very useful to us, but we can convert that to a list and then go through that list and print information about each model in the simulation. In this case there is only one model, but had there been more models, we would see them listed here

[9]:
model_names = list(sim.model_names)
for mname in model_names:
    print(mname)
tutorial02_mf6

If we want to get a model from a simulation, then we use the get_model() method of the sim object. Here we go through all the models in the simulation and print the model name and the model type.

[10]:
model_names = list(sim.model_names)
for mname in model_names:
    m = sim.get_model(mname)
    print(m.name, m.model_type)
tutorial02_mf6 gwf6

For this simple case here with only one GWF model, we can very easily get the FloPy representation of the GWF model as

[11]:
gwf = sim.get_model("tutorial02_mf6")

Now that we have the gwf object, we can print it, and see what’s it contains.

[12]:
print(gwf)
name = tutorial02_mf6
model_type = gwf6
version = mf6
model_relative_path = .

###################
Package dis
###################

package_name = dis
filename = tutorial02_mf6.dis
package_type = dis
model_or_simulation_package = model
model_name = tutorial02_mf6


###################
Package ic
###################

package_name = ic
filename = tutorial02_mf6.ic
package_type = ic
model_or_simulation_package = model
model_name = tutorial02_mf6


###################
Package npf
###################

package_name = npf
filename = tutorial02_mf6.npf
package_type = npf
model_or_simulation_package = model
model_name = tutorial02_mf6


###################
Package chd_0
###################

package_name = chd_0
filename = tutorial02_mf6.chd
package_type = chd
model_or_simulation_package = model
model_name = tutorial02_mf6


###################
Package oc
###################

package_name = oc
filename = tutorial02_mf6.oc
package_type = oc
model_or_simulation_package = model
model_name = tutorial02_mf6



What we see here is the information that we saw when we printed the sim object.

One of the most common operations on a model is to see what packages are in in and then get packages of interest. A list of packages in a model can obtained as

[13]:
package_list = gwf.get_package_list()
print(package_list)
['DIS', 'IC', 'NPF', 'CHD_0', 'OC']

As you might expect we can access each package in this list with gwf.get_package(). Thus, the following syntax can be used to obtain and print the contents of the Discretization Package

[14]:
dis = gwf.get_package("dis")
print(dis)
package_name = dis
filename = tutorial02_mf6.dis
package_type = dis
model_or_simulation_package = model
model_name = tutorial02_mf6

Block dimensions
--------------------
nlay
{internal}
(3)

nrow
{internal}
(4)

ncol
{internal}
(5)


Block griddata
--------------------
delr
{constant 1.0}

delc
{constant 1.0}

top
{constant 1.0}

botm
{constant 0.0}



The Python type for this dis package is simply

[15]:
print(type(dis))
<class 'flopy.mf6.modflow.mfgwfdis.ModflowGwfdis'>

FloPy MODFLOW 6 Scalar Variables (MFScalar)

Once we are able to get any package from a FloPy simulation object, a next step is to be able to access individual package variables. We could see the variables in the dis object when we used the print(dis) command. If we wanted to see information about ncol, for example, we print it as

[16]:
print(dis.ncol)
{internal}
(5)

By doing so, we get information about ncol, but we do not get an integer value. Instead we get a representation of ncol and how it is stored in FloPy. The type of ncol is

[17]:
print(type(dis.ncol))
<class 'flopy.mf6.data.mfdatascalar.MFScalar'>

When we print the of ncol, we see that it is an MFScalar type. This is a specific type of information used by FloPy to represent variables that are stored in in MODFLOW 6 objects.

If we want to get a more useful representation of ncol, then we use the get_data() method, which is available on all of the underlying flopy package variables. Thus, for ncol, we can get the integer value and the type that is returned as

[18]:
ncol = dis.ncol.get_data()
print(ncol)
print(type(ncol))
5
<class 'int'>

FloPy MODFLOW 6 Arrays (MFArray)

The dis object also has several arrays stored with it. For example the discretization has botm, which stores the bottom elevation for every model cell in the grid. We can see the type of botm as

[19]:
print(type(dis.botm))
<class 'flopy.mf6.data.mfdataarray.MFArray'>

The MFArray class in flopy is designed to efficiently store array information for MODFLOW 6 variables. In this case, dis.botm has a constant value of zero, which we can see with

[20]:
print(dis.botm)
{constant 0.0}

If we want to get an array representation of dis.botm, we can use

[21]:
print(dis.botm.get_data())
[[[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.]]]

or

[22]:
print(dis.botm.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.]]]

In both of these cases, a full three-dimensional array is created on the fly and provided back to the user. In this particular case, the returned arrays are the same; however, if a factor is assigned to this array, as will be seen later, dis.botm.array will have values with the factor applied whereas dis.botm.get_data() will be the data values stored in the array without the factor applied.

We can see here that the shape of the returned array is correct and is (nlay, nrow, ncol)

[23]:
print(dis.botm.array.shape)
(3, 4, 5)

and that it is a numpy array

[24]:
print(type(dis.botm.array))
<class 'numpy.ndarray'>

We can easily change the value of this array as a constant using the set_data() method

[25]:
dis.botm.set_data(-10)
print(dis.botm)
{constant -10}

Or alternatively, we could call set_data() with an array as long as it is the correct shape

[26]:
shp = dis.botm.array.shape
a = np.arange(shp[0] * shp[1] * shp[2]).reshape(shp)
dis.botm.set_data(a)
print(dis.botm.array)
[[[ 0.  1.  2.  3.  4.]
  [ 5.  6.  7.  8.  9.]
  [10. 11. 12. 13. 14.]
  [15. 16. 17. 18. 19.]]

 [[20. 21. 22. 23. 24.]
  [25. 26. 27. 28. 29.]
  [30. 31. 32. 33. 34.]
  [35. 36. 37. 38. 39.]]

 [[40. 41. 42. 43. 44.]
  [45. 46. 47. 48. 49.]
  [50. 51. 52. 53. 54.]
  [55. 56. 57. 58. 59.]]]

We even have an option to see how dis.botm will be written to the MODFLOW 6 Discretization input file

[27]:
print(dis.botm.get_file_entry())
  botm
    INTERNAL  FACTOR  1.0
         0.00000000       1.00000000       2.00000000       3.00000000       4.00000000
         5.00000000       6.00000000       7.00000000       8.00000000       9.00000000
        10.00000000      11.00000000      12.00000000      13.00000000      14.00000000
        15.00000000      16.00000000      17.00000000      18.00000000      19.00000000
        20.00000000      21.00000000      22.00000000      23.00000000      24.00000000
        25.00000000      26.00000000      27.00000000      28.00000000      29.00000000
        30.00000000      31.00000000      32.00000000      33.00000000      34.00000000
        35.00000000      36.00000000      37.00000000      38.00000000      39.00000000
        40.00000000      41.00000000      42.00000000      43.00000000      44.00000000
        45.00000000      46.00000000      47.00000000      48.00000000      49.00000000
        50.00000000      51.00000000      52.00000000      53.00000000      54.00000000
        55.00000000      56.00000000      57.00000000      58.00000000      59.00000000

Layered Data

When we look at what will be written to the discretization input file, we see that the entire dis.botm array is written as one long array with the number of values equal to nlay * nrow * ncol. And this whole-array specification may be of use in some cases. Often times, however, it is easier to work with each layer separately. An MFArray object, such as dis.botm can be set to be a layered array as follows

[28]:
dis.botm.make_layered()

By changing dis.botm to layered, we are then able to manage each layer separately. Before doing so, however, we need to pass in data that can be separated into three layers. An array of the correct size is one option

[29]:
a = np.arange(shp[0] * shp[1] * shp[2]).reshape(shp)
dis.botm.set_data(a)

Now that dis.botm has been set to be layered, if we print information about it, we see that each layer is stored separately, however, dis.botm.array will still return a full three-dimensional array.

[30]:
print(type(dis.botm))
print(dis.botm)
<class 'flopy.mf6.data.mfdataarray.MFArray'>
Layer_1{internal}
([[ 0  1  2  3  4]
 [ 5  6  7  8  9]
 [10 11 12 13 14]
 [15 16 17 18 19]])
Layer_2{internal}
([[20 21 22 23 24]
 [25 26 27 28 29]
 [30 31 32 33 34]
 [35 36 37 38 39]])
Layer_3{internal}
([[40 41 42 43 44]
 [45 46 47 48 49]
 [50 51 52 53 54]
 [55 56 57 58 59]])

We also see that each layer is printed separately to the Discretization Package input file, and that the LAYERED keyword is activated:

[31]:
print(dis.botm.get_file_entry())
  botm  LAYERED
    INTERNAL  FACTOR  1.0
           0.00000000       1.00000000       2.00000000       3.00000000       4.00000000
           5.00000000       6.00000000       7.00000000       8.00000000       9.00000000
          10.00000000      11.00000000      12.00000000      13.00000000      14.00000000
          15.00000000      16.00000000      17.00000000      18.00000000      19.00000000
    INTERNAL  FACTOR  1.0
          20.00000000      21.00000000      22.00000000      23.00000000      24.00000000
          25.00000000      26.00000000      27.00000000      28.00000000      29.00000000
          30.00000000      31.00000000      32.00000000      33.00000000      34.00000000
          35.00000000      36.00000000      37.00000000      38.00000000      39.00000000
    INTERNAL  FACTOR  1.0
          40.00000000      41.00000000      42.00000000      43.00000000      44.00000000
          45.00000000      46.00000000      47.00000000      48.00000000      49.00000000
          50.00000000      51.00000000      52.00000000      53.00000000      54.00000000
          55.00000000      56.00000000      57.00000000      58.00000000      59.00000000

Working with a layered array provides lots of flexibility. For example, constants can be set for some layers, but arrays for others:

[32]:
dis.botm.set_data([-1, -a[2], -200])
print(dis.botm.get_file_entry())
  botm  LAYERED
    CONSTANT      -1.00000000
    INTERNAL  FACTOR  1.0
         -40.00000000     -41.00000000     -42.00000000     -43.00000000     -44.00000000
         -45.00000000     -46.00000000     -47.00000000     -48.00000000     -49.00000000
         -50.00000000     -51.00000000     -52.00000000     -53.00000000     -54.00000000
         -55.00000000     -56.00000000     -57.00000000     -58.00000000     -59.00000000
    CONSTANT    -200.00000000

To gain full control over an individual layers, layer information can be provided as a dictionary:

[33]:
a0 = {"factor": 0.5, "iprn": 1, "data": np.ones((4, 5))}
a1 = -100
a2 = {"factor": 1.0, "iprn": 14, "data": -100 * np.ones((4, 5))}
dis.botm.set_data([a0, a1, a2])
print(dis.botm.get_file_entry())
  botm  LAYERED
    INTERNAL  FACTOR  0.5  IPRN  1
           1.00000000       1.00000000       1.00000000       1.00000000       1.00000000
           1.00000000       1.00000000       1.00000000       1.00000000       1.00000000
           1.00000000       1.00000000       1.00000000       1.00000000       1.00000000
           1.00000000       1.00000000       1.00000000       1.00000000       1.00000000
    CONSTANT    -100.00000000
    INTERNAL  FACTOR  1.0  IPRN  14
        -100.00000000    -100.00000000    -100.00000000    -100.00000000    -100.00000000
        -100.00000000    -100.00000000    -100.00000000    -100.00000000    -100.00000000
        -100.00000000    -100.00000000    -100.00000000    -100.00000000    -100.00000000
        -100.00000000    -100.00000000    -100.00000000    -100.00000000    -100.00000000

Here we say that the FACTOR has been set to 0.5 for the first layer and an alternative print flag is set for the last layer.

Because we are specifying a factor for the top layer, we can also see that the get_data() method returns the array without the factor applied

[34]:
print(dis.botm.get_data())
[[[   1.    1.    1.    1.    1.]
  [   1.    1.    1.    1.    1.]
  [   1.    1.    1.    1.    1.]
  [   1.    1.    1.    1.    1.]]

 [[-100. -100. -100. -100. -100.]
  [-100. -100. -100. -100. -100.]
  [-100. -100. -100. -100. -100.]
  [-100. -100. -100. -100. -100.]]

 [[-100. -100. -100. -100. -100.]
  [-100. -100. -100. -100. -100.]
  [-100. -100. -100. -100. -100.]
  [-100. -100. -100. -100. -100.]]]

whereas .array returns the array with the factor applied

[35]:
print(dis.botm.array)
[[[   0.5    0.5    0.5    0.5    0.5]
  [   0.5    0.5    0.5    0.5    0.5]
  [   0.5    0.5    0.5    0.5    0.5]
  [   0.5    0.5    0.5    0.5    0.5]]

 [[-100.  -100.  -100.  -100.  -100. ]
  [-100.  -100.  -100.  -100.  -100. ]
  [-100.  -100.  -100.  -100.  -100. ]
  [-100.  -100.  -100.  -100.  -100. ]]

 [[-100.  -100.  -100.  -100.  -100. ]
  [-100.  -100.  -100.  -100.  -100. ]
  [-100.  -100.  -100.  -100.  -100. ]
  [-100.  -100.  -100.  -100.  -100. ]]]

External Files

If we want to store the bottom elevations for the bottom layer to an external file, then the dictionary that we pass in for the third layer can be given a filename keyword

[36]:
a0 = {"factor": 0.5, "iprn": 1, "data": np.ones((4, 5))}
a1 = -100
a2 = {
    "filename": "dis.botm.3.txt",
    "factor": 2.0,
    "iprn": 1,
    "data": -100 * np.ones((4, 5)),
}
dis.botm.set_data([a0, a1, a2])
print(dis.botm.get_file_entry())
  botm  LAYERED
    INTERNAL  FACTOR  0.5  IPRN  1
           1.00000000       1.00000000       1.00000000       1.00000000       1.00000000
           1.00000000       1.00000000       1.00000000       1.00000000       1.00000000
           1.00000000       1.00000000       1.00000000       1.00000000       1.00000000
           1.00000000       1.00000000       1.00000000       1.00000000       1.00000000
    CONSTANT    -100.00000000
    OPEN/CLOSE  'dis.botm.3.txt'  FACTOR  2.0  IPRN  1

And we can even have our data be stored in binary format by adding a ‘binary’ key to the layer dictionary and setting it’s value to True.

[37]:
a0 = {"factor": 0.5, "iprn": 1, "data": np.ones((4, 5))}
a1 = -100
a2 = {
    "filename": "dis.botm.3.bin",
    "factor": 2.0,
    "iprn": 1,
    "data": -100 * np.ones((4, 5)),
    "binary": True,
}
dis.botm.set_data([a0, a1, a2])
print(dis.botm.get_file_entry())
print(dis.botm.array)
  botm  LAYERED
    INTERNAL  FACTOR  0.5  IPRN  1
           1.00000000       1.00000000       1.00000000       1.00000000       1.00000000
           1.00000000       1.00000000       1.00000000       1.00000000       1.00000000
           1.00000000       1.00000000       1.00000000       1.00000000       1.00000000
           1.00000000       1.00000000       1.00000000       1.00000000       1.00000000
    CONSTANT    -100.00000000
    OPEN/CLOSE  'dis.botm.3.bin'  FACTOR  2.0  (BINARY)  IPRN  1

[[[   0.5    0.5    0.5    0.5    0.5]
  [   0.5    0.5    0.5    0.5    0.5]
  [   0.5    0.5    0.5    0.5    0.5]
  [   0.5    0.5    0.5    0.5    0.5]]

 [[-100.  -100.  -100.  -100.  -100. ]
  [-100.  -100.  -100.  -100.  -100. ]
  [-100.  -100.  -100.  -100.  -100. ]
  [-100.  -100.  -100.  -100.  -100. ]]

 [[-200.  -200.  -200.  -200.  -200. ]
  [-200.  -200.  -200.  -200.  -200. ]
  [-200.  -200.  -200.  -200.  -200. ]
  [-200.  -200.  -200.  -200.  -200. ]]]

Note that we could have also specified botm this way as part of the original flopy.mf6.ModflowGwfdis constructor:

[38]:
a0 = {"factor": 0.5, "iprn": 1, "data": np.ones((4, 5))}
a1 = -100
a2 = {
    "filename": "dis.botm.3.bin",
    "factor": 2.0,
    "iprn": 1,
    "data": -100 * np.ones((4, 5)),
    "binary": True,
}
botm = [a0, a1, a2]
flopy.mf6.ModflowGwfdis(gwf, nlay=3, nrow=4, ncol=5, botm=botm)
WARNING: Package with type dis already exists. Replacing existing package.
[38]:
package_name = dis
filename = tutorial02_mf6.dis
package_type = dis
model_or_simulation_package = model
model_name = tutorial02_mf6

Block dimensions
--------------------
nlay
{internal}
(3)

nrow
{internal}
(4)

ncol
{internal}
(5)


Block griddata
--------------------
delr
{constant 1.0}

delc
{constant 1.0}

top
{constant 1.0}

botm
Layer_1{internal, factor 0.5, iprn 1}
(array([[1., 1., 1., 1., 1.],
       [1., 1., 1., 1., 1.],
       [1., 1., 1., 1., 1.],
       [1., 1., 1., 1., 1.]]))
Layer_2{constant -100}


Stress Period Data (MFTransientList)

Data that varies during a simulation is often stored in flopy in a special data structured call an MFTransientList. We can see how one of these behaves by looking at the stress period data for the constant head package. We can access the constant head package by getting it from the GWF model using the package name:

[39]:
chd = gwf.get_package("chd_0")
print(chd)
package_name = chd_0
filename = tutorial02_mf6.chd
package_type = chd
model_or_simulation_package = model
model_name = tutorial02_mf6

Block period
--------------------
stress_period_data
{internal}
([((0, 0, 0), 1.) ((2, 3, 4), 0.)])



[40]:
# We can now look at the type and contents of the stress period data
print(type(chd.stress_period_data))
print(chd.stress_period_data)
<class 'flopy.mf6.data.mfdatalist.MFTransientList'>
{internal}
([((0, 0, 0), 1.) ((2, 3, 4), 0.)])

We can get a dictionary of the stress period data using the get_data() method:

[41]:
spd = chd.stress_period_data.get_data()
print(spd)
{0: rec.array([((0, 0, 0), 1.), ((2, 3, 4), 0.)],
          dtype=[('cellid', 'O'), ('head', '<f8')])}

Here we see that they key in the dictionary is the stress period number, which is zero based and the value in the dictionary is a numpy recarray, which is a numpy array that is optimized to store columns of infomration. The first column contains a tuple, which is the layer, row, and column number. The second column contains the head value.

more to come…

Time Series

more to come…

Observations

more to come…

Activating External Output

more to come…

Plotting

more to come…