flopy/examples/Notebooks/flopy3_modflow_boundaries.i...

699 lines
22 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Flopy MODFLOW-2005 Boundary Conditions\n",
"\n",
"Flopy has a new way to enter boundary conditions for some MODFLOW packages. These changes are substantial. Boundary conditions can now be entered as a list of boundaries, as a numpy recarray, or as a dictionary. These different styles are described in this notebook.\n",
"\n",
"Flopy also now requires zero-based input. This means that **all boundaries are entered in zero-based layer, row, and column indices**. This means that older Flopy scripts will need to be modified to account for this change. If you are familiar with Python, this should be natural, but if not, then it may take some time to get used to zero-based numbering. Flopy users submit all information in zero-based form, and Flopy converts this to the one-based form required by MODFLOW.\n",
"\n",
"The following MODFLOW-2005 packages are affected by this change:\n",
"\n",
" * Well\n",
" * Drain\n",
" * River\n",
" * General-Head Boundary\n",
" * Time-Variant Constant Head\n",
" \n",
"This notebook explains the different ways to enter these types of boundary conditions.\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3.8.6 | packaged by conda-forge | (default, Oct 7 2020, 18:42:56) \n",
"[Clang 10.0.1 ]\n",
"numpy version: 1.18.5\n",
"flopy version: 3.3.3\n"
]
}
],
"source": [
"#begin by importing flopy\n",
"import os\n",
"import sys\n",
"import numpy as np\n",
"\n",
"# run installed version of flopy or add local path\n",
"try:\n",
" import flopy\n",
"except:\n",
" fpth = os.path.abspath(os.path.join('..', '..'))\n",
" sys.path.append(fpth)\n",
" import flopy\n",
"\n",
"workspace = os.path.join('data')\n",
"#make sure workspace directory exists\n",
"if not os.path.exists(workspace):\n",
" os.makedirs(workspace)\n",
" \n",
"print(sys.version)\n",
"print('numpy version: {}'.format(np.__version__))\n",
"print('flopy version: {}'.format(flopy.__version__))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## List of Boundaries"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Boundary condition information is passed to a package constructor as stress_period_data. In its simplest form, stress_period_data can be a list of individual boundaries, which themselves are lists. The following shows a simple example for a MODFLOW River Package boundary:"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"stress_period_data = [\n",
" [2, 3, 4, 10.7, 5000., -5.7], #layer, row, column, stage, conductance, river bottom\n",
" [2, 3, 5, 10.7, 5000., -5.7], #layer, row, column, stage, conductance, river bottom\n",
" [2, 3, 6, 10.7, 5000., -5.7], #layer, row, column, stage, conductance, river bottom\n",
" ]\n",
"m = flopy.modflow.Modflow(modelname='test', model_ws=workspace)\n",
"riv = flopy.modflow.ModflowRiv(m, stress_period_data=stress_period_data)\n",
"m.write_input()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If we look at the River Package created here, you see that the layer, row, and column numbers have been increased by one."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"# RIV package for MODFLOW-2005, generated by Flopy.\r\n",
" 3 0\r\n",
" 3 0 # stress period 1\r\n",
" 3 4 5 10.7 5000.0 -5.7\r\n",
" 3 4 6 10.7 5000.0 -5.7\r\n",
" 3 4 7 10.7 5000.0 -5.7\r\n"
]
}
],
"source": [
"!head -n 10 'data/test.riv'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If this model had more than one stress period, then Flopy will assume that this boundary condition information applies until the end of the simulation"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"# RIV package for MODFLOW-2005, generated by Flopy.\r\n",
" 3 0\r\n",
" 3 0 # stress period 1\r\n",
" 3 4 5 10.7 5000.0 -5.7\r\n",
" 3 4 6 10.7 5000.0 -5.7\r\n",
" 3 4 7 10.7 5000.0 -5.7\r\n",
" -1 0 # stress period 2\r\n",
" -1 0 # stress period 3\r\n"
]
}
],
"source": [
"m = flopy.modflow.Modflow(modelname='test', model_ws=workspace)\n",
"dis = flopy.modflow.ModflowDis(m, nper=3)\n",
"riv = flopy.modflow.ModflowRiv(m, stress_period_data=stress_period_data)\n",
"m.write_input()\n",
"!head -n 10 'data/test.riv'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Recarray of Boundaries\n",
"\n",
"Numpy allows the use of recarrays, which are numpy arrays in which each column of the array may be given a different type. Boundary conditions can be entered as recarrays. Information on the structure of the recarray for a boundary condition package can be obtained from that particular package. The structure of the recarray is contained in the dtype. "
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[('k', '<i8'), ('i', '<i8'), ('j', '<i8'), ('stage', '<f4'), ('cond', '<f4'), ('rbot', '<f4')]\n"
]
}
],
"source": [
"riv_dtype = flopy.modflow.ModflowRiv.get_default_dtype()\n",
"print(riv_dtype)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now that we know the structure of the recarray that we want to create, we can create a new one as follows."
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"stress_period_data: [(0, 0, 0, 0., 0., 0.) (0, 0, 0, 0., 0., 0.) (0, 0, 0, 0., 0., 0.)]\n",
"type is: <class 'numpy.recarray'>\n"
]
}
],
"source": [
"stress_period_data = np.zeros((3), dtype=riv_dtype)\n",
"stress_period_data = stress_period_data.view(np.recarray)\n",
"print('stress_period_data: ', stress_period_data)\n",
"print('type is: ', type(stress_period_data))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can then fill the recarray with our boundary conditions."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[(2, 3, 4, 10.7, 5000., -5.7) (2, 3, 5, 10.7, 5000., -5.7)\n",
" (2, 3, 6, 10.7, 5000., -5.7)]\n"
]
}
],
"source": [
"stress_period_data[0] = (2, 3, 4, 10.7, 5000., -5.7)\n",
"stress_period_data[1] = (2, 3, 5, 10.7, 5000., -5.7)\n",
"stress_period_data[2] = (2, 3, 6, 10.7, 5000., -5.7)\n",
"print(stress_period_data)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"# RIV package for MODFLOW-2005, generated by Flopy.\r\n",
" 3 0\r\n",
" 3 0 # stress period 1\r\n",
" 3 4 5 10.7 5000.0 -5.7\r\n",
" 3 4 6 10.7 5000.0 -5.7\r\n",
" 3 4 7 10.7 5000.0 -5.7\r\n"
]
}
],
"source": [
"m = flopy.modflow.Modflow(modelname='test', model_ws=workspace)\n",
"riv = flopy.modflow.ModflowRiv(m, stress_period_data=stress_period_data)\n",
"m.write_input()\n",
"!head -n 10 'data/test.riv'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"As before, if we have multiple stress periods, then this recarray will apply to all of them."
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"# RIV package for MODFLOW-2005, generated by Flopy.\r\n",
" 3 0\r\n",
" 3 0 # stress period 1\r\n",
" 3 4 5 10.7 5000.0 -5.7\r\n",
" 3 4 6 10.7 5000.0 -5.7\r\n",
" 3 4 7 10.7 5000.0 -5.7\r\n",
" -1 0 # stress period 2\r\n",
" -1 0 # stress period 3\r\n"
]
}
],
"source": [
"m = flopy.modflow.Modflow(modelname='test', model_ws=workspace)\n",
"dis = flopy.modflow.ModflowDis(m, nper=3)\n",
"riv = flopy.modflow.ModflowRiv(m, stress_period_data=stress_period_data)\n",
"m.write_input()\n",
"!head -n 10 'data/test.riv'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Dictionary of Boundaries\n",
"\n",
"The power of the new functionality in Flopy3 is the ability to specify a dictionary for stress_period_data. If specified as a dictionary, the key is the stress period number (**as a zero-based number**), and the value is either a nested list, an integer value of 0 or -1, or a recarray for that stress period.\n",
"\n",
"Let's say that we want to use the following schedule for our rivers:\n",
" 0. No rivers in stress period zero\n",
" 1. Rivers specified by a list in stress period 1\n",
" 2. No rivers\n",
" 3. No rivers\n",
" 4. No rivers\n",
" 5. Rivers specified by a recarray\n",
" 6. Same recarray rivers\n",
" 7. Same recarray rivers\n",
" 8. Same recarray rivers\n"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[2, 3, 4, 10.7, 5000.0, -5.7], [2, 3, 5, 10.7, 5000.0, -5.7], [2, 3, 6, 10.7, 5000.0, -5.7]]\n"
]
}
],
"source": [
"sp1 = [\n",
" [2, 3, 4, 10.7, 5000., -5.7], #layer, row, column, stage, conductance, river bottom\n",
" [2, 3, 5, 10.7, 5000., -5.7], #layer, row, column, stage, conductance, river bottom\n",
" [2, 3, 6, 10.7, 5000., -5.7], #layer, row, column, stage, conductance, river bottom\n",
" ]\n",
"print(sp1)"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[(2, 3, 4, 20.7, 5000., -5.7) (2, 3, 5, 20.7, 5000., -5.7)\n",
" (2, 3, 6, 20.7, 5000., -5.7)]\n"
]
}
],
"source": [
"riv_dtype = flopy.modflow.ModflowRiv.get_default_dtype()\n",
"sp5 = np.zeros((3), dtype=riv_dtype)\n",
"sp5 = sp5.view(np.recarray)\n",
"sp5[0] = (2, 3, 4, 20.7, 5000., -5.7)\n",
"sp5[1] = (2, 3, 5, 20.7, 5000., -5.7)\n",
"sp5[2] = (2, 3, 6, 20.7, 5000., -5.7)\n",
"print(sp5)"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"# RIV package for MODFLOW-2005, generated by Flopy.\r\n",
" 3 0\r\n",
" 0 0 # stress period 1\r\n",
" 3 0 # stress period 2\r\n",
" 3 4 5 10.7 5000.0 -5.7\r\n",
" 3 4 6 10.7 5000.0 -5.7\r\n",
" 3 4 7 10.7 5000.0 -5.7\r\n",
" 0 0 # stress period 3\r\n",
" -1 0 # stress period 4\r\n",
" -1 0 # stress period 5\r\n"
]
}
],
"source": [
"sp_dict = {0:0, 1:sp1, 2:0, 5:sp5}\n",
"m = flopy.modflow.Modflow(modelname='test', model_ws=workspace)\n",
"dis = flopy.modflow.ModflowDis(m, nper=8)\n",
"riv = flopy.modflow.ModflowRiv(m, stress_period_data=sp_dict)\n",
"m.write_input()\n",
"!head -n 10 'data/test.riv'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## MODFLOW Auxiliary Variables\n",
"\n",
"Flopy works with MODFLOW auxiliary variables by allowing the recarray to contain additional columns of information. The auxiliary variables must be specified as package options as shown in the example below.\n",
"\n",
"In this example, we also add a string in the last column of the list in order to name each boundary condition. In this case, however, we do not include boundname as an auxiliary variable as MODFLOW would try to read it as a floating point number."
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"stress_period_data: [(0, 0, 0, 0., 0., 0., 0, 0) (0, 0, 0, 0., 0., 0., 0, 0)\n",
" (0, 0, 0, 0., 0., 0., 0, 0)]\n",
"type is: <class 'numpy.recarray'>\n"
]
}
],
"source": [
"#create an empty array with an iface auxiliary variable at the end\n",
"riva_dtype = [('k', '<i8'), ('i', '<i8'), ('j', '<i8'), \n",
" ('stage', '<f4'), ('cond', '<f4'), ('rbot', '<f4'), \n",
" ('iface', '<i4'), ('boundname', object)]\n",
"riva_dtype = np.dtype(riva_dtype)\n",
"stress_period_data = np.zeros((3), dtype=riva_dtype)\n",
"stress_period_data = stress_period_data.view(np.recarray)\n",
"print('stress_period_data: ', stress_period_data)\n",
"print('type is: ', type(stress_period_data))"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[(2, 3, 4, 10.7, 5000., -5.7, 1, 'riv1')\n",
" (2, 3, 5, 10.7, 5000., -5.7, 2, 'riv2')\n",
" (2, 3, 6, 10.7, 5000., -5.7, 3, 'riv3')]\n"
]
}
],
"source": [
"stress_period_data[0] = (2, 3, 4, 10.7, 5000., -5.7, 1, 'riv1')\n",
"stress_period_data[1] = (2, 3, 5, 10.7, 5000., -5.7, 2, 'riv2')\n",
"stress_period_data[2] = (2, 3, 6, 10.7, 5000., -5.7, 3, 'riv3')\n",
"print(stress_period_data)"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"# RIV package for MODFLOW-2005, generated by Flopy.\r\n",
" 3 0 aux iface\r\n",
" 3 0 # stress period 1\r\n",
" 3 4 5 10.7 5000.0 -5.7 1 riv1\r\n",
" 3 4 6 10.7 5000.0 -5.7 2 riv2\r\n",
" 3 4 7 10.7 5000.0 -5.7 3 riv3\r\n"
]
}
],
"source": [
"m = flopy.modflow.Modflow(modelname='test', model_ws=workspace)\n",
"riv = flopy.modflow.ModflowRiv(m, stress_period_data=stress_period_data, dtype=riva_dtype, options=['aux iface'])\n",
"m.write_input()\n",
"!head -n 10 'data/test.riv'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Working with Unstructured Grids\n",
"\n",
"Flopy can create an unstructured grid boundary condition package for MODFLOW-USG. This can be done by specifying a custom dtype for the recarray. The following shows an example of how that can be done."
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"stress_period_data: [(0, 0., 0., 0.) (0, 0., 0., 0.) (0, 0., 0., 0.)]\n",
"type is: <class 'numpy.recarray'>\n"
]
}
],
"source": [
"#create an empty array based on nodenumber instead of layer, row, and column\n",
"rivu_dtype = [('nodenumber', '<i8'), ('stage', '<f4'), ('cond', '<f4'), ('rbot', '<f4')]\n",
"rivu_dtype = np.dtype(rivu_dtype)\n",
"stress_period_data = np.zeros((3), dtype=rivu_dtype)\n",
"stress_period_data = stress_period_data.view(np.recarray)\n",
"print('stress_period_data: ', stress_period_data)\n",
"print('type is: ', type(stress_period_data))"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[( 77, 10.7, 5000., -5.7) ( 245, 10.7, 5000., -5.7)\n",
" (450034, 10.7, 5000., -5.7)]\n"
]
}
],
"source": [
"stress_period_data[0] = (77, 10.7, 5000., -5.7)\n",
"stress_period_data[1] = (245, 10.7, 5000., -5.7)\n",
"stress_period_data[2] = (450034, 10.7, 5000., -5.7)\n",
"print(stress_period_data)"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"data\n",
"# RIV package for MODFLOW-2005, generated by Flopy.\r\n",
" 3 0\r\n",
" 3 0 # stress period 1\r\n",
" 77 10.7 5000.0 -5.7\r\n",
" 245 10.7 5000.0 -5.7\r\n",
" 450034 10.7 5000.0 -5.7\r\n"
]
}
],
"source": [
"m = flopy.modflow.Modflow(modelname='test', model_ws=workspace)\n",
"riv = flopy.modflow.ModflowRiv(m, stress_period_data=stress_period_data, dtype=rivu_dtype)\n",
"m.write_input()\n",
"print(workspace)\n",
"!head -n 10 'data/test.riv'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Combining two boundary condition packages"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"# WEL package for MODFLOW-2005, generated by Flopy.\r\n",
" 1 0 \r\n",
" 0 0 # stress period 1\r\n",
" 0 0 # stress period 2\r\n",
" 0 0 # stress period 3\r\n",
" 1 0 # stress period 4\r\n",
" 2 2 2 1.0\r\n",
" -1 0 # stress period 5\r\n",
" 1 0 # stress period 6\r\n",
" 2 3 5 4.0\r\n"
]
}
],
"source": [
"ml = flopy.modflow.Modflow(modelname=\"test\",model_ws=workspace)\n",
"dis = flopy.modflow.ModflowDis(ml,10,10,10,10)\n",
"sp_data1 = {3: [1, 1, 1, 1.0],5:[1,2,4,4.0]}\n",
"wel1 = flopy.modflow.ModflowWel(ml, stress_period_data=sp_data1)\n",
"ml.write_input()\n",
"!head -n 10 'data/test.wel'"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"# WEL package for MODFLOW-2005, generated by Flopy.\r\n",
" 1 0 \r\n",
" 1 0 # stress period 1\r\n",
" 2 2 4 3.0\r\n",
" -1 0 # stress period 2\r\n",
" -1 0 # stress period 3\r\n",
" -1 0 # stress period 4\r\n",
" -1 0 # stress period 5\r\n",
" -1 0 # stress period 6\r\n",
" -1 0 # stress period 7\r\n"
]
}
],
"source": [
"sp_data2 = {0: [1, 1, 3, 3.0],8:[9,2,4,4.0]}\n",
"wel2 = flopy.modflow.ModflowWel(ml, stress_period_data=sp_data2)\n",
"ml.write_input()\n",
"!head -n 10 'data/test.wel'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we create a third wel package, using the ```MfList.append()``` method:"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"# WEL package for MODFLOW-2005, generated by Flopy.\r\n",
" 2 0 \r\n",
" 1 0 # stress period 1\r\n",
" 2 2 4 3.0\r\n",
" -1 0 # stress period 2\r\n",
" -1 0 # stress period 3\r\n",
" 2 0 # stress period 4\r\n",
" 2 2 4 3.0\r\n",
" 2 2 2 1.0\r\n",
" -1 0 # stress period 5\r\n"
]
}
],
"source": [
"wel3 = flopy.modflow.ModflowWel(ml,stress_period_data=\\\n",
" wel2.stress_period_data.append(\n",
" wel1.stress_period_data))\n",
"ml.write_input()\n",
"!head -n 10 'data/test.wel'"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"anaconda-cloud": {},
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.6"
}
},
"nbformat": 4,
"nbformat_minor": 1
}