From 29736437802dc623dc54f099b956151c97813859 Mon Sep 17 00:00:00 2001 From: jdhughes-usgs Date: Tue, 11 May 2021 17:44:15 -0400 Subject: [PATCH 01/34] Initial develop branch (#2) --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 150627e..e7d23ef 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,7 +5,7 @@ on: - cron: '0 8 * * *' # run at 8 AM UTC (12 am PST) push: branches: - - master + - main - develop - 'release*' pull_request: @@ -39,7 +39,7 @@ jobs: - name: Base installation run: | - pip install . + pip install . --use-feature=in-tree-build - name: Print version run: | From fe1289b14e5407107d71d310c047c05e351c41ab Mon Sep 17 00:00:00 2001 From: Hofer-Julian <30049909+Hofer-Julian@users.noreply.github.com> Date: Wed, 12 May 2021 15:44:10 +0200 Subject: [PATCH 02/34] Fix typo in README (#4) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8c77c70..14aff4d 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # modflowapi -`modflowapi` is an extension to [xmiipy](https://pypi.org/project/xmipy/) for the MODFLOW API. +`modflowapi` is an extension to [xmipy](https://pypi.org/project/xmipy/) for the MODFLOW API. The `modflowapi` can be used to access functionality in the eXtended Model Interface (XMI) wrapper (XmiWrapper) and additional functionality specific to the MODFLOW API. Currently it is a joint development of the USGS and Deltares. `modflowapi` can be installed by running ``` pip install modflowapi -``` \ No newline at end of file +``` From de4452c64d2f0091068af177eae609db7ccce40c Mon Sep 17 00:00:00 2001 From: Joshua Larsen Date: Wed, 15 Feb 2023 13:25:46 -0800 Subject: [PATCH 03/34] modflowapi interface (#8) * update package: manual variable address assembly updated to use xmipy get_variable_addr() * update additional manual variable address assembly statements * Refactor code and added functionality: * add stress_period_start, stress_period_end Callbacks * fix ApiModel __repr__ * added Exchanges, TDIS, ATS, and SLN support * added ScalarInput and ScalarPackage support * update autotests * added parallel testing support through pytest-xdist * updated markers and split the extensions tests from the mf6 examples tests * added a test for ATS * update setup.cfg * update ci.yml * update(ListInput): add auxvar to stress_period_data when auxiliary variables are used * Allow None to be passed to stress_period_data.values to disable stresses for a package * updates: ApiModel, ApiSimulation, run_simulation * added a `totim` property on `ApiSimulation` and `ApiModel` * added docstrings to ApiModel property methods * updated termination message in run_simulation * added a finalize callback to Callbacks and run_simulation * add support for AUXNAME_CST * add(Head Monitor Example): Add a head monitor example application * ApiModel: adjust X based on nodetouser * ApiPackage: enforce lower cased variable names in get_advanced_var * ArrayPointer: trap for arrays that are not adjusted by reduced node numbers (ex. idomain) * update setup.cfg * try reformatting the xmipy installation instructions --- .github/workflows/ci.yml | 126 +- README.md | 3 +- autotest/__init__.py | 1 + autotest/conftest.py | 138 ++ autotest/pytest.ini | 7 + autotest/test_interface.py | 325 +++ autotest/test_mf6_examples.py | 53 + etc/requirements.pip.txt | 1 + examples/data/ats0/gwf_ats01a.ats | 10 + examples/data/ats0/gwf_ats01a.dis | 24 + examples/data/ats0/gwf_ats01a.ghb | 14 + examples/data/ats0/gwf_ats01a.ic | 6 + examples/data/ats0/gwf_ats01a.ims | 22 + examples/data/ats0/gwf_ats01a.nam | 15 + examples/data/ats0/gwf_ats01a.npf | 11 + examples/data/ats0/gwf_ats01a.obs | 10 + examples/data/ats0/gwf_ats01a.oc | 14 + examples/data/ats0/gwf_ats01a.sto | 17 + examples/data/ats0/gwf_ats01a.tdis | 14 + examples/data/ats0/gwf_ats01a.wel | 14 + examples/data/ats0/mfsim.nam | 19 + examples/data/dis_model/mfsim.nam | 19 + examples/data/dis_model/test_model.chd | 188 ++ examples/data/dis_model/test_model.dis | 34 + examples/data/dis_model/test_model.drn | 68 + examples/data/dis_model/test_model.evt | 68 + examples/data/dis_model/test_model.ic | 6 + examples/data/dis_model/test_model.ims | 20 + examples/data/dis_model/test_model.nam | 22 + examples/data/dis_model/test_model.npf | 12 + examples/data/dis_model/test_model.oc | 76 + examples/data/dis_model/test_model.rch | 68 + examples/data/dis_model/test_model.rcha | 10 + examples/data/dis_model/test_model.sto | 13 + examples/data/dis_model/test_model.tdis | 24 + examples/data/dis_model/test_model.wel | 81 + examples/data/disu_model/flow.chd | 27 + examples/data/disu_model/flow.disu | 31 + examples/data/disu_model/flow.disu.area.dat | 25 + examples/data/disu_model/flow.disu.cl12.dat | 121 + examples/data/disu_model/flow.disu.hwva.dat | 121 + examples/data/disu_model/flow.disu.iac.dat | 25 + examples/data/disu_model/flow.disu.ja.dat | 121 + examples/data/disu_model/flow.ic | 33 + examples/data/disu_model/flow.ims | 20 + examples/data/disu_model/flow.nam | 12 + examples/data/disu_model/flow.npf | 34 + examples/data/disu_model/flow.oc | 11 + examples/data/disu_model/flow.rch | 20 + examples/data/disu_model/flow.tdis | 12 + examples/data/disu_model/mfsim.nam | 19 + examples/data/disv_model/mfsim.nam | 19 + examples/data/disv_model/model.ims | 40 + examples/data/disv_model/simulation.tdis | 12 + examples/data/disv_model/tri_model.ic | 8 + examples/data/disv_model/tri_model.nam | 10 + examples/data/disv_model/tri_model.npf | 18 + examples/data/disv_model/tri_model.oc | 12 + examples/data/disv_model/tri_model_cnst.disv | 361 +++ .../data/disv_model/tri_model_cnst.disv.grb | Bin 0 -> 45560 bytes examples/data/disv_model/tri_model_gaus.disv | 461 ++++ examples/data/disv_model/tri_model_left.chd | 24 + examples/data/disv_model/tri_model_right.chd | 23 + examples/data/two_models/mfsim.nam | 24 + examples/data/two_models/model1.chd | 30 + examples/data/two_models/model1.dis | 30 + examples/data/two_models/model1.ic | 15 + examples/data/two_models/model1.mawq | 26 + examples/data/two_models/model1.nam | 13 + examples/data/two_models/model1.npf | 12 + examples/data/two_models/model1.oc | 11 + examples/data/two_models/model2.dis | 21 + examples/data/two_models/model2.ic | 8 + examples/data/two_models/model2.mawq | 26 + examples/data/two_models/model2.nam | 12 + examples/data/two_models/model2.npf | 34 + examples/data/two_models/model2.oc | 11 + examples/data/two_models/simulation.exg | 62 + examples/data/two_models/simulation.gnc | 58 + examples/data/two_models/simulation.ims | 20 + examples/data/two_models/simulation.mvr | 21 + examples/data/two_models/simulation.tdis | 12 + examples/notebooks/Head Monitor Example.ipynb | 255 ++ .../MODFLOW-API extensions objects.ipynb | 2047 +++++++++++++++++ examples/notebooks/Quickstart.ipynb | 572 +++++ modflowapi/__init__.py | 4 +- modflowapi/extensions/__init__.py | 3 + modflowapi/extensions/apiexchange.py | 20 + modflowapi/extensions/apimodel.py | 383 +++ modflowapi/extensions/apisimulation.py | 353 +++ modflowapi/extensions/data.py | 723 ++++++ modflowapi/extensions/pakbase.py | 717 ++++++ modflowapi/extensions/runner.py | 150 ++ modflowapi/version.py | 6 + setup.cfg | 90 + setup.py | 52 +- 96 files changed, 8932 insertions(+), 62 deletions(-) create mode 100644 autotest/__init__.py create mode 100644 autotest/conftest.py create mode 100644 autotest/pytest.ini create mode 100644 autotest/test_interface.py create mode 100644 autotest/test_mf6_examples.py create mode 100644 examples/data/ats0/gwf_ats01a.ats create mode 100644 examples/data/ats0/gwf_ats01a.dis create mode 100644 examples/data/ats0/gwf_ats01a.ghb create mode 100644 examples/data/ats0/gwf_ats01a.ic create mode 100644 examples/data/ats0/gwf_ats01a.ims create mode 100644 examples/data/ats0/gwf_ats01a.nam create mode 100644 examples/data/ats0/gwf_ats01a.npf create mode 100644 examples/data/ats0/gwf_ats01a.obs create mode 100644 examples/data/ats0/gwf_ats01a.oc create mode 100644 examples/data/ats0/gwf_ats01a.sto create mode 100644 examples/data/ats0/gwf_ats01a.tdis create mode 100644 examples/data/ats0/gwf_ats01a.wel create mode 100644 examples/data/ats0/mfsim.nam create mode 100644 examples/data/dis_model/mfsim.nam create mode 100644 examples/data/dis_model/test_model.chd create mode 100644 examples/data/dis_model/test_model.dis create mode 100644 examples/data/dis_model/test_model.drn create mode 100644 examples/data/dis_model/test_model.evt create mode 100644 examples/data/dis_model/test_model.ic create mode 100644 examples/data/dis_model/test_model.ims create mode 100644 examples/data/dis_model/test_model.nam create mode 100644 examples/data/dis_model/test_model.npf create mode 100644 examples/data/dis_model/test_model.oc create mode 100644 examples/data/dis_model/test_model.rch create mode 100644 examples/data/dis_model/test_model.rcha create mode 100644 examples/data/dis_model/test_model.sto create mode 100644 examples/data/dis_model/test_model.tdis create mode 100644 examples/data/dis_model/test_model.wel create mode 100644 examples/data/disu_model/flow.chd create mode 100644 examples/data/disu_model/flow.disu create mode 100644 examples/data/disu_model/flow.disu.area.dat create mode 100644 examples/data/disu_model/flow.disu.cl12.dat create mode 100644 examples/data/disu_model/flow.disu.hwva.dat create mode 100644 examples/data/disu_model/flow.disu.iac.dat create mode 100644 examples/data/disu_model/flow.disu.ja.dat create mode 100644 examples/data/disu_model/flow.ic create mode 100644 examples/data/disu_model/flow.ims create mode 100644 examples/data/disu_model/flow.nam create mode 100644 examples/data/disu_model/flow.npf create mode 100644 examples/data/disu_model/flow.oc create mode 100644 examples/data/disu_model/flow.rch create mode 100644 examples/data/disu_model/flow.tdis create mode 100644 examples/data/disu_model/mfsim.nam create mode 100644 examples/data/disv_model/mfsim.nam create mode 100644 examples/data/disv_model/model.ims create mode 100644 examples/data/disv_model/simulation.tdis create mode 100644 examples/data/disv_model/tri_model.ic create mode 100644 examples/data/disv_model/tri_model.nam create mode 100644 examples/data/disv_model/tri_model.npf create mode 100644 examples/data/disv_model/tri_model.oc create mode 100644 examples/data/disv_model/tri_model_cnst.disv create mode 100644 examples/data/disv_model/tri_model_cnst.disv.grb create mode 100644 examples/data/disv_model/tri_model_gaus.disv create mode 100644 examples/data/disv_model/tri_model_left.chd create mode 100644 examples/data/disv_model/tri_model_right.chd create mode 100644 examples/data/two_models/mfsim.nam create mode 100644 examples/data/two_models/model1.chd create mode 100644 examples/data/two_models/model1.dis create mode 100644 examples/data/two_models/model1.ic create mode 100644 examples/data/two_models/model1.mawq create mode 100644 examples/data/two_models/model1.nam create mode 100644 examples/data/two_models/model1.npf create mode 100644 examples/data/two_models/model1.oc create mode 100644 examples/data/two_models/model2.dis create mode 100644 examples/data/two_models/model2.ic create mode 100644 examples/data/two_models/model2.mawq create mode 100644 examples/data/two_models/model2.nam create mode 100644 examples/data/two_models/model2.npf create mode 100644 examples/data/two_models/model2.oc create mode 100644 examples/data/two_models/simulation.exg create mode 100644 examples/data/two_models/simulation.gnc create mode 100644 examples/data/two_models/simulation.ims create mode 100644 examples/data/two_models/simulation.mvr create mode 100644 examples/data/two_models/simulation.tdis create mode 100644 examples/notebooks/Head Monitor Example.ipynb create mode 100644 examples/notebooks/MODFLOW-API extensions objects.ipynb create mode 100644 examples/notebooks/Quickstart.ipynb create mode 100644 modflowapi/extensions/__init__.py create mode 100644 modflowapi/extensions/apiexchange.py create mode 100644 modflowapi/extensions/apimodel.py create mode 100644 modflowapi/extensions/apisimulation.py create mode 100644 modflowapi/extensions/data.py create mode 100644 modflowapi/extensions/pakbase.py create mode 100644 modflowapi/extensions/runner.py create mode 100644 modflowapi/version.py create mode 100644 setup.cfg diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e7d23ef..6d68bf8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,10 +26,10 @@ jobs: # check out repo - name: Checkout repo - uses: actions/checkout@v2.3.4 + uses: actions/checkout@v3 - name: Setup Python 3.8 - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: 3.8 @@ -39,15 +39,15 @@ jobs: - name: Base installation run: | - pip install . --use-feature=in-tree-build - + pip install -e . + - name: Print version run: | python -c "import modflowapi; print(modflowapi.__version__)" lint: - name: linting + name: lint runs-on: ubuntu-latest strategy: fail-fast: false @@ -59,24 +59,27 @@ jobs: steps: # check out repo - name: Checkout repo - uses: actions/checkout@v2.3.4 + uses: actions/checkout@v3 - # Standard python fails on windows without GDAL installation. Using + # Standard python fails on Windows without GDAL installation. Using # standard python here since only linting on linux. # Use standard bash shell with standard python - name: Setup Python 3.8 - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: 3.8 + cache: 'pip' + cache-dependency-path: setup.cfg - name: Print python version run: | python --version - - name: Install Python 3.8 packages + - name: Install Python dependencies run: | python -m pip install --upgrade pip - pip install -r etc/requirements.pip.txt + pip install . + pip install ".[lint]" - name: Run black run: | @@ -93,3 +96,106 @@ jobs: run: | pylint --jobs=2 --errors-only --exit-zero ./modflowapi + autotest_extensions: + name: modflowapi extensions autotests + needs: lint + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ ubuntu-latest, macos-latest, windows-latest ] + python-version: [ 3.8, 3.9, "3.10"] + defaults: + run: + shell: bash + + steps: + # check out repo + - name: Checkout repo + uses: actions/checkout@v3 + + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + cache: 'pip' + cache-dependency-path: setup.cfg + + - name: Install Python dependencies + if: runner.os != 'Windows' + run: | + pip install --upgrade pip + pip install . + pip install ".[test]" + + - name: Install Python dependencies Windows + if: runner.os == 'Windows' + run: | + python.exe -m pip install --upgrade pip + python.exe -m pip install . + python.exe -m pip install ".[test]" + + - name: Install modflow executables + uses: modflowpy/install-modflow-action@v1 + with: + path: ~/work/modflowapi/modflowapi/autotest + repo: modflow6-nightly-build + + - name: Run autotests + working-directory: ./autotest + shell: bash -l {0} + run: | + # chmod a+x libmf6* + pytest -n auto -m "not mf6" + + autotest_mf6_examples: + name: modflowapi mf6 examples autotests + needs: lint + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ ubuntu-latest, macos-latest, windows-latest ] + python-version: [ 3.8, 3.9, "3.10"] + defaults: + run: + shell: bash + + steps: + # check out repo + - name: Checkout repo + uses: actions/checkout@v3 + + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + cache: 'pip' + cache-dependency-path: setup.cfg + + - name: Install Python dependencies + if: runner.os != 'Windows' + run: | + pip install --upgrade pip + pip install . + pip install ".[test]" + + - name: Install Python dependencies Windows + if: runner.os == 'Windows' + run: | + python.exe -m pip install --upgrade pip + python.exe -m pip install . + python.exe -m pip install ".[test]" + + - name: Install modflow executables + uses: modflowpy/install-modflow-action@v1 + with: + path: ~/work/modflowapi/modflowapi/autotest + repo: modflow6-nightly-build + + - name: Run autotests + working-directory: ./autotest + shell: bash -l {0} + run: | + # chmod a+x libmf6* + pytest -n auto -m "mf6 and not extensions" \ No newline at end of file diff --git a/README.md b/README.md index 14aff4d..b05708a 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,8 @@ `modflowapi` is an extension to [xmipy](https://pypi.org/project/xmipy/) for the MODFLOW API. -The `modflowapi` can be used to access functionality in the eXtended Model Interface (XMI) wrapper (XmiWrapper) and additional functionality specific to the MODFLOW API. Currently it is a joint development of the USGS and Deltares. +The `modflowapi` can be used to access functionality in the eXtended Model Interface (XMI) wrapper (XmiWrapper) +and additional functionality specific to the MODFLOW API. Currently it is a joint development of the USGS and Deltares. `modflowapi` can be installed by running ``` diff --git a/autotest/__init__.py b/autotest/__init__.py new file mode 100644 index 0000000..042b236 --- /dev/null +++ b/autotest/__init__.py @@ -0,0 +1 @@ +# init file for pytest \ No newline at end of file diff --git a/autotest/conftest.py b/autotest/conftest.py new file mode 100644 index 0000000..cf0540f --- /dev/null +++ b/autotest/conftest.py @@ -0,0 +1,138 @@ +from itertools import groupby +from os import linesep +from pathlib import Path +from tempfile import gettempdir + +import pytest +from filelock import FileLock + + +__mf6_examples = "mf6_examples" +__mf6_examples_path = Path(gettempdir()) / __mf6_examples +__mf6_examples_lock = FileLock(Path(gettempdir()) / f"{__mf6_examples}.lock") + + +def get_mf6_examples_path() -> Path: + pytest.importorskip("modflow_devtools") + from modflow_devtools.download import download_and_unzip + + # use file lock so mf6 distribution is downloaded once, + # even when tests are run in parallel with pytest-xdist + __mf6_examples_lock.acquire() + try: + if not __mf6_examples_path.is_dir(): + __mf6_examples_path.mkdir(exist_ok=True) + download_and_unzip( + url="https://github.com/MODFLOW-USGS/modflow6-examples/releases/download/current/modflow6-examples.zip", + path=__mf6_examples_path, + verbose=True, + ) + return __mf6_examples_path + finally: + __mf6_examples_lock.release() + +def is_nested(namfile) -> bool: + p = Path(namfile) + if not p.is_file() or not p.name.endswith(".nam"): + raise ValueError(f"Expected a namfile path, got {p}") + + return p.parent.parent.name != __mf6_examples + + +def pytest_generate_tests(metafunc): + # examples to skip: + # - ex-gwtgwt-mt3dms-p10: https://github.com/MODFLOW-USGS/modflow6/pull/1008 + exclude = ["ex-gwt-gwtgwt-mt3dms-p10"] + namfiles = [ + str(p) + for p in get_mf6_examples_path().rglob("mfsim.nam") + if not any(e in str(p) for e in exclude) + ] + + # parametrization by model + # - single namfile per test case + # - no coupling (only first model in each simulation subdir is used) + key = "mf6_example_namfile" + if key in metafunc.fixturenames: + metafunc.parametrize(key, sorted(namfiles)) + + # parametrization by simulation + # - each test case gets an ordered list of 1+ namfiles + # - models can be coupled (run in order provided, sharing workspace) + key = "mf6_example_namfiles" + if key in metafunc.fixturenames: + simulations = [] + + def simulation_name_from_model_path(p): + p = Path(p) + return p.parent.parent.name if is_nested(p) else p.parent.name + + for model_name, model_namfiles in groupby( + namfiles, key=simulation_name_from_model_path + ): + models = sorted( + list(model_namfiles) + ) # sort in alphabetical order (gwf < gwt) + simulations.append(models) + print( + f"Simulation {model_name} has {len(models)} model(s):\n" + f"{linesep.join(model_namfiles)}" + ) + + def simulation_name_from_model_namfiles(mnams): + try: + namfile = next(iter(mnams), None) + except TypeError: + namfile = None + if namfile is None: + pytest.skip("No namfiles (expected ordered collection)") + namfile = Path(namfile) + return ( + namfile.parent.parent if is_nested(namfile) else namfile.parent + ).name + + metafunc.parametrize( + key, simulations, ids=simulation_name_from_model_namfiles + ) + + +@pytest.fixture(scope="function") +def tmpdir(tmpdir_factory, request) -> Path: + node = ( + request.node.name.replace("/", "_") + .replace("\\", "_") + .replace(":", "_") + ) + temp = Path(tmpdir_factory.mktemp(node)) + yield Path(temp) + + keep = request.config.getoption("--keep") + if keep: + copytree(temp, Path(keep) / temp.name) + + keep_failed = request.config.getoption("--keep-failed") + if keep_failed and request.node.rep_call.failed: + copytree(temp, Path(keep_failed) / temp.name) + + +def pytest_addoption(parser): + parser.addoption( + "-K", + "--keep", + action="store", + default=None, + help="Move the contents of temporary test directories to correspondingly named subdirectories at the given " + "location after tests complete. This option can be used to exclude test results from automatic cleanup, " + "e.g. for manual inspection. The provided path is created if it does not already exist. An error is " + "thrown if any matching files already exist.", + ) + + parser.addoption( + "--keep-failed", + action="store", + default=None, + help="Move the contents of temporary test directories to correspondingly named subdirectories at the given " + "location if the test case fails. This option automatically saves the outputs of failed tests in the " + "given location. The path is created if it doesn't already exist. An error is thrown if files with the " + "same names already exist in the given location.", + ) \ No newline at end of file diff --git a/autotest/pytest.ini b/autotest/pytest.ini new file mode 100644 index 0000000..d7b645a --- /dev/null +++ b/autotest/pytest.ini @@ -0,0 +1,7 @@ +[pytest] +addopts = -ra +python_files = + test_*.py +markers = + mf6: tests for modflow 6 examples + extensions: tests for modflowapi extensions \ No newline at end of file diff --git a/autotest/test_interface.py b/autotest/test_interface.py new file mode 100644 index 0000000..ce1df81 --- /dev/null +++ b/autotest/test_interface.py @@ -0,0 +1,325 @@ +import pytest +import pathlib +from modflowapi.extensions.pakbase import ( + ArrayPackage, + ListPackage, + AdvancedPackage, +) +from modflowapi import Callbacks, run_simulation +import shutil +import numpy as np + +pytestmark = pytest.mark.extensions +so = "libmf6" +data_pth = pathlib.Path("../examples/data") + + +def test_dis_model(tmpdir): + def callback(sim, step): + """ + Callback function + + Parameters + ---------- + sim : modflowapi.ApiSimulation object + step : Enum + step is the simulation step defined by Callbacks + """ + if step == Callbacks.initialize: + if len(sim.models) != 1: + raise AssertionError("Invalid number of models") + + model = sim.test_model + if len(model.package_names) != 16: + raise AssertionError("Invalid number of packages") + + if len(model.package_types) != 15: + raise AssertionError("Invalid number of package types") + + if model.shape != (1, 10, 10): + raise AssertionError("ApiModel shape is incorrect") + + if model.size != 100: + raise AssertionError("ApiModel size is incorrect") + + if (model.kper, model.kstp) != (-1, -1): + raise AssertionError( + "ApiModel has advanced prior to initialization callback" + ) + + dis = model.dis + if not isinstance(dis, ArrayPackage): + raise TypeError("DIS package has incorrect base class type") + + wel = model.wel + if not isinstance(wel, ListPackage): + raise TypeError("WEL package has incorrect base class type") + + gnc = model.gnc + if not isinstance(gnc, AdvancedPackage): + raise TypeError("GNC package has incorrect base class type") + + rch = model.rch + if len(rch) != 2: + raise AssertionError( + "ApiModel object not returning multiple packages" + ) + + idomain = dis.idomain.values + if not isinstance(idomain, np.ndarray): + raise TypeError("Expecting a numpy array for idomain") + + elif step == Callbacks.stress_period_start: + if sim.kstp != 0: + raise AssertionError( + "Solution advanced prior to stress_period_start callback" + ) + + elif step == Callbacks.timestep_start: + if sim.iteration != -1: + raise AssertionError( + "Solution advanced prior to timestep_start callback" + ) + + factor = ((1 + sim.kstp) / sim.nstp) * 0.5 + spd = sim.test_model.wel.stress_period_data.values + sim.test_model.wel.stress_period_data["flux"] *= factor + + spd2 = sim.test_model.wel.stress_period_data.values + if not np.allclose((spd["flux"] * factor), spd2["flux"]): + raise AssertionError("Pointer not being set properly") + + if sim.kper >= 3 and sim.kstp == 0: + spd = sim.test_model.wel.stress_period_data.values + nbound0 = sim.test_model.wel.nbound + spd.resize((nbound0 + 1), refcheck=False) + spd[-1] = ((0, 1, 5), -20, 1.0, 2.0) + sim.test_model.wel.stress_period_data.values = spd + if sim.test_model.wel.nbound != nbound0 + 1: + raise AssertionError("Resize routine not properly working") + + name = "dis_model" + sim_pth = data_pth / name + test_pth = tmpdir / name + shutil.copytree(sim_pth, test_pth, dirs_exist_ok=True) + + try: + run_simulation(so, test_pth, callback) + except Exception as e: + raise Exception(e) + + +def test_disv_model(tmpdir): + def callback(sim, step): + """ + Callback function + + Parameters + ---------- + sim : modflowapi.ApiSimulation object + step : Enum + step is the simulation step defined by Callbacks + """ + if step == Callbacks.initialize: + if len(sim.models) != 1: + raise AssertionError("Invalid number of models") + + model = sim.gwf_1 + if len(model.package_names) != 12: + raise AssertionError("Invalid number of packages") + + if len(model.package_types) != 11: + raise AssertionError("Invalid number of package types") + + if model.shape != (4, 200): + raise AssertionError("ApiModel shape is incorrect") + + if model.size != 800: + raise AssertionError("ApiModel size is incorrect") + + if (model.kper, model.kstp) != (-1, -1): + raise AssertionError( + "ApiModel has advanced prior to initialization callback" + ) + + dis = model.dis + if not isinstance(dis, ArrayPackage): + raise TypeError("DIS package has incorrect base class type") + + chd = model.chd_left + if not isinstance(chd, ListPackage): + raise TypeError("CHD package has incorrect base class type") + + hfb = model.hfb + if not isinstance(hfb, AdvancedPackage): + raise TypeError("HFB package has incorrect base class type") + + chd = model.chd + if len(chd) != 2: + raise AssertionError( + "ApiModel object not returning multiple packages" + ) + + top = dis.top.values + if not isinstance(top, np.ndarray): + raise TypeError("Expecting a numpy array for top") + + elif step == Callbacks.stress_period_start: + if sim.kstp != 0: + raise AssertionError( + "Solution advanced prior to stress_period_start callback" + ) + + elif step == Callbacks.timestep_start: + if sim.iteration != -1: + raise AssertionError( + "Solution advanced prior to timestep_start callback" + ) + + factor = 0.75 + spd = sim.gwf_1.chd_left.stress_period_data.values + sim.gwf_1.chd_left.stress_period_data["head"] *= factor + + spd2 = sim.gwf_1.chd_left.stress_period_data.values + if not np.allclose((spd["head"] * factor), spd2["head"]): + raise AssertionError("Pointer not being set properly") + + name = "disv_model" + sim_pth = data_pth / name + test_pth = tmpdir / name + shutil.copytree(sim_pth, test_pth, dirs_exist_ok=True) + + try: + run_simulation(so, test_pth, callback) + except Exception as e: + raise Exception(e) + + +def test_disu_model(tmpdir): + def callback(sim, step): + """ + Callback function + + Parameters + ---------- + sim : modflowapi.ApiSimulation object + step : Enum + step is the simulation step defined by Callbacks + """ + if step == Callbacks.initialize: + if len(sim.models) != 1: + raise AssertionError("Invalid number of models") + + model = sim.gwf_1 + if len(model.package_names) != 12: + raise AssertionError("Invalid number of packages") + + if len(model.package_types) != 12: + raise AssertionError("Invalid number of package types") + + if model.shape != (121,): + raise AssertionError("ApiModel shape is incorrect") + + if model.size != 121: + raise AssertionError("ApiModel size is incorrect") + + if (model.kper, model.kstp) != (-1, -1): + raise AssertionError( + "ApiModel has advanced prior to initialization callback" + ) + + dis = model.dis + if not isinstance(dis, ArrayPackage): + raise TypeError("DIS package has incorrect base class type") + + rch = model.rch + if not isinstance(rch, ListPackage): + raise TypeError("RCH package has incorrect base class type") + + mvr = model.mvr + if not isinstance(mvr, AdvancedPackage): + raise TypeError("MVR package has incorrect base class type") + + top = dis.top.values + if not isinstance(top, np.ndarray): + raise TypeError("Expecting a numpy array for top") + + elif step == Callbacks.stress_period_start: + if sim.kstp != 0: + raise AssertionError( + "Solution advanced prior to stress_period_start callback" + ) + + elif step == Callbacks.timestep_start: + if sim.iteration != -1: + raise AssertionError( + "Solution advanced prior to timestep_start callback" + ) + + factor = 1.75 + spd = sim.gwf_1.rch.stress_period_data.values + sim.gwf_1.rch.stress_period_data["recharge"] += factor + + spd2 = sim.gwf_1.rch.stress_period_data.values + if not np.allclose((spd["recharge"] + factor), spd2["recharge"]): + raise AssertionError("Pointer not being set properly") + + name = "disu_model" + sim_pth = data_pth / name + test_pth = tmpdir / name + shutil.copytree(sim_pth, test_pth, dirs_exist_ok=True) + + try: + run_simulation(so, test_pth, callback) + except Exception as e: + raise Exception(e) + + +def test_two_models(tmpdir): + def callback(sim, step): + """ + Callback function + + Parameters + ---------- + sim : modflowapi.ApiSimulation object + step : Enum + step is the simulation step defined by Callbacks + """ + if step == Callbacks.initialize: + if len(sim.models) != 2: + raise AssertionError("Invalid number of models") + + name = "two_models" + sim_pth = data_pth / name + test_pth = tmpdir / name + shutil.copytree(sim_pth, test_pth, dirs_exist_ok=True) + + try: + run_simulation(so, test_pth, callback) + except Exception as e: + raise Exception(e) + + +def test_ats_model(tmpdir): + def callback(sim, step): + if step == Callbacks.stress_period_start: + if sim.kper == 0 and sim.kstp == 0: + delt0 = sim.delt + + if step == Callbacks.timestep_start: + if sim.kstp == 1: + if delt0 == sim.delt: + raise AssertionError( + "ATS routines not reducing timestep length" + ) + + name = "ats0" + sim_pth = data_pth / name + test_pth = tmpdir / name + shutil.copytree(sim_pth, test_pth, dirs_exist_ok=True) + + try: + run_simulation(so, test_pth, callback) + except Exception as e: + raise Exception(e) \ No newline at end of file diff --git a/autotest/test_mf6_examples.py b/autotest/test_mf6_examples.py new file mode 100644 index 0000000..f2f5634 --- /dev/null +++ b/autotest/test_mf6_examples.py @@ -0,0 +1,53 @@ +from pathlib import Path +from shutil import copytree +from modflowapi import run_simulation + +import pytest +from autotest.conftest import is_nested + +pytestmark = pytest.mark.mf6 +dll = "libmf6" + + +def test_mf6_example_simulations(tmpdir, mf6_example_namfiles): + """ + MF6 examples parametrized by simulation. `mf6_example_namfiles` is a list + of models to run in order provided. Coupled models share the same tempdir + + Parameters + ---------- + tmpdir: function-scoped temporary directory fixture + mf6_example_namfiles: ordered list of namfiles for 1+ coupled models + """ + if len(mf6_example_namfiles) == 0: + pytest.skip("No namfiles (expected ordered collection)") + namfile = Path(mf6_example_namfiles[0]) + + nested = is_nested(namfile) + tmpdir = Path( + tmpdir / "workspace" + ) + + copytree( + src=namfile.parent.parent if nested else namfile.parent, dst=tmpdir + ) + + def callback(sim, step): + pass + + def run_models(): + # run models in order received (should be alphabetical, so gwf precedes gwt) + for namfile in mf6_example_namfiles: + namfile_path = Path(namfile).resolve() + namfile_name = namfile_path.name + model_path = namfile_path.parent + + # working directory must be named according to the name file's parent (e.g. + # 'mf6gwf') because coupled models refer to each other with relative paths + wrkdir = Path(tmpdir / model_path.name) if nested else tmpdir + try: + run_simulation(dll, wrkdir, callback, verbose=True) + except Exception as e: + raise Exception(e) + + run_models() diff --git a/etc/requirements.pip.txt b/etc/requirements.pip.txt index 7091d3b..f65b07c 100644 --- a/etc/requirements.pip.txt +++ b/etc/requirements.pip.txt @@ -7,5 +7,6 @@ coverage requests appdirs numpy +pandas bmipy xmipy diff --git a/examples/data/ats0/gwf_ats01a.ats b/examples/data/ats0/gwf_ats01a.ats new file mode 100644 index 0000000..51ff2dd --- /dev/null +++ b/examples/data/ats0/gwf_ats01a.ats @@ -0,0 +1,10 @@ +# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. +BEGIN dimensions + MAXATS 2 +END dimensions + +BEGIN perioddata + 1 5.00000000 1.00100000E-05 10.00000000 2.00000000 5.00000000 + 8 5.00000000 1.00100000E-05 10.00000000 2.00000000 5.00000000 +END perioddata + diff --git a/examples/data/ats0/gwf_ats01a.dis b/examples/data/ats0/gwf_ats01a.dis new file mode 100644 index 0000000..d1f42df --- /dev/null +++ b/examples/data/ats0/gwf_ats01a.dis @@ -0,0 +1,24 @@ +# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. +BEGIN options +END options + +BEGIN dimensions + NLAY 1 + NROW 1 + NCOL 2 +END dimensions + +BEGIN griddata + delr + CONSTANT 100.00000000 + delc + CONSTANT 1.00000000 + top + CONSTANT 100.00000000 + botm + CONSTANT 0.00000000 + idomain + INTERNAL FACTOR 1 + 1 1 +END griddata + diff --git a/examples/data/ats0/gwf_ats01a.ghb b/examples/data/ats0/gwf_ats01a.ghb new file mode 100644 index 0000000..fa6adfe --- /dev/null +++ b/examples/data/ats0/gwf_ats01a.ghb @@ -0,0 +1,14 @@ +# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. +BEGIN options + PRINT_INPUT + PRINT_FLOWS +END options + +BEGIN dimensions + MAXBOUND 1 +END dimensions + +BEGIN period 1 + 1 1 1 50.00000000 1.00000000 +END period 1 + diff --git a/examples/data/ats0/gwf_ats01a.ic b/examples/data/ats0/gwf_ats01a.ic new file mode 100644 index 0000000..d8c8b3c --- /dev/null +++ b/examples/data/ats0/gwf_ats01a.ic @@ -0,0 +1,6 @@ +# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. +BEGIN griddata + strt + CONSTANT 50.00000000 +END griddata + diff --git a/examples/data/ats0/gwf_ats01a.ims b/examples/data/ats0/gwf_ats01a.ims new file mode 100644 index 0000000..d7c7244 --- /dev/null +++ b/examples/data/ats0/gwf_ats01a.ims @@ -0,0 +1,22 @@ +# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. +BEGIN options + PRINT_OPTION summary +END options + +BEGIN nonlinear + OUTER_DVCLOSE 1.00000000E-06 + OUTER_MAXIMUM 10 + UNDER_RELAXATION dbd + UNDER_RELAXATION_THETA 0.70000000 +END nonlinear + +BEGIN linear + INNER_MAXIMUM 2 + INNER_DVCLOSE 1.00000000E-06 + inner_rclose 1.00000000E-06 + LINEAR_ACCELERATION cg + RELAXATION_FACTOR 0.97000000 + SCALING_METHOD none + REORDERING_METHOD none +END linear + diff --git a/examples/data/ats0/gwf_ats01a.nam b/examples/data/ats0/gwf_ats01a.nam new file mode 100644 index 0000000..b55815a --- /dev/null +++ b/examples/data/ats0/gwf_ats01a.nam @@ -0,0 +1,15 @@ +# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. +BEGIN options +END options + +BEGIN packages + DIS6 gwf_ats01a.dis dis + IC6 gwf_ats01a.ic ic + NPF6 gwf_ats01a.npf npf + STO6 gwf_ats01a.sto sto + WEL6 gwf_ats01a.wel wel_0 + GHB6 gwf_ats01a.ghb ghb_0 + OC6 gwf_ats01a.oc oc + OBS6 gwf_ats01a.obs head_obs +END packages + diff --git a/examples/data/ats0/gwf_ats01a.npf b/examples/data/ats0/gwf_ats01a.npf new file mode 100644 index 0000000..6093b98 --- /dev/null +++ b/examples/data/ats0/gwf_ats01a.npf @@ -0,0 +1,11 @@ +# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. +BEGIN options +END options + +BEGIN griddata + icelltype + CONSTANT 1 + k + CONSTANT 1.00000000 +END griddata + diff --git a/examples/data/ats0/gwf_ats01a.obs b/examples/data/ats0/gwf_ats01a.obs new file mode 100644 index 0000000..b5d05f7 --- /dev/null +++ b/examples/data/ats0/gwf_ats01a.obs @@ -0,0 +1,10 @@ +# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. +BEGIN options + DIGITS 20 +END options + +BEGIN continuous FILEOUT gwf_ats01a.obs.csv + obs1 head 1 1 1 + obs2 head 1 1 2 +END continuous FILEOUT gwf_ats01a.obs.csv + diff --git a/examples/data/ats0/gwf_ats01a.oc b/examples/data/ats0/gwf_ats01a.oc new file mode 100644 index 0000000..71a7f21 --- /dev/null +++ b/examples/data/ats0/gwf_ats01a.oc @@ -0,0 +1,14 @@ +# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. +BEGIN options + BUDGET FILEOUT gwf_ats01a.cbc + BUDGETCSV FILEOUT gwf_ats01a.csv + HEAD FILEOUT gwf_ats01a.hds + HEAD PRINT_FORMAT COLUMNS 10 WIDTH 15 DIGITS 6 GENERAL +END options + +BEGIN period 1 + SAVE HEAD ALL + PRINT HEAD ALL + PRINT BUDGET ALL +END period 1 + diff --git a/examples/data/ats0/gwf_ats01a.sto b/examples/data/ats0/gwf_ats01a.sto new file mode 100644 index 0000000..1bc176c --- /dev/null +++ b/examples/data/ats0/gwf_ats01a.sto @@ -0,0 +1,17 @@ +# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. +BEGIN options +END options + +BEGIN griddata + iconvert + CONSTANT 1 + ss + CONSTANT 0.00000000 + sy + CONSTANT 0.10000000 +END griddata + +BEGIN period 1 + TRANSIENT +END period 1 + diff --git a/examples/data/ats0/gwf_ats01a.tdis b/examples/data/ats0/gwf_ats01a.tdis new file mode 100644 index 0000000..bd34906 --- /dev/null +++ b/examples/data/ats0/gwf_ats01a.tdis @@ -0,0 +1,14 @@ +# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. +BEGIN options + TIME_UNITS days + ATS6 FILEIN gwf_ats01a.ats +END options + +BEGIN dimensions + NPER 1 +END dimensions + +BEGIN perioddata + 10.00000000 1 1.00000000 +END perioddata + diff --git a/examples/data/ats0/gwf_ats01a.wel b/examples/data/ats0/gwf_ats01a.wel new file mode 100644 index 0000000..2c50997 --- /dev/null +++ b/examples/data/ats0/gwf_ats01a.wel @@ -0,0 +1,14 @@ +# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. +BEGIN options + PRINT_INPUT + PRINT_FLOWS +END options + +BEGIN dimensions + MAXBOUND 1 +END dimensions + +BEGIN period 1 + 1 1 2 -10.00000000 +END period 1 + diff --git a/examples/data/ats0/mfsim.nam b/examples/data/ats0/mfsim.nam new file mode 100644 index 0000000..46a2634 --- /dev/null +++ b/examples/data/ats0/mfsim.nam @@ -0,0 +1,19 @@ +# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. +BEGIN options +END options + +BEGIN timing + TDIS6 gwf_ats01a.tdis +END timing + +BEGIN models + gwf6 gwf_ats01a.nam gwf_ats01a +END models + +BEGIN exchanges +END exchanges + +BEGIN solutiongroup 1 + ims6 gwf_ats01a.ims gwf_ats01a +END solutiongroup 1 + diff --git a/examples/data/dis_model/mfsim.nam b/examples/data/dis_model/mfsim.nam new file mode 100644 index 0000000..3e36193 --- /dev/null +++ b/examples/data/dis_model/mfsim.nam @@ -0,0 +1,19 @@ +# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. +BEGIN options +END options + +BEGIN timing + TDIS6 test_model.tdis +END timing + +BEGIN models + gwf6 test_model.nam test_model +END models + +BEGIN exchanges +END exchanges + +BEGIN solutiongroup 1 + ims6 test_model.ims test_model +END solutiongroup 1 + diff --git a/examples/data/dis_model/test_model.chd b/examples/data/dis_model/test_model.chd new file mode 100644 index 0000000..25556d1 --- /dev/null +++ b/examples/data/dis_model/test_model.chd @@ -0,0 +1,188 @@ +# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. +BEGIN options +END options + +BEGIN dimensions + MAXBOUND 12 +END dimensions + +BEGIN period 1 + 1 1 3 95.00000000 + 1 1 4 95.00000000 + 1 1 5 95.00000000 + 1 1 6 95.00000000 + 1 1 7 95.00000000 + 1 1 8 95.00000000 + 1 10 3 75.00000000 + 1 10 4 75.00000000 + 1 10 5 75.00000000 + 1 10 6 75.00000000 + 1 10 7 75.00000000 + 1 10 8 75.00000000 +END period 1 + +BEGIN period 2 + 1 1 3 95.00000000 + 1 1 4 95.00000000 + 1 1 5 95.00000000 + 1 1 6 95.00000000 + 1 1 7 95.00000000 + 1 1 8 95.00000000 + 1 10 3 75.00000000 + 1 10 4 75.00000000 + 1 10 5 75.00000000 + 1 10 6 75.00000000 + 1 10 7 75.00000000 + 1 10 8 75.00000000 +END period 2 + +BEGIN period 3 + 1 1 3 95.00000000 + 1 1 4 95.00000000 + 1 1 5 95.00000000 + 1 1 6 95.00000000 + 1 1 7 95.00000000 + 1 1 8 95.00000000 + 1 10 3 75.00000000 + 1 10 4 75.00000000 + 1 10 5 75.00000000 + 1 10 6 75.00000000 + 1 10 7 75.00000000 + 1 10 8 75.00000000 +END period 3 + +BEGIN period 4 + 1 1 3 95.00000000 + 1 1 4 95.00000000 + 1 1 5 95.00000000 + 1 1 6 95.00000000 + 1 1 7 95.00000000 + 1 1 8 95.00000000 + 1 10 3 75.00000000 + 1 10 4 75.00000000 + 1 10 5 75.00000000 + 1 10 6 75.00000000 + 1 10 7 75.00000000 + 1 10 8 75.00000000 +END period 4 + +BEGIN period 5 + 1 1 3 95.00000000 + 1 1 4 95.00000000 + 1 1 5 95.00000000 + 1 1 6 95.00000000 + 1 1 7 95.00000000 + 1 1 8 95.00000000 + 1 10 3 75.00000000 + 1 10 4 75.00000000 + 1 10 5 75.00000000 + 1 10 6 75.00000000 + 1 10 7 75.00000000 + 1 10 8 75.00000000 +END period 5 + +BEGIN period 6 + 1 1 3 95.00000000 + 1 1 4 95.00000000 + 1 1 5 95.00000000 + 1 1 6 95.00000000 + 1 1 7 95.00000000 + 1 1 8 95.00000000 + 1 10 3 75.00000000 + 1 10 4 75.00000000 + 1 10 5 75.00000000 + 1 10 6 75.00000000 + 1 10 7 75.00000000 + 1 10 8 75.00000000 +END period 6 + +BEGIN period 7 + 1 1 3 95.00000000 + 1 1 4 95.00000000 + 1 1 5 95.00000000 + 1 1 6 95.00000000 + 1 1 7 95.00000000 + 1 1 8 95.00000000 + 1 10 3 75.00000000 + 1 10 4 75.00000000 + 1 10 5 75.00000000 + 1 10 6 75.00000000 + 1 10 7 75.00000000 + 1 10 8 75.00000000 +END period 7 + +BEGIN period 8 + 1 1 3 95.00000000 + 1 1 4 95.00000000 + 1 1 5 95.00000000 + 1 1 6 95.00000000 + 1 1 7 95.00000000 + 1 1 8 95.00000000 + 1 10 3 75.00000000 + 1 10 4 75.00000000 + 1 10 5 75.00000000 + 1 10 6 75.00000000 + 1 10 7 75.00000000 + 1 10 8 75.00000000 +END period 8 + +BEGIN period 9 + 1 1 3 95.00000000 + 1 1 4 95.00000000 + 1 1 5 95.00000000 + 1 1 6 95.00000000 + 1 1 7 95.00000000 + 1 1 8 95.00000000 + 1 10 3 75.00000000 + 1 10 4 75.00000000 + 1 10 5 75.00000000 + 1 10 6 75.00000000 + 1 10 7 75.00000000 + 1 10 8 75.00000000 +END period 9 + +BEGIN period 10 + 1 1 3 95.00000000 + 1 1 4 95.00000000 + 1 1 5 95.00000000 + 1 1 6 95.00000000 + 1 1 7 95.00000000 + 1 1 8 95.00000000 + 1 10 3 75.00000000 + 1 10 4 75.00000000 + 1 10 5 75.00000000 + 1 10 6 75.00000000 + 1 10 7 75.00000000 + 1 10 8 75.00000000 +END period 10 + +BEGIN period 11 + 1 1 3 95.00000000 + 1 1 4 95.00000000 + 1 1 5 95.00000000 + 1 1 6 95.00000000 + 1 1 7 95.00000000 + 1 1 8 95.00000000 + 1 10 3 75.00000000 + 1 10 4 75.00000000 + 1 10 5 75.00000000 + 1 10 6 75.00000000 + 1 10 7 75.00000000 + 1 10 8 75.00000000 +END period 11 + +BEGIN period 12 + 1 1 3 95.00000000 + 1 1 4 95.00000000 + 1 1 5 95.00000000 + 1 1 6 95.00000000 + 1 1 7 95.00000000 + 1 1 8 95.00000000 + 1 10 3 75.00000000 + 1 10 4 75.00000000 + 1 10 5 75.00000000 + 1 10 6 75.00000000 + 1 10 7 75.00000000 + 1 10 8 75.00000000 +END period 12 + diff --git a/examples/data/dis_model/test_model.dis b/examples/data/dis_model/test_model.dis new file mode 100644 index 0000000..b23a15c --- /dev/null +++ b/examples/data/dis_model/test_model.dis @@ -0,0 +1,34 @@ +# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. +BEGIN options + LENGTH_UNITS meters +END options + +BEGIN dimensions + NLAY 1 + NROW 10 + NCOL 10 +END dimensions + +BEGIN griddata + delr + CONSTANT 63.60000000 + delc + CONSTANT 63.60000000 + top + CONSTANT 100.00000000 + botm + CONSTANT 0.00000000 + IDOMAIN + INTERNAL FACTOR 1 + 0 0 1 1 1 1 1 1 0 0 + 0 1 1 1 1 1 1 1 1 0 + 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 + 0 1 1 1 1 1 1 1 1 0 + 0 0 1 1 1 1 1 1 0 0 +END griddata + diff --git a/examples/data/dis_model/test_model.drn b/examples/data/dis_model/test_model.drn new file mode 100644 index 0000000..a0f40a5 --- /dev/null +++ b/examples/data/dis_model/test_model.drn @@ -0,0 +1,68 @@ +# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. +BEGIN options +END options + +BEGIN dimensions + MAXBOUND 2 +END dimensions + +BEGIN period 1 + 1 2 3 94.00000000 10.00000000 + 1 2 4 95.00000000 10.00000000 +END period 1 + +BEGIN period 2 + 1 2 3 94.00000000 10.00000000 + 1 2 4 95.00000000 10.00000000 +END period 2 + +BEGIN period 3 + 1 2 3 94.00000000 10.00000000 + 1 2 4 95.00000000 10.00000000 +END period 3 + +BEGIN period 4 + 1 2 3 94.00000000 10.00000000 + 1 2 4 95.00000000 10.00000000 +END period 4 + +BEGIN period 5 + 1 2 3 94.00000000 10.00000000 + 1 2 4 95.00000000 10.00000000 +END period 5 + +BEGIN period 6 + 1 2 3 94.00000000 10.00000000 + 1 2 4 95.00000000 10.00000000 +END period 6 + +BEGIN period 7 + 1 2 3 94.00000000 10.00000000 + 1 2 4 95.00000000 10.00000000 +END period 7 + +BEGIN period 8 + 1 2 3 94.00000000 10.00000000 + 1 2 4 95.00000000 10.00000000 +END period 8 + +BEGIN period 9 + 1 2 3 94.00000000 10.00000000 + 1 2 4 95.00000000 10.00000000 +END period 9 + +BEGIN period 10 + 1 2 3 94.00000000 10.00000000 + 1 2 4 95.00000000 10.00000000 +END period 10 + +BEGIN period 11 + 1 2 3 94.00000000 10.00000000 + 1 2 4 95.00000000 10.00000000 +END period 11 + +BEGIN period 12 + 1 2 3 94.00000000 10.00000000 + 1 2 4 95.00000000 10.00000000 +END period 12 + diff --git a/examples/data/dis_model/test_model.evt b/examples/data/dis_model/test_model.evt new file mode 100644 index 0000000..d6bdb33 --- /dev/null +++ b/examples/data/dis_model/test_model.evt @@ -0,0 +1,68 @@ +# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. +BEGIN options +END options + +BEGIN dimensions + MAXBOUND 2 +END dimensions + +BEGIN period 1 + 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 + 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 +END period 1 + +BEGIN period 2 + 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 + 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 +END period 2 + +BEGIN period 3 + 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 + 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 +END period 3 + +BEGIN period 4 + 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 + 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 +END period 4 + +BEGIN period 5 + 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 + 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 +END period 5 + +BEGIN period 6 + 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 + 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 +END period 6 + +BEGIN period 7 + 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 + 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 +END period 7 + +BEGIN period 8 + 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 + 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 +END period 8 + +BEGIN period 9 + 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 + 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 +END period 9 + +BEGIN period 10 + 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 + 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 +END period 10 + +BEGIN period 11 + 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 + 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 +END period 11 + +BEGIN period 12 + 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 + 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 +END period 12 + diff --git a/examples/data/dis_model/test_model.ic b/examples/data/dis_model/test_model.ic new file mode 100644 index 0000000..5503fc6 --- /dev/null +++ b/examples/data/dis_model/test_model.ic @@ -0,0 +1,6 @@ +# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. +BEGIN griddata + strt + CONSTANT 95.00000000 +END griddata + diff --git a/examples/data/dis_model/test_model.ims b/examples/data/dis_model/test_model.ims new file mode 100644 index 0000000..3e054f9 --- /dev/null +++ b/examples/data/dis_model/test_model.ims @@ -0,0 +1,20 @@ +# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. +BEGIN options + PRINT_OPTION all + COMPLEXITY complex + NO_PTC ALL +END options + +BEGIN nonlinear + UNDER_RELAXATION dbd + UNDER_RELAXATION_GAMMA 0.00000000 + UNDER_RELAXATION_THETA 0.97000000 + UNDER_RELAXATION_KAPPA 1.00000000E-04 +END nonlinear + +BEGIN linear + inner_rclose 1.00000000E-10 L2NORM_RCLOSE + LINEAR_ACCELERATION bicgstab + SCALING_METHOD l2norm +END linear + diff --git a/examples/data/dis_model/test_model.nam b/examples/data/dis_model/test_model.nam new file mode 100644 index 0000000..e6eb44f --- /dev/null +++ b/examples/data/dis_model/test_model.nam @@ -0,0 +1,22 @@ +# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. +BEGIN options + PRINT_INPUT + PRINT_FLOWS + SAVE_FLOWS + NEWTON UNDER_RELAXATION +END options + +BEGIN packages + DIS6 test_model.dis dis + IC6 test_model.ic ic + NPF6 test_model.npf npf + STO6 test_model.sto sto + WEL6 test_model.wel wel_0 + DRN6 test_model.drn drn_0 + RCH6 test_model.rch rch_0 + RCH6 test_model.rcha rcha_0 + CHD6 test_model.chd chd_0 + EVT6 test_model.evt evt_0 + OC6 test_model.oc oc +END packages + diff --git a/examples/data/dis_model/test_model.npf b/examples/data/dis_model/test_model.npf new file mode 100644 index 0000000..7be835b --- /dev/null +++ b/examples/data/dis_model/test_model.npf @@ -0,0 +1,12 @@ +# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. +BEGIN options + SAVE_SPECIFIC_DISCHARGE +END options + +BEGIN griddata + icelltype + CONSTANT 1 + k + CONSTANT 1.00000000 +END griddata + diff --git a/examples/data/dis_model/test_model.oc b/examples/data/dis_model/test_model.oc new file mode 100644 index 0000000..365b28d --- /dev/null +++ b/examples/data/dis_model/test_model.oc @@ -0,0 +1,76 @@ +# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. +BEGIN options + BUDGET FILEOUT test_model.cbc + HEAD FILEOUT test_model.hds +END options + +BEGIN period 1 + SAVE HEAD ALL + SAVE BUDGET ALL + PRINT HEAD ALL + PRINT BUDGET ALL +END period 1 + +BEGIN period 2 + SAVE HEAD ALL + SAVE BUDGET ALL + PRINT HEAD ALL + PRINT BUDGET ALL +END period 2 + +BEGIN period 3 + SAVE HEAD ALL + SAVE BUDGET ALL + PRINT HEAD ALL + PRINT BUDGET ALL +END period 3 + +BEGIN period 4 + SAVE HEAD ALL + SAVE BUDGET ALL + PRINT HEAD ALL + PRINT BUDGET ALL +END period 4 + +BEGIN period 5 + SAVE HEAD ALL + SAVE BUDGET ALL + PRINT HEAD ALL + PRINT BUDGET ALL +END period 5 + +BEGIN period 6 + SAVE HEAD ALL + SAVE BUDGET ALL + PRINT HEAD ALL + PRINT BUDGET ALL +END period 6 + +BEGIN period 7 + SAVE HEAD ALL + SAVE BUDGET ALL + PRINT HEAD ALL + PRINT BUDGET ALL +END period 7 + +BEGIN period 8 + SAVE HEAD ALL + SAVE BUDGET ALL + PRINT HEAD ALL + PRINT BUDGET ALL +END period 8 + +BEGIN period 9 + SAVE HEAD ALL + SAVE BUDGET ALL + PRINT HEAD ALL + PRINT BUDGET ALL +END period 9 + +BEGIN period 10 + SAVE HEAD ALL + SAVE BUDGET ALL + PRINT HEAD ALL + PRINT BUDGET ALL +END period 10 + diff --git a/examples/data/dis_model/test_model.rch b/examples/data/dis_model/test_model.rch new file mode 100644 index 0000000..07b12c6 --- /dev/null +++ b/examples/data/dis_model/test_model.rch @@ -0,0 +1,68 @@ +# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. +BEGIN options +END options + +BEGIN dimensions + MAXBOUND 2 +END dimensions + +BEGIN period 1 + 1 10 3 0.25000000 + 1 10 4 0.25000000 +END period 1 + +BEGIN period 2 + 1 10 3 0.25000000 + 1 10 4 0.25000000 +END period 2 + +BEGIN period 3 + 1 10 3 0.25000000 + 1 10 4 0.25000000 +END period 3 + +BEGIN period 4 + 1 10 3 0.25000000 + 1 10 4 0.25000000 +END period 4 + +BEGIN period 5 + 1 10 3 0.25000000 + 1 10 4 0.25000000 +END period 5 + +BEGIN period 6 + 1 10 3 0.25000000 + 1 10 4 0.25000000 +END period 6 + +BEGIN period 7 + 1 10 3 0.25000000 + 1 10 4 0.25000000 +END period 7 + +BEGIN period 8 + 1 10 3 0.25000000 + 1 10 4 0.25000000 +END period 8 + +BEGIN period 9 + 1 10 3 0.25000000 + 1 10 4 0.25000000 +END period 9 + +BEGIN period 10 + 1 10 3 0.25000000 + 1 10 4 0.25000000 +END period 10 + +BEGIN period 11 + 1 10 3 0.25000000 + 1 10 4 0.25000000 +END period 11 + +BEGIN period 12 + 1 10 3 0.25000000 + 1 10 4 0.25000000 +END period 12 + diff --git a/examples/data/dis_model/test_model.rcha b/examples/data/dis_model/test_model.rcha new file mode 100644 index 0000000..28fe2b4 --- /dev/null +++ b/examples/data/dis_model/test_model.rcha @@ -0,0 +1,10 @@ +# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. +BEGIN options + READASARRAYS +END options + +BEGIN period 1 + recharge + CONSTANT 0.00100000 +END period 1 + diff --git a/examples/data/dis_model/test_model.sto b/examples/data/dis_model/test_model.sto new file mode 100644 index 0000000..4e78a5d --- /dev/null +++ b/examples/data/dis_model/test_model.sto @@ -0,0 +1,13 @@ +# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. +BEGIN options +END options + +BEGIN griddata + iconvert + CONSTANT 1 + ss + CONSTANT 1.00000000E-05 + sy + CONSTANT 0.15000000 +END griddata + diff --git a/examples/data/dis_model/test_model.tdis b/examples/data/dis_model/test_model.tdis new file mode 100644 index 0000000..245c1df --- /dev/null +++ b/examples/data/dis_model/test_model.tdis @@ -0,0 +1,24 @@ +# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. +BEGIN options + TIME_UNITS days +END options + +BEGIN dimensions + NPER 12 +END dimensions + +BEGIN perioddata + 31.00000000 31 1.00000000 + 28.00000000 28 1.00000000 + 31.00000000 31 1.00000000 + 30.00000000 30 1.00000000 + 31.00000000 31 1.00000000 + 30.00000000 30 1.00000000 + 31.00000000 31 1.00000000 + 31.00000000 31 1.00000000 + 30.00000000 30 1.00000000 + 31.00000000 31 1.00000000 + 30.00000000 30 1.00000000 + 31.00000000 31 1.00000000 +END perioddata + diff --git a/examples/data/dis_model/test_model.wel b/examples/data/dis_model/test_model.wel new file mode 100644 index 0000000..4931fc3 --- /dev/null +++ b/examples/data/dis_model/test_model.wel @@ -0,0 +1,81 @@ +# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. +BEGIN options +AUXILIARY TEST1 TEST2 +END options + +BEGIN dimensions + MAXBOUND 10 +END dimensions + +BEGIN period 1 + 1 6 5 -150.00000000 1.0 2.0 + 1 2 3 -100.00000000 1.0 2.0 + 1 4 6 -50.0000000000 1.0 2.0 +END period 1 + +BEGIN period 2 + 1 6 5 -100.00000000 1.0 2.0 + 1 2 3 -50.00000000 1.0 2.0 + 1 4 6 -50.0000000000 1.0 2.0 +END period 2 + +BEGIN period 3 + 1 6 5 -0.00000000 1.0 2.0 + 1 2 3 -0.00000000 1.0 2.0 + 1 4 6 -50.0000000000 1.0 2.0 +END period 3 + +BEGIN period 4 + 1 6 5 -10.00000000 1.0 2.0 + 1 2 3 -0.00000000 1.0 2.0 + 1 4 6 -5.0000000000 1.0 2.0 +END period 4 + +BEGIN period 5 + 1 6 5 -150.00000000 1.0 2.0 + 1 2 3 -200.00000000 1.0 2.0 + 1 4 6 -350.0000000000 1.0 2.0 +END period 5 + +BEGIN period 6 + 1 6 5 -100.00000000 1.0 2.0 + 1 2 3 -10.00000000 1.0 2.0 + 1 4 6 -80.0000000000 1.0 2.0 +END period 6 + +BEGIN period 7 + 1 6 5 -10.00000000 1.0 2.0 + 1 2 3 -50.00000000 1.0 2.0 + 1 4 6 -50.0000000000 1.0 2.0 +END period 7 + +BEGIN period 8 + 1 6 5 -100.00000000 1.0 2.0 + 1 2 3 -50.00000000 1.0 2.0 + 1 4 6 -50.0000000000 1.0 2.0 +END period 8 + +BEGIN period 9 + 1 6 5 -100.00000000 1.0 2.0 + 1 2 3 -50.00000000 1.0 2.0 + 1 4 6 -50.0000000000 1.0 2.0 +END period 9 + +BEGIN period 10 + 1 6 5 -100.00000000 1.0 2.0 + 1 2 3 -50.00000000 1.0 2.0 + 1 4 6 -50.0000000000 1.0 2.0 +END period 10 + +BEGIN period 11 + 1 6 5 -100.00000000 1.0 2.0 + 1 2 3 -50.00000000 1.0 2.0 + 1 4 6 -50.0000000000 1.0 2.0 +END period 11 + +BEGIN period 12 + 1 6 5 -100.00000000 1.0 2.0 + 1 2 3 -50.00000000 1.0 2.0 + 1 4 6 -50.0000000000 1.0 2.0 +END period 12 + diff --git a/examples/data/disu_model/flow.chd b/examples/data/disu_model/flow.chd new file mode 100644 index 0000000..7e8bac9 --- /dev/null +++ b/examples/data/disu_model/flow.chd @@ -0,0 +1,27 @@ +begin options + PRINT_INPUT + PRINT_FLOWS + SAVE_FLOWS +end options + +begin dimensions + MAXBOUND 14 +end dimensions + +begin period 1 + 1 1. + 8 1. +15 1. +19 1. +23 1. +27 1. +34 1. + + 7 0. +14 0. +18 0. +22 0. +26 0. +33 0. +40 0. +end period diff --git a/examples/data/disu_model/flow.disu b/examples/data/disu_model/flow.disu new file mode 100644 index 0000000..aa41f78 --- /dev/null +++ b/examples/data/disu_model/flow.disu @@ -0,0 +1,31 @@ +# Unstructured discretization file for MODFLOW-USG +begin options + LENGTH_UNITS meters +end options + +begin dimensions + nodes 121 + nja 601 +end dimensions + +BEGIN GRIDDATA + top + constant 0. + bot + constant -100. + area + open/close 'flow.disu.area.dat' FACTOR 1.0 IPRN 0 +END GRIDDATA + +begin connectiondata + ihc + constant 1 + iac + open/close 'flow.disu.iac.dat' FACTOR 1 IPRN 0 + ja + open/close 'flow.disu.ja.dat' FACTOR 1 IPRN 0 + cl12 + open/close 'flow.disu.cl12.dat' FACTOR 1.0 IPRN 0 + hwva + open/close 'flow.disu.hwva.dat' FACTOR 1.0 IPRN 0 +end connectiondata diff --git a/examples/data/disu_model/flow.disu.area.dat b/examples/data/disu_model/flow.disu.area.dat new file mode 100644 index 0000000..f9457ad --- /dev/null +++ b/examples/data/disu_model/flow.disu.area.dat @@ -0,0 +1,25 @@ + 10000 10000 10000 10000 10000 + 10000 10000 10000 10000 10000 + 10000 10000 10000 10000 10000 + 10000 10000 10000 10000 10000 + 10000 10000 10000 10000 10000 + 10000 10000 10000 10000 10000 + 10000 10000 10000 10000 10000 + 10000 10000 10000 10000 10000 + 1111.11 1111.11 1111.11 1111.11 1111.11 + 1111.11 1111.11 1111.11 1111.11 1111.11 + 1111.11 1111.11 1111.11 1111.11 1111.11 + 1111.11 1111.11 1111.11 1111.11 1111.11 + 1111.11 1111.11 1111.11 1111.11 1111.11 + 1111.11 1111.11 1111.11 1111.11 1111.11 + 1111.11 1111.11 1111.11 1111.11 1111.11 + 1111.11 1111.11 1111.11 1111.11 1111.11 + 1111.11 1111.11 1111.11 1111.11 1111.11 + 1111.11 1111.11 1111.11 1111.11 1111.11 + 1111.11 1111.11 1111.11 1111.11 1111.11 + 1111.11 1111.11 1111.11 1111.11 1111.11 + 1111.11 1111.11 1111.11 1111.11 1111.11 + 1111.11 1111.11 1111.11 1111.11 1111.11 + 1111.11 1111.11 1111.11 1111.11 1111.11 + 1111.11 1111.11 1111.11 1111.11 1111.11 + 1111.11 diff --git a/examples/data/disu_model/flow.disu.cl12.dat b/examples/data/disu_model/flow.disu.cl12.dat new file mode 100644 index 0000000..a995d98 --- /dev/null +++ b/examples/data/disu_model/flow.disu.cl12.dat @@ -0,0 +1,121 @@ + 0 50 50 0 50 + 50 50 0 50 50 + 50 0 50 50 50 + 0 50 50 50 0 + 50 50 50 0 50 + 50 0 50 50 50 + 0 50 50 50 50 + 0 50 50 50 50 + 50 50 0 50 50 + 50 50 50 50 0 + 50 50 50 50 50 + 50 0 50 50 50 + 50 0 50 50 50 + 0 50 50 50 0 + 50 50 50 50 50 + 50 0 50 50 50 + 50 50 50 0 50 + 50 50 0 50 50 + 50 0 50 50 50 + 50 50 50 0 50 + 50 50 50 50 50 + 0 50 50 50 0 + 50 50 50 0 50 + 50 50 50 50 50 + 0 50 50 50 50 + 50 50 0 50 50 + 50 0 50 50 50 + 0 50 50 50 50 + 0 50 50 50 50 + 50 50 0 50 50 + 50 50 50 50 0 + 50 50 50 50 50 + 50 0 50 50 50 + 50 0 50 50 50 + 0 50 50 0 50 + 50 50 0 50 50 + 50 0 50 50 50 + 0 50 50 50 0 + 50 50 50 0 50 + 50 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 diff --git a/examples/data/disu_model/flow.disu.hwva.dat b/examples/data/disu_model/flow.disu.hwva.dat new file mode 100644 index 0000000..b994d0a --- /dev/null +++ b/examples/data/disu_model/flow.disu.hwva.dat @@ -0,0 +1,121 @@ +0 100. 100. +0 100. 100. 100. +0 100. 100. 100. +0 100. 100. 100. +0 100. 100. 100. +0 100. 100. 100. +0 100. 100. +0 100. 100. 100. +0 100. 100. 100. 100. +0 100. 100. 100. 33.33 33.33 33.33 +0 100. 100. 100. 33.33 33.33 33.33 +0 100. 100. 100. 33.33 33.33 33.33 +0 100. 100. 100. 100. +0 100. 100. 100. +0 100. 100. 100. +0 100. 100. 100. 33.33 33.33 33.33 +0 100. 100. 100. 33.33 33.33 33.33 +0 100. 100. 100. +0 100. 100. 100. +0 100. 100. 100. 33.33 33.33 33.33 +0 100. 100. 100. 33.33 33.33 33.33 +0 100. 100. 100. +0 100. 100. 100. +0 100. 100. 100. 33.33 33.33 33.33 +0 100. 100. 100. 33.33 33.33 33.33 +0 100. 100. 100. +0 100. 100. 100. +0 100. 100. 100. 100. +0 100. 100. 100. 33.33 33.33 33.33 +0 100. 100. 100. 33.33 33.33 33.33 +0 100. 100. 100. 33.33 33.33 33.33 +0 100. 100. 100. 100. +0 100. 100. 100. +0 100. 100. +0 100. 100. 100. +0 100. 100. 100. +0 100. 100. 100. +0 100. 100. 100. +0 100. 100. 100. +0 100. 100. +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 diff --git a/examples/data/disu_model/flow.disu.iac.dat b/examples/data/disu_model/flow.disu.iac.dat new file mode 100644 index 0000000..0a127ee --- /dev/null +++ b/examples/data/disu_model/flow.disu.iac.dat @@ -0,0 +1,25 @@ + 3 4 4 4 4 + 4 3 4 5 7 + 7 7 5 4 4 + 7 7 4 4 7 + 7 4 4 7 7 + 4 4 5 7 7 + 7 5 4 3 4 + 4 4 4 4 3 + 5 5 5 5 5 + 5 5 5 5 5 + 5 5 5 5 5 + 5 5 5 5 5 + 5 5 5 5 5 + 5 5 5 5 5 + 5 5 5 5 5 + 5 5 5 5 5 + 5 5 5 5 5 + 5 5 5 5 5 + 5 5 5 5 5 + 5 5 5 5 5 + 5 5 5 5 5 + 5 5 5 5 5 + 5 5 5 5 5 + 5 5 5 5 5 + 5 diff --git a/examples/data/disu_model/flow.disu.ja.dat b/examples/data/disu_model/flow.disu.ja.dat new file mode 100644 index 0000000..9bb6c6c --- /dev/null +++ b/examples/data/disu_model/flow.disu.ja.dat @@ -0,0 +1,121 @@ + 1 2 8 2 1 + 3 9 3 2 4 + 10 4 3 5 11 + 5 4 6 12 6 + 5 7 13 7 6 + 14 8 1 9 15 + 9 2 8 10 16 + 10 3 9 11 41 + 42 43 11 4 10 + 12 44 45 46 12 + 5 11 13 47 48 + 49 13 6 12 14 + 17 14 7 13 18 + 15 8 16 19 16 + 9 15 20 41 50 + 59 17 13 18 21 + 49 58 67 18 14 + 17 22 19 15 20 + 23 20 16 19 24 + 68 77 86 21 17 + 22 25 76 85 94 + 22 18 21 26 23 + 19 24 27 24 20 + 23 28 95 104 113 + 25 21 26 32 103 + 112 121 26 22 25 + 33 27 23 28 34 + 28 24 27 29 35 + 29 28 30 36 113 + 114 115 30 29 31 + 37 116 117 118 31 + 30 32 38 119 120 + 121 32 25 31 33 + 39 33 26 32 40 + 34 27 35 35 28 + 34 36 36 29 35 + 37 37 30 36 38 + 38 31 37 39 39 + 32 38 40 40 33 + 39 41 10 16 42 + 50 42 10 41 43 + 51 43 10 42 44 + 52 44 11 43 45 + 53 45 11 44 46 + 54 46 11 45 47 + 55 47 12 46 48 + 56 48 12 47 49 + 57 49 12 17 48 + 58 50 16 41 51 + 59 51 42 50 52 + 60 52 43 51 53 + 61 53 44 52 54 + 62 54 45 53 55 + 63 55 46 54 56 + 64 56 47 55 57 + 65 57 48 56 58 + 66 58 17 49 57 + 67 59 16 50 60 + 68 60 51 59 61 + 69 61 52 60 62 + 70 62 53 61 63 + 71 63 54 62 64 + 72 64 55 63 65 + 73 65 56 64 66 + 74 66 57 65 67 + 75 67 17 58 66 + 76 68 20 59 69 + 77 69 60 68 70 + 78 70 61 69 71 + 79 71 62 70 72 + 80 72 63 71 73 + 81 73 64 72 74 + 82 74 65 73 75 + 83 75 66 74 76 + 84 76 21 67 75 + 85 77 20 68 78 + 86 78 69 77 79 + 87 79 70 78 80 + 88 80 71 79 81 + 89 81 72 80 82 + 90 82 73 81 83 + 91 83 74 82 84 + 92 84 75 83 85 + 93 85 21 76 84 + 94 86 20 77 87 + 95 87 78 86 88 + 96 88 79 87 89 + 97 89 80 88 90 + 98 90 81 89 91 + 99 91 82 90 92 + 100 92 83 91 93 + 101 93 84 92 94 + 102 94 21 85 93 + 103 95 24 86 96 + 104 96 87 95 97 + 105 97 88 96 98 + 106 98 89 97 99 + 107 99 90 98 100 + 108 100 91 99 101 + 109 101 92 100 102 + 110 102 93 101 103 + 111 103 25 94 102 + 112 104 24 95 105 + 113 105 96 104 106 + 114 106 97 105 107 + 115 107 98 106 108 + 116 108 99 107 109 + 117 109 100 108 110 + 118 110 101 109 111 + 119 111 102 110 112 + 120 112 25 103 111 + 121 113 24 29 104 + 114 114 29 105 113 + 115 115 29 106 114 + 116 116 30 107 115 + 117 117 30 108 116 + 118 118 30 109 117 + 119 119 31 110 118 + 120 120 31 111 119 + 121 121 25 31 112 + 120 diff --git a/examples/data/disu_model/flow.ic b/examples/data/disu_model/flow.ic new file mode 100644 index 0000000..3d1b93d --- /dev/null +++ b/examples/data/disu_model/flow.ic @@ -0,0 +1,33 @@ +# Basic package file for MODFLOW-USG, generated by Flopy. +begin options +end options + +BEGIN GRIDDATA +strt +INTERNAL FACTOR 1 IPRN + 1 0 0 0 0 + 0 0 1 0 0 + 0 0 0 0 1 + 0 0 0 1 0 + 0 0 1 0 0 + 0 1 0 0 0 + 0 0 0 1 0 + 0 0 0 0 0 + 0 0 0 0 0 + 0 0 0 0 0 + 0 0 0 0 0 + 0 0 0 0 0 + 0 0 0 0 0 + 0 0 0 0 0 + 0 0 0 0 0 + 0 0 0 0 0 + 0 0 0 0 0 + 0 0 0 0 0 + 0 0 0 0 0 + 0 0 0 0 0 + 0 0 0 0 0 + 0 0 0 0 0 + 0 0 0 0 0 + 0 0 0 0 0 + 0 +END GRIDDATA \ No newline at end of file diff --git a/examples/data/disu_model/flow.ims b/examples/data/disu_model/flow.ims new file mode 100644 index 0000000..f01fd7a --- /dev/null +++ b/examples/data/disu_model/flow.ims @@ -0,0 +1,20 @@ +begin options + PRINT_OPTION SUMMARY +end options + +begin nonlinear + OUTER_DVCLOSE 1.e-8 + outer_maximum 1000 + under_relaxation none +end nonlinear + +begin linear + INNER_DVCLOSE 1.0e-8 + inner_rclose 0.01 + inner_maximum 1000 + linear_acceleration cg + scaling_method none + REORDERING_METHOD none + relaxation_factor 0.97 +end linear + diff --git a/examples/data/disu_model/flow.nam b/examples/data/disu_model/flow.nam new file mode 100644 index 0000000..5389478 --- /dev/null +++ b/examples/data/disu_model/flow.nam @@ -0,0 +1,12 @@ +BEGIN OPTIONS +END OPTIONS + +BEGIN PACKAGES + DISU6 flow.disu + IC6 flow.ic + CHD6 flow.chd + NPF6 flow.npf + RCH6 flow.rch + OC6 flow.oc +END PACKAGES + diff --git a/examples/data/disu_model/flow.npf b/examples/data/disu_model/flow.npf new file mode 100644 index 0000000..6b4411a --- /dev/null +++ b/examples/data/disu_model/flow.npf @@ -0,0 +1,34 @@ +begin options + SAVE_FLOWS +end options +# +BEGIN GRIDDATA +# +#apply these arrays for the entire simulation +# +#icelltype(nodes) is 0:confined, 1:convertible, 4:upstream? + icelltype + constant 0 +# +#K(nodes) horizontal hydraulic conductivity + K + constant 1. +# +#K33(nodes) vertical hydraulic conductivity + K33 + constant 1. +# +#this will crash it funkyarray +# constant +END GRIDDATA + + + 50 -1.0e+30 0 0 + 0 + 0 + 1 + 1 + 0 + 0 1.000e+00 (10G13.0) -1 HK() = Horizontal hydraulic conductivity of layer 1 + 0 1.000e+00 (10G13.0) -1 VKA() = Vertical hydraulic conductivity of layer 1 + 0 0.000e+00 (10G13.0) -1 WETDRY() = Wetting threshold of layer 1 diff --git a/examples/data/disu_model/flow.oc b/examples/data/disu_model/flow.oc new file mode 100644 index 0000000..c41ee8c --- /dev/null +++ b/examples/data/disu_model/flow.oc @@ -0,0 +1,11 @@ +BEGIN OPTIONS + HEAD FILEOUT flow.hds + BUDGET FILEOUT flow.cbc +END OPTIONS + +BEGIN PERIOD 1 + PRINT BUDGET ALL + SAVE BUDGET ALL + PRINT HEAD ALL + SAVE HEAD ALL +END PERIOD diff --git a/examples/data/disu_model/flow.rch b/examples/data/disu_model/flow.rch new file mode 100644 index 0000000..6b7dd1d --- /dev/null +++ b/examples/data/disu_model/flow.rch @@ -0,0 +1,20 @@ +BEGIN OPTIONS + FIXED_CELL +END OPTIONS + +BEGIN DIMENSIONS + MAXBOUND 10 +END DIMENSIONS + +BEGIN PERIOD 1 + 1 0.000 + 2 0.000 + 3 0.000 + 4 0.000 + 5 0.000 + 6 0.000 + 7 0.000 + 8 0.000 + 9 0.000 + 10 0.000 +END PERIOD 1 diff --git a/examples/data/disu_model/flow.tdis b/examples/data/disu_model/flow.tdis new file mode 100644 index 0000000..31e5be0 --- /dev/null +++ b/examples/data/disu_model/flow.tdis @@ -0,0 +1,12 @@ +BEGIN OPTIONS + TIME_UNITS DAYS +END OPTIONS + +BEGIN DIMENSIONS + NPER 1 +END DIMENSIONS + +BEGIN PERIODDATA + #perlen nstp tsmult + 1.0 1 1.0 +END PERIODDATA diff --git a/examples/data/disu_model/mfsim.nam b/examples/data/disu_model/mfsim.nam new file mode 100644 index 0000000..018d9d0 --- /dev/null +++ b/examples/data/disu_model/mfsim.nam @@ -0,0 +1,19 @@ +BEGIN OPTIONS +END OPTIONS + +BEGIN TIMING + TDIS6 flow.tdis +END TIMING + +BEGIN MODELS + #modeltype namefile modelname + GWF6 flow.nam GWF_1 +END MODELS + +BEGIN EXCHANGES +END EXCHANGES + +BEGIN SOLUTIONGROUP 1 + MXITER 1 + IMS6 flow.ims GWF_1 +END SOLUTIONGROUP diff --git a/examples/data/disv_model/mfsim.nam b/examples/data/disv_model/mfsim.nam new file mode 100644 index 0000000..963fd4c --- /dev/null +++ b/examples/data/disv_model/mfsim.nam @@ -0,0 +1,19 @@ +BEGIN OPTIONS +END OPTIONS + +BEGIN TIMING + TDIS6 simulation.tdis +END TIMING + +BEGIN MODELS + #modeltype namefile modelname + GWF6 tri_model.nam GWF_1 +END MODELS + +BEGIN EXCHANGES +END EXCHANGES + +BEGIN SOLUTIONGROUP 1 + MXITER 1 + IMS6 model.ims GWF_1 +END SOLUTIONGROUP diff --git a/examples/data/disv_model/model.ims b/examples/data/disv_model/model.ims new file mode 100644 index 0000000..23020b0 --- /dev/null +++ b/examples/data/disv_model/model.ims @@ -0,0 +1,40 @@ +begin options + PRINT_OPTION SUMMARY +end options + +begin nonlinear + OUTER_DVCLOSE 1.e-4 + outer_maximum 500 + under_relaxation none +end nonlinear + +begin linear + INNER_DVCLOSE 1.0e-4 + inner_rclose 0.001 + #L2NORM_RCLOSE + inner_maximum 100 + linear_acceleration cg + scaling_method none + REORDERING_METHOD none + relaxation_factor 0.97 +end linear + + + +1.0E-4 1.0E-4 500 100 1 0 002 #hclose, hiclose,mxiter,iter1,iprsms,nonmeth,linmeth +#PCGU [option: "bcgs", "cg"] ipc iscl iord rclosepcgu relax + cg 3 0 0 0.001 0.97 +# bcgs 3 0 0 0.001 0.97 + +1.0E-4 1.0E-4 500 100 1 0 001 #hclose, hiclose,mxiter,iter1,iprsms,nonmeth,linmeth +2 0 0 2 0 0 0 1e-3 +IACL NORDER LEVEL NORTH IREDSYS RRCTOL IDROPTOL EPSRN + + + + 0.0001 0.0001 500 100 1 0 1 +2 0 0 2 0 0 0 1e-3 +IACL NORDER LEVEL NORTH IREDSYS RRCTOL IDROPTOL EPSRN + + 0.0001 0.0001 500 100 1 0 5 + 3 0 0 100000 diff --git a/examples/data/disv_model/simulation.tdis b/examples/data/disv_model/simulation.tdis new file mode 100644 index 0000000..0acd8e7 --- /dev/null +++ b/examples/data/disv_model/simulation.tdis @@ -0,0 +1,12 @@ +BEGIN OPTIONS + TIME_UNITS MINUTES +END OPTIONS + +BEGIN DIMENSIONS + NPER 1 +END DIMENSIONS + +BEGIN PERIODDATA + #perlen nstp tsmult + 1.0 1 1.0 +END PERIODDATA diff --git a/examples/data/disv_model/tri_model.ic b/examples/data/disv_model/tri_model.ic new file mode 100644 index 0000000..2e72cd7 --- /dev/null +++ b/examples/data/disv_model/tri_model.ic @@ -0,0 +1,8 @@ +# Basic package file for MODFLOW, generated by Flopy. +begin options +end options + +BEGIN GRIDDATA + strt + constant 1. +END GRIDDATA diff --git a/examples/data/disv_model/tri_model.nam b/examples/data/disv_model/tri_model.nam new file mode 100644 index 0000000..f5cabce --- /dev/null +++ b/examples/data/disv_model/tri_model.nam @@ -0,0 +1,10 @@ +# Name file for mf2005, generated by Flopy. +BEGIN PACKAGES + DISV6 tri_model_cnst.disv + IC6 tri_model.ic + NPF6 tri_model.npf + CHD6 tri_model_left.chd CHD_LEFT + CHD6 tri_model_right.chd CHD_RIGHT + OC6 tri_model.oc +END PACKAGES + diff --git a/examples/data/disv_model/tri_model.npf b/examples/data/disv_model/tri_model.npf new file mode 100644 index 0000000..7704f7e --- /dev/null +++ b/examples/data/disv_model/tri_model.npf @@ -0,0 +1,18 @@ +begin options + PRINT_FLOWS + SAVE_FLOWS + SAVE_SPECIFIC_DISCHARGE +end options +# +BEGIN GRIDDATA + #icelltype(nodes) is 0:confined, 1:convertible, 4:upstream? + icelltype + constant 0 + # + K + constant 1.0 k Layer 1 + K33 + constant 1.0 K33 Layer 1 + k22 + constant 1.0 +END GRIDDATA \ No newline at end of file diff --git a/examples/data/disv_model/tri_model.oc b/examples/data/disv_model/tri_model.oc new file mode 100644 index 0000000..129935b --- /dev/null +++ b/examples/data/disv_model/tri_model.oc @@ -0,0 +1,12 @@ +BEGIN OPTIONS + HEAD FILEOUT tri_model.hds + BUDGET FILEOUT tri_model.cbc +END OPTIONS + +BEGIN PERIOD 1 + PRINT BUDGET ALL + SAVE BUDGET ALL + PRINT HEAD ALL + SAVE HEAD ALL + END PERIOD + diff --git a/examples/data/disv_model/tri_model_cnst.disv b/examples/data/disv_model/tri_model_cnst.disv new file mode 100644 index 0000000..e788d45 --- /dev/null +++ b/examples/data/disv_model/tri_model_cnst.disv @@ -0,0 +1,361 @@ +BEGIN OPTIONS +END OPTIONS + +BEGIN DIMENSIONS + NCPL 200 + NLAY 4 + NVERT 121 +END DIMENSIONS + +BEGIN GRIDDATA + TOP + CONSTANT 2.0 + BOTM LAYERED + CONSTANT 1.5 + CONSTANT 1.0 + CONSTANT 0.5 + CONSTANT 0.0 + IDOMAIN LAYERED + INTERNAL FACTOR 1 IPRN -1 + 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + CONSTANT 1 + CONSTANT 1 + CONSTANT 1 +END GRIDDATA + +BEGIN VERTICES + 1 0.0 10.0 + 2 1.0 10.0 + 3 2.0 10.0 + 4 3.0 10.0 + 5 4.0 10.0 + 6 5.0 10.0 + 7 6.0 10.0 + 8 7.0 10.0 + 9 8.0 10.0 + 10 9.0 10.0 + 11 10.0 10.0 + 12 0.0 9.0 + 13 1.0 9.0 + 14 2.0 9.0 + 15 3.0 9.0 + 16 4.0 9.0 + 17 5.0 9.0 + 18 6.0 9.0 + 19 7.0 9.0 + 20 8.0 9.0 + 21 9.0 9.0 + 22 10.0 9.0 + 23 0.0 8.0 + 24 1.0 8.0 + 25 2.0 8.0 + 26 3.0 8.0 + 27 4.0 8.0 + 28 5.0 8.0 + 29 6.0 8.0 + 30 7.0 8.0 + 31 8.0 8.0 + 32 9.0 8.0 + 33 10.0 8.0 + 34 0.0 7.0 + 35 1.0 7.0 + 36 2.0 7.0 + 37 3.0 7.0 + 38 4.0 7.0 + 39 5.0 7.0 + 40 6.0 7.0 + 41 7.0 7.0 + 42 8.0 7.0 + 43 9.0 7.0 + 44 10.0 7.0 + 45 0.0 6.0 + 46 1.0 6.0 + 47 2.0 6.0 + 48 3.0 6.0 + 49 4.0 6.0 + 50 5.0 6.0 + 51 6.0 6.0 + 52 7.0 6.0 + 53 8.0 6.0 + 54 9.0 6.0 + 55 10.0 6.0 + 56 0.0 5.0 + 57 1.0 5.0 + 58 2.0 5.0 + 59 3.0 5.0 + 60 4.0 5.0 + 61 5.0 5.0 + 62 6.0 5.0 + 63 7.0 5.0 + 64 8.0 5.0 + 65 9.0 5.0 + 66 10.0 5.0 + 67 0.0 4.0 + 68 1.0 4.0 + 69 2.0 4.0 + 70 3.0 4.0 + 71 4.0 4.0 + 72 5.0 4.0 + 73 6.0 4.0 + 74 7.0 4.0 + 75 8.0 4.0 + 76 9.0 4.0 + 77 10.0 4.0 + 78 0.0 3.0 + 79 1.0 3.0 + 80 2.0 3.0 + 81 3.0 3.0 + 82 4.0 3.0 + 83 5.0 3.0 + 84 6.0 3.0 + 85 7.0 3.0 + 86 8.0 3.0 + 87 9.0 3.0 + 88 10.0 3.0 + 89 0.0 2.0 + 90 1.0 2.0 + 91 2.0 2.0 + 92 3.0 2.0 + 93 4.0 2.0 + 94 5.0 2.0 + 95 6.0 2.0 + 96 7.0 2.0 + 97 8.0 2.0 + 98 9.0 2.0 + 99 10.0 2.0 + 100 0.0 1.0 + 101 1.0 1.0 + 102 2.0 1.0 + 103 3.0 1.0 + 104 4.0 1.0 + 105 5.0 1.0 + 106 6.0 1.0 + 107 7.0 1.0 + 108 8.0 1.0 + 109 9.0 1.0 + 110 10.0 1.0 + 111 0.0 0.0 + 112 1.0 0.0 + 113 2.0 0.0 + 114 3.0 0.0 + 115 4.0 0.0 + 116 5.0 0.0 + 117 6.0 0.0 + 118 7.0 0.0 + 119 8.0 0.0 + 120 9.0 0.0 + 121 10.0 0.0 +END VERTICES + +BEGIN CELL2D +1 0.33 9.67 3 1 2 12 +2 0.67 9.33 3 2 13 12 +3 1.33 9.67 3 2 3 13 +4 1.67 9.33 3 3 14 13 +5 2.33 9.67 3 3 4 14 +6 2.67 9.33 3 4 15 14 +7 3.33 9.67 3 4 5 15 +8 3.67 9.33 3 5 16 15 +9 4.33 9.67 3 5 6 16 +10 4.67 9.33 3 6 17 16 +11 5.33 9.67 3 6 7 17 +12 5.67 9.33 3 7 18 17 +13 6.33 9.67 3 7 8 18 +14 6.67 9.33 3 8 19 18 +15 7.33 9.67 3 8 9 19 +16 7.67 9.33 3 9 20 19 +17 8.33 9.67 3 9 10 20 +18 8.67 9.33 3 10 21 20 +19 9.33 9.67 3 10 11 21 +20 9.67 9.33 3 11 22 21 +21 0.33 8.67 3 12 13 23 +22 0.67 8.33 3 13 24 23 +23 1.33 8.67 3 13 14 24 +24 1.67 8.33 3 14 25 24 +25 2.33 8.67 3 14 15 25 +26 2.67 8.33 3 15 26 25 +27 3.33 8.67 3 15 16 26 +28 3.67 8.33 3 16 27 26 +29 4.33 8.67 3 16 17 27 +30 4.67 8.33 3 17 28 27 +31 5.33 8.67 3 17 18 28 +32 5.67 8.33 3 18 29 28 +33 6.33 8.67 3 18 19 29 +34 6.67 8.33 3 19 30 29 +35 7.33 8.67 3 19 20 30 +36 7.67 8.33 3 20 31 30 +37 8.33 8.67 3 20 21 31 +38 8.67 8.33 3 21 32 31 +39 9.33 8.67 3 21 22 32 +40 9.67 8.33 3 22 33 32 +41 0.33 7.67 3 23 24 34 +42 0.67 7.33 3 24 35 34 +43 1.33 7.67 3 24 25 35 +44 1.67 7.33 3 25 36 35 +45 2.33 7.67 3 25 26 36 +46 2.67 7.33 3 26 37 36 +47 3.33 7.67 3 26 27 37 +48 3.67 7.33 3 27 38 37 +49 4.33 7.67 3 27 28 38 +50 4.67 7.33 3 28 39 38 +51 5.33 7.67 3 28 29 39 +52 5.67 7.33 3 29 40 39 +53 6.33 7.67 3 29 30 40 +54 6.67 7.33 3 30 41 40 +55 7.33 7.67 3 30 31 41 +56 7.67 7.33 3 31 42 41 +57 8.33 7.67 3 31 32 42 +58 8.67 7.33 3 32 43 42 +59 9.33 7.67 3 32 33 43 +60 9.67 7.33 3 33 44 43 +61 0.33 6.67 3 34 35 45 +62 0.67 6.33 3 35 46 45 +63 1.33 6.67 3 35 36 46 +64 1.67 6.33 3 36 47 46 +65 2.33 6.67 3 36 37 47 +66 2.67 6.33 3 37 48 47 +67 3.33 6.67 3 37 38 48 +68 3.67 6.33 3 38 49 48 +69 4.33 6.67 3 38 39 49 +70 4.67 6.33 3 39 50 49 +71 5.33 6.67 3 39 40 50 +72 5.67 6.33 3 40 51 50 +73 6.33 6.67 3 40 41 51 +74 6.67 6.33 3 41 52 51 +75 7.33 6.67 3 41 42 52 +76 7.67 6.33 3 42 53 52 +77 8.33 6.67 3 42 43 53 +78 8.67 6.33 3 43 54 53 +79 9.33 6.67 3 43 44 54 +80 9.67 6.33 3 44 55 54 +81 0.33 5.67 3 45 46 56 +82 0.67 5.33 3 46 57 56 +83 1.33 5.67 3 46 47 57 +84 1.67 5.33 3 47 58 57 +85 2.33 5.67 3 47 48 58 +86 2.67 5.33 3 48 59 58 +87 3.33 5.67 3 48 49 59 +88 3.67 5.33 3 49 60 59 +89 4.33 5.67 3 49 50 60 +90 4.67 5.33 3 50 61 60 +91 5.33 5.67 3 50 51 61 +92 5.67 5.33 3 51 62 61 +93 6.33 5.67 3 51 52 62 +94 6.67 5.33 3 52 63 62 +95 7.33 5.67 3 52 53 63 +96 7.67 5.33 3 53 64 63 +97 8.33 5.67 3 53 54 64 +98 8.67 5.33 3 54 65 64 +99 9.33 5.67 3 54 55 65 +100 9.67 5.33 3 55 66 65 +101 0.33 4.67 3 56 57 67 +102 0.67 4.33 3 57 68 67 +103 1.33 4.67 3 57 58 68 +104 1.67 4.33 3 58 69 68 +105 2.33 4.67 3 58 59 69 +106 2.67 4.33 3 59 70 69 +107 3.33 4.67 3 59 60 70 +108 3.67 4.33 3 60 71 70 +109 4.33 4.67 3 60 61 71 +110 4.67 4.33 3 61 72 71 +111 5.33 4.67 3 61 62 72 +112 5.67 4.33 3 62 73 72 +113 6.33 4.67 3 62 63 73 +114 6.67 4.33 3 63 74 73 +115 7.33 4.67 3 63 64 74 +116 7.67 4.33 3 64 75 74 +117 8.33 4.67 3 64 65 75 +118 8.67 4.33 3 65 76 75 +119 9.33 4.67 3 65 66 76 +120 9.67 4.33 3 66 77 76 +121 0.33 3.67 3 67 68 78 +122 0.67 3.33 3 68 79 78 +123 1.33 3.67 3 68 69 79 +124 1.67 3.33 3 69 80 79 +125 2.33 3.67 3 69 70 80 +126 2.67 3.33 3 70 81 80 +127 3.33 3.67 3 70 71 81 +128 3.67 3.33 3 71 82 81 +129 4.33 3.67 3 71 72 82 +130 4.67 3.33 3 72 83 82 +131 5.33 3.67 3 72 73 83 +132 5.67 3.33 3 73 84 83 +133 6.33 3.67 3 73 74 84 +134 6.67 3.33 3 74 85 84 +135 7.33 3.67 3 74 75 85 +136 7.67 3.33 3 75 86 85 +137 8.33 3.67 3 75 76 86 +138 8.67 3.33 3 76 87 86 +139 9.33 3.67 3 76 77 87 +140 9.67 3.33 3 77 88 87 +141 0.33 2.67 3 78 79 89 +142 0.67 2.33 3 79 90 89 +143 1.33 2.67 3 79 80 90 +144 1.67 2.33 3 80 91 90 +145 2.33 2.67 3 80 81 91 +146 2.67 2.33 3 81 92 91 +147 3.33 2.67 3 81 82 92 +148 3.67 2.33 3 82 93 92 +149 4.33 2.67 3 82 83 93 +150 4.67 2.33 3 83 94 93 +151 5.33 2.67 3 83 84 94 +152 5.67 2.33 3 84 95 94 +153 6.33 2.67 3 84 85 95 +154 6.67 2.33 3 85 96 95 +155 7.33 2.67 3 85 86 96 +156 7.67 2.33 3 86 97 96 +157 8.33 2.67 3 86 87 97 +158 8.67 2.33 3 87 98 97 +159 9.33 2.67 3 87 88 98 +160 9.67 2.33 3 88 99 98 +161 0.33 1.67 3 89 90 100 +162 0.67 1.33 3 90 101 100 +163 1.33 1.67 3 90 91 101 +164 1.67 1.33 3 91 102 101 +165 2.33 1.67 3 91 92 102 +166 2.67 1.33 3 92 103 102 +167 3.33 1.67 3 92 93 103 +168 3.67 1.33 3 93 104 103 +169 4.33 1.67 3 93 94 104 +170 4.67 1.33 3 94 105 104 +171 5.33 1.67 3 94 95 105 +172 5.67 1.33 3 95 106 105 +173 6.33 1.67 3 95 96 106 +174 6.67 1.33 3 96 107 106 +175 7.33 1.67 3 96 97 107 +176 7.67 1.33 3 97 108 107 +177 8.33 1.67 3 97 98 108 +178 8.67 1.33 3 98 109 108 +179 9.33 1.67 3 98 99 109 +180 9.67 1.33 3 99 110 109 +181 0.33 0.67 3 100 101 111 +182 0.67 0.33 3 101 112 111 +183 1.33 0.67 3 101 102 112 +184 1.67 0.33 3 102 113 112 +185 2.33 0.67 3 102 103 113 +186 2.67 0.33 3 103 114 113 +187 3.33 0.67 3 103 104 114 +188 3.67 0.33 3 104 115 114 +189 4.33 0.67 3 104 105 115 +190 4.67 0.33 3 105 116 115 +191 5.33 0.67 3 105 106 116 +192 5.67 0.33 3 106 117 116 +193 6.33 0.67 3 106 107 117 +194 6.67 0.33 3 107 118 117 +195 7.33 0.67 3 107 108 118 +196 7.67 0.33 3 108 119 118 +197 8.33 0.67 3 108 109 119 +198 8.67 0.33 3 109 120 119 +199 9.33 0.67 3 109 110 120 +200 9.67 0.33 3 110 121 120 +END CELL2D + diff --git a/examples/data/disv_model/tri_model_cnst.disv.grb b/examples/data/disv_model/tri_model_cnst.disv.grb new file mode 100644 index 0000000000000000000000000000000000000000..285a471837f63a5f6e9727320a1f1cdb1bbeeaa7 GIT binary patch literal 45560 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�*A)+(x_QQyUiSE{!6~Qh+TBDz~=-VTZpopHCHM=VZsx6Zs9>`ipW z-EN9lg6M9Yc|RygbjIC&6|of2-8%C@P@3qByWJeI4AI>>vnD7@bjIC&8?hYG-8%D8 zP@d?F``r?8AENtrW?fK$=*;)vo-2a;T_02;>fP-R5%(p!TW2-|*+ggD?T-;F6Wy&d zp9NKj&bZs3BUUB4TW7uqsu7)Wx4%ZLPIR}QOVbjIEKKG3*7xLaqw4r&nXxm(}= z8Eb;Ob>^Gk0HQs2>-#?Af#7bP`7St!XwTjHe$QA7+^sWPgW5!U?$`Hu#)HBAJF_jQ zL$v36JNH}{-0$|F9#QXZeP3rh1l+ANKLz!P_S~)S>5L7)-8%D2(2!`)-THpccqq7A zXY%2s5xG5g>w7t4V`_J6-}l(kBxc;L@8gVz;oPl#-&;#lYJ2Y1_i)B$ICpE`_tbJY zwLN$1`!{2AoV&H}duhp`w&!kr?`CX)bGP<=4=pXJ?YUpyw;5aE+`oO_KTB(Bd%jM5gXPiBEDP5@DqdngbOIMsd_bA<{-Jw0-2TOOHJ$EQQsNJ7E-~UQaoIUp^ zy{O%tJ>U0AZ=5~%Cr47dS9{q(ADlgY+xiW{|LVW=^JL;bcAD8mW*3>)K;|`&c@1P< z1DV%A<~5Lc4P;&enb*MYUjzTEHyxQDoY_ET1DOqEHjvpsW&@cGWHyl5KxPA(4g3!_ F@L#rKyxaf) literal 0 HcmV?d00001 diff --git a/examples/data/disv_model/tri_model_gaus.disv b/examples/data/disv_model/tri_model_gaus.disv new file mode 100644 index 0000000..239b184 --- /dev/null +++ b/examples/data/disv_model/tri_model_gaus.disv @@ -0,0 +1,461 @@ +BEGIN OPTIONS +END OPTIONS + +BEGIN DIMENSIONS + NCPL 200 + NLAY 4 + NVERT 121 +END DIMENSIONS + +BEGIN GRIDDATA + TOP + INTERNAL FACTOR 1.0 +6.13 4.84 4.51 4.93 2.87 3.52 3.32 5.56 4.93 4.52 +4.20 4.98 3.59 5.51 3.94 6.77 4.87 4.15 3.67 4.68 +5.97 4.17 5.28 4.78 3.95 4.83 4.57 5.21 4.89 4.60 +4.72 3.52 3.28 5.46 5.37 5.29 4.20 5.70 3.17 5.88 +4.83 6.51 4.76 6.33 4.00 5.38 2.93 3.71 3.80 7.58 +5.75 4.96 5.51 4.65 4.14 4.56 4.20 4.34 5.19 3.95 +5.06 5.11 5.14 4.68 4.32 4.44 3.57 5.53 4.42 5.74 +4.00 5.74 4.33 3.99 4.10 5.85 4.88 3.63 4.30 5.14 +4.56 3.59 3.68 5.68 4.54 4.71 4.40 5.38 3.54 4.80 +5.24 4.87 4.94 4.09 3.44 4.02 2.99 5.75 4.53 5.82 +4.42 4.03 3.54 5.57 5.45 2.74 3.61 6.33 4.23 4.26 +4.48 4.70 3.05 6.01 5.87 4.00 4.77 5.02 6.05 5.21 +4.89 4.31 4.49 6.07 4.78 5.03 4.00 4.04 6.03 3.73 +4.71 4.55 5.62 4.26 3.18 4.39 4.07 4.07 3.90 5.78 +4.64 4.49 3.46 4.23 3.80 5.18 5.56 4.84 4.31 2.86 +5.28 5.57 4.84 4.96 4.10 4.71 5.76 4.93 3.73 4.68 +5.68 4.87 5.22 6.10 3.96 3.24 5.06 3.38 4.33 3.80 +7.13 4.83 4.74 3.55 5.13 3.59 5.96 4.41 4.65 4.49 +5.13 5.17 4.48 4.96 3.50 4.49 5.30 4.92 3.88 5.48 +4.28 5.14 3.91 4.88 4.26 6.70 3.29 5.22 4.78 4.11 + BOTM LAYERED + INTERNAL FACTOR 1.0 +4.93 4.43 3.52 3.82 2.85 3.48 2.60 4.72 2.34 2.93 +2.83 4.06 3.52 4.51 3.54 4.61 2.73 3.70 3.30 3.92 +5.36 3.47 4.81 3.65 3.12 3.40 4.05 4.40 2.65 3.58 +3.53 3.02 2.57 4.55 4.18 4.69 3.19 5.06 2.48 4.11 +4.28 5.40 3.62 5.20 3.81 4.74 2.52 2.32 2.43 6.47 +4.84 4.29 2.89 3.71 2.54 2.68 3.90 3.34 4.25 2.51 +3.13 2.96 4.10 2.71 3.33 3.56 3.09 4.38 3.50 4.77 +3.39 4.88 3.50 3.44 3.45 4.61 4.22 3.37 3.15 4.84 +3.16 3.31 3.13 4.19 3.67 3.44 3.25 3.10 2.68 3.95 +4.91 4.30 4.27 1.52 2.88 2.68 2.76 3.92 2.34 4.57 +2.90 3.31 2.70 4.53 4.76 2.59 3.23 5.21 3.84 1.69 +3.77 3.57 2.99 5.33 3.92 3.79 2.95 4.43 4.92 4.68 +4.27 3.89 3.83 4.83 3.96 3.81 3.76 2.89 4.86 2.91 +4.26 2.76 4.50 3.58 2.59 4.20 3.81 3.80 3.01 4.85 +4.00 3.57 3.26 3.32 3.45 4.17 3.56 4.12 2.68 2.75 +4.90 4.90 3.35 4.69 3.70 4.44 3.25 3.95 2.71 2.86 +4.37 4.44 3.98 4.83 3.20 2.64 3.07 3.18 4.00 2.38 +5.99 3.36 3.98 3.01 2.19 3.00 5.06 3.09 2.78 4.36 +3.25 4.55 2.72 4.33 3.04 2.89 4.82 3.94 3.18 4.36 +3.76 4.42 3.16 3.15 3.70 3.19 2.37 4.09 3.27 3.33 + INTERNAL FACTOR 1.0 +2.35 3.52 0.56 3.19 2.18 2.15 2.11 2.50 1.96 2.86 +1.59 3.09 2.80 1.71 2.86 3.57 2.60 3.25 2.47 2.80 +1.25 2.25 4.10 3.27 3.09 2.74 3.46 1.48 2.38 0.40 +2.71 1.45 0.86 3.37 2.77 2.27 2.48 3.82 0.72 3.46 +3.18 0.64 2.71 2.04 2.18 3.49 2.15 1.53 1.91 5.43 +3.64 2.51 2.18 3.20 1.23 1.87 2.91 2.26 1.63 1.71 +2.60 1.91 3.36 2.00 2.29 1.82 2.49 3.58 2.26 3.43 +1.27 4.35 2.98 0.95 2.51 2.01 3.38 2.55 1.69 3.51 +2.56 2.30 2.84 3.35 2.41 1.66 2.17 2.50 2.21 2.79 +4.07 3.71 1.94 1.07 1.96 2.57 2.53 2.33 1.37 4.07 +2.86 2.76 1.26 2.02 2.69 0.91 1.25 3.36 2.61 0.93 +3.07 2.63 2.25 1.69 3.00 2.67 2.67 4.12 4.21 2.19 +3.01 2.80 3.30 3.93 2.36 2.54 1.49 2.31 3.97 1.93 +2.52 1.28 3.34 3.08 2.21 1.53 3.32 2.27 2.83 1.99 +3.29 2.91 0.75 3.04 2.55 3.70 3.27 3.55 1.18 0.78 +1.95 3.81 3.04 4.01 1.82 3.45 0.77 3.37 1.52 0.89 +3.14 3.36 2.81 4.07 2.87 2.30 2.12 2.23 3.43 1.66 +1.99 2.45 2.40 2.26 1.99 2.74 3.89 1.40 2.40 3.19 +2.27 3.44 2.25 2.75 1.12 2.34 3.69 2.22 2.15 3.42 +3.14 2.19 1.47 1.97 3.06 1.11 2.19 3.58 2.62 2.78 + INTERNAL FACTOR 1.0 +0.99 2.72 0.18 0.77 0.41 1.74 1.54 0.79 1.58 0.74 +0.89 2.19 1.69 1.33 2.40 1.97 2.03 2.94 2.15 2.10 +1.07 1.98 3.53 1.48 2.79 2.00 2.34 0.72 0.69 0.36 +1.74 0.75 0.41 2.67 2.13 1.05 0.36 2.05 0.65 2.95 +2.20 0.48 1.63 1.03 1.34 1.50 1.05 1.48 0.89 4.19 +0.89 1.92 1.84 0.35 0.81 1.34 1.37 1.67 1.33 0.11 +0.14 1.07 2.23 1.32 0.72 1.08 0.99 2.36 0.25 2.34 +0.15 3.59 1.16 0.82 2.05 1.28 2.16 1.54 1.44 3.23 +0.18 1.71 1.27 1.61 0.37 1.29 1.66 0.56 1.91 2.28 +0.67 2.58 1.16 0.68 1.47 1.34 0.94 1.68 1.13 0.78 +0.90 2.12 0.28 1.05 2.31 0.63 0.54 2.82 1.68 0.40 +2.39 2.07 1.43 0.48 2.07 1.41 1.13 2.96 1.68 1.26 +0.77 1.22 0.71 1.08 0.49 1.15 0.80 1.93 1.77 1.11 +1.10 0.50 0.26 2.13 0.38 0.69 0.51 2.09 1.11 1.94 +1.09 2.10 0.50 2.39 1.67 2.26 2.54 2.46 1.05 0.73 +1.86 3.54 2.80 1.03 1.52 2.24 0.41 2.12 0.87 0.49 +2.62 0.45 2.30 3.09 1.88 0.80 0.69 1.21 1.80 0.68 +0.19 0.22 1.44 1.20 1.27 2.04 1.40 0.49 0.43 1.83 +1.37 2.48 1.46 2.37 0.33 1.87 2.86 1.42 0.95 1.52 +0.45 1.06 1.46 0.78 1.34 0.84 0.71 0.48 2.21 1.92 + INTERNAL FACTOR 1.0 +0.71 0.00 0.00 0.00 0.00 0.77 0.00 0.00 0.59 0.43 +0.38 0.09 0.00 0.00 0.00 0.61 0.94 0.52 1.06 0.00 +0.00 0.00 0.03 0.00 0.00 0.00 0.08 0.00 0.00 0.00 +0.68 0.31 0.00 0.00 0.00 0.00 0.00 0.68 0.00 0.81 +0.00 0.00 0.70 0.33 0.00 0.48 0.00 0.00 0.00 1.79 +0.00 0.21 1.20 0.00 0.77 1.07 0.00 1.00 0.85 0.00 +0.00 0.16 1.21 0.90 0.23 0.00 0.58 1.56 0.00 1.72 +0.00 2.39 0.12 0.59 0.61 0.29 1.54 0.34 0.16 2.32 +0.00 1.27 0.10 0.47 0.23 0.00 1.26 0.00 1.76 1.42 +0.00 0.00 0.79 0.00 0.55 0.00 0.11 1.27 0.00 0.00 +0.00 0.00 0.00 0.00 1.08 0.00 0.00 0.76 0.37 0.00 +1.91 0.00 0.53 0.14 1.68 0.00 0.00 2.53 0.00 0.14 +0.00 0.00 0.00 0.05 0.00 0.07 0.00 0.00 0.00 0.00 +0.00 0.00 0.00 0.97 0.00 0.00 0.00 1.41 0.36 0.00 +0.66 0.08 0.00 0.00 0.87 1.39 1.48 0.00 0.40 0.00 +1.49 2.38 0.08 0.29 0.00 0.85 0.34 0.41 0.11 0.00 +0.14 0.00 0.87 1.96 1.08 0.05 0.00 0.00 0.64 0.02 +0.00 0.00 0.00 0.86 0.21 0.00 0.00 0.00 0.00 0.91 +0.71 0.00 0.00 1.67 0.16 0.00 0.00 0.73 0.68 0.84 +0.00 0.84 1.01 0.00 0.00 0.28 0.00 0.28 1.77 0.00 + IDOMAIN LAYERED + INTERNAL FACTOR 1 IPRN -1 + 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + CONSTANT 1 + CONSTANT 1 + CONSTANT 1 +END GRIDDATA + +BEGIN VERTICES + 1 0.0 10.0 + 2 1.0 10.0 + 3 2.0 10.0 + 4 3.0 10.0 + 5 4.0 10.0 + 6 5.0 10.0 + 7 6.0 10.0 + 8 7.0 10.0 + 9 8.0 10.0 + 10 9.0 10.0 + 11 10.0 10.0 + 12 0.0 9.0 + 13 1.0 9.0 + 14 2.0 9.0 + 15 3.0 9.0 + 16 4.0 9.0 + 17 5.0 9.0 + 18 6.0 9.0 + 19 7.0 9.0 + 20 8.0 9.0 + 21 9.0 9.0 + 22 10.0 9.0 + 23 0.0 8.0 + 24 1.0 8.0 + 25 2.0 8.0 + 26 3.0 8.0 + 27 4.0 8.0 + 28 5.0 8.0 + 29 6.0 8.0 + 30 7.0 8.0 + 31 8.0 8.0 + 32 9.0 8.0 + 33 10.0 8.0 + 34 0.0 7.0 + 35 1.0 7.0 + 36 2.0 7.0 + 37 3.0 7.0 + 38 4.0 7.0 + 39 5.0 7.0 + 40 6.0 7.0 + 41 7.0 7.0 + 42 8.0 7.0 + 43 9.0 7.0 + 44 10.0 7.0 + 45 0.0 6.0 + 46 1.0 6.0 + 47 2.0 6.0 + 48 3.0 6.0 + 49 4.0 6.0 + 50 5.0 6.0 + 51 6.0 6.0 + 52 7.0 6.0 + 53 8.0 6.0 + 54 9.0 6.0 + 55 10.0 6.0 + 56 0.0 5.0 + 57 1.0 5.0 + 58 2.0 5.0 + 59 3.0 5.0 + 60 4.0 5.0 + 61 5.0 5.0 + 62 6.0 5.0 + 63 7.0 5.0 + 64 8.0 5.0 + 65 9.0 5.0 + 66 10.0 5.0 + 67 0.0 4.0 + 68 1.0 4.0 + 69 2.0 4.0 + 70 3.0 4.0 + 71 4.0 4.0 + 72 5.0 4.0 + 73 6.0 4.0 + 74 7.0 4.0 + 75 8.0 4.0 + 76 9.0 4.0 + 77 10.0 4.0 + 78 0.0 3.0 + 79 1.0 3.0 + 80 2.0 3.0 + 81 3.0 3.0 + 82 4.0 3.0 + 83 5.0 3.0 + 84 6.0 3.0 + 85 7.0 3.0 + 86 8.0 3.0 + 87 9.0 3.0 + 88 10.0 3.0 + 89 0.0 2.0 + 90 1.0 2.0 + 91 2.0 2.0 + 92 3.0 2.0 + 93 4.0 2.0 + 94 5.0 2.0 + 95 6.0 2.0 + 96 7.0 2.0 + 97 8.0 2.0 + 98 9.0 2.0 + 99 10.0 2.0 + 100 0.0 1.0 + 101 1.0 1.0 + 102 2.0 1.0 + 103 3.0 1.0 + 104 4.0 1.0 + 105 5.0 1.0 + 106 6.0 1.0 + 107 7.0 1.0 + 108 8.0 1.0 + 109 9.0 1.0 + 110 10.0 1.0 + 111 0.0 0.0 + 112 1.0 0.0 + 113 2.0 0.0 + 114 3.0 0.0 + 115 4.0 0.0 + 116 5.0 0.0 + 117 6.0 0.0 + 118 7.0 0.0 + 119 8.0 0.0 + 120 9.0 0.0 + 121 10.0 0.0 +END VERTICES + +BEGIN CELL2D +1 0.33 9.67 3 1 2 12 +2 0.67 9.33 3 2 13 12 +3 1.33 9.67 3 2 3 13 +4 1.67 9.33 3 3 14 13 +5 2.33 9.67 3 3 4 14 +6 2.67 9.33 3 4 15 14 +7 3.33 9.67 3 4 5 15 +8 3.67 9.33 3 5 16 15 +9 4.33 9.67 3 5 6 16 +10 4.67 9.33 3 6 17 16 +11 5.33 9.67 3 6 7 17 +12 5.67 9.33 3 7 18 17 +13 6.33 9.67 3 7 8 18 +14 6.67 9.33 3 8 19 18 +15 7.33 9.67 3 8 9 19 +16 7.67 9.33 3 9 20 19 +17 8.33 9.67 3 9 10 20 +18 8.67 9.33 3 10 21 20 +19 9.33 9.67 3 10 11 21 +20 9.67 9.33 3 11 22 21 +21 0.33 8.67 3 12 13 23 +22 0.67 8.33 3 13 24 23 +23 1.33 8.67 3 13 14 24 +24 1.67 8.33 3 14 25 24 +25 2.33 8.67 3 14 15 25 +26 2.67 8.33 3 15 26 25 +27 3.33 8.67 3 15 16 26 +28 3.67 8.33 3 16 27 26 +29 4.33 8.67 3 16 17 27 +30 4.67 8.33 3 17 28 27 +31 5.33 8.67 3 17 18 28 +32 5.67 8.33 3 18 29 28 +33 6.33 8.67 3 18 19 29 +34 6.67 8.33 3 19 30 29 +35 7.33 8.67 3 19 20 30 +36 7.67 8.33 3 20 31 30 +37 8.33 8.67 3 20 21 31 +38 8.67 8.33 3 21 32 31 +39 9.33 8.67 3 21 22 32 +40 9.67 8.33 3 22 33 32 +41 0.33 7.67 3 23 24 34 +42 0.67 7.33 3 24 35 34 +43 1.33 7.67 3 24 25 35 +44 1.67 7.33 3 25 36 35 +45 2.33 7.67 3 25 26 36 +46 2.67 7.33 3 26 37 36 +47 3.33 7.67 3 26 27 37 +48 3.67 7.33 3 27 38 37 +49 4.33 7.67 3 27 28 38 +50 4.67 7.33 3 28 39 38 +51 5.33 7.67 3 28 29 39 +52 5.67 7.33 3 29 40 39 +53 6.33 7.67 3 29 30 40 +54 6.67 7.33 3 30 41 40 +55 7.33 7.67 3 30 31 41 +56 7.67 7.33 3 31 42 41 +57 8.33 7.67 3 31 32 42 +58 8.67 7.33 3 32 43 42 +59 9.33 7.67 3 32 33 43 +60 9.67 7.33 3 33 44 43 +61 0.33 6.67 3 34 35 45 +62 0.67 6.33 3 35 46 45 +63 1.33 6.67 3 35 36 46 +64 1.67 6.33 3 36 47 46 +65 2.33 6.67 3 36 37 47 +66 2.67 6.33 3 37 48 47 +67 3.33 6.67 3 37 38 48 +68 3.67 6.33 3 38 49 48 +69 4.33 6.67 3 38 39 49 +70 4.67 6.33 3 39 50 49 +71 5.33 6.67 3 39 40 50 +72 5.67 6.33 3 40 51 50 +73 6.33 6.67 3 40 41 51 +74 6.67 6.33 3 41 52 51 +75 7.33 6.67 3 41 42 52 +76 7.67 6.33 3 42 53 52 +77 8.33 6.67 3 42 43 53 +78 8.67 6.33 3 43 54 53 +79 9.33 6.67 3 43 44 54 +80 9.67 6.33 3 44 55 54 +81 0.33 5.67 3 45 46 56 +82 0.67 5.33 3 46 57 56 +83 1.33 5.67 3 46 47 57 +84 1.67 5.33 3 47 58 57 +85 2.33 5.67 3 47 48 58 +86 2.67 5.33 3 48 59 58 +87 3.33 5.67 3 48 49 59 +88 3.67 5.33 3 49 60 59 +89 4.33 5.67 3 49 50 60 +90 4.67 5.33 3 50 61 60 +91 5.33 5.67 3 50 51 61 +92 5.67 5.33 3 51 62 61 +93 6.33 5.67 3 51 52 62 +94 6.67 5.33 3 52 63 62 +95 7.33 5.67 3 52 53 63 +96 7.67 5.33 3 53 64 63 +97 8.33 5.67 3 53 54 64 +98 8.67 5.33 3 54 65 64 +99 9.33 5.67 3 54 55 65 +100 9.67 5.33 3 55 66 65 +101 0.33 4.67 3 56 57 67 +102 0.67 4.33 3 57 68 67 +103 1.33 4.67 3 57 58 68 +104 1.67 4.33 3 58 69 68 +105 2.33 4.67 3 58 59 69 +106 2.67 4.33 3 59 70 69 +107 3.33 4.67 3 59 60 70 +108 3.67 4.33 3 60 71 70 +109 4.33 4.67 3 60 61 71 +110 4.67 4.33 3 61 72 71 +111 5.33 4.67 3 61 62 72 +112 5.67 4.33 3 62 73 72 +113 6.33 4.67 3 62 63 73 +114 6.67 4.33 3 63 74 73 +115 7.33 4.67 3 63 64 74 +116 7.67 4.33 3 64 75 74 +117 8.33 4.67 3 64 65 75 +118 8.67 4.33 3 65 76 75 +119 9.33 4.67 3 65 66 76 +120 9.67 4.33 3 66 77 76 +121 0.33 3.67 3 67 68 78 +122 0.67 3.33 3 68 79 78 +123 1.33 3.67 3 68 69 79 +124 1.67 3.33 3 69 80 79 +125 2.33 3.67 3 69 70 80 +126 2.67 3.33 3 70 81 80 +127 3.33 3.67 3 70 71 81 +128 3.67 3.33 3 71 82 81 +129 4.33 3.67 3 71 72 82 +130 4.67 3.33 3 72 83 82 +131 5.33 3.67 3 72 73 83 +132 5.67 3.33 3 73 84 83 +133 6.33 3.67 3 73 74 84 +134 6.67 3.33 3 74 85 84 +135 7.33 3.67 3 74 75 85 +136 7.67 3.33 3 75 86 85 +137 8.33 3.67 3 75 76 86 +138 8.67 3.33 3 76 87 86 +139 9.33 3.67 3 76 77 87 +140 9.67 3.33 3 77 88 87 +141 0.33 2.67 3 78 79 89 +142 0.67 2.33 3 79 90 89 +143 1.33 2.67 3 79 80 90 +144 1.67 2.33 3 80 91 90 +145 2.33 2.67 3 80 81 91 +146 2.67 2.33 3 81 92 91 +147 3.33 2.67 3 81 82 92 +148 3.67 2.33 3 82 93 92 +149 4.33 2.67 3 82 83 93 +150 4.67 2.33 3 83 94 93 +151 5.33 2.67 3 83 84 94 +152 5.67 2.33 3 84 95 94 +153 6.33 2.67 3 84 85 95 +154 6.67 2.33 3 85 96 95 +155 7.33 2.67 3 85 86 96 +156 7.67 2.33 3 86 97 96 +157 8.33 2.67 3 86 87 97 +158 8.67 2.33 3 87 98 97 +159 9.33 2.67 3 87 88 98 +160 9.67 2.33 3 88 99 98 +161 0.33 1.67 3 89 90 100 +162 0.67 1.33 3 90 101 100 +163 1.33 1.67 3 90 91 101 +164 1.67 1.33 3 91 102 101 +165 2.33 1.67 3 91 92 102 +166 2.67 1.33 3 92 103 102 +167 3.33 1.67 3 92 93 103 +168 3.67 1.33 3 93 104 103 +169 4.33 1.67 3 93 94 104 +170 4.67 1.33 3 94 105 104 +171 5.33 1.67 3 94 95 105 +172 5.67 1.33 3 95 106 105 +173 6.33 1.67 3 95 96 106 +174 6.67 1.33 3 96 107 106 +175 7.33 1.67 3 96 97 107 +176 7.67 1.33 3 97 108 107 +177 8.33 1.67 3 97 98 108 +178 8.67 1.33 3 98 109 108 +179 9.33 1.67 3 98 99 109 +180 9.67 1.33 3 99 110 109 +181 0.33 0.67 3 100 101 111 +182 0.67 0.33 3 101 112 111 +183 1.33 0.67 3 101 102 112 +184 1.67 0.33 3 102 113 112 +185 2.33 0.67 3 102 103 113 +186 2.67 0.33 3 103 114 113 +187 3.33 0.67 3 103 104 114 +188 3.67 0.33 3 104 115 114 +189 4.33 0.67 3 104 105 115 +190 4.67 0.33 3 105 116 115 +191 5.33 0.67 3 105 106 116 +192 5.67 0.33 3 106 117 116 +193 6.33 0.67 3 106 107 117 +194 6.67 0.33 3 107 118 117 +195 7.33 0.67 3 107 108 118 +196 7.67 0.33 3 108 119 118 +197 8.33 0.67 3 108 109 119 +198 8.67 0.33 3 109 120 119 +199 9.33 0.67 3 109 110 120 +200 9.67 0.33 3 110 121 120 +END CELL2D + diff --git a/examples/data/disv_model/tri_model_left.chd b/examples/data/disv_model/tri_model_left.chd new file mode 100644 index 0000000..766c38a --- /dev/null +++ b/examples/data/disv_model/tri_model_left.chd @@ -0,0 +1,24 @@ +begin options + PRINT_INPUT + PRINT_FLOWS + SAVE_FLOWS +end options + +begin dimensions + MAXBOUND 10 +end dimensions + +begin period 1 +#layer 1 + 1 1 10. + 1 21 10. + 1 41 10. + 1 61 10. + 1 81 10. + 1 101 10. + 1 121 10. + 1 141 10. + 1 161 10. + 1 181 10. +end period + diff --git a/examples/data/disv_model/tri_model_right.chd b/examples/data/disv_model/tri_model_right.chd new file mode 100644 index 0000000..446cd9c --- /dev/null +++ b/examples/data/disv_model/tri_model_right.chd @@ -0,0 +1,23 @@ +begin options + PRINT_INPUT + PRINT_FLOWS + SAVE_FLOWS +end options + +begin dimensions + MAXBOUND 10 +end dimensions + +begin period 1 +#layer 1 + 1 20 5. + 1 40 5. + 1 60 5. + 1 80 5. + 1 100 5. + 1 120 5. + 1 140 5. + 1 160 5. + 1 180 5. + 1 200 5. +end period diff --git a/examples/data/two_models/mfsim.nam b/examples/data/two_models/mfsim.nam new file mode 100644 index 0000000..86f9764 --- /dev/null +++ b/examples/data/two_models/mfsim.nam @@ -0,0 +1,24 @@ +BEGIN OPTIONS +#none +END OPTIONS + +BEGIN TIMING + TDIS6 simulation.tdis +END TIMING + +BEGIN MODELS + #modeltype namefile modelname + GWF6 model1.nam PARENT + GWF6 model2.nam CHILD +END MODELS + +BEGIN EXCHANGES + GWF6-GWF6 simulation.exg PARENT CHILD +END EXCHANGES + +BEGIN SOLUTIONGROUP 1 + MXITER 1 + IMS6 simulation.ims PARENT CHILD +END SOLUTIONGROUP + + diff --git a/examples/data/two_models/model1.chd b/examples/data/two_models/model1.chd new file mode 100644 index 0000000..081c1f0 --- /dev/null +++ b/examples/data/two_models/model1.chd @@ -0,0 +1,30 @@ +begin options + PRINT_INPUT + PRINT_FLOWS + SAVE_FLOWS +end options + +begin dimensions + MAXBOUND 30 +end dimensions + +begin period 1 + +#left + 1 1 1 1. + 1 2 1 1. + 1 3 1 1. + 1 4 1 1. + 1 5 1 1. + 1 6 1 1. + 1 7 1 1. + +#right + 1 1 7 0. + 1 2 7 0. + 1 3 7 0. + 1 4 7 0. + 1 5 7 0. + 1 6 7 0. + 1 7 7 0. +end period diff --git a/examples/data/two_models/model1.dis b/examples/data/two_models/model1.dis new file mode 100644 index 0000000..1f9005c --- /dev/null +++ b/examples/data/two_models/model1.dis @@ -0,0 +1,30 @@ +# Structured discretization file for MODFLOW-USG +begin options + LENGTH_UNITS meters +end options + +begin dimensions + nlay 1 + nrow 7 + ncol 7 +end dimensions + +BEGIN GRIDDATA + IDOMAIN + INTERNAL FACTOR 1 + 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 + 1 1 0 0 0 1 1 + 1 1 0 0 0 1 1 + 1 1 0 0 0 1 1 + 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 + delr + constant 100. + delc + constant 100. + top + constant 0. + botm + constant -100 +END GRIDDATA diff --git a/examples/data/two_models/model1.ic b/examples/data/two_models/model1.ic new file mode 100644 index 0000000..841d89f --- /dev/null +++ b/examples/data/two_models/model1.ic @@ -0,0 +1,15 @@ +# Basic package file for MODFLOW-USG, generated by Flopy. +begin options +end options + +BEGIN GRIDDATA +strt +INTERNAL FACTOR 1.0 IPRN + 1.0 1.0 1.0 1.0 1.0 1.0 0.0 + 1.0 1.0 1.0 1.0 1.0 1.0 0.0 + 1.0 1.0 1.0 1.0 1.0 1.0 0.0 + 1.0 1.0 1.0 1.0 1.0 1.0 0.0 + 1.0 1.0 1.0 1.0 1.0 1.0 0.0 + 1.0 1.0 1.0 1.0 1.0 1.0 0.0 + 1.0 1.0 1.0 1.0 1.0 1.0 0.0 +END GRIDDATA diff --git a/examples/data/two_models/model1.mawq b/examples/data/two_models/model1.mawq new file mode 100644 index 0000000..869d5d9 --- /dev/null +++ b/examples/data/two_models/model1.mawq @@ -0,0 +1,26 @@ +#option block. Note -- no comments allowed on auxiliary line +begin options + PRINT_INPUT (echo input to listing file) + PRINT_FLOWS (print the flows to the listing file) + BOUNDNAMES + #OBS6 FILEIN flow15.maw_1.obs + MOVER +end options + +begin dimensions + NMAWWELLS 1 +end dimensions + +BEGIN PACKAGEDATA +# no radius bottom strt condeqn ngwnodes name + 1 0.15 -10.0 10.0 SPECIFIED 1 'well 1' +END PACKAGEDATA + +begin CONNECTIONDATA +# conn l r c stop sbot K rskin + 1 1 1 4 2 10. -10. 1. 0 +end CONNECTIONDATA + +begin period 1 steady-state + 1 rate 0. +end period diff --git a/examples/data/two_models/model1.nam b/examples/data/two_models/model1.nam new file mode 100644 index 0000000..92ac07d --- /dev/null +++ b/examples/data/two_models/model1.nam @@ -0,0 +1,13 @@ +BEGIN OPTIONS + NEWTON +END OPTIONS + +BEGIN PACKAGES + DIS6 model1.dis + IC6 model1.ic + NPF6 model1.npf npf_p1 + CHD6 model1.chd + MAW6 model1.mawq + OC6 model1.oc oc_p1 +END PACKAGES + diff --git a/examples/data/two_models/model1.npf b/examples/data/two_models/model1.npf new file mode 100644 index 0000000..e83c9f2 --- /dev/null +++ b/examples/data/two_models/model1.npf @@ -0,0 +1,12 @@ +begin options + save_FLOWS +end options +# +BEGIN GRIDDATA + icelltype + constant 0 + K + constant 1. + K33 + constant 1. +END GRIDDATA diff --git a/examples/data/two_models/model1.oc b/examples/data/two_models/model1.oc new file mode 100644 index 0000000..10560bf --- /dev/null +++ b/examples/data/two_models/model1.oc @@ -0,0 +1,11 @@ +BEGIN OPTIONS + HEAD FILEOUT model1.hds + BUDGET FILEOUT model1.cbc +END OPTIONS + +BEGIN PERIOD 1 + PRINT BUDGET ALL + SAVE BUDGET ALL + PRINT HEAD ALL + SAVE HEAD ALL +END PERIOD diff --git a/examples/data/two_models/model2.dis b/examples/data/two_models/model2.dis new file mode 100644 index 0000000..a74dded --- /dev/null +++ b/examples/data/two_models/model2.dis @@ -0,0 +1,21 @@ +# Unstructured discretization file for MODFLOW-USG +begin options + LENGTH_UNITS meters +end options + +begin dimensions + nlay 1 + nrow 9 + ncol 9 +end dimensions + +BEGIN GRIDDATA + delr + constant 33.33 + delc + constant 33.33 + top + constant 0. + botm + constant -100. +END GRIDDATA diff --git a/examples/data/two_models/model2.ic b/examples/data/two_models/model2.ic new file mode 100644 index 0000000..e87daea --- /dev/null +++ b/examples/data/two_models/model2.ic @@ -0,0 +1,8 @@ +# Basic package file for MODFLOW-USG, generated by Flopy. +begin options +end options + +BEGIN GRIDDATA +strt + constant 1.0 +END GRIDDATA diff --git a/examples/data/two_models/model2.mawq b/examples/data/two_models/model2.mawq new file mode 100644 index 0000000..62bad2b --- /dev/null +++ b/examples/data/two_models/model2.mawq @@ -0,0 +1,26 @@ +#option block. Note -- no comments allowed on auxiliary line +begin options + PRINT_INPUT (echo input to listing file) + PRINT_FLOWS (print the flows to the listing file) + BOUNDNAMES + #OBS6 FILEIN flow15.maw_2.obs + MOVER +end options + +begin dimensions + NMAWWELLS 1 +end dimensions + +BEGIN PACKAGEDATA +# no radius bottom strt condeqn ngwnodes name + 1 0.15 -10.0 10.0 SPECIFIED 1 'well 1' +END PACKAGEDATA + +begin CONNECTIONDATA +# conn l r c stop sbot K rskin + 1 1 1 5 5 10. -10. 1. 0 +end CONNECTIONDATA + +begin period 1 steady-state + 1 rate -10. +end period diff --git a/examples/data/two_models/model2.nam b/examples/data/two_models/model2.nam new file mode 100644 index 0000000..8783862 --- /dev/null +++ b/examples/data/two_models/model2.nam @@ -0,0 +1,12 @@ +BEGIN OPTIONS + NEWTON +END OPTIONS + +BEGIN PACKAGES + DIS6 model2.dis + IC6 model2.ic + NPF6 model2.npf + MAW6 model2.mawq + OC6 model2.oc oc_p2 +END PACKAGES + diff --git a/examples/data/two_models/model2.npf b/examples/data/two_models/model2.npf new file mode 100644 index 0000000..d584c43 --- /dev/null +++ b/examples/data/two_models/model2.npf @@ -0,0 +1,34 @@ +begin options + SAVE_FLOWS +end options +# +BEGIN GRIDDATA +# +#apply these arrays for the entire simulation +# +#icelltype(nodes) is 0:confined, 1:convertible, 4:upstream? + icelltype + constant 0 +# +#K(nodes) horizontal hydraulic conductivity + K + constant 1. +# +#K33(nodes) vertical hydraulic conductivity + K33 + constant 1. +# +#this will crash it funkyarray +# constant +END GRIDDATA + + + 50 -1.0e+30 0 0 + 0 + 0 + 1 + 1 + 0 + 0 1.000e+00 (10G13.0) -1 HK() = Horizontal hydraulic conductivity of layer 1 + 0 1.000e+00 (10G13.0) -1 VKA() = Vertical hydraulic conductivity of layer 1 + 0 0.000e+00 (10G13.0) -1 WETDRY() = Wetting threshold of layer 1 diff --git a/examples/data/two_models/model2.oc b/examples/data/two_models/model2.oc new file mode 100644 index 0000000..9ff0ac5 --- /dev/null +++ b/examples/data/two_models/model2.oc @@ -0,0 +1,11 @@ +BEGIN OPTIONS + HEAD FILEOUT model2.hds + BUDGET FILEOUT model2.cbc +END OPTIONS + +BEGIN PERIOD 1 + PRINT BUDGET ALL + SAVE BUDGET ALL + PRINT HEAD ALL + SAVE HEAD ALL +END PERIOD diff --git a/examples/data/two_models/simulation.exg b/examples/data/two_models/simulation.exg new file mode 100644 index 0000000..44c67b3 --- /dev/null +++ b/examples/data/two_models/simulation.exg @@ -0,0 +1,62 @@ + +begin options + PRINT_INPUT + PRINT_FLOWS + SAVE_FLOWS + AUXILIARY testaux + GNC6 FILEIN simulation.gnc + MVR6 FILEIN simulation.mvr +end options + +begin dimensions + NEXG 36 +end dimensions + + # nodem1 nodem2 ihc cl1 cl2 hwva testaux +begin exchangedata +# +# left side + 1 3 2 1 1 1 1 50. 16.67 33.33 100.99 + 1 3 2 1 2 1 1 50. 16.67 33.33 100.99 + 1 3 2 1 3 1 1 50. 16.67 33.33 100.99 + 1 4 2 1 4 1 1 50. 16.67 33.33 100.99 + 1 4 2 1 5 1 1 50. 16.67 33.33 100.99 + 1 4 2 1 6 1 1 50. 16.67 33.33 100.99 + 1 5 2 1 7 1 1 50. 16.67 33.33 100.99 + 1 5 2 1 8 1 1 50. 16.67 33.33 100.99 + 1 5 2 1 9 1 1 50. 16.67 33.33 100.99 +# +# right side + 1 3 6 1 1 9 1 50. 16.67 33.33 100.99 + 1 3 6 1 2 9 1 50. 16.67 33.33 100.99 + 1 3 6 1 3 9 1 50. 16.67 33.33 100.99 + 1 4 6 1 4 9 1 50. 16.67 33.33 100.99 + 1 4 6 1 5 9 1 50. 16.67 33.33 100.99 + 1 4 6 1 6 9 1 50. 16.67 33.33 100.99 + 1 5 6 1 7 9 1 50. 16.67 33.33 100.99 + 1 5 6 1 8 9 1 50. 16.67 33.33 100.99 + 1 5 6 1 9 9 1 50. 16.67 33.33 100.99 +# +# back + 1 2 3 1 1 1 1 50. 16.67 33.33 100.99 + 1 2 3 1 1 2 1 50. 16.67 33.33 100.99 + 1 2 3 1 1 3 1 50. 16.67 33.33 100.99 + 1 2 4 1 1 4 1 50. 16.67 33.33 100.99 + 1 2 4 1 1 5 1 50. 16.67 33.33 100.99 + 1 2 4 1 1 6 1 50. 16.67 33.33 100.99 + 1 2 5 1 1 7 1 50. 16.67 33.33 100.99 + 1 2 5 1 1 8 1 50. 16.67 33.33 100.99 + 1 2 5 1 1 9 1 50. 16.67 33.33 100.99 +# +# front + 1 6 3 1 9 1 1 50. 16.67 33.33 100.99 + 1 6 3 1 9 2 1 50. 16.67 33.33 100.99 + 1 6 3 1 9 3 1 50. 16.67 33.33 100.99 + 1 6 4 1 9 4 1 50. 16.67 33.33 100.99 + 1 6 4 1 9 5 1 50. 16.67 33.33 100.99 + 1 6 4 1 9 6 1 50. 16.67 33.33 100.99 + 1 6 5 1 9 7 1 50. 16.67 33.33 100.99 + 1 6 5 1 9 8 1 50. 16.67 33.33 100.99 + 1 6 5 1 9 9 1 50. 16.67 33.33 100.99 +end exchangedata + diff --git a/examples/data/two_models/simulation.gnc b/examples/data/two_models/simulation.gnc new file mode 100644 index 0000000..a590308 --- /dev/null +++ b/examples/data/two_models/simulation.gnc @@ -0,0 +1,58 @@ +BEGIN OPTIONS + #I2KN + #IMPLICIT + PRINT_INPUT + PRINT_FLOWS +END OPTIONS + +BEGIN DIMENSIONS + NUMGNC 36 + NUMALPHAJ 1 +END DIMENSIONS + +BEGIN GNCDATA +# noden nodem nodesj alphasj +# left side + 1 3 2 1 1 1 1 2 2 0.333333333333 + 1 3 2 1 2 1 0 0 0 0.333333333333 + 1 3 2 1 3 1 1 4 2 0.333333333333 + 1 4 2 1 4 1 1 3 2 0.333333333333 + 1 4 2 1 5 1 0 0 0 0.333333333333 + 1 4 2 1 6 1 1 5 2 0.333333333333 + 1 5 2 1 7 1 1 4 2 0.333333333333 + 1 5 2 1 8 1 0 0 0 0.333333333333 + 1 5 2 1 9 1 1 6 2 0.333333333333 +# +# right side + 1 3 6 1 1 9 1 2 6 0.333333333333 + 1 3 6 1 2 9 0 0 0 0.333333333333 + 1 3 6 1 3 9 1 4 6 0.333333333333 + 1 4 6 1 4 9 1 3 6 0.333333333333 + 1 4 6 1 5 9 0 0 0 0.333333333333 + 1 4 6 1 6 9 1 5 6 0.333333333333 + 1 5 6 1 7 9 1 4 6 0.333333333333 + 1 5 6 1 8 9 0 0 0 0.333333333333 + 1 5 6 1 9 9 1 6 6 0.333333333333 +# +# back + 1 2 3 1 1 1 1 2 2 0.333333333333 + 1 2 3 1 1 2 0 0 0 0.333333333333 + 1 2 3 1 1 3 1 2 4 0.333333333333 + 1 2 4 1 1 4 1 2 3 0.333333333333 + 1 2 4 1 1 5 0 0 0 0.333333333333 + 1 2 4 1 1 6 1 2 5 0.333333333333 + 1 2 5 1 1 7 1 2 4 0.333333333333 + 1 2 5 1 1 8 0 0 0 0.333333333333 + 1 2 5 1 1 9 1 2 6 0.333333333333 +# +# front + 1 6 3 1 9 1 1 6 2 0.333333333333 + 1 6 3 1 9 2 0 0 0 0.333333333333 + 1 6 3 1 9 3 1 6 4 0.333333333333 + 1 6 4 1 9 4 1 6 3 0.333333333333 + 1 6 4 1 9 5 0 0 0 0.333333333333 + 1 6 4 1 9 6 1 6 5 0.333333333333 + 1 6 5 1 9 7 1 6 4 0.333333333333 + 1 6 5 1 9 8 0 0 0 0.333333333333 + 1 6 5 1 9 9 1 6 6 0.333333333333 +END GNCDATA diff --git a/examples/data/two_models/simulation.ims b/examples/data/two_models/simulation.ims new file mode 100644 index 0000000..6a15577 --- /dev/null +++ b/examples/data/two_models/simulation.ims @@ -0,0 +1,20 @@ +begin options + PRINT_OPTION SUMMARY +end options + +begin nonlinear + OUTER_DVCLOSE 1.e-8 + outer_maximum 1000 + under_relaxation none +end nonlinear + +begin linear + INNER_DVCLOSE 1.0e-8 + inner_rclose 0.01 + inner_maximum 1000 + linear_acceleration bicgstab + scaling_method none + REORDERING_METHOD none + relaxation_factor 0.97 +end linear + diff --git a/examples/data/two_models/simulation.mvr b/examples/data/two_models/simulation.mvr new file mode 100644 index 0000000..e28ec24 --- /dev/null +++ b/examples/data/two_models/simulation.mvr @@ -0,0 +1,21 @@ +BEGIN OPTIONS + PRINT_INPUT + PRINT_FLOWS + MODELNAMES +END OPTIONS + +BEGIN DIMENSIONS + MAXMVR 10 + MAXPACKAGES 2 +END DIMENSIONS + +BEGIN PACKAGES + 'PARENT' 'MAW-1' + 'CHILD' 'MAW-1' +END PACKAGES + +BEGIN PERIOD 1 +# mnamep packnamep idp mnamer packnamer idr type val +# ------------------------------------------------------- + 'CHILD' 'MAW-1' 1 'PARENT' 'MAW-1' 1 FACTOR 0.5 +END PERIOD 1 diff --git a/examples/data/two_models/simulation.tdis b/examples/data/two_models/simulation.tdis new file mode 100644 index 0000000..31e5be0 --- /dev/null +++ b/examples/data/two_models/simulation.tdis @@ -0,0 +1,12 @@ +BEGIN OPTIONS + TIME_UNITS DAYS +END OPTIONS + +BEGIN DIMENSIONS + NPER 1 +END DIMENSIONS + +BEGIN PERIODDATA + #perlen nstp tsmult + 1.0 1 1.0 +END PERIODDATA diff --git a/examples/notebooks/Head Monitor Example.ipynb b/examples/notebooks/Head Monitor Example.ipynb new file mode 100644 index 0000000..4e800ea --- /dev/null +++ b/examples/notebooks/Head Monitor Example.ipynb @@ -0,0 +1,255 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "ee31d799", + "metadata": {}, + "source": [ + "# MODFLOW-API Head monitor example\n", + "\n", + "In this example the modflow-api is used in a more complex callback function to create a Head Monitor that updates at the timestep level. This example reverses `CHD` boundary conditions each stress period on a simple 10 x 10 model and displays the head results for each timestep.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "4526a124", + "metadata": {}, + "outputs": [], + "source": [ + "from IPython.display import clear_output, display # remove this import if adapted to python script\n", + "\n", + "from modflowapi import run_simulation, Callbacks\n", + "from flopy.discretization import StructuredGrid\n", + "from flopy.plot import PlotMapView, styles\n", + "from pathlib import Path\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "id": "3f7ac8a2", + "metadata": {}, + "source": [ + "### Create a class that includes a callback function\n", + "\n", + "This class handles changing the `CHD` boundary condition as well as updating the matplotlib plot." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "cdd38b59", + "metadata": {}, + "outputs": [], + "source": [ + "class StructuredHeadMonitor:\n", + " \"\"\"\n", + " An example class that reverses the model gradient by\n", + " swapping CHD boundary conditions each stress period, \n", + " and monitors the head at each timestep by updating\n", + " a matplotlib plot. This class could be adapted to \n", + " be used as a head monitor to observe other changes\n", + " in the model by modifying the callback class.\n", + " \n", + " Parameters\n", + " ----------\n", + " layer: int\n", + " zero based model layer to plot\n", + " vmin : float\n", + " minimum head value for color scaling on the plot\n", + " vmax : float\n", + " maximum head value for color scaling on the plot\n", + " \"\"\"\n", + "\n", + " def __init__(self, layer, vmin, vmax):\n", + " self.modelgrid = None\n", + " self.ax = None\n", + " self.pmv = None\n", + " self.pc = None\n", + " self.ax = None\n", + " self.layer = layer\n", + " self.vmin = vmin\n", + " self.vmax = vmax\n", + " self.kperold = None\n", + "\n", + " def build_modelgrid(self, ml):\n", + " \"\"\"\n", + " Method to update the matplotlib plot\n", + " \n", + " Parameters\n", + " ----------\n", + " ml : ApiModel\n", + " modflow-api ApiModel object\n", + " \"\"\"\n", + " delc = ml.dis.get_advanced_var(\"delc\")\n", + " delr = ml.dis.get_advanced_var(\"delr\")\n", + " top = ml.dis.top.values[0]\n", + " botm = ml.dis.bot.values\n", + " idomain = ml.dis.idomain.values\n", + " self.modelgrid = StructuredGrid(\n", + " delc=delc,\n", + " delr=delr,\n", + " top=top,\n", + " botm=botm,\n", + " idomain=idomain\n", + " )\n", + "\n", + " def initialize_plot(self):\n", + " \"\"\"\n", + " Method to initalize a matplotlib plot using flopy\n", + " \"\"\"\n", + " fig, ax = plt.subplots(figsize=(8, 8))\n", + " self.fig = fig\n", + " self.ax = ax\n", + " self.pmv = PlotMapView(modelgrid=self.modelgrid, ax=ax, layer=self.layer)\n", + " grid = self.pmv.plot_grid()\n", + " idm = self.pmv.plot_inactive()\n", + " initial = np.full(self.modelgrid.shape, np.nan)\n", + " self.pc = self.pmv.plot_array(initial, vmin=self.vmin, vmax=self.vmax)\n", + " plt.colorbar(self.pc)\n", + "\n", + " def update_plot(self, ml):\n", + " \"\"\"\n", + " Method to update the matplotlib plot\n", + " \n", + " Parameters\n", + " ----------\n", + " ml : ApiModel\n", + " modflow-api ApiModel object\n", + " \"\"\"\n", + " heads = ml.X\n", + " self.ax.cla()\n", + " grid = self.pmv.plot_grid()\n", + " idm = self.pmv.plot_inactive()\n", + " self.pc = self.pmv.plot_array(heads, vmin=self.vmin, vmax=self.vmax)\n", + " \n", + " # only applicable to jupyter notebooks, remove these two lines in python scipt\n", + " display(self.fig) \n", + " if ml.kper == (ml.nper - 1) and ml.kstp == (ml.nstp - 1):\n", + " pass\n", + " else:\n", + " clear_output(wait = True) \n", + " \n", + " # the pause time can be reduced if adapted in python script \n", + " plt.pause(0.1) \n", + "\n", + " def callback(self, sim, callback_step):\n", + " \"\"\"\n", + " A demonstration function that dynamically adjusts the CHD\n", + " boundary conditions each stress period in a modflow-6 model\n", + " through the MODFLOW-API and then updates heads on a matplotlib\n", + " plot for each timestep.\n", + "\n", + " Parameters\n", + " ----------\n", + " sim : modflowapi.Simulation\n", + " A simulation object for the solution group that is \n", + " currently being solved\n", + " callback_step : enumeration\n", + " modflowapi.Callbacks enumeration object that indicates\n", + " the part of the solution modflow is currently in.\n", + " \"\"\"\n", + " if callback_step == Callbacks.initialize:\n", + " ml = sim.get_model()\n", + " self.build_modelgrid(ml)\n", + " self.initialize_plot()\n", + "\n", + " if callback_step == Callbacks.timestep_start:\n", + " ml = sim.get_model()\n", + " if ml.kper == 0:\n", + " self.kperold = ml.kper\n", + " head = ml.chd.stress_period_data.dataframe[\"head\"].values\n", + " self.head = head\n", + " else:\n", + " df = ml.chd.stress_period_data.dataframe\n", + " if self.kperold != ml.kper:\n", + " self.kperold = ml.kper\n", + " self.head = self.head[::-1]\n", + "\n", + " df[\"head\"] = self.head\n", + " ml.chd.stress_period_data.dataframe = df\n", + "\n", + " if callback_step == Callbacks.timestep_end:\n", + " ml = sim.get_model()\n", + " self.update_plot(ml)\n" + ] + }, + { + "cell_type": "markdown", + "id": "ef5cf1d9", + "metadata": {}, + "source": [ + "Run the model using the and supply the `StructuredHeadMonitor`'s `callback` function" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "f2902aff", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Solving: Stress Period 12; Timestep 31\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "NORMAL TERMINATION OF SIMULATION\n" + ] + } + ], + "source": [ + "hdmon = StructuredHeadMonitor(layer=0, vmin=70, vmax=95)\n", + "dll = \"libmf6\"\n", + "sim_ws = Path(\"../data/dis_model\")\n", + "run_simulation(dll, sim_ws, hdmon.callback, verbose=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6ba6ce60", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.9.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/notebooks/MODFLOW-API extensions objects.ipynb b/examples/notebooks/MODFLOW-API extensions objects.ipynb new file mode 100644 index 0000000..d6637e1 --- /dev/null +++ b/examples/notebooks/MODFLOW-API extensions objects.ipynb @@ -0,0 +1,2047 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "5acdb8ec", + "metadata": {}, + "source": [ + "# Interacting with MODFLOW-API Interface objects\n", + "\n", + "The purpose of this notebook is to show the MODFLOW-API interface objects and introduce the user to the data types and how to interact with the objects. \n", + "\n", + "**Note**: This notebook shows how to run a model using the modflow-api at the end of the notebook. However, the majority of the notebook is an illustration of how to access and work with the data types that are returned to a user defined callback function. " + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "4b0e6a93", + "metadata": {}, + "outputs": [], + "source": [ + "import modflowapi\n", + "from modflowapi.extensions import ApiSimulation\n", + "from pathlib import Path\n", + "import platform" + ] + }, + { + "cell_type": "markdown", + "id": "9e654316", + "metadata": {}, + "source": [ + "Define the paths to the model and the Modflow shared library" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "66c0f32c", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "sim_ws = Path(\"../data/dis_model\")\n", + "dll = \"./libmf6\"\n", + "if platform.system().lower() == \"windows\":\n", + " ext = \".dll\"\n", + "elif platform.system().lower() == \"linux\":\n", + " ext = \".so\"\n", + "else:\n", + " ext = \".dylib\"\n", + " \n", + "dll = Path(dll + ext)" + ] + }, + { + "cell_type": "markdown", + "id": "d258b430", + "metadata": {}, + "source": [ + "#### Initializing the API model object\n", + "\n", + "The modflow api allows users to initialize an object that can be used to interact with the model. This processes is done automatically with the `modflowapi.run_model` function call. We're going to initialize an object outside of that call as a demonstration of the interface data objects" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "9c18c3bf", + "metadata": {}, + "outputs": [], + "source": [ + "mf6 = modflowapi.ModflowApi(dll, working_directory=sim_ws)\n", + "mf6.initialize()\n", + "\n", + "# let's advance the model to the first timestep\n", + "dt = mf6.get_time_step()\n", + "mf6.prepare_time_step(dt)" + ] + }, + { + "cell_type": "markdown", + "id": "424925fc", + "metadata": {}, + "source": [ + "## The `ApiSimulation` object \n", + "\n", + "The `ApiSimulation` object is the top level container for the modflowapi interface classes. This container holds methods and other objects that allow the user to access boundary condition pointer data without assembling the specific memory addresses of the modflow data. \n", + "\n", + "Let's take a look at the `ApiSimulation` object" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "b0e83b86", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\n", + " ApiSimulation object that holds a modflow simulation info and loads\n", + " supported models.\n", + "\n", + " Parameters\n", + " ----------\n", + " mf6 : ModflowApi\n", + " initialized ModflowApi object\n", + " models : dict\n", + " dictionary of model_name: modflowapi.extensions.ApiModel objects\n", + " solutions : dict\n", + " dictionary of solution_id: solution_name\n", + " exchanges : dict\n", + " dictoinary of exchange_name: modflowapi.extensions.ApiExchange objects\n", + " tdis : ApiTdisPackage\n", + " time discretization (TDIS) ScalarPackage\n", + " ats : None or ApiAtsPackage\n", + " adaptive time step ScalarPackage object\n", + " Number of models: 1:\n", + "\ttest_model : \n", + "Simulation level packages include:\n", + "\tSLN: SLN Package: SLN_1 \n", + " Accessible variables include:\n", + " akappa \n", + " amomentum \n", + " breduc \n", + " btol \n", + " droptol \n", + " dvclose \n", + " gamma \n", + " ims_dvclose \n", + " iord \n", + " ipc \n", + " iscl \n", + " mxiter \n", + " niterc \n", + " north \n", + " numtrack \n", + " rclose \n", + " relax \n", + " res_lim \n", + " theta \n", + "\n", + "\tTDIS: TDIS Package: TDIS \n", + " Accessible variables include:\n", + " delt \n", + " itmuni \n", + " kper \n", + " kstp \n", + " nper \n", + " nstp \n", + " perlen \n", + " pertim \n", + " tsmult \n" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sim = ApiSimulation.load(mf6)\n", + "sim" + ] + }, + { + "cell_type": "markdown", + "id": "65030e7d", + "metadata": {}, + "source": [ + "The simulation object allows the user to access models by name and has a number of handy properties and contains simulation level packages such as `sln`, `tdis`, `ats`, and `exchanges`" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "c6930030", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['test_model']" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mnames = sim.model_names\n", + "mnames" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "327a1c6e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(0, 0)" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "kstp, kper = sim.kstp, sim.kper\n", + "kstp, kper" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "93c4c417", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "31" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "nstp = sim.nstp\n", + "nstp" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "77c77460", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "SLN Package: SLN_1 \n", + " Accessible variables include:\n", + " akappa \n", + " amomentum \n", + " breduc \n", + " btol \n", + " droptol \n", + " dvclose \n", + " gamma \n", + " ims_dvclose \n", + " iord \n", + " ipc \n", + " iscl \n", + " mxiter \n", + " niterc \n", + " north \n", + " numtrack \n", + " rclose \n", + " relax \n", + " res_lim \n", + " theta " + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ims = sim.sln\n", + "ims" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "3805e031", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.1" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ims.dvclose" + ] + }, + { + "cell_type": "markdown", + "id": "236d4a25", + "metadata": {}, + "source": [ + "## The `ApiModel` object\n", + "\n", + "`ApiModel` objects are accessed from the `ApiSimulation` object and are a container for packages. These objects allow the user to view which packages are available and access those packages. \n", + "\n", + "The following cells show the main attributes and functions available on the `ApiModel` object" + ] + }, + { + "cell_type": "markdown", + "id": "7e65a3f3", + "metadata": {}, + "source": [ + "Model objects are accessible through the `get_model` function and as attributes on the sim object" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "232c0660", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "TEST_MODEL, 1 Layer, 10 Row, 10 Column model\n", + "Packages accessible include: \n", + " ArrayPackage objects:\n", + " dis: \n", + " npf: \n", + " sto: \n", + " ic: \n", + " ListPackage objects:\n", + " wel_0: \n", + " drn_0: \n", + " rch_0: \n", + " rcha_0: \n", + " evt_0: \n", + " chd_0: \n", + " AdvancedPackage objects:\n", + " buy: \n", + " vsc: \n", + " gnc: \n", + " hfb: \n", + " csub: \n", + " mvr: " + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model = sim.get_model('test_model')\n", + "model" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "bb9328af", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "TEST_MODEL, 1 Layer, 10 Row, 10 Column model\n", + "Packages accessible include: \n", + " ArrayPackage objects:\n", + " dis: \n", + " npf: \n", + " sto: \n", + " ic: \n", + " ListPackage objects:\n", + " wel_0: \n", + " drn_0: \n", + " rch_0: \n", + " rcha_0: \n", + " evt_0: \n", + " chd_0: \n", + " AdvancedPackage objects:\n", + " buy: \n", + " vsc: \n", + " gnc: \n", + " hfb: \n", + " csub: \n", + " mvr: " + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# approach 2\n", + "model = sim.test_model\n", + "model" + ] + }, + { + "cell_type": "markdown", + "id": "0ddc33e1", + "metadata": {}, + "source": [ + "There are also a number of other functions available including the following:" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "43aaed16", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(1, 10, 10)" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "07b0b3e2", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "100" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model.size" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "088578c0", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model.solution_id" + ] + }, + { + "cell_type": "markdown", + "id": "4eafd365", + "metadata": {}, + "source": [ + "A list of all package names that are accesible is also available" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "eee1f0a5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['dis',\n", + " 'npf',\n", + " 'buy',\n", + " 'vsc',\n", + " 'gnc',\n", + " 'hfb',\n", + " 'sto',\n", + " 'csub',\n", + " 'ic',\n", + " 'mvr',\n", + " 'wel_0',\n", + " 'drn_0',\n", + " 'rch_0',\n", + " 'rcha_0',\n", + " 'evt_0',\n", + " 'chd_0']" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model.package_names" + ] + }, + { + "cell_type": "markdown", + "id": "073bb268", + "metadata": {}, + "source": [ + "## The `ApiPackage` object(s)\n", + "\n", + "Each package is contained in `ApiPackage` container. There are three types depending on the input data. We'll access and take a look at each of the types of `ApiPackage` containers." + ] + }, + { + "cell_type": "markdown", + "id": "79ac8066", + "metadata": {}, + "source": [ + "Packages can be accessed from the `Model` object using `get_package()` or by attribute" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "4914c509", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "RCH Package: RCHA_0" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# example 1: get a package using get_package\n", + "rch = model.get_package(\"rcha_0\")\n", + "rch" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "cbc0aadf", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "WEL Package: WEL_0" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# example 2: get a package by package name attribute\n", + "wel = model.wel_0\n", + "wel" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "1a705679", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[RCH Package: RCH_0, RCH Package: RCHA_0]" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# example 3: get all packages based on a package type\n", + "rch_pkgs = model.rch\n", + "rch_pkgs" + ] + }, + { + "cell_type": "markdown", + "id": "8d59405f", + "metadata": {}, + "source": [ + "### `ListPackage` objects\n", + "\n", + "`ListPackage` objects are the primary object type of stress period data. The exception to this rule is the advanced packages which will be discussed later. \n", + "\n", + "`ListPackage` objects allow users to access stress period data as a numpy recarray or as a pandas dataframe." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "fbc7ed8a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "rec.array([((0, 9, 7), 1.00000e-03), ((0, 9, 7), 1.00000e-03),\n", + " ((0, 0, 2), 4.04496e+00), ((0, 0, 3), 4.04496e+00),\n", + " ((0, 0, 4), 4.04496e+00), ((0, 0, 5), 4.04496e+00),\n", + " ((0, 0, 6), 4.04496e+00), ((0, 0, 7), 4.04496e+00),\n", + " ((0, 9, 7), 1.00000e-03), ((0, 9, 7), 1.00000e-03)],\n", + " dtype=[('nodelist', 'O'), ('recharge', '\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
nodelistrecharge
0(0, 9, 7)0.00100
1(0, 9, 7)0.00100
2(0, 0, 2)4.04496
3(0, 0, 3)4.04496
4(0, 0, 4)4.04496
\n", + "" + ], + "text/plain": [ + " nodelist recharge\n", + "0 (0, 9, 7) 0.00100\n", + "1 (0, 9, 7) 0.00100\n", + "2 (0, 0, 2) 4.04496\n", + "3 (0, 0, 3) 4.04496\n", + "4 (0, 0, 4) 4.04496" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = rch.stress_period_data.dataframe\n", + "df.head()" + ] + }, + { + "cell_type": "markdown", + "id": "62faee8b", + "metadata": {}, + "source": [ + "### Updating values for `ListPackage` based data\n", + "\n", + "There are multiple ways to update values for `ListPackage` based data. The `.values` and `.dataframe` attributes can be used, or the object can be directly indexed if the user knows the underlying data. Here are some examples" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "0fecf116", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "rec.array([((0, 9, 7), 1.00000e-01), ((0, 9, 7), 1.00000e-03),\n", + " ((0, 0, 2), 4.04496e+00), ((0, 0, 3), 4.04496e+00),\n", + " ((0, 0, 4), 4.04496e+00)],\n", + " dtype=[('nodelist', 'O'), ('recharge', '\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
nodelistrecharge
0(0, 9, 7)0.10000
1(0, 9, 7)10000.00000
2(0, 0, 2)4.04496
3(0, 0, 3)4.04496
4(0, 0, 4)4.04496
\n", + "" + ], + "text/plain": [ + " nodelist recharge\n", + "0 (0, 9, 7) 0.10000\n", + "1 (0, 9, 7) 10000.00000\n", + "2 (0, 0, 2) 4.04496\n", + "3 (0, 0, 3) 4.04496\n", + "4 (0, 0, 4) 4.04496" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = rch.stress_period_data.dataframe\n", + "df.loc[1, \"recharge\"] = 10000\n", + "rch.stress_period_data.dataframe = df\n", + "\n", + "# show that values have been updated\n", + "df = rch.stress_period_data.dataframe\n", + "df.head()" + ] + }, + { + "cell_type": "markdown", + "id": "fd85083e", + "metadata": {}, + "source": [ + "#### Interfacing directly with the `.stress_period_data` attribute\n", + "\n", + "The `.stress_period_data` attribute returns a container class that interacts with the internal modflow pointers. The data can be adjusted by interacting with `.stress_period_data` in the same fashion as changing data in a numpy recarray. " + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "c1d21b67", + "metadata": {}, + "outputs": [], + "source": [ + "rch.stress_period_data[\"recharge\"] *= 100" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "0a127471", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
nodelistrecharge
0(0, 9, 7)10.000
1(0, 9, 7)1000000.000
2(0, 0, 2)404.496
3(0, 0, 3)404.496
4(0, 0, 4)404.496
\n", + "
" + ], + "text/plain": [ + " nodelist recharge\n", + "0 (0, 9, 7) 10.000\n", + "1 (0, 9, 7) 1000000.000\n", + "2 (0, 0, 2) 404.496\n", + "3 (0, 0, 3) 404.496\n", + "4 (0, 0, 4) 404.496" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = rch.stress_period_data.dataframe\n", + "df.head()" + ] + }, + { + "cell_type": "markdown", + "id": "85f6922c", + "metadata": {}, + "source": [ + "#### Adding or removing a boundary condition\n", + "In list packages the user can add and remove specific boundary conditions. Note: if a user adds a boundary condition, such as another well during a stress period, the total number of wells cannot be greater than the wel package's `maxbound` variable. Here's an example" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "4921081e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "nbound=3 maxbound=10\n" + ] + } + ], + "source": [ + "wel = model.wel\n", + "maxbound = wel.maxbound\n", + "nbound = wel.nbound\n", + "print(f\"{nbound=}\", f\"{maxbound=}\")" + ] + }, + { + "cell_type": "markdown", + "id": "9639edaf", + "metadata": {}, + "source": [ + "For the current stress period there are two active wells `nbound=2`, but there can be up to ten `maxbound=10`." + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "a9d7ba04", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "rec.array([((0, 5, 4), -150., 1., 2.), ((0, 1, 2), -100., 1., 2.),\n", + " ((0, 3, 5), -50., 1., 2.)],\n", + " dtype=[('nodelist', 'O'), ('flux', '\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
nodelistfluxTEST1TEST2
0(0, 5, 4)-150.01.02.0
1(0, 1, 2)-100.01.02.0
2(0, 3, 5)-50.01.02.0
3(0, 1, 5)-20.00.01.0
\n", + "" + ], + "text/plain": [ + " nodelist flux TEST1 TEST2\n", + "0 (0, 5, 4) -150.0 1.0 2.0\n", + "1 (0, 1, 2) -100.0 1.0 2.0\n", + "2 (0, 3, 5) -50.0 1.0 2.0\n", + "3 (0, 1, 5) -20.0 0.0 1.0" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wel.stress_period_data.dataframe" + ] + }, + { + "cell_type": "markdown", + "id": "42b72baa", + "metadata": {}, + "source": [ + "### `ArrayPackage` objects\n", + "\n", + "The `ArrayPackage` class is used as a container for packages such as `DIS`, `NPF`, and `IC` that do not contain any sort of stress period data. These packages are used primarily to define model connectivity, initial conditions, and hydraulic parameters of the basin. " + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "e9939cae", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "NPF Package: NPF \n", + " Accessible variables include:\n", + " angle1 \n", + " angle2 \n", + " angle3 \n", + " icelltype \n", + " k11 \n", + " k22 \n", + " k33 " + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "npf = model.npf\n", + "npf" + ] + }, + { + "cell_type": "markdown", + "id": "f55215ba", + "metadata": {}, + "source": [ + "For an `ArrayPackage` type object, variable names can be viewed by calling the `.variable_names` property" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "df4e7242", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['angle1', 'angle2', 'angle3', 'icelltype', 'k11', 'k22', 'k33']" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "npf.variable_names" + ] + }, + { + "cell_type": "markdown", + "id": "93c2006e", + "metadata": {}, + "source": [ + "### Updating values for `ArrayPackage` objects\n", + "\n", + "Two methods are available for accessing and updating data in `ArrayPackage` objects. `get_array()` and `set_array()` methods can be used to get and set data. Arrays can also be accessed as attributes on the object." + ] + }, + { + "cell_type": "markdown", + "id": "0f408dff", + "metadata": {}, + "source": [ + "Using `get_array()` and `set_array()`" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "0d202974", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[[nan, nan, 1., 1., 1., 1., 1., 1., nan, nan],\n", + " [nan, 1., 1., 1., 1., 1., 1., 1., 1., nan],\n", + " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", + " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", + " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", + " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", + " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", + " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", + " [nan, 1., 1., 1., 1., 1., 1., 1., 1., nan],\n", + " [nan, nan, 1., 1., 1., 1., 1., 1., nan, nan]]])" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "hk = npf.get_array(\"k11\")\n", + "hk" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "17ce597b", + "metadata": {}, + "outputs": [], + "source": [ + "hk[0, 0:5, 0:5] = 50\n", + "npf.set_array(\"k11\", hk)" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "2ed869a9", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[[nan, nan, 50., 50., 50., 1., 1., 1., nan, nan],\n", + " [nan, 50., 50., 50., 50., 1., 1., 1., 1., nan],\n", + " [50., 50., 50., 50., 50., 1., 1., 1., 1., 1.],\n", + " [50., 50., 50., 50., 50., 1., 1., 1., 1., 1.],\n", + " [50., 50., 50., 50., 50., 1., 1., 1., 1., 1.],\n", + " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", + " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", + " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", + " [nan, 1., 1., 1., 1., 1., 1., 1., 1., nan],\n", + " [nan, nan, 1., 1., 1., 1., 1., 1., nan, nan]]])" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# confirm that the data has been updated\n", + "hk = npf.get_array(\"k11\")\n", + "hk" + ] + }, + { + "cell_type": "markdown", + "id": "7bdbdb1e", + "metadata": {}, + "source": [ + "Getting and setting data by attribute" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "2b589b5f", + "metadata": {}, + "outputs": [], + "source": [ + "# needs an update for inplace operations....\n", + "npf.k33[0, 0:5, 0:5] = 5" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "38e79b05", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[[nan, nan, 5., 5., 5., 1., 1., 1., nan, nan],\n", + " [nan, 5., 5., 5., 5., 1., 1., 1., 1., nan],\n", + " [ 5., 5., 5., 5., 5., 1., 1., 1., 1., 1.],\n", + " [ 5., 5., 5., 5., 5., 1., 1., 1., 1., 1.],\n", + " [ 5., 5., 5., 5., 5., 1., 1., 1., 1., 1.],\n", + " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", + " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", + " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", + " [nan, 1., 1., 1., 1., 1., 1., 1., 1., nan],\n", + " [nan, nan, 1., 1., 1., 1., 1., 1., nan, nan]]])" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# confirm that the data has been updated\n", + "npf.k33.values" + ] + }, + { + "cell_type": "markdown", + "id": "f245911d", + "metadata": {}, + "source": [ + "## Accessing \"advanced variables\"\n", + "\n", + "Advanced variables in this context are variables that would not normally need to be accessed by the user, and in many cases changes to these variables would cause the Modflow simulation to do unexpected things. " + ] + }, + { + "cell_type": "markdown", + "id": "ff9a706b", + "metadata": {}, + "source": [ + "For each package object a list of avanced variables can be returned by calling the `advanced_vars` attribute" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "4c943166", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['package_type',\n", + " 'id',\n", + " 'inunit',\n", + " 'iout',\n", + " 'inewton',\n", + " 'iasym',\n", + " 'iprpak',\n", + " 'iprflow',\n", + " 'ipakcb',\n", + " 'ionper',\n", + " 'lastonper',\n", + " 'listlabel',\n", + " 'isadvpak',\n", + " 'ibcnum',\n", + " 'ncolbnd',\n", + " 'iscloc',\n", + " 'inamedbound',\n", + " 'iauxmultcol',\n", + " 'inobspkg',\n", + " 'imover',\n", + " 'ivsc',\n", + " 'npakeq',\n", + " 'ioffset',\n", + " 'auxname',\n", + " 'iflowred',\n", + " 'flowred',\n", + " 'ioutafrcsv',\n", + " 'noupdateauxvar',\n", + " 'bound',\n", + " 'condinput',\n", + " 'hcof',\n", + " 'rhs',\n", + " 'simvals',\n", + " 'simtomvr',\n", + " 'boundname',\n", + " 'boundname_cst']" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wel = model.wel_0\n", + "wel.advanced_vars" + ] + }, + { + "cell_type": "markdown", + "id": "dcd0e792", + "metadata": {}, + "source": [ + "The user can access and change these values, _at their own risk_, using the `.get_advanced_var()` and `.set_advanced_var()` methods. Data is returned to the user in the internal modflowapi structure. " + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "id": "5a8ee821", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([1])" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wel.get_advanced_var(\"ibcnum\")" + ] + }, + { + "cell_type": "markdown", + "id": "b034954d", + "metadata": {}, + "source": [ + "### Advanced Packages\n", + "\n", + "Certain packages only support accessing data through the `.get_advanced_var()` and `.set_advanced_var()` methods. These packages, are sometimes refered to as \"advanced packages\" and include: BUY, CSUB, GNC, HFB, MAW, MVR, SFR, and UZF. " + ] + }, + { + "cell_type": "markdown", + "id": "2e2d960a", + "metadata": {}, + "source": [ + "-------" + ] + }, + { + "cell_type": "markdown", + "id": "853b6390", + "metadata": {}, + "source": [ + "Let's close the existing modflowapi shared library object and look at an example of how this is all used in practice" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "6896d260", + "metadata": {}, + "outputs": [], + "source": [ + "mf6.finalize()" + ] + }, + { + "cell_type": "markdown", + "id": "27d3baa1", + "metadata": {}, + "source": [ + "# Putting it all together and running a modflowapi simulation\n", + "\n", + "To run a simulation using the built in modflowapi runner the user needs to create a function that will receive callbacks at different steps in the simulation run. For the remainder of this notebook, we'll show how to create a callback function and use it with the `modflowapi.run_simulation()` method." + ] + }, + { + "cell_type": "markdown", + "id": "4404b2c2", + "metadata": {}, + "source": [ + "## Create a callback function for adjusting model data\n", + "\n", + "The callback function allows users to wrap function that updates the modflow model at different steps. The `modflowapi.Callbacks` object allows users to find the particular solution step that they are currently in. `modflowapi.Callbacks` includes:\n", + "\n", + " - `Callbacks.initalize`: the initialize callback sends loaded simulation data back to the user to make adjustments before the model begins solving. This callback only occurs once at the beginning of the MODFLOW6 simulation\n", + " - `Callbacks.stress_period_start`: the stress_period_start callback sends simulation data for each solution group to the user to make adjustments to stress packages at the beginning of each stress period.\n", + " - `Callbacks.stress_period_end`: the stress_period_end callback sends simulation data for each solution group to the user at the end of each stress period. This can be useful for writing custom output and coupling models\n", + " - `Callbacks.timestep_start`: the timestep_start callback sends simulation data for each solution group to the user to make adjustments to stress packages at the beginning of each timestep.\n", + " - `Callbacks.timestep_end`: the timestep_end callback sends simulation data for each solution group to the user at the end of each timestep. This can be useful for writing custom output and coupling models\n", + " - `Callbacks.iteration_start`: the iteration_start callback sends simulation data for each solution group to the user to make adjustments to stress packages at the beginning of each outer solution iteration.\n", + " - `Callbacks.iteration_end`: the iteration_end callback sends simulation data for each solution group to the user to make adjustments to stress packages and check values of stress packages at the end of each outer solution iteration.\n", + " - `Callbacks.finalize`: the finalize callback is useful for finalizing models coupled with the modflowapi.\n", + " \n", + "The user can use any or all of these callbacks within their callback function" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "id": "c2783828", + "metadata": {}, + "outputs": [], + "source": [ + "from modflowapi import Callbacks" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "id": "395327da", + "metadata": {}, + "outputs": [], + "source": [ + "def callback_function(sim, callback_step):\n", + " \"\"\"\n", + " A demonstration function that dynamically adjusts recharge\n", + " and pumping in a modflow-6 model through the MODFLOW-API\n", + " \n", + " Parameters\n", + " ----------\n", + " sim : modflowapi.Simulation\n", + " A simulation object for the solution group that is \n", + " currently being solved\n", + " callback_step : enumeration\n", + " modflowapi.Callbacks enumeration object that indicates\n", + " the part of the solution modflow is currently in.\n", + " \"\"\"\n", + " ml = sim.test_model\n", + " if callback_step == Callbacks.initialize:\n", + " print(sim.models)\n", + " \n", + " if callback_step == Callbacks.stress_period_start:\n", + " # adjust recharge for stress periods 1 through 7\n", + " if sim.kper <= 6:\n", + " rcha = ml.rcha_0\n", + " spd = rcha.stress_period_data\n", + " print(f\"updating recharge: stress_period={ml.kper}\")\n", + " spd[\"recharge\"] += 0.40 * sim.kper\n", + " \n", + " \n", + " if callback_step == Callbacks.timestep_start:\n", + " print(f\"updating wel flux: stress_period={ml.kper}, timestep={ml.kstp}\")\n", + " ml.wel.stress_period_data[\"flux\"] -= ml.kstp * 1.5\n", + " \n", + " if callback_step == Callbacks.iteration_start:\n", + " # we can implement complex solutions to boundary conditions here!\n", + " pass\n", + " " + ] + }, + { + "cell_type": "markdown", + "id": "b751eb41", + "metadata": {}, + "source": [ + "The callback function is then passed to `modflowapi.run_simulation`" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "id": "0878e5b6", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[TEST_MODEL, 1 Layer, 10 Row, 10 Column model\n", + "Packages accessible include: \n", + " ArrayPackage objects:\n", + " dis: \n", + " npf: \n", + " sto: \n", + " ic: \n", + " ListPackage objects:\n", + " wel_0: \n", + " drn_0: \n", + " rch_0: \n", + " rcha_0: \n", + " evt_0: \n", + " chd_0: \n", + " AdvancedPackage objects:\n", + " buy: \n", + " vsc: \n", + " gnc: \n", + " hfb: \n", + " csub: \n", + " mvr: \n", + "]\n", + "updating recharge: stress_period=0\n", + "updating wel flux: stress_period=0, timestep=0\n", + "updating wel flux: stress_period=0, timestep=1\n", + "updating wel flux: stress_period=0, timestep=2\n", + "updating wel flux: stress_period=0, timestep=3\n", + "updating wel flux: stress_period=0, timestep=4\n", + "updating wel flux: stress_period=0, timestep=5\n", + "updating wel flux: stress_period=0, timestep=6\n", + "updating wel flux: stress_period=0, timestep=7\n", + "updating wel flux: stress_period=0, timestep=8\n", + "updating wel flux: stress_period=0, timestep=9\n", + "updating wel flux: stress_period=0, timestep=10\n", + "updating wel flux: stress_period=0, timestep=11\n", + "updating wel flux: stress_period=0, timestep=12\n", + "updating wel flux: stress_period=0, timestep=13\n", + "updating wel flux: stress_period=0, timestep=14\n", + "updating wel flux: stress_period=0, timestep=15\n", + "updating wel flux: stress_period=0, timestep=16\n", + "updating wel flux: stress_period=0, timestep=17\n", + "updating wel flux: stress_period=0, timestep=18\n", + "updating wel flux: stress_period=0, timestep=19\n", + "updating wel flux: stress_period=0, timestep=20\n", + "updating wel flux: stress_period=0, timestep=21\n", + "updating wel flux: stress_period=0, timestep=22\n", + "updating wel flux: stress_period=0, timestep=23\n", + "updating wel flux: stress_period=0, timestep=24\n", + "updating wel flux: stress_period=0, timestep=25\n", + "updating wel flux: stress_period=0, timestep=26\n", + "updating wel flux: stress_period=0, timestep=27\n", + "updating wel flux: stress_period=0, timestep=28\n", + "updating wel flux: stress_period=0, timestep=29\n", + "updating wel flux: stress_period=0, timestep=30\n", + "updating recharge: stress_period=1\n", + "updating wel flux: stress_period=1, timestep=0\n", + "updating wel flux: stress_period=1, timestep=1\n", + "updating wel flux: stress_period=1, timestep=2\n", + "updating wel flux: stress_period=1, timestep=3\n", + "updating wel flux: stress_period=1, timestep=4\n", + "updating wel flux: stress_period=1, timestep=5\n", + "updating wel flux: stress_period=1, timestep=6\n", + "updating wel flux: stress_period=1, timestep=7\n", + "updating wel flux: stress_period=1, timestep=8\n", + "updating wel flux: stress_period=1, timestep=9\n", + "updating wel flux: stress_period=1, timestep=10\n", + "updating wel flux: stress_period=1, timestep=11\n", + "updating wel flux: stress_period=1, timestep=12\n", + "updating wel flux: stress_period=1, timestep=13\n", + "updating wel flux: stress_period=1, timestep=14\n", + "updating wel flux: stress_period=1, timestep=15\n", + "updating wel flux: stress_period=1, timestep=16\n", + "updating wel flux: stress_period=1, timestep=17\n", + "updating wel flux: stress_period=1, timestep=18\n", + "updating wel flux: stress_period=1, timestep=19\n", + "updating wel flux: stress_period=1, timestep=20\n", + "updating wel flux: stress_period=1, timestep=21\n", + "updating wel flux: stress_period=1, timestep=22\n", + "updating wel flux: stress_period=1, timestep=23\n", + "updating wel flux: stress_period=1, timestep=24\n", + "updating wel flux: stress_period=1, timestep=25\n", + "updating wel flux: stress_period=1, timestep=26\n", + "updating wel flux: stress_period=1, timestep=27\n", + "updating recharge: stress_period=2\n", + "updating wel flux: stress_period=2, timestep=0\n", + "updating wel flux: stress_period=2, timestep=1\n", + "updating wel flux: stress_period=2, timestep=2\n", + "updating wel flux: stress_period=2, timestep=3\n", + "updating wel flux: stress_period=2, timestep=4\n", + "updating wel flux: stress_period=2, timestep=5\n", + "updating wel flux: stress_period=2, timestep=6\n", + "updating wel flux: stress_period=2, timestep=7\n", + "updating wel flux: stress_period=2, timestep=8\n", + "updating wel flux: stress_period=2, timestep=9\n", + "updating wel flux: stress_period=2, timestep=10\n", + "updating wel flux: stress_period=2, timestep=11\n", + "updating wel flux: stress_period=2, timestep=12\n", + "updating wel flux: stress_period=2, timestep=13\n", + "updating wel flux: stress_period=2, timestep=14\n", + "updating wel flux: stress_period=2, timestep=15\n", + "updating wel flux: stress_period=2, timestep=16\n", + "updating wel flux: stress_period=2, timestep=17\n", + "updating wel flux: stress_period=2, timestep=18\n", + "updating wel flux: stress_period=2, timestep=19\n", + "updating wel flux: stress_period=2, timestep=20\n", + "updating wel flux: stress_period=2, timestep=21\n", + "updating wel flux: stress_period=2, timestep=22\n", + "updating wel flux: stress_period=2, timestep=23\n", + "updating wel flux: stress_period=2, timestep=24\n", + "updating wel flux: stress_period=2, timestep=25\n", + "updating wel flux: stress_period=2, timestep=26\n", + "updating wel flux: stress_period=2, timestep=27\n", + "updating wel flux: stress_period=2, timestep=28\n", + "updating wel flux: stress_period=2, timestep=29\n", + "updating wel flux: stress_period=2, timestep=30\n", + "updating recharge: stress_period=3\n", + "updating wel flux: stress_period=3, timestep=0\n", + "updating wel flux: stress_period=3, timestep=1\n", + "updating wel flux: stress_period=3, timestep=2\n", + "updating wel flux: stress_period=3, timestep=3\n", + "updating wel flux: stress_period=3, timestep=4\n", + "updating wel flux: stress_period=3, timestep=5\n", + "updating wel flux: stress_period=3, timestep=6\n", + "updating wel flux: stress_period=3, timestep=7\n", + "updating wel flux: stress_period=3, timestep=8\n", + "updating wel flux: stress_period=3, timestep=9\n", + "updating wel flux: stress_period=3, timestep=10\n", + "updating wel flux: stress_period=3, timestep=11\n", + "updating wel flux: stress_period=3, timestep=12\n", + "updating wel flux: stress_period=3, timestep=13\n", + "updating wel flux: stress_period=3, timestep=14\n", + "updating wel flux: stress_period=3, timestep=15\n", + "updating wel flux: stress_period=3, timestep=16\n", + "updating wel flux: stress_period=3, timestep=17\n", + "updating wel flux: stress_period=3, timestep=18\n", + "updating wel flux: stress_period=3, timestep=19\n", + "updating wel flux: stress_period=3, timestep=20\n", + "updating wel flux: stress_period=3, timestep=21\n", + "updating wel flux: stress_period=3, timestep=22\n", + "updating wel flux: stress_period=3, timestep=23\n", + "updating wel flux: stress_period=3, timestep=24\n", + "updating wel flux: stress_period=3, timestep=25\n", + "updating wel flux: stress_period=3, timestep=26\n", + "updating wel flux: stress_period=3, timestep=27\n", + "updating wel flux: stress_period=3, timestep=28\n", + "updating wel flux: stress_period=3, timestep=29\n", + "updating recharge: stress_period=4\n", + "updating wel flux: stress_period=4, timestep=0\n", + "updating wel flux: stress_period=4, timestep=1\n", + "updating wel flux: stress_period=4, timestep=2\n", + "updating wel flux: stress_period=4, timestep=3\n", + "updating wel flux: stress_period=4, timestep=4\n", + "updating wel flux: stress_period=4, timestep=5\n", + "updating wel flux: stress_period=4, timestep=6\n", + "updating wel flux: stress_period=4, timestep=7\n", + "updating wel flux: stress_period=4, timestep=8\n", + "updating wel flux: stress_period=4, timestep=9\n", + "updating wel flux: stress_period=4, timestep=10\n", + "updating wel flux: stress_period=4, timestep=11\n", + "updating wel flux: stress_period=4, timestep=12\n", + "updating wel flux: stress_period=4, timestep=13\n", + "updating wel flux: stress_period=4, timestep=14\n", + "updating wel flux: stress_period=4, timestep=15\n", + "updating wel flux: stress_period=4, timestep=16\n", + "updating wel flux: stress_period=4, timestep=17\n", + "updating wel flux: stress_period=4, timestep=18\n", + "updating wel flux: stress_period=4, timestep=19\n", + "updating wel flux: stress_period=4, timestep=20\n", + "updating wel flux: stress_period=4, timestep=21\n", + "updating wel flux: stress_period=4, timestep=22\n", + "updating wel flux: stress_period=4, timestep=23\n", + "updating wel flux: stress_period=4, timestep=24\n", + "updating wel flux: stress_period=4, timestep=25\n", + "updating wel flux: stress_period=4, timestep=26\n", + "updating wel flux: stress_period=4, timestep=27\n", + "updating wel flux: stress_period=4, timestep=28\n", + "updating wel flux: stress_period=4, timestep=29\n", + "updating wel flux: stress_period=4, timestep=30\n", + "updating recharge: stress_period=5\n", + "updating wel flux: stress_period=5, timestep=0\n", + "updating wel flux: stress_period=5, timestep=1\n", + "updating wel flux: stress_period=5, timestep=2\n", + "updating wel flux: stress_period=5, timestep=3\n", + "updating wel flux: stress_period=5, timestep=4\n", + "updating wel flux: stress_period=5, timestep=5\n", + "updating wel flux: stress_period=5, timestep=6\n", + "updating wel flux: stress_period=5, timestep=7\n", + "updating wel flux: stress_period=5, timestep=8\n", + "updating wel flux: stress_period=5, timestep=9\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "updating wel flux: stress_period=5, timestep=10\n", + "updating wel flux: stress_period=5, timestep=11\n", + "updating wel flux: stress_period=5, timestep=12\n", + "updating wel flux: stress_period=5, timestep=13\n", + "updating wel flux: stress_period=5, timestep=14\n", + "updating wel flux: stress_period=5, timestep=15\n", + "updating wel flux: stress_period=5, timestep=16\n", + "updating wel flux: stress_period=5, timestep=17\n", + "updating wel flux: stress_period=5, timestep=18\n", + "updating wel flux: stress_period=5, timestep=19\n", + "updating wel flux: stress_period=5, timestep=20\n", + "updating wel flux: stress_period=5, timestep=21\n", + "updating wel flux: stress_period=5, timestep=22\n", + "updating wel flux: stress_period=5, timestep=23\n", + "updating wel flux: stress_period=5, timestep=24\n", + "updating wel flux: stress_period=5, timestep=25\n", + "updating wel flux: stress_period=5, timestep=26\n", + "updating wel flux: stress_period=5, timestep=27\n", + "updating wel flux: stress_period=5, timestep=28\n", + "updating wel flux: stress_period=5, timestep=29\n", + "updating recharge: stress_period=6\n", + "updating wel flux: stress_period=6, timestep=0\n", + "updating wel flux: stress_period=6, timestep=1\n", + "updating wel flux: stress_period=6, timestep=2\n", + "updating wel flux: stress_period=6, timestep=3\n", + "updating wel flux: stress_period=6, timestep=4\n", + "updating wel flux: stress_period=6, timestep=5\n", + "updating wel flux: stress_period=6, timestep=6\n", + "updating wel flux: stress_period=6, timestep=7\n", + "updating wel flux: stress_period=6, timestep=8\n", + "updating wel flux: stress_period=6, timestep=9\n", + "updating wel flux: stress_period=6, timestep=10\n", + "updating wel flux: stress_period=6, timestep=11\n", + "updating wel flux: stress_period=6, timestep=12\n", + "updating wel flux: stress_period=6, timestep=13\n", + "updating wel flux: stress_period=6, timestep=14\n", + "updating wel flux: stress_period=6, timestep=15\n", + "updating wel flux: stress_period=6, timestep=16\n", + "updating wel flux: stress_period=6, timestep=17\n", + "updating wel flux: stress_period=6, timestep=18\n", + "updating wel flux: stress_period=6, timestep=19\n", + "updating wel flux: stress_period=6, timestep=20\n", + "updating wel flux: stress_period=6, timestep=21\n", + "updating wel flux: stress_period=6, timestep=22\n", + "updating wel flux: stress_period=6, timestep=23\n", + "updating wel flux: stress_period=6, timestep=24\n", + "updating wel flux: stress_period=6, timestep=25\n", + "updating wel flux: stress_period=6, timestep=26\n", + "updating wel flux: stress_period=6, timestep=27\n", + "updating wel flux: stress_period=6, timestep=28\n", + "updating wel flux: stress_period=6, timestep=29\n", + "updating wel flux: stress_period=6, timestep=30\n", + "updating wel flux: stress_period=7, timestep=0\n", + "updating wel flux: stress_period=7, timestep=1\n", + "updating wel flux: stress_period=7, timestep=2\n", + "updating wel flux: stress_period=7, timestep=3\n", + "updating wel flux: stress_period=7, timestep=4\n", + "updating wel flux: stress_period=7, timestep=5\n", + "updating wel flux: stress_period=7, timestep=6\n", + "updating wel flux: stress_period=7, timestep=7\n", + "updating wel flux: stress_period=7, timestep=8\n", + "updating wel flux: stress_period=7, timestep=9\n", + "updating wel flux: stress_period=7, timestep=10\n", + "updating wel flux: stress_period=7, timestep=11\n", + "updating wel flux: stress_period=7, timestep=12\n", + "updating wel flux: stress_period=7, timestep=13\n", + "updating wel flux: stress_period=7, timestep=14\n", + "updating wel flux: stress_period=7, timestep=15\n", + "updating wel flux: stress_period=7, timestep=16\n", + "updating wel flux: stress_period=7, timestep=17\n", + "updating wel flux: stress_period=7, timestep=18\n", + "updating wel flux: stress_period=7, timestep=19\n", + "updating wel flux: stress_period=7, timestep=20\n", + "updating wel flux: stress_period=7, timestep=21\n", + "updating wel flux: stress_period=7, timestep=22\n", + "updating wel flux: stress_period=7, timestep=23\n", + "updating wel flux: stress_period=7, timestep=24\n", + "updating wel flux: stress_period=7, timestep=25\n", + "updating wel flux: stress_period=7, timestep=26\n", + "updating wel flux: stress_period=7, timestep=27\n", + "updating wel flux: stress_period=7, timestep=28\n", + "updating wel flux: stress_period=7, timestep=29\n", + "updating wel flux: stress_period=7, timestep=30\n", + "updating wel flux: stress_period=8, timestep=0\n", + "updating wel flux: stress_period=8, timestep=1\n", + "updating wel flux: stress_period=8, timestep=2\n", + "updating wel flux: stress_period=8, timestep=3\n", + "updating wel flux: stress_period=8, timestep=4\n", + "updating wel flux: stress_period=8, timestep=5\n", + "updating wel flux: stress_period=8, timestep=6\n", + "updating wel flux: stress_period=8, timestep=7\n", + "updating wel flux: stress_period=8, timestep=8\n", + "updating wel flux: stress_period=8, timestep=9\n", + "updating wel flux: stress_period=8, timestep=10\n", + "updating wel flux: stress_period=8, timestep=11\n", + "updating wel flux: stress_period=8, timestep=12\n", + "updating wel flux: stress_period=8, timestep=13\n", + "updating wel flux: stress_period=8, timestep=14\n", + "updating wel flux: stress_period=8, timestep=15\n", + "updating wel flux: stress_period=8, timestep=16\n", + "updating wel flux: stress_period=8, timestep=17\n", + "updating wel flux: stress_period=8, timestep=18\n", + "updating wel flux: stress_period=8, timestep=19\n", + "updating wel flux: stress_period=8, timestep=20\n", + "updating wel flux: stress_period=8, timestep=21\n", + "updating wel flux: stress_period=8, timestep=22\n", + "updating wel flux: stress_period=8, timestep=23\n", + "updating wel flux: stress_period=8, timestep=24\n", + "updating wel flux: stress_period=8, timestep=25\n", + "updating wel flux: stress_period=8, timestep=26\n", + "updating wel flux: stress_period=8, timestep=27\n", + "updating wel flux: stress_period=8, timestep=28\n", + "updating wel flux: stress_period=8, timestep=29\n", + "updating wel flux: stress_period=9, timestep=0\n", + "updating wel flux: stress_period=9, timestep=1\n", + "updating wel flux: stress_period=9, timestep=2\n", + "updating wel flux: stress_period=9, timestep=3\n", + "updating wel flux: stress_period=9, timestep=4\n", + "updating wel flux: stress_period=9, timestep=5\n", + "updating wel flux: stress_period=9, timestep=6\n", + "updating wel flux: stress_period=9, timestep=7\n", + "updating wel flux: stress_period=9, timestep=8\n", + "updating wel flux: stress_period=9, timestep=9\n", + "updating wel flux: stress_period=9, timestep=10\n", + "updating wel flux: stress_period=9, timestep=11\n", + "updating wel flux: stress_period=9, timestep=12\n", + "updating wel flux: stress_period=9, timestep=13\n", + "updating wel flux: stress_period=9, timestep=14\n", + "updating wel flux: stress_period=9, timestep=15\n", + "updating wel flux: stress_period=9, timestep=16\n", + "updating wel flux: stress_period=9, timestep=17\n", + "updating wel flux: stress_period=9, timestep=18\n", + "updating wel flux: stress_period=9, timestep=19\n", + "updating wel flux: stress_period=9, timestep=20\n", + "updating wel flux: stress_period=9, timestep=21\n", + "updating wel flux: stress_period=9, timestep=22\n", + "updating wel flux: stress_period=9, timestep=23\n", + "updating wel flux: stress_period=9, timestep=24\n", + "updating wel flux: stress_period=9, timestep=25\n", + "updating wel flux: stress_period=9, timestep=26\n", + "updating wel flux: stress_period=9, timestep=27\n", + "updating wel flux: stress_period=9, timestep=28\n", + "updating wel flux: stress_period=9, timestep=29\n", + "updating wel flux: stress_period=9, timestep=30\n", + "updating wel flux: stress_period=10, timestep=0\n", + "updating wel flux: stress_period=10, timestep=1\n", + "updating wel flux: stress_period=10, timestep=2\n", + "updating wel flux: stress_period=10, timestep=3\n", + "updating wel flux: stress_period=10, timestep=4\n", + "updating wel flux: stress_period=10, timestep=5\n", + "updating wel flux: stress_period=10, timestep=6\n", + "updating wel flux: stress_period=10, timestep=7\n", + "updating wel flux: stress_period=10, timestep=8\n", + "updating wel flux: stress_period=10, timestep=9\n", + "updating wel flux: stress_period=10, timestep=10\n", + "updating wel flux: stress_period=10, timestep=11\n", + "updating wel flux: stress_period=10, timestep=12\n", + "updating wel flux: stress_period=10, timestep=13\n", + "updating wel flux: stress_period=10, timestep=14\n", + "updating wel flux: stress_period=10, timestep=15\n", + "updating wel flux: stress_period=10, timestep=16\n", + "updating wel flux: stress_period=10, timestep=17\n", + "updating wel flux: stress_period=10, timestep=18\n", + "updating wel flux: stress_period=10, timestep=19\n", + "updating wel flux: stress_period=10, timestep=20\n", + "updating wel flux: stress_period=10, timestep=21\n", + "updating wel flux: stress_period=10, timestep=22\n", + "updating wel flux: stress_period=10, timestep=23\n", + "updating wel flux: stress_period=10, timestep=24\n", + "updating wel flux: stress_period=10, timestep=25\n", + "updating wel flux: stress_period=10, timestep=26\n", + "updating wel flux: stress_period=10, timestep=27\n", + "updating wel flux: stress_period=10, timestep=28\n", + "updating wel flux: stress_period=10, timestep=29\n", + "updating wel flux: stress_period=11, timestep=0\n", + "updating wel flux: stress_period=11, timestep=1\n", + "updating wel flux: stress_period=11, timestep=2\n", + "updating wel flux: stress_period=11, timestep=3\n", + "updating wel flux: stress_period=11, timestep=4\n", + "updating wel flux: stress_period=11, timestep=5\n", + "updating wel flux: stress_period=11, timestep=6\n", + "updating wel flux: stress_period=11, timestep=7\n", + "updating wel flux: stress_period=11, timestep=8\n", + "updating wel flux: stress_period=11, timestep=9\n", + "updating wel flux: stress_period=11, timestep=10\n", + "updating wel flux: stress_period=11, timestep=11\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "updating wel flux: stress_period=11, timestep=12\n", + "updating wel flux: stress_period=11, timestep=13\n", + "updating wel flux: stress_period=11, timestep=14\n", + "updating wel flux: stress_period=11, timestep=15\n", + "updating wel flux: stress_period=11, timestep=16\n", + "updating wel flux: stress_period=11, timestep=17\n", + "updating wel flux: stress_period=11, timestep=18\n", + "updating wel flux: stress_period=11, timestep=19\n", + "updating wel flux: stress_period=11, timestep=20\n", + "updating wel flux: stress_period=11, timestep=21\n", + "updating wel flux: stress_period=11, timestep=22\n", + "updating wel flux: stress_period=11, timestep=23\n", + "updating wel flux: stress_period=11, timestep=24\n", + "updating wel flux: stress_period=11, timestep=25\n", + "updating wel flux: stress_period=11, timestep=26\n", + "updating wel flux: stress_period=11, timestep=27\n", + "updating wel flux: stress_period=11, timestep=28\n", + "updating wel flux: stress_period=11, timestep=29\n", + "updating wel flux: stress_period=11, timestep=30\n", + "NORMAL TERMINATION OF SIMULATION\n" + ] + } + ], + "source": [ + "modflowapi.run_simulation(dll, sim_ws, callback_function, verbose=False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bc1e31af", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.9.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/notebooks/Quickstart.ipynb b/examples/notebooks/Quickstart.ipynb new file mode 100644 index 0000000..82524f8 --- /dev/null +++ b/examples/notebooks/Quickstart.ipynb @@ -0,0 +1,572 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "ef27bcb9", + "metadata": {}, + "source": [ + "# MODFLOW API Quickstart\n", + "\n", + "This notebook presents a quickstart guide to working with the modflowapi package through the extension modules. This quickstart guide serves as a roadmap for user development of custom callback functions. For a detailed explanation of the `modflowapi.extensions` objects that are accessible through a callback function, see the notebook `MODFLOW-API extensions objects.ipynb` " + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "334a5509", + "metadata": {}, + "outputs": [], + "source": [ + "import modflowapi\n", + "from modflowapi import Callbacks\n", + "import numpy as np\n", + "from pathlib import Path" + ] + }, + { + "cell_type": "markdown", + "id": "309a015d", + "metadata": {}, + "source": [ + "Define paths to the modflow6 api shared library" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "31936d06", + "metadata": {}, + "outputs": [], + "source": [ + "sim_ws = Path(\"../data/dis_model\")\n", + "\n", + "dll = Path(\"./libmf6\")" + ] + }, + { + "cell_type": "markdown", + "id": "308ba215", + "metadata": {}, + "source": [ + "### Create a callback function for adjusting model data\n", + "\n", + "The callback function allows users to wrap function that updates the modflow model at different steps. The `modflowapi.Callbacks` object allows users to find the particular solution step that they are currently in. `modflowapi.Callbacks` includes:\n", + "\n", + " - `Callbacks.initalize`: the initialize callback sends loaded simulation data back to the user to make adjustments before the model begins solving. This callback only occurs once at the beginning of the MODFLOW6 simulation\n", + " - `Callbacks.stress_period_start`: the stress_period_start callback sends simulation data for each solution group to the user to make adjustments to stress packages at the beginning of each stress period.\n", + " - `Callbacks.stress_period_end`: the stress_period_end callback sends simulation data for each solution group to the user at the end of each stress period. This can be useful for writing custom output and coupling models\n", + " - `Callbacks.timestep_start`: the timestep_start callback sends simulation data for each solution group to the user to make adjustments to stress packages at the beginning of each timestep.\n", + " - `Callbacks.timestep_end`: the timestep_end callback sends simulation data for each solution group to the user at the end of each timestep. This can be useful for writing custom output and coupling models\n", + " - `Callbacks.iteration_start`: the iteration_start callback sends simulation data for each solution group to the user to make adjustments to stress packages at the beginning of each outer solution iteration.\n", + " - `Callbacks.iteration_end`: the iteration_end callback sends simulation data for each solution group to the user to make adjustments to stress packages and check values of stress packages at the end of each outer solution iteration.\n", + " \n", + "The user can use any of these callbacks within their callback function." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "f7ed7fca", + "metadata": {}, + "outputs": [], + "source": [ + "def callback_function(sim, callback_step):\n", + " \"\"\"\n", + " A demonstration function that dynamically adjusts recharge\n", + " and pumping in a modflow-6 model through the MODFLOW-API\n", + " \n", + " Parameters\n", + " ----------\n", + " sim : modflowapi.ApiSimulation\n", + " A simulation object for the solution group that is \n", + " currently being solved\n", + " step : enumeration\n", + " modflowapi.Callbacks enumeration object that indicates\n", + " the part of the solution modflow is currently in.\n", + " \"\"\"\n", + " ml = sim.test_model\n", + " if callback_step == Callbacks.initialize:\n", + " print(sim.models)\n", + " \n", + " if callback_step == Callbacks.stress_period_start:\n", + " # adjust recharge for stress periods 7 through 12\n", + " if sim.kper <= 6:\n", + " rcha = ml.rcha_0\n", + " spd = rcha.stress_period_data\n", + " print(f\"updating recharge: stress_period={ml.kper}\")\n", + " spd[\"recharge\"] += 0.40 * sim.kper\n", + " \n", + " \n", + " if callback_step == Callbacks.timestep_start:\n", + " print(f\"updating wel flux: stress_period={ml.kper}, timestep={ml.kstp}\")\n", + " ml.wel.stress_period_data[\"flux\"] -= ml.kstp * 1.5\n", + " \n", + " if step == Callbacks.iteration_start:\n", + " # we can implement complex solutions to boundary conditions here!\n", + " pass\n", + " " + ] + }, + { + "cell_type": "markdown", + "id": "b3f1d912", + "metadata": {}, + "source": [ + "The callback function is then passed to `modflowapi.run_simulation`" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "8741915e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[TEST_MODEL, 1 Layer, 10 Row, 10 Column model\n", + "Packages accessible include: \n", + " ArrayPackage objects:\n", + " dis: \n", + " npf: \n", + " sto: \n", + " ic: \n", + " ListPackage objects:\n", + " wel_0: \n", + " drn_0: \n", + " ghb_0: \n", + " rch_0: \n", + " rcha_0: \n", + " evt_0: \n", + " chd_0: \n", + " AdvancedPackage objects:\n", + " buy: \n", + " gnc: \n", + " hfb: \n", + " csub: \n", + " mvr: \n", + "]\n", + "updating recharge: stress_period=0\n", + "updating wel flux: stress_period=0, timestep=0\n", + "updating wel flux: stress_period=0, timestep=1\n", + "updating wel flux: stress_period=0, timestep=2\n", + "updating wel flux: stress_period=0, timestep=3\n", + "updating wel flux: stress_period=0, timestep=4\n", + "updating wel flux: stress_period=0, timestep=5\n", + "updating wel flux: stress_period=0, timestep=6\n", + "updating wel flux: stress_period=0, timestep=7\n", + "updating wel flux: stress_period=0, timestep=8\n", + "updating wel flux: stress_period=0, timestep=9\n", + "updating wel flux: stress_period=0, timestep=10\n", + "updating wel flux: stress_period=0, timestep=11\n", + "updating wel flux: stress_period=0, timestep=12\n", + "updating wel flux: stress_period=0, timestep=13\n", + "updating wel flux: stress_period=0, timestep=14\n", + "updating wel flux: stress_period=0, timestep=15\n", + "updating wel flux: stress_period=0, timestep=16\n", + "updating wel flux: stress_period=0, timestep=17\n", + "updating wel flux: stress_period=0, timestep=18\n", + "updating wel flux: stress_period=0, timestep=19\n", + "updating wel flux: stress_period=0, timestep=20\n", + "updating wel flux: stress_period=0, timestep=21\n", + "updating wel flux: stress_period=0, timestep=22\n", + "updating wel flux: stress_period=0, timestep=23\n", + "updating wel flux: stress_period=0, timestep=24\n", + "updating wel flux: stress_period=0, timestep=25\n", + "updating wel flux: stress_period=0, timestep=26\n", + "updating wel flux: stress_period=0, timestep=27\n", + "updating wel flux: stress_period=0, timestep=28\n", + "updating wel flux: stress_period=0, timestep=29\n", + "updating wel flux: stress_period=0, timestep=30\n", + "updating recharge: stress_period=1\n", + "updating wel flux: stress_period=1, timestep=0\n", + "updating wel flux: stress_period=1, timestep=1\n", + "updating wel flux: stress_period=1, timestep=2\n", + "updating wel flux: stress_period=1, timestep=3\n", + "updating wel flux: stress_period=1, timestep=4\n", + "updating wel flux: stress_period=1, timestep=5\n", + "updating wel flux: stress_period=1, timestep=6\n", + "updating wel flux: stress_period=1, timestep=7\n", + "updating wel flux: stress_period=1, timestep=8\n", + "updating wel flux: stress_period=1, timestep=9\n", + "updating wel flux: stress_period=1, timestep=10\n", + "updating wel flux: stress_period=1, timestep=11\n", + "updating wel flux: stress_period=1, timestep=12\n", + "updating wel flux: stress_period=1, timestep=13\n", + "updating wel flux: stress_period=1, timestep=14\n", + "updating wel flux: stress_period=1, timestep=15\n", + "updating wel flux: stress_period=1, timestep=16\n", + "updating wel flux: stress_period=1, timestep=17\n", + "updating wel flux: stress_period=1, timestep=18\n", + "updating wel flux: stress_period=1, timestep=19\n", + "updating wel flux: stress_period=1, timestep=20\n", + "updating wel flux: stress_period=1, timestep=21\n", + "updating wel flux: stress_period=1, timestep=22\n", + "updating wel flux: stress_period=1, timestep=23\n", + "updating wel flux: stress_period=1, timestep=24\n", + "updating wel flux: stress_period=1, timestep=25\n", + "updating wel flux: stress_period=1, timestep=26\n", + "updating wel flux: stress_period=1, timestep=27\n", + "updating recharge: stress_period=2\n", + "updating wel flux: stress_period=2, timestep=0\n", + "updating wel flux: stress_period=2, timestep=1\n", + "updating wel flux: stress_period=2, timestep=2\n", + "updating wel flux: stress_period=2, timestep=3\n", + "updating wel flux: stress_period=2, timestep=4\n", + "updating wel flux: stress_period=2, timestep=5\n", + "updating wel flux: stress_period=2, timestep=6\n", + "updating wel flux: stress_period=2, timestep=7\n", + "updating wel flux: stress_period=2, timestep=8\n", + "updating wel flux: stress_period=2, timestep=9\n", + "updating wel flux: stress_period=2, timestep=10\n", + "updating wel flux: stress_period=2, timestep=11\n", + "updating wel flux: stress_period=2, timestep=12\n", + "updating wel flux: stress_period=2, timestep=13\n", + "updating wel flux: stress_period=2, timestep=14\n", + "updating wel flux: stress_period=2, timestep=15\n", + "updating wel flux: stress_period=2, timestep=16\n", + "updating wel flux: stress_period=2, timestep=17\n", + "updating wel flux: stress_period=2, timestep=18\n", + "updating wel flux: stress_period=2, timestep=19\n", + "updating wel flux: stress_period=2, timestep=20\n", + "updating wel flux: stress_period=2, timestep=21\n", + "updating wel flux: stress_period=2, timestep=22\n", + "updating wel flux: stress_period=2, timestep=23\n", + "updating wel flux: stress_period=2, timestep=24\n", + "updating wel flux: stress_period=2, timestep=25\n", + "updating wel flux: stress_period=2, timestep=26\n", + "updating wel flux: stress_period=2, timestep=27\n", + "updating wel flux: stress_period=2, timestep=28\n", + "updating wel flux: stress_period=2, timestep=29\n", + "updating wel flux: stress_period=2, timestep=30\n", + "updating recharge: stress_period=3\n", + "updating wel flux: stress_period=3, timestep=0\n", + "updating wel flux: stress_period=3, timestep=1\n", + "updating wel flux: stress_period=3, timestep=2\n", + "updating wel flux: stress_period=3, timestep=3\n", + "updating wel flux: stress_period=3, timestep=4\n", + "updating wel flux: stress_period=3, timestep=5\n", + "updating wel flux: stress_period=3, timestep=6\n", + "updating wel flux: stress_period=3, timestep=7\n", + "updating wel flux: stress_period=3, timestep=8\n", + "updating wel flux: stress_period=3, timestep=9\n", + "updating wel flux: stress_period=3, timestep=10\n", + "updating wel flux: stress_period=3, timestep=11\n", + "updating wel flux: stress_period=3, timestep=12\n", + "updating wel flux: stress_period=3, timestep=13\n", + "updating wel flux: stress_period=3, timestep=14\n", + "updating wel flux: stress_period=3, timestep=15\n", + "updating wel flux: stress_period=3, timestep=16\n", + "updating wel flux: stress_period=3, timestep=17\n", + "updating wel flux: stress_period=3, timestep=18\n", + "updating wel flux: stress_period=3, timestep=19\n", + "updating wel flux: stress_period=3, timestep=20\n", + "updating wel flux: stress_period=3, timestep=21\n", + "updating wel flux: stress_period=3, timestep=22\n", + "updating wel flux: stress_period=3, timestep=23\n", + "updating wel flux: stress_period=3, timestep=24\n", + "updating wel flux: stress_period=3, timestep=25\n", + "updating wel flux: stress_period=3, timestep=26\n", + "updating wel flux: stress_period=3, timestep=27\n", + "updating wel flux: stress_period=3, timestep=28\n", + "updating wel flux: stress_period=3, timestep=29\n", + "updating recharge: stress_period=4\n", + "updating wel flux: stress_period=4, timestep=0\n", + "updating wel flux: stress_period=4, timestep=1\n", + "updating wel flux: stress_period=4, timestep=2\n", + "updating wel flux: stress_period=4, timestep=3\n", + "updating wel flux: stress_period=4, timestep=4\n", + "updating wel flux: stress_period=4, timestep=5\n", + "updating wel flux: stress_period=4, timestep=6\n", + "updating wel flux: stress_period=4, timestep=7\n", + "updating wel flux: stress_period=4, timestep=8\n", + "updating wel flux: stress_period=4, timestep=9\n", + "updating wel flux: stress_period=4, timestep=10\n", + "updating wel flux: stress_period=4, timestep=11\n", + "updating wel flux: stress_period=4, timestep=12\n", + "updating wel flux: stress_period=4, timestep=13\n", + "updating wel flux: stress_period=4, timestep=14\n", + "updating wel flux: stress_period=4, timestep=15\n", + "updating wel flux: stress_period=4, timestep=16\n", + "updating wel flux: stress_period=4, timestep=17\n", + "updating wel flux: stress_period=4, timestep=18\n", + "updating wel flux: stress_period=4, timestep=19\n", + "updating wel flux: stress_period=4, timestep=20\n", + "updating wel flux: stress_period=4, timestep=21\n", + "updating wel flux: stress_period=4, timestep=22\n", + "updating wel flux: stress_period=4, timestep=23\n", + "updating wel flux: stress_period=4, timestep=24\n", + "updating wel flux: stress_period=4, timestep=25\n", + "updating wel flux: stress_period=4, timestep=26\n", + "updating wel flux: stress_period=4, timestep=27\n", + "updating wel flux: stress_period=4, timestep=28\n", + "updating wel flux: stress_period=4, timestep=29\n", + "updating wel flux: stress_period=4, timestep=30\n", + "updating recharge: stress_period=5\n", + "updating wel flux: stress_period=5, timestep=0\n", + "updating wel flux: stress_period=5, timestep=1\n", + "updating wel flux: stress_period=5, timestep=2\n", + "updating wel flux: stress_period=5, timestep=3\n", + "updating wel flux: stress_period=5, timestep=4\n", + "updating wel flux: stress_period=5, timestep=5\n", + "updating wel flux: stress_period=5, timestep=6\n", + "updating wel flux: stress_period=5, timestep=7\n", + "updating wel flux: stress_period=5, timestep=8\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "updating wel flux: stress_period=5, timestep=9\n", + "updating wel flux: stress_period=5, timestep=10\n", + "updating wel flux: stress_period=5, timestep=11\n", + "updating wel flux: stress_period=5, timestep=12\n", + "updating wel flux: stress_period=5, timestep=13\n", + "updating wel flux: stress_period=5, timestep=14\n", + "updating wel flux: stress_period=5, timestep=15\n", + "updating wel flux: stress_period=5, timestep=16\n", + "updating wel flux: stress_period=5, timestep=17\n", + "updating wel flux: stress_period=5, timestep=18\n", + "updating wel flux: stress_period=5, timestep=19\n", + "updating wel flux: stress_period=5, timestep=20\n", + "updating wel flux: stress_period=5, timestep=21\n", + "updating wel flux: stress_period=5, timestep=22\n", + "updating wel flux: stress_period=5, timestep=23\n", + "updating wel flux: stress_period=5, timestep=24\n", + "updating wel flux: stress_period=5, timestep=25\n", + "updating wel flux: stress_period=5, timestep=26\n", + "updating wel flux: stress_period=5, timestep=27\n", + "updating wel flux: stress_period=5, timestep=28\n", + "updating wel flux: stress_period=5, timestep=29\n", + "updating recharge: stress_period=6\n", + "updating wel flux: stress_period=6, timestep=0\n", + "updating wel flux: stress_period=6, timestep=1\n", + "updating wel flux: stress_period=6, timestep=2\n", + "updating wel flux: stress_period=6, timestep=3\n", + "updating wel flux: stress_period=6, timestep=4\n", + "updating wel flux: stress_period=6, timestep=5\n", + "updating wel flux: stress_period=6, timestep=6\n", + "updating wel flux: stress_period=6, timestep=7\n", + "updating wel flux: stress_period=6, timestep=8\n", + "updating wel flux: stress_period=6, timestep=9\n", + "updating wel flux: stress_period=6, timestep=10\n", + "updating wel flux: stress_period=6, timestep=11\n", + "updating wel flux: stress_period=6, timestep=12\n", + "updating wel flux: stress_period=6, timestep=13\n", + "updating wel flux: stress_period=6, timestep=14\n", + "updating wel flux: stress_period=6, timestep=15\n", + "updating wel flux: stress_period=6, timestep=16\n", + "updating wel flux: stress_period=6, timestep=17\n", + "updating wel flux: stress_period=6, timestep=18\n", + "updating wel flux: stress_period=6, timestep=19\n", + "updating wel flux: stress_period=6, timestep=20\n", + "updating wel flux: stress_period=6, timestep=21\n", + "updating wel flux: stress_period=6, timestep=22\n", + "updating wel flux: stress_period=6, timestep=23\n", + "updating wel flux: stress_period=6, timestep=24\n", + "updating wel flux: stress_period=6, timestep=25\n", + "updating wel flux: stress_period=6, timestep=26\n", + "updating wel flux: stress_period=6, timestep=27\n", + "updating wel flux: stress_period=6, timestep=28\n", + "updating wel flux: stress_period=6, timestep=29\n", + "updating wel flux: stress_period=6, timestep=30\n", + "updating wel flux: stress_period=7, timestep=0\n", + "updating wel flux: stress_period=7, timestep=1\n", + "updating wel flux: stress_period=7, timestep=2\n", + "updating wel flux: stress_period=7, timestep=3\n", + "updating wel flux: stress_period=7, timestep=4\n", + "updating wel flux: stress_period=7, timestep=5\n", + "updating wel flux: stress_period=7, timestep=6\n", + "updating wel flux: stress_period=7, timestep=7\n", + "updating wel flux: stress_period=7, timestep=8\n", + "updating wel flux: stress_period=7, timestep=9\n", + "updating wel flux: stress_period=7, timestep=10\n", + "updating wel flux: stress_period=7, timestep=11\n", + "updating wel flux: stress_period=7, timestep=12\n", + "updating wel flux: stress_period=7, timestep=13\n", + "updating wel flux: stress_period=7, timestep=14\n", + "updating wel flux: stress_period=7, timestep=15\n", + "updating wel flux: stress_period=7, timestep=16\n", + "updating wel flux: stress_period=7, timestep=17\n", + "updating wel flux: stress_period=7, timestep=18\n", + "updating wel flux: stress_period=7, timestep=19\n", + "updating wel flux: stress_period=7, timestep=20\n", + "updating wel flux: stress_period=7, timestep=21\n", + "updating wel flux: stress_period=7, timestep=22\n", + "updating wel flux: stress_period=7, timestep=23\n", + "updating wel flux: stress_period=7, timestep=24\n", + "updating wel flux: stress_period=7, timestep=25\n", + "updating wel flux: stress_period=7, timestep=26\n", + "updating wel flux: stress_period=7, timestep=27\n", + "updating wel flux: stress_period=7, timestep=28\n", + "updating wel flux: stress_period=7, timestep=29\n", + "updating wel flux: stress_period=7, timestep=30\n", + "updating wel flux: stress_period=8, timestep=0\n", + "updating wel flux: stress_period=8, timestep=1\n", + "updating wel flux: stress_period=8, timestep=2\n", + "updating wel flux: stress_period=8, timestep=3\n", + "updating wel flux: stress_period=8, timestep=4\n", + "updating wel flux: stress_period=8, timestep=5\n", + "updating wel flux: stress_period=8, timestep=6\n", + "updating wel flux: stress_period=8, timestep=7\n", + "updating wel flux: stress_period=8, timestep=8\n", + "updating wel flux: stress_period=8, timestep=9\n", + "updating wel flux: stress_period=8, timestep=10\n", + "updating wel flux: stress_period=8, timestep=11\n", + "updating wel flux: stress_period=8, timestep=12\n", + "updating wel flux: stress_period=8, timestep=13\n", + "updating wel flux: stress_period=8, timestep=14\n", + "updating wel flux: stress_period=8, timestep=15\n", + "updating wel flux: stress_period=8, timestep=16\n", + "updating wel flux: stress_period=8, timestep=17\n", + "updating wel flux: stress_period=8, timestep=18\n", + "updating wel flux: stress_period=8, timestep=19\n", + "updating wel flux: stress_period=8, timestep=20\n", + "updating wel flux: stress_period=8, timestep=21\n", + "updating wel flux: stress_period=8, timestep=22\n", + "updating wel flux: stress_period=8, timestep=23\n", + "updating wel flux: stress_period=8, timestep=24\n", + "updating wel flux: stress_period=8, timestep=25\n", + "updating wel flux: stress_period=8, timestep=26\n", + "updating wel flux: stress_period=8, timestep=27\n", + "updating wel flux: stress_period=8, timestep=28\n", + "updating wel flux: stress_period=8, timestep=29\n", + "updating wel flux: stress_period=9, timestep=0\n", + "updating wel flux: stress_period=9, timestep=1\n", + "updating wel flux: stress_period=9, timestep=2\n", + "updating wel flux: stress_period=9, timestep=3\n", + "updating wel flux: stress_period=9, timestep=4\n", + "updating wel flux: stress_period=9, timestep=5\n", + "updating wel flux: stress_period=9, timestep=6\n", + "updating wel flux: stress_period=9, timestep=7\n", + "updating wel flux: stress_period=9, timestep=8\n", + "updating wel flux: stress_period=9, timestep=9\n", + "updating wel flux: stress_period=9, timestep=10\n", + "updating wel flux: stress_period=9, timestep=11\n", + "updating wel flux: stress_period=9, timestep=12\n", + "updating wel flux: stress_period=9, timestep=13\n", + "updating wel flux: stress_period=9, timestep=14\n", + "updating wel flux: stress_period=9, timestep=15\n", + "updating wel flux: stress_period=9, timestep=16\n", + "updating wel flux: stress_period=9, timestep=17\n", + "updating wel flux: stress_period=9, timestep=18\n", + "updating wel flux: stress_period=9, timestep=19\n", + "updating wel flux: stress_period=9, timestep=20\n", + "updating wel flux: stress_period=9, timestep=21\n", + "updating wel flux: stress_period=9, timestep=22\n", + "updating wel flux: stress_period=9, timestep=23\n", + "updating wel flux: stress_period=9, timestep=24\n", + "updating wel flux: stress_period=9, timestep=25\n", + "updating wel flux: stress_period=9, timestep=26\n", + "updating wel flux: stress_period=9, timestep=27\n", + "updating wel flux: stress_period=9, timestep=28\n", + "updating wel flux: stress_period=9, timestep=29\n", + "updating wel flux: stress_period=9, timestep=30\n", + "updating wel flux: stress_period=10, timestep=0\n", + "updating wel flux: stress_period=10, timestep=1\n", + "updating wel flux: stress_period=10, timestep=2\n", + "updating wel flux: stress_period=10, timestep=3\n", + "updating wel flux: stress_period=10, timestep=4\n", + "updating wel flux: stress_period=10, timestep=5\n", + "updating wel flux: stress_period=10, timestep=6\n", + "updating wel flux: stress_period=10, timestep=7\n", + "updating wel flux: stress_period=10, timestep=8\n", + "updating wel flux: stress_period=10, timestep=9\n", + "updating wel flux: stress_period=10, timestep=10\n", + "updating wel flux: stress_period=10, timestep=11\n", + "updating wel flux: stress_period=10, timestep=12\n", + "updating wel flux: stress_period=10, timestep=13\n", + "updating wel flux: stress_period=10, timestep=14\n", + "updating wel flux: stress_period=10, timestep=15\n", + "updating wel flux: stress_period=10, timestep=16\n", + "updating wel flux: stress_period=10, timestep=17\n", + "updating wel flux: stress_period=10, timestep=18\n", + "updating wel flux: stress_period=10, timestep=19\n", + "updating wel flux: stress_period=10, timestep=20\n", + "updating wel flux: stress_period=10, timestep=21\n", + "updating wel flux: stress_period=10, timestep=22\n", + "updating wel flux: stress_period=10, timestep=23\n", + "updating wel flux: stress_period=10, timestep=24\n", + "updating wel flux: stress_period=10, timestep=25\n", + "updating wel flux: stress_period=10, timestep=26\n", + "updating wel flux: stress_period=10, timestep=27\n", + "updating wel flux: stress_period=10, timestep=28\n", + "updating wel flux: stress_period=10, timestep=29\n", + "updating wel flux: stress_period=11, timestep=0\n", + "updating wel flux: stress_period=11, timestep=1\n", + "updating wel flux: stress_period=11, timestep=2\n", + "updating wel flux: stress_period=11, timestep=3\n", + "updating wel flux: stress_period=11, timestep=4\n", + "updating wel flux: stress_period=11, timestep=5\n", + "updating wel flux: stress_period=11, timestep=6\n", + "updating wel flux: stress_period=11, timestep=7\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "updating wel flux: stress_period=11, timestep=8\n", + "updating wel flux: stress_period=11, timestep=9\n", + "updating wel flux: stress_period=11, timestep=10\n", + "updating wel flux: stress_period=11, timestep=11\n", + "updating wel flux: stress_period=11, timestep=12\n", + "updating wel flux: stress_period=11, timestep=13\n", + "updating wel flux: stress_period=11, timestep=14\n", + "updating wel flux: stress_period=11, timestep=15\n", + "updating wel flux: stress_period=11, timestep=16\n", + "updating wel flux: stress_period=11, timestep=17\n", + "updating wel flux: stress_period=11, timestep=18\n", + "updating wel flux: stress_period=11, timestep=19\n", + "updating wel flux: stress_period=11, timestep=20\n", + "updating wel flux: stress_period=11, timestep=21\n", + "updating wel flux: stress_period=11, timestep=22\n", + "updating wel flux: stress_period=11, timestep=23\n", + "updating wel flux: stress_period=11, timestep=24\n", + "updating wel flux: stress_period=11, timestep=25\n", + "updating wel flux: stress_period=11, timestep=26\n", + "updating wel flux: stress_period=11, timestep=27\n", + "updating wel flux: stress_period=11, timestep=28\n", + "updating wel flux: stress_period=11, timestep=29\n", + "updating wel flux: stress_period=11, timestep=30\n", + "SUCCESSFUL TERMINATION OF THE SIMULATION\n" + ] + } + ], + "source": [ + "modflowapi.run_simulation(dll, sim_ws, callback_function, verbose=False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6a174a0a", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.9.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/modflowapi/__init__.py b/modflowapi/__init__.py index 5a0cdff..dccdd54 100644 --- a/modflowapi/__init__.py +++ b/modflowapi/__init__.py @@ -1,4 +1,6 @@ # imports +from .version import __version__ from modflowapi.modflowapi import ModflowApi -__version__ = "0.0.1" +from . import extensions +from .extensions.runner import Callbacks, run_simulation diff --git a/modflowapi/extensions/__init__.py b/modflowapi/extensions/__init__.py new file mode 100644 index 0000000..347b259 --- /dev/null +++ b/modflowapi/extensions/__init__.py @@ -0,0 +1,3 @@ +from .apisimulation import ApiSimulation +from .apimodel import ApiModel +from .apiexchange import ApiExchange diff --git a/modflowapi/extensions/apiexchange.py b/modflowapi/extensions/apiexchange.py new file mode 100644 index 0000000..226b3b1 --- /dev/null +++ b/modflowapi/extensions/apiexchange.py @@ -0,0 +1,20 @@ +from .pakbase import ListPackage +from .apimodel import ApiMbase + + +class ApiExchange(ApiMbase): + """ + ApiExchange class for GWF-GWF packages and container to access the + simulation level GWF-GWF, MVR, and GNC packages + + Parameters + ---------- + mf6 : ModflowApi + initialized ModflowApi object + name : str + modflow exchange name. ex. "GWF-GWF_1" + """ + + def __init__(self, mf6, name): + pkg_types = {"gwf-gwf": ListPackage, "gwt-gwt": ListPackage} + super().__init__(mf6, name, pkg_types) diff --git a/modflowapi/extensions/apimodel.py b/modflowapi/extensions/apimodel.py new file mode 100644 index 0000000..a606641 --- /dev/null +++ b/modflowapi/extensions/apimodel.py @@ -0,0 +1,383 @@ +from .pakbase import ( + AdvancedPackage, + ArrayPackage, + ListPackage, + package_factory, +) +import numpy as np + + +gridshape = { + "dis": ["nlay", "nrow", "ncol"], + "disu": [ + "nlay", + "ncpl", + ], +} + + +class ApiMbase: + """ + Base object for the Models and Exchanges + + Parameters + ---------- + mf6 : ModflowApi + initialized ModflowApi object + name : str + modflow model name. ex. "GWF_1", "GWF-GWF_1" + pkg_types : dict + dictionary of package types and ApiPackage class types + """ + + def __init__(self, mf6, name, pkg_types): + self.mf6 = mf6 + self.name = name + self._pkg_names = None + self._pak_type = None + self.pkg_types = pkg_types + self.package_dict = {} + self._set_package_names() + self._create_package_list() + + @property + def package_list(self): + """ + Returns a list of package objects for the model + """ + return [package for _, package in self.package_dict.items()] + + @property + def package_names(self): + """ + Returns a list of package names for the model + """ + return list(self.package_dict.keys()) + + @property + def package_types(self): + return list(set([package.pkg_type for package in self.package_list])) + + def _set_package_names(self): + """ + Method to get/set all package names within the model + """ + pak_types = {"dis": "DIS"} + for addr in self.mf6.get_input_var_names(): + tmp = addr.split("/") + if addr.endswith("PACKAGE_TYPE") and tmp[0] == self.name: + pak_types[tmp[1]] = self.mf6.get_value(addr)[0] + elif tmp[0] == self.name and len(tmp) == 2: + if tmp[0].startswith("GWF-GWF"): + pak_types[tmp[0]] = "GWF-GWF" + pak_types.pop("dis", None) + elif tmp[0].startswith("GWT-GWT"): + pak_types[tmp[0]] = "GWT-GWT" + pak_types.pop("dis", None) + + self._pak_type = list(pak_types.values()) + self._pkg_names = list(pak_types.keys()) + + def _create_package_list(self): + """ + Method to load packages and set up the package dict/list variable + """ + for ix, pkg_name in enumerate(self._pkg_names): + pkg_type = self._pak_type[ix].lower() + if pkg_type in self.pkg_types: + basepackage = self.pkg_types[pkg_type] + else: + basepackage = AdvancedPackage + + package = package_factory(pkg_type, basepackage) + adj_pkg_name = "".join(pkg_type.split("-")) + + if adj_pkg_name.lower() in ("gwfgwf", "gwtgwt"): + adj_pkg_name = "" + else: + adj_pkg_name = pkg_name + + package = package(basepackage, self, pkg_type, adj_pkg_name) + self.package_dict[pkg_name.lower()] = package + + def get_package( + self, pkg_name + ) -> ListPackage or ArrayPackage or AdvancedPackage: + """ + Method to get a package + + Parameters + ---------- + pkg_name : str + package name str. Ex. "wel_0" + """ + pkg_name = pkg_name.lower() + if pkg_name in self.package_dict: + return self.package_dict[pkg_name] + + raise KeyError( + f"{pkg_name} is not a valid package name for this model" + ) + + +class ApiModel(ApiMbase): + """ + Container to hold MODFLOW model information and load supported packages + + Parameters + ---------- + mf6 : ModflowApi + initialized ModflowApi object + name : str + modflow model name. ex. "GWF_1" + + """ + + def __init__(self, mf6, name): + _id_addr = mf6.get_var_address("ID", name) + self._id = mf6.get_value(_id_addr)[0] + if self._id < 1: + self._id = 1 + _solnid = mf6.get_var_address("IDSOLN", name) + self._solnid = mf6.get_value(_solnid)[0] + grid_type = mf6.get_grid_type(self._id) + if grid_type == "rectilinear": + self.dis_type = "dis" + self.dis_name = "DIS" + elif grid_type == "unstructured": + self.dis_type = "disu" + self.dis_name = "DIS" + else: + raise AssertionError( + f"Unrecognized discretization type {grid_type}" + ) + + pkg_types = { + "dis": ArrayPackage, + "chd": ListPackage, + "drn": ListPackage, + "evt": ListPackage, + "ghb": ListPackage, + "ic": ArrayPackage, + "npf": ArrayPackage, + "rch": ListPackage, + "sto": ArrayPackage, + "wel": ListPackage, + # gwt + "adv": ArrayPackage, + "cnc": ListPackage, + "ist": ArrayPackage, + "mst": ArrayPackage, + "src": ListPackage, + } + + self.allow_convergence = True + self._shape = None + self._size = None + self._nodetouser = None + self._usertonode = None + self._iteration = 0 + + super().__init__(mf6, name, pkg_types) + + def __repr__(self): + s = f"{self.name}, " + shape = self.shape + if self.dis_type == "dis": + s += ( + f"{shape[0]} Layer, {shape[1]} Row, {shape[2]} " + f"Column model\n" + ) + + elif self.dis_type == "disu": + if len(shape) == 2: + s += f"{shape[0]} Layer, {shape[1]} Nodes per layer model\n" + else: + s += f"{shape[0]} Node model\n" + else: + pass + + s += "Packages accessible include: \n" + for typ, baseobj in [ + ("ArrayPackage", ArrayPackage), + ("ListPackage", ListPackage), + ("AdvancedPackage", AdvancedPackage), + ]: + s += f" {typ} objects:\n" + for name, obj in self.package_dict.items(): + if isinstance(obj, baseobj): + s += f" {name}: {type(obj)}\n" + + return s + + def __getattr__(self, item): + """ + Method for getting packages either by package name or by + package type name + + """ + if item in self.package_dict: + return self.package_dict[item] + else: + pkg_list = [] + for pkg_name, package in self.package_dict.items(): + if item == package.pkg_type: + pkg_list.append(package) + + if len(pkg_list) == 0: + return super().__getattribute__(item) + elif len(pkg_list) == 1: + return pkg_list[0] + else: + return pkg_list + + def __setattr__(self, key, value): + """ + Method for type checking variables + """ + if key == "allow_convergence": + if not isinstance(value, bool): + raise TypeError("allow convergenge must be a boolean value") + + super().__setattr__(key, value) + + @property + def kper(self): + """ + Returns the current stress period + """ + var_addr = self.mf6.get_var_address("KPER", "TDIS") + return self.mf6.get_value(var_addr)[0] - 1 + + @property + def kstp(self): + """ + Returns the current timestep + """ + var_addr = self.mf6.get_var_address("KSTP", "TDIS") + return self.mf6.get_value(var_addr)[0] - 1 + + @property + def nstp(self): + """ + Returns the number of timesteps in the current stress period + """ + var_addr = self.mf6.get_var_address("NSTP", "TDIS") + return self.mf6.get_value(var_addr)[0] + + @property + def nper(self): + """ + Returns the number of stress periods + """ + var_addr = self.mf6.get_var_address("NPER", "TDIS") + return self.mf6.get_value(var_addr)[0] + + @property + def totim(self): + """ + Returns the current model time + """ + var_addr = self.mf6.get_var_address("TOTIM", "TDIS") + return self.mf6.get_value(var_addr)[0] + + @property + def subcomponent_id(self): + """ + Returns the model subcomponent id + """ + return self._id + + @property + def solution_id(self): + """ + Returns the model solution id + """ + return self._solnid + + @property + def shape(self): + """ + Returns a tuple of the model shape + """ + ivn = self.mf6.get_input_var_names() + if self._shape is None: + shape_vars = gridshape[self.dis_type] + shape = [] + for var in shape_vars: + var_addr = self.mf6.get_var_address( + var.upper(), self.name, self.dis_name + ) + if var_addr in ivn: + shape.append(self.mf6.get_value(var_addr)[0]) + if not shape: + var_addr = self.mf6.get_var_address( + "NODES", self.name, self.dis_name + ) + shape.append(self.mf6.get_value(var_addr)[0]) + self._shape = tuple(shape) + return self._shape + + @property + def size(self): + """ + Returns the number of nodes in the model + """ + if self._size is None: + size = 1 + for dim in self.shape: + size *= dim + self._size = size + return self._size + + @property + def nodetouser(self): + """ + Returns the "nodeuser" array + """ + if self._nodetouser is None: + self._set_node_mapping() + return self._nodetouser + + @property + def usertonode(self): + """ + Returns an array that maps user arrays to modflow's internal nodes + """ + if self._usertonode is None: + self._set_node_mapping() + return self._usertonode + + @property + def X(self): + """ + Returns the solution array. Ex. GFW models return heads, GWT + returns a concentration array, etc... + """ + x = self.mf6.get_value(self.mf6.get_var_address("X", self.name)) + array = np.full(self.size, np.nan) + array[self.nodetouser] = x + return array.reshape(self.shape) + + def _set_node_mapping(self): + """ + Sets the node mapping arrays NODEUSER and NODEREDUCED for mapping + user arrays to modflow's internal arrays + """ + node_addr = self.mf6.get_var_address("NODES", self.name, self.dis_name) + nodes = self.mf6.get_value(node_addr) + if nodes[0] == self.size: + nodeuser = np.arange(nodes).astype(int) + nodereduced = np.copy(nodeuser) + else: + nodeuser_addr = self.mf6.get_var_address( + "NODEUSER", self.name, self.dis_name + ) + nodeuser = self.mf6.get_value(nodeuser_addr) - 1 + nodereduced_addr = self.mf6.get_var_address( + "NODEREDUCED", self.name, self.dis_name + ) + nodereduced = self.mf6.get_value(nodereduced_addr) - 1 + + self._nodetouser = nodeuser + self._usertonode = nodereduced diff --git a/modflowapi/extensions/apisimulation.py b/modflowapi/extensions/apisimulation.py new file mode 100644 index 0000000..282e459 --- /dev/null +++ b/modflowapi/extensions/apisimulation.py @@ -0,0 +1,353 @@ +from .apimodel import ApiMbase, ApiModel +from .apiexchange import ApiExchange +from .pakbase import ApiSlnPackage, ListPackage, ScalarPackage, package_factory +import numpy as np + + +class ApiSimulation: + """ + ApiSimulation object that holds a modflow simulation info and loads + supported models. + + Parameters + ---------- + mf6 : ModflowApi + initialized ModflowApi object + models : dict + dictionary of model_name: modflowapi.extensions.ApiModel objects + solutions : dict + dictionary of solution_id: solution_name + exchanges : dict + dictoinary of exchange_name: modflowapi.extensions.ApiExchange objects + tdis : ApiTdisPackage + time discretization (TDIS) ScalarPackage + ats : None or ApiAtsPackage + adaptive time step ScalarPackage object + """ + + def __init__(self, mf6, models, solutions, exchanges, tdis, ats): + self.mf6 = mf6 + self._models = models + self._exchanges = exchanges + self._solutions = solutions + self._iteration = -1 + + self.tdis = tdis + self.ats = ats + self._ats_active = True + if ats is None: + self._ats_active = False + + def __getattr__(self, item): + """ + Dynamic method to get models by model name + """ + if item.lower() in self._models: + return self.get_model(item) + else: + return super().__getattribute__(item) + + def __repr__(self): + s = self.__doc__ + s += f"Number of models: {len(self._models)}:\n" + for name, obj in self._models.items(): + s += f"\t{name} : {type(obj)}\n" + s += f"Simulation level packages include:\n" + s += f"\tSLN: {self.sln}\n" + s += f"\tTDIS: {self.tdis}\n" + if self.ats_active: + s += f"\tATS: {self.ats}\n" + if self._exchanges: + s += f"\tExchanges include:\n" + for name, exchange in self._exchanges.items(): + f"\t\t{name}: {type(exchange)}\n" + + return s + + @property + def ats_active(self): + """ + Returns a boolean to indicate if the ATS package is used in this + simulation. + """ + return self._ats_active + + @property + def ats_period(self): + """ + Returns a boolean to indicate if this is an ATS stress period + """ + # maybe return tuple (bool, dtmin) + if self.ats_active: + recarray = self.ats.stress_period_data.values + idx = np.where(recarray["iperats"] == self.kper + 1)[0] + if len(idx) > 0: + return True, recarray["dtmin"][idx[0]] + + return False, None + + @property + def allow_convergence(self): + """ + Returns a boolean value that specifies if the user will allow the + model to converge. Default is True + """ + for model in self.models: + if not model.allow_convergence: + return False + return True + + @allow_convergence.setter + def allow_convergence(self, value): + """ + Method to set the allow_convergence flag + + Parameters + ---------- + value : bool + if True (default) model converges if solution converges, if False + model will continue solving after solution converges. + """ + for model in self.models: + model.allow_convergence = value + + @property + def subcomponent_count(self): + """ + Returns the number of subcomponents in the simulation + """ + return self.mf6.get_subcomponent_count() + + @property + def solutions(self): + """ + Returns a dictionary of solution_id : (name, ApiSlnPackage) + """ + return self._solutions + + @property + def sln(self): + """ + Returns an ApiSolution object + """ + if len(self._solutions) > 1: + return list(self._solutions.values()) + else: + for sln in self._solutions.values(): + return sln + + @property + def model_names(self): + """ + Returns a list of model names + """ + return list(self._models.keys()) + + @property + def exchange_names(self): + """ + Returns a list of exchange GWF-GWF names + """ + if self._exchanges.keys(): + return list(self._exchanges.keys()) + + @property + def models(self): + """ + Returns a list of ApiModel objects associated with the simulation + """ + return [v for _, v in self._models.items()] + + @property + def iteration(self): + return self._iteration + + @iteration.setter + def iteration(self, value): + if isinstance(value, int): + self._iteration = value + + @property + def kper(self): + """ + Returns the current stress period + """ + return self.tdis.kper - 1 + + @property + def kstp(self): + """ + Returns the current time step + """ + return self.tdis.kstp - 1 + + @property + def nstp(self): + """ + Returns the total number of time steps + """ + return self.tdis.nstp + + @property + def nper(self): + """ + Returns the total number of stress periods + """ + return self.tdis.nper + + @property + def totim(self): + """ + Returns the current model time + """ + return self.tdis.totim + + @property + def delt(self): + """ + Returns the timestep length for the current time step + """ + return self.tdis.delt + + def get_model(self, model_id=None): + """ + Method to get a model from the simulation object by model name or + subcomponent id + + Parameters + ---------- + model_id : str, int + model name (ex. "GWF_1") or subcomponent id (ex. 1) + """ + if model_id is None: + model_id = int( + min([model.subcomponent_id for model in self.models]) + ) + + if isinstance(model_id, int): + for model in self.models: + if model_id == model.subcomponent_id: + return model + raise KeyError(f"No model found with subcomponent id {model_id}") + + elif isinstance(model_id, str): + model_id = model_id.lower() + if model_id in self._models: + return self._models[model_id] + raise KeyError(f"Model name {model_id} is invalid") + + else: + raise TypeError("A string or int must be supplied to get model") + + def get_exchange(self, exchange_name=None): + """ + Get a GWF-GWF "model" and all associated simulation level package + data (ex. GNC, MVR) + + Parameters + ---------- + exchange_name : str + name of the GWF-GWF exchange package + + Returns + ------- + modflowapi.extensions.ApiExchange object + """ + if self.exchange_names is None: + raise AssertionError("No exchanges are present in this simulation") + + if exchange_name is None: + for _, exg in self._exchanges: + return exg + + else: + if exchange_name in self._exchanges: + return self._exchanges[exchange_name] + raise KeyError(f"Exchange name {exchange_name} is invalid") + + @staticmethod + def load(mf6): + """ + Method to load a modflowapi instance into the ApiSimulation extensions + + Parameters + ---------- + mf6 : ModflowApi + initialized ModflowApi object + """ + variables = mf6.get_input_var_names() + model_names = [] + for variable in variables: + t = variable.split("/") + if len(t) == 3: + name = t[0] + id_var_addr = mf6.get_var_address("ID", name) + if name.startswith("SLN"): + continue + if id_var_addr not in variables: + continue + + if name not in model_names: + model_names.append(name) + + models = {} + for name in model_names: + models[name.lower()] = ApiModel(mf6, name) + + solution_names = [] + for variable in variables: + t = variable.split("/") + if len(t) == 2: + name = t[0] + id_var_addr = mf6.get_var_address("ID", name) + if name.lower() in models or name == "TDIS": + continue + if id_var_addr not in variables: + continue + + solution_names.append(t[0]) + + tmpmdl = ApiMbase(mf6, "", {}) + solution_names = list(set(solution_names)) + solution_dict = {} + for name in solution_names: + sid_var_addr = mf6.get_var_address("ID", name) + sid = mf6.get_value(sid_var_addr)[0] + sln = ApiSlnPackage(tmpmdl, name) + solution_dict[sid] = sln + + solutions = solution_dict + + # TDIS package construction + tdis_constructor = package_factory("tdis", ScalarPackage) + tdis = tdis_constructor( + ScalarPackage, tmpmdl, "tdis", "tdis", sim_package=True + ) + + ats = None + # ATS package construction + for variable in variables: + if variable.startswith("ATS"): + ats_constructor = package_factory("ats", ListPackage) + ats = ats_constructor( + ListPackage, tmpmdl, "ats", "ats", sim_package=True + ) + break + + # get the exchanges + exchange_names = [] + for variable in variables: + if variable.startswith("GWF-GWF") or variable.startswith( + "GWT-GWT" + ): + exchange_name = variable.split("/")[0] + if exchange_name not in exchange_names: + exchange_names.append(exchange_name) + + # sim_packages: tdis, gwf-gwf, sln + exchanges = {} + for exchange_name in exchanges: + exchange = ApiExchange(mf6, exchange_name) + exchanges[exchange_name.lower()] = exchange + + return ApiSimulation(mf6, models, solutions, exchanges, tdis, ats) diff --git a/modflowapi/extensions/data.py b/modflowapi/extensions/data.py new file mode 100644 index 0000000..cec3812 --- /dev/null +++ b/modflowapi/extensions/data.py @@ -0,0 +1,723 @@ +import numpy as np +import pandas as pd +import xmipy.errors + + +class ListInput(object): + """ + Data object for storing pointers and working with list based input data + + Parameters + ---------- + parent : ListPackage + modflowapi ListPackage object + var_addrs : list, None + optional list of variable addresses + mf6 : ModflowApi, None + optional ModflowApi object + """ + + def __init__(self, parent, var_addrs=None, mf6=None): + self.parent = parent + if self.parent is not None: + self.var_addrs = self.parent.var_addrs + self.mf6 = self.parent.model.mf6 + else: + if var_addrs is None or mf6 is None: + raise AssertionError( + "var_addrs and mf6 must be supplied if parent is None" + ) + self.var_addrs = var_addrs + self.mf6 = mf6 + + self._ptrs = {} + self._nodevars = ("nodelist", "nexg", "maxats") + self._boundvars = ("bound",) + # self._auxname = [] + self._maxbound = [ + 0, + ] + self._nbound = [ + 0, + ] + self._naux = [ + 0, + ] + self._auxnames = [] + self._dtype = [] + self._reduced_to_var_addr = {} + self._set_stress_period_data() + + def _set_stress_period_data(self): + """ + Method to set stress period data variable pointers to the _ptrs + dictionary + + """ + for var_addr in self.var_addrs: + try: + values = self.mf6.get_value_ptr(var_addr) + except xmipy.errors.InputError: + if self._naux[0] > 0: + values = self.mf6.get_value(var_addr) + else: + continue + reduced = var_addr.split("/")[-1].lower() + if reduced in ("maxbound", "nbound"): + setattr(self, f"_{reduced}", values) + elif reduced in ("nexg", "maxats"): + setattr(self, "_maxbound", values) + setattr(self, "_nbound", values) + elif reduced in ("naux",): + setattr(self, "_naux", values) + elif reduced in ("auxname_cst"): + setattr(self, "_auxnames", list(values)) + else: + self._ptrs[reduced] = values + self._reduced_to_var_addr[reduced] = var_addr + if reduced in self._boundvars: + for name in self.parent._bound_vars: + typ_str = values.dtype.str + dtype = (name, typ_str) + self._dtype.append(dtype) + elif reduced in self._nodevars: + dtype = (reduced, "O") + self._dtype.append(dtype) + elif reduced == "auxvar": + if self._naux == 0: + continue + else: + for ix in range(self._naux[0]): + typ_str = values.dtype.str + dtype = (self._auxnames[ix], typ_str) + self._dtype.append(dtype) + else: + typ_str = values.dtype.str + dtype = (reduced, typ_str) + self._dtype.append(dtype) + + def _ptr_to_recarray(self): + """ + Method to get a recarray of stress period data from modflow pointers + + Returns + ------- + np.recarray + """ + if self._nbound[0] == 0: + return + recarray = np.recarray((self._nbound[0],), self._dtype) + for name, ptr in self._ptrs.items(): + values = np.copy(ptr) + if name in self._boundvars: + for ix, nm in enumerate(self.parent._bound_vars): + recarray[nm][0 : self._nbound[0]] = values[ + 0 : self._nbound[0], ix + ] + elif name == "auxvar": + if self._naux[0] == 0: + continue + else: + for ix in range(self._naux[0]): + nm = self._auxnames[ix] + recarray[nm][0 : self._nbound[0]] = values[ + 0 : self._nbound[0], ix + ] + elif name == "auxname_cst": + pass + + else: + values = values.ravel() + if name in self._nodevars: + values -= 1 + values = self.parent.model.nodetouser[values] + values = list( + zip(*np.unravel_index(values, self.parent.model.shape)) + ) + + recarray[name][0 : self._nbound[0]] = values[ + 0 : self._nbound[0] + ] + + return recarray + + def _recarray_to_ptr(self, recarray): + """ + Method to update stress period information pointers from user supplied + data + + Parameters + ---------- + recarray : np.recarray + numpy recarray of stress period data + + """ + if recarray is None: + self._nbound[0] = 0 + return + + if len(recarray) != self._nbound: + if len(recarray) > self._maxbound[0]: + raise AssertionError( + f"Length of stresses ({len(recarray)},) cannot be larger " + f"than maxbound value ({self._maxbound[0]},)" + ) + self._nbound[0] = len(recarray) + + if len(recarray) == 0: + return + + for name in recarray.dtype.names: + if name in self._nodevars: + multi_index = tuple( + np.array([list(i) for i in recarray[name]]).T + ) + nodes = np.ravel_multi_index( + multi_index, self.parent.model.shape + ) + recarray[name] = self.parent.model.usertonode[nodes] + 1 + + if name in self.parent._bound_vars: + idx = self.parent._bound_vars.index(name) + bname = "bound" + self._ptrs[bname][0 : self._nbound[0], idx] = recarray[name] + elif name in self._auxnames: + idx = self._auxnames.index(name) + self._ptrs["auxvar"][0 : self._nbound[0], idx] = recarray[name] + elif name == "auxname_cst": + pass + else: + self._ptrs[name][0 : self._nbound[0]] = recarray[name].ravel() + + def __getitem__(self, item): + recarray = self._ptr_to_recarray() + return recarray[item] + + def __setitem__(self, key, value): + recarray = self._ptr_to_recarray() + recarray[key] = value + self._recarray_to_ptr(recarray) + + @property + def dtype(self): + """ + Returns the numpy dtypes for the recarray + """ + return self._dtype + + @property + def values(self): + """ + Returns a np.recarray of the current stress_period_data + """ + return self._ptr_to_recarray() + + @values.setter + def values(self, recarray): + """ + Setter method to update the current stress_period_data + """ + self._recarray_to_ptr(recarray) + + @property + def dataframe(self): + recarray = self._ptr_to_recarray() + return pd.DataFrame.from_records(recarray) + + @dataframe.setter + def dataframe(self, dataframe): + recarray = dataframe.to_records(index=False) + self._recarray_to_ptr(recarray) + + +class ArrayPointer: + """ + Data object for storing single pointers and working with array based input data + + Parameters + ---------- + parent : ArrayPackage + ArrayPackage object + var_addr : str + variable pointer location + mf6 : ModflowApi + optional ModflowApi object + """ + + def __init__(self, parent, var_addr, mf6=None): + self._ptr = None + self.parent = parent + self._mapping = None + self.name = None + self.var_addr = var_addr + self._vshape = None + + if self.parent is not None: + self.mf6 = self.parent.model.mf6 + else: + if mf6 is None: + raise AssertionError("mf6 must be supplied if parent is None") + self._set_array() + + def _set_array(self): + ivn = self.mf6.get_input_var_names() + if self.var_addr in ivn: + values = self.mf6.get_value_ptr(self.var_addr) + reduced = self.var_addr.split("/")[-1].lower() + self._vshape = values.shape + self._ptr = values + self.name = reduced + + def __getitem__(self, item): + return self.values[item] + + def __setitem__(self, key, value): + array = self.values + array[key] = value + self.values = array + + @property + def values(self): + """ + Method to get an array from modflow + + Returns + ------- + np.array of modflow data + """ + if not self.parent._sim_package: + value = np.ones((self.parent.model.size,)) * np.nan + if self._ptr.size == self.parent.model.size: + value[:] = self._ptr.ravel() + else: + value[self.parent.model.nodetouser] = self._ptr.ravel() + return value.reshape(self.parent.model.shape) + else: + return np.copy(self._ptr.ravel()) + + @values.setter + def values(self, array): + """ + Method to update the modflow pointer arrays + + Parameters + ---------- + array : np.array + numpy array + + """ + + if not isinstance(array, np.ndarray): + raise TypeError() + if not self.parent._sim_package: + if array.size != self.parent.model.size: + raise ValueError( + f"{self.name} size {array.size} is not equal to " + f"modflow variable size {self.parent.model.size}" + ) + + array = array.ravel() + if self._ptr.size != array.size: + array = array[self.parent.model.nodetouser] + if len(self._vshape) > 1: + array.shape = self._vshape + else: + array = array.ravel() + self._ptr[:] = array + + +class ArrayInput: + """ + Data object for storing pointers and working with array based input data + + Parameters + ---------- + parent : ArrayPackage + modflowapi ArrayPackage object + var_addrs : list, None + optional list of variable addresses + mf6 : ModflowApi, None + optional ModflowApi object + """ + + def __init__(self, parent, var_addrs=None, mf6=None): + self._ptrs = {} + self.parent = parent + # change this to a parent package.mapping + self._mapping = None + + if self.parent is not None: + self.var_addrs = self.parent.var_addrs + self.mf6 = self.parent.model.mf6 + else: + if var_addrs is None or mf6 is None: + raise AssertionError( + "var_addrs and mf6 must be supplied if parent is None" + ) + self.var_addrs = var_addrs + self.mf6 = mf6 + + self._maxbound = [ + 0, + ] + self._nbound = [ + 0, + ] + self._reduced_to_var_addr = {} + self._set_arrays() + + def _set_arrays(self): + """ + Method to modflow variable pointers to the _ptrs dictionary + """ + ivn = self.mf6.get_input_var_names() + for var_addr in self.var_addrs: + if var_addr in ivn: + ptr = ArrayPointer(self.parent, var_addr) + reduced = var_addr.split("/")[-1].lower() + self._ptrs[reduced] = ptr + self._reduced_to_var_addr[reduced] = var_addr + + def __getattr__(self, item): + """ + Dynamic method to get modflow varaibles as an attribute + """ + if item in self._ptrs: + return self._ptrs[item] + else: + return super(ArrayInput).__getattribute__(item) + + def __setattr__(self, item, value): + """ + Dynamic method that allows users to set modflow variables to the + _ptr dict + """ + if item in ( + "parent", + "var_addrs", + "_mapping", + "_ptrs", + "mf6", + "_maxbound", + "_nbound", + "_reduced_to_var_addr", + ): + super().__setattr__(item, value) + + elif item in self._ptrs: + if isinstance(value, ArrayPointer): + self._ptrs[item] = value + else: + raise AttributeError(f"{item} is not a vaild attribute") + + @property + def variable_names(self): + """ + Returns a list of valid array names that can be accessed by the user + """ + return list(sorted(self._ptrs.keys())) + + def get_ptr(self, item): + """ + Method to get the ArrayPointer object + + Parameters + ---------- + item : str + modflow variable name: Ex. "k11" + + Returns + ------- + ArrayPointer object + """ + if item in self._ptrs: + return self._ptrs[item] + + def set_ptr(self, item, ptr): + """ + Method to set an ArrayPointer object + + Parameters + ---------- + item : str + modflow variable name: Ex. "k11" + ptr : ArrayPointer + ArrayPointer object + """ + if item in self._ptrs: + if isinstance(ptr, ArrayPointer): + self._ptrs[item] = ptr + else: + raise TypeError("An ArrayPointer object must be provided") + + else: + raise KeyError(f"{item} is not accessible in this package") + + def get_array(self, item): + """ + Method to get an array from modflow + + Parameters + ---------- + item : str + modflow variable name. Ex. "k11" + + Returns + ------- + np.array of modflow data + """ + if item in self._ptrs: + return self._ptrs[item].values + else: + raise KeyError(f"{item} is not accessible in this package") + + def set_array(self, item, array): + """ + Method to update the modflow pointer arrays + + Parameters + ---------- + item : str + modflow variable name. Ex. "k11" + array : np.array + numpy array + + """ + if item in self._ptrs: + self._ptrs[item].values = array + else: + raise KeyError( + f"{item} is not a valid variable name for this package" + ) + + +class AdvancedInput(object): + """ + Data object for dynamically storing pointers and working with + "advanced" data types + + Parameters + ---------- + parent : ArrayPackage + modflowapi ArrayPackage object + mf6 : ModflowApi, None + optional ModflowApi object + """ + + def __init__(self, parent, mf6=None): + self._ptrs = {} + self.parent = parent + + if self.parent is not None: + self.mf6 = self.parent.model.mf6 + else: + if mf6 is None: + raise AssertionError("mf6 must be supplied if parent is None") + self.mf6 = mf6 + + def get_variable(self, name, model=None, package=None): + """ + method to assemble a variable address and get a variable from the + ModflowApi instance + + Parameters: + ---------- + name : str + variable name + model : str + optional model name, note this is required if parent is None + package : str + optional package name, note this is requried if parent is None + + Returns: + ------- + np.ndarray or scalar float, int, string, or boolean value + depending on data type and length + """ + if name.lower() in self._ptrs: + return self._ptrs[name.lower()] + + if not self.parent._sim_package: + if self.parent is not None: + var_addr = self.mf6.get_var_address( + name.upper(), self.parent.model.name, self.parent.pkg_name + ) + else: + var_addr = self.mf6.get_var_address( + name.upper(), model.upper(), package.upper() + ) + else: + if self.parent is not None: + var_addr = self.mf6.get_var_address( + name.upper(), self.parent.pkg_name + ) + else: + var_addr = self.mf6.get_var_address( + name.upper(), package.upper() + ) + + try: + values = self.mf6.get_value_ptr(var_addr) + except InputError: + values = self.mf6.get_value(var_addr) + + self._ptrs[name.lower()] = values + return values.copy() + + def set_variable(self, name, values, model=None, package=None): + """ + method to assemble a variable address and get a variable from the + ModflowApi instance + + Parameters: + ---------- + name : str + variable name + values : np.ndarray + numpy array of variable values + model : str + optional model name, note this is required if parent is None + package : str + optional package name, note this is requried if parent is None + + Returns: + ------- + np.ndarray or scalar float, int, string, or boolean value + depending on data type and length + """ + if model is None and not self.parent._sim_package: + model = self.parent.model.name + if package is None: + package = self.parent.pkg_name + + if name.lower() not in self._ptrs: + values0 = self.get_variable(name, model, package) + else: + values0 = self._ptrs[name.lower()] + + if values0.shape != values.shape: + raise ValueError( + f"Array shapes are incompatable: " + f"current shape={values.shape}, valid shape={values0.shape}" + ) + + self._ptrs[name.lower()] = values + + +class ScalarInput: + """ + Data object for storing pointers and working with array based input data + + Parameters + ---------- + parent : ArrayPackage + modflowapi ArrayPackage object + var_addrs : list, None + optional list of variable addresses + mf6 : ModflowApi, None + optional ModflowApi object + """ + + def __init__(self, parent, var_addrs=None, mf6=None): + self._ptrs = {} + self.parent = parent + # change this to a parent package.mapping + self._mapping = None + + if self.parent is not None: + self.var_addrs = self.parent.var_addrs + self.mf6 = self.parent.model.mf6 + else: + if var_addrs is None or mf6 is None: + raise AssertionError( + "var_addrs and mf6 must be supplied if parent is None" + ) + self.var_addrs = var_addrs + self.mf6 = mf6 + + self._reduced_to_var_addr = {} + self._set_scalars() + + def __getattr__(self, item): + """ + Dynamic method to get modflow varaibles as an attribute + """ + if item in self._ptrs: + return self._ptrs[item] + else: + return super(ArrayInput).__getattribute__(item) + + def __setattr__(self, item, value): + """ + Dynamic method that allows users to set modflow variables to the + _ptr dict + """ + if item in ( + "parent", + "var_addrs", + "_mapping", + "_ptrs", + "mf6", + "_maxbound", + "_nbound", + "_reduced_to_var_addr", + ): + super().__setattr__(item, value) + + elif item in self._ptrs: + self._ptrs[item] = value + else: + raise AttributeError(f"{item} is not a vaild attribute") + + @property + def variable_names(self): + """ + Returns a list of valid array names that can be accessed by the user + """ + return list(sorted(self._ptrs.keys())) + + def _set_scalars(self): + """ + Method to modflow variable pointers to the _ptrs dictionary + """ + ivn = self.mf6.get_input_var_names() + for var_addr in self.var_addrs: + if var_addr in ivn: + ptr = self.mf6.get_value_ptr(var_addr) + reduced = var_addr.split("/")[-1].lower() + self._ptrs[reduced] = ptr + self._reduced_to_var_addr[reduced] = var_addr + + def get_value(self, item): + """ + Method to get a scalar value from modflow + + Parameters + ---------- + item : str + modflow variable name. Ex. "NPER" + + Returns + ------- + str, int, float + """ + if item in self._ptrs: + return self._ptrs[item][0] + else: + raise KeyError(f"{item} is not accessible in this package") + + def set_value(self, item, value): + """ + Method to set a scalar value in modflow + + Parameters + ---------- + item : str + modflow variable name. Ex. "NPER" + + value : str, int, float + """ + if item in self._ptrs: + self._ptrs[item][0] = value + else: + raise KeyError(f"{item} is not accessible in this package") diff --git a/modflowapi/extensions/pakbase.py b/modflowapi/extensions/pakbase.py new file mode 100644 index 0000000..aee94c0 --- /dev/null +++ b/modflowapi/extensions/pakbase.py @@ -0,0 +1,717 @@ +import numpy as np + +from .data import AdvancedInput, ArrayInput, ListInput, ScalarInput + +# Note: HFB variables are not accessible in the memory manager 10/7/2022 +pkgvars = { + "dis": ["top", "bot", "area", "idomain"], + "chd": [ + "nbound", + "maxbound", + "nodelist", + ("bound", ("head",)), + "naux", + "auxname_cst", + "auxvar", + ], + "drn": [ + "nbound", + "maxbound", + "nodelist", + ( + "bound", + ( + "elev", + "cond", + ), + ), + "naux", + "auxname_cst", + "auxvar", + ], + "evt": [ + "nbound", + "maxbound", + "nodelist", + ( + "bound", + ( + "surface", + "rate", + "depth", + ), + ), + # "pxdp:NSEG", "petm:NSEG" + "naux", + "auxname_cst", + "auxvar", + ], + "ghb": [ + "nbound", + "maxbound", + "nodelist", + ( + "bound", + ( + "bhead", + "cond", + ), + ), + "naux", + "auxname_cst", + "auxvar", + ], + "ic": ["strt"], + "npf": ["k11", "k22", "k33", "angle1", "angle2", "angle3", "icelltype"], + "rch": [ + "maxbound", + "nbound", + "nodelist", + ("bound", ("recharge",)), + "naux", + "auxname_cst", + "auxvar", + ], + "sto": ["iconvert", "ss", "sy"], + "wel": [ + "maxbound", + "nbound", + "nodelist", + ("bound", ("flux",)), + "naux", + "auxname_cst", + "auxvar", + ], + # gwt model + "adv": ["diffc", "alh", "alv", "ath1", "ath2", "atv"], + "cnc": [ + "maxbound", + "nbound", + "nodelist", + ("bound", ("conc",)), + "naux", + "auxname_cst", + "auxvar", + ], + "ist": [ + "cim", + "thtaim", + "zetaim", + "decay", + "decay_sorbed", + "bulk_density", + "distcoef", + ], + "mst": ["porosity", "decay", "decay_sorbed", "bulk_density", "distcoef"], + "src": [ + "maxbound", + "nbound", + "nodelist", + ("bound", ("smassrate",)), + "naux", + "auxname_cst", + "auxvar", + ], + # exchange model + "gwf-gwf": ["nexg", "nodem1", "nodem2", "cl1", "cl2", "ihc"], + "gwt-gwt": ["nexg", "nodem1", "nodem2", "cl1", "cl2", "ihc"], + # simulation + "ats": [ + "maxats", + "iperats", + "dt0", + "dtmin", + "dtmax", + "dtadj", + "dtfailadj", + ], + "tdis": [ + "nper", + "itmuni", + "kper", + "kstp", + "delt", + "pertim", + "totim,", + "perlen", + "nstp", + "tsmult", + ], + # solution package + "sln": [ + "mxiter", + "dvclose", + "gamma", + "theta", + "akappa", + "amomentum", + "numtrack", + "btol", + "breduc", + "res_lim", + ], + "ims": [ + "niterc", + "dvclose", + "rclose", + "relax", + "ipc", + "droptol", + "north", + "iscl", + "iord", + ], +} + + +class PackageBase: + """ + Base class for packages within the modflow-6 api + + + Parameters + ---------- + model : ApiModel + modflowapi ApiModel object + pkg_type : str + package type name. ex. 'wel' + pkg_name : str + modflow package name. ex. 'wel_0' + child_type : str + type of child input package + sim_package : bool + flag to indicate this is a simulation level package + """ + + def __init__(self, model, pkg_type, pkg_name, child_type, sim_package): + self.model = model + self.pkg_name = pkg_name + self.pkg_type = pkg_type + self._child_type = child_type + self._sim_package = sim_package + self._rhs = None + self._hcof = None + self._bound_vars = [] + self._advanced_var_names = None + + var_addrs = [] + if self._child_type != "advanced": + for var in pkgvars[self.pkg_type]: + if isinstance(var, tuple): + bound_vars = [] + for bv in var[-1]: + t = bv.split(":") + if len(t) == 2: + # this is a repeating variable + addr = self.model.mf6.get_var_address( + t[-1].upper(), self.model.name, self.pkg_name + ) + nrep = self.model.mf6.get_value(addr)[0] + if nrep > 1: + for rep in range(nrep): + bound_vars.append(f"{t[0]}{rep}") + else: + bound_vars.append(t[0]) + else: + bound_vars.append(t[0]) + + self._bound_vars = var[-1] + var = var[0] + + if sim_package: + var_addrs.append( + self.model.mf6.get_var_address( + var.upper(), self.pkg_name + ) + ) + else: + var_addrs.append( + self.model.mf6.get_var_address( + var.upper(), self.model.name, self.pkg_name + ) + ) + + self.var_addrs = var_addrs + self._variables_adv = AdvancedInput(self) + + @property + def advanced_vars(self): + """ + Returns a list of additional "advanced" variables that are + accessible through the API + """ + if self._advanced_var_names is None: + adv_vars = [] + for var_addr in self.model.mf6.get_input_var_names(): + is_advanced = False + t = var_addr.split("/") + if not self._sim_package: + if t[0] == self.model.name and t[1] == self.pkg_name: + is_advanced = self._check_if_advanced_var(t[-1]) + else: + if t[0] == self.pkg_name: + is_advanced = self._check_if_advanced_var(t[-1]) + + if is_advanced: + adv_vars.append(t[-1].lower()) + + self._advanced_var_names = adv_vars + return self._advanced_var_names + + def _check_if_advanced_var(self, variable_name): + """ + Method to check if a variable is an advanced variable + + Parameters + ---------- + variable_name : str + variable name to check + + Returns + ------- + bool + """ + if variable_name.lower() in self._bound_vars: + is_advanced = False + elif self.pkg_type not in pkgvars: + is_advanced = True + elif variable_name.lower() in pkgvars[self.pkg_type]: + is_advanced = False + else: + is_advanced = True + return is_advanced + + def get_advanced_var(self, name): + """ + Method to get an advanced variable that is not automatically + accessible through stress period data or as an array name + """ + name = name.lower() + if name not in self.advanced_vars: + raise AssertionError( + f"{name} is not accessible as an advanced " + f"variable for this package" + ) + + values = self._variables_adv.get_variable(name) + if not self._sim_package: + if ( + values.size == self.model.nodetouser.size + and self._child_type == "array" + ): + array = np.full(self.model.size, np.nan) + array[self.model.nodetouser] = values + return array + + return values + + def set_advanced_var(self, name, values): + """ + Method to set data to an advanced variable + + Parameters + ---------- + name : str + parameter name + values : np.ndarray + numpy array + """ + if not self._sim_package: + if self._child_type == "array" and values.size == self.model.size: + values = values[self.model.nodetouser] + + self._variables_adv.set_variable(name, values) + + @property + def rhs(self): + if not self._sim_package: + if self._rhs is None: + var_addr = self.model.mf6.get_var_address( + "RHS", self.model.name, self.pkg_name + ) + if var_addr in self.model.mf6.get_input_var_names(): + self._rhs = self.model.mf6.get_value_ptr(var_addr) + else: + return + + return np.copy(self._rhs) + + @rhs.setter + def rhs(self, values): + if self._rhs is None: + return + + self._rhs = values + + @property + def hcof(self): + if not self._sim_package: + if self._hcof is None: + var_addr = self.model.mf6.get_var_address( + "HCOF", self.model.name, self.pkg_name + ) + if var_addr in self.model.mf6.get_input_var_names(): + self._hcof = self.model.mf6.get_value_ptr(var_addr) + else: + return + + return np.copy(self._hcof) + + @hcof.setter + def hcof(self, values): + if self._hcof is None: + return + + self.__hcof = values + + +class ListPackage(PackageBase): + """ + Package object for "list based" input packages such as WEL, DRN, RCH + + Parameters + ---------- + model : ApiModel + modflowapi model object + pkg_type : str + package type. Ex. "RCH" + pkg_name : str + package name (in the mf6 variables) + sim_package : bool + flag to indicate this is a simulation level package + """ + + def __init__(self, model, pkg_type, pkg_name, sim_package=False): + super().__init__( + model, pkg_type, pkg_name.upper(), "list", sim_package + ) + + self._variables = ListInput(self) + + def __repr__(self): + s = f"{self.pkg_type.upper()} Package: {self.pkg_name}" + return s + + @property + def nbound(self): + """ + Returns the "nbound" value for the stress period + """ + return self._variables._nbound[0] + + @property + def maxbound(self): + """ + Returns the "maxbound" value for the stress period + """ + return self._variables._maxbound[0] + + @property + def stress_period_data(self): + """ + Returns a ListInput object of the current stress_period_data + """ + return self._variables + + @stress_period_data.setter + def stress_period_data(self, recarray): + """ + Setter method to update the current stress_period_data + """ + if isinstance(recarray, np.recarray): + self._variables.values = recarray + elif isinstance(recarray, ListInput): + self._variables.values = recarray.values + elif recarray is None: + self._variables.values = recarray + else: + raise TypeError( + f"{type(recarray)} is not a supported stress_period_data type" + ) + + +class ArrayPackage(PackageBase): + """ + Package object for "array based" input packages such as NPF, DIS, + + Parameters + ---------- + model : ApiModel + modflowapi model object + pkg_type : str + package type. Ex. "DIS" + pkg_name : str + package name (in the mf6 variables) + sim_package : bool + flag to indicate this is a simulation level package + """ + + def __init__(self, model, pkg_type, pkg_name, sim_package=False): + super().__init__( + model, pkg_type, pkg_name.upper(), "array", sim_package + ) + + self._variables = ArrayInput(self) + + def __repr__(self): + s = f"{self.pkg_type.upper()} Package: {self.pkg_name} \n" + s += " Accessible variables include:\n" + for var_name in self.variable_names: + s += f" {var_name} \n" + return s + + def __setattr__(self, item, value): + """ + Method that enables dynamic variable setting and distributes + modflow variable storage and updates to the data object class + """ + if item in ( + "model", + "pkg_name", + "pkg_type", + "var_addrs", + ): + super().__setattr__(item, value) + + elif item.startswith("_"): + super().__setattr__(item, value) + + elif item in self._variables._ptrs: + self._variables.set_ptr(item, value) + + else: + raise AttributeError(f"{item}") + + def __getattr__(self, item): + """ + Method to dynamically get modflow variables by attribute + """ + if item in self._variables._ptrs: + return self._variables.get_ptr(item) + else: + return super().__getattribute__(item) + + @property + def variable_names(self): + """ + Returns a list of valid modflow variable names that the user can access + """ + return self._variables.variable_names + + def get_array(self, item): + """ + Method to get an array from modflow + + Parameters + ---------- + item : str + modflow variable name. Ex. "k11" + + Returns + ------- + np.array of modflow data + """ + return self._variables.get_array(item) + + def set_array(self, item, array): + """ + Method to update the modflow pointer arrays + + Parameters + ---------- + item : str + modflow variable name. Ex. "k11" + array : np.array + numpy array + + """ + self._variables.set_array(item, array) + + +class ScalarPackage(PackageBase): + """ + Container for advanced data packages + + Parameters + ---------- + model : ApiModel + modflowapi model object + pkg_type : str + package type. Ex. "RCH" + pkg_name : str + package name (in the mf6 variables) + sim_package : bool + boolean flag for simulation level packages. Ex. TDIS, IMS + """ + + def __init__(self, model, pkg_type, pkg_name, sim_package=False): + super().__init__( + model, pkg_type, pkg_name.upper(), "scalar", sim_package + ) + + self._variables = ScalarInput(self) + + def __repr__(self): + s = f"{self.pkg_type.upper()} Package: {self.pkg_name} \n" + s += " Accessible variables include:\n" + for var_name in self.variable_names: + s += f" {var_name} \n" + return s + + def __setattr__(self, item, value): + """ + Method that enables dynamic variable setting and distributes + modflow variable storage and updates to the data object class + """ + if item in ( + "model", + "pkg_name", + "pkg_type", + "var_addrs", + ): + super().__setattr__(item, value) + + elif item.startswith("_"): + super().__setattr__(item, value) + + elif item in self._variables._ptrs: + self._variables.set_value(item, value) + + else: + raise AttributeError(f"{item}") + + def __getattr__(self, item): + """ + Method to dynamically get modflow variables by attribute + """ + if item in self._variables._ptrs: + return self._variables.get_value(item) + else: + return super().__getattribute__(item) + + @property + def variable_names(self): + """ + Returns a list of valid modflow variable names that the user can access + """ + return self._variables.variable_names + + def get_value(self, item): + """ + Method to get a scalar value from modflow + + Parameters + ---------- + item : str + modflow variable name. Ex. "NBOUND" + + Returns + ------- + np.array of modflow data + """ + return self._variables.get_value(item) + + def set_value(self, item, value): + """ + Method to update the modflow pointer arrays + + Parameters + ---------- + item : str + modflow variable name. Ex. "k11" + array : str, int, float + scalar value + + """ + self._variables.set_value(item, value) + + +class AdvancedPackage(PackageBase): + """ + Container for advanced data packages + + Parameters + ---------- + model : ApiModel + modflowapi model object + pkg_type : str + package type. Ex. "RCH" + pkg_name : str + package name (in the mf6 variables) + sim_package : bool + boolean flag for simulation level packages. Ex. TDIS, IMS + """ + + def __init__(self, model, pkg_type, pkg_name, sim_package=False): + super().__init__( + model, pkg_type, pkg_name.upper(), "advanced", sim_package + ) + + def __repr__(self): + s = f"{self.pkg_type.upper()} Package: {self.pkg_name} \n" + s += " Advanced Package, variables only accessible through\n" + s += " get_advanced_var() and set_advanced_var() methods" + return s + + +class ApiSlnPackage(ScalarPackage): + """ + Class to acess solution packages + + Parameters + ---------- + model : ApiModel + modflowapi model object + pkg_type : str + package type. Ex. "RCH" + pkg_name : str + package name (in the mf6 variables) + sim_package : bool + boolean flag for simulation level packages. Ex. TDIS, IMS + """ + + def __init__(self, sim, pkg_name): + from .apimodel import ApiMbase + + super().__init__(sim, "sln", pkg_name, sim_package=True) + + mdl = ApiMbase( + sim.mf6, pkg_name.upper(), pkg_types={"ims": ScalarPackage} + ) + imslin = ScalarPackage(mdl, "ims", "IMSLINEAR") + for key, ptr in imslin._variables._ptrs.items(): + if key in self._variables._ptrs: + key = f"{imslin.pkg_type}_{key}".lower() + self._variables._ptrs[key] = ptr + + +def package_factory(pkg_type, basepackage): + """ + Method to autogenerate unique package "types" from the base packages: + ArrayPackage, ListPackage, and AdvancedPackage + + Parameters + ---------- + pkg_type : str + package type + basepackage : ArrayPackage, ListPackage, or AdvancedPackage + a base package type + + Returns + Package object : ex. ApiWelPackage + """ + + # hack for now. need a pkg_type variable for robustness + def __init__(self, obj, model, pkg_type, pkg_name, sim_package=False): + obj.__init__(self, model, pkg_type, pkg_name, sim_package=sim_package) + + cls_str = "".join(pkg_type.split("-")) + cls_str = f"{cls_str[0].upper()}{cls_str[1:]}" + + package = type( + f"Api{cls_str}Package", + (basepackage,), + {"__init__": __init__}, + ) + + return package diff --git a/modflowapi/extensions/runner.py b/modflowapi/extensions/runner.py new file mode 100644 index 0000000..c708d5c --- /dev/null +++ b/modflowapi/extensions/runner.py @@ -0,0 +1,150 @@ +from .. import ModflowApi +from .apisimulation import ApiSimulation +import pathlib +import platform +from enum import Enum + + +class Callbacks(Enum): + initialize = 0 + stress_period_start = 1 + stress_period_end = 2 + timestep_start = 3 + timestep_end = 4 + iteration_start = 5 + iteration_end = 6 + finalize = 7 + + +def run_simulation(dll, sim_path, callback, verbose=False, _develop=False): + """ + Method to run a Modflow simulation using the MODFLOW-API + with a callback function + + Parameters + ---------- + dll : str + path to the Modflow6 shared object + sim_path : str + path to the Modflow6 simulation + callback : method + user defined method that intercepts the simulation + progress and allows for input variable adjustments on the fly + verbose : bool + flag for verbose output from the simulation runner + _develop : bool + flag that dumps a list of all mf6 api variable addresses to text + file named "var_list.txt". This is primarily used for extensions + development purposes and bug fixes within the modflowapi python + package. + """ + ext = pathlib.Path(dll).suffix + dll = str(dll) + if not ext: + if platform.system().lower() == "windows": + dll += ".dll" + elif platform.system().lower() == "linux": + if not dll.startswith("./"): + if not dll.startswith("/"): + dll = "./" + dll + ".so" + else: + dll = "." + dll + ".so" + else: + dll += ".dylib" + + mf6 = ModflowApi( + dll, + working_directory=sim_path, + ) + + if verbose: + version = mf6.get_version() + print(f"MODFLOW-6 API Version {version}") + print("Initializing MODFLOW-6 simulation") + + mf6.initialize() + sim = ApiSimulation.load(mf6) + + if _develop: + with open("var_list.txt", "w") as foo: + for name in mf6.get_input_var_names(): + foo.write(f"{name}\n") + + callback(sim, Callbacks.initialize) + + has_converged = False + current_time = mf6.get_current_time() + end_time = mf6.get_end_time() + kperold = [0 for _ in range(sim.subcomponent_count)] + + while current_time < end_time: + dt = mf6.get_time_step() + mf6.prepare_time_step(dt) + + if verbose: + print( + f"Solving: Stress Period {sim.kper + 1}; " + f"Timestep {sim.kstp + 1}" + ) + + for sol_id, slnobj in sorted(sim.solutions.items()): + models = {} + maxiter = slnobj.mxiter + solution = {sol_id: slnobj} + for model in sim.models: + if sol_id == model.solution_id: + models[model.name.lower()] = model + + sim_grp = ApiSimulation( + mf6, models, solution, sim._exchanges, sim.tdis, sim.ats + ) + mf6.prepare_solve(sol_id) + if sim.kper != kperold[sol_id - 1]: + callback(sim_grp, Callbacks.stress_period_start) + kperold[sol_id - 1] += 1 + elif current_time == 0: + callback(sim_grp, Callbacks.stress_period_start) + + kiter = 0 + callback(sim_grp, Callbacks.timestep_start) + + if sim_grp.ats_period[0]: + mindt = sim_grp.ats_period[-1] + while sim_grp.delt > mindt: + sim_grp.iteration = kiter + callback(sim_grp, Callbacks.iteration_start) + has_converged = mf6.solve(sol_id) + callback(sim_grp, Callbacks.iteration_end) + kiter += 1 + if has_converged and sim_grp.allow_convergence: + break + + else: + while kiter < maxiter: + sim_grp.iteration = kiter + callback(sim_grp, Callbacks.iteration_start) + has_converged = mf6.solve(sol_id) + callback(sim_grp, Callbacks.iteration_end) + kiter += 1 + if has_converged and sim_grp.allow_convergence: + break + + callback(sim_grp, Callbacks.timestep_end) + mf6.finalize_solve(sol_id) + + mf6.finalize_time_step() + current_time = mf6.get_current_time() + + if not has_converged: + print(f"Simulation group: {sim_grp} DID NOT CONVERGE") + + if sim_grp.nstp == sim_grp.kstp + 1: + callback(sim_grp, Callbacks.stress_period_end) + + try: + callback(sim, Callbacks.finalize) + mf6.finalize() + except Exception: + raise RuntimeError("MF6 simulation failed, check listing file") + + print("NORMAL TERMINATION OF SIMULATION") diff --git a/modflowapi/version.py b/modflowapi/version.py new file mode 100644 index 0000000..2a30a86 --- /dev/null +++ b/modflowapi/version.py @@ -0,0 +1,6 @@ +# version file for modflowapi + +major = 0 +minor = 0 +micro = 2 +__version__ = f"{major}.{minor}.{micro}" diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..dc60b58 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,90 @@ +[metadata] +name = modflowapi +version = attr: modflowapi.version.__version__ +description = modflowapi is an extension to the xmipy Python package +long_description = file: README.md +long_description_content_type = text/markdown +author = Joseph D. Hughes, Martijn Russcher, Christian D. Langevin, Julian Hofer, Joshua D. Larsen +author_email = jdhughes@usgs.gov, Martijn.Russcher@deltares.nl, langevin@usgs.gov, Julian.Hofer@deltares.nl, jlarsen@usgs.gov +maintainer = Joseph D. Hughes +maintainer_email = jdhughes@usgs.gov +license = CC0 +license_files = LICENSE +platform = Windows, Mac OS-X, Linux +keywords = MODFLOW, groundwater, hydrogeology +classifiers = + Development Status :: 5 - Production/Stable + Intended Audience :: Science/Research + License :: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication + Operating System :: Microsoft :: Windows + Operating System :: POSIX + Operating System :: Unix + Operating System :: MacOS + Programming Language :: Python + Programming Language :: Python :: 3 + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 + Programming Language :: Python :: 3 :: Only + Topic :: Scientific/Engineering :: Hydrology +url = https://github.com/MODFLOW-USGS/modflowapi +download_url = https://pypi.org/project/modflowapi/ + +[options] +zip_safe = False +packages = find: +python_requires = >=3.8 +install_requires = + numpy + pandas + xmipy @ git+https://git@github.com/Deltares/xmipy@develop + +[options.extras_require] +lint = + black + flake8 + pylint + requests + +test = + %(lint)s + pytest + pytest-xdist + pytest-order + filelock + modflow-devtools @ git+https://git@github.com/MODFLOW-USGS/modflow-devtools@develop + +[flake8] +exclude = + .git, + __pycache__, + build, + dist, + examples, + autotest +ignore = + F401, + E121, + E122, + E126, + E127, + E128, + E203, + E221, + E222, + E226, + E231, + E241, + E402, + E501, + E502, + E722, + E741, + W291, + W292, + W293, + W391, + W503, + W504 + +statistics = True \ No newline at end of file diff --git a/setup.py b/setup.py index f308c77..b024da8 100755 --- a/setup.py +++ b/setup.py @@ -1,52 +1,4 @@ -import sys -from setuptools import find_namespace_packages, setup -import codecs -import os.path +from setuptools import setup -# edit author dictionary as necessary -author_dict = { - "Joseph D. Hughes": "jdhughes@usgs.gov", - "Martijn Russcher": "Martijn.Russcher@deltares.nl", - "Christian D. Langevin": "langevin@usgs.gov", - "Julian Hofer": "Julian.Hofer@deltares.nl", -} -__author__ = ", ".join(author_dict.keys()) -__author_email__ = ", ".join(s for _, s in author_dict.items()) - -def read(rel_path): - here = os.path.abspath(os.path.dirname(__file__)) - with codecs.open(os.path.join(here, rel_path), "r") as fp: - return fp.read() - - -def get_version(rel_path): - for line in read(rel_path).splitlines(): - if line.startswith("__version__"): - delim = '"' if '"' in line else "'" - return line.split(delim)[1] - else: - raise RuntimeError("Unable to find version string.") - - -long_description = read("README.md") - - -setup( - name="modflowapi", - description="modflowapi is an extension to the xmipy Python package.", - long_description=long_description, - long_description_content_type="text/markdown", - author=__author__, - author_email=__author_email__, - url="https://github.com/MODFLOW-USGS/modflowapi.git", - license="CC0", - platforms="Windows, Mac OS-X, Linux", - install_requires=[ - "xmipy", - ], - python_requires=">=3.6", - packages=find_namespace_packages(exclude=("etc",)), - version=get_version("modflowapi/__init__.py"), - classifiers=["Topic :: Scientific/Engineering :: Hydrology"], -) +setup() From defd2ee2bfc840ee2b7b3df76fcea4af651f1936 Mon Sep 17 00:00:00 2001 From: spaulins-usgs Date: Fri, 24 Feb 2023 09:25:53 -0800 Subject: [PATCH 04/34] fix(get value): fixed error handling when modflowapi fails to get a pointer to a value from the API (#9) Co-authored-by: scottrp <45947939+scottrp@users.noreply.github.com> --- modflowapi/extensions/data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modflowapi/extensions/data.py b/modflowapi/extensions/data.py index cec3812..bf733c1 100644 --- a/modflowapi/extensions/data.py +++ b/modflowapi/extensions/data.py @@ -558,7 +558,7 @@ def get_variable(self, name, model=None, package=None): try: values = self.mf6.get_value_ptr(var_addr) - except InputError: + except xmipy.errors.InputError: values = self.mf6.get_value(var_addr) self._ptrs[name.lower()] = values From 2c4d893eaa96457be099313a220c7c7d8fca888a Mon Sep 17 00:00:00 2001 From: Joshua Larsen Date: Fri, 24 Feb 2023 16:56:47 -0800 Subject: [PATCH 05/34] update(rhs, hcof, AdvancedInput): bug fixes for setting variable values for advanced inputs * update rhs and hcof to copy values to pointer instead of overwriting the pointer * add a check for AdvancedInput variables that do not have pointer support in xmipy --- modflowapi/extensions/data.py | 15 +++++++++++++-- modflowapi/extensions/pakbase.py | 4 ++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/modflowapi/extensions/data.py b/modflowapi/extensions/data.py index bf733c1..888ce26 100644 --- a/modflowapi/extensions/data.py +++ b/modflowapi/extensions/data.py @@ -558,10 +558,10 @@ def get_variable(self, name, model=None, package=None): try: values = self.mf6.get_value_ptr(var_addr) + self._ptrs[name.lower()] = values except xmipy.errors.InputError: values = self.mf6.get_value(var_addr) - self._ptrs[name.lower()] = values return values.copy() def set_variable(self, name, values, model=None, package=None): @@ -601,7 +601,18 @@ def set_variable(self, name, values, model=None, package=None): f"current shape={values.shape}, valid shape={values0.shape}" ) - self._ptrs[name.lower()] = values + if name.lower() not in self._ptrs: + # this is a set value situation + self.mf6.set_value( + self.mf6.get_var_address( + name.upper(), + self.parent.model.name, + self.parent.pkg_name + ), + values + ) + else: + self._ptrs[name.lower()] = values class ScalarInput: diff --git a/modflowapi/extensions/pakbase.py b/modflowapi/extensions/pakbase.py index aee94c0..b235009 100644 --- a/modflowapi/extensions/pakbase.py +++ b/modflowapi/extensions/pakbase.py @@ -341,7 +341,7 @@ def rhs(self, values): if self._rhs is None: return - self._rhs = values + self._rhs[:] = values[:] @property def hcof(self): @@ -362,7 +362,7 @@ def hcof(self, values): if self._hcof is None: return - self.__hcof = values + self._hcof[:] = values[:] class ListPackage(PackageBase): From ce775a6533e2ebef47ea1425018a71b4959cfd1d Mon Sep 17 00:00:00 2001 From: Joshua Larsen Date: Fri, 24 Feb 2023 16:58:48 -0800 Subject: [PATCH 06/34] lint --- modflowapi/extensions/data.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/modflowapi/extensions/data.py b/modflowapi/extensions/data.py index 888ce26..d69e1d6 100644 --- a/modflowapi/extensions/data.py +++ b/modflowapi/extensions/data.py @@ -605,11 +605,9 @@ def set_variable(self, name, values, model=None, package=None): # this is a set value situation self.mf6.set_value( self.mf6.get_var_address( - name.upper(), - self.parent.model.name, - self.parent.pkg_name + name.upper(), self.parent.model.name, self.parent.pkg_name ), - values + values, ) else: self._ptrs[name.lower()] = values From 4fd8a1d43373841874b625007c43345f6e737e07 Mon Sep 17 00:00:00 2001 From: Joshua Larsen Date: Fri, 24 Feb 2023 17:09:11 -0800 Subject: [PATCH 07/34] update setting routine for AdvancedInput --- modflowapi/extensions/data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modflowapi/extensions/data.py b/modflowapi/extensions/data.py index d69e1d6..b443313 100644 --- a/modflowapi/extensions/data.py +++ b/modflowapi/extensions/data.py @@ -610,7 +610,7 @@ def set_variable(self, name, values, model=None, package=None): values, ) else: - self._ptrs[name.lower()] = values + self._ptrs[name.lower()][:] = values[:] class ScalarInput: From e0ca9e80a60ae6c85933a69ec322a5bc861a32ab Mon Sep 17 00:00:00 2001 From: Mike Taves Date: Sat, 25 Mar 2023 11:26:32 +1300 Subject: [PATCH 08/34] refactor(EOL): change CRLF to LF line endings for source files (#12) --- .gitattributes | 1 - autotest/conftest.py | 276 ++--- autotest/pytest.ini | 14 +- autotest/test_interface.py | 650 +++++------ autotest/test_mf6_examples.py | 106 +- modflowapi/extensions/__init__.py | 6 +- modflowapi/extensions/apiexchange.py | 40 +- modflowapi/extensions/apimodel.py | 766 ++++++------- modflowapi/extensions/apisimulation.py | 706 ++++++------ modflowapi/extensions/data.py | 1464 ++++++++++++------------ modflowapi/extensions/pakbase.py | 1434 +++++++++++------------ modflowapi/extensions/runner.py | 300 ++--- 12 files changed, 2881 insertions(+), 2882 deletions(-) diff --git a/.gitattributes b/.gitattributes index 7ee4b11..7a62c71 100644 --- a/.gitattributes +++ b/.gitattributes @@ -15,4 +15,3 @@ # Do not modify the model data in various directories examples/data/** binary -examples/groundwater_paper/uspb/** binary diff --git a/autotest/conftest.py b/autotest/conftest.py index cf0540f..9413bdd 100644 --- a/autotest/conftest.py +++ b/autotest/conftest.py @@ -1,138 +1,138 @@ -from itertools import groupby -from os import linesep -from pathlib import Path -from tempfile import gettempdir - -import pytest -from filelock import FileLock - - -__mf6_examples = "mf6_examples" -__mf6_examples_path = Path(gettempdir()) / __mf6_examples -__mf6_examples_lock = FileLock(Path(gettempdir()) / f"{__mf6_examples}.lock") - - -def get_mf6_examples_path() -> Path: - pytest.importorskip("modflow_devtools") - from modflow_devtools.download import download_and_unzip - - # use file lock so mf6 distribution is downloaded once, - # even when tests are run in parallel with pytest-xdist - __mf6_examples_lock.acquire() - try: - if not __mf6_examples_path.is_dir(): - __mf6_examples_path.mkdir(exist_ok=True) - download_and_unzip( - url="https://github.com/MODFLOW-USGS/modflow6-examples/releases/download/current/modflow6-examples.zip", - path=__mf6_examples_path, - verbose=True, - ) - return __mf6_examples_path - finally: - __mf6_examples_lock.release() - -def is_nested(namfile) -> bool: - p = Path(namfile) - if not p.is_file() or not p.name.endswith(".nam"): - raise ValueError(f"Expected a namfile path, got {p}") - - return p.parent.parent.name != __mf6_examples - - -def pytest_generate_tests(metafunc): - # examples to skip: - # - ex-gwtgwt-mt3dms-p10: https://github.com/MODFLOW-USGS/modflow6/pull/1008 - exclude = ["ex-gwt-gwtgwt-mt3dms-p10"] - namfiles = [ - str(p) - for p in get_mf6_examples_path().rglob("mfsim.nam") - if not any(e in str(p) for e in exclude) - ] - - # parametrization by model - # - single namfile per test case - # - no coupling (only first model in each simulation subdir is used) - key = "mf6_example_namfile" - if key in metafunc.fixturenames: - metafunc.parametrize(key, sorted(namfiles)) - - # parametrization by simulation - # - each test case gets an ordered list of 1+ namfiles - # - models can be coupled (run in order provided, sharing workspace) - key = "mf6_example_namfiles" - if key in metafunc.fixturenames: - simulations = [] - - def simulation_name_from_model_path(p): - p = Path(p) - return p.parent.parent.name if is_nested(p) else p.parent.name - - for model_name, model_namfiles in groupby( - namfiles, key=simulation_name_from_model_path - ): - models = sorted( - list(model_namfiles) - ) # sort in alphabetical order (gwf < gwt) - simulations.append(models) - print( - f"Simulation {model_name} has {len(models)} model(s):\n" - f"{linesep.join(model_namfiles)}" - ) - - def simulation_name_from_model_namfiles(mnams): - try: - namfile = next(iter(mnams), None) - except TypeError: - namfile = None - if namfile is None: - pytest.skip("No namfiles (expected ordered collection)") - namfile = Path(namfile) - return ( - namfile.parent.parent if is_nested(namfile) else namfile.parent - ).name - - metafunc.parametrize( - key, simulations, ids=simulation_name_from_model_namfiles - ) - - -@pytest.fixture(scope="function") -def tmpdir(tmpdir_factory, request) -> Path: - node = ( - request.node.name.replace("/", "_") - .replace("\\", "_") - .replace(":", "_") - ) - temp = Path(tmpdir_factory.mktemp(node)) - yield Path(temp) - - keep = request.config.getoption("--keep") - if keep: - copytree(temp, Path(keep) / temp.name) - - keep_failed = request.config.getoption("--keep-failed") - if keep_failed and request.node.rep_call.failed: - copytree(temp, Path(keep_failed) / temp.name) - - -def pytest_addoption(parser): - parser.addoption( - "-K", - "--keep", - action="store", - default=None, - help="Move the contents of temporary test directories to correspondingly named subdirectories at the given " - "location after tests complete. This option can be used to exclude test results from automatic cleanup, " - "e.g. for manual inspection. The provided path is created if it does not already exist. An error is " - "thrown if any matching files already exist.", - ) - - parser.addoption( - "--keep-failed", - action="store", - default=None, - help="Move the contents of temporary test directories to correspondingly named subdirectories at the given " - "location if the test case fails. This option automatically saves the outputs of failed tests in the " - "given location. The path is created if it doesn't already exist. An error is thrown if files with the " - "same names already exist in the given location.", - ) \ No newline at end of file +from itertools import groupby +from os import linesep +from pathlib import Path +from tempfile import gettempdir + +import pytest +from filelock import FileLock + + +__mf6_examples = "mf6_examples" +__mf6_examples_path = Path(gettempdir()) / __mf6_examples +__mf6_examples_lock = FileLock(Path(gettempdir()) / f"{__mf6_examples}.lock") + + +def get_mf6_examples_path() -> Path: + pytest.importorskip("modflow_devtools") + from modflow_devtools.download import download_and_unzip + + # use file lock so mf6 distribution is downloaded once, + # even when tests are run in parallel with pytest-xdist + __mf6_examples_lock.acquire() + try: + if not __mf6_examples_path.is_dir(): + __mf6_examples_path.mkdir(exist_ok=True) + download_and_unzip( + url="https://github.com/MODFLOW-USGS/modflow6-examples/releases/download/current/modflow6-examples.zip", + path=__mf6_examples_path, + verbose=True, + ) + return __mf6_examples_path + finally: + __mf6_examples_lock.release() + +def is_nested(namfile) -> bool: + p = Path(namfile) + if not p.is_file() or not p.name.endswith(".nam"): + raise ValueError(f"Expected a namfile path, got {p}") + + return p.parent.parent.name != __mf6_examples + + +def pytest_generate_tests(metafunc): + # examples to skip: + # - ex-gwtgwt-mt3dms-p10: https://github.com/MODFLOW-USGS/modflow6/pull/1008 + exclude = ["ex-gwt-gwtgwt-mt3dms-p10"] + namfiles = [ + str(p) + for p in get_mf6_examples_path().rglob("mfsim.nam") + if not any(e in str(p) for e in exclude) + ] + + # parametrization by model + # - single namfile per test case + # - no coupling (only first model in each simulation subdir is used) + key = "mf6_example_namfile" + if key in metafunc.fixturenames: + metafunc.parametrize(key, sorted(namfiles)) + + # parametrization by simulation + # - each test case gets an ordered list of 1+ namfiles + # - models can be coupled (run in order provided, sharing workspace) + key = "mf6_example_namfiles" + if key in metafunc.fixturenames: + simulations = [] + + def simulation_name_from_model_path(p): + p = Path(p) + return p.parent.parent.name if is_nested(p) else p.parent.name + + for model_name, model_namfiles in groupby( + namfiles, key=simulation_name_from_model_path + ): + models = sorted( + list(model_namfiles) + ) # sort in alphabetical order (gwf < gwt) + simulations.append(models) + print( + f"Simulation {model_name} has {len(models)} model(s):\n" + f"{linesep.join(model_namfiles)}" + ) + + def simulation_name_from_model_namfiles(mnams): + try: + namfile = next(iter(mnams), None) + except TypeError: + namfile = None + if namfile is None: + pytest.skip("No namfiles (expected ordered collection)") + namfile = Path(namfile) + return ( + namfile.parent.parent if is_nested(namfile) else namfile.parent + ).name + + metafunc.parametrize( + key, simulations, ids=simulation_name_from_model_namfiles + ) + + +@pytest.fixture(scope="function") +def tmpdir(tmpdir_factory, request) -> Path: + node = ( + request.node.name.replace("/", "_") + .replace("\\", "_") + .replace(":", "_") + ) + temp = Path(tmpdir_factory.mktemp(node)) + yield Path(temp) + + keep = request.config.getoption("--keep") + if keep: + copytree(temp, Path(keep) / temp.name) + + keep_failed = request.config.getoption("--keep-failed") + if keep_failed and request.node.rep_call.failed: + copytree(temp, Path(keep_failed) / temp.name) + + +def pytest_addoption(parser): + parser.addoption( + "-K", + "--keep", + action="store", + default=None, + help="Move the contents of temporary test directories to correspondingly named subdirectories at the given " + "location after tests complete. This option can be used to exclude test results from automatic cleanup, " + "e.g. for manual inspection. The provided path is created if it does not already exist. An error is " + "thrown if any matching files already exist.", + ) + + parser.addoption( + "--keep-failed", + action="store", + default=None, + help="Move the contents of temporary test directories to correspondingly named subdirectories at the given " + "location if the test case fails. This option automatically saves the outputs of failed tests in the " + "given location. The path is created if it doesn't already exist. An error is thrown if files with the " + "same names already exist in the given location.", + ) diff --git a/autotest/pytest.ini b/autotest/pytest.ini index d7b645a..63e2571 100644 --- a/autotest/pytest.ini +++ b/autotest/pytest.ini @@ -1,7 +1,7 @@ -[pytest] -addopts = -ra -python_files = - test_*.py -markers = - mf6: tests for modflow 6 examples - extensions: tests for modflowapi extensions \ No newline at end of file +[pytest] +addopts = -ra +python_files = + test_*.py +markers = + mf6: tests for modflow 6 examples + extensions: tests for modflowapi extensions diff --git a/autotest/test_interface.py b/autotest/test_interface.py index ce1df81..e14a14e 100644 --- a/autotest/test_interface.py +++ b/autotest/test_interface.py @@ -1,325 +1,325 @@ -import pytest -import pathlib -from modflowapi.extensions.pakbase import ( - ArrayPackage, - ListPackage, - AdvancedPackage, -) -from modflowapi import Callbacks, run_simulation -import shutil -import numpy as np - -pytestmark = pytest.mark.extensions -so = "libmf6" -data_pth = pathlib.Path("../examples/data") - - -def test_dis_model(tmpdir): - def callback(sim, step): - """ - Callback function - - Parameters - ---------- - sim : modflowapi.ApiSimulation object - step : Enum - step is the simulation step defined by Callbacks - """ - if step == Callbacks.initialize: - if len(sim.models) != 1: - raise AssertionError("Invalid number of models") - - model = sim.test_model - if len(model.package_names) != 16: - raise AssertionError("Invalid number of packages") - - if len(model.package_types) != 15: - raise AssertionError("Invalid number of package types") - - if model.shape != (1, 10, 10): - raise AssertionError("ApiModel shape is incorrect") - - if model.size != 100: - raise AssertionError("ApiModel size is incorrect") - - if (model.kper, model.kstp) != (-1, -1): - raise AssertionError( - "ApiModel has advanced prior to initialization callback" - ) - - dis = model.dis - if not isinstance(dis, ArrayPackage): - raise TypeError("DIS package has incorrect base class type") - - wel = model.wel - if not isinstance(wel, ListPackage): - raise TypeError("WEL package has incorrect base class type") - - gnc = model.gnc - if not isinstance(gnc, AdvancedPackage): - raise TypeError("GNC package has incorrect base class type") - - rch = model.rch - if len(rch) != 2: - raise AssertionError( - "ApiModel object not returning multiple packages" - ) - - idomain = dis.idomain.values - if not isinstance(idomain, np.ndarray): - raise TypeError("Expecting a numpy array for idomain") - - elif step == Callbacks.stress_period_start: - if sim.kstp != 0: - raise AssertionError( - "Solution advanced prior to stress_period_start callback" - ) - - elif step == Callbacks.timestep_start: - if sim.iteration != -1: - raise AssertionError( - "Solution advanced prior to timestep_start callback" - ) - - factor = ((1 + sim.kstp) / sim.nstp) * 0.5 - spd = sim.test_model.wel.stress_period_data.values - sim.test_model.wel.stress_period_data["flux"] *= factor - - spd2 = sim.test_model.wel.stress_period_data.values - if not np.allclose((spd["flux"] * factor), spd2["flux"]): - raise AssertionError("Pointer not being set properly") - - if sim.kper >= 3 and sim.kstp == 0: - spd = sim.test_model.wel.stress_period_data.values - nbound0 = sim.test_model.wel.nbound - spd.resize((nbound0 + 1), refcheck=False) - spd[-1] = ((0, 1, 5), -20, 1.0, 2.0) - sim.test_model.wel.stress_period_data.values = spd - if sim.test_model.wel.nbound != nbound0 + 1: - raise AssertionError("Resize routine not properly working") - - name = "dis_model" - sim_pth = data_pth / name - test_pth = tmpdir / name - shutil.copytree(sim_pth, test_pth, dirs_exist_ok=True) - - try: - run_simulation(so, test_pth, callback) - except Exception as e: - raise Exception(e) - - -def test_disv_model(tmpdir): - def callback(sim, step): - """ - Callback function - - Parameters - ---------- - sim : modflowapi.ApiSimulation object - step : Enum - step is the simulation step defined by Callbacks - """ - if step == Callbacks.initialize: - if len(sim.models) != 1: - raise AssertionError("Invalid number of models") - - model = sim.gwf_1 - if len(model.package_names) != 12: - raise AssertionError("Invalid number of packages") - - if len(model.package_types) != 11: - raise AssertionError("Invalid number of package types") - - if model.shape != (4, 200): - raise AssertionError("ApiModel shape is incorrect") - - if model.size != 800: - raise AssertionError("ApiModel size is incorrect") - - if (model.kper, model.kstp) != (-1, -1): - raise AssertionError( - "ApiModel has advanced prior to initialization callback" - ) - - dis = model.dis - if not isinstance(dis, ArrayPackage): - raise TypeError("DIS package has incorrect base class type") - - chd = model.chd_left - if not isinstance(chd, ListPackage): - raise TypeError("CHD package has incorrect base class type") - - hfb = model.hfb - if not isinstance(hfb, AdvancedPackage): - raise TypeError("HFB package has incorrect base class type") - - chd = model.chd - if len(chd) != 2: - raise AssertionError( - "ApiModel object not returning multiple packages" - ) - - top = dis.top.values - if not isinstance(top, np.ndarray): - raise TypeError("Expecting a numpy array for top") - - elif step == Callbacks.stress_period_start: - if sim.kstp != 0: - raise AssertionError( - "Solution advanced prior to stress_period_start callback" - ) - - elif step == Callbacks.timestep_start: - if sim.iteration != -1: - raise AssertionError( - "Solution advanced prior to timestep_start callback" - ) - - factor = 0.75 - spd = sim.gwf_1.chd_left.stress_period_data.values - sim.gwf_1.chd_left.stress_period_data["head"] *= factor - - spd2 = sim.gwf_1.chd_left.stress_period_data.values - if not np.allclose((spd["head"] * factor), spd2["head"]): - raise AssertionError("Pointer not being set properly") - - name = "disv_model" - sim_pth = data_pth / name - test_pth = tmpdir / name - shutil.copytree(sim_pth, test_pth, dirs_exist_ok=True) - - try: - run_simulation(so, test_pth, callback) - except Exception as e: - raise Exception(e) - - -def test_disu_model(tmpdir): - def callback(sim, step): - """ - Callback function - - Parameters - ---------- - sim : modflowapi.ApiSimulation object - step : Enum - step is the simulation step defined by Callbacks - """ - if step == Callbacks.initialize: - if len(sim.models) != 1: - raise AssertionError("Invalid number of models") - - model = sim.gwf_1 - if len(model.package_names) != 12: - raise AssertionError("Invalid number of packages") - - if len(model.package_types) != 12: - raise AssertionError("Invalid number of package types") - - if model.shape != (121,): - raise AssertionError("ApiModel shape is incorrect") - - if model.size != 121: - raise AssertionError("ApiModel size is incorrect") - - if (model.kper, model.kstp) != (-1, -1): - raise AssertionError( - "ApiModel has advanced prior to initialization callback" - ) - - dis = model.dis - if not isinstance(dis, ArrayPackage): - raise TypeError("DIS package has incorrect base class type") - - rch = model.rch - if not isinstance(rch, ListPackage): - raise TypeError("RCH package has incorrect base class type") - - mvr = model.mvr - if not isinstance(mvr, AdvancedPackage): - raise TypeError("MVR package has incorrect base class type") - - top = dis.top.values - if not isinstance(top, np.ndarray): - raise TypeError("Expecting a numpy array for top") - - elif step == Callbacks.stress_period_start: - if sim.kstp != 0: - raise AssertionError( - "Solution advanced prior to stress_period_start callback" - ) - - elif step == Callbacks.timestep_start: - if sim.iteration != -1: - raise AssertionError( - "Solution advanced prior to timestep_start callback" - ) - - factor = 1.75 - spd = sim.gwf_1.rch.stress_period_data.values - sim.gwf_1.rch.stress_period_data["recharge"] += factor - - spd2 = sim.gwf_1.rch.stress_period_data.values - if not np.allclose((spd["recharge"] + factor), spd2["recharge"]): - raise AssertionError("Pointer not being set properly") - - name = "disu_model" - sim_pth = data_pth / name - test_pth = tmpdir / name - shutil.copytree(sim_pth, test_pth, dirs_exist_ok=True) - - try: - run_simulation(so, test_pth, callback) - except Exception as e: - raise Exception(e) - - -def test_two_models(tmpdir): - def callback(sim, step): - """ - Callback function - - Parameters - ---------- - sim : modflowapi.ApiSimulation object - step : Enum - step is the simulation step defined by Callbacks - """ - if step == Callbacks.initialize: - if len(sim.models) != 2: - raise AssertionError("Invalid number of models") - - name = "two_models" - sim_pth = data_pth / name - test_pth = tmpdir / name - shutil.copytree(sim_pth, test_pth, dirs_exist_ok=True) - - try: - run_simulation(so, test_pth, callback) - except Exception as e: - raise Exception(e) - - -def test_ats_model(tmpdir): - def callback(sim, step): - if step == Callbacks.stress_period_start: - if sim.kper == 0 and sim.kstp == 0: - delt0 = sim.delt - - if step == Callbacks.timestep_start: - if sim.kstp == 1: - if delt0 == sim.delt: - raise AssertionError( - "ATS routines not reducing timestep length" - ) - - name = "ats0" - sim_pth = data_pth / name - test_pth = tmpdir / name - shutil.copytree(sim_pth, test_pth, dirs_exist_ok=True) - - try: - run_simulation(so, test_pth, callback) - except Exception as e: - raise Exception(e) \ No newline at end of file +import pytest +import pathlib +from modflowapi.extensions.pakbase import ( + ArrayPackage, + ListPackage, + AdvancedPackage, +) +from modflowapi import Callbacks, run_simulation +import shutil +import numpy as np + +pytestmark = pytest.mark.extensions +so = "libmf6" +data_pth = pathlib.Path("../examples/data") + + +def test_dis_model(tmpdir): + def callback(sim, step): + """ + Callback function + + Parameters + ---------- + sim : modflowapi.ApiSimulation object + step : Enum + step is the simulation step defined by Callbacks + """ + if step == Callbacks.initialize: + if len(sim.models) != 1: + raise AssertionError("Invalid number of models") + + model = sim.test_model + if len(model.package_names) != 16: + raise AssertionError("Invalid number of packages") + + if len(model.package_types) != 15: + raise AssertionError("Invalid number of package types") + + if model.shape != (1, 10, 10): + raise AssertionError("ApiModel shape is incorrect") + + if model.size != 100: + raise AssertionError("ApiModel size is incorrect") + + if (model.kper, model.kstp) != (-1, -1): + raise AssertionError( + "ApiModel has advanced prior to initialization callback" + ) + + dis = model.dis + if not isinstance(dis, ArrayPackage): + raise TypeError("DIS package has incorrect base class type") + + wel = model.wel + if not isinstance(wel, ListPackage): + raise TypeError("WEL package has incorrect base class type") + + gnc = model.gnc + if not isinstance(gnc, AdvancedPackage): + raise TypeError("GNC package has incorrect base class type") + + rch = model.rch + if len(rch) != 2: + raise AssertionError( + "ApiModel object not returning multiple packages" + ) + + idomain = dis.idomain.values + if not isinstance(idomain, np.ndarray): + raise TypeError("Expecting a numpy array for idomain") + + elif step == Callbacks.stress_period_start: + if sim.kstp != 0: + raise AssertionError( + "Solution advanced prior to stress_period_start callback" + ) + + elif step == Callbacks.timestep_start: + if sim.iteration != -1: + raise AssertionError( + "Solution advanced prior to timestep_start callback" + ) + + factor = ((1 + sim.kstp) / sim.nstp) * 0.5 + spd = sim.test_model.wel.stress_period_data.values + sim.test_model.wel.stress_period_data["flux"] *= factor + + spd2 = sim.test_model.wel.stress_period_data.values + if not np.allclose((spd["flux"] * factor), spd2["flux"]): + raise AssertionError("Pointer not being set properly") + + if sim.kper >= 3 and sim.kstp == 0: + spd = sim.test_model.wel.stress_period_data.values + nbound0 = sim.test_model.wel.nbound + spd.resize((nbound0 + 1), refcheck=False) + spd[-1] = ((0, 1, 5), -20, 1.0, 2.0) + sim.test_model.wel.stress_period_data.values = spd + if sim.test_model.wel.nbound != nbound0 + 1: + raise AssertionError("Resize routine not properly working") + + name = "dis_model" + sim_pth = data_pth / name + test_pth = tmpdir / name + shutil.copytree(sim_pth, test_pth, dirs_exist_ok=True) + + try: + run_simulation(so, test_pth, callback) + except Exception as e: + raise Exception(e) + + +def test_disv_model(tmpdir): + def callback(sim, step): + """ + Callback function + + Parameters + ---------- + sim : modflowapi.ApiSimulation object + step : Enum + step is the simulation step defined by Callbacks + """ + if step == Callbacks.initialize: + if len(sim.models) != 1: + raise AssertionError("Invalid number of models") + + model = sim.gwf_1 + if len(model.package_names) != 12: + raise AssertionError("Invalid number of packages") + + if len(model.package_types) != 11: + raise AssertionError("Invalid number of package types") + + if model.shape != (4, 200): + raise AssertionError("ApiModel shape is incorrect") + + if model.size != 800: + raise AssertionError("ApiModel size is incorrect") + + if (model.kper, model.kstp) != (-1, -1): + raise AssertionError( + "ApiModel has advanced prior to initialization callback" + ) + + dis = model.dis + if not isinstance(dis, ArrayPackage): + raise TypeError("DIS package has incorrect base class type") + + chd = model.chd_left + if not isinstance(chd, ListPackage): + raise TypeError("CHD package has incorrect base class type") + + hfb = model.hfb + if not isinstance(hfb, AdvancedPackage): + raise TypeError("HFB package has incorrect base class type") + + chd = model.chd + if len(chd) != 2: + raise AssertionError( + "ApiModel object not returning multiple packages" + ) + + top = dis.top.values + if not isinstance(top, np.ndarray): + raise TypeError("Expecting a numpy array for top") + + elif step == Callbacks.stress_period_start: + if sim.kstp != 0: + raise AssertionError( + "Solution advanced prior to stress_period_start callback" + ) + + elif step == Callbacks.timestep_start: + if sim.iteration != -1: + raise AssertionError( + "Solution advanced prior to timestep_start callback" + ) + + factor = 0.75 + spd = sim.gwf_1.chd_left.stress_period_data.values + sim.gwf_1.chd_left.stress_period_data["head"] *= factor + + spd2 = sim.gwf_1.chd_left.stress_period_data.values + if not np.allclose((spd["head"] * factor), spd2["head"]): + raise AssertionError("Pointer not being set properly") + + name = "disv_model" + sim_pth = data_pth / name + test_pth = tmpdir / name + shutil.copytree(sim_pth, test_pth, dirs_exist_ok=True) + + try: + run_simulation(so, test_pth, callback) + except Exception as e: + raise Exception(e) + + +def test_disu_model(tmpdir): + def callback(sim, step): + """ + Callback function + + Parameters + ---------- + sim : modflowapi.ApiSimulation object + step : Enum + step is the simulation step defined by Callbacks + """ + if step == Callbacks.initialize: + if len(sim.models) != 1: + raise AssertionError("Invalid number of models") + + model = sim.gwf_1 + if len(model.package_names) != 12: + raise AssertionError("Invalid number of packages") + + if len(model.package_types) != 12: + raise AssertionError("Invalid number of package types") + + if model.shape != (121,): + raise AssertionError("ApiModel shape is incorrect") + + if model.size != 121: + raise AssertionError("ApiModel size is incorrect") + + if (model.kper, model.kstp) != (-1, -1): + raise AssertionError( + "ApiModel has advanced prior to initialization callback" + ) + + dis = model.dis + if not isinstance(dis, ArrayPackage): + raise TypeError("DIS package has incorrect base class type") + + rch = model.rch + if not isinstance(rch, ListPackage): + raise TypeError("RCH package has incorrect base class type") + + mvr = model.mvr + if not isinstance(mvr, AdvancedPackage): + raise TypeError("MVR package has incorrect base class type") + + top = dis.top.values + if not isinstance(top, np.ndarray): + raise TypeError("Expecting a numpy array for top") + + elif step == Callbacks.stress_period_start: + if sim.kstp != 0: + raise AssertionError( + "Solution advanced prior to stress_period_start callback" + ) + + elif step == Callbacks.timestep_start: + if sim.iteration != -1: + raise AssertionError( + "Solution advanced prior to timestep_start callback" + ) + + factor = 1.75 + spd = sim.gwf_1.rch.stress_period_data.values + sim.gwf_1.rch.stress_period_data["recharge"] += factor + + spd2 = sim.gwf_1.rch.stress_period_data.values + if not np.allclose((spd["recharge"] + factor), spd2["recharge"]): + raise AssertionError("Pointer not being set properly") + + name = "disu_model" + sim_pth = data_pth / name + test_pth = tmpdir / name + shutil.copytree(sim_pth, test_pth, dirs_exist_ok=True) + + try: + run_simulation(so, test_pth, callback) + except Exception as e: + raise Exception(e) + + +def test_two_models(tmpdir): + def callback(sim, step): + """ + Callback function + + Parameters + ---------- + sim : modflowapi.ApiSimulation object + step : Enum + step is the simulation step defined by Callbacks + """ + if step == Callbacks.initialize: + if len(sim.models) != 2: + raise AssertionError("Invalid number of models") + + name = "two_models" + sim_pth = data_pth / name + test_pth = tmpdir / name + shutil.copytree(sim_pth, test_pth, dirs_exist_ok=True) + + try: + run_simulation(so, test_pth, callback) + except Exception as e: + raise Exception(e) + + +def test_ats_model(tmpdir): + def callback(sim, step): + if step == Callbacks.stress_period_start: + if sim.kper == 0 and sim.kstp == 0: + delt0 = sim.delt + + if step == Callbacks.timestep_start: + if sim.kstp == 1: + if delt0 == sim.delt: + raise AssertionError( + "ATS routines not reducing timestep length" + ) + + name = "ats0" + sim_pth = data_pth / name + test_pth = tmpdir / name + shutil.copytree(sim_pth, test_pth, dirs_exist_ok=True) + + try: + run_simulation(so, test_pth, callback) + except Exception as e: + raise Exception(e) diff --git a/autotest/test_mf6_examples.py b/autotest/test_mf6_examples.py index f2f5634..72c89d2 100644 --- a/autotest/test_mf6_examples.py +++ b/autotest/test_mf6_examples.py @@ -1,53 +1,53 @@ -from pathlib import Path -from shutil import copytree -from modflowapi import run_simulation - -import pytest -from autotest.conftest import is_nested - -pytestmark = pytest.mark.mf6 -dll = "libmf6" - - -def test_mf6_example_simulations(tmpdir, mf6_example_namfiles): - """ - MF6 examples parametrized by simulation. `mf6_example_namfiles` is a list - of models to run in order provided. Coupled models share the same tempdir - - Parameters - ---------- - tmpdir: function-scoped temporary directory fixture - mf6_example_namfiles: ordered list of namfiles for 1+ coupled models - """ - if len(mf6_example_namfiles) == 0: - pytest.skip("No namfiles (expected ordered collection)") - namfile = Path(mf6_example_namfiles[0]) - - nested = is_nested(namfile) - tmpdir = Path( - tmpdir / "workspace" - ) - - copytree( - src=namfile.parent.parent if nested else namfile.parent, dst=tmpdir - ) - - def callback(sim, step): - pass - - def run_models(): - # run models in order received (should be alphabetical, so gwf precedes gwt) - for namfile in mf6_example_namfiles: - namfile_path = Path(namfile).resolve() - namfile_name = namfile_path.name - model_path = namfile_path.parent - - # working directory must be named according to the name file's parent (e.g. - # 'mf6gwf') because coupled models refer to each other with relative paths - wrkdir = Path(tmpdir / model_path.name) if nested else tmpdir - try: - run_simulation(dll, wrkdir, callback, verbose=True) - except Exception as e: - raise Exception(e) - - run_models() +from pathlib import Path +from shutil import copytree +from modflowapi import run_simulation + +import pytest +from autotest.conftest import is_nested + +pytestmark = pytest.mark.mf6 +dll = "libmf6" + + +def test_mf6_example_simulations(tmpdir, mf6_example_namfiles): + """ + MF6 examples parametrized by simulation. `mf6_example_namfiles` is a list + of models to run in order provided. Coupled models share the same tempdir + + Parameters + ---------- + tmpdir: function-scoped temporary directory fixture + mf6_example_namfiles: ordered list of namfiles for 1+ coupled models + """ + if len(mf6_example_namfiles) == 0: + pytest.skip("No namfiles (expected ordered collection)") + namfile = Path(mf6_example_namfiles[0]) + + nested = is_nested(namfile) + tmpdir = Path( + tmpdir / "workspace" + ) + + copytree( + src=namfile.parent.parent if nested else namfile.parent, dst=tmpdir + ) + + def callback(sim, step): + pass + + def run_models(): + # run models in order received (should be alphabetical, so gwf precedes gwt) + for namfile in mf6_example_namfiles: + namfile_path = Path(namfile).resolve() + namfile_name = namfile_path.name + model_path = namfile_path.parent + + # working directory must be named according to the name file's parent (e.g. + # 'mf6gwf') because coupled models refer to each other with relative paths + wrkdir = Path(tmpdir / model_path.name) if nested else tmpdir + try: + run_simulation(dll, wrkdir, callback, verbose=True) + except Exception as e: + raise Exception(e) + + run_models() diff --git a/modflowapi/extensions/__init__.py b/modflowapi/extensions/__init__.py index 347b259..9fa55e0 100644 --- a/modflowapi/extensions/__init__.py +++ b/modflowapi/extensions/__init__.py @@ -1,3 +1,3 @@ -from .apisimulation import ApiSimulation -from .apimodel import ApiModel -from .apiexchange import ApiExchange +from .apisimulation import ApiSimulation +from .apimodel import ApiModel +from .apiexchange import ApiExchange diff --git a/modflowapi/extensions/apiexchange.py b/modflowapi/extensions/apiexchange.py index 226b3b1..46de560 100644 --- a/modflowapi/extensions/apiexchange.py +++ b/modflowapi/extensions/apiexchange.py @@ -1,20 +1,20 @@ -from .pakbase import ListPackage -from .apimodel import ApiMbase - - -class ApiExchange(ApiMbase): - """ - ApiExchange class for GWF-GWF packages and container to access the - simulation level GWF-GWF, MVR, and GNC packages - - Parameters - ---------- - mf6 : ModflowApi - initialized ModflowApi object - name : str - modflow exchange name. ex. "GWF-GWF_1" - """ - - def __init__(self, mf6, name): - pkg_types = {"gwf-gwf": ListPackage, "gwt-gwt": ListPackage} - super().__init__(mf6, name, pkg_types) +from .pakbase import ListPackage +from .apimodel import ApiMbase + + +class ApiExchange(ApiMbase): + """ + ApiExchange class for GWF-GWF packages and container to access the + simulation level GWF-GWF, MVR, and GNC packages + + Parameters + ---------- + mf6 : ModflowApi + initialized ModflowApi object + name : str + modflow exchange name. ex. "GWF-GWF_1" + """ + + def __init__(self, mf6, name): + pkg_types = {"gwf-gwf": ListPackage, "gwt-gwt": ListPackage} + super().__init__(mf6, name, pkg_types) diff --git a/modflowapi/extensions/apimodel.py b/modflowapi/extensions/apimodel.py index a606641..16086ec 100644 --- a/modflowapi/extensions/apimodel.py +++ b/modflowapi/extensions/apimodel.py @@ -1,383 +1,383 @@ -from .pakbase import ( - AdvancedPackage, - ArrayPackage, - ListPackage, - package_factory, -) -import numpy as np - - -gridshape = { - "dis": ["nlay", "nrow", "ncol"], - "disu": [ - "nlay", - "ncpl", - ], -} - - -class ApiMbase: - """ - Base object for the Models and Exchanges - - Parameters - ---------- - mf6 : ModflowApi - initialized ModflowApi object - name : str - modflow model name. ex. "GWF_1", "GWF-GWF_1" - pkg_types : dict - dictionary of package types and ApiPackage class types - """ - - def __init__(self, mf6, name, pkg_types): - self.mf6 = mf6 - self.name = name - self._pkg_names = None - self._pak_type = None - self.pkg_types = pkg_types - self.package_dict = {} - self._set_package_names() - self._create_package_list() - - @property - def package_list(self): - """ - Returns a list of package objects for the model - """ - return [package for _, package in self.package_dict.items()] - - @property - def package_names(self): - """ - Returns a list of package names for the model - """ - return list(self.package_dict.keys()) - - @property - def package_types(self): - return list(set([package.pkg_type for package in self.package_list])) - - def _set_package_names(self): - """ - Method to get/set all package names within the model - """ - pak_types = {"dis": "DIS"} - for addr in self.mf6.get_input_var_names(): - tmp = addr.split("/") - if addr.endswith("PACKAGE_TYPE") and tmp[0] == self.name: - pak_types[tmp[1]] = self.mf6.get_value(addr)[0] - elif tmp[0] == self.name and len(tmp) == 2: - if tmp[0].startswith("GWF-GWF"): - pak_types[tmp[0]] = "GWF-GWF" - pak_types.pop("dis", None) - elif tmp[0].startswith("GWT-GWT"): - pak_types[tmp[0]] = "GWT-GWT" - pak_types.pop("dis", None) - - self._pak_type = list(pak_types.values()) - self._pkg_names = list(pak_types.keys()) - - def _create_package_list(self): - """ - Method to load packages and set up the package dict/list variable - """ - for ix, pkg_name in enumerate(self._pkg_names): - pkg_type = self._pak_type[ix].lower() - if pkg_type in self.pkg_types: - basepackage = self.pkg_types[pkg_type] - else: - basepackage = AdvancedPackage - - package = package_factory(pkg_type, basepackage) - adj_pkg_name = "".join(pkg_type.split("-")) - - if adj_pkg_name.lower() in ("gwfgwf", "gwtgwt"): - adj_pkg_name = "" - else: - adj_pkg_name = pkg_name - - package = package(basepackage, self, pkg_type, adj_pkg_name) - self.package_dict[pkg_name.lower()] = package - - def get_package( - self, pkg_name - ) -> ListPackage or ArrayPackage or AdvancedPackage: - """ - Method to get a package - - Parameters - ---------- - pkg_name : str - package name str. Ex. "wel_0" - """ - pkg_name = pkg_name.lower() - if pkg_name in self.package_dict: - return self.package_dict[pkg_name] - - raise KeyError( - f"{pkg_name} is not a valid package name for this model" - ) - - -class ApiModel(ApiMbase): - """ - Container to hold MODFLOW model information and load supported packages - - Parameters - ---------- - mf6 : ModflowApi - initialized ModflowApi object - name : str - modflow model name. ex. "GWF_1" - - """ - - def __init__(self, mf6, name): - _id_addr = mf6.get_var_address("ID", name) - self._id = mf6.get_value(_id_addr)[0] - if self._id < 1: - self._id = 1 - _solnid = mf6.get_var_address("IDSOLN", name) - self._solnid = mf6.get_value(_solnid)[0] - grid_type = mf6.get_grid_type(self._id) - if grid_type == "rectilinear": - self.dis_type = "dis" - self.dis_name = "DIS" - elif grid_type == "unstructured": - self.dis_type = "disu" - self.dis_name = "DIS" - else: - raise AssertionError( - f"Unrecognized discretization type {grid_type}" - ) - - pkg_types = { - "dis": ArrayPackage, - "chd": ListPackage, - "drn": ListPackage, - "evt": ListPackage, - "ghb": ListPackage, - "ic": ArrayPackage, - "npf": ArrayPackage, - "rch": ListPackage, - "sto": ArrayPackage, - "wel": ListPackage, - # gwt - "adv": ArrayPackage, - "cnc": ListPackage, - "ist": ArrayPackage, - "mst": ArrayPackage, - "src": ListPackage, - } - - self.allow_convergence = True - self._shape = None - self._size = None - self._nodetouser = None - self._usertonode = None - self._iteration = 0 - - super().__init__(mf6, name, pkg_types) - - def __repr__(self): - s = f"{self.name}, " - shape = self.shape - if self.dis_type == "dis": - s += ( - f"{shape[0]} Layer, {shape[1]} Row, {shape[2]} " - f"Column model\n" - ) - - elif self.dis_type == "disu": - if len(shape) == 2: - s += f"{shape[0]} Layer, {shape[1]} Nodes per layer model\n" - else: - s += f"{shape[0]} Node model\n" - else: - pass - - s += "Packages accessible include: \n" - for typ, baseobj in [ - ("ArrayPackage", ArrayPackage), - ("ListPackage", ListPackage), - ("AdvancedPackage", AdvancedPackage), - ]: - s += f" {typ} objects:\n" - for name, obj in self.package_dict.items(): - if isinstance(obj, baseobj): - s += f" {name}: {type(obj)}\n" - - return s - - def __getattr__(self, item): - """ - Method for getting packages either by package name or by - package type name - - """ - if item in self.package_dict: - return self.package_dict[item] - else: - pkg_list = [] - for pkg_name, package in self.package_dict.items(): - if item == package.pkg_type: - pkg_list.append(package) - - if len(pkg_list) == 0: - return super().__getattribute__(item) - elif len(pkg_list) == 1: - return pkg_list[0] - else: - return pkg_list - - def __setattr__(self, key, value): - """ - Method for type checking variables - """ - if key == "allow_convergence": - if not isinstance(value, bool): - raise TypeError("allow convergenge must be a boolean value") - - super().__setattr__(key, value) - - @property - def kper(self): - """ - Returns the current stress period - """ - var_addr = self.mf6.get_var_address("KPER", "TDIS") - return self.mf6.get_value(var_addr)[0] - 1 - - @property - def kstp(self): - """ - Returns the current timestep - """ - var_addr = self.mf6.get_var_address("KSTP", "TDIS") - return self.mf6.get_value(var_addr)[0] - 1 - - @property - def nstp(self): - """ - Returns the number of timesteps in the current stress period - """ - var_addr = self.mf6.get_var_address("NSTP", "TDIS") - return self.mf6.get_value(var_addr)[0] - - @property - def nper(self): - """ - Returns the number of stress periods - """ - var_addr = self.mf6.get_var_address("NPER", "TDIS") - return self.mf6.get_value(var_addr)[0] - - @property - def totim(self): - """ - Returns the current model time - """ - var_addr = self.mf6.get_var_address("TOTIM", "TDIS") - return self.mf6.get_value(var_addr)[0] - - @property - def subcomponent_id(self): - """ - Returns the model subcomponent id - """ - return self._id - - @property - def solution_id(self): - """ - Returns the model solution id - """ - return self._solnid - - @property - def shape(self): - """ - Returns a tuple of the model shape - """ - ivn = self.mf6.get_input_var_names() - if self._shape is None: - shape_vars = gridshape[self.dis_type] - shape = [] - for var in shape_vars: - var_addr = self.mf6.get_var_address( - var.upper(), self.name, self.dis_name - ) - if var_addr in ivn: - shape.append(self.mf6.get_value(var_addr)[0]) - if not shape: - var_addr = self.mf6.get_var_address( - "NODES", self.name, self.dis_name - ) - shape.append(self.mf6.get_value(var_addr)[0]) - self._shape = tuple(shape) - return self._shape - - @property - def size(self): - """ - Returns the number of nodes in the model - """ - if self._size is None: - size = 1 - for dim in self.shape: - size *= dim - self._size = size - return self._size - - @property - def nodetouser(self): - """ - Returns the "nodeuser" array - """ - if self._nodetouser is None: - self._set_node_mapping() - return self._nodetouser - - @property - def usertonode(self): - """ - Returns an array that maps user arrays to modflow's internal nodes - """ - if self._usertonode is None: - self._set_node_mapping() - return self._usertonode - - @property - def X(self): - """ - Returns the solution array. Ex. GFW models return heads, GWT - returns a concentration array, etc... - """ - x = self.mf6.get_value(self.mf6.get_var_address("X", self.name)) - array = np.full(self.size, np.nan) - array[self.nodetouser] = x - return array.reshape(self.shape) - - def _set_node_mapping(self): - """ - Sets the node mapping arrays NODEUSER and NODEREDUCED for mapping - user arrays to modflow's internal arrays - """ - node_addr = self.mf6.get_var_address("NODES", self.name, self.dis_name) - nodes = self.mf6.get_value(node_addr) - if nodes[0] == self.size: - nodeuser = np.arange(nodes).astype(int) - nodereduced = np.copy(nodeuser) - else: - nodeuser_addr = self.mf6.get_var_address( - "NODEUSER", self.name, self.dis_name - ) - nodeuser = self.mf6.get_value(nodeuser_addr) - 1 - nodereduced_addr = self.mf6.get_var_address( - "NODEREDUCED", self.name, self.dis_name - ) - nodereduced = self.mf6.get_value(nodereduced_addr) - 1 - - self._nodetouser = nodeuser - self._usertonode = nodereduced +from .pakbase import ( + AdvancedPackage, + ArrayPackage, + ListPackage, + package_factory, +) +import numpy as np + + +gridshape = { + "dis": ["nlay", "nrow", "ncol"], + "disu": [ + "nlay", + "ncpl", + ], +} + + +class ApiMbase: + """ + Base object for the Models and Exchanges + + Parameters + ---------- + mf6 : ModflowApi + initialized ModflowApi object + name : str + modflow model name. ex. "GWF_1", "GWF-GWF_1" + pkg_types : dict + dictionary of package types and ApiPackage class types + """ + + def __init__(self, mf6, name, pkg_types): + self.mf6 = mf6 + self.name = name + self._pkg_names = None + self._pak_type = None + self.pkg_types = pkg_types + self.package_dict = {} + self._set_package_names() + self._create_package_list() + + @property + def package_list(self): + """ + Returns a list of package objects for the model + """ + return [package for _, package in self.package_dict.items()] + + @property + def package_names(self): + """ + Returns a list of package names for the model + """ + return list(self.package_dict.keys()) + + @property + def package_types(self): + return list(set([package.pkg_type for package in self.package_list])) + + def _set_package_names(self): + """ + Method to get/set all package names within the model + """ + pak_types = {"dis": "DIS"} + for addr in self.mf6.get_input_var_names(): + tmp = addr.split("/") + if addr.endswith("PACKAGE_TYPE") and tmp[0] == self.name: + pak_types[tmp[1]] = self.mf6.get_value(addr)[0] + elif tmp[0] == self.name and len(tmp) == 2: + if tmp[0].startswith("GWF-GWF"): + pak_types[tmp[0]] = "GWF-GWF" + pak_types.pop("dis", None) + elif tmp[0].startswith("GWT-GWT"): + pak_types[tmp[0]] = "GWT-GWT" + pak_types.pop("dis", None) + + self._pak_type = list(pak_types.values()) + self._pkg_names = list(pak_types.keys()) + + def _create_package_list(self): + """ + Method to load packages and set up the package dict/list variable + """ + for ix, pkg_name in enumerate(self._pkg_names): + pkg_type = self._pak_type[ix].lower() + if pkg_type in self.pkg_types: + basepackage = self.pkg_types[pkg_type] + else: + basepackage = AdvancedPackage + + package = package_factory(pkg_type, basepackage) + adj_pkg_name = "".join(pkg_type.split("-")) + + if adj_pkg_name.lower() in ("gwfgwf", "gwtgwt"): + adj_pkg_name = "" + else: + adj_pkg_name = pkg_name + + package = package(basepackage, self, pkg_type, adj_pkg_name) + self.package_dict[pkg_name.lower()] = package + + def get_package( + self, pkg_name + ) -> ListPackage or ArrayPackage or AdvancedPackage: + """ + Method to get a package + + Parameters + ---------- + pkg_name : str + package name str. Ex. "wel_0" + """ + pkg_name = pkg_name.lower() + if pkg_name in self.package_dict: + return self.package_dict[pkg_name] + + raise KeyError( + f"{pkg_name} is not a valid package name for this model" + ) + + +class ApiModel(ApiMbase): + """ + Container to hold MODFLOW model information and load supported packages + + Parameters + ---------- + mf6 : ModflowApi + initialized ModflowApi object + name : str + modflow model name. ex. "GWF_1" + + """ + + def __init__(self, mf6, name): + _id_addr = mf6.get_var_address("ID", name) + self._id = mf6.get_value(_id_addr)[0] + if self._id < 1: + self._id = 1 + _solnid = mf6.get_var_address("IDSOLN", name) + self._solnid = mf6.get_value(_solnid)[0] + grid_type = mf6.get_grid_type(self._id) + if grid_type == "rectilinear": + self.dis_type = "dis" + self.dis_name = "DIS" + elif grid_type == "unstructured": + self.dis_type = "disu" + self.dis_name = "DIS" + else: + raise AssertionError( + f"Unrecognized discretization type {grid_type}" + ) + + pkg_types = { + "dis": ArrayPackage, + "chd": ListPackage, + "drn": ListPackage, + "evt": ListPackage, + "ghb": ListPackage, + "ic": ArrayPackage, + "npf": ArrayPackage, + "rch": ListPackage, + "sto": ArrayPackage, + "wel": ListPackage, + # gwt + "adv": ArrayPackage, + "cnc": ListPackage, + "ist": ArrayPackage, + "mst": ArrayPackage, + "src": ListPackage, + } + + self.allow_convergence = True + self._shape = None + self._size = None + self._nodetouser = None + self._usertonode = None + self._iteration = 0 + + super().__init__(mf6, name, pkg_types) + + def __repr__(self): + s = f"{self.name}, " + shape = self.shape + if self.dis_type == "dis": + s += ( + f"{shape[0]} Layer, {shape[1]} Row, {shape[2]} " + f"Column model\n" + ) + + elif self.dis_type == "disu": + if len(shape) == 2: + s += f"{shape[0]} Layer, {shape[1]} Nodes per layer model\n" + else: + s += f"{shape[0]} Node model\n" + else: + pass + + s += "Packages accessible include: \n" + for typ, baseobj in [ + ("ArrayPackage", ArrayPackage), + ("ListPackage", ListPackage), + ("AdvancedPackage", AdvancedPackage), + ]: + s += f" {typ} objects:\n" + for name, obj in self.package_dict.items(): + if isinstance(obj, baseobj): + s += f" {name}: {type(obj)}\n" + + return s + + def __getattr__(self, item): + """ + Method for getting packages either by package name or by + package type name + + """ + if item in self.package_dict: + return self.package_dict[item] + else: + pkg_list = [] + for pkg_name, package in self.package_dict.items(): + if item == package.pkg_type: + pkg_list.append(package) + + if len(pkg_list) == 0: + return super().__getattribute__(item) + elif len(pkg_list) == 1: + return pkg_list[0] + else: + return pkg_list + + def __setattr__(self, key, value): + """ + Method for type checking variables + """ + if key == "allow_convergence": + if not isinstance(value, bool): + raise TypeError("allow convergenge must be a boolean value") + + super().__setattr__(key, value) + + @property + def kper(self): + """ + Returns the current stress period + """ + var_addr = self.mf6.get_var_address("KPER", "TDIS") + return self.mf6.get_value(var_addr)[0] - 1 + + @property + def kstp(self): + """ + Returns the current timestep + """ + var_addr = self.mf6.get_var_address("KSTP", "TDIS") + return self.mf6.get_value(var_addr)[0] - 1 + + @property + def nstp(self): + """ + Returns the number of timesteps in the current stress period + """ + var_addr = self.mf6.get_var_address("NSTP", "TDIS") + return self.mf6.get_value(var_addr)[0] + + @property + def nper(self): + """ + Returns the number of stress periods + """ + var_addr = self.mf6.get_var_address("NPER", "TDIS") + return self.mf6.get_value(var_addr)[0] + + @property + def totim(self): + """ + Returns the current model time + """ + var_addr = self.mf6.get_var_address("TOTIM", "TDIS") + return self.mf6.get_value(var_addr)[0] + + @property + def subcomponent_id(self): + """ + Returns the model subcomponent id + """ + return self._id + + @property + def solution_id(self): + """ + Returns the model solution id + """ + return self._solnid + + @property + def shape(self): + """ + Returns a tuple of the model shape + """ + ivn = self.mf6.get_input_var_names() + if self._shape is None: + shape_vars = gridshape[self.dis_type] + shape = [] + for var in shape_vars: + var_addr = self.mf6.get_var_address( + var.upper(), self.name, self.dis_name + ) + if var_addr in ivn: + shape.append(self.mf6.get_value(var_addr)[0]) + if not shape: + var_addr = self.mf6.get_var_address( + "NODES", self.name, self.dis_name + ) + shape.append(self.mf6.get_value(var_addr)[0]) + self._shape = tuple(shape) + return self._shape + + @property + def size(self): + """ + Returns the number of nodes in the model + """ + if self._size is None: + size = 1 + for dim in self.shape: + size *= dim + self._size = size + return self._size + + @property + def nodetouser(self): + """ + Returns the "nodeuser" array + """ + if self._nodetouser is None: + self._set_node_mapping() + return self._nodetouser + + @property + def usertonode(self): + """ + Returns an array that maps user arrays to modflow's internal nodes + """ + if self._usertonode is None: + self._set_node_mapping() + return self._usertonode + + @property + def X(self): + """ + Returns the solution array. Ex. GFW models return heads, GWT + returns a concentration array, etc... + """ + x = self.mf6.get_value(self.mf6.get_var_address("X", self.name)) + array = np.full(self.size, np.nan) + array[self.nodetouser] = x + return array.reshape(self.shape) + + def _set_node_mapping(self): + """ + Sets the node mapping arrays NODEUSER and NODEREDUCED for mapping + user arrays to modflow's internal arrays + """ + node_addr = self.mf6.get_var_address("NODES", self.name, self.dis_name) + nodes = self.mf6.get_value(node_addr) + if nodes[0] == self.size: + nodeuser = np.arange(nodes).astype(int) + nodereduced = np.copy(nodeuser) + else: + nodeuser_addr = self.mf6.get_var_address( + "NODEUSER", self.name, self.dis_name + ) + nodeuser = self.mf6.get_value(nodeuser_addr) - 1 + nodereduced_addr = self.mf6.get_var_address( + "NODEREDUCED", self.name, self.dis_name + ) + nodereduced = self.mf6.get_value(nodereduced_addr) - 1 + + self._nodetouser = nodeuser + self._usertonode = nodereduced diff --git a/modflowapi/extensions/apisimulation.py b/modflowapi/extensions/apisimulation.py index 282e459..5d96dde 100644 --- a/modflowapi/extensions/apisimulation.py +++ b/modflowapi/extensions/apisimulation.py @@ -1,353 +1,353 @@ -from .apimodel import ApiMbase, ApiModel -from .apiexchange import ApiExchange -from .pakbase import ApiSlnPackage, ListPackage, ScalarPackage, package_factory -import numpy as np - - -class ApiSimulation: - """ - ApiSimulation object that holds a modflow simulation info and loads - supported models. - - Parameters - ---------- - mf6 : ModflowApi - initialized ModflowApi object - models : dict - dictionary of model_name: modflowapi.extensions.ApiModel objects - solutions : dict - dictionary of solution_id: solution_name - exchanges : dict - dictoinary of exchange_name: modflowapi.extensions.ApiExchange objects - tdis : ApiTdisPackage - time discretization (TDIS) ScalarPackage - ats : None or ApiAtsPackage - adaptive time step ScalarPackage object - """ - - def __init__(self, mf6, models, solutions, exchanges, tdis, ats): - self.mf6 = mf6 - self._models = models - self._exchanges = exchanges - self._solutions = solutions - self._iteration = -1 - - self.tdis = tdis - self.ats = ats - self._ats_active = True - if ats is None: - self._ats_active = False - - def __getattr__(self, item): - """ - Dynamic method to get models by model name - """ - if item.lower() in self._models: - return self.get_model(item) - else: - return super().__getattribute__(item) - - def __repr__(self): - s = self.__doc__ - s += f"Number of models: {len(self._models)}:\n" - for name, obj in self._models.items(): - s += f"\t{name} : {type(obj)}\n" - s += f"Simulation level packages include:\n" - s += f"\tSLN: {self.sln}\n" - s += f"\tTDIS: {self.tdis}\n" - if self.ats_active: - s += f"\tATS: {self.ats}\n" - if self._exchanges: - s += f"\tExchanges include:\n" - for name, exchange in self._exchanges.items(): - f"\t\t{name}: {type(exchange)}\n" - - return s - - @property - def ats_active(self): - """ - Returns a boolean to indicate if the ATS package is used in this - simulation. - """ - return self._ats_active - - @property - def ats_period(self): - """ - Returns a boolean to indicate if this is an ATS stress period - """ - # maybe return tuple (bool, dtmin) - if self.ats_active: - recarray = self.ats.stress_period_data.values - idx = np.where(recarray["iperats"] == self.kper + 1)[0] - if len(idx) > 0: - return True, recarray["dtmin"][idx[0]] - - return False, None - - @property - def allow_convergence(self): - """ - Returns a boolean value that specifies if the user will allow the - model to converge. Default is True - """ - for model in self.models: - if not model.allow_convergence: - return False - return True - - @allow_convergence.setter - def allow_convergence(self, value): - """ - Method to set the allow_convergence flag - - Parameters - ---------- - value : bool - if True (default) model converges if solution converges, if False - model will continue solving after solution converges. - """ - for model in self.models: - model.allow_convergence = value - - @property - def subcomponent_count(self): - """ - Returns the number of subcomponents in the simulation - """ - return self.mf6.get_subcomponent_count() - - @property - def solutions(self): - """ - Returns a dictionary of solution_id : (name, ApiSlnPackage) - """ - return self._solutions - - @property - def sln(self): - """ - Returns an ApiSolution object - """ - if len(self._solutions) > 1: - return list(self._solutions.values()) - else: - for sln in self._solutions.values(): - return sln - - @property - def model_names(self): - """ - Returns a list of model names - """ - return list(self._models.keys()) - - @property - def exchange_names(self): - """ - Returns a list of exchange GWF-GWF names - """ - if self._exchanges.keys(): - return list(self._exchanges.keys()) - - @property - def models(self): - """ - Returns a list of ApiModel objects associated with the simulation - """ - return [v for _, v in self._models.items()] - - @property - def iteration(self): - return self._iteration - - @iteration.setter - def iteration(self, value): - if isinstance(value, int): - self._iteration = value - - @property - def kper(self): - """ - Returns the current stress period - """ - return self.tdis.kper - 1 - - @property - def kstp(self): - """ - Returns the current time step - """ - return self.tdis.kstp - 1 - - @property - def nstp(self): - """ - Returns the total number of time steps - """ - return self.tdis.nstp - - @property - def nper(self): - """ - Returns the total number of stress periods - """ - return self.tdis.nper - - @property - def totim(self): - """ - Returns the current model time - """ - return self.tdis.totim - - @property - def delt(self): - """ - Returns the timestep length for the current time step - """ - return self.tdis.delt - - def get_model(self, model_id=None): - """ - Method to get a model from the simulation object by model name or - subcomponent id - - Parameters - ---------- - model_id : str, int - model name (ex. "GWF_1") or subcomponent id (ex. 1) - """ - if model_id is None: - model_id = int( - min([model.subcomponent_id for model in self.models]) - ) - - if isinstance(model_id, int): - for model in self.models: - if model_id == model.subcomponent_id: - return model - raise KeyError(f"No model found with subcomponent id {model_id}") - - elif isinstance(model_id, str): - model_id = model_id.lower() - if model_id in self._models: - return self._models[model_id] - raise KeyError(f"Model name {model_id} is invalid") - - else: - raise TypeError("A string or int must be supplied to get model") - - def get_exchange(self, exchange_name=None): - """ - Get a GWF-GWF "model" and all associated simulation level package - data (ex. GNC, MVR) - - Parameters - ---------- - exchange_name : str - name of the GWF-GWF exchange package - - Returns - ------- - modflowapi.extensions.ApiExchange object - """ - if self.exchange_names is None: - raise AssertionError("No exchanges are present in this simulation") - - if exchange_name is None: - for _, exg in self._exchanges: - return exg - - else: - if exchange_name in self._exchanges: - return self._exchanges[exchange_name] - raise KeyError(f"Exchange name {exchange_name} is invalid") - - @staticmethod - def load(mf6): - """ - Method to load a modflowapi instance into the ApiSimulation extensions - - Parameters - ---------- - mf6 : ModflowApi - initialized ModflowApi object - """ - variables = mf6.get_input_var_names() - model_names = [] - for variable in variables: - t = variable.split("/") - if len(t) == 3: - name = t[0] - id_var_addr = mf6.get_var_address("ID", name) - if name.startswith("SLN"): - continue - if id_var_addr not in variables: - continue - - if name not in model_names: - model_names.append(name) - - models = {} - for name in model_names: - models[name.lower()] = ApiModel(mf6, name) - - solution_names = [] - for variable in variables: - t = variable.split("/") - if len(t) == 2: - name = t[0] - id_var_addr = mf6.get_var_address("ID", name) - if name.lower() in models or name == "TDIS": - continue - if id_var_addr not in variables: - continue - - solution_names.append(t[0]) - - tmpmdl = ApiMbase(mf6, "", {}) - solution_names = list(set(solution_names)) - solution_dict = {} - for name in solution_names: - sid_var_addr = mf6.get_var_address("ID", name) - sid = mf6.get_value(sid_var_addr)[0] - sln = ApiSlnPackage(tmpmdl, name) - solution_dict[sid] = sln - - solutions = solution_dict - - # TDIS package construction - tdis_constructor = package_factory("tdis", ScalarPackage) - tdis = tdis_constructor( - ScalarPackage, tmpmdl, "tdis", "tdis", sim_package=True - ) - - ats = None - # ATS package construction - for variable in variables: - if variable.startswith("ATS"): - ats_constructor = package_factory("ats", ListPackage) - ats = ats_constructor( - ListPackage, tmpmdl, "ats", "ats", sim_package=True - ) - break - - # get the exchanges - exchange_names = [] - for variable in variables: - if variable.startswith("GWF-GWF") or variable.startswith( - "GWT-GWT" - ): - exchange_name = variable.split("/")[0] - if exchange_name not in exchange_names: - exchange_names.append(exchange_name) - - # sim_packages: tdis, gwf-gwf, sln - exchanges = {} - for exchange_name in exchanges: - exchange = ApiExchange(mf6, exchange_name) - exchanges[exchange_name.lower()] = exchange - - return ApiSimulation(mf6, models, solutions, exchanges, tdis, ats) +from .apimodel import ApiMbase, ApiModel +from .apiexchange import ApiExchange +from .pakbase import ApiSlnPackage, ListPackage, ScalarPackage, package_factory +import numpy as np + + +class ApiSimulation: + """ + ApiSimulation object that holds a modflow simulation info and loads + supported models. + + Parameters + ---------- + mf6 : ModflowApi + initialized ModflowApi object + models : dict + dictionary of model_name: modflowapi.extensions.ApiModel objects + solutions : dict + dictionary of solution_id: solution_name + exchanges : dict + dictoinary of exchange_name: modflowapi.extensions.ApiExchange objects + tdis : ApiTdisPackage + time discretization (TDIS) ScalarPackage + ats : None or ApiAtsPackage + adaptive time step ScalarPackage object + """ + + def __init__(self, mf6, models, solutions, exchanges, tdis, ats): + self.mf6 = mf6 + self._models = models + self._exchanges = exchanges + self._solutions = solutions + self._iteration = -1 + + self.tdis = tdis + self.ats = ats + self._ats_active = True + if ats is None: + self._ats_active = False + + def __getattr__(self, item): + """ + Dynamic method to get models by model name + """ + if item.lower() in self._models: + return self.get_model(item) + else: + return super().__getattribute__(item) + + def __repr__(self): + s = self.__doc__ + s += f"Number of models: {len(self._models)}:\n" + for name, obj in self._models.items(): + s += f"\t{name} : {type(obj)}\n" + s += f"Simulation level packages include:\n" + s += f"\tSLN: {self.sln}\n" + s += f"\tTDIS: {self.tdis}\n" + if self.ats_active: + s += f"\tATS: {self.ats}\n" + if self._exchanges: + s += f"\tExchanges include:\n" + for name, exchange in self._exchanges.items(): + f"\t\t{name}: {type(exchange)}\n" + + return s + + @property + def ats_active(self): + """ + Returns a boolean to indicate if the ATS package is used in this + simulation. + """ + return self._ats_active + + @property + def ats_period(self): + """ + Returns a boolean to indicate if this is an ATS stress period + """ + # maybe return tuple (bool, dtmin) + if self.ats_active: + recarray = self.ats.stress_period_data.values + idx = np.where(recarray["iperats"] == self.kper + 1)[0] + if len(idx) > 0: + return True, recarray["dtmin"][idx[0]] + + return False, None + + @property + def allow_convergence(self): + """ + Returns a boolean value that specifies if the user will allow the + model to converge. Default is True + """ + for model in self.models: + if not model.allow_convergence: + return False + return True + + @allow_convergence.setter + def allow_convergence(self, value): + """ + Method to set the allow_convergence flag + + Parameters + ---------- + value : bool + if True (default) model converges if solution converges, if False + model will continue solving after solution converges. + """ + for model in self.models: + model.allow_convergence = value + + @property + def subcomponent_count(self): + """ + Returns the number of subcomponents in the simulation + """ + return self.mf6.get_subcomponent_count() + + @property + def solutions(self): + """ + Returns a dictionary of solution_id : (name, ApiSlnPackage) + """ + return self._solutions + + @property + def sln(self): + """ + Returns an ApiSolution object + """ + if len(self._solutions) > 1: + return list(self._solutions.values()) + else: + for sln in self._solutions.values(): + return sln + + @property + def model_names(self): + """ + Returns a list of model names + """ + return list(self._models.keys()) + + @property + def exchange_names(self): + """ + Returns a list of exchange GWF-GWF names + """ + if self._exchanges.keys(): + return list(self._exchanges.keys()) + + @property + def models(self): + """ + Returns a list of ApiModel objects associated with the simulation + """ + return [v for _, v in self._models.items()] + + @property + def iteration(self): + return self._iteration + + @iteration.setter + def iteration(self, value): + if isinstance(value, int): + self._iteration = value + + @property + def kper(self): + """ + Returns the current stress period + """ + return self.tdis.kper - 1 + + @property + def kstp(self): + """ + Returns the current time step + """ + return self.tdis.kstp - 1 + + @property + def nstp(self): + """ + Returns the total number of time steps + """ + return self.tdis.nstp + + @property + def nper(self): + """ + Returns the total number of stress periods + """ + return self.tdis.nper + + @property + def totim(self): + """ + Returns the current model time + """ + return self.tdis.totim + + @property + def delt(self): + """ + Returns the timestep length for the current time step + """ + return self.tdis.delt + + def get_model(self, model_id=None): + """ + Method to get a model from the simulation object by model name or + subcomponent id + + Parameters + ---------- + model_id : str, int + model name (ex. "GWF_1") or subcomponent id (ex. 1) + """ + if model_id is None: + model_id = int( + min([model.subcomponent_id for model in self.models]) + ) + + if isinstance(model_id, int): + for model in self.models: + if model_id == model.subcomponent_id: + return model + raise KeyError(f"No model found with subcomponent id {model_id}") + + elif isinstance(model_id, str): + model_id = model_id.lower() + if model_id in self._models: + return self._models[model_id] + raise KeyError(f"Model name {model_id} is invalid") + + else: + raise TypeError("A string or int must be supplied to get model") + + def get_exchange(self, exchange_name=None): + """ + Get a GWF-GWF "model" and all associated simulation level package + data (ex. GNC, MVR) + + Parameters + ---------- + exchange_name : str + name of the GWF-GWF exchange package + + Returns + ------- + modflowapi.extensions.ApiExchange object + """ + if self.exchange_names is None: + raise AssertionError("No exchanges are present in this simulation") + + if exchange_name is None: + for _, exg in self._exchanges: + return exg + + else: + if exchange_name in self._exchanges: + return self._exchanges[exchange_name] + raise KeyError(f"Exchange name {exchange_name} is invalid") + + @staticmethod + def load(mf6): + """ + Method to load a modflowapi instance into the ApiSimulation extensions + + Parameters + ---------- + mf6 : ModflowApi + initialized ModflowApi object + """ + variables = mf6.get_input_var_names() + model_names = [] + for variable in variables: + t = variable.split("/") + if len(t) == 3: + name = t[0] + id_var_addr = mf6.get_var_address("ID", name) + if name.startswith("SLN"): + continue + if id_var_addr not in variables: + continue + + if name not in model_names: + model_names.append(name) + + models = {} + for name in model_names: + models[name.lower()] = ApiModel(mf6, name) + + solution_names = [] + for variable in variables: + t = variable.split("/") + if len(t) == 2: + name = t[0] + id_var_addr = mf6.get_var_address("ID", name) + if name.lower() in models or name == "TDIS": + continue + if id_var_addr not in variables: + continue + + solution_names.append(t[0]) + + tmpmdl = ApiMbase(mf6, "", {}) + solution_names = list(set(solution_names)) + solution_dict = {} + for name in solution_names: + sid_var_addr = mf6.get_var_address("ID", name) + sid = mf6.get_value(sid_var_addr)[0] + sln = ApiSlnPackage(tmpmdl, name) + solution_dict[sid] = sln + + solutions = solution_dict + + # TDIS package construction + tdis_constructor = package_factory("tdis", ScalarPackage) + tdis = tdis_constructor( + ScalarPackage, tmpmdl, "tdis", "tdis", sim_package=True + ) + + ats = None + # ATS package construction + for variable in variables: + if variable.startswith("ATS"): + ats_constructor = package_factory("ats", ListPackage) + ats = ats_constructor( + ListPackage, tmpmdl, "ats", "ats", sim_package=True + ) + break + + # get the exchanges + exchange_names = [] + for variable in variables: + if variable.startswith("GWF-GWF") or variable.startswith( + "GWT-GWT" + ): + exchange_name = variable.split("/")[0] + if exchange_name not in exchange_names: + exchange_names.append(exchange_name) + + # sim_packages: tdis, gwf-gwf, sln + exchanges = {} + for exchange_name in exchanges: + exchange = ApiExchange(mf6, exchange_name) + exchanges[exchange_name.lower()] = exchange + + return ApiSimulation(mf6, models, solutions, exchanges, tdis, ats) diff --git a/modflowapi/extensions/data.py b/modflowapi/extensions/data.py index b443313..5449558 100644 --- a/modflowapi/extensions/data.py +++ b/modflowapi/extensions/data.py @@ -1,732 +1,732 @@ -import numpy as np -import pandas as pd -import xmipy.errors - - -class ListInput(object): - """ - Data object for storing pointers and working with list based input data - - Parameters - ---------- - parent : ListPackage - modflowapi ListPackage object - var_addrs : list, None - optional list of variable addresses - mf6 : ModflowApi, None - optional ModflowApi object - """ - - def __init__(self, parent, var_addrs=None, mf6=None): - self.parent = parent - if self.parent is not None: - self.var_addrs = self.parent.var_addrs - self.mf6 = self.parent.model.mf6 - else: - if var_addrs is None or mf6 is None: - raise AssertionError( - "var_addrs and mf6 must be supplied if parent is None" - ) - self.var_addrs = var_addrs - self.mf6 = mf6 - - self._ptrs = {} - self._nodevars = ("nodelist", "nexg", "maxats") - self._boundvars = ("bound",) - # self._auxname = [] - self._maxbound = [ - 0, - ] - self._nbound = [ - 0, - ] - self._naux = [ - 0, - ] - self._auxnames = [] - self._dtype = [] - self._reduced_to_var_addr = {} - self._set_stress_period_data() - - def _set_stress_period_data(self): - """ - Method to set stress period data variable pointers to the _ptrs - dictionary - - """ - for var_addr in self.var_addrs: - try: - values = self.mf6.get_value_ptr(var_addr) - except xmipy.errors.InputError: - if self._naux[0] > 0: - values = self.mf6.get_value(var_addr) - else: - continue - reduced = var_addr.split("/")[-1].lower() - if reduced in ("maxbound", "nbound"): - setattr(self, f"_{reduced}", values) - elif reduced in ("nexg", "maxats"): - setattr(self, "_maxbound", values) - setattr(self, "_nbound", values) - elif reduced in ("naux",): - setattr(self, "_naux", values) - elif reduced in ("auxname_cst"): - setattr(self, "_auxnames", list(values)) - else: - self._ptrs[reduced] = values - self._reduced_to_var_addr[reduced] = var_addr - if reduced in self._boundvars: - for name in self.parent._bound_vars: - typ_str = values.dtype.str - dtype = (name, typ_str) - self._dtype.append(dtype) - elif reduced in self._nodevars: - dtype = (reduced, "O") - self._dtype.append(dtype) - elif reduced == "auxvar": - if self._naux == 0: - continue - else: - for ix in range(self._naux[0]): - typ_str = values.dtype.str - dtype = (self._auxnames[ix], typ_str) - self._dtype.append(dtype) - else: - typ_str = values.dtype.str - dtype = (reduced, typ_str) - self._dtype.append(dtype) - - def _ptr_to_recarray(self): - """ - Method to get a recarray of stress period data from modflow pointers - - Returns - ------- - np.recarray - """ - if self._nbound[0] == 0: - return - recarray = np.recarray((self._nbound[0],), self._dtype) - for name, ptr in self._ptrs.items(): - values = np.copy(ptr) - if name in self._boundvars: - for ix, nm in enumerate(self.parent._bound_vars): - recarray[nm][0 : self._nbound[0]] = values[ - 0 : self._nbound[0], ix - ] - elif name == "auxvar": - if self._naux[0] == 0: - continue - else: - for ix in range(self._naux[0]): - nm = self._auxnames[ix] - recarray[nm][0 : self._nbound[0]] = values[ - 0 : self._nbound[0], ix - ] - elif name == "auxname_cst": - pass - - else: - values = values.ravel() - if name in self._nodevars: - values -= 1 - values = self.parent.model.nodetouser[values] - values = list( - zip(*np.unravel_index(values, self.parent.model.shape)) - ) - - recarray[name][0 : self._nbound[0]] = values[ - 0 : self._nbound[0] - ] - - return recarray - - def _recarray_to_ptr(self, recarray): - """ - Method to update stress period information pointers from user supplied - data - - Parameters - ---------- - recarray : np.recarray - numpy recarray of stress period data - - """ - if recarray is None: - self._nbound[0] = 0 - return - - if len(recarray) != self._nbound: - if len(recarray) > self._maxbound[0]: - raise AssertionError( - f"Length of stresses ({len(recarray)},) cannot be larger " - f"than maxbound value ({self._maxbound[0]},)" - ) - self._nbound[0] = len(recarray) - - if len(recarray) == 0: - return - - for name in recarray.dtype.names: - if name in self._nodevars: - multi_index = tuple( - np.array([list(i) for i in recarray[name]]).T - ) - nodes = np.ravel_multi_index( - multi_index, self.parent.model.shape - ) - recarray[name] = self.parent.model.usertonode[nodes] + 1 - - if name in self.parent._bound_vars: - idx = self.parent._bound_vars.index(name) - bname = "bound" - self._ptrs[bname][0 : self._nbound[0], idx] = recarray[name] - elif name in self._auxnames: - idx = self._auxnames.index(name) - self._ptrs["auxvar"][0 : self._nbound[0], idx] = recarray[name] - elif name == "auxname_cst": - pass - else: - self._ptrs[name][0 : self._nbound[0]] = recarray[name].ravel() - - def __getitem__(self, item): - recarray = self._ptr_to_recarray() - return recarray[item] - - def __setitem__(self, key, value): - recarray = self._ptr_to_recarray() - recarray[key] = value - self._recarray_to_ptr(recarray) - - @property - def dtype(self): - """ - Returns the numpy dtypes for the recarray - """ - return self._dtype - - @property - def values(self): - """ - Returns a np.recarray of the current stress_period_data - """ - return self._ptr_to_recarray() - - @values.setter - def values(self, recarray): - """ - Setter method to update the current stress_period_data - """ - self._recarray_to_ptr(recarray) - - @property - def dataframe(self): - recarray = self._ptr_to_recarray() - return pd.DataFrame.from_records(recarray) - - @dataframe.setter - def dataframe(self, dataframe): - recarray = dataframe.to_records(index=False) - self._recarray_to_ptr(recarray) - - -class ArrayPointer: - """ - Data object for storing single pointers and working with array based input data - - Parameters - ---------- - parent : ArrayPackage - ArrayPackage object - var_addr : str - variable pointer location - mf6 : ModflowApi - optional ModflowApi object - """ - - def __init__(self, parent, var_addr, mf6=None): - self._ptr = None - self.parent = parent - self._mapping = None - self.name = None - self.var_addr = var_addr - self._vshape = None - - if self.parent is not None: - self.mf6 = self.parent.model.mf6 - else: - if mf6 is None: - raise AssertionError("mf6 must be supplied if parent is None") - self._set_array() - - def _set_array(self): - ivn = self.mf6.get_input_var_names() - if self.var_addr in ivn: - values = self.mf6.get_value_ptr(self.var_addr) - reduced = self.var_addr.split("/")[-1].lower() - self._vshape = values.shape - self._ptr = values - self.name = reduced - - def __getitem__(self, item): - return self.values[item] - - def __setitem__(self, key, value): - array = self.values - array[key] = value - self.values = array - - @property - def values(self): - """ - Method to get an array from modflow - - Returns - ------- - np.array of modflow data - """ - if not self.parent._sim_package: - value = np.ones((self.parent.model.size,)) * np.nan - if self._ptr.size == self.parent.model.size: - value[:] = self._ptr.ravel() - else: - value[self.parent.model.nodetouser] = self._ptr.ravel() - return value.reshape(self.parent.model.shape) - else: - return np.copy(self._ptr.ravel()) - - @values.setter - def values(self, array): - """ - Method to update the modflow pointer arrays - - Parameters - ---------- - array : np.array - numpy array - - """ - - if not isinstance(array, np.ndarray): - raise TypeError() - if not self.parent._sim_package: - if array.size != self.parent.model.size: - raise ValueError( - f"{self.name} size {array.size} is not equal to " - f"modflow variable size {self.parent.model.size}" - ) - - array = array.ravel() - if self._ptr.size != array.size: - array = array[self.parent.model.nodetouser] - if len(self._vshape) > 1: - array.shape = self._vshape - else: - array = array.ravel() - self._ptr[:] = array - - -class ArrayInput: - """ - Data object for storing pointers and working with array based input data - - Parameters - ---------- - parent : ArrayPackage - modflowapi ArrayPackage object - var_addrs : list, None - optional list of variable addresses - mf6 : ModflowApi, None - optional ModflowApi object - """ - - def __init__(self, parent, var_addrs=None, mf6=None): - self._ptrs = {} - self.parent = parent - # change this to a parent package.mapping - self._mapping = None - - if self.parent is not None: - self.var_addrs = self.parent.var_addrs - self.mf6 = self.parent.model.mf6 - else: - if var_addrs is None or mf6 is None: - raise AssertionError( - "var_addrs and mf6 must be supplied if parent is None" - ) - self.var_addrs = var_addrs - self.mf6 = mf6 - - self._maxbound = [ - 0, - ] - self._nbound = [ - 0, - ] - self._reduced_to_var_addr = {} - self._set_arrays() - - def _set_arrays(self): - """ - Method to modflow variable pointers to the _ptrs dictionary - """ - ivn = self.mf6.get_input_var_names() - for var_addr in self.var_addrs: - if var_addr in ivn: - ptr = ArrayPointer(self.parent, var_addr) - reduced = var_addr.split("/")[-1].lower() - self._ptrs[reduced] = ptr - self._reduced_to_var_addr[reduced] = var_addr - - def __getattr__(self, item): - """ - Dynamic method to get modflow varaibles as an attribute - """ - if item in self._ptrs: - return self._ptrs[item] - else: - return super(ArrayInput).__getattribute__(item) - - def __setattr__(self, item, value): - """ - Dynamic method that allows users to set modflow variables to the - _ptr dict - """ - if item in ( - "parent", - "var_addrs", - "_mapping", - "_ptrs", - "mf6", - "_maxbound", - "_nbound", - "_reduced_to_var_addr", - ): - super().__setattr__(item, value) - - elif item in self._ptrs: - if isinstance(value, ArrayPointer): - self._ptrs[item] = value - else: - raise AttributeError(f"{item} is not a vaild attribute") - - @property - def variable_names(self): - """ - Returns a list of valid array names that can be accessed by the user - """ - return list(sorted(self._ptrs.keys())) - - def get_ptr(self, item): - """ - Method to get the ArrayPointer object - - Parameters - ---------- - item : str - modflow variable name: Ex. "k11" - - Returns - ------- - ArrayPointer object - """ - if item in self._ptrs: - return self._ptrs[item] - - def set_ptr(self, item, ptr): - """ - Method to set an ArrayPointer object - - Parameters - ---------- - item : str - modflow variable name: Ex. "k11" - ptr : ArrayPointer - ArrayPointer object - """ - if item in self._ptrs: - if isinstance(ptr, ArrayPointer): - self._ptrs[item] = ptr - else: - raise TypeError("An ArrayPointer object must be provided") - - else: - raise KeyError(f"{item} is not accessible in this package") - - def get_array(self, item): - """ - Method to get an array from modflow - - Parameters - ---------- - item : str - modflow variable name. Ex. "k11" - - Returns - ------- - np.array of modflow data - """ - if item in self._ptrs: - return self._ptrs[item].values - else: - raise KeyError(f"{item} is not accessible in this package") - - def set_array(self, item, array): - """ - Method to update the modflow pointer arrays - - Parameters - ---------- - item : str - modflow variable name. Ex. "k11" - array : np.array - numpy array - - """ - if item in self._ptrs: - self._ptrs[item].values = array - else: - raise KeyError( - f"{item} is not a valid variable name for this package" - ) - - -class AdvancedInput(object): - """ - Data object for dynamically storing pointers and working with - "advanced" data types - - Parameters - ---------- - parent : ArrayPackage - modflowapi ArrayPackage object - mf6 : ModflowApi, None - optional ModflowApi object - """ - - def __init__(self, parent, mf6=None): - self._ptrs = {} - self.parent = parent - - if self.parent is not None: - self.mf6 = self.parent.model.mf6 - else: - if mf6 is None: - raise AssertionError("mf6 must be supplied if parent is None") - self.mf6 = mf6 - - def get_variable(self, name, model=None, package=None): - """ - method to assemble a variable address and get a variable from the - ModflowApi instance - - Parameters: - ---------- - name : str - variable name - model : str - optional model name, note this is required if parent is None - package : str - optional package name, note this is requried if parent is None - - Returns: - ------- - np.ndarray or scalar float, int, string, or boolean value - depending on data type and length - """ - if name.lower() in self._ptrs: - return self._ptrs[name.lower()] - - if not self.parent._sim_package: - if self.parent is not None: - var_addr = self.mf6.get_var_address( - name.upper(), self.parent.model.name, self.parent.pkg_name - ) - else: - var_addr = self.mf6.get_var_address( - name.upper(), model.upper(), package.upper() - ) - else: - if self.parent is not None: - var_addr = self.mf6.get_var_address( - name.upper(), self.parent.pkg_name - ) - else: - var_addr = self.mf6.get_var_address( - name.upper(), package.upper() - ) - - try: - values = self.mf6.get_value_ptr(var_addr) - self._ptrs[name.lower()] = values - except xmipy.errors.InputError: - values = self.mf6.get_value(var_addr) - - return values.copy() - - def set_variable(self, name, values, model=None, package=None): - """ - method to assemble a variable address and get a variable from the - ModflowApi instance - - Parameters: - ---------- - name : str - variable name - values : np.ndarray - numpy array of variable values - model : str - optional model name, note this is required if parent is None - package : str - optional package name, note this is requried if parent is None - - Returns: - ------- - np.ndarray or scalar float, int, string, or boolean value - depending on data type and length - """ - if model is None and not self.parent._sim_package: - model = self.parent.model.name - if package is None: - package = self.parent.pkg_name - - if name.lower() not in self._ptrs: - values0 = self.get_variable(name, model, package) - else: - values0 = self._ptrs[name.lower()] - - if values0.shape != values.shape: - raise ValueError( - f"Array shapes are incompatable: " - f"current shape={values.shape}, valid shape={values0.shape}" - ) - - if name.lower() not in self._ptrs: - # this is a set value situation - self.mf6.set_value( - self.mf6.get_var_address( - name.upper(), self.parent.model.name, self.parent.pkg_name - ), - values, - ) - else: - self._ptrs[name.lower()][:] = values[:] - - -class ScalarInput: - """ - Data object for storing pointers and working with array based input data - - Parameters - ---------- - parent : ArrayPackage - modflowapi ArrayPackage object - var_addrs : list, None - optional list of variable addresses - mf6 : ModflowApi, None - optional ModflowApi object - """ - - def __init__(self, parent, var_addrs=None, mf6=None): - self._ptrs = {} - self.parent = parent - # change this to a parent package.mapping - self._mapping = None - - if self.parent is not None: - self.var_addrs = self.parent.var_addrs - self.mf6 = self.parent.model.mf6 - else: - if var_addrs is None or mf6 is None: - raise AssertionError( - "var_addrs and mf6 must be supplied if parent is None" - ) - self.var_addrs = var_addrs - self.mf6 = mf6 - - self._reduced_to_var_addr = {} - self._set_scalars() - - def __getattr__(self, item): - """ - Dynamic method to get modflow varaibles as an attribute - """ - if item in self._ptrs: - return self._ptrs[item] - else: - return super(ArrayInput).__getattribute__(item) - - def __setattr__(self, item, value): - """ - Dynamic method that allows users to set modflow variables to the - _ptr dict - """ - if item in ( - "parent", - "var_addrs", - "_mapping", - "_ptrs", - "mf6", - "_maxbound", - "_nbound", - "_reduced_to_var_addr", - ): - super().__setattr__(item, value) - - elif item in self._ptrs: - self._ptrs[item] = value - else: - raise AttributeError(f"{item} is not a vaild attribute") - - @property - def variable_names(self): - """ - Returns a list of valid array names that can be accessed by the user - """ - return list(sorted(self._ptrs.keys())) - - def _set_scalars(self): - """ - Method to modflow variable pointers to the _ptrs dictionary - """ - ivn = self.mf6.get_input_var_names() - for var_addr in self.var_addrs: - if var_addr in ivn: - ptr = self.mf6.get_value_ptr(var_addr) - reduced = var_addr.split("/")[-1].lower() - self._ptrs[reduced] = ptr - self._reduced_to_var_addr[reduced] = var_addr - - def get_value(self, item): - """ - Method to get a scalar value from modflow - - Parameters - ---------- - item : str - modflow variable name. Ex. "NPER" - - Returns - ------- - str, int, float - """ - if item in self._ptrs: - return self._ptrs[item][0] - else: - raise KeyError(f"{item} is not accessible in this package") - - def set_value(self, item, value): - """ - Method to set a scalar value in modflow - - Parameters - ---------- - item : str - modflow variable name. Ex. "NPER" - - value : str, int, float - """ - if item in self._ptrs: - self._ptrs[item][0] = value - else: - raise KeyError(f"{item} is not accessible in this package") +import numpy as np +import pandas as pd +import xmipy.errors + + +class ListInput(object): + """ + Data object for storing pointers and working with list based input data + + Parameters + ---------- + parent : ListPackage + modflowapi ListPackage object + var_addrs : list, None + optional list of variable addresses + mf6 : ModflowApi, None + optional ModflowApi object + """ + + def __init__(self, parent, var_addrs=None, mf6=None): + self.parent = parent + if self.parent is not None: + self.var_addrs = self.parent.var_addrs + self.mf6 = self.parent.model.mf6 + else: + if var_addrs is None or mf6 is None: + raise AssertionError( + "var_addrs and mf6 must be supplied if parent is None" + ) + self.var_addrs = var_addrs + self.mf6 = mf6 + + self._ptrs = {} + self._nodevars = ("nodelist", "nexg", "maxats") + self._boundvars = ("bound",) + # self._auxname = [] + self._maxbound = [ + 0, + ] + self._nbound = [ + 0, + ] + self._naux = [ + 0, + ] + self._auxnames = [] + self._dtype = [] + self._reduced_to_var_addr = {} + self._set_stress_period_data() + + def _set_stress_period_data(self): + """ + Method to set stress period data variable pointers to the _ptrs + dictionary + + """ + for var_addr in self.var_addrs: + try: + values = self.mf6.get_value_ptr(var_addr) + except xmipy.errors.InputError: + if self._naux[0] > 0: + values = self.mf6.get_value(var_addr) + else: + continue + reduced = var_addr.split("/")[-1].lower() + if reduced in ("maxbound", "nbound"): + setattr(self, f"_{reduced}", values) + elif reduced in ("nexg", "maxats"): + setattr(self, "_maxbound", values) + setattr(self, "_nbound", values) + elif reduced in ("naux",): + setattr(self, "_naux", values) + elif reduced in ("auxname_cst"): + setattr(self, "_auxnames", list(values)) + else: + self._ptrs[reduced] = values + self._reduced_to_var_addr[reduced] = var_addr + if reduced in self._boundvars: + for name in self.parent._bound_vars: + typ_str = values.dtype.str + dtype = (name, typ_str) + self._dtype.append(dtype) + elif reduced in self._nodevars: + dtype = (reduced, "O") + self._dtype.append(dtype) + elif reduced == "auxvar": + if self._naux == 0: + continue + else: + for ix in range(self._naux[0]): + typ_str = values.dtype.str + dtype = (self._auxnames[ix], typ_str) + self._dtype.append(dtype) + else: + typ_str = values.dtype.str + dtype = (reduced, typ_str) + self._dtype.append(dtype) + + def _ptr_to_recarray(self): + """ + Method to get a recarray of stress period data from modflow pointers + + Returns + ------- + np.recarray + """ + if self._nbound[0] == 0: + return + recarray = np.recarray((self._nbound[0],), self._dtype) + for name, ptr in self._ptrs.items(): + values = np.copy(ptr) + if name in self._boundvars: + for ix, nm in enumerate(self.parent._bound_vars): + recarray[nm][0 : self._nbound[0]] = values[ + 0 : self._nbound[0], ix + ] + elif name == "auxvar": + if self._naux[0] == 0: + continue + else: + for ix in range(self._naux[0]): + nm = self._auxnames[ix] + recarray[nm][0 : self._nbound[0]] = values[ + 0 : self._nbound[0], ix + ] + elif name == "auxname_cst": + pass + + else: + values = values.ravel() + if name in self._nodevars: + values -= 1 + values = self.parent.model.nodetouser[values] + values = list( + zip(*np.unravel_index(values, self.parent.model.shape)) + ) + + recarray[name][0 : self._nbound[0]] = values[ + 0 : self._nbound[0] + ] + + return recarray + + def _recarray_to_ptr(self, recarray): + """ + Method to update stress period information pointers from user supplied + data + + Parameters + ---------- + recarray : np.recarray + numpy recarray of stress period data + + """ + if recarray is None: + self._nbound[0] = 0 + return + + if len(recarray) != self._nbound: + if len(recarray) > self._maxbound[0]: + raise AssertionError( + f"Length of stresses ({len(recarray)},) cannot be larger " + f"than maxbound value ({self._maxbound[0]},)" + ) + self._nbound[0] = len(recarray) + + if len(recarray) == 0: + return + + for name in recarray.dtype.names: + if name in self._nodevars: + multi_index = tuple( + np.array([list(i) for i in recarray[name]]).T + ) + nodes = np.ravel_multi_index( + multi_index, self.parent.model.shape + ) + recarray[name] = self.parent.model.usertonode[nodes] + 1 + + if name in self.parent._bound_vars: + idx = self.parent._bound_vars.index(name) + bname = "bound" + self._ptrs[bname][0 : self._nbound[0], idx] = recarray[name] + elif name in self._auxnames: + idx = self._auxnames.index(name) + self._ptrs["auxvar"][0 : self._nbound[0], idx] = recarray[name] + elif name == "auxname_cst": + pass + else: + self._ptrs[name][0 : self._nbound[0]] = recarray[name].ravel() + + def __getitem__(self, item): + recarray = self._ptr_to_recarray() + return recarray[item] + + def __setitem__(self, key, value): + recarray = self._ptr_to_recarray() + recarray[key] = value + self._recarray_to_ptr(recarray) + + @property + def dtype(self): + """ + Returns the numpy dtypes for the recarray + """ + return self._dtype + + @property + def values(self): + """ + Returns a np.recarray of the current stress_period_data + """ + return self._ptr_to_recarray() + + @values.setter + def values(self, recarray): + """ + Setter method to update the current stress_period_data + """ + self._recarray_to_ptr(recarray) + + @property + def dataframe(self): + recarray = self._ptr_to_recarray() + return pd.DataFrame.from_records(recarray) + + @dataframe.setter + def dataframe(self, dataframe): + recarray = dataframe.to_records(index=False) + self._recarray_to_ptr(recarray) + + +class ArrayPointer: + """ + Data object for storing single pointers and working with array based input data + + Parameters + ---------- + parent : ArrayPackage + ArrayPackage object + var_addr : str + variable pointer location + mf6 : ModflowApi + optional ModflowApi object + """ + + def __init__(self, parent, var_addr, mf6=None): + self._ptr = None + self.parent = parent + self._mapping = None + self.name = None + self.var_addr = var_addr + self._vshape = None + + if self.parent is not None: + self.mf6 = self.parent.model.mf6 + else: + if mf6 is None: + raise AssertionError("mf6 must be supplied if parent is None") + self._set_array() + + def _set_array(self): + ivn = self.mf6.get_input_var_names() + if self.var_addr in ivn: + values = self.mf6.get_value_ptr(self.var_addr) + reduced = self.var_addr.split("/")[-1].lower() + self._vshape = values.shape + self._ptr = values + self.name = reduced + + def __getitem__(self, item): + return self.values[item] + + def __setitem__(self, key, value): + array = self.values + array[key] = value + self.values = array + + @property + def values(self): + """ + Method to get an array from modflow + + Returns + ------- + np.array of modflow data + """ + if not self.parent._sim_package: + value = np.ones((self.parent.model.size,)) * np.nan + if self._ptr.size == self.parent.model.size: + value[:] = self._ptr.ravel() + else: + value[self.parent.model.nodetouser] = self._ptr.ravel() + return value.reshape(self.parent.model.shape) + else: + return np.copy(self._ptr.ravel()) + + @values.setter + def values(self, array): + """ + Method to update the modflow pointer arrays + + Parameters + ---------- + array : np.array + numpy array + + """ + + if not isinstance(array, np.ndarray): + raise TypeError() + if not self.parent._sim_package: + if array.size != self.parent.model.size: + raise ValueError( + f"{self.name} size {array.size} is not equal to " + f"modflow variable size {self.parent.model.size}" + ) + + array = array.ravel() + if self._ptr.size != array.size: + array = array[self.parent.model.nodetouser] + if len(self._vshape) > 1: + array.shape = self._vshape + else: + array = array.ravel() + self._ptr[:] = array + + +class ArrayInput: + """ + Data object for storing pointers and working with array based input data + + Parameters + ---------- + parent : ArrayPackage + modflowapi ArrayPackage object + var_addrs : list, None + optional list of variable addresses + mf6 : ModflowApi, None + optional ModflowApi object + """ + + def __init__(self, parent, var_addrs=None, mf6=None): + self._ptrs = {} + self.parent = parent + # change this to a parent package.mapping + self._mapping = None + + if self.parent is not None: + self.var_addrs = self.parent.var_addrs + self.mf6 = self.parent.model.mf6 + else: + if var_addrs is None or mf6 is None: + raise AssertionError( + "var_addrs and mf6 must be supplied if parent is None" + ) + self.var_addrs = var_addrs + self.mf6 = mf6 + + self._maxbound = [ + 0, + ] + self._nbound = [ + 0, + ] + self._reduced_to_var_addr = {} + self._set_arrays() + + def _set_arrays(self): + """ + Method to modflow variable pointers to the _ptrs dictionary + """ + ivn = self.mf6.get_input_var_names() + for var_addr in self.var_addrs: + if var_addr in ivn: + ptr = ArrayPointer(self.parent, var_addr) + reduced = var_addr.split("/")[-1].lower() + self._ptrs[reduced] = ptr + self._reduced_to_var_addr[reduced] = var_addr + + def __getattr__(self, item): + """ + Dynamic method to get modflow varaibles as an attribute + """ + if item in self._ptrs: + return self._ptrs[item] + else: + return super(ArrayInput).__getattribute__(item) + + def __setattr__(self, item, value): + """ + Dynamic method that allows users to set modflow variables to the + _ptr dict + """ + if item in ( + "parent", + "var_addrs", + "_mapping", + "_ptrs", + "mf6", + "_maxbound", + "_nbound", + "_reduced_to_var_addr", + ): + super().__setattr__(item, value) + + elif item in self._ptrs: + if isinstance(value, ArrayPointer): + self._ptrs[item] = value + else: + raise AttributeError(f"{item} is not a vaild attribute") + + @property + def variable_names(self): + """ + Returns a list of valid array names that can be accessed by the user + """ + return list(sorted(self._ptrs.keys())) + + def get_ptr(self, item): + """ + Method to get the ArrayPointer object + + Parameters + ---------- + item : str + modflow variable name: Ex. "k11" + + Returns + ------- + ArrayPointer object + """ + if item in self._ptrs: + return self._ptrs[item] + + def set_ptr(self, item, ptr): + """ + Method to set an ArrayPointer object + + Parameters + ---------- + item : str + modflow variable name: Ex. "k11" + ptr : ArrayPointer + ArrayPointer object + """ + if item in self._ptrs: + if isinstance(ptr, ArrayPointer): + self._ptrs[item] = ptr + else: + raise TypeError("An ArrayPointer object must be provided") + + else: + raise KeyError(f"{item} is not accessible in this package") + + def get_array(self, item): + """ + Method to get an array from modflow + + Parameters + ---------- + item : str + modflow variable name. Ex. "k11" + + Returns + ------- + np.array of modflow data + """ + if item in self._ptrs: + return self._ptrs[item].values + else: + raise KeyError(f"{item} is not accessible in this package") + + def set_array(self, item, array): + """ + Method to update the modflow pointer arrays + + Parameters + ---------- + item : str + modflow variable name. Ex. "k11" + array : np.array + numpy array + + """ + if item in self._ptrs: + self._ptrs[item].values = array + else: + raise KeyError( + f"{item} is not a valid variable name for this package" + ) + + +class AdvancedInput(object): + """ + Data object for dynamically storing pointers and working with + "advanced" data types + + Parameters + ---------- + parent : ArrayPackage + modflowapi ArrayPackage object + mf6 : ModflowApi, None + optional ModflowApi object + """ + + def __init__(self, parent, mf6=None): + self._ptrs = {} + self.parent = parent + + if self.parent is not None: + self.mf6 = self.parent.model.mf6 + else: + if mf6 is None: + raise AssertionError("mf6 must be supplied if parent is None") + self.mf6 = mf6 + + def get_variable(self, name, model=None, package=None): + """ + method to assemble a variable address and get a variable from the + ModflowApi instance + + Parameters: + ---------- + name : str + variable name + model : str + optional model name, note this is required if parent is None + package : str + optional package name, note this is requried if parent is None + + Returns: + ------- + np.ndarray or scalar float, int, string, or boolean value + depending on data type and length + """ + if name.lower() in self._ptrs: + return self._ptrs[name.lower()] + + if not self.parent._sim_package: + if self.parent is not None: + var_addr = self.mf6.get_var_address( + name.upper(), self.parent.model.name, self.parent.pkg_name + ) + else: + var_addr = self.mf6.get_var_address( + name.upper(), model.upper(), package.upper() + ) + else: + if self.parent is not None: + var_addr = self.mf6.get_var_address( + name.upper(), self.parent.pkg_name + ) + else: + var_addr = self.mf6.get_var_address( + name.upper(), package.upper() + ) + + try: + values = self.mf6.get_value_ptr(var_addr) + self._ptrs[name.lower()] = values + except xmipy.errors.InputError: + values = self.mf6.get_value(var_addr) + + return values.copy() + + def set_variable(self, name, values, model=None, package=None): + """ + method to assemble a variable address and get a variable from the + ModflowApi instance + + Parameters: + ---------- + name : str + variable name + values : np.ndarray + numpy array of variable values + model : str + optional model name, note this is required if parent is None + package : str + optional package name, note this is requried if parent is None + + Returns: + ------- + np.ndarray or scalar float, int, string, or boolean value + depending on data type and length + """ + if model is None and not self.parent._sim_package: + model = self.parent.model.name + if package is None: + package = self.parent.pkg_name + + if name.lower() not in self._ptrs: + values0 = self.get_variable(name, model, package) + else: + values0 = self._ptrs[name.lower()] + + if values0.shape != values.shape: + raise ValueError( + f"Array shapes are incompatable: " + f"current shape={values.shape}, valid shape={values0.shape}" + ) + + if name.lower() not in self._ptrs: + # this is a set value situation + self.mf6.set_value( + self.mf6.get_var_address( + name.upper(), self.parent.model.name, self.parent.pkg_name + ), + values, + ) + else: + self._ptrs[name.lower()][:] = values[:] + + +class ScalarInput: + """ + Data object for storing pointers and working with array based input data + + Parameters + ---------- + parent : ArrayPackage + modflowapi ArrayPackage object + var_addrs : list, None + optional list of variable addresses + mf6 : ModflowApi, None + optional ModflowApi object + """ + + def __init__(self, parent, var_addrs=None, mf6=None): + self._ptrs = {} + self.parent = parent + # change this to a parent package.mapping + self._mapping = None + + if self.parent is not None: + self.var_addrs = self.parent.var_addrs + self.mf6 = self.parent.model.mf6 + else: + if var_addrs is None or mf6 is None: + raise AssertionError( + "var_addrs and mf6 must be supplied if parent is None" + ) + self.var_addrs = var_addrs + self.mf6 = mf6 + + self._reduced_to_var_addr = {} + self._set_scalars() + + def __getattr__(self, item): + """ + Dynamic method to get modflow varaibles as an attribute + """ + if item in self._ptrs: + return self._ptrs[item] + else: + return super(ArrayInput).__getattribute__(item) + + def __setattr__(self, item, value): + """ + Dynamic method that allows users to set modflow variables to the + _ptr dict + """ + if item in ( + "parent", + "var_addrs", + "_mapping", + "_ptrs", + "mf6", + "_maxbound", + "_nbound", + "_reduced_to_var_addr", + ): + super().__setattr__(item, value) + + elif item in self._ptrs: + self._ptrs[item] = value + else: + raise AttributeError(f"{item} is not a vaild attribute") + + @property + def variable_names(self): + """ + Returns a list of valid array names that can be accessed by the user + """ + return list(sorted(self._ptrs.keys())) + + def _set_scalars(self): + """ + Method to modflow variable pointers to the _ptrs dictionary + """ + ivn = self.mf6.get_input_var_names() + for var_addr in self.var_addrs: + if var_addr in ivn: + ptr = self.mf6.get_value_ptr(var_addr) + reduced = var_addr.split("/")[-1].lower() + self._ptrs[reduced] = ptr + self._reduced_to_var_addr[reduced] = var_addr + + def get_value(self, item): + """ + Method to get a scalar value from modflow + + Parameters + ---------- + item : str + modflow variable name. Ex. "NPER" + + Returns + ------- + str, int, float + """ + if item in self._ptrs: + return self._ptrs[item][0] + else: + raise KeyError(f"{item} is not accessible in this package") + + def set_value(self, item, value): + """ + Method to set a scalar value in modflow + + Parameters + ---------- + item : str + modflow variable name. Ex. "NPER" + + value : str, int, float + """ + if item in self._ptrs: + self._ptrs[item][0] = value + else: + raise KeyError(f"{item} is not accessible in this package") diff --git a/modflowapi/extensions/pakbase.py b/modflowapi/extensions/pakbase.py index b235009..fcc6fe8 100644 --- a/modflowapi/extensions/pakbase.py +++ b/modflowapi/extensions/pakbase.py @@ -1,717 +1,717 @@ -import numpy as np - -from .data import AdvancedInput, ArrayInput, ListInput, ScalarInput - -# Note: HFB variables are not accessible in the memory manager 10/7/2022 -pkgvars = { - "dis": ["top", "bot", "area", "idomain"], - "chd": [ - "nbound", - "maxbound", - "nodelist", - ("bound", ("head",)), - "naux", - "auxname_cst", - "auxvar", - ], - "drn": [ - "nbound", - "maxbound", - "nodelist", - ( - "bound", - ( - "elev", - "cond", - ), - ), - "naux", - "auxname_cst", - "auxvar", - ], - "evt": [ - "nbound", - "maxbound", - "nodelist", - ( - "bound", - ( - "surface", - "rate", - "depth", - ), - ), - # "pxdp:NSEG", "petm:NSEG" - "naux", - "auxname_cst", - "auxvar", - ], - "ghb": [ - "nbound", - "maxbound", - "nodelist", - ( - "bound", - ( - "bhead", - "cond", - ), - ), - "naux", - "auxname_cst", - "auxvar", - ], - "ic": ["strt"], - "npf": ["k11", "k22", "k33", "angle1", "angle2", "angle3", "icelltype"], - "rch": [ - "maxbound", - "nbound", - "nodelist", - ("bound", ("recharge",)), - "naux", - "auxname_cst", - "auxvar", - ], - "sto": ["iconvert", "ss", "sy"], - "wel": [ - "maxbound", - "nbound", - "nodelist", - ("bound", ("flux",)), - "naux", - "auxname_cst", - "auxvar", - ], - # gwt model - "adv": ["diffc", "alh", "alv", "ath1", "ath2", "atv"], - "cnc": [ - "maxbound", - "nbound", - "nodelist", - ("bound", ("conc",)), - "naux", - "auxname_cst", - "auxvar", - ], - "ist": [ - "cim", - "thtaim", - "zetaim", - "decay", - "decay_sorbed", - "bulk_density", - "distcoef", - ], - "mst": ["porosity", "decay", "decay_sorbed", "bulk_density", "distcoef"], - "src": [ - "maxbound", - "nbound", - "nodelist", - ("bound", ("smassrate",)), - "naux", - "auxname_cst", - "auxvar", - ], - # exchange model - "gwf-gwf": ["nexg", "nodem1", "nodem2", "cl1", "cl2", "ihc"], - "gwt-gwt": ["nexg", "nodem1", "nodem2", "cl1", "cl2", "ihc"], - # simulation - "ats": [ - "maxats", - "iperats", - "dt0", - "dtmin", - "dtmax", - "dtadj", - "dtfailadj", - ], - "tdis": [ - "nper", - "itmuni", - "kper", - "kstp", - "delt", - "pertim", - "totim,", - "perlen", - "nstp", - "tsmult", - ], - # solution package - "sln": [ - "mxiter", - "dvclose", - "gamma", - "theta", - "akappa", - "amomentum", - "numtrack", - "btol", - "breduc", - "res_lim", - ], - "ims": [ - "niterc", - "dvclose", - "rclose", - "relax", - "ipc", - "droptol", - "north", - "iscl", - "iord", - ], -} - - -class PackageBase: - """ - Base class for packages within the modflow-6 api - - - Parameters - ---------- - model : ApiModel - modflowapi ApiModel object - pkg_type : str - package type name. ex. 'wel' - pkg_name : str - modflow package name. ex. 'wel_0' - child_type : str - type of child input package - sim_package : bool - flag to indicate this is a simulation level package - """ - - def __init__(self, model, pkg_type, pkg_name, child_type, sim_package): - self.model = model - self.pkg_name = pkg_name - self.pkg_type = pkg_type - self._child_type = child_type - self._sim_package = sim_package - self._rhs = None - self._hcof = None - self._bound_vars = [] - self._advanced_var_names = None - - var_addrs = [] - if self._child_type != "advanced": - for var in pkgvars[self.pkg_type]: - if isinstance(var, tuple): - bound_vars = [] - for bv in var[-1]: - t = bv.split(":") - if len(t) == 2: - # this is a repeating variable - addr = self.model.mf6.get_var_address( - t[-1].upper(), self.model.name, self.pkg_name - ) - nrep = self.model.mf6.get_value(addr)[0] - if nrep > 1: - for rep in range(nrep): - bound_vars.append(f"{t[0]}{rep}") - else: - bound_vars.append(t[0]) - else: - bound_vars.append(t[0]) - - self._bound_vars = var[-1] - var = var[0] - - if sim_package: - var_addrs.append( - self.model.mf6.get_var_address( - var.upper(), self.pkg_name - ) - ) - else: - var_addrs.append( - self.model.mf6.get_var_address( - var.upper(), self.model.name, self.pkg_name - ) - ) - - self.var_addrs = var_addrs - self._variables_adv = AdvancedInput(self) - - @property - def advanced_vars(self): - """ - Returns a list of additional "advanced" variables that are - accessible through the API - """ - if self._advanced_var_names is None: - adv_vars = [] - for var_addr in self.model.mf6.get_input_var_names(): - is_advanced = False - t = var_addr.split("/") - if not self._sim_package: - if t[0] == self.model.name and t[1] == self.pkg_name: - is_advanced = self._check_if_advanced_var(t[-1]) - else: - if t[0] == self.pkg_name: - is_advanced = self._check_if_advanced_var(t[-1]) - - if is_advanced: - adv_vars.append(t[-1].lower()) - - self._advanced_var_names = adv_vars - return self._advanced_var_names - - def _check_if_advanced_var(self, variable_name): - """ - Method to check if a variable is an advanced variable - - Parameters - ---------- - variable_name : str - variable name to check - - Returns - ------- - bool - """ - if variable_name.lower() in self._bound_vars: - is_advanced = False - elif self.pkg_type not in pkgvars: - is_advanced = True - elif variable_name.lower() in pkgvars[self.pkg_type]: - is_advanced = False - else: - is_advanced = True - return is_advanced - - def get_advanced_var(self, name): - """ - Method to get an advanced variable that is not automatically - accessible through stress period data or as an array name - """ - name = name.lower() - if name not in self.advanced_vars: - raise AssertionError( - f"{name} is not accessible as an advanced " - f"variable for this package" - ) - - values = self._variables_adv.get_variable(name) - if not self._sim_package: - if ( - values.size == self.model.nodetouser.size - and self._child_type == "array" - ): - array = np.full(self.model.size, np.nan) - array[self.model.nodetouser] = values - return array - - return values - - def set_advanced_var(self, name, values): - """ - Method to set data to an advanced variable - - Parameters - ---------- - name : str - parameter name - values : np.ndarray - numpy array - """ - if not self._sim_package: - if self._child_type == "array" and values.size == self.model.size: - values = values[self.model.nodetouser] - - self._variables_adv.set_variable(name, values) - - @property - def rhs(self): - if not self._sim_package: - if self._rhs is None: - var_addr = self.model.mf6.get_var_address( - "RHS", self.model.name, self.pkg_name - ) - if var_addr in self.model.mf6.get_input_var_names(): - self._rhs = self.model.mf6.get_value_ptr(var_addr) - else: - return - - return np.copy(self._rhs) - - @rhs.setter - def rhs(self, values): - if self._rhs is None: - return - - self._rhs[:] = values[:] - - @property - def hcof(self): - if not self._sim_package: - if self._hcof is None: - var_addr = self.model.mf6.get_var_address( - "HCOF", self.model.name, self.pkg_name - ) - if var_addr in self.model.mf6.get_input_var_names(): - self._hcof = self.model.mf6.get_value_ptr(var_addr) - else: - return - - return np.copy(self._hcof) - - @hcof.setter - def hcof(self, values): - if self._hcof is None: - return - - self._hcof[:] = values[:] - - -class ListPackage(PackageBase): - """ - Package object for "list based" input packages such as WEL, DRN, RCH - - Parameters - ---------- - model : ApiModel - modflowapi model object - pkg_type : str - package type. Ex. "RCH" - pkg_name : str - package name (in the mf6 variables) - sim_package : bool - flag to indicate this is a simulation level package - """ - - def __init__(self, model, pkg_type, pkg_name, sim_package=False): - super().__init__( - model, pkg_type, pkg_name.upper(), "list", sim_package - ) - - self._variables = ListInput(self) - - def __repr__(self): - s = f"{self.pkg_type.upper()} Package: {self.pkg_name}" - return s - - @property - def nbound(self): - """ - Returns the "nbound" value for the stress period - """ - return self._variables._nbound[0] - - @property - def maxbound(self): - """ - Returns the "maxbound" value for the stress period - """ - return self._variables._maxbound[0] - - @property - def stress_period_data(self): - """ - Returns a ListInput object of the current stress_period_data - """ - return self._variables - - @stress_period_data.setter - def stress_period_data(self, recarray): - """ - Setter method to update the current stress_period_data - """ - if isinstance(recarray, np.recarray): - self._variables.values = recarray - elif isinstance(recarray, ListInput): - self._variables.values = recarray.values - elif recarray is None: - self._variables.values = recarray - else: - raise TypeError( - f"{type(recarray)} is not a supported stress_period_data type" - ) - - -class ArrayPackage(PackageBase): - """ - Package object for "array based" input packages such as NPF, DIS, - - Parameters - ---------- - model : ApiModel - modflowapi model object - pkg_type : str - package type. Ex. "DIS" - pkg_name : str - package name (in the mf6 variables) - sim_package : bool - flag to indicate this is a simulation level package - """ - - def __init__(self, model, pkg_type, pkg_name, sim_package=False): - super().__init__( - model, pkg_type, pkg_name.upper(), "array", sim_package - ) - - self._variables = ArrayInput(self) - - def __repr__(self): - s = f"{self.pkg_type.upper()} Package: {self.pkg_name} \n" - s += " Accessible variables include:\n" - for var_name in self.variable_names: - s += f" {var_name} \n" - return s - - def __setattr__(self, item, value): - """ - Method that enables dynamic variable setting and distributes - modflow variable storage and updates to the data object class - """ - if item in ( - "model", - "pkg_name", - "pkg_type", - "var_addrs", - ): - super().__setattr__(item, value) - - elif item.startswith("_"): - super().__setattr__(item, value) - - elif item in self._variables._ptrs: - self._variables.set_ptr(item, value) - - else: - raise AttributeError(f"{item}") - - def __getattr__(self, item): - """ - Method to dynamically get modflow variables by attribute - """ - if item in self._variables._ptrs: - return self._variables.get_ptr(item) - else: - return super().__getattribute__(item) - - @property - def variable_names(self): - """ - Returns a list of valid modflow variable names that the user can access - """ - return self._variables.variable_names - - def get_array(self, item): - """ - Method to get an array from modflow - - Parameters - ---------- - item : str - modflow variable name. Ex. "k11" - - Returns - ------- - np.array of modflow data - """ - return self._variables.get_array(item) - - def set_array(self, item, array): - """ - Method to update the modflow pointer arrays - - Parameters - ---------- - item : str - modflow variable name. Ex. "k11" - array : np.array - numpy array - - """ - self._variables.set_array(item, array) - - -class ScalarPackage(PackageBase): - """ - Container for advanced data packages - - Parameters - ---------- - model : ApiModel - modflowapi model object - pkg_type : str - package type. Ex. "RCH" - pkg_name : str - package name (in the mf6 variables) - sim_package : bool - boolean flag for simulation level packages. Ex. TDIS, IMS - """ - - def __init__(self, model, pkg_type, pkg_name, sim_package=False): - super().__init__( - model, pkg_type, pkg_name.upper(), "scalar", sim_package - ) - - self._variables = ScalarInput(self) - - def __repr__(self): - s = f"{self.pkg_type.upper()} Package: {self.pkg_name} \n" - s += " Accessible variables include:\n" - for var_name in self.variable_names: - s += f" {var_name} \n" - return s - - def __setattr__(self, item, value): - """ - Method that enables dynamic variable setting and distributes - modflow variable storage and updates to the data object class - """ - if item in ( - "model", - "pkg_name", - "pkg_type", - "var_addrs", - ): - super().__setattr__(item, value) - - elif item.startswith("_"): - super().__setattr__(item, value) - - elif item in self._variables._ptrs: - self._variables.set_value(item, value) - - else: - raise AttributeError(f"{item}") - - def __getattr__(self, item): - """ - Method to dynamically get modflow variables by attribute - """ - if item in self._variables._ptrs: - return self._variables.get_value(item) - else: - return super().__getattribute__(item) - - @property - def variable_names(self): - """ - Returns a list of valid modflow variable names that the user can access - """ - return self._variables.variable_names - - def get_value(self, item): - """ - Method to get a scalar value from modflow - - Parameters - ---------- - item : str - modflow variable name. Ex. "NBOUND" - - Returns - ------- - np.array of modflow data - """ - return self._variables.get_value(item) - - def set_value(self, item, value): - """ - Method to update the modflow pointer arrays - - Parameters - ---------- - item : str - modflow variable name. Ex. "k11" - array : str, int, float - scalar value - - """ - self._variables.set_value(item, value) - - -class AdvancedPackage(PackageBase): - """ - Container for advanced data packages - - Parameters - ---------- - model : ApiModel - modflowapi model object - pkg_type : str - package type. Ex. "RCH" - pkg_name : str - package name (in the mf6 variables) - sim_package : bool - boolean flag for simulation level packages. Ex. TDIS, IMS - """ - - def __init__(self, model, pkg_type, pkg_name, sim_package=False): - super().__init__( - model, pkg_type, pkg_name.upper(), "advanced", sim_package - ) - - def __repr__(self): - s = f"{self.pkg_type.upper()} Package: {self.pkg_name} \n" - s += " Advanced Package, variables only accessible through\n" - s += " get_advanced_var() and set_advanced_var() methods" - return s - - -class ApiSlnPackage(ScalarPackage): - """ - Class to acess solution packages - - Parameters - ---------- - model : ApiModel - modflowapi model object - pkg_type : str - package type. Ex. "RCH" - pkg_name : str - package name (in the mf6 variables) - sim_package : bool - boolean flag for simulation level packages. Ex. TDIS, IMS - """ - - def __init__(self, sim, pkg_name): - from .apimodel import ApiMbase - - super().__init__(sim, "sln", pkg_name, sim_package=True) - - mdl = ApiMbase( - sim.mf6, pkg_name.upper(), pkg_types={"ims": ScalarPackage} - ) - imslin = ScalarPackage(mdl, "ims", "IMSLINEAR") - for key, ptr in imslin._variables._ptrs.items(): - if key in self._variables._ptrs: - key = f"{imslin.pkg_type}_{key}".lower() - self._variables._ptrs[key] = ptr - - -def package_factory(pkg_type, basepackage): - """ - Method to autogenerate unique package "types" from the base packages: - ArrayPackage, ListPackage, and AdvancedPackage - - Parameters - ---------- - pkg_type : str - package type - basepackage : ArrayPackage, ListPackage, or AdvancedPackage - a base package type - - Returns - Package object : ex. ApiWelPackage - """ - - # hack for now. need a pkg_type variable for robustness - def __init__(self, obj, model, pkg_type, pkg_name, sim_package=False): - obj.__init__(self, model, pkg_type, pkg_name, sim_package=sim_package) - - cls_str = "".join(pkg_type.split("-")) - cls_str = f"{cls_str[0].upper()}{cls_str[1:]}" - - package = type( - f"Api{cls_str}Package", - (basepackage,), - {"__init__": __init__}, - ) - - return package +import numpy as np + +from .data import AdvancedInput, ArrayInput, ListInput, ScalarInput + +# Note: HFB variables are not accessible in the memory manager 10/7/2022 +pkgvars = { + "dis": ["top", "bot", "area", "idomain"], + "chd": [ + "nbound", + "maxbound", + "nodelist", + ("bound", ("head",)), + "naux", + "auxname_cst", + "auxvar", + ], + "drn": [ + "nbound", + "maxbound", + "nodelist", + ( + "bound", + ( + "elev", + "cond", + ), + ), + "naux", + "auxname_cst", + "auxvar", + ], + "evt": [ + "nbound", + "maxbound", + "nodelist", + ( + "bound", + ( + "surface", + "rate", + "depth", + ), + ), + # "pxdp:NSEG", "petm:NSEG" + "naux", + "auxname_cst", + "auxvar", + ], + "ghb": [ + "nbound", + "maxbound", + "nodelist", + ( + "bound", + ( + "bhead", + "cond", + ), + ), + "naux", + "auxname_cst", + "auxvar", + ], + "ic": ["strt"], + "npf": ["k11", "k22", "k33", "angle1", "angle2", "angle3", "icelltype"], + "rch": [ + "maxbound", + "nbound", + "nodelist", + ("bound", ("recharge",)), + "naux", + "auxname_cst", + "auxvar", + ], + "sto": ["iconvert", "ss", "sy"], + "wel": [ + "maxbound", + "nbound", + "nodelist", + ("bound", ("flux",)), + "naux", + "auxname_cst", + "auxvar", + ], + # gwt model + "adv": ["diffc", "alh", "alv", "ath1", "ath2", "atv"], + "cnc": [ + "maxbound", + "nbound", + "nodelist", + ("bound", ("conc",)), + "naux", + "auxname_cst", + "auxvar", + ], + "ist": [ + "cim", + "thtaim", + "zetaim", + "decay", + "decay_sorbed", + "bulk_density", + "distcoef", + ], + "mst": ["porosity", "decay", "decay_sorbed", "bulk_density", "distcoef"], + "src": [ + "maxbound", + "nbound", + "nodelist", + ("bound", ("smassrate",)), + "naux", + "auxname_cst", + "auxvar", + ], + # exchange model + "gwf-gwf": ["nexg", "nodem1", "nodem2", "cl1", "cl2", "ihc"], + "gwt-gwt": ["nexg", "nodem1", "nodem2", "cl1", "cl2", "ihc"], + # simulation + "ats": [ + "maxats", + "iperats", + "dt0", + "dtmin", + "dtmax", + "dtadj", + "dtfailadj", + ], + "tdis": [ + "nper", + "itmuni", + "kper", + "kstp", + "delt", + "pertim", + "totim,", + "perlen", + "nstp", + "tsmult", + ], + # solution package + "sln": [ + "mxiter", + "dvclose", + "gamma", + "theta", + "akappa", + "amomentum", + "numtrack", + "btol", + "breduc", + "res_lim", + ], + "ims": [ + "niterc", + "dvclose", + "rclose", + "relax", + "ipc", + "droptol", + "north", + "iscl", + "iord", + ], +} + + +class PackageBase: + """ + Base class for packages within the modflow-6 api + + + Parameters + ---------- + model : ApiModel + modflowapi ApiModel object + pkg_type : str + package type name. ex. 'wel' + pkg_name : str + modflow package name. ex. 'wel_0' + child_type : str + type of child input package + sim_package : bool + flag to indicate this is a simulation level package + """ + + def __init__(self, model, pkg_type, pkg_name, child_type, sim_package): + self.model = model + self.pkg_name = pkg_name + self.pkg_type = pkg_type + self._child_type = child_type + self._sim_package = sim_package + self._rhs = None + self._hcof = None + self._bound_vars = [] + self._advanced_var_names = None + + var_addrs = [] + if self._child_type != "advanced": + for var in pkgvars[self.pkg_type]: + if isinstance(var, tuple): + bound_vars = [] + for bv in var[-1]: + t = bv.split(":") + if len(t) == 2: + # this is a repeating variable + addr = self.model.mf6.get_var_address( + t[-1].upper(), self.model.name, self.pkg_name + ) + nrep = self.model.mf6.get_value(addr)[0] + if nrep > 1: + for rep in range(nrep): + bound_vars.append(f"{t[0]}{rep}") + else: + bound_vars.append(t[0]) + else: + bound_vars.append(t[0]) + + self._bound_vars = var[-1] + var = var[0] + + if sim_package: + var_addrs.append( + self.model.mf6.get_var_address( + var.upper(), self.pkg_name + ) + ) + else: + var_addrs.append( + self.model.mf6.get_var_address( + var.upper(), self.model.name, self.pkg_name + ) + ) + + self.var_addrs = var_addrs + self._variables_adv = AdvancedInput(self) + + @property + def advanced_vars(self): + """ + Returns a list of additional "advanced" variables that are + accessible through the API + """ + if self._advanced_var_names is None: + adv_vars = [] + for var_addr in self.model.mf6.get_input_var_names(): + is_advanced = False + t = var_addr.split("/") + if not self._sim_package: + if t[0] == self.model.name and t[1] == self.pkg_name: + is_advanced = self._check_if_advanced_var(t[-1]) + else: + if t[0] == self.pkg_name: + is_advanced = self._check_if_advanced_var(t[-1]) + + if is_advanced: + adv_vars.append(t[-1].lower()) + + self._advanced_var_names = adv_vars + return self._advanced_var_names + + def _check_if_advanced_var(self, variable_name): + """ + Method to check if a variable is an advanced variable + + Parameters + ---------- + variable_name : str + variable name to check + + Returns + ------- + bool + """ + if variable_name.lower() in self._bound_vars: + is_advanced = False + elif self.pkg_type not in pkgvars: + is_advanced = True + elif variable_name.lower() in pkgvars[self.pkg_type]: + is_advanced = False + else: + is_advanced = True + return is_advanced + + def get_advanced_var(self, name): + """ + Method to get an advanced variable that is not automatically + accessible through stress period data or as an array name + """ + name = name.lower() + if name not in self.advanced_vars: + raise AssertionError( + f"{name} is not accessible as an advanced " + f"variable for this package" + ) + + values = self._variables_adv.get_variable(name) + if not self._sim_package: + if ( + values.size == self.model.nodetouser.size + and self._child_type == "array" + ): + array = np.full(self.model.size, np.nan) + array[self.model.nodetouser] = values + return array + + return values + + def set_advanced_var(self, name, values): + """ + Method to set data to an advanced variable + + Parameters + ---------- + name : str + parameter name + values : np.ndarray + numpy array + """ + if not self._sim_package: + if self._child_type == "array" and values.size == self.model.size: + values = values[self.model.nodetouser] + + self._variables_adv.set_variable(name, values) + + @property + def rhs(self): + if not self._sim_package: + if self._rhs is None: + var_addr = self.model.mf6.get_var_address( + "RHS", self.model.name, self.pkg_name + ) + if var_addr in self.model.mf6.get_input_var_names(): + self._rhs = self.model.mf6.get_value_ptr(var_addr) + else: + return + + return np.copy(self._rhs) + + @rhs.setter + def rhs(self, values): + if self._rhs is None: + return + + self._rhs[:] = values[:] + + @property + def hcof(self): + if not self._sim_package: + if self._hcof is None: + var_addr = self.model.mf6.get_var_address( + "HCOF", self.model.name, self.pkg_name + ) + if var_addr in self.model.mf6.get_input_var_names(): + self._hcof = self.model.mf6.get_value_ptr(var_addr) + else: + return + + return np.copy(self._hcof) + + @hcof.setter + def hcof(self, values): + if self._hcof is None: + return + + self._hcof[:] = values[:] + + +class ListPackage(PackageBase): + """ + Package object for "list based" input packages such as WEL, DRN, RCH + + Parameters + ---------- + model : ApiModel + modflowapi model object + pkg_type : str + package type. Ex. "RCH" + pkg_name : str + package name (in the mf6 variables) + sim_package : bool + flag to indicate this is a simulation level package + """ + + def __init__(self, model, pkg_type, pkg_name, sim_package=False): + super().__init__( + model, pkg_type, pkg_name.upper(), "list", sim_package + ) + + self._variables = ListInput(self) + + def __repr__(self): + s = f"{self.pkg_type.upper()} Package: {self.pkg_name}" + return s + + @property + def nbound(self): + """ + Returns the "nbound" value for the stress period + """ + return self._variables._nbound[0] + + @property + def maxbound(self): + """ + Returns the "maxbound" value for the stress period + """ + return self._variables._maxbound[0] + + @property + def stress_period_data(self): + """ + Returns a ListInput object of the current stress_period_data + """ + return self._variables + + @stress_period_data.setter + def stress_period_data(self, recarray): + """ + Setter method to update the current stress_period_data + """ + if isinstance(recarray, np.recarray): + self._variables.values = recarray + elif isinstance(recarray, ListInput): + self._variables.values = recarray.values + elif recarray is None: + self._variables.values = recarray + else: + raise TypeError( + f"{type(recarray)} is not a supported stress_period_data type" + ) + + +class ArrayPackage(PackageBase): + """ + Package object for "array based" input packages such as NPF, DIS, + + Parameters + ---------- + model : ApiModel + modflowapi model object + pkg_type : str + package type. Ex. "DIS" + pkg_name : str + package name (in the mf6 variables) + sim_package : bool + flag to indicate this is a simulation level package + """ + + def __init__(self, model, pkg_type, pkg_name, sim_package=False): + super().__init__( + model, pkg_type, pkg_name.upper(), "array", sim_package + ) + + self._variables = ArrayInput(self) + + def __repr__(self): + s = f"{self.pkg_type.upper()} Package: {self.pkg_name} \n" + s += " Accessible variables include:\n" + for var_name in self.variable_names: + s += f" {var_name} \n" + return s + + def __setattr__(self, item, value): + """ + Method that enables dynamic variable setting and distributes + modflow variable storage and updates to the data object class + """ + if item in ( + "model", + "pkg_name", + "pkg_type", + "var_addrs", + ): + super().__setattr__(item, value) + + elif item.startswith("_"): + super().__setattr__(item, value) + + elif item in self._variables._ptrs: + self._variables.set_ptr(item, value) + + else: + raise AttributeError(f"{item}") + + def __getattr__(self, item): + """ + Method to dynamically get modflow variables by attribute + """ + if item in self._variables._ptrs: + return self._variables.get_ptr(item) + else: + return super().__getattribute__(item) + + @property + def variable_names(self): + """ + Returns a list of valid modflow variable names that the user can access + """ + return self._variables.variable_names + + def get_array(self, item): + """ + Method to get an array from modflow + + Parameters + ---------- + item : str + modflow variable name. Ex. "k11" + + Returns + ------- + np.array of modflow data + """ + return self._variables.get_array(item) + + def set_array(self, item, array): + """ + Method to update the modflow pointer arrays + + Parameters + ---------- + item : str + modflow variable name. Ex. "k11" + array : np.array + numpy array + + """ + self._variables.set_array(item, array) + + +class ScalarPackage(PackageBase): + """ + Container for advanced data packages + + Parameters + ---------- + model : ApiModel + modflowapi model object + pkg_type : str + package type. Ex. "RCH" + pkg_name : str + package name (in the mf6 variables) + sim_package : bool + boolean flag for simulation level packages. Ex. TDIS, IMS + """ + + def __init__(self, model, pkg_type, pkg_name, sim_package=False): + super().__init__( + model, pkg_type, pkg_name.upper(), "scalar", sim_package + ) + + self._variables = ScalarInput(self) + + def __repr__(self): + s = f"{self.pkg_type.upper()} Package: {self.pkg_name} \n" + s += " Accessible variables include:\n" + for var_name in self.variable_names: + s += f" {var_name} \n" + return s + + def __setattr__(self, item, value): + """ + Method that enables dynamic variable setting and distributes + modflow variable storage and updates to the data object class + """ + if item in ( + "model", + "pkg_name", + "pkg_type", + "var_addrs", + ): + super().__setattr__(item, value) + + elif item.startswith("_"): + super().__setattr__(item, value) + + elif item in self._variables._ptrs: + self._variables.set_value(item, value) + + else: + raise AttributeError(f"{item}") + + def __getattr__(self, item): + """ + Method to dynamically get modflow variables by attribute + """ + if item in self._variables._ptrs: + return self._variables.get_value(item) + else: + return super().__getattribute__(item) + + @property + def variable_names(self): + """ + Returns a list of valid modflow variable names that the user can access + """ + return self._variables.variable_names + + def get_value(self, item): + """ + Method to get a scalar value from modflow + + Parameters + ---------- + item : str + modflow variable name. Ex. "NBOUND" + + Returns + ------- + np.array of modflow data + """ + return self._variables.get_value(item) + + def set_value(self, item, value): + """ + Method to update the modflow pointer arrays + + Parameters + ---------- + item : str + modflow variable name. Ex. "k11" + array : str, int, float + scalar value + + """ + self._variables.set_value(item, value) + + +class AdvancedPackage(PackageBase): + """ + Container for advanced data packages + + Parameters + ---------- + model : ApiModel + modflowapi model object + pkg_type : str + package type. Ex. "RCH" + pkg_name : str + package name (in the mf6 variables) + sim_package : bool + boolean flag for simulation level packages. Ex. TDIS, IMS + """ + + def __init__(self, model, pkg_type, pkg_name, sim_package=False): + super().__init__( + model, pkg_type, pkg_name.upper(), "advanced", sim_package + ) + + def __repr__(self): + s = f"{self.pkg_type.upper()} Package: {self.pkg_name} \n" + s += " Advanced Package, variables only accessible through\n" + s += " get_advanced_var() and set_advanced_var() methods" + return s + + +class ApiSlnPackage(ScalarPackage): + """ + Class to acess solution packages + + Parameters + ---------- + model : ApiModel + modflowapi model object + pkg_type : str + package type. Ex. "RCH" + pkg_name : str + package name (in the mf6 variables) + sim_package : bool + boolean flag for simulation level packages. Ex. TDIS, IMS + """ + + def __init__(self, sim, pkg_name): + from .apimodel import ApiMbase + + super().__init__(sim, "sln", pkg_name, sim_package=True) + + mdl = ApiMbase( + sim.mf6, pkg_name.upper(), pkg_types={"ims": ScalarPackage} + ) + imslin = ScalarPackage(mdl, "ims", "IMSLINEAR") + for key, ptr in imslin._variables._ptrs.items(): + if key in self._variables._ptrs: + key = f"{imslin.pkg_type}_{key}".lower() + self._variables._ptrs[key] = ptr + + +def package_factory(pkg_type, basepackage): + """ + Method to autogenerate unique package "types" from the base packages: + ArrayPackage, ListPackage, and AdvancedPackage + + Parameters + ---------- + pkg_type : str + package type + basepackage : ArrayPackage, ListPackage, or AdvancedPackage + a base package type + + Returns + Package object : ex. ApiWelPackage + """ + + # hack for now. need a pkg_type variable for robustness + def __init__(self, obj, model, pkg_type, pkg_name, sim_package=False): + obj.__init__(self, model, pkg_type, pkg_name, sim_package=sim_package) + + cls_str = "".join(pkg_type.split("-")) + cls_str = f"{cls_str[0].upper()}{cls_str[1:]}" + + package = type( + f"Api{cls_str}Package", + (basepackage,), + {"__init__": __init__}, + ) + + return package diff --git a/modflowapi/extensions/runner.py b/modflowapi/extensions/runner.py index c708d5c..bd2a8d5 100644 --- a/modflowapi/extensions/runner.py +++ b/modflowapi/extensions/runner.py @@ -1,150 +1,150 @@ -from .. import ModflowApi -from .apisimulation import ApiSimulation -import pathlib -import platform -from enum import Enum - - -class Callbacks(Enum): - initialize = 0 - stress_period_start = 1 - stress_period_end = 2 - timestep_start = 3 - timestep_end = 4 - iteration_start = 5 - iteration_end = 6 - finalize = 7 - - -def run_simulation(dll, sim_path, callback, verbose=False, _develop=False): - """ - Method to run a Modflow simulation using the MODFLOW-API - with a callback function - - Parameters - ---------- - dll : str - path to the Modflow6 shared object - sim_path : str - path to the Modflow6 simulation - callback : method - user defined method that intercepts the simulation - progress and allows for input variable adjustments on the fly - verbose : bool - flag for verbose output from the simulation runner - _develop : bool - flag that dumps a list of all mf6 api variable addresses to text - file named "var_list.txt". This is primarily used for extensions - development purposes and bug fixes within the modflowapi python - package. - """ - ext = pathlib.Path(dll).suffix - dll = str(dll) - if not ext: - if platform.system().lower() == "windows": - dll += ".dll" - elif platform.system().lower() == "linux": - if not dll.startswith("./"): - if not dll.startswith("/"): - dll = "./" + dll + ".so" - else: - dll = "." + dll + ".so" - else: - dll += ".dylib" - - mf6 = ModflowApi( - dll, - working_directory=sim_path, - ) - - if verbose: - version = mf6.get_version() - print(f"MODFLOW-6 API Version {version}") - print("Initializing MODFLOW-6 simulation") - - mf6.initialize() - sim = ApiSimulation.load(mf6) - - if _develop: - with open("var_list.txt", "w") as foo: - for name in mf6.get_input_var_names(): - foo.write(f"{name}\n") - - callback(sim, Callbacks.initialize) - - has_converged = False - current_time = mf6.get_current_time() - end_time = mf6.get_end_time() - kperold = [0 for _ in range(sim.subcomponent_count)] - - while current_time < end_time: - dt = mf6.get_time_step() - mf6.prepare_time_step(dt) - - if verbose: - print( - f"Solving: Stress Period {sim.kper + 1}; " - f"Timestep {sim.kstp + 1}" - ) - - for sol_id, slnobj in sorted(sim.solutions.items()): - models = {} - maxiter = slnobj.mxiter - solution = {sol_id: slnobj} - for model in sim.models: - if sol_id == model.solution_id: - models[model.name.lower()] = model - - sim_grp = ApiSimulation( - mf6, models, solution, sim._exchanges, sim.tdis, sim.ats - ) - mf6.prepare_solve(sol_id) - if sim.kper != kperold[sol_id - 1]: - callback(sim_grp, Callbacks.stress_period_start) - kperold[sol_id - 1] += 1 - elif current_time == 0: - callback(sim_grp, Callbacks.stress_period_start) - - kiter = 0 - callback(sim_grp, Callbacks.timestep_start) - - if sim_grp.ats_period[0]: - mindt = sim_grp.ats_period[-1] - while sim_grp.delt > mindt: - sim_grp.iteration = kiter - callback(sim_grp, Callbacks.iteration_start) - has_converged = mf6.solve(sol_id) - callback(sim_grp, Callbacks.iteration_end) - kiter += 1 - if has_converged and sim_grp.allow_convergence: - break - - else: - while kiter < maxiter: - sim_grp.iteration = kiter - callback(sim_grp, Callbacks.iteration_start) - has_converged = mf6.solve(sol_id) - callback(sim_grp, Callbacks.iteration_end) - kiter += 1 - if has_converged and sim_grp.allow_convergence: - break - - callback(sim_grp, Callbacks.timestep_end) - mf6.finalize_solve(sol_id) - - mf6.finalize_time_step() - current_time = mf6.get_current_time() - - if not has_converged: - print(f"Simulation group: {sim_grp} DID NOT CONVERGE") - - if sim_grp.nstp == sim_grp.kstp + 1: - callback(sim_grp, Callbacks.stress_period_end) - - try: - callback(sim, Callbacks.finalize) - mf6.finalize() - except Exception: - raise RuntimeError("MF6 simulation failed, check listing file") - - print("NORMAL TERMINATION OF SIMULATION") +from .. import ModflowApi +from .apisimulation import ApiSimulation +import pathlib +import platform +from enum import Enum + + +class Callbacks(Enum): + initialize = 0 + stress_period_start = 1 + stress_period_end = 2 + timestep_start = 3 + timestep_end = 4 + iteration_start = 5 + iteration_end = 6 + finalize = 7 + + +def run_simulation(dll, sim_path, callback, verbose=False, _develop=False): + """ + Method to run a Modflow simulation using the MODFLOW-API + with a callback function + + Parameters + ---------- + dll : str + path to the Modflow6 shared object + sim_path : str + path to the Modflow6 simulation + callback : method + user defined method that intercepts the simulation + progress and allows for input variable adjustments on the fly + verbose : bool + flag for verbose output from the simulation runner + _develop : bool + flag that dumps a list of all mf6 api variable addresses to text + file named "var_list.txt". This is primarily used for extensions + development purposes and bug fixes within the modflowapi python + package. + """ + ext = pathlib.Path(dll).suffix + dll = str(dll) + if not ext: + if platform.system().lower() == "windows": + dll += ".dll" + elif platform.system().lower() == "linux": + if not dll.startswith("./"): + if not dll.startswith("/"): + dll = "./" + dll + ".so" + else: + dll = "." + dll + ".so" + else: + dll += ".dylib" + + mf6 = ModflowApi( + dll, + working_directory=sim_path, + ) + + if verbose: + version = mf6.get_version() + print(f"MODFLOW-6 API Version {version}") + print("Initializing MODFLOW-6 simulation") + + mf6.initialize() + sim = ApiSimulation.load(mf6) + + if _develop: + with open("var_list.txt", "w") as foo: + for name in mf6.get_input_var_names(): + foo.write(f"{name}\n") + + callback(sim, Callbacks.initialize) + + has_converged = False + current_time = mf6.get_current_time() + end_time = mf6.get_end_time() + kperold = [0 for _ in range(sim.subcomponent_count)] + + while current_time < end_time: + dt = mf6.get_time_step() + mf6.prepare_time_step(dt) + + if verbose: + print( + f"Solving: Stress Period {sim.kper + 1}; " + f"Timestep {sim.kstp + 1}" + ) + + for sol_id, slnobj in sorted(sim.solutions.items()): + models = {} + maxiter = slnobj.mxiter + solution = {sol_id: slnobj} + for model in sim.models: + if sol_id == model.solution_id: + models[model.name.lower()] = model + + sim_grp = ApiSimulation( + mf6, models, solution, sim._exchanges, sim.tdis, sim.ats + ) + mf6.prepare_solve(sol_id) + if sim.kper != kperold[sol_id - 1]: + callback(sim_grp, Callbacks.stress_period_start) + kperold[sol_id - 1] += 1 + elif current_time == 0: + callback(sim_grp, Callbacks.stress_period_start) + + kiter = 0 + callback(sim_grp, Callbacks.timestep_start) + + if sim_grp.ats_period[0]: + mindt = sim_grp.ats_period[-1] + while sim_grp.delt > mindt: + sim_grp.iteration = kiter + callback(sim_grp, Callbacks.iteration_start) + has_converged = mf6.solve(sol_id) + callback(sim_grp, Callbacks.iteration_end) + kiter += 1 + if has_converged and sim_grp.allow_convergence: + break + + else: + while kiter < maxiter: + sim_grp.iteration = kiter + callback(sim_grp, Callbacks.iteration_start) + has_converged = mf6.solve(sol_id) + callback(sim_grp, Callbacks.iteration_end) + kiter += 1 + if has_converged and sim_grp.allow_convergence: + break + + callback(sim_grp, Callbacks.timestep_end) + mf6.finalize_solve(sol_id) + + mf6.finalize_time_step() + current_time = mf6.get_current_time() + + if not has_converged: + print(f"Simulation group: {sim_grp} DID NOT CONVERGE") + + if sim_grp.nstp == sim_grp.kstp + 1: + callback(sim_grp, Callbacks.stress_period_end) + + try: + callback(sim, Callbacks.finalize) + mf6.finalize() + except Exception: + raise RuntimeError("MF6 simulation failed, check listing file") + + print("NORMAL TERMINATION OF SIMULATION") From 61ccbb6687e13ba45205164039a4e2f2e86ded9d Mon Sep 17 00:00:00 2001 From: Mike Taves Date: Thu, 30 Mar 2023 03:02:19 +1300 Subject: [PATCH 09/34] Use pyproject.toml for project metadata, add citation info (#11) --- .flake8 | 41 ++++++++---------- .github/workflows/ci.yml | 55 +++++++++--------------- CITATION.cff | 61 +++++++++++++++++++++++++++ README.md | 4 ++ etc/requirements.pip.txt | 12 ------ guide-to-publish.md | 10 ++--- pyproject.toml | 67 ++++++++++++++++++++++++++++++ setup.cfg | 90 ---------------------------------------- setup.py | 4 +- 9 files changed, 176 insertions(+), 168 deletions(-) create mode 100644 CITATION.cff delete mode 100644 etc/requirements.pip.txt create mode 100644 pyproject.toml delete mode 100644 setup.cfg mode change 100755 => 100644 setup.py diff --git a/.flake8 b/.flake8 index 5e64c1b..dfb17d8 100644 --- a/.flake8 +++ b/.flake8 @@ -8,29 +8,24 @@ exclude = autotest ignore = # https://flake8.pycqa.org/en/latest/user/error-codes.html - F401, # 'module' imported but unused + # 'module' imported but unused + F401, # https://pycodestyle.readthedocs.io/en/latest/intro.html#error-codes - E121, # continuation line under-indented for hanging indent - E122, # continuation line missing indentation or outdented - E126, # continuation line over-indented for hanging indent - E127, # continuation line over-indented for visual indent - E128, # continuation line under-indented for visual indent - E203, # whitespace before - E221, # multiple spaces before operator - E222, # multiple spaces after operator - E226, # missing whitespace around arithmetic operator - E231, # missing whitespace after ',' - E241, # multiple spaces after ',' - E402, # module level import not at top of file - E501, # line too long (> 79 characters) - E502, # backslash is redundant between brackets - E722, # do not use bare 'except' - E741, # ambiguous variable name - W291, # trailing whitespace - W292, # no newline at end of file - W293, # blank line contains whitespace - W391, # blank line at end of file - W503, # line break before binary operator - W504 # line break after binary operator + # E1: Indentation + E121, E122, E126, E127, E128, + # E2: Whitespace + E203, E221, E222, E226, E231, E241, + # E4: Import + E402, + # E5: Line length + E501, E502, + # E7: Statement + E722, E741, + # W2: Whitespace warning + W291, W292, W293, + # W3: Blank line warning + W391, + # W5: Line break warning + W503, W504 statistics = True diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6d68bf8..2d8b41e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,10 +28,10 @@ jobs: - name: Checkout repo uses: actions/checkout@v3 - - name: Setup Python 3.8 + - name: Setup Python uses: actions/setup-python@v4 with: - python-version: 3.8 + python-version: 3.x - name: Upgrade pip run: | @@ -64,29 +64,26 @@ jobs: # Standard python fails on Windows without GDAL installation. Using # standard python here since only linting on linux. # Use standard bash shell with standard python - - name: Setup Python 3.8 + - name: Setup Python uses: actions/setup-python@v4 with: - python-version: 3.8 - cache: 'pip' - cache-dependency-path: setup.cfg + python-version: 3.x - name: Print python version run: | python --version - - name: Install Python dependencies + - name: Install Python packages run: | python -m pip install --upgrade pip - pip install . - pip install ".[lint]" + pip install -e .[lint] - name: Run black run: | echo "if black check fails run" - echo " black --line-length 79 ./modflowapi" + echo " black ./modflowapi" echo "and then commit the changes." - black --check --line-length 79 ./modflowapi + black --check ./modflowapi - name: Run flake8 run: | @@ -104,7 +101,7 @@ jobs: fail-fast: false matrix: os: [ ubuntu-latest, macos-latest, windows-latest ] - python-version: [ 3.8, 3.9, "3.10"] + python-version: [ 3.8, 3.9, "3.10", "3.11" ] defaults: run: shell: bash @@ -119,21 +116,14 @@ jobs: with: python-version: ${{ matrix.python-version }} cache: 'pip' - cache-dependency-path: setup.cfg + cache-dependency-path: pyproject.toml - name: Install Python dependencies - if: runner.os != 'Windows' run: | pip install --upgrade pip - pip install . - pip install ".[test]" - - - name: Install Python dependencies Windows - if: runner.os == 'Windows' - run: | - python.exe -m pip install --upgrade pip - python.exe -m pip install . - python.exe -m pip install ".[test]" + pip install git+https://git@github.com/Deltares/xmipy@develop + pip install git+https://git@github.com/MODFLOW-USGS/modflow-devtools@develop + pip install .[test] - name: Install modflow executables uses: modflowpy/install-modflow-action@v1 @@ -156,7 +146,7 @@ jobs: fail-fast: false matrix: os: [ ubuntu-latest, macos-latest, windows-latest ] - python-version: [ 3.8, 3.9, "3.10"] + python-version: [ 3.8, 3.9, "3.10", "3.11" ] defaults: run: shell: bash @@ -171,21 +161,14 @@ jobs: with: python-version: ${{ matrix.python-version }} cache: 'pip' - cache-dependency-path: setup.cfg + cache-dependency-path: pyproject.toml - name: Install Python dependencies - if: runner.os != 'Windows' run: | pip install --upgrade pip - pip install . - pip install ".[test]" - - - name: Install Python dependencies Windows - if: runner.os == 'Windows' - run: | - python.exe -m pip install --upgrade pip - python.exe -m pip install . - python.exe -m pip install ".[test]" + pip install git+https://git@github.com/Deltares/xmipy@develop + pip install git+https://git@github.com/MODFLOW-USGS/modflow-devtools@develop + pip install .[test] - name: Install modflow executables uses: modflowpy/install-modflow-action@v1 @@ -198,4 +181,4 @@ jobs: shell: bash -l {0} run: | # chmod a+x libmf6* - pytest -n auto -m "mf6 and not extensions" \ No newline at end of file + pytest -n auto -m "mf6 and not extensions" diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 0000000..4874017 --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,61 @@ +cff-version: 1.2.0 +message: If you use this software, please cite both the article from preferred-citation + and the software itself. +type: software +title: MODFLOW API +version: 0.0.1 +date-released: '2021-05-12' +abstract: An extension to xmipy for the MODFLOW API. +repository-artifact: https://pypi.org/project/modflowapi +repository-code: https://github.com/MODFLOW-USGS/modflowapi +license: CC0-1.0 +authors: +- family-names: Hughes + given-names: Joseph D. + alias: jdhughes-usgs + affiliation: U.S. Geological Survey + orcid: https://orcid.org/0000-0003-1311-2354 +- family-names: Russcher + given-names: Martijn + alias: mjr-deltares + affiliation: Deltares + orcid: https://orcid.org/0000-0001-8799-6514 +- family-names: Langevin + given-names: Christian D. + alias: langevin-usgs + affiliation: U.S. Geological Survey + orcid: https://orcid.org/0000-0001-5610-9759 +- family-names: Hofer + given-names: Julian + alias: Hofer-Julian + affiliation: Deltares +- family-names: Larsen + given-names: Joshua D. + alias: jlarsen-usgs + affiliation: U.S. Geological Survey + orcid: https://orcid.org/0000-0002-1218-800X +preferred-citation: + type: article + authors: + - family-names: Hughes + given-names: Joseph D. + orcid: https://orcid.org/0000-0003-1311-2354 + - family-names: Russcher + given-names: Martijn J. + orcid: https://orcid.org/0000-0001-8799-6514 + - family-names: Langevin + given-names: Christian D. + orcid: https://orcid.org/0000-0001-5610-9759 + - family-names: Morway + given-names: Eric D. + orcid: https://orcid.org/0000-0002-8553-6140 + - family-names: McDonald + given-names: Richard R. + orcid: https://orcid.org/0000-0002-0703-0638 + title: The MODFLOW Application Programming Interface for simulation control and software interoperability + doi: 10.1016/j.envsoft.2021.105257 + journal: Environmental Modelling & Software + volume: 138 + start: 105257 + year: 2022 + month: 2 diff --git a/README.md b/README.md index b05708a..f3542aa 100644 --- a/README.md +++ b/README.md @@ -9,3 +9,7 @@ and additional functionality specific to the MODFLOW API. Currently it is a join ``` pip install modflowapi ``` + +### Citation + +Hughes, Joseph D., Russcher, M. J., Langevin, C. D., Morway, E. D. and McDonald, R. R., 2022, The MODFLOW Application Programming Interface for simulationcontrol and software interoperability: Environmental Modelling & Software, v. 148, p. 105257, [doi:10.1016/j.envsoft.2021.105257](https://doi.org/10.1016/j.envsoft.2021.105257). diff --git a/etc/requirements.pip.txt b/etc/requirements.pip.txt deleted file mode 100644 index f65b07c..0000000 --- a/etc/requirements.pip.txt +++ /dev/null @@ -1,12 +0,0 @@ -black -flake8 -pylint -nose -nose-timer -coverage -requests -appdirs -numpy -pandas -bmipy -xmipy diff --git a/guide-to-publish.md b/guide-to-publish.md index 285f861..dd43652 100644 --- a/guide-to-publish.md +++ b/guide-to-publish.md @@ -2,17 +2,17 @@ 1) If present delete dist folder -2) If not done yet, install twine via +2) If not done yet, install build and twine via ``` -pip install twine +pip install build twine ``` -3) Update the version number in the setup.py file. +3) Update the version in ``modflowapi/version.py`` 4) Re-create the wheels: ``` -python setup.py sdist bdist_wheel +python -m build ``` 5) Re-upload the new files: ``` twine upload dist/* -``` \ No newline at end of file +``` diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..691b4e6 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,67 @@ +[build-system] +requires = ["setuptools >=61"] +build-backend = "setuptools.build_meta" + +[project] +name = "modflowapi" +dynamic = ["version"] +authors = [ + {name = "Joseph D. Hughes", email = "jdhughes@usgs.gov"}, + {name = "Martijn Russcher", email = "Martijn.Russcher@deltares.nl"}, + {name = "Christian D. Langevin", email = "langevin@usgs.gov"}, + {name = "Julian Hofer", email = "Julian.Hofer@deltares.nl"}, + {name = "Joshua D. Larsen", email = "jlarsen@usgs.gov"}, +] +maintainers = [ + {name = "Joseph D. Hughes", email = "jdhughes@usgs.gov"}, +] +description = "modflowapi is an extension to the xmipy Python package" +readme = "README.md" +keywords = ["MODFLOW", "groundwater", "hydrogeology", "bmi", "xmi"] +license = {text = "CC0"} +classifiers = [ + "Intended Audience :: Science/Research", + "License :: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Topic :: Scientific/Engineering :: Hydrology", +] +requires-python = ">=3.8" +dependencies = [ + "numpy", + "pandas", + "xmipy", # develop branch from github.com/Deltares/xmipy +] + +[project.optional-dependencies] +dev = ["modflowapi[test,lint]"] +test = [ + "filelock", + "modflow-devtools", # develop branch from github.com/MODFLOW-USGS/modflow-devtools + "pytest", + "pytest-order", + "pytest-xdist", +] +lint = [ + "black", + "flake8", + "pylint", +] + +[project.urls] +Repository = "https://github.com/MODFLOW-USGS/modflowapi" +Publication = "https://doi.org/10.1016/j.envsoft.2021.105257" + +[tool.setuptools.dynamic] +version = {attr = "modflowapi.version.__version__"} + +[tool.setuptools.packages.find] +include = ["modflowapi", "modflowapi.*"] + +[tool.black] +line-length = 79 +target_version = ["py37"] diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index dc60b58..0000000 --- a/setup.cfg +++ /dev/null @@ -1,90 +0,0 @@ -[metadata] -name = modflowapi -version = attr: modflowapi.version.__version__ -description = modflowapi is an extension to the xmipy Python package -long_description = file: README.md -long_description_content_type = text/markdown -author = Joseph D. Hughes, Martijn Russcher, Christian D. Langevin, Julian Hofer, Joshua D. Larsen -author_email = jdhughes@usgs.gov, Martijn.Russcher@deltares.nl, langevin@usgs.gov, Julian.Hofer@deltares.nl, jlarsen@usgs.gov -maintainer = Joseph D. Hughes -maintainer_email = jdhughes@usgs.gov -license = CC0 -license_files = LICENSE -platform = Windows, Mac OS-X, Linux -keywords = MODFLOW, groundwater, hydrogeology -classifiers = - Development Status :: 5 - Production/Stable - Intended Audience :: Science/Research - License :: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication - Operating System :: Microsoft :: Windows - Operating System :: POSIX - Operating System :: Unix - Operating System :: MacOS - Programming Language :: Python - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.8 - Programming Language :: Python :: 3.9 - Programming Language :: Python :: 3.10 - Programming Language :: Python :: 3 :: Only - Topic :: Scientific/Engineering :: Hydrology -url = https://github.com/MODFLOW-USGS/modflowapi -download_url = https://pypi.org/project/modflowapi/ - -[options] -zip_safe = False -packages = find: -python_requires = >=3.8 -install_requires = - numpy - pandas - xmipy @ git+https://git@github.com/Deltares/xmipy@develop - -[options.extras_require] -lint = - black - flake8 - pylint - requests - -test = - %(lint)s - pytest - pytest-xdist - pytest-order - filelock - modflow-devtools @ git+https://git@github.com/MODFLOW-USGS/modflow-devtools@develop - -[flake8] -exclude = - .git, - __pycache__, - build, - dist, - examples, - autotest -ignore = - F401, - E121, - E122, - E126, - E127, - E128, - E203, - E221, - E222, - E226, - E231, - E241, - E402, - E501, - E502, - E722, - E741, - W291, - W292, - W293, - W391, - W503, - W504 - -statistics = True \ No newline at end of file diff --git a/setup.py b/setup.py old mode 100755 new mode 100644 index b024da8..5507373 --- a/setup.py +++ b/setup.py @@ -1,4 +1,4 @@ from setuptools import setup - -setup() +# see pyproject.toml for project metadata +setup(name="modflowapi") From a8e241df1def5899ccbf22368eddc76da0d7a60c Mon Sep 17 00:00:00 2001 From: Joshua Larsen Date: Wed, 29 Mar 2023 15:31:51 -0700 Subject: [PATCH 10/34] add(test_rhs_hcof_advanced): add additional test (#13) * added test for getting and setting rhs, hcof, and advanced variable values * update project to use unix line separators * use np.testing.assert_allclose() instead of AssertionError --- autotest/test_interface.py | 47 +++ examples/data/ats0/gwf_ats01a.ats | 20 +- examples/data/ats0/gwf_ats01a.dis | 48 +-- examples/data/ats0/gwf_ats01a.ghb | 28 +- examples/data/ats0/gwf_ats01a.ic | 12 +- examples/data/ats0/gwf_ats01a.ims | 44 +-- examples/data/ats0/gwf_ats01a.nam | 30 +- examples/data/ats0/gwf_ats01a.npf | 22 +- examples/data/ats0/gwf_ats01a.obs | 20 +- examples/data/ats0/gwf_ats01a.oc | 28 +- examples/data/ats0/gwf_ats01a.sto | 34 +- examples/data/ats0/gwf_ats01a.tdis | 28 +- examples/data/ats0/gwf_ats01a.wel | 28 +- examples/data/ats0/mfsim.nam | 38 +- examples/data/dis_model/mfsim.nam | 38 +- examples/data/dis_model/test_model.chd | 376 ++++++++++---------- examples/data/dis_model/test_model.dis | 68 ++-- examples/data/dis_model/test_model.drn | 136 +++---- examples/data/dis_model/test_model.evt | 136 +++---- examples/data/dis_model/test_model.ic | 12 +- examples/data/dis_model/test_model.ims | 40 +-- examples/data/dis_model/test_model.nam | 44 +-- examples/data/dis_model/test_model.npf | 24 +- examples/data/dis_model/test_model.oc | 152 ++++---- examples/data/dis_model/test_model.rch | 136 +++---- examples/data/dis_model/test_model.rcha | 20 +- examples/data/dis_model/test_model.sto | 26 +- examples/data/dis_model/test_model.tdis | 48 +-- examples/data/dis_model/test_model.wel | 162 ++++----- examples/data/disu_model/flow.disu.area.dat | 50 +-- examples/data/disu_model/flow.disu.cl12.dat | 242 ++++++------- examples/data/disu_model/flow.disu.hwva.dat | 242 ++++++------- examples/data/disu_model/flow.disu.iac.dat | 50 +-- examples/data/disu_model/flow.disu.ja.dat | 242 ++++++------- examples/data/disu_model/flow.oc | 22 +- examples/data/disu_model/flow.rch | 40 +-- examples/data/two_models/model1.oc | 22 +- examples/data/two_models/model2.oc | 22 +- examples/data/two_models/simulation.gnc | 116 +++--- examples/data/two_models/simulation.mvr | 42 +-- 40 files changed, 1491 insertions(+), 1444 deletions(-) diff --git a/autotest/test_interface.py b/autotest/test_interface.py index e14a14e..45f11a3 100644 --- a/autotest/test_interface.py +++ b/autotest/test_interface.py @@ -323,3 +323,50 @@ def callback(sim, step): run_simulation(so, test_pth, callback) except Exception as e: raise Exception(e) + + +def test_rhs_hcof_advanced(tmpdir): + def callback(sim, step): + model = sim.test_model + if step == Callbacks.timestep_start: + + wel = model.wel + rhs = wel.rhs + rhs[0:3] = [-150, -100, -50] + wel.rhs = rhs + + rhs2 = wel.get_advanced_var("rhs") + np.testing.assert_allclose( + rhs, rhs2, err_msg="rhs variable not being properly set" + ) + + hcof = wel.hcof + hcof[0: 3] = np.abs(rhs)[0:3] / 2 + + wel.hcof = hcof + + hcof2 = wel.get_advanced_var("hcof") + + np.testing.assert_allclose( + hcof, hcof2, err_msg="hcof is not being properly set" + ) + + rhs *= 1.2 + wel.set_advanced_var('rhs', rhs) + rhs3 = wel.rhs + + np.testing.assert_allclose( + rhs, + rhs3, + err_msg="set advanced var method not working properly" + ) + + name = "dis_model" + sim_pth = data_pth / name + test_pth = tmpdir / name + shutil.copytree(sim_pth, test_pth, dirs_exist_ok=True) + + try: + run_simulation(so, test_pth, callback) + except Exception as e: + raise Exception(e) \ No newline at end of file diff --git a/examples/data/ats0/gwf_ats01a.ats b/examples/data/ats0/gwf_ats01a.ats index 51ff2dd..703eb58 100644 --- a/examples/data/ats0/gwf_ats01a.ats +++ b/examples/data/ats0/gwf_ats01a.ats @@ -1,10 +1,10 @@ -# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. -BEGIN dimensions - MAXATS 2 -END dimensions - -BEGIN perioddata - 1 5.00000000 1.00100000E-05 10.00000000 2.00000000 5.00000000 - 8 5.00000000 1.00100000E-05 10.00000000 2.00000000 5.00000000 -END perioddata - +# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. +BEGIN dimensions + MAXATS 2 +END dimensions + +BEGIN perioddata + 1 5.00000000 1.00100000E-05 10.00000000 2.00000000 5.00000000 + 8 5.00000000 1.00100000E-05 10.00000000 2.00000000 5.00000000 +END perioddata + diff --git a/examples/data/ats0/gwf_ats01a.dis b/examples/data/ats0/gwf_ats01a.dis index d1f42df..d32b5a4 100644 --- a/examples/data/ats0/gwf_ats01a.dis +++ b/examples/data/ats0/gwf_ats01a.dis @@ -1,24 +1,24 @@ -# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. -BEGIN options -END options - -BEGIN dimensions - NLAY 1 - NROW 1 - NCOL 2 -END dimensions - -BEGIN griddata - delr - CONSTANT 100.00000000 - delc - CONSTANT 1.00000000 - top - CONSTANT 100.00000000 - botm - CONSTANT 0.00000000 - idomain - INTERNAL FACTOR 1 - 1 1 -END griddata - +# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. +BEGIN options +END options + +BEGIN dimensions + NLAY 1 + NROW 1 + NCOL 2 +END dimensions + +BEGIN griddata + delr + CONSTANT 100.00000000 + delc + CONSTANT 1.00000000 + top + CONSTANT 100.00000000 + botm + CONSTANT 0.00000000 + idomain + INTERNAL FACTOR 1 + 1 1 +END griddata + diff --git a/examples/data/ats0/gwf_ats01a.ghb b/examples/data/ats0/gwf_ats01a.ghb index fa6adfe..d0cec89 100644 --- a/examples/data/ats0/gwf_ats01a.ghb +++ b/examples/data/ats0/gwf_ats01a.ghb @@ -1,14 +1,14 @@ -# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. -BEGIN options - PRINT_INPUT - PRINT_FLOWS -END options - -BEGIN dimensions - MAXBOUND 1 -END dimensions - -BEGIN period 1 - 1 1 1 50.00000000 1.00000000 -END period 1 - +# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. +BEGIN options + PRINT_INPUT + PRINT_FLOWS +END options + +BEGIN dimensions + MAXBOUND 1 +END dimensions + +BEGIN period 1 + 1 1 1 50.00000000 1.00000000 +END period 1 + diff --git a/examples/data/ats0/gwf_ats01a.ic b/examples/data/ats0/gwf_ats01a.ic index d8c8b3c..cdeae07 100644 --- a/examples/data/ats0/gwf_ats01a.ic +++ b/examples/data/ats0/gwf_ats01a.ic @@ -1,6 +1,6 @@ -# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. -BEGIN griddata - strt - CONSTANT 50.00000000 -END griddata - +# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. +BEGIN griddata + strt + CONSTANT 50.00000000 +END griddata + diff --git a/examples/data/ats0/gwf_ats01a.ims b/examples/data/ats0/gwf_ats01a.ims index d7c7244..40086cf 100644 --- a/examples/data/ats0/gwf_ats01a.ims +++ b/examples/data/ats0/gwf_ats01a.ims @@ -1,22 +1,22 @@ -# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. -BEGIN options - PRINT_OPTION summary -END options - -BEGIN nonlinear - OUTER_DVCLOSE 1.00000000E-06 - OUTER_MAXIMUM 10 - UNDER_RELAXATION dbd - UNDER_RELAXATION_THETA 0.70000000 -END nonlinear - -BEGIN linear - INNER_MAXIMUM 2 - INNER_DVCLOSE 1.00000000E-06 - inner_rclose 1.00000000E-06 - LINEAR_ACCELERATION cg - RELAXATION_FACTOR 0.97000000 - SCALING_METHOD none - REORDERING_METHOD none -END linear - +# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. +BEGIN options + PRINT_OPTION summary +END options + +BEGIN nonlinear + OUTER_DVCLOSE 1.00000000E-06 + OUTER_MAXIMUM 10 + UNDER_RELAXATION dbd + UNDER_RELAXATION_THETA 0.70000000 +END nonlinear + +BEGIN linear + INNER_MAXIMUM 2 + INNER_DVCLOSE 1.00000000E-06 + inner_rclose 1.00000000E-06 + LINEAR_ACCELERATION cg + RELAXATION_FACTOR 0.97000000 + SCALING_METHOD none + REORDERING_METHOD none +END linear + diff --git a/examples/data/ats0/gwf_ats01a.nam b/examples/data/ats0/gwf_ats01a.nam index b55815a..41819b1 100644 --- a/examples/data/ats0/gwf_ats01a.nam +++ b/examples/data/ats0/gwf_ats01a.nam @@ -1,15 +1,15 @@ -# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. -BEGIN options -END options - -BEGIN packages - DIS6 gwf_ats01a.dis dis - IC6 gwf_ats01a.ic ic - NPF6 gwf_ats01a.npf npf - STO6 gwf_ats01a.sto sto - WEL6 gwf_ats01a.wel wel_0 - GHB6 gwf_ats01a.ghb ghb_0 - OC6 gwf_ats01a.oc oc - OBS6 gwf_ats01a.obs head_obs -END packages - +# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. +BEGIN options +END options + +BEGIN packages + DIS6 gwf_ats01a.dis dis + IC6 gwf_ats01a.ic ic + NPF6 gwf_ats01a.npf npf + STO6 gwf_ats01a.sto sto + WEL6 gwf_ats01a.wel wel_0 + GHB6 gwf_ats01a.ghb ghb_0 + OC6 gwf_ats01a.oc oc + OBS6 gwf_ats01a.obs head_obs +END packages + diff --git a/examples/data/ats0/gwf_ats01a.npf b/examples/data/ats0/gwf_ats01a.npf index 6093b98..c44027f 100644 --- a/examples/data/ats0/gwf_ats01a.npf +++ b/examples/data/ats0/gwf_ats01a.npf @@ -1,11 +1,11 @@ -# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. -BEGIN options -END options - -BEGIN griddata - icelltype - CONSTANT 1 - k - CONSTANT 1.00000000 -END griddata - +# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. +BEGIN options +END options + +BEGIN griddata + icelltype + CONSTANT 1 + k + CONSTANT 1.00000000 +END griddata + diff --git a/examples/data/ats0/gwf_ats01a.obs b/examples/data/ats0/gwf_ats01a.obs index b5d05f7..bba9adf 100644 --- a/examples/data/ats0/gwf_ats01a.obs +++ b/examples/data/ats0/gwf_ats01a.obs @@ -1,10 +1,10 @@ -# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. -BEGIN options - DIGITS 20 -END options - -BEGIN continuous FILEOUT gwf_ats01a.obs.csv - obs1 head 1 1 1 - obs2 head 1 1 2 -END continuous FILEOUT gwf_ats01a.obs.csv - +# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. +BEGIN options + DIGITS 20 +END options + +BEGIN continuous FILEOUT gwf_ats01a.obs.csv + obs1 head 1 1 1 + obs2 head 1 1 2 +END continuous FILEOUT gwf_ats01a.obs.csv + diff --git a/examples/data/ats0/gwf_ats01a.oc b/examples/data/ats0/gwf_ats01a.oc index 71a7f21..909efb2 100644 --- a/examples/data/ats0/gwf_ats01a.oc +++ b/examples/data/ats0/gwf_ats01a.oc @@ -1,14 +1,14 @@ -# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. -BEGIN options - BUDGET FILEOUT gwf_ats01a.cbc - BUDGETCSV FILEOUT gwf_ats01a.csv - HEAD FILEOUT gwf_ats01a.hds - HEAD PRINT_FORMAT COLUMNS 10 WIDTH 15 DIGITS 6 GENERAL -END options - -BEGIN period 1 - SAVE HEAD ALL - PRINT HEAD ALL - PRINT BUDGET ALL -END period 1 - +# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. +BEGIN options + BUDGET FILEOUT gwf_ats01a.cbc + BUDGETCSV FILEOUT gwf_ats01a.csv + HEAD FILEOUT gwf_ats01a.hds + HEAD PRINT_FORMAT COLUMNS 10 WIDTH 15 DIGITS 6 GENERAL +END options + +BEGIN period 1 + SAVE HEAD ALL + PRINT HEAD ALL + PRINT BUDGET ALL +END period 1 + diff --git a/examples/data/ats0/gwf_ats01a.sto b/examples/data/ats0/gwf_ats01a.sto index 1bc176c..5a82c66 100644 --- a/examples/data/ats0/gwf_ats01a.sto +++ b/examples/data/ats0/gwf_ats01a.sto @@ -1,17 +1,17 @@ -# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. -BEGIN options -END options - -BEGIN griddata - iconvert - CONSTANT 1 - ss - CONSTANT 0.00000000 - sy - CONSTANT 0.10000000 -END griddata - -BEGIN period 1 - TRANSIENT -END period 1 - +# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. +BEGIN options +END options + +BEGIN griddata + iconvert + CONSTANT 1 + ss + CONSTANT 0.00000000 + sy + CONSTANT 0.10000000 +END griddata + +BEGIN period 1 + TRANSIENT +END period 1 + diff --git a/examples/data/ats0/gwf_ats01a.tdis b/examples/data/ats0/gwf_ats01a.tdis index bd34906..1427d85 100644 --- a/examples/data/ats0/gwf_ats01a.tdis +++ b/examples/data/ats0/gwf_ats01a.tdis @@ -1,14 +1,14 @@ -# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. -BEGIN options - TIME_UNITS days - ATS6 FILEIN gwf_ats01a.ats -END options - -BEGIN dimensions - NPER 1 -END dimensions - -BEGIN perioddata - 10.00000000 1 1.00000000 -END perioddata - +# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. +BEGIN options + TIME_UNITS days + ATS6 FILEIN gwf_ats01a.ats +END options + +BEGIN dimensions + NPER 1 +END dimensions + +BEGIN perioddata + 10.00000000 1 1.00000000 +END perioddata + diff --git a/examples/data/ats0/gwf_ats01a.wel b/examples/data/ats0/gwf_ats01a.wel index 2c50997..9fd3033 100644 --- a/examples/data/ats0/gwf_ats01a.wel +++ b/examples/data/ats0/gwf_ats01a.wel @@ -1,14 +1,14 @@ -# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. -BEGIN options - PRINT_INPUT - PRINT_FLOWS -END options - -BEGIN dimensions - MAXBOUND 1 -END dimensions - -BEGIN period 1 - 1 1 2 -10.00000000 -END period 1 - +# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. +BEGIN options + PRINT_INPUT + PRINT_FLOWS +END options + +BEGIN dimensions + MAXBOUND 1 +END dimensions + +BEGIN period 1 + 1 1 2 -10.00000000 +END period 1 + diff --git a/examples/data/ats0/mfsim.nam b/examples/data/ats0/mfsim.nam index 46a2634..3f95669 100644 --- a/examples/data/ats0/mfsim.nam +++ b/examples/data/ats0/mfsim.nam @@ -1,19 +1,19 @@ -# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. -BEGIN options -END options - -BEGIN timing - TDIS6 gwf_ats01a.tdis -END timing - -BEGIN models - gwf6 gwf_ats01a.nam gwf_ats01a -END models - -BEGIN exchanges -END exchanges - -BEGIN solutiongroup 1 - ims6 gwf_ats01a.ims gwf_ats01a -END solutiongroup 1 - +# File generated by Flopy version 3.3.6 on 12/21/2022 at 10:15:53. +BEGIN options +END options + +BEGIN timing + TDIS6 gwf_ats01a.tdis +END timing + +BEGIN models + gwf6 gwf_ats01a.nam gwf_ats01a +END models + +BEGIN exchanges +END exchanges + +BEGIN solutiongroup 1 + ims6 gwf_ats01a.ims gwf_ats01a +END solutiongroup 1 + diff --git a/examples/data/dis_model/mfsim.nam b/examples/data/dis_model/mfsim.nam index 3e36193..f1ec84b 100644 --- a/examples/data/dis_model/mfsim.nam +++ b/examples/data/dis_model/mfsim.nam @@ -1,19 +1,19 @@ -# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. -BEGIN options -END options - -BEGIN timing - TDIS6 test_model.tdis -END timing - -BEGIN models - gwf6 test_model.nam test_model -END models - -BEGIN exchanges -END exchanges - -BEGIN solutiongroup 1 - ims6 test_model.ims test_model -END solutiongroup 1 - +# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. +BEGIN options +END options + +BEGIN timing + TDIS6 test_model.tdis +END timing + +BEGIN models + gwf6 test_model.nam test_model +END models + +BEGIN exchanges +END exchanges + +BEGIN solutiongroup 1 + ims6 test_model.ims test_model +END solutiongroup 1 + diff --git a/examples/data/dis_model/test_model.chd b/examples/data/dis_model/test_model.chd index 25556d1..a3b56a2 100644 --- a/examples/data/dis_model/test_model.chd +++ b/examples/data/dis_model/test_model.chd @@ -1,188 +1,188 @@ -# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. -BEGIN options -END options - -BEGIN dimensions - MAXBOUND 12 -END dimensions - -BEGIN period 1 - 1 1 3 95.00000000 - 1 1 4 95.00000000 - 1 1 5 95.00000000 - 1 1 6 95.00000000 - 1 1 7 95.00000000 - 1 1 8 95.00000000 - 1 10 3 75.00000000 - 1 10 4 75.00000000 - 1 10 5 75.00000000 - 1 10 6 75.00000000 - 1 10 7 75.00000000 - 1 10 8 75.00000000 -END period 1 - -BEGIN period 2 - 1 1 3 95.00000000 - 1 1 4 95.00000000 - 1 1 5 95.00000000 - 1 1 6 95.00000000 - 1 1 7 95.00000000 - 1 1 8 95.00000000 - 1 10 3 75.00000000 - 1 10 4 75.00000000 - 1 10 5 75.00000000 - 1 10 6 75.00000000 - 1 10 7 75.00000000 - 1 10 8 75.00000000 -END period 2 - -BEGIN period 3 - 1 1 3 95.00000000 - 1 1 4 95.00000000 - 1 1 5 95.00000000 - 1 1 6 95.00000000 - 1 1 7 95.00000000 - 1 1 8 95.00000000 - 1 10 3 75.00000000 - 1 10 4 75.00000000 - 1 10 5 75.00000000 - 1 10 6 75.00000000 - 1 10 7 75.00000000 - 1 10 8 75.00000000 -END period 3 - -BEGIN period 4 - 1 1 3 95.00000000 - 1 1 4 95.00000000 - 1 1 5 95.00000000 - 1 1 6 95.00000000 - 1 1 7 95.00000000 - 1 1 8 95.00000000 - 1 10 3 75.00000000 - 1 10 4 75.00000000 - 1 10 5 75.00000000 - 1 10 6 75.00000000 - 1 10 7 75.00000000 - 1 10 8 75.00000000 -END period 4 - -BEGIN period 5 - 1 1 3 95.00000000 - 1 1 4 95.00000000 - 1 1 5 95.00000000 - 1 1 6 95.00000000 - 1 1 7 95.00000000 - 1 1 8 95.00000000 - 1 10 3 75.00000000 - 1 10 4 75.00000000 - 1 10 5 75.00000000 - 1 10 6 75.00000000 - 1 10 7 75.00000000 - 1 10 8 75.00000000 -END period 5 - -BEGIN period 6 - 1 1 3 95.00000000 - 1 1 4 95.00000000 - 1 1 5 95.00000000 - 1 1 6 95.00000000 - 1 1 7 95.00000000 - 1 1 8 95.00000000 - 1 10 3 75.00000000 - 1 10 4 75.00000000 - 1 10 5 75.00000000 - 1 10 6 75.00000000 - 1 10 7 75.00000000 - 1 10 8 75.00000000 -END period 6 - -BEGIN period 7 - 1 1 3 95.00000000 - 1 1 4 95.00000000 - 1 1 5 95.00000000 - 1 1 6 95.00000000 - 1 1 7 95.00000000 - 1 1 8 95.00000000 - 1 10 3 75.00000000 - 1 10 4 75.00000000 - 1 10 5 75.00000000 - 1 10 6 75.00000000 - 1 10 7 75.00000000 - 1 10 8 75.00000000 -END period 7 - -BEGIN period 8 - 1 1 3 95.00000000 - 1 1 4 95.00000000 - 1 1 5 95.00000000 - 1 1 6 95.00000000 - 1 1 7 95.00000000 - 1 1 8 95.00000000 - 1 10 3 75.00000000 - 1 10 4 75.00000000 - 1 10 5 75.00000000 - 1 10 6 75.00000000 - 1 10 7 75.00000000 - 1 10 8 75.00000000 -END period 8 - -BEGIN period 9 - 1 1 3 95.00000000 - 1 1 4 95.00000000 - 1 1 5 95.00000000 - 1 1 6 95.00000000 - 1 1 7 95.00000000 - 1 1 8 95.00000000 - 1 10 3 75.00000000 - 1 10 4 75.00000000 - 1 10 5 75.00000000 - 1 10 6 75.00000000 - 1 10 7 75.00000000 - 1 10 8 75.00000000 -END period 9 - -BEGIN period 10 - 1 1 3 95.00000000 - 1 1 4 95.00000000 - 1 1 5 95.00000000 - 1 1 6 95.00000000 - 1 1 7 95.00000000 - 1 1 8 95.00000000 - 1 10 3 75.00000000 - 1 10 4 75.00000000 - 1 10 5 75.00000000 - 1 10 6 75.00000000 - 1 10 7 75.00000000 - 1 10 8 75.00000000 -END period 10 - -BEGIN period 11 - 1 1 3 95.00000000 - 1 1 4 95.00000000 - 1 1 5 95.00000000 - 1 1 6 95.00000000 - 1 1 7 95.00000000 - 1 1 8 95.00000000 - 1 10 3 75.00000000 - 1 10 4 75.00000000 - 1 10 5 75.00000000 - 1 10 6 75.00000000 - 1 10 7 75.00000000 - 1 10 8 75.00000000 -END period 11 - -BEGIN period 12 - 1 1 3 95.00000000 - 1 1 4 95.00000000 - 1 1 5 95.00000000 - 1 1 6 95.00000000 - 1 1 7 95.00000000 - 1 1 8 95.00000000 - 1 10 3 75.00000000 - 1 10 4 75.00000000 - 1 10 5 75.00000000 - 1 10 6 75.00000000 - 1 10 7 75.00000000 - 1 10 8 75.00000000 -END period 12 - +# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. +BEGIN options +END options + +BEGIN dimensions + MAXBOUND 12 +END dimensions + +BEGIN period 1 + 1 1 3 95.00000000 + 1 1 4 95.00000000 + 1 1 5 95.00000000 + 1 1 6 95.00000000 + 1 1 7 95.00000000 + 1 1 8 95.00000000 + 1 10 3 75.00000000 + 1 10 4 75.00000000 + 1 10 5 75.00000000 + 1 10 6 75.00000000 + 1 10 7 75.00000000 + 1 10 8 75.00000000 +END period 1 + +BEGIN period 2 + 1 1 3 95.00000000 + 1 1 4 95.00000000 + 1 1 5 95.00000000 + 1 1 6 95.00000000 + 1 1 7 95.00000000 + 1 1 8 95.00000000 + 1 10 3 75.00000000 + 1 10 4 75.00000000 + 1 10 5 75.00000000 + 1 10 6 75.00000000 + 1 10 7 75.00000000 + 1 10 8 75.00000000 +END period 2 + +BEGIN period 3 + 1 1 3 95.00000000 + 1 1 4 95.00000000 + 1 1 5 95.00000000 + 1 1 6 95.00000000 + 1 1 7 95.00000000 + 1 1 8 95.00000000 + 1 10 3 75.00000000 + 1 10 4 75.00000000 + 1 10 5 75.00000000 + 1 10 6 75.00000000 + 1 10 7 75.00000000 + 1 10 8 75.00000000 +END period 3 + +BEGIN period 4 + 1 1 3 95.00000000 + 1 1 4 95.00000000 + 1 1 5 95.00000000 + 1 1 6 95.00000000 + 1 1 7 95.00000000 + 1 1 8 95.00000000 + 1 10 3 75.00000000 + 1 10 4 75.00000000 + 1 10 5 75.00000000 + 1 10 6 75.00000000 + 1 10 7 75.00000000 + 1 10 8 75.00000000 +END period 4 + +BEGIN period 5 + 1 1 3 95.00000000 + 1 1 4 95.00000000 + 1 1 5 95.00000000 + 1 1 6 95.00000000 + 1 1 7 95.00000000 + 1 1 8 95.00000000 + 1 10 3 75.00000000 + 1 10 4 75.00000000 + 1 10 5 75.00000000 + 1 10 6 75.00000000 + 1 10 7 75.00000000 + 1 10 8 75.00000000 +END period 5 + +BEGIN period 6 + 1 1 3 95.00000000 + 1 1 4 95.00000000 + 1 1 5 95.00000000 + 1 1 6 95.00000000 + 1 1 7 95.00000000 + 1 1 8 95.00000000 + 1 10 3 75.00000000 + 1 10 4 75.00000000 + 1 10 5 75.00000000 + 1 10 6 75.00000000 + 1 10 7 75.00000000 + 1 10 8 75.00000000 +END period 6 + +BEGIN period 7 + 1 1 3 95.00000000 + 1 1 4 95.00000000 + 1 1 5 95.00000000 + 1 1 6 95.00000000 + 1 1 7 95.00000000 + 1 1 8 95.00000000 + 1 10 3 75.00000000 + 1 10 4 75.00000000 + 1 10 5 75.00000000 + 1 10 6 75.00000000 + 1 10 7 75.00000000 + 1 10 8 75.00000000 +END period 7 + +BEGIN period 8 + 1 1 3 95.00000000 + 1 1 4 95.00000000 + 1 1 5 95.00000000 + 1 1 6 95.00000000 + 1 1 7 95.00000000 + 1 1 8 95.00000000 + 1 10 3 75.00000000 + 1 10 4 75.00000000 + 1 10 5 75.00000000 + 1 10 6 75.00000000 + 1 10 7 75.00000000 + 1 10 8 75.00000000 +END period 8 + +BEGIN period 9 + 1 1 3 95.00000000 + 1 1 4 95.00000000 + 1 1 5 95.00000000 + 1 1 6 95.00000000 + 1 1 7 95.00000000 + 1 1 8 95.00000000 + 1 10 3 75.00000000 + 1 10 4 75.00000000 + 1 10 5 75.00000000 + 1 10 6 75.00000000 + 1 10 7 75.00000000 + 1 10 8 75.00000000 +END period 9 + +BEGIN period 10 + 1 1 3 95.00000000 + 1 1 4 95.00000000 + 1 1 5 95.00000000 + 1 1 6 95.00000000 + 1 1 7 95.00000000 + 1 1 8 95.00000000 + 1 10 3 75.00000000 + 1 10 4 75.00000000 + 1 10 5 75.00000000 + 1 10 6 75.00000000 + 1 10 7 75.00000000 + 1 10 8 75.00000000 +END period 10 + +BEGIN period 11 + 1 1 3 95.00000000 + 1 1 4 95.00000000 + 1 1 5 95.00000000 + 1 1 6 95.00000000 + 1 1 7 95.00000000 + 1 1 8 95.00000000 + 1 10 3 75.00000000 + 1 10 4 75.00000000 + 1 10 5 75.00000000 + 1 10 6 75.00000000 + 1 10 7 75.00000000 + 1 10 8 75.00000000 +END period 11 + +BEGIN period 12 + 1 1 3 95.00000000 + 1 1 4 95.00000000 + 1 1 5 95.00000000 + 1 1 6 95.00000000 + 1 1 7 95.00000000 + 1 1 8 95.00000000 + 1 10 3 75.00000000 + 1 10 4 75.00000000 + 1 10 5 75.00000000 + 1 10 6 75.00000000 + 1 10 7 75.00000000 + 1 10 8 75.00000000 +END period 12 + diff --git a/examples/data/dis_model/test_model.dis b/examples/data/dis_model/test_model.dis index b23a15c..13e5658 100644 --- a/examples/data/dis_model/test_model.dis +++ b/examples/data/dis_model/test_model.dis @@ -1,34 +1,34 @@ -# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. -BEGIN options - LENGTH_UNITS meters -END options - -BEGIN dimensions - NLAY 1 - NROW 10 - NCOL 10 -END dimensions - -BEGIN griddata - delr - CONSTANT 63.60000000 - delc - CONSTANT 63.60000000 - top - CONSTANT 100.00000000 - botm - CONSTANT 0.00000000 - IDOMAIN - INTERNAL FACTOR 1 - 0 0 1 1 1 1 1 1 0 0 - 0 1 1 1 1 1 1 1 1 0 - 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 - 0 1 1 1 1 1 1 1 1 0 - 0 0 1 1 1 1 1 1 0 0 -END griddata - +# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. +BEGIN options + LENGTH_UNITS meters +END options + +BEGIN dimensions + NLAY 1 + NROW 10 + NCOL 10 +END dimensions + +BEGIN griddata + delr + CONSTANT 63.60000000 + delc + CONSTANT 63.60000000 + top + CONSTANT 100.00000000 + botm + CONSTANT 0.00000000 + IDOMAIN + INTERNAL FACTOR 1 + 0 0 1 1 1 1 1 1 0 0 + 0 1 1 1 1 1 1 1 1 0 + 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 + 0 1 1 1 1 1 1 1 1 0 + 0 0 1 1 1 1 1 1 0 0 +END griddata + diff --git a/examples/data/dis_model/test_model.drn b/examples/data/dis_model/test_model.drn index a0f40a5..08afd2a 100644 --- a/examples/data/dis_model/test_model.drn +++ b/examples/data/dis_model/test_model.drn @@ -1,68 +1,68 @@ -# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. -BEGIN options -END options - -BEGIN dimensions - MAXBOUND 2 -END dimensions - -BEGIN period 1 - 1 2 3 94.00000000 10.00000000 - 1 2 4 95.00000000 10.00000000 -END period 1 - -BEGIN period 2 - 1 2 3 94.00000000 10.00000000 - 1 2 4 95.00000000 10.00000000 -END period 2 - -BEGIN period 3 - 1 2 3 94.00000000 10.00000000 - 1 2 4 95.00000000 10.00000000 -END period 3 - -BEGIN period 4 - 1 2 3 94.00000000 10.00000000 - 1 2 4 95.00000000 10.00000000 -END period 4 - -BEGIN period 5 - 1 2 3 94.00000000 10.00000000 - 1 2 4 95.00000000 10.00000000 -END period 5 - -BEGIN period 6 - 1 2 3 94.00000000 10.00000000 - 1 2 4 95.00000000 10.00000000 -END period 6 - -BEGIN period 7 - 1 2 3 94.00000000 10.00000000 - 1 2 4 95.00000000 10.00000000 -END period 7 - -BEGIN period 8 - 1 2 3 94.00000000 10.00000000 - 1 2 4 95.00000000 10.00000000 -END period 8 - -BEGIN period 9 - 1 2 3 94.00000000 10.00000000 - 1 2 4 95.00000000 10.00000000 -END period 9 - -BEGIN period 10 - 1 2 3 94.00000000 10.00000000 - 1 2 4 95.00000000 10.00000000 -END period 10 - -BEGIN period 11 - 1 2 3 94.00000000 10.00000000 - 1 2 4 95.00000000 10.00000000 -END period 11 - -BEGIN period 12 - 1 2 3 94.00000000 10.00000000 - 1 2 4 95.00000000 10.00000000 -END period 12 - +# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. +BEGIN options +END options + +BEGIN dimensions + MAXBOUND 2 +END dimensions + +BEGIN period 1 + 1 2 3 94.00000000 10.00000000 + 1 2 4 95.00000000 10.00000000 +END period 1 + +BEGIN period 2 + 1 2 3 94.00000000 10.00000000 + 1 2 4 95.00000000 10.00000000 +END period 2 + +BEGIN period 3 + 1 2 3 94.00000000 10.00000000 + 1 2 4 95.00000000 10.00000000 +END period 3 + +BEGIN period 4 + 1 2 3 94.00000000 10.00000000 + 1 2 4 95.00000000 10.00000000 +END period 4 + +BEGIN period 5 + 1 2 3 94.00000000 10.00000000 + 1 2 4 95.00000000 10.00000000 +END period 5 + +BEGIN period 6 + 1 2 3 94.00000000 10.00000000 + 1 2 4 95.00000000 10.00000000 +END period 6 + +BEGIN period 7 + 1 2 3 94.00000000 10.00000000 + 1 2 4 95.00000000 10.00000000 +END period 7 + +BEGIN period 8 + 1 2 3 94.00000000 10.00000000 + 1 2 4 95.00000000 10.00000000 +END period 8 + +BEGIN period 9 + 1 2 3 94.00000000 10.00000000 + 1 2 4 95.00000000 10.00000000 +END period 9 + +BEGIN period 10 + 1 2 3 94.00000000 10.00000000 + 1 2 4 95.00000000 10.00000000 +END period 10 + +BEGIN period 11 + 1 2 3 94.00000000 10.00000000 + 1 2 4 95.00000000 10.00000000 +END period 11 + +BEGIN period 12 + 1 2 3 94.00000000 10.00000000 + 1 2 4 95.00000000 10.00000000 +END period 12 + diff --git a/examples/data/dis_model/test_model.evt b/examples/data/dis_model/test_model.evt index d6bdb33..70e727f 100644 --- a/examples/data/dis_model/test_model.evt +++ b/examples/data/dis_model/test_model.evt @@ -1,68 +1,68 @@ -# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. -BEGIN options -END options - -BEGIN dimensions - MAXBOUND 2 -END dimensions - -BEGIN period 1 - 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 - 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 -END period 1 - -BEGIN period 2 - 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 - 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 -END period 2 - -BEGIN period 3 - 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 - 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 -END period 3 - -BEGIN period 4 - 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 - 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 -END period 4 - -BEGIN period 5 - 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 - 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 -END period 5 - -BEGIN period 6 - 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 - 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 -END period 6 - -BEGIN period 7 - 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 - 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 -END period 7 - -BEGIN period 8 - 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 - 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 -END period 8 - -BEGIN period 9 - 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 - 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 -END period 9 - -BEGIN period 10 - 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 - 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 -END period 10 - -BEGIN period 11 - 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 - 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 -END period 11 - -BEGIN period 12 - 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 - 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 -END period 12 - +# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. +BEGIN options +END options + +BEGIN dimensions + MAXBOUND 2 +END dimensions + +BEGIN period 1 + 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 + 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 +END period 1 + +BEGIN period 2 + 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 + 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 +END period 2 + +BEGIN period 3 + 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 + 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 +END period 3 + +BEGIN period 4 + 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 + 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 +END period 4 + +BEGIN period 5 + 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 + 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 +END period 5 + +BEGIN period 6 + 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 + 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 +END period 6 + +BEGIN period 7 + 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 + 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 +END period 7 + +BEGIN period 8 + 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 + 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 +END period 8 + +BEGIN period 9 + 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 + 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 +END period 9 + +BEGIN period 10 + 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 + 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 +END period 10 + +BEGIN period 11 + 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 + 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 +END period 11 + +BEGIN period 12 + 1 5 4 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 + 1 5 5 100.00000000 0.02000000 10.00000000 0.20000000 0.10000000 +END period 12 + diff --git a/examples/data/dis_model/test_model.ic b/examples/data/dis_model/test_model.ic index 5503fc6..2190fe4 100644 --- a/examples/data/dis_model/test_model.ic +++ b/examples/data/dis_model/test_model.ic @@ -1,6 +1,6 @@ -# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. -BEGIN griddata - strt - CONSTANT 95.00000000 -END griddata - +# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. +BEGIN griddata + strt + CONSTANT 95.00000000 +END griddata + diff --git a/examples/data/dis_model/test_model.ims b/examples/data/dis_model/test_model.ims index 3e054f9..c644a65 100644 --- a/examples/data/dis_model/test_model.ims +++ b/examples/data/dis_model/test_model.ims @@ -1,20 +1,20 @@ -# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. -BEGIN options - PRINT_OPTION all - COMPLEXITY complex - NO_PTC ALL -END options - -BEGIN nonlinear - UNDER_RELAXATION dbd - UNDER_RELAXATION_GAMMA 0.00000000 - UNDER_RELAXATION_THETA 0.97000000 - UNDER_RELAXATION_KAPPA 1.00000000E-04 -END nonlinear - -BEGIN linear - inner_rclose 1.00000000E-10 L2NORM_RCLOSE - LINEAR_ACCELERATION bicgstab - SCALING_METHOD l2norm -END linear - +# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. +BEGIN options + PRINT_OPTION all + COMPLEXITY complex + NO_PTC ALL +END options + +BEGIN nonlinear + UNDER_RELAXATION dbd + UNDER_RELAXATION_GAMMA 0.00000000 + UNDER_RELAXATION_THETA 0.97000000 + UNDER_RELAXATION_KAPPA 1.00000000E-04 +END nonlinear + +BEGIN linear + inner_rclose 1.00000000E-10 L2NORM_RCLOSE + LINEAR_ACCELERATION bicgstab + SCALING_METHOD l2norm +END linear + diff --git a/examples/data/dis_model/test_model.nam b/examples/data/dis_model/test_model.nam index e6eb44f..2a4522d 100644 --- a/examples/data/dis_model/test_model.nam +++ b/examples/data/dis_model/test_model.nam @@ -1,22 +1,22 @@ -# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. -BEGIN options - PRINT_INPUT - PRINT_FLOWS - SAVE_FLOWS - NEWTON UNDER_RELAXATION -END options - -BEGIN packages - DIS6 test_model.dis dis - IC6 test_model.ic ic - NPF6 test_model.npf npf - STO6 test_model.sto sto - WEL6 test_model.wel wel_0 - DRN6 test_model.drn drn_0 - RCH6 test_model.rch rch_0 - RCH6 test_model.rcha rcha_0 - CHD6 test_model.chd chd_0 - EVT6 test_model.evt evt_0 - OC6 test_model.oc oc -END packages - +# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. +BEGIN options + PRINT_INPUT + PRINT_FLOWS + SAVE_FLOWS + NEWTON UNDER_RELAXATION +END options + +BEGIN packages + DIS6 test_model.dis dis + IC6 test_model.ic ic + NPF6 test_model.npf npf + STO6 test_model.sto sto + WEL6 test_model.wel wel_0 + DRN6 test_model.drn drn_0 + RCH6 test_model.rch rch_0 + RCH6 test_model.rcha rcha_0 + CHD6 test_model.chd chd_0 + EVT6 test_model.evt evt_0 + OC6 test_model.oc oc +END packages + diff --git a/examples/data/dis_model/test_model.npf b/examples/data/dis_model/test_model.npf index 7be835b..42b6bc6 100644 --- a/examples/data/dis_model/test_model.npf +++ b/examples/data/dis_model/test_model.npf @@ -1,12 +1,12 @@ -# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. -BEGIN options - SAVE_SPECIFIC_DISCHARGE -END options - -BEGIN griddata - icelltype - CONSTANT 1 - k - CONSTANT 1.00000000 -END griddata - +# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. +BEGIN options + SAVE_SPECIFIC_DISCHARGE +END options + +BEGIN griddata + icelltype + CONSTANT 1 + k + CONSTANT 1.00000000 +END griddata + diff --git a/examples/data/dis_model/test_model.oc b/examples/data/dis_model/test_model.oc index 365b28d..93314c0 100644 --- a/examples/data/dis_model/test_model.oc +++ b/examples/data/dis_model/test_model.oc @@ -1,76 +1,76 @@ -# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. -BEGIN options - BUDGET FILEOUT test_model.cbc - HEAD FILEOUT test_model.hds -END options - -BEGIN period 1 - SAVE HEAD ALL - SAVE BUDGET ALL - PRINT HEAD ALL - PRINT BUDGET ALL -END period 1 - -BEGIN period 2 - SAVE HEAD ALL - SAVE BUDGET ALL - PRINT HEAD ALL - PRINT BUDGET ALL -END period 2 - -BEGIN period 3 - SAVE HEAD ALL - SAVE BUDGET ALL - PRINT HEAD ALL - PRINT BUDGET ALL -END period 3 - -BEGIN period 4 - SAVE HEAD ALL - SAVE BUDGET ALL - PRINT HEAD ALL - PRINT BUDGET ALL -END period 4 - -BEGIN period 5 - SAVE HEAD ALL - SAVE BUDGET ALL - PRINT HEAD ALL - PRINT BUDGET ALL -END period 5 - -BEGIN period 6 - SAVE HEAD ALL - SAVE BUDGET ALL - PRINT HEAD ALL - PRINT BUDGET ALL -END period 6 - -BEGIN period 7 - SAVE HEAD ALL - SAVE BUDGET ALL - PRINT HEAD ALL - PRINT BUDGET ALL -END period 7 - -BEGIN period 8 - SAVE HEAD ALL - SAVE BUDGET ALL - PRINT HEAD ALL - PRINT BUDGET ALL -END period 8 - -BEGIN period 9 - SAVE HEAD ALL - SAVE BUDGET ALL - PRINT HEAD ALL - PRINT BUDGET ALL -END period 9 - -BEGIN period 10 - SAVE HEAD ALL - SAVE BUDGET ALL - PRINT HEAD ALL - PRINT BUDGET ALL -END period 10 - +# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. +BEGIN options + BUDGET FILEOUT test_model.cbc + HEAD FILEOUT test_model.hds +END options + +BEGIN period 1 + SAVE HEAD ALL + SAVE BUDGET ALL + PRINT HEAD ALL + PRINT BUDGET ALL +END period 1 + +BEGIN period 2 + SAVE HEAD ALL + SAVE BUDGET ALL + PRINT HEAD ALL + PRINT BUDGET ALL +END period 2 + +BEGIN period 3 + SAVE HEAD ALL + SAVE BUDGET ALL + PRINT HEAD ALL + PRINT BUDGET ALL +END period 3 + +BEGIN period 4 + SAVE HEAD ALL + SAVE BUDGET ALL + PRINT HEAD ALL + PRINT BUDGET ALL +END period 4 + +BEGIN period 5 + SAVE HEAD ALL + SAVE BUDGET ALL + PRINT HEAD ALL + PRINT BUDGET ALL +END period 5 + +BEGIN period 6 + SAVE HEAD ALL + SAVE BUDGET ALL + PRINT HEAD ALL + PRINT BUDGET ALL +END period 6 + +BEGIN period 7 + SAVE HEAD ALL + SAVE BUDGET ALL + PRINT HEAD ALL + PRINT BUDGET ALL +END period 7 + +BEGIN period 8 + SAVE HEAD ALL + SAVE BUDGET ALL + PRINT HEAD ALL + PRINT BUDGET ALL +END period 8 + +BEGIN period 9 + SAVE HEAD ALL + SAVE BUDGET ALL + PRINT HEAD ALL + PRINT BUDGET ALL +END period 9 + +BEGIN period 10 + SAVE HEAD ALL + SAVE BUDGET ALL + PRINT HEAD ALL + PRINT BUDGET ALL +END period 10 + diff --git a/examples/data/dis_model/test_model.rch b/examples/data/dis_model/test_model.rch index 07b12c6..5803723 100644 --- a/examples/data/dis_model/test_model.rch +++ b/examples/data/dis_model/test_model.rch @@ -1,68 +1,68 @@ -# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. -BEGIN options -END options - -BEGIN dimensions - MAXBOUND 2 -END dimensions - -BEGIN period 1 - 1 10 3 0.25000000 - 1 10 4 0.25000000 -END period 1 - -BEGIN period 2 - 1 10 3 0.25000000 - 1 10 4 0.25000000 -END period 2 - -BEGIN period 3 - 1 10 3 0.25000000 - 1 10 4 0.25000000 -END period 3 - -BEGIN period 4 - 1 10 3 0.25000000 - 1 10 4 0.25000000 -END period 4 - -BEGIN period 5 - 1 10 3 0.25000000 - 1 10 4 0.25000000 -END period 5 - -BEGIN period 6 - 1 10 3 0.25000000 - 1 10 4 0.25000000 -END period 6 - -BEGIN period 7 - 1 10 3 0.25000000 - 1 10 4 0.25000000 -END period 7 - -BEGIN period 8 - 1 10 3 0.25000000 - 1 10 4 0.25000000 -END period 8 - -BEGIN period 9 - 1 10 3 0.25000000 - 1 10 4 0.25000000 -END period 9 - -BEGIN period 10 - 1 10 3 0.25000000 - 1 10 4 0.25000000 -END period 10 - -BEGIN period 11 - 1 10 3 0.25000000 - 1 10 4 0.25000000 -END period 11 - -BEGIN period 12 - 1 10 3 0.25000000 - 1 10 4 0.25000000 -END period 12 - +# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. +BEGIN options +END options + +BEGIN dimensions + MAXBOUND 2 +END dimensions + +BEGIN period 1 + 1 10 3 0.25000000 + 1 10 4 0.25000000 +END period 1 + +BEGIN period 2 + 1 10 3 0.25000000 + 1 10 4 0.25000000 +END period 2 + +BEGIN period 3 + 1 10 3 0.25000000 + 1 10 4 0.25000000 +END period 3 + +BEGIN period 4 + 1 10 3 0.25000000 + 1 10 4 0.25000000 +END period 4 + +BEGIN period 5 + 1 10 3 0.25000000 + 1 10 4 0.25000000 +END period 5 + +BEGIN period 6 + 1 10 3 0.25000000 + 1 10 4 0.25000000 +END period 6 + +BEGIN period 7 + 1 10 3 0.25000000 + 1 10 4 0.25000000 +END period 7 + +BEGIN period 8 + 1 10 3 0.25000000 + 1 10 4 0.25000000 +END period 8 + +BEGIN period 9 + 1 10 3 0.25000000 + 1 10 4 0.25000000 +END period 9 + +BEGIN period 10 + 1 10 3 0.25000000 + 1 10 4 0.25000000 +END period 10 + +BEGIN period 11 + 1 10 3 0.25000000 + 1 10 4 0.25000000 +END period 11 + +BEGIN period 12 + 1 10 3 0.25000000 + 1 10 4 0.25000000 +END period 12 + diff --git a/examples/data/dis_model/test_model.rcha b/examples/data/dis_model/test_model.rcha index 28fe2b4..18ffbcf 100644 --- a/examples/data/dis_model/test_model.rcha +++ b/examples/data/dis_model/test_model.rcha @@ -1,10 +1,10 @@ -# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. -BEGIN options - READASARRAYS -END options - -BEGIN period 1 - recharge - CONSTANT 0.00100000 -END period 1 - +# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. +BEGIN options + READASARRAYS +END options + +BEGIN period 1 + recharge + CONSTANT 0.00100000 +END period 1 + diff --git a/examples/data/dis_model/test_model.sto b/examples/data/dis_model/test_model.sto index 4e78a5d..78af964 100644 --- a/examples/data/dis_model/test_model.sto +++ b/examples/data/dis_model/test_model.sto @@ -1,13 +1,13 @@ -# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. -BEGIN options -END options - -BEGIN griddata - iconvert - CONSTANT 1 - ss - CONSTANT 1.00000000E-05 - sy - CONSTANT 0.15000000 -END griddata - +# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. +BEGIN options +END options + +BEGIN griddata + iconvert + CONSTANT 1 + ss + CONSTANT 1.00000000E-05 + sy + CONSTANT 0.15000000 +END griddata + diff --git a/examples/data/dis_model/test_model.tdis b/examples/data/dis_model/test_model.tdis index 245c1df..cd7fa9e 100644 --- a/examples/data/dis_model/test_model.tdis +++ b/examples/data/dis_model/test_model.tdis @@ -1,24 +1,24 @@ -# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. -BEGIN options - TIME_UNITS days -END options - -BEGIN dimensions - NPER 12 -END dimensions - -BEGIN perioddata - 31.00000000 31 1.00000000 - 28.00000000 28 1.00000000 - 31.00000000 31 1.00000000 - 30.00000000 30 1.00000000 - 31.00000000 31 1.00000000 - 30.00000000 30 1.00000000 - 31.00000000 31 1.00000000 - 31.00000000 31 1.00000000 - 30.00000000 30 1.00000000 - 31.00000000 31 1.00000000 - 30.00000000 30 1.00000000 - 31.00000000 31 1.00000000 -END perioddata - +# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. +BEGIN options + TIME_UNITS days +END options + +BEGIN dimensions + NPER 12 +END dimensions + +BEGIN perioddata + 31.00000000 31 1.00000000 + 28.00000000 28 1.00000000 + 31.00000000 31 1.00000000 + 30.00000000 30 1.00000000 + 31.00000000 31 1.00000000 + 30.00000000 30 1.00000000 + 31.00000000 31 1.00000000 + 31.00000000 31 1.00000000 + 30.00000000 30 1.00000000 + 31.00000000 31 1.00000000 + 30.00000000 30 1.00000000 + 31.00000000 31 1.00000000 +END perioddata + diff --git a/examples/data/dis_model/test_model.wel b/examples/data/dis_model/test_model.wel index 4931fc3..c886096 100644 --- a/examples/data/dis_model/test_model.wel +++ b/examples/data/dis_model/test_model.wel @@ -1,81 +1,81 @@ -# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. -BEGIN options -AUXILIARY TEST1 TEST2 -END options - -BEGIN dimensions - MAXBOUND 10 -END dimensions - -BEGIN period 1 - 1 6 5 -150.00000000 1.0 2.0 - 1 2 3 -100.00000000 1.0 2.0 - 1 4 6 -50.0000000000 1.0 2.0 -END period 1 - -BEGIN period 2 - 1 6 5 -100.00000000 1.0 2.0 - 1 2 3 -50.00000000 1.0 2.0 - 1 4 6 -50.0000000000 1.0 2.0 -END period 2 - -BEGIN period 3 - 1 6 5 -0.00000000 1.0 2.0 - 1 2 3 -0.00000000 1.0 2.0 - 1 4 6 -50.0000000000 1.0 2.0 -END period 3 - -BEGIN period 4 - 1 6 5 -10.00000000 1.0 2.0 - 1 2 3 -0.00000000 1.0 2.0 - 1 4 6 -5.0000000000 1.0 2.0 -END period 4 - -BEGIN period 5 - 1 6 5 -150.00000000 1.0 2.0 - 1 2 3 -200.00000000 1.0 2.0 - 1 4 6 -350.0000000000 1.0 2.0 -END period 5 - -BEGIN period 6 - 1 6 5 -100.00000000 1.0 2.0 - 1 2 3 -10.00000000 1.0 2.0 - 1 4 6 -80.0000000000 1.0 2.0 -END period 6 - -BEGIN period 7 - 1 6 5 -10.00000000 1.0 2.0 - 1 2 3 -50.00000000 1.0 2.0 - 1 4 6 -50.0000000000 1.0 2.0 -END period 7 - -BEGIN period 8 - 1 6 5 -100.00000000 1.0 2.0 - 1 2 3 -50.00000000 1.0 2.0 - 1 4 6 -50.0000000000 1.0 2.0 -END period 8 - -BEGIN period 9 - 1 6 5 -100.00000000 1.0 2.0 - 1 2 3 -50.00000000 1.0 2.0 - 1 4 6 -50.0000000000 1.0 2.0 -END period 9 - -BEGIN period 10 - 1 6 5 -100.00000000 1.0 2.0 - 1 2 3 -50.00000000 1.0 2.0 - 1 4 6 -50.0000000000 1.0 2.0 -END period 10 - -BEGIN period 11 - 1 6 5 -100.00000000 1.0 2.0 - 1 2 3 -50.00000000 1.0 2.0 - 1 4 6 -50.0000000000 1.0 2.0 -END period 11 - -BEGIN period 12 - 1 6 5 -100.00000000 1.0 2.0 - 1 2 3 -50.00000000 1.0 2.0 - 1 4 6 -50.0000000000 1.0 2.0 -END period 12 - +# File generated by Flopy version 3.3.6 on 10/07/2022 at 11:12:19. +BEGIN options +AUXILIARY TEST1 TEST2 +END options + +BEGIN dimensions + MAXBOUND 10 +END dimensions + +BEGIN period 1 + 1 6 5 -150.00000000 1.0 2.0 + 1 2 3 -100.00000000 1.0 2.0 + 1 4 6 -50.0000000000 1.0 2.0 +END period 1 + +BEGIN period 2 + 1 6 5 -100.00000000 1.0 2.0 + 1 2 3 -50.00000000 1.0 2.0 + 1 4 6 -50.0000000000 1.0 2.0 +END period 2 + +BEGIN period 3 + 1 6 5 -0.00000000 1.0 2.0 + 1 2 3 -0.00000000 1.0 2.0 + 1 4 6 -50.0000000000 1.0 2.0 +END period 3 + +BEGIN period 4 + 1 6 5 -10.00000000 1.0 2.0 + 1 2 3 -0.00000000 1.0 2.0 + 1 4 6 -5.0000000000 1.0 2.0 +END period 4 + +BEGIN period 5 + 1 6 5 -150.00000000 1.0 2.0 + 1 2 3 -200.00000000 1.0 2.0 + 1 4 6 -350.0000000000 1.0 2.0 +END period 5 + +BEGIN period 6 + 1 6 5 -100.00000000 1.0 2.0 + 1 2 3 -10.00000000 1.0 2.0 + 1 4 6 -80.0000000000 1.0 2.0 +END period 6 + +BEGIN period 7 + 1 6 5 -10.00000000 1.0 2.0 + 1 2 3 -50.00000000 1.0 2.0 + 1 4 6 -50.0000000000 1.0 2.0 +END period 7 + +BEGIN period 8 + 1 6 5 -100.00000000 1.0 2.0 + 1 2 3 -50.00000000 1.0 2.0 + 1 4 6 -50.0000000000 1.0 2.0 +END period 8 + +BEGIN period 9 + 1 6 5 -100.00000000 1.0 2.0 + 1 2 3 -50.00000000 1.0 2.0 + 1 4 6 -50.0000000000 1.0 2.0 +END period 9 + +BEGIN period 10 + 1 6 5 -100.00000000 1.0 2.0 + 1 2 3 -50.00000000 1.0 2.0 + 1 4 6 -50.0000000000 1.0 2.0 +END period 10 + +BEGIN period 11 + 1 6 5 -100.00000000 1.0 2.0 + 1 2 3 -50.00000000 1.0 2.0 + 1 4 6 -50.0000000000 1.0 2.0 +END period 11 + +BEGIN period 12 + 1 6 5 -100.00000000 1.0 2.0 + 1 2 3 -50.00000000 1.0 2.0 + 1 4 6 -50.0000000000 1.0 2.0 +END period 12 + diff --git a/examples/data/disu_model/flow.disu.area.dat b/examples/data/disu_model/flow.disu.area.dat index f9457ad..33d510d 100644 --- a/examples/data/disu_model/flow.disu.area.dat +++ b/examples/data/disu_model/flow.disu.area.dat @@ -1,25 +1,25 @@ - 10000 10000 10000 10000 10000 - 10000 10000 10000 10000 10000 - 10000 10000 10000 10000 10000 - 10000 10000 10000 10000 10000 - 10000 10000 10000 10000 10000 - 10000 10000 10000 10000 10000 - 10000 10000 10000 10000 10000 - 10000 10000 10000 10000 10000 - 1111.11 1111.11 1111.11 1111.11 1111.11 - 1111.11 1111.11 1111.11 1111.11 1111.11 - 1111.11 1111.11 1111.11 1111.11 1111.11 - 1111.11 1111.11 1111.11 1111.11 1111.11 - 1111.11 1111.11 1111.11 1111.11 1111.11 - 1111.11 1111.11 1111.11 1111.11 1111.11 - 1111.11 1111.11 1111.11 1111.11 1111.11 - 1111.11 1111.11 1111.11 1111.11 1111.11 - 1111.11 1111.11 1111.11 1111.11 1111.11 - 1111.11 1111.11 1111.11 1111.11 1111.11 - 1111.11 1111.11 1111.11 1111.11 1111.11 - 1111.11 1111.11 1111.11 1111.11 1111.11 - 1111.11 1111.11 1111.11 1111.11 1111.11 - 1111.11 1111.11 1111.11 1111.11 1111.11 - 1111.11 1111.11 1111.11 1111.11 1111.11 - 1111.11 1111.11 1111.11 1111.11 1111.11 - 1111.11 + 10000 10000 10000 10000 10000 + 10000 10000 10000 10000 10000 + 10000 10000 10000 10000 10000 + 10000 10000 10000 10000 10000 + 10000 10000 10000 10000 10000 + 10000 10000 10000 10000 10000 + 10000 10000 10000 10000 10000 + 10000 10000 10000 10000 10000 + 1111.11 1111.11 1111.11 1111.11 1111.11 + 1111.11 1111.11 1111.11 1111.11 1111.11 + 1111.11 1111.11 1111.11 1111.11 1111.11 + 1111.11 1111.11 1111.11 1111.11 1111.11 + 1111.11 1111.11 1111.11 1111.11 1111.11 + 1111.11 1111.11 1111.11 1111.11 1111.11 + 1111.11 1111.11 1111.11 1111.11 1111.11 + 1111.11 1111.11 1111.11 1111.11 1111.11 + 1111.11 1111.11 1111.11 1111.11 1111.11 + 1111.11 1111.11 1111.11 1111.11 1111.11 + 1111.11 1111.11 1111.11 1111.11 1111.11 + 1111.11 1111.11 1111.11 1111.11 1111.11 + 1111.11 1111.11 1111.11 1111.11 1111.11 + 1111.11 1111.11 1111.11 1111.11 1111.11 + 1111.11 1111.11 1111.11 1111.11 1111.11 + 1111.11 1111.11 1111.11 1111.11 1111.11 + 1111.11 diff --git a/examples/data/disu_model/flow.disu.cl12.dat b/examples/data/disu_model/flow.disu.cl12.dat index a995d98..2b4023a 100644 --- a/examples/data/disu_model/flow.disu.cl12.dat +++ b/examples/data/disu_model/flow.disu.cl12.dat @@ -1,121 +1,121 @@ - 0 50 50 0 50 - 50 50 0 50 50 - 50 0 50 50 50 - 0 50 50 50 0 - 50 50 50 0 50 - 50 0 50 50 50 - 0 50 50 50 50 - 0 50 50 50 50 - 50 50 0 50 50 - 50 50 50 50 0 - 50 50 50 50 50 - 50 0 50 50 50 - 50 0 50 50 50 - 0 50 50 50 0 - 50 50 50 50 50 - 50 0 50 50 50 - 50 50 50 0 50 - 50 50 0 50 50 - 50 0 50 50 50 - 50 50 50 0 50 - 50 50 50 50 50 - 0 50 50 50 0 - 50 50 50 0 50 - 50 50 50 50 50 - 0 50 50 50 50 - 50 50 0 50 50 - 50 0 50 50 50 - 0 50 50 50 50 - 0 50 50 50 50 - 50 50 0 50 50 - 50 50 50 50 0 - 50 50 50 50 50 - 50 0 50 50 50 - 50 0 50 50 50 - 0 50 50 0 50 - 50 50 0 50 50 - 50 0 50 50 50 - 0 50 50 50 0 - 50 50 50 0 50 - 50 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 0 16.6667 16.6667 16.6667 - 16.6667 + 0 50 50 0 50 + 50 50 0 50 50 + 50 0 50 50 50 + 0 50 50 50 0 + 50 50 50 0 50 + 50 0 50 50 50 + 0 50 50 50 50 + 0 50 50 50 50 + 50 50 0 50 50 + 50 50 50 50 0 + 50 50 50 50 50 + 50 0 50 50 50 + 50 0 50 50 50 + 0 50 50 50 0 + 50 50 50 50 50 + 50 0 50 50 50 + 50 50 50 0 50 + 50 50 0 50 50 + 50 0 50 50 50 + 50 50 50 0 50 + 50 50 50 50 50 + 0 50 50 50 0 + 50 50 50 0 50 + 50 50 50 50 50 + 0 50 50 50 50 + 50 50 0 50 50 + 50 0 50 50 50 + 0 50 50 50 50 + 0 50 50 50 50 + 50 50 0 50 50 + 50 50 50 50 0 + 50 50 50 50 50 + 50 0 50 50 50 + 50 0 50 50 50 + 0 50 50 0 50 + 50 50 0 50 50 + 50 0 50 50 50 + 0 50 50 50 0 + 50 50 50 0 50 + 50 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 0 16.6667 16.6667 16.6667 + 16.6667 diff --git a/examples/data/disu_model/flow.disu.hwva.dat b/examples/data/disu_model/flow.disu.hwva.dat index b994d0a..844449b 100644 --- a/examples/data/disu_model/flow.disu.hwva.dat +++ b/examples/data/disu_model/flow.disu.hwva.dat @@ -1,121 +1,121 @@ -0 100. 100. -0 100. 100. 100. -0 100. 100. 100. -0 100. 100. 100. -0 100. 100. 100. -0 100. 100. 100. -0 100. 100. -0 100. 100. 100. -0 100. 100. 100. 100. -0 100. 100. 100. 33.33 33.33 33.33 -0 100. 100. 100. 33.33 33.33 33.33 -0 100. 100. 100. 33.33 33.33 33.33 -0 100. 100. 100. 100. -0 100. 100. 100. -0 100. 100. 100. -0 100. 100. 100. 33.33 33.33 33.33 -0 100. 100. 100. 33.33 33.33 33.33 -0 100. 100. 100. -0 100. 100. 100. -0 100. 100. 100. 33.33 33.33 33.33 -0 100. 100. 100. 33.33 33.33 33.33 -0 100. 100. 100. -0 100. 100. 100. -0 100. 100. 100. 33.33 33.33 33.33 -0 100. 100. 100. 33.33 33.33 33.33 -0 100. 100. 100. -0 100. 100. 100. -0 100. 100. 100. 100. -0 100. 100. 100. 33.33 33.33 33.33 -0 100. 100. 100. 33.33 33.33 33.33 -0 100. 100. 100. 33.33 33.33 33.33 -0 100. 100. 100. 100. -0 100. 100. 100. -0 100. 100. -0 100. 100. 100. -0 100. 100. 100. -0 100. 100. 100. -0 100. 100. 100. -0 100. 100. 100. -0 100. 100. -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 -0 33.33 33.33 33.33 33.33 +0 100. 100. +0 100. 100. 100. +0 100. 100. 100. +0 100. 100. 100. +0 100. 100. 100. +0 100. 100. 100. +0 100. 100. +0 100. 100. 100. +0 100. 100. 100. 100. +0 100. 100. 100. 33.33 33.33 33.33 +0 100. 100. 100. 33.33 33.33 33.33 +0 100. 100. 100. 33.33 33.33 33.33 +0 100. 100. 100. 100. +0 100. 100. 100. +0 100. 100. 100. +0 100. 100. 100. 33.33 33.33 33.33 +0 100. 100. 100. 33.33 33.33 33.33 +0 100. 100. 100. +0 100. 100. 100. +0 100. 100. 100. 33.33 33.33 33.33 +0 100. 100. 100. 33.33 33.33 33.33 +0 100. 100. 100. +0 100. 100. 100. +0 100. 100. 100. 33.33 33.33 33.33 +0 100. 100. 100. 33.33 33.33 33.33 +0 100. 100. 100. +0 100. 100. 100. +0 100. 100. 100. 100. +0 100. 100. 100. 33.33 33.33 33.33 +0 100. 100. 100. 33.33 33.33 33.33 +0 100. 100. 100. 33.33 33.33 33.33 +0 100. 100. 100. 100. +0 100. 100. 100. +0 100. 100. +0 100. 100. 100. +0 100. 100. 100. +0 100. 100. 100. +0 100. 100. 100. +0 100. 100. 100. +0 100. 100. +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 +0 33.33 33.33 33.33 33.33 diff --git a/examples/data/disu_model/flow.disu.iac.dat b/examples/data/disu_model/flow.disu.iac.dat index 0a127ee..fdebe57 100644 --- a/examples/data/disu_model/flow.disu.iac.dat +++ b/examples/data/disu_model/flow.disu.iac.dat @@ -1,25 +1,25 @@ - 3 4 4 4 4 - 4 3 4 5 7 - 7 7 5 4 4 - 7 7 4 4 7 - 7 4 4 7 7 - 4 4 5 7 7 - 7 5 4 3 4 - 4 4 4 4 3 - 5 5 5 5 5 - 5 5 5 5 5 - 5 5 5 5 5 - 5 5 5 5 5 - 5 5 5 5 5 - 5 5 5 5 5 - 5 5 5 5 5 - 5 5 5 5 5 - 5 5 5 5 5 - 5 5 5 5 5 - 5 5 5 5 5 - 5 5 5 5 5 - 5 5 5 5 5 - 5 5 5 5 5 - 5 5 5 5 5 - 5 5 5 5 5 - 5 + 3 4 4 4 4 + 4 3 4 5 7 + 7 7 5 4 4 + 7 7 4 4 7 + 7 4 4 7 7 + 4 4 5 7 7 + 7 5 4 3 4 + 4 4 4 4 3 + 5 5 5 5 5 + 5 5 5 5 5 + 5 5 5 5 5 + 5 5 5 5 5 + 5 5 5 5 5 + 5 5 5 5 5 + 5 5 5 5 5 + 5 5 5 5 5 + 5 5 5 5 5 + 5 5 5 5 5 + 5 5 5 5 5 + 5 5 5 5 5 + 5 5 5 5 5 + 5 5 5 5 5 + 5 5 5 5 5 + 5 5 5 5 5 + 5 diff --git a/examples/data/disu_model/flow.disu.ja.dat b/examples/data/disu_model/flow.disu.ja.dat index 9bb6c6c..21df1fb 100644 --- a/examples/data/disu_model/flow.disu.ja.dat +++ b/examples/data/disu_model/flow.disu.ja.dat @@ -1,121 +1,121 @@ - 1 2 8 2 1 - 3 9 3 2 4 - 10 4 3 5 11 - 5 4 6 12 6 - 5 7 13 7 6 - 14 8 1 9 15 - 9 2 8 10 16 - 10 3 9 11 41 - 42 43 11 4 10 - 12 44 45 46 12 - 5 11 13 47 48 - 49 13 6 12 14 - 17 14 7 13 18 - 15 8 16 19 16 - 9 15 20 41 50 - 59 17 13 18 21 - 49 58 67 18 14 - 17 22 19 15 20 - 23 20 16 19 24 - 68 77 86 21 17 - 22 25 76 85 94 - 22 18 21 26 23 - 19 24 27 24 20 - 23 28 95 104 113 - 25 21 26 32 103 - 112 121 26 22 25 - 33 27 23 28 34 - 28 24 27 29 35 - 29 28 30 36 113 - 114 115 30 29 31 - 37 116 117 118 31 - 30 32 38 119 120 - 121 32 25 31 33 - 39 33 26 32 40 - 34 27 35 35 28 - 34 36 36 29 35 - 37 37 30 36 38 - 38 31 37 39 39 - 32 38 40 40 33 - 39 41 10 16 42 - 50 42 10 41 43 - 51 43 10 42 44 - 52 44 11 43 45 - 53 45 11 44 46 - 54 46 11 45 47 - 55 47 12 46 48 - 56 48 12 47 49 - 57 49 12 17 48 - 58 50 16 41 51 - 59 51 42 50 52 - 60 52 43 51 53 - 61 53 44 52 54 - 62 54 45 53 55 - 63 55 46 54 56 - 64 56 47 55 57 - 65 57 48 56 58 - 66 58 17 49 57 - 67 59 16 50 60 - 68 60 51 59 61 - 69 61 52 60 62 - 70 62 53 61 63 - 71 63 54 62 64 - 72 64 55 63 65 - 73 65 56 64 66 - 74 66 57 65 67 - 75 67 17 58 66 - 76 68 20 59 69 - 77 69 60 68 70 - 78 70 61 69 71 - 79 71 62 70 72 - 80 72 63 71 73 - 81 73 64 72 74 - 82 74 65 73 75 - 83 75 66 74 76 - 84 76 21 67 75 - 85 77 20 68 78 - 86 78 69 77 79 - 87 79 70 78 80 - 88 80 71 79 81 - 89 81 72 80 82 - 90 82 73 81 83 - 91 83 74 82 84 - 92 84 75 83 85 - 93 85 21 76 84 - 94 86 20 77 87 - 95 87 78 86 88 - 96 88 79 87 89 - 97 89 80 88 90 - 98 90 81 89 91 - 99 91 82 90 92 - 100 92 83 91 93 - 101 93 84 92 94 - 102 94 21 85 93 - 103 95 24 86 96 - 104 96 87 95 97 - 105 97 88 96 98 - 106 98 89 97 99 - 107 99 90 98 100 - 108 100 91 99 101 - 109 101 92 100 102 - 110 102 93 101 103 - 111 103 25 94 102 - 112 104 24 95 105 - 113 105 96 104 106 - 114 106 97 105 107 - 115 107 98 106 108 - 116 108 99 107 109 - 117 109 100 108 110 - 118 110 101 109 111 - 119 111 102 110 112 - 120 112 25 103 111 - 121 113 24 29 104 - 114 114 29 105 113 - 115 115 29 106 114 - 116 116 30 107 115 - 117 117 30 108 116 - 118 118 30 109 117 - 119 119 31 110 118 - 120 120 31 111 119 - 121 121 25 31 112 - 120 + 1 2 8 2 1 + 3 9 3 2 4 + 10 4 3 5 11 + 5 4 6 12 6 + 5 7 13 7 6 + 14 8 1 9 15 + 9 2 8 10 16 + 10 3 9 11 41 + 42 43 11 4 10 + 12 44 45 46 12 + 5 11 13 47 48 + 49 13 6 12 14 + 17 14 7 13 18 + 15 8 16 19 16 + 9 15 20 41 50 + 59 17 13 18 21 + 49 58 67 18 14 + 17 22 19 15 20 + 23 20 16 19 24 + 68 77 86 21 17 + 22 25 76 85 94 + 22 18 21 26 23 + 19 24 27 24 20 + 23 28 95 104 113 + 25 21 26 32 103 + 112 121 26 22 25 + 33 27 23 28 34 + 28 24 27 29 35 + 29 28 30 36 113 + 114 115 30 29 31 + 37 116 117 118 31 + 30 32 38 119 120 + 121 32 25 31 33 + 39 33 26 32 40 + 34 27 35 35 28 + 34 36 36 29 35 + 37 37 30 36 38 + 38 31 37 39 39 + 32 38 40 40 33 + 39 41 10 16 42 + 50 42 10 41 43 + 51 43 10 42 44 + 52 44 11 43 45 + 53 45 11 44 46 + 54 46 11 45 47 + 55 47 12 46 48 + 56 48 12 47 49 + 57 49 12 17 48 + 58 50 16 41 51 + 59 51 42 50 52 + 60 52 43 51 53 + 61 53 44 52 54 + 62 54 45 53 55 + 63 55 46 54 56 + 64 56 47 55 57 + 65 57 48 56 58 + 66 58 17 49 57 + 67 59 16 50 60 + 68 60 51 59 61 + 69 61 52 60 62 + 70 62 53 61 63 + 71 63 54 62 64 + 72 64 55 63 65 + 73 65 56 64 66 + 74 66 57 65 67 + 75 67 17 58 66 + 76 68 20 59 69 + 77 69 60 68 70 + 78 70 61 69 71 + 79 71 62 70 72 + 80 72 63 71 73 + 81 73 64 72 74 + 82 74 65 73 75 + 83 75 66 74 76 + 84 76 21 67 75 + 85 77 20 68 78 + 86 78 69 77 79 + 87 79 70 78 80 + 88 80 71 79 81 + 89 81 72 80 82 + 90 82 73 81 83 + 91 83 74 82 84 + 92 84 75 83 85 + 93 85 21 76 84 + 94 86 20 77 87 + 95 87 78 86 88 + 96 88 79 87 89 + 97 89 80 88 90 + 98 90 81 89 91 + 99 91 82 90 92 + 100 92 83 91 93 + 101 93 84 92 94 + 102 94 21 85 93 + 103 95 24 86 96 + 104 96 87 95 97 + 105 97 88 96 98 + 106 98 89 97 99 + 107 99 90 98 100 + 108 100 91 99 101 + 109 101 92 100 102 + 110 102 93 101 103 + 111 103 25 94 102 + 112 104 24 95 105 + 113 105 96 104 106 + 114 106 97 105 107 + 115 107 98 106 108 + 116 108 99 107 109 + 117 109 100 108 110 + 118 110 101 109 111 + 119 111 102 110 112 + 120 112 25 103 111 + 121 113 24 29 104 + 114 114 29 105 113 + 115 115 29 106 114 + 116 116 30 107 115 + 117 117 30 108 116 + 118 118 30 109 117 + 119 119 31 110 118 + 120 120 31 111 119 + 121 121 25 31 112 + 120 diff --git a/examples/data/disu_model/flow.oc b/examples/data/disu_model/flow.oc index c41ee8c..235104a 100644 --- a/examples/data/disu_model/flow.oc +++ b/examples/data/disu_model/flow.oc @@ -1,11 +1,11 @@ -BEGIN OPTIONS - HEAD FILEOUT flow.hds - BUDGET FILEOUT flow.cbc -END OPTIONS - -BEGIN PERIOD 1 - PRINT BUDGET ALL - SAVE BUDGET ALL - PRINT HEAD ALL - SAVE HEAD ALL -END PERIOD +BEGIN OPTIONS + HEAD FILEOUT flow.hds + BUDGET FILEOUT flow.cbc +END OPTIONS + +BEGIN PERIOD 1 + PRINT BUDGET ALL + SAVE BUDGET ALL + PRINT HEAD ALL + SAVE HEAD ALL +END PERIOD diff --git a/examples/data/disu_model/flow.rch b/examples/data/disu_model/flow.rch index 6b7dd1d..59c7597 100644 --- a/examples/data/disu_model/flow.rch +++ b/examples/data/disu_model/flow.rch @@ -1,20 +1,20 @@ -BEGIN OPTIONS - FIXED_CELL -END OPTIONS - -BEGIN DIMENSIONS - MAXBOUND 10 -END DIMENSIONS - -BEGIN PERIOD 1 - 1 0.000 - 2 0.000 - 3 0.000 - 4 0.000 - 5 0.000 - 6 0.000 - 7 0.000 - 8 0.000 - 9 0.000 - 10 0.000 -END PERIOD 1 +BEGIN OPTIONS + FIXED_CELL +END OPTIONS + +BEGIN DIMENSIONS + MAXBOUND 10 +END DIMENSIONS + +BEGIN PERIOD 1 + 1 0.000 + 2 0.000 + 3 0.000 + 4 0.000 + 5 0.000 + 6 0.000 + 7 0.000 + 8 0.000 + 9 0.000 + 10 0.000 +END PERIOD 1 diff --git a/examples/data/two_models/model1.oc b/examples/data/two_models/model1.oc index 10560bf..807b23a 100644 --- a/examples/data/two_models/model1.oc +++ b/examples/data/two_models/model1.oc @@ -1,11 +1,11 @@ -BEGIN OPTIONS - HEAD FILEOUT model1.hds - BUDGET FILEOUT model1.cbc -END OPTIONS - -BEGIN PERIOD 1 - PRINT BUDGET ALL - SAVE BUDGET ALL - PRINT HEAD ALL - SAVE HEAD ALL -END PERIOD +BEGIN OPTIONS + HEAD FILEOUT model1.hds + BUDGET FILEOUT model1.cbc +END OPTIONS + +BEGIN PERIOD 1 + PRINT BUDGET ALL + SAVE BUDGET ALL + PRINT HEAD ALL + SAVE HEAD ALL +END PERIOD diff --git a/examples/data/two_models/model2.oc b/examples/data/two_models/model2.oc index 9ff0ac5..c266a68 100644 --- a/examples/data/two_models/model2.oc +++ b/examples/data/two_models/model2.oc @@ -1,11 +1,11 @@ -BEGIN OPTIONS - HEAD FILEOUT model2.hds - BUDGET FILEOUT model2.cbc -END OPTIONS - -BEGIN PERIOD 1 - PRINT BUDGET ALL - SAVE BUDGET ALL - PRINT HEAD ALL - SAVE HEAD ALL -END PERIOD +BEGIN OPTIONS + HEAD FILEOUT model2.hds + BUDGET FILEOUT model2.cbc +END OPTIONS + +BEGIN PERIOD 1 + PRINT BUDGET ALL + SAVE BUDGET ALL + PRINT HEAD ALL + SAVE HEAD ALL +END PERIOD diff --git a/examples/data/two_models/simulation.gnc b/examples/data/two_models/simulation.gnc index a590308..1d515fc 100644 --- a/examples/data/two_models/simulation.gnc +++ b/examples/data/two_models/simulation.gnc @@ -1,58 +1,58 @@ -BEGIN OPTIONS - #I2KN - #IMPLICIT - PRINT_INPUT - PRINT_FLOWS -END OPTIONS - -BEGIN DIMENSIONS - NUMGNC 36 - NUMALPHAJ 1 -END DIMENSIONS - -BEGIN GNCDATA -# noden nodem nodesj alphasj -# left side - 1 3 2 1 1 1 1 2 2 0.333333333333 - 1 3 2 1 2 1 0 0 0 0.333333333333 - 1 3 2 1 3 1 1 4 2 0.333333333333 - 1 4 2 1 4 1 1 3 2 0.333333333333 - 1 4 2 1 5 1 0 0 0 0.333333333333 - 1 4 2 1 6 1 1 5 2 0.333333333333 - 1 5 2 1 7 1 1 4 2 0.333333333333 - 1 5 2 1 8 1 0 0 0 0.333333333333 - 1 5 2 1 9 1 1 6 2 0.333333333333 -# -# right side - 1 3 6 1 1 9 1 2 6 0.333333333333 - 1 3 6 1 2 9 0 0 0 0.333333333333 - 1 3 6 1 3 9 1 4 6 0.333333333333 - 1 4 6 1 4 9 1 3 6 0.333333333333 - 1 4 6 1 5 9 0 0 0 0.333333333333 - 1 4 6 1 6 9 1 5 6 0.333333333333 - 1 5 6 1 7 9 1 4 6 0.333333333333 - 1 5 6 1 8 9 0 0 0 0.333333333333 - 1 5 6 1 9 9 1 6 6 0.333333333333 -# -# back - 1 2 3 1 1 1 1 2 2 0.333333333333 - 1 2 3 1 1 2 0 0 0 0.333333333333 - 1 2 3 1 1 3 1 2 4 0.333333333333 - 1 2 4 1 1 4 1 2 3 0.333333333333 - 1 2 4 1 1 5 0 0 0 0.333333333333 - 1 2 4 1 1 6 1 2 5 0.333333333333 - 1 2 5 1 1 7 1 2 4 0.333333333333 - 1 2 5 1 1 8 0 0 0 0.333333333333 - 1 2 5 1 1 9 1 2 6 0.333333333333 -# -# front - 1 6 3 1 9 1 1 6 2 0.333333333333 - 1 6 3 1 9 2 0 0 0 0.333333333333 - 1 6 3 1 9 3 1 6 4 0.333333333333 - 1 6 4 1 9 4 1 6 3 0.333333333333 - 1 6 4 1 9 5 0 0 0 0.333333333333 - 1 6 4 1 9 6 1 6 5 0.333333333333 - 1 6 5 1 9 7 1 6 4 0.333333333333 - 1 6 5 1 9 8 0 0 0 0.333333333333 - 1 6 5 1 9 9 1 6 6 0.333333333333 -END GNCDATA +BEGIN OPTIONS + #I2KN + #IMPLICIT + PRINT_INPUT + PRINT_FLOWS +END OPTIONS + +BEGIN DIMENSIONS + NUMGNC 36 + NUMALPHAJ 1 +END DIMENSIONS + +BEGIN GNCDATA +# noden nodem nodesj alphasj +# left side + 1 3 2 1 1 1 1 2 2 0.333333333333 + 1 3 2 1 2 1 0 0 0 0.333333333333 + 1 3 2 1 3 1 1 4 2 0.333333333333 + 1 4 2 1 4 1 1 3 2 0.333333333333 + 1 4 2 1 5 1 0 0 0 0.333333333333 + 1 4 2 1 6 1 1 5 2 0.333333333333 + 1 5 2 1 7 1 1 4 2 0.333333333333 + 1 5 2 1 8 1 0 0 0 0.333333333333 + 1 5 2 1 9 1 1 6 2 0.333333333333 +# +# right side + 1 3 6 1 1 9 1 2 6 0.333333333333 + 1 3 6 1 2 9 0 0 0 0.333333333333 + 1 3 6 1 3 9 1 4 6 0.333333333333 + 1 4 6 1 4 9 1 3 6 0.333333333333 + 1 4 6 1 5 9 0 0 0 0.333333333333 + 1 4 6 1 6 9 1 5 6 0.333333333333 + 1 5 6 1 7 9 1 4 6 0.333333333333 + 1 5 6 1 8 9 0 0 0 0.333333333333 + 1 5 6 1 9 9 1 6 6 0.333333333333 +# +# back + 1 2 3 1 1 1 1 2 2 0.333333333333 + 1 2 3 1 1 2 0 0 0 0.333333333333 + 1 2 3 1 1 3 1 2 4 0.333333333333 + 1 2 4 1 1 4 1 2 3 0.333333333333 + 1 2 4 1 1 5 0 0 0 0.333333333333 + 1 2 4 1 1 6 1 2 5 0.333333333333 + 1 2 5 1 1 7 1 2 4 0.333333333333 + 1 2 5 1 1 8 0 0 0 0.333333333333 + 1 2 5 1 1 9 1 2 6 0.333333333333 +# +# front + 1 6 3 1 9 1 1 6 2 0.333333333333 + 1 6 3 1 9 2 0 0 0 0.333333333333 + 1 6 3 1 9 3 1 6 4 0.333333333333 + 1 6 4 1 9 4 1 6 3 0.333333333333 + 1 6 4 1 9 5 0 0 0 0.333333333333 + 1 6 4 1 9 6 1 6 5 0.333333333333 + 1 6 5 1 9 7 1 6 4 0.333333333333 + 1 6 5 1 9 8 0 0 0 0.333333333333 + 1 6 5 1 9 9 1 6 6 0.333333333333 +END GNCDATA diff --git a/examples/data/two_models/simulation.mvr b/examples/data/two_models/simulation.mvr index e28ec24..47b311a 100644 --- a/examples/data/two_models/simulation.mvr +++ b/examples/data/two_models/simulation.mvr @@ -1,21 +1,21 @@ -BEGIN OPTIONS - PRINT_INPUT - PRINT_FLOWS - MODELNAMES -END OPTIONS - -BEGIN DIMENSIONS - MAXMVR 10 - MAXPACKAGES 2 -END DIMENSIONS - -BEGIN PACKAGES - 'PARENT' 'MAW-1' - 'CHILD' 'MAW-1' -END PACKAGES - -BEGIN PERIOD 1 -# mnamep packnamep idp mnamer packnamer idr type val -# ------------------------------------------------------- - 'CHILD' 'MAW-1' 1 'PARENT' 'MAW-1' 1 FACTOR 0.5 -END PERIOD 1 +BEGIN OPTIONS + PRINT_INPUT + PRINT_FLOWS + MODELNAMES +END OPTIONS + +BEGIN DIMENSIONS + MAXMVR 10 + MAXPACKAGES 2 +END DIMENSIONS + +BEGIN PACKAGES + 'PARENT' 'MAW-1' + 'CHILD' 'MAW-1' +END PACKAGES + +BEGIN PERIOD 1 +# mnamep packnamep idp mnamer packnamer idr type val +# ------------------------------------------------------- + 'CHILD' 'MAW-1' 1 'PARENT' 'MAW-1' 1 FACTOR 0.5 +END PERIOD 1 From f08d8e80b42fcde5d8d181115e22172f5004682d Mon Sep 17 00:00:00 2001 From: Joshua Larsen Date: Wed, 19 Apr 2023 13:09:33 -0700 Subject: [PATCH 11/34] Add missing RIV support to modflowapi (#16) * add(test_rhs_hcof_advanced): add additional test * added test for getting and setting rhs, hcof, and advanced variable values * update project to use unix line separators * use np.testing.assert_allclose() instead of AssertionError * Add missing riv package to modflowapi --- modflowapi/extensions/apimodel.py | 1 + modflowapi/extensions/pakbase.py | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/modflowapi/extensions/apimodel.py b/modflowapi/extensions/apimodel.py index 16086ec..d899d7d 100644 --- a/modflowapi/extensions/apimodel.py +++ b/modflowapi/extensions/apimodel.py @@ -161,6 +161,7 @@ def __init__(self, mf6, name): "ic": ArrayPackage, "npf": ArrayPackage, "rch": ListPackage, + "riv": ListPackage, "sto": ArrayPackage, "wel": ListPackage, # gwt diff --git a/modflowapi/extensions/pakbase.py b/modflowapi/extensions/pakbase.py index fcc6fe8..19be40c 100644 --- a/modflowapi/extensions/pakbase.py +++ b/modflowapi/extensions/pakbase.py @@ -72,6 +72,15 @@ "auxname_cst", "auxvar", ], + "riv": [ + "maxbound", + "nbound", + "nodelist", + ("bound", ("stage", "cond", "rbot")), + "naux", + "auxname_cst", + "auxvar", + ], "sto": ["iconvert", "ss", "sy"], "wel": [ "maxbound", From afc08dfcbf34b9e529f3cfbf89fada3e084fa713 Mon Sep 17 00:00:00 2001 From: jdhughes-usgs Date: Thu, 20 Apr 2023 08:41:22 -0500 Subject: [PATCH 12/34] Update develop with v0.1.0 changes (#17) --- .github/workflows/ci.yml | 6 +- CITATION.cff | 4 +- README.md | 10 + examples/notebooks/Head_Monitor_Example.ipynb | 255 ++ .../MODFLOW-API_extensions_objects.ipynb | 2047 +++++++++++++++++ modflowapi/version.py | 4 +- 6 files changed, 2319 insertions(+), 7 deletions(-) create mode 100644 examples/notebooks/Head_Monitor_Example.ipynb create mode 100644 examples/notebooks/MODFLOW-API_extensions_objects.ipynb diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2d8b41e..3ba4fb1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,7 +9,7 @@ on: - develop - 'release*' pull_request: - branches: [master, develop] + branches: [main, develop] jobs: @@ -120,7 +120,7 @@ jobs: - name: Install Python dependencies run: | - pip install --upgrade pip + python -m pip install --upgrade pip pip install git+https://git@github.com/Deltares/xmipy@develop pip install git+https://git@github.com/MODFLOW-USGS/modflow-devtools@develop pip install .[test] @@ -165,7 +165,7 @@ jobs: - name: Install Python dependencies run: | - pip install --upgrade pip + python -m pip install --upgrade pip pip install git+https://git@github.com/Deltares/xmipy@develop pip install git+https://git@github.com/MODFLOW-USGS/modflow-devtools@develop pip install .[test] diff --git a/CITATION.cff b/CITATION.cff index 4874017..ccd7d09 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -3,8 +3,8 @@ message: If you use this software, please cite both the article from preferred-c and the software itself. type: software title: MODFLOW API -version: 0.0.1 -date-released: '2021-05-12' +version: 0.2.0 +date-released: '2023-04-19' abstract: An extension to xmipy for the MODFLOW API. repository-artifact: https://pypi.org/project/modflowapi repository-code: https://github.com/MODFLOW-USGS/modflowapi diff --git a/README.md b/README.md index f3542aa..f20da3a 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,21 @@ The `modflowapi` can be used to access functionality in the eXtended Model Interface (XMI) wrapper (XmiWrapper) and additional functionality specific to the MODFLOW API. Currently it is a joint development of the USGS and Deltares. +Use of modflowapi and modflowapi extensions can be found in the [Quickstart](examples/notebooks/Quickstart.ipynb) and the [Extensions](examples/notebooks/MODFLOW-API_extensions_objects.ipynb) Notebooks. An example of using the MODFLOW API to monitor heads during a simulation can be found in the [Head Monitor Example](examples/notebooks/Head_Monitor_Example.ipynb) Notebook. + + `modflowapi` can be installed by running + ``` pip install modflowapi ``` +or + +``` +conda install -c conda-forge modflowapi +``` + ### Citation Hughes, Joseph D., Russcher, M. J., Langevin, C. D., Morway, E. D. and McDonald, R. R., 2022, The MODFLOW Application Programming Interface for simulationcontrol and software interoperability: Environmental Modelling & Software, v. 148, p. 105257, [doi:10.1016/j.envsoft.2021.105257](https://doi.org/10.1016/j.envsoft.2021.105257). diff --git a/examples/notebooks/Head_Monitor_Example.ipynb b/examples/notebooks/Head_Monitor_Example.ipynb new file mode 100644 index 0000000..4e800ea --- /dev/null +++ b/examples/notebooks/Head_Monitor_Example.ipynb @@ -0,0 +1,255 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "ee31d799", + "metadata": {}, + "source": [ + "# MODFLOW-API Head monitor example\n", + "\n", + "In this example the modflow-api is used in a more complex callback function to create a Head Monitor that updates at the timestep level. This example reverses `CHD` boundary conditions each stress period on a simple 10 x 10 model and displays the head results for each timestep.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "4526a124", + "metadata": {}, + "outputs": [], + "source": [ + "from IPython.display import clear_output, display # remove this import if adapted to python script\n", + "\n", + "from modflowapi import run_simulation, Callbacks\n", + "from flopy.discretization import StructuredGrid\n", + "from flopy.plot import PlotMapView, styles\n", + "from pathlib import Path\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "id": "3f7ac8a2", + "metadata": {}, + "source": [ + "### Create a class that includes a callback function\n", + "\n", + "This class handles changing the `CHD` boundary condition as well as updating the matplotlib plot." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "cdd38b59", + "metadata": {}, + "outputs": [], + "source": [ + "class StructuredHeadMonitor:\n", + " \"\"\"\n", + " An example class that reverses the model gradient by\n", + " swapping CHD boundary conditions each stress period, \n", + " and monitors the head at each timestep by updating\n", + " a matplotlib plot. This class could be adapted to \n", + " be used as a head monitor to observe other changes\n", + " in the model by modifying the callback class.\n", + " \n", + " Parameters\n", + " ----------\n", + " layer: int\n", + " zero based model layer to plot\n", + " vmin : float\n", + " minimum head value for color scaling on the plot\n", + " vmax : float\n", + " maximum head value for color scaling on the plot\n", + " \"\"\"\n", + "\n", + " def __init__(self, layer, vmin, vmax):\n", + " self.modelgrid = None\n", + " self.ax = None\n", + " self.pmv = None\n", + " self.pc = None\n", + " self.ax = None\n", + " self.layer = layer\n", + " self.vmin = vmin\n", + " self.vmax = vmax\n", + " self.kperold = None\n", + "\n", + " def build_modelgrid(self, ml):\n", + " \"\"\"\n", + " Method to update the matplotlib plot\n", + " \n", + " Parameters\n", + " ----------\n", + " ml : ApiModel\n", + " modflow-api ApiModel object\n", + " \"\"\"\n", + " delc = ml.dis.get_advanced_var(\"delc\")\n", + " delr = ml.dis.get_advanced_var(\"delr\")\n", + " top = ml.dis.top.values[0]\n", + " botm = ml.dis.bot.values\n", + " idomain = ml.dis.idomain.values\n", + " self.modelgrid = StructuredGrid(\n", + " delc=delc,\n", + " delr=delr,\n", + " top=top,\n", + " botm=botm,\n", + " idomain=idomain\n", + " )\n", + "\n", + " def initialize_plot(self):\n", + " \"\"\"\n", + " Method to initalize a matplotlib plot using flopy\n", + " \"\"\"\n", + " fig, ax = plt.subplots(figsize=(8, 8))\n", + " self.fig = fig\n", + " self.ax = ax\n", + " self.pmv = PlotMapView(modelgrid=self.modelgrid, ax=ax, layer=self.layer)\n", + " grid = self.pmv.plot_grid()\n", + " idm = self.pmv.plot_inactive()\n", + " initial = np.full(self.modelgrid.shape, np.nan)\n", + " self.pc = self.pmv.plot_array(initial, vmin=self.vmin, vmax=self.vmax)\n", + " plt.colorbar(self.pc)\n", + "\n", + " def update_plot(self, ml):\n", + " \"\"\"\n", + " Method to update the matplotlib plot\n", + " \n", + " Parameters\n", + " ----------\n", + " ml : ApiModel\n", + " modflow-api ApiModel object\n", + " \"\"\"\n", + " heads = ml.X\n", + " self.ax.cla()\n", + " grid = self.pmv.plot_grid()\n", + " idm = self.pmv.plot_inactive()\n", + " self.pc = self.pmv.plot_array(heads, vmin=self.vmin, vmax=self.vmax)\n", + " \n", + " # only applicable to jupyter notebooks, remove these two lines in python scipt\n", + " display(self.fig) \n", + " if ml.kper == (ml.nper - 1) and ml.kstp == (ml.nstp - 1):\n", + " pass\n", + " else:\n", + " clear_output(wait = True) \n", + " \n", + " # the pause time can be reduced if adapted in python script \n", + " plt.pause(0.1) \n", + "\n", + " def callback(self, sim, callback_step):\n", + " \"\"\"\n", + " A demonstration function that dynamically adjusts the CHD\n", + " boundary conditions each stress period in a modflow-6 model\n", + " through the MODFLOW-API and then updates heads on a matplotlib\n", + " plot for each timestep.\n", + "\n", + " Parameters\n", + " ----------\n", + " sim : modflowapi.Simulation\n", + " A simulation object for the solution group that is \n", + " currently being solved\n", + " callback_step : enumeration\n", + " modflowapi.Callbacks enumeration object that indicates\n", + " the part of the solution modflow is currently in.\n", + " \"\"\"\n", + " if callback_step == Callbacks.initialize:\n", + " ml = sim.get_model()\n", + " self.build_modelgrid(ml)\n", + " self.initialize_plot()\n", + "\n", + " if callback_step == Callbacks.timestep_start:\n", + " ml = sim.get_model()\n", + " if ml.kper == 0:\n", + " self.kperold = ml.kper\n", + " head = ml.chd.stress_period_data.dataframe[\"head\"].values\n", + " self.head = head\n", + " else:\n", + " df = ml.chd.stress_period_data.dataframe\n", + " if self.kperold != ml.kper:\n", + " self.kperold = ml.kper\n", + " self.head = self.head[::-1]\n", + "\n", + " df[\"head\"] = self.head\n", + " ml.chd.stress_period_data.dataframe = df\n", + "\n", + " if callback_step == Callbacks.timestep_end:\n", + " ml = sim.get_model()\n", + " self.update_plot(ml)\n" + ] + }, + { + "cell_type": "markdown", + "id": "ef5cf1d9", + "metadata": {}, + "source": [ + "Run the model using the and supply the `StructuredHeadMonitor`'s `callback` function" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "f2902aff", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Solving: Stress Period 12; Timestep 31\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "NORMAL TERMINATION OF SIMULATION\n" + ] + } + ], + "source": [ + "hdmon = StructuredHeadMonitor(layer=0, vmin=70, vmax=95)\n", + "dll = \"libmf6\"\n", + "sim_ws = Path(\"../data/dis_model\")\n", + "run_simulation(dll, sim_ws, hdmon.callback, verbose=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6ba6ce60", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.9.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/notebooks/MODFLOW-API_extensions_objects.ipynb b/examples/notebooks/MODFLOW-API_extensions_objects.ipynb new file mode 100644 index 0000000..d6637e1 --- /dev/null +++ b/examples/notebooks/MODFLOW-API_extensions_objects.ipynb @@ -0,0 +1,2047 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "5acdb8ec", + "metadata": {}, + "source": [ + "# Interacting with MODFLOW-API Interface objects\n", + "\n", + "The purpose of this notebook is to show the MODFLOW-API interface objects and introduce the user to the data types and how to interact with the objects. \n", + "\n", + "**Note**: This notebook shows how to run a model using the modflow-api at the end of the notebook. However, the majority of the notebook is an illustration of how to access and work with the data types that are returned to a user defined callback function. " + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "4b0e6a93", + "metadata": {}, + "outputs": [], + "source": [ + "import modflowapi\n", + "from modflowapi.extensions import ApiSimulation\n", + "from pathlib import Path\n", + "import platform" + ] + }, + { + "cell_type": "markdown", + "id": "9e654316", + "metadata": {}, + "source": [ + "Define the paths to the model and the Modflow shared library" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "66c0f32c", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "sim_ws = Path(\"../data/dis_model\")\n", + "dll = \"./libmf6\"\n", + "if platform.system().lower() == \"windows\":\n", + " ext = \".dll\"\n", + "elif platform.system().lower() == \"linux\":\n", + " ext = \".so\"\n", + "else:\n", + " ext = \".dylib\"\n", + " \n", + "dll = Path(dll + ext)" + ] + }, + { + "cell_type": "markdown", + "id": "d258b430", + "metadata": {}, + "source": [ + "#### Initializing the API model object\n", + "\n", + "The modflow api allows users to initialize an object that can be used to interact with the model. This processes is done automatically with the `modflowapi.run_model` function call. We're going to initialize an object outside of that call as a demonstration of the interface data objects" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "9c18c3bf", + "metadata": {}, + "outputs": [], + "source": [ + "mf6 = modflowapi.ModflowApi(dll, working_directory=sim_ws)\n", + "mf6.initialize()\n", + "\n", + "# let's advance the model to the first timestep\n", + "dt = mf6.get_time_step()\n", + "mf6.prepare_time_step(dt)" + ] + }, + { + "cell_type": "markdown", + "id": "424925fc", + "metadata": {}, + "source": [ + "## The `ApiSimulation` object \n", + "\n", + "The `ApiSimulation` object is the top level container for the modflowapi interface classes. This container holds methods and other objects that allow the user to access boundary condition pointer data without assembling the specific memory addresses of the modflow data. \n", + "\n", + "Let's take a look at the `ApiSimulation` object" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "b0e83b86", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\n", + " ApiSimulation object that holds a modflow simulation info and loads\n", + " supported models.\n", + "\n", + " Parameters\n", + " ----------\n", + " mf6 : ModflowApi\n", + " initialized ModflowApi object\n", + " models : dict\n", + " dictionary of model_name: modflowapi.extensions.ApiModel objects\n", + " solutions : dict\n", + " dictionary of solution_id: solution_name\n", + " exchanges : dict\n", + " dictoinary of exchange_name: modflowapi.extensions.ApiExchange objects\n", + " tdis : ApiTdisPackage\n", + " time discretization (TDIS) ScalarPackage\n", + " ats : None or ApiAtsPackage\n", + " adaptive time step ScalarPackage object\n", + " Number of models: 1:\n", + "\ttest_model : \n", + "Simulation level packages include:\n", + "\tSLN: SLN Package: SLN_1 \n", + " Accessible variables include:\n", + " akappa \n", + " amomentum \n", + " breduc \n", + " btol \n", + " droptol \n", + " dvclose \n", + " gamma \n", + " ims_dvclose \n", + " iord \n", + " ipc \n", + " iscl \n", + " mxiter \n", + " niterc \n", + " north \n", + " numtrack \n", + " rclose \n", + " relax \n", + " res_lim \n", + " theta \n", + "\n", + "\tTDIS: TDIS Package: TDIS \n", + " Accessible variables include:\n", + " delt \n", + " itmuni \n", + " kper \n", + " kstp \n", + " nper \n", + " nstp \n", + " perlen \n", + " pertim \n", + " tsmult \n" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sim = ApiSimulation.load(mf6)\n", + "sim" + ] + }, + { + "cell_type": "markdown", + "id": "65030e7d", + "metadata": {}, + "source": [ + "The simulation object allows the user to access models by name and has a number of handy properties and contains simulation level packages such as `sln`, `tdis`, `ats`, and `exchanges`" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "c6930030", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['test_model']" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mnames = sim.model_names\n", + "mnames" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "327a1c6e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(0, 0)" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "kstp, kper = sim.kstp, sim.kper\n", + "kstp, kper" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "93c4c417", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "31" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "nstp = sim.nstp\n", + "nstp" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "77c77460", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "SLN Package: SLN_1 \n", + " Accessible variables include:\n", + " akappa \n", + " amomentum \n", + " breduc \n", + " btol \n", + " droptol \n", + " dvclose \n", + " gamma \n", + " ims_dvclose \n", + " iord \n", + " ipc \n", + " iscl \n", + " mxiter \n", + " niterc \n", + " north \n", + " numtrack \n", + " rclose \n", + " relax \n", + " res_lim \n", + " theta " + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ims = sim.sln\n", + "ims" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "3805e031", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.1" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ims.dvclose" + ] + }, + { + "cell_type": "markdown", + "id": "236d4a25", + "metadata": {}, + "source": [ + "## The `ApiModel` object\n", + "\n", + "`ApiModel` objects are accessed from the `ApiSimulation` object and are a container for packages. These objects allow the user to view which packages are available and access those packages. \n", + "\n", + "The following cells show the main attributes and functions available on the `ApiModel` object" + ] + }, + { + "cell_type": "markdown", + "id": "7e65a3f3", + "metadata": {}, + "source": [ + "Model objects are accessible through the `get_model` function and as attributes on the sim object" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "232c0660", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "TEST_MODEL, 1 Layer, 10 Row, 10 Column model\n", + "Packages accessible include: \n", + " ArrayPackage objects:\n", + " dis: \n", + " npf: \n", + " sto: \n", + " ic: \n", + " ListPackage objects:\n", + " wel_0: \n", + " drn_0: \n", + " rch_0: \n", + " rcha_0: \n", + " evt_0: \n", + " chd_0: \n", + " AdvancedPackage objects:\n", + " buy: \n", + " vsc: \n", + " gnc: \n", + " hfb: \n", + " csub: \n", + " mvr: " + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model = sim.get_model('test_model')\n", + "model" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "bb9328af", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "TEST_MODEL, 1 Layer, 10 Row, 10 Column model\n", + "Packages accessible include: \n", + " ArrayPackage objects:\n", + " dis: \n", + " npf: \n", + " sto: \n", + " ic: \n", + " ListPackage objects:\n", + " wel_0: \n", + " drn_0: \n", + " rch_0: \n", + " rcha_0: \n", + " evt_0: \n", + " chd_0: \n", + " AdvancedPackage objects:\n", + " buy: \n", + " vsc: \n", + " gnc: \n", + " hfb: \n", + " csub: \n", + " mvr: " + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# approach 2\n", + "model = sim.test_model\n", + "model" + ] + }, + { + "cell_type": "markdown", + "id": "0ddc33e1", + "metadata": {}, + "source": [ + "There are also a number of other functions available including the following:" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "43aaed16", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(1, 10, 10)" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "07b0b3e2", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "100" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model.size" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "088578c0", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model.solution_id" + ] + }, + { + "cell_type": "markdown", + "id": "4eafd365", + "metadata": {}, + "source": [ + "A list of all package names that are accesible is also available" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "eee1f0a5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['dis',\n", + " 'npf',\n", + " 'buy',\n", + " 'vsc',\n", + " 'gnc',\n", + " 'hfb',\n", + " 'sto',\n", + " 'csub',\n", + " 'ic',\n", + " 'mvr',\n", + " 'wel_0',\n", + " 'drn_0',\n", + " 'rch_0',\n", + " 'rcha_0',\n", + " 'evt_0',\n", + " 'chd_0']" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model.package_names" + ] + }, + { + "cell_type": "markdown", + "id": "073bb268", + "metadata": {}, + "source": [ + "## The `ApiPackage` object(s)\n", + "\n", + "Each package is contained in `ApiPackage` container. There are three types depending on the input data. We'll access and take a look at each of the types of `ApiPackage` containers." + ] + }, + { + "cell_type": "markdown", + "id": "79ac8066", + "metadata": {}, + "source": [ + "Packages can be accessed from the `Model` object using `get_package()` or by attribute" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "4914c509", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "RCH Package: RCHA_0" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# example 1: get a package using get_package\n", + "rch = model.get_package(\"rcha_0\")\n", + "rch" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "cbc0aadf", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "WEL Package: WEL_0" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# example 2: get a package by package name attribute\n", + "wel = model.wel_0\n", + "wel" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "1a705679", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[RCH Package: RCH_0, RCH Package: RCHA_0]" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# example 3: get all packages based on a package type\n", + "rch_pkgs = model.rch\n", + "rch_pkgs" + ] + }, + { + "cell_type": "markdown", + "id": "8d59405f", + "metadata": {}, + "source": [ + "### `ListPackage` objects\n", + "\n", + "`ListPackage` objects are the primary object type of stress period data. The exception to this rule is the advanced packages which will be discussed later. \n", + "\n", + "`ListPackage` objects allow users to access stress period data as a numpy recarray or as a pandas dataframe." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "fbc7ed8a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "rec.array([((0, 9, 7), 1.00000e-03), ((0, 9, 7), 1.00000e-03),\n", + " ((0, 0, 2), 4.04496e+00), ((0, 0, 3), 4.04496e+00),\n", + " ((0, 0, 4), 4.04496e+00), ((0, 0, 5), 4.04496e+00),\n", + " ((0, 0, 6), 4.04496e+00), ((0, 0, 7), 4.04496e+00),\n", + " ((0, 9, 7), 1.00000e-03), ((0, 9, 7), 1.00000e-03)],\n", + " dtype=[('nodelist', 'O'), ('recharge', '\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
nodelistrecharge
0(0, 9, 7)0.00100
1(0, 9, 7)0.00100
2(0, 0, 2)4.04496
3(0, 0, 3)4.04496
4(0, 0, 4)4.04496
\n", + "" + ], + "text/plain": [ + " nodelist recharge\n", + "0 (0, 9, 7) 0.00100\n", + "1 (0, 9, 7) 0.00100\n", + "2 (0, 0, 2) 4.04496\n", + "3 (0, 0, 3) 4.04496\n", + "4 (0, 0, 4) 4.04496" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = rch.stress_period_data.dataframe\n", + "df.head()" + ] + }, + { + "cell_type": "markdown", + "id": "62faee8b", + "metadata": {}, + "source": [ + "### Updating values for `ListPackage` based data\n", + "\n", + "There are multiple ways to update values for `ListPackage` based data. The `.values` and `.dataframe` attributes can be used, or the object can be directly indexed if the user knows the underlying data. Here are some examples" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "0fecf116", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "rec.array([((0, 9, 7), 1.00000e-01), ((0, 9, 7), 1.00000e-03),\n", + " ((0, 0, 2), 4.04496e+00), ((0, 0, 3), 4.04496e+00),\n", + " ((0, 0, 4), 4.04496e+00)],\n", + " dtype=[('nodelist', 'O'), ('recharge', '\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
nodelistrecharge
0(0, 9, 7)0.10000
1(0, 9, 7)10000.00000
2(0, 0, 2)4.04496
3(0, 0, 3)4.04496
4(0, 0, 4)4.04496
\n", + "" + ], + "text/plain": [ + " nodelist recharge\n", + "0 (0, 9, 7) 0.10000\n", + "1 (0, 9, 7) 10000.00000\n", + "2 (0, 0, 2) 4.04496\n", + "3 (0, 0, 3) 4.04496\n", + "4 (0, 0, 4) 4.04496" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = rch.stress_period_data.dataframe\n", + "df.loc[1, \"recharge\"] = 10000\n", + "rch.stress_period_data.dataframe = df\n", + "\n", + "# show that values have been updated\n", + "df = rch.stress_period_data.dataframe\n", + "df.head()" + ] + }, + { + "cell_type": "markdown", + "id": "fd85083e", + "metadata": {}, + "source": [ + "#### Interfacing directly with the `.stress_period_data` attribute\n", + "\n", + "The `.stress_period_data` attribute returns a container class that interacts with the internal modflow pointers. The data can be adjusted by interacting with `.stress_period_data` in the same fashion as changing data in a numpy recarray. " + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "c1d21b67", + "metadata": {}, + "outputs": [], + "source": [ + "rch.stress_period_data[\"recharge\"] *= 100" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "0a127471", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
nodelistrecharge
0(0, 9, 7)10.000
1(0, 9, 7)1000000.000
2(0, 0, 2)404.496
3(0, 0, 3)404.496
4(0, 0, 4)404.496
\n", + "
" + ], + "text/plain": [ + " nodelist recharge\n", + "0 (0, 9, 7) 10.000\n", + "1 (0, 9, 7) 1000000.000\n", + "2 (0, 0, 2) 404.496\n", + "3 (0, 0, 3) 404.496\n", + "4 (0, 0, 4) 404.496" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = rch.stress_period_data.dataframe\n", + "df.head()" + ] + }, + { + "cell_type": "markdown", + "id": "85f6922c", + "metadata": {}, + "source": [ + "#### Adding or removing a boundary condition\n", + "In list packages the user can add and remove specific boundary conditions. Note: if a user adds a boundary condition, such as another well during a stress period, the total number of wells cannot be greater than the wel package's `maxbound` variable. Here's an example" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "4921081e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "nbound=3 maxbound=10\n" + ] + } + ], + "source": [ + "wel = model.wel\n", + "maxbound = wel.maxbound\n", + "nbound = wel.nbound\n", + "print(f\"{nbound=}\", f\"{maxbound=}\")" + ] + }, + { + "cell_type": "markdown", + "id": "9639edaf", + "metadata": {}, + "source": [ + "For the current stress period there are two active wells `nbound=2`, but there can be up to ten `maxbound=10`." + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "a9d7ba04", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "rec.array([((0, 5, 4), -150., 1., 2.), ((0, 1, 2), -100., 1., 2.),\n", + " ((0, 3, 5), -50., 1., 2.)],\n", + " dtype=[('nodelist', 'O'), ('flux', '\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
nodelistfluxTEST1TEST2
0(0, 5, 4)-150.01.02.0
1(0, 1, 2)-100.01.02.0
2(0, 3, 5)-50.01.02.0
3(0, 1, 5)-20.00.01.0
\n", + "" + ], + "text/plain": [ + " nodelist flux TEST1 TEST2\n", + "0 (0, 5, 4) -150.0 1.0 2.0\n", + "1 (0, 1, 2) -100.0 1.0 2.0\n", + "2 (0, 3, 5) -50.0 1.0 2.0\n", + "3 (0, 1, 5) -20.0 0.0 1.0" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wel.stress_period_data.dataframe" + ] + }, + { + "cell_type": "markdown", + "id": "42b72baa", + "metadata": {}, + "source": [ + "### `ArrayPackage` objects\n", + "\n", + "The `ArrayPackage` class is used as a container for packages such as `DIS`, `NPF`, and `IC` that do not contain any sort of stress period data. These packages are used primarily to define model connectivity, initial conditions, and hydraulic parameters of the basin. " + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "e9939cae", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "NPF Package: NPF \n", + " Accessible variables include:\n", + " angle1 \n", + " angle2 \n", + " angle3 \n", + " icelltype \n", + " k11 \n", + " k22 \n", + " k33 " + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "npf = model.npf\n", + "npf" + ] + }, + { + "cell_type": "markdown", + "id": "f55215ba", + "metadata": {}, + "source": [ + "For an `ArrayPackage` type object, variable names can be viewed by calling the `.variable_names` property" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "df4e7242", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['angle1', 'angle2', 'angle3', 'icelltype', 'k11', 'k22', 'k33']" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "npf.variable_names" + ] + }, + { + "cell_type": "markdown", + "id": "93c2006e", + "metadata": {}, + "source": [ + "### Updating values for `ArrayPackage` objects\n", + "\n", + "Two methods are available for accessing and updating data in `ArrayPackage` objects. `get_array()` and `set_array()` methods can be used to get and set data. Arrays can also be accessed as attributes on the object." + ] + }, + { + "cell_type": "markdown", + "id": "0f408dff", + "metadata": {}, + "source": [ + "Using `get_array()` and `set_array()`" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "0d202974", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[[nan, nan, 1., 1., 1., 1., 1., 1., nan, nan],\n", + " [nan, 1., 1., 1., 1., 1., 1., 1., 1., nan],\n", + " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", + " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", + " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", + " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", + " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", + " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", + " [nan, 1., 1., 1., 1., 1., 1., 1., 1., nan],\n", + " [nan, nan, 1., 1., 1., 1., 1., 1., nan, nan]]])" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "hk = npf.get_array(\"k11\")\n", + "hk" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "17ce597b", + "metadata": {}, + "outputs": [], + "source": [ + "hk[0, 0:5, 0:5] = 50\n", + "npf.set_array(\"k11\", hk)" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "2ed869a9", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[[nan, nan, 50., 50., 50., 1., 1., 1., nan, nan],\n", + " [nan, 50., 50., 50., 50., 1., 1., 1., 1., nan],\n", + " [50., 50., 50., 50., 50., 1., 1., 1., 1., 1.],\n", + " [50., 50., 50., 50., 50., 1., 1., 1., 1., 1.],\n", + " [50., 50., 50., 50., 50., 1., 1., 1., 1., 1.],\n", + " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", + " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", + " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", + " [nan, 1., 1., 1., 1., 1., 1., 1., 1., nan],\n", + " [nan, nan, 1., 1., 1., 1., 1., 1., nan, nan]]])" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# confirm that the data has been updated\n", + "hk = npf.get_array(\"k11\")\n", + "hk" + ] + }, + { + "cell_type": "markdown", + "id": "7bdbdb1e", + "metadata": {}, + "source": [ + "Getting and setting data by attribute" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "2b589b5f", + "metadata": {}, + "outputs": [], + "source": [ + "# needs an update for inplace operations....\n", + "npf.k33[0, 0:5, 0:5] = 5" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "38e79b05", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[[nan, nan, 5., 5., 5., 1., 1., 1., nan, nan],\n", + " [nan, 5., 5., 5., 5., 1., 1., 1., 1., nan],\n", + " [ 5., 5., 5., 5., 5., 1., 1., 1., 1., 1.],\n", + " [ 5., 5., 5., 5., 5., 1., 1., 1., 1., 1.],\n", + " [ 5., 5., 5., 5., 5., 1., 1., 1., 1., 1.],\n", + " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", + " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", + " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", + " [nan, 1., 1., 1., 1., 1., 1., 1., 1., nan],\n", + " [nan, nan, 1., 1., 1., 1., 1., 1., nan, nan]]])" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# confirm that the data has been updated\n", + "npf.k33.values" + ] + }, + { + "cell_type": "markdown", + "id": "f245911d", + "metadata": {}, + "source": [ + "## Accessing \"advanced variables\"\n", + "\n", + "Advanced variables in this context are variables that would not normally need to be accessed by the user, and in many cases changes to these variables would cause the Modflow simulation to do unexpected things. " + ] + }, + { + "cell_type": "markdown", + "id": "ff9a706b", + "metadata": {}, + "source": [ + "For each package object a list of avanced variables can be returned by calling the `advanced_vars` attribute" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "4c943166", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['package_type',\n", + " 'id',\n", + " 'inunit',\n", + " 'iout',\n", + " 'inewton',\n", + " 'iasym',\n", + " 'iprpak',\n", + " 'iprflow',\n", + " 'ipakcb',\n", + " 'ionper',\n", + " 'lastonper',\n", + " 'listlabel',\n", + " 'isadvpak',\n", + " 'ibcnum',\n", + " 'ncolbnd',\n", + " 'iscloc',\n", + " 'inamedbound',\n", + " 'iauxmultcol',\n", + " 'inobspkg',\n", + " 'imover',\n", + " 'ivsc',\n", + " 'npakeq',\n", + " 'ioffset',\n", + " 'auxname',\n", + " 'iflowred',\n", + " 'flowred',\n", + " 'ioutafrcsv',\n", + " 'noupdateauxvar',\n", + " 'bound',\n", + " 'condinput',\n", + " 'hcof',\n", + " 'rhs',\n", + " 'simvals',\n", + " 'simtomvr',\n", + " 'boundname',\n", + " 'boundname_cst']" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wel = model.wel_0\n", + "wel.advanced_vars" + ] + }, + { + "cell_type": "markdown", + "id": "dcd0e792", + "metadata": {}, + "source": [ + "The user can access and change these values, _at their own risk_, using the `.get_advanced_var()` and `.set_advanced_var()` methods. Data is returned to the user in the internal modflowapi structure. " + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "id": "5a8ee821", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([1])" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "wel.get_advanced_var(\"ibcnum\")" + ] + }, + { + "cell_type": "markdown", + "id": "b034954d", + "metadata": {}, + "source": [ + "### Advanced Packages\n", + "\n", + "Certain packages only support accessing data through the `.get_advanced_var()` and `.set_advanced_var()` methods. These packages, are sometimes refered to as \"advanced packages\" and include: BUY, CSUB, GNC, HFB, MAW, MVR, SFR, and UZF. " + ] + }, + { + "cell_type": "markdown", + "id": "2e2d960a", + "metadata": {}, + "source": [ + "-------" + ] + }, + { + "cell_type": "markdown", + "id": "853b6390", + "metadata": {}, + "source": [ + "Let's close the existing modflowapi shared library object and look at an example of how this is all used in practice" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "6896d260", + "metadata": {}, + "outputs": [], + "source": [ + "mf6.finalize()" + ] + }, + { + "cell_type": "markdown", + "id": "27d3baa1", + "metadata": {}, + "source": [ + "# Putting it all together and running a modflowapi simulation\n", + "\n", + "To run a simulation using the built in modflowapi runner the user needs to create a function that will receive callbacks at different steps in the simulation run. For the remainder of this notebook, we'll show how to create a callback function and use it with the `modflowapi.run_simulation()` method." + ] + }, + { + "cell_type": "markdown", + "id": "4404b2c2", + "metadata": {}, + "source": [ + "## Create a callback function for adjusting model data\n", + "\n", + "The callback function allows users to wrap function that updates the modflow model at different steps. The `modflowapi.Callbacks` object allows users to find the particular solution step that they are currently in. `modflowapi.Callbacks` includes:\n", + "\n", + " - `Callbacks.initalize`: the initialize callback sends loaded simulation data back to the user to make adjustments before the model begins solving. This callback only occurs once at the beginning of the MODFLOW6 simulation\n", + " - `Callbacks.stress_period_start`: the stress_period_start callback sends simulation data for each solution group to the user to make adjustments to stress packages at the beginning of each stress period.\n", + " - `Callbacks.stress_period_end`: the stress_period_end callback sends simulation data for each solution group to the user at the end of each stress period. This can be useful for writing custom output and coupling models\n", + " - `Callbacks.timestep_start`: the timestep_start callback sends simulation data for each solution group to the user to make adjustments to stress packages at the beginning of each timestep.\n", + " - `Callbacks.timestep_end`: the timestep_end callback sends simulation data for each solution group to the user at the end of each timestep. This can be useful for writing custom output and coupling models\n", + " - `Callbacks.iteration_start`: the iteration_start callback sends simulation data for each solution group to the user to make adjustments to stress packages at the beginning of each outer solution iteration.\n", + " - `Callbacks.iteration_end`: the iteration_end callback sends simulation data for each solution group to the user to make adjustments to stress packages and check values of stress packages at the end of each outer solution iteration.\n", + " - `Callbacks.finalize`: the finalize callback is useful for finalizing models coupled with the modflowapi.\n", + " \n", + "The user can use any or all of these callbacks within their callback function" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "id": "c2783828", + "metadata": {}, + "outputs": [], + "source": [ + "from modflowapi import Callbacks" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "id": "395327da", + "metadata": {}, + "outputs": [], + "source": [ + "def callback_function(sim, callback_step):\n", + " \"\"\"\n", + " A demonstration function that dynamically adjusts recharge\n", + " and pumping in a modflow-6 model through the MODFLOW-API\n", + " \n", + " Parameters\n", + " ----------\n", + " sim : modflowapi.Simulation\n", + " A simulation object for the solution group that is \n", + " currently being solved\n", + " callback_step : enumeration\n", + " modflowapi.Callbacks enumeration object that indicates\n", + " the part of the solution modflow is currently in.\n", + " \"\"\"\n", + " ml = sim.test_model\n", + " if callback_step == Callbacks.initialize:\n", + " print(sim.models)\n", + " \n", + " if callback_step == Callbacks.stress_period_start:\n", + " # adjust recharge for stress periods 1 through 7\n", + " if sim.kper <= 6:\n", + " rcha = ml.rcha_0\n", + " spd = rcha.stress_period_data\n", + " print(f\"updating recharge: stress_period={ml.kper}\")\n", + " spd[\"recharge\"] += 0.40 * sim.kper\n", + " \n", + " \n", + " if callback_step == Callbacks.timestep_start:\n", + " print(f\"updating wel flux: stress_period={ml.kper}, timestep={ml.kstp}\")\n", + " ml.wel.stress_period_data[\"flux\"] -= ml.kstp * 1.5\n", + " \n", + " if callback_step == Callbacks.iteration_start:\n", + " # we can implement complex solutions to boundary conditions here!\n", + " pass\n", + " " + ] + }, + { + "cell_type": "markdown", + "id": "b751eb41", + "metadata": {}, + "source": [ + "The callback function is then passed to `modflowapi.run_simulation`" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "id": "0878e5b6", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[TEST_MODEL, 1 Layer, 10 Row, 10 Column model\n", + "Packages accessible include: \n", + " ArrayPackage objects:\n", + " dis: \n", + " npf: \n", + " sto: \n", + " ic: \n", + " ListPackage objects:\n", + " wel_0: \n", + " drn_0: \n", + " rch_0: \n", + " rcha_0: \n", + " evt_0: \n", + " chd_0: \n", + " AdvancedPackage objects:\n", + " buy: \n", + " vsc: \n", + " gnc: \n", + " hfb: \n", + " csub: \n", + " mvr: \n", + "]\n", + "updating recharge: stress_period=0\n", + "updating wel flux: stress_period=0, timestep=0\n", + "updating wel flux: stress_period=0, timestep=1\n", + "updating wel flux: stress_period=0, timestep=2\n", + "updating wel flux: stress_period=0, timestep=3\n", + "updating wel flux: stress_period=0, timestep=4\n", + "updating wel flux: stress_period=0, timestep=5\n", + "updating wel flux: stress_period=0, timestep=6\n", + "updating wel flux: stress_period=0, timestep=7\n", + "updating wel flux: stress_period=0, timestep=8\n", + "updating wel flux: stress_period=0, timestep=9\n", + "updating wel flux: stress_period=0, timestep=10\n", + "updating wel flux: stress_period=0, timestep=11\n", + "updating wel flux: stress_period=0, timestep=12\n", + "updating wel flux: stress_period=0, timestep=13\n", + "updating wel flux: stress_period=0, timestep=14\n", + "updating wel flux: stress_period=0, timestep=15\n", + "updating wel flux: stress_period=0, timestep=16\n", + "updating wel flux: stress_period=0, timestep=17\n", + "updating wel flux: stress_period=0, timestep=18\n", + "updating wel flux: stress_period=0, timestep=19\n", + "updating wel flux: stress_period=0, timestep=20\n", + "updating wel flux: stress_period=0, timestep=21\n", + "updating wel flux: stress_period=0, timestep=22\n", + "updating wel flux: stress_period=0, timestep=23\n", + "updating wel flux: stress_period=0, timestep=24\n", + "updating wel flux: stress_period=0, timestep=25\n", + "updating wel flux: stress_period=0, timestep=26\n", + "updating wel flux: stress_period=0, timestep=27\n", + "updating wel flux: stress_period=0, timestep=28\n", + "updating wel flux: stress_period=0, timestep=29\n", + "updating wel flux: stress_period=0, timestep=30\n", + "updating recharge: stress_period=1\n", + "updating wel flux: stress_period=1, timestep=0\n", + "updating wel flux: stress_period=1, timestep=1\n", + "updating wel flux: stress_period=1, timestep=2\n", + "updating wel flux: stress_period=1, timestep=3\n", + "updating wel flux: stress_period=1, timestep=4\n", + "updating wel flux: stress_period=1, timestep=5\n", + "updating wel flux: stress_period=1, timestep=6\n", + "updating wel flux: stress_period=1, timestep=7\n", + "updating wel flux: stress_period=1, timestep=8\n", + "updating wel flux: stress_period=1, timestep=9\n", + "updating wel flux: stress_period=1, timestep=10\n", + "updating wel flux: stress_period=1, timestep=11\n", + "updating wel flux: stress_period=1, timestep=12\n", + "updating wel flux: stress_period=1, timestep=13\n", + "updating wel flux: stress_period=1, timestep=14\n", + "updating wel flux: stress_period=1, timestep=15\n", + "updating wel flux: stress_period=1, timestep=16\n", + "updating wel flux: stress_period=1, timestep=17\n", + "updating wel flux: stress_period=1, timestep=18\n", + "updating wel flux: stress_period=1, timestep=19\n", + "updating wel flux: stress_period=1, timestep=20\n", + "updating wel flux: stress_period=1, timestep=21\n", + "updating wel flux: stress_period=1, timestep=22\n", + "updating wel flux: stress_period=1, timestep=23\n", + "updating wel flux: stress_period=1, timestep=24\n", + "updating wel flux: stress_period=1, timestep=25\n", + "updating wel flux: stress_period=1, timestep=26\n", + "updating wel flux: stress_period=1, timestep=27\n", + "updating recharge: stress_period=2\n", + "updating wel flux: stress_period=2, timestep=0\n", + "updating wel flux: stress_period=2, timestep=1\n", + "updating wel flux: stress_period=2, timestep=2\n", + "updating wel flux: stress_period=2, timestep=3\n", + "updating wel flux: stress_period=2, timestep=4\n", + "updating wel flux: stress_period=2, timestep=5\n", + "updating wel flux: stress_period=2, timestep=6\n", + "updating wel flux: stress_period=2, timestep=7\n", + "updating wel flux: stress_period=2, timestep=8\n", + "updating wel flux: stress_period=2, timestep=9\n", + "updating wel flux: stress_period=2, timestep=10\n", + "updating wel flux: stress_period=2, timestep=11\n", + "updating wel flux: stress_period=2, timestep=12\n", + "updating wel flux: stress_period=2, timestep=13\n", + "updating wel flux: stress_period=2, timestep=14\n", + "updating wel flux: stress_period=2, timestep=15\n", + "updating wel flux: stress_period=2, timestep=16\n", + "updating wel flux: stress_period=2, timestep=17\n", + "updating wel flux: stress_period=2, timestep=18\n", + "updating wel flux: stress_period=2, timestep=19\n", + "updating wel flux: stress_period=2, timestep=20\n", + "updating wel flux: stress_period=2, timestep=21\n", + "updating wel flux: stress_period=2, timestep=22\n", + "updating wel flux: stress_period=2, timestep=23\n", + "updating wel flux: stress_period=2, timestep=24\n", + "updating wel flux: stress_period=2, timestep=25\n", + "updating wel flux: stress_period=2, timestep=26\n", + "updating wel flux: stress_period=2, timestep=27\n", + "updating wel flux: stress_period=2, timestep=28\n", + "updating wel flux: stress_period=2, timestep=29\n", + "updating wel flux: stress_period=2, timestep=30\n", + "updating recharge: stress_period=3\n", + "updating wel flux: stress_period=3, timestep=0\n", + "updating wel flux: stress_period=3, timestep=1\n", + "updating wel flux: stress_period=3, timestep=2\n", + "updating wel flux: stress_period=3, timestep=3\n", + "updating wel flux: stress_period=3, timestep=4\n", + "updating wel flux: stress_period=3, timestep=5\n", + "updating wel flux: stress_period=3, timestep=6\n", + "updating wel flux: stress_period=3, timestep=7\n", + "updating wel flux: stress_period=3, timestep=8\n", + "updating wel flux: stress_period=3, timestep=9\n", + "updating wel flux: stress_period=3, timestep=10\n", + "updating wel flux: stress_period=3, timestep=11\n", + "updating wel flux: stress_period=3, timestep=12\n", + "updating wel flux: stress_period=3, timestep=13\n", + "updating wel flux: stress_period=3, timestep=14\n", + "updating wel flux: stress_period=3, timestep=15\n", + "updating wel flux: stress_period=3, timestep=16\n", + "updating wel flux: stress_period=3, timestep=17\n", + "updating wel flux: stress_period=3, timestep=18\n", + "updating wel flux: stress_period=3, timestep=19\n", + "updating wel flux: stress_period=3, timestep=20\n", + "updating wel flux: stress_period=3, timestep=21\n", + "updating wel flux: stress_period=3, timestep=22\n", + "updating wel flux: stress_period=3, timestep=23\n", + "updating wel flux: stress_period=3, timestep=24\n", + "updating wel flux: stress_period=3, timestep=25\n", + "updating wel flux: stress_period=3, timestep=26\n", + "updating wel flux: stress_period=3, timestep=27\n", + "updating wel flux: stress_period=3, timestep=28\n", + "updating wel flux: stress_period=3, timestep=29\n", + "updating recharge: stress_period=4\n", + "updating wel flux: stress_period=4, timestep=0\n", + "updating wel flux: stress_period=4, timestep=1\n", + "updating wel flux: stress_period=4, timestep=2\n", + "updating wel flux: stress_period=4, timestep=3\n", + "updating wel flux: stress_period=4, timestep=4\n", + "updating wel flux: stress_period=4, timestep=5\n", + "updating wel flux: stress_period=4, timestep=6\n", + "updating wel flux: stress_period=4, timestep=7\n", + "updating wel flux: stress_period=4, timestep=8\n", + "updating wel flux: stress_period=4, timestep=9\n", + "updating wel flux: stress_period=4, timestep=10\n", + "updating wel flux: stress_period=4, timestep=11\n", + "updating wel flux: stress_period=4, timestep=12\n", + "updating wel flux: stress_period=4, timestep=13\n", + "updating wel flux: stress_period=4, timestep=14\n", + "updating wel flux: stress_period=4, timestep=15\n", + "updating wel flux: stress_period=4, timestep=16\n", + "updating wel flux: stress_period=4, timestep=17\n", + "updating wel flux: stress_period=4, timestep=18\n", + "updating wel flux: stress_period=4, timestep=19\n", + "updating wel flux: stress_period=4, timestep=20\n", + "updating wel flux: stress_period=4, timestep=21\n", + "updating wel flux: stress_period=4, timestep=22\n", + "updating wel flux: stress_period=4, timestep=23\n", + "updating wel flux: stress_period=4, timestep=24\n", + "updating wel flux: stress_period=4, timestep=25\n", + "updating wel flux: stress_period=4, timestep=26\n", + "updating wel flux: stress_period=4, timestep=27\n", + "updating wel flux: stress_period=4, timestep=28\n", + "updating wel flux: stress_period=4, timestep=29\n", + "updating wel flux: stress_period=4, timestep=30\n", + "updating recharge: stress_period=5\n", + "updating wel flux: stress_period=5, timestep=0\n", + "updating wel flux: stress_period=5, timestep=1\n", + "updating wel flux: stress_period=5, timestep=2\n", + "updating wel flux: stress_period=5, timestep=3\n", + "updating wel flux: stress_period=5, timestep=4\n", + "updating wel flux: stress_period=5, timestep=5\n", + "updating wel flux: stress_period=5, timestep=6\n", + "updating wel flux: stress_period=5, timestep=7\n", + "updating wel flux: stress_period=5, timestep=8\n", + "updating wel flux: stress_period=5, timestep=9\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "updating wel flux: stress_period=5, timestep=10\n", + "updating wel flux: stress_period=5, timestep=11\n", + "updating wel flux: stress_period=5, timestep=12\n", + "updating wel flux: stress_period=5, timestep=13\n", + "updating wel flux: stress_period=5, timestep=14\n", + "updating wel flux: stress_period=5, timestep=15\n", + "updating wel flux: stress_period=5, timestep=16\n", + "updating wel flux: stress_period=5, timestep=17\n", + "updating wel flux: stress_period=5, timestep=18\n", + "updating wel flux: stress_period=5, timestep=19\n", + "updating wel flux: stress_period=5, timestep=20\n", + "updating wel flux: stress_period=5, timestep=21\n", + "updating wel flux: stress_period=5, timestep=22\n", + "updating wel flux: stress_period=5, timestep=23\n", + "updating wel flux: stress_period=5, timestep=24\n", + "updating wel flux: stress_period=5, timestep=25\n", + "updating wel flux: stress_period=5, timestep=26\n", + "updating wel flux: stress_period=5, timestep=27\n", + "updating wel flux: stress_period=5, timestep=28\n", + "updating wel flux: stress_period=5, timestep=29\n", + "updating recharge: stress_period=6\n", + "updating wel flux: stress_period=6, timestep=0\n", + "updating wel flux: stress_period=6, timestep=1\n", + "updating wel flux: stress_period=6, timestep=2\n", + "updating wel flux: stress_period=6, timestep=3\n", + "updating wel flux: stress_period=6, timestep=4\n", + "updating wel flux: stress_period=6, timestep=5\n", + "updating wel flux: stress_period=6, timestep=6\n", + "updating wel flux: stress_period=6, timestep=7\n", + "updating wel flux: stress_period=6, timestep=8\n", + "updating wel flux: stress_period=6, timestep=9\n", + "updating wel flux: stress_period=6, timestep=10\n", + "updating wel flux: stress_period=6, timestep=11\n", + "updating wel flux: stress_period=6, timestep=12\n", + "updating wel flux: stress_period=6, timestep=13\n", + "updating wel flux: stress_period=6, timestep=14\n", + "updating wel flux: stress_period=6, timestep=15\n", + "updating wel flux: stress_period=6, timestep=16\n", + "updating wel flux: stress_period=6, timestep=17\n", + "updating wel flux: stress_period=6, timestep=18\n", + "updating wel flux: stress_period=6, timestep=19\n", + "updating wel flux: stress_period=6, timestep=20\n", + "updating wel flux: stress_period=6, timestep=21\n", + "updating wel flux: stress_period=6, timestep=22\n", + "updating wel flux: stress_period=6, timestep=23\n", + "updating wel flux: stress_period=6, timestep=24\n", + "updating wel flux: stress_period=6, timestep=25\n", + "updating wel flux: stress_period=6, timestep=26\n", + "updating wel flux: stress_period=6, timestep=27\n", + "updating wel flux: stress_period=6, timestep=28\n", + "updating wel flux: stress_period=6, timestep=29\n", + "updating wel flux: stress_period=6, timestep=30\n", + "updating wel flux: stress_period=7, timestep=0\n", + "updating wel flux: stress_period=7, timestep=1\n", + "updating wel flux: stress_period=7, timestep=2\n", + "updating wel flux: stress_period=7, timestep=3\n", + "updating wel flux: stress_period=7, timestep=4\n", + "updating wel flux: stress_period=7, timestep=5\n", + "updating wel flux: stress_period=7, timestep=6\n", + "updating wel flux: stress_period=7, timestep=7\n", + "updating wel flux: stress_period=7, timestep=8\n", + "updating wel flux: stress_period=7, timestep=9\n", + "updating wel flux: stress_period=7, timestep=10\n", + "updating wel flux: stress_period=7, timestep=11\n", + "updating wel flux: stress_period=7, timestep=12\n", + "updating wel flux: stress_period=7, timestep=13\n", + "updating wel flux: stress_period=7, timestep=14\n", + "updating wel flux: stress_period=7, timestep=15\n", + "updating wel flux: stress_period=7, timestep=16\n", + "updating wel flux: stress_period=7, timestep=17\n", + "updating wel flux: stress_period=7, timestep=18\n", + "updating wel flux: stress_period=7, timestep=19\n", + "updating wel flux: stress_period=7, timestep=20\n", + "updating wel flux: stress_period=7, timestep=21\n", + "updating wel flux: stress_period=7, timestep=22\n", + "updating wel flux: stress_period=7, timestep=23\n", + "updating wel flux: stress_period=7, timestep=24\n", + "updating wel flux: stress_period=7, timestep=25\n", + "updating wel flux: stress_period=7, timestep=26\n", + "updating wel flux: stress_period=7, timestep=27\n", + "updating wel flux: stress_period=7, timestep=28\n", + "updating wel flux: stress_period=7, timestep=29\n", + "updating wel flux: stress_period=7, timestep=30\n", + "updating wel flux: stress_period=8, timestep=0\n", + "updating wel flux: stress_period=8, timestep=1\n", + "updating wel flux: stress_period=8, timestep=2\n", + "updating wel flux: stress_period=8, timestep=3\n", + "updating wel flux: stress_period=8, timestep=4\n", + "updating wel flux: stress_period=8, timestep=5\n", + "updating wel flux: stress_period=8, timestep=6\n", + "updating wel flux: stress_period=8, timestep=7\n", + "updating wel flux: stress_period=8, timestep=8\n", + "updating wel flux: stress_period=8, timestep=9\n", + "updating wel flux: stress_period=8, timestep=10\n", + "updating wel flux: stress_period=8, timestep=11\n", + "updating wel flux: stress_period=8, timestep=12\n", + "updating wel flux: stress_period=8, timestep=13\n", + "updating wel flux: stress_period=8, timestep=14\n", + "updating wel flux: stress_period=8, timestep=15\n", + "updating wel flux: stress_period=8, timestep=16\n", + "updating wel flux: stress_period=8, timestep=17\n", + "updating wel flux: stress_period=8, timestep=18\n", + "updating wel flux: stress_period=8, timestep=19\n", + "updating wel flux: stress_period=8, timestep=20\n", + "updating wel flux: stress_period=8, timestep=21\n", + "updating wel flux: stress_period=8, timestep=22\n", + "updating wel flux: stress_period=8, timestep=23\n", + "updating wel flux: stress_period=8, timestep=24\n", + "updating wel flux: stress_period=8, timestep=25\n", + "updating wel flux: stress_period=8, timestep=26\n", + "updating wel flux: stress_period=8, timestep=27\n", + "updating wel flux: stress_period=8, timestep=28\n", + "updating wel flux: stress_period=8, timestep=29\n", + "updating wel flux: stress_period=9, timestep=0\n", + "updating wel flux: stress_period=9, timestep=1\n", + "updating wel flux: stress_period=9, timestep=2\n", + "updating wel flux: stress_period=9, timestep=3\n", + "updating wel flux: stress_period=9, timestep=4\n", + "updating wel flux: stress_period=9, timestep=5\n", + "updating wel flux: stress_period=9, timestep=6\n", + "updating wel flux: stress_period=9, timestep=7\n", + "updating wel flux: stress_period=9, timestep=8\n", + "updating wel flux: stress_period=9, timestep=9\n", + "updating wel flux: stress_period=9, timestep=10\n", + "updating wel flux: stress_period=9, timestep=11\n", + "updating wel flux: stress_period=9, timestep=12\n", + "updating wel flux: stress_period=9, timestep=13\n", + "updating wel flux: stress_period=9, timestep=14\n", + "updating wel flux: stress_period=9, timestep=15\n", + "updating wel flux: stress_period=9, timestep=16\n", + "updating wel flux: stress_period=9, timestep=17\n", + "updating wel flux: stress_period=9, timestep=18\n", + "updating wel flux: stress_period=9, timestep=19\n", + "updating wel flux: stress_period=9, timestep=20\n", + "updating wel flux: stress_period=9, timestep=21\n", + "updating wel flux: stress_period=9, timestep=22\n", + "updating wel flux: stress_period=9, timestep=23\n", + "updating wel flux: stress_period=9, timestep=24\n", + "updating wel flux: stress_period=9, timestep=25\n", + "updating wel flux: stress_period=9, timestep=26\n", + "updating wel flux: stress_period=9, timestep=27\n", + "updating wel flux: stress_period=9, timestep=28\n", + "updating wel flux: stress_period=9, timestep=29\n", + "updating wel flux: stress_period=9, timestep=30\n", + "updating wel flux: stress_period=10, timestep=0\n", + "updating wel flux: stress_period=10, timestep=1\n", + "updating wel flux: stress_period=10, timestep=2\n", + "updating wel flux: stress_period=10, timestep=3\n", + "updating wel flux: stress_period=10, timestep=4\n", + "updating wel flux: stress_period=10, timestep=5\n", + "updating wel flux: stress_period=10, timestep=6\n", + "updating wel flux: stress_period=10, timestep=7\n", + "updating wel flux: stress_period=10, timestep=8\n", + "updating wel flux: stress_period=10, timestep=9\n", + "updating wel flux: stress_period=10, timestep=10\n", + "updating wel flux: stress_period=10, timestep=11\n", + "updating wel flux: stress_period=10, timestep=12\n", + "updating wel flux: stress_period=10, timestep=13\n", + "updating wel flux: stress_period=10, timestep=14\n", + "updating wel flux: stress_period=10, timestep=15\n", + "updating wel flux: stress_period=10, timestep=16\n", + "updating wel flux: stress_period=10, timestep=17\n", + "updating wel flux: stress_period=10, timestep=18\n", + "updating wel flux: stress_period=10, timestep=19\n", + "updating wel flux: stress_period=10, timestep=20\n", + "updating wel flux: stress_period=10, timestep=21\n", + "updating wel flux: stress_period=10, timestep=22\n", + "updating wel flux: stress_period=10, timestep=23\n", + "updating wel flux: stress_period=10, timestep=24\n", + "updating wel flux: stress_period=10, timestep=25\n", + "updating wel flux: stress_period=10, timestep=26\n", + "updating wel flux: stress_period=10, timestep=27\n", + "updating wel flux: stress_period=10, timestep=28\n", + "updating wel flux: stress_period=10, timestep=29\n", + "updating wel flux: stress_period=11, timestep=0\n", + "updating wel flux: stress_period=11, timestep=1\n", + "updating wel flux: stress_period=11, timestep=2\n", + "updating wel flux: stress_period=11, timestep=3\n", + "updating wel flux: stress_period=11, timestep=4\n", + "updating wel flux: stress_period=11, timestep=5\n", + "updating wel flux: stress_period=11, timestep=6\n", + "updating wel flux: stress_period=11, timestep=7\n", + "updating wel flux: stress_period=11, timestep=8\n", + "updating wel flux: stress_period=11, timestep=9\n", + "updating wel flux: stress_period=11, timestep=10\n", + "updating wel flux: stress_period=11, timestep=11\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "updating wel flux: stress_period=11, timestep=12\n", + "updating wel flux: stress_period=11, timestep=13\n", + "updating wel flux: stress_period=11, timestep=14\n", + "updating wel flux: stress_period=11, timestep=15\n", + "updating wel flux: stress_period=11, timestep=16\n", + "updating wel flux: stress_period=11, timestep=17\n", + "updating wel flux: stress_period=11, timestep=18\n", + "updating wel flux: stress_period=11, timestep=19\n", + "updating wel flux: stress_period=11, timestep=20\n", + "updating wel flux: stress_period=11, timestep=21\n", + "updating wel flux: stress_period=11, timestep=22\n", + "updating wel flux: stress_period=11, timestep=23\n", + "updating wel flux: stress_period=11, timestep=24\n", + "updating wel flux: stress_period=11, timestep=25\n", + "updating wel flux: stress_period=11, timestep=26\n", + "updating wel flux: stress_period=11, timestep=27\n", + "updating wel flux: stress_period=11, timestep=28\n", + "updating wel flux: stress_period=11, timestep=29\n", + "updating wel flux: stress_period=11, timestep=30\n", + "NORMAL TERMINATION OF SIMULATION\n" + ] + } + ], + "source": [ + "modflowapi.run_simulation(dll, sim_ws, callback_function, verbose=False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bc1e31af", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.9.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/modflowapi/version.py b/modflowapi/version.py index 2a30a86..be5ce0b 100644 --- a/modflowapi/version.py +++ b/modflowapi/version.py @@ -1,6 +1,6 @@ # version file for modflowapi major = 0 -minor = 0 -micro = 2 +minor = 2 +micro = 0 __version__ = f"{major}.{minor}.{micro}" From ab73ed613f948a8dd130b44a820ce6c22b3f64fa Mon Sep 17 00:00:00 2001 From: w-bonelli Date: Tue, 25 Apr 2023 10:07:17 -0400 Subject: [PATCH 13/34] ci(release): add automated release workflow and utility scripts (#18) --- .github/workflows/release.yml | 273 ++++++++++++++++++++++++++++++++ cliff.toml | 46 ++++++ pyproject.toml | 1 + scripts/pull_request_prepare.py | 22 +++ scripts/update_version.py | 152 ++++++++++++++++++ 5 files changed, 494 insertions(+) create mode 100644 .github/workflows/release.yml create mode 100644 cliff.toml create mode 100644 scripts/pull_request_prepare.py create mode 100644 scripts/update_version.py diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..a071a43 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,273 @@ +name: Release +on: + push: + branches: + - main + - v[0-9]+.[0-9]+.[0-9]+* + release: + types: + - published +jobs: + prep: + name: Prepare release + runs-on: ubuntu-latest + if: ${{ github.event_name == 'push' && github.ref_name != 'main' }} + permissions: + contents: write + pull-requests: write + defaults: + run: + shell: bash + steps: + + - name: Checkout release branch + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: 3.8 + cache: 'pip' + cache-dependency-path: pyproject.toml + + - name: Install Python dependencies + run: | + pip install --upgrade pip + pip install build twine + pip install . + pip install ".[lint, test]" + + - name: Update version + id: version + run: | + ref="${{ github.ref_name }}" + version="${ref#"v"}" + python scripts/update_version.py -v "$version" + python -c "import modflowapi; print('Version: ', modflowapi.__version__)" + echo "version=$version" >> $GITHUB_OUTPUT + + - name: Touch changelog + run: touch HISTORY.md + + - name: Generate changelog + id: cliff + uses: orhun/git-cliff-action@v1 + with: + config: cliff.toml + args: --verbose --unreleased --tag ${{ steps.version.outputs.version }} + env: + OUTPUT: CHANGELOG.md + + - name: Update changelog + id: update-changelog + run: | + # move changelog + clog="CHANGELOG_${{ steps.version.outputs.version }}.md" + echo "changelog=$clog" >> $GITHUB_OUTPUT + sudo cp "${{ steps.cliff.outputs.changelog }}" "$clog" + + # show current release changelog + cat "$clog" + + # substitute full group names + sed -i 's/#### Ci/#### Continuous integration/' "$clog" + sed -i 's/#### Feat/#### New features/' "$clog" + sed -i 's/#### Fix/#### Bug fixes/' "$clog" + sed -i 's/#### Refactor/#### Refactoring/' "$clog" + sed -i 's/#### Test/#### Testing/' "$clog" + + cat "$clog" HISTORY.md > temp_history.md + sudo mv temp_history.md HISTORY.md + + # show full changelog + cat HISTORY.md + + - name: Upload changelog + uses: actions/upload-artifact@v3 + with: + name: changelog + path: ${{ steps.update-changelog.outputs.changelog }} + + - name: Format Python files + run: python scripts/pull_request_prepare.py + + - name: Push release branch + env: + GITHUB_TOKEN: ${{ github.token }} + run: | + ver="${{ steps.version.outputs.version }}" + changelog=$(cat ${{ steps.update-changelog.outputs.changelog }} | grep -v "### Version $ver") + + # remove this release's changelog so we don't commit it + # the changes have already been prepended to HISTORY.md + rm ${{ steps.update-changelog.outputs.changelog }} + rm -f CHANGELOG.md + + # commit and push changes + git config core.sharedRepository true + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add -A + git commit -m "ci(release): set version to ${{ steps.version.outputs.version }}, update changelog" + git push origin "${{ github.ref_name }}" + + title="Release $ver" + body=' + # Release '$ver' + + The release can be approved by merging this pull request into `main`. This will trigger jobs to publish the release to PyPI and reset `develop` from `main`, incrementing the minor version number. + + ## Changelog + + '$changelog' + ' + gh pr create -B "main" -H "${{ github.ref_name }}" --title "$title" --draft --body "$body" + + release: + name: Draft release + # runs only when changes are merged to main + if: ${{ github.event_name == 'push' && github.ref_name == 'main' }} + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + + - name: Checkout repo + uses: actions/checkout@v3 + with: + ref: main + + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: 3.8 + + - name: Install Python dependencies + run: | + pip install --upgrade pip + pip install . + pip install ".[test]" + + # actions/download-artifact won't look at previous workflow runs but we need to in order to get changelog + - name: Download artifacts + uses: dawidd6/action-download-artifact@v2 + + - name: Draft release + env: + GITHUB_TOKEN: ${{ github.token }} + run: | + version=$(python scripts/update_version.py -g) + title="modflowapi $version" + notes=$(cat "changelog/CHANGELOG_$version.md" | grep -v "### Version $version") + gh release create "$version" \ + --target main \ + --title "$title" \ + --notes "$notes" \ + --draft \ + --latest + + publish: + name: Publish package + # runs only after release is published (manually promoted from draft) + if: github.event_name == 'release' && github.repository_owner == 'MODFLOW-USGS' + runs-on: ubuntu-22.04 + permissions: + contents: write + pull-requests: write + steps: + + - name: Checkout main branch + uses: actions/checkout@v3 + with: + ref: main + + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: 3.8 + + - name: Install Python dependencies + run: | + pip install --upgrade pip + pip install build twine + pip install . + + - name: Build package + run: python -m build + + - name: Check package + run: twine check --strict dist/* + + - name: Publish package + run: twine upload dist/* + + reset: + name: Draft reset PR + if: ${{ github.event_name == 'release' }} + runs-on: ubuntu-22.04 + permissions: + contents: write + pull-requests: write + steps: + + - name: Checkout main branch + uses: actions/checkout@v3 + with: + ref: main + + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: 3.8 + cache: 'pip' + cache-dependency-path: pyproject.toml + + - name: Install Python dependencies + run: | + pip install --upgrade pip + pip install . + pip install ".[lint, test]" + + - name: Get release tag + uses: oprypin/find-latest-tag@v1 + id: latest_tag + with: + repository: ${{ github.repository }} + releases-only: true + + - name: Draft pull request + env: + GITHUB_TOKEN: ${{ github.token }} + run: | + # create reset branch from main + reset_branch="post-release-${{ steps.latest_tag.outputs.tag }}-reset" + git switch -c $reset_branch + + # increment minor version + major_version=$(echo "${{ steps.latest_tag.outputs.tag }}" | cut -d. -f1) + minor_version=$(echo "${{ steps.latest_tag.outputs.tag }}" | cut -d. -f2) + patch_version=0 + version="$major_version.$((minor_version + 1)).$patch_version" + python scripts/update_version.py -v "$version" + + # format Python files + python scripts/pull_request_prepare.py + + # commit and push reset branch + git config core.sharedRepository true + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add -A + git commit -m "ci(release): update to development version $version" + git push -u origin $reset_branch + + # create PR into develop + body=' + # Reinitialize for development + + Updates the `develop` branch from `main` following a successful release. Increments the minor version number. + ' + gh pr create -B "develop" -H "$reset_branch" --title "Reinitialize develop branch" --draft --body "$body" \ No newline at end of file diff --git a/cliff.toml b/cliff.toml new file mode 100644 index 0000000..d8089d6 --- /dev/null +++ b/cliff.toml @@ -0,0 +1,46 @@ +# configuration file for git-cliff (0.1.0) + +[changelog] +body = """ +{% if version %}\ + ### Version {{ version | trim_start_matches(pat="v") }} +{% else %}\ + ### [unreleased] +{% endif %}\ +{% for group, commits in commits | group_by(attribute="group") %} + #### {{ group | upper_first }} + {% for commit in commits %} + * [{{ commit.group }}{% if commit.scope %}({{ commit.scope }}){% endif %}](https://github.com/MODFLOW-USGS/modflowapi/commit/{{ commit.id }}): {% if commit.breaking %}[**breaking**] {% endif %}{{ commit.message | upper_first }}. Committed by {{ commit.author.name }} on {{ commit.author.timestamp | date(format="%Y-%m-%d") }}.\ + {% endfor %} +{% endfor %}\n +""" +trim = true + +[git] +conventional_commits = true +filter_unconventional = true +split_commits = false +commit_parsers = [ + { message = "^[fF]eat", group = "feat"}, + { message = "^[fF]ix", group = "fix"}, + { message = "^[bB]ug", group = "fix"}, + { message = "^[pP]erf", group = "perf"}, + { message = "^[rR]efactor", group = "refactor"}, + { message = "^[uU]pdate", group = "refactor"}, + { message = "^[aA]dd", group = "refactor"}, + { message = "^[dD]oc.*", group = "docs", skip = true}, + { message = "^[bB]inder", group = "docs", skip = true}, + { message = "^[nN]otebook.*", group = "docs", skip = true}, + { message = "^[rR][eE][aA][dD].*", group = "docs", skip = true}, + { message = "^[sS]tyl.*", group = "style", skip = true}, + { message = "^[tT]est.*", group = "test", skip = true}, + { message = "^[cC][iI]", skip = true}, + { message = "^[cC][iI]\\(release\\):", skip = true}, + { message = "^[rR]elease", skip = true}, + { message = "^[cC]hore", group = "chore", skip = true}, +] +protect_breaking_commits = false +filter_commits = false +tag_pattern = "[0-9].[0-9].[0-9]" +ignore_tags = "" +sort_commits = "oldest" diff --git a/pyproject.toml b/pyproject.toml index 691b4e6..f2df586 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,6 +49,7 @@ test = [ lint = [ "black", "flake8", + "isort", "pylint", ] diff --git a/scripts/pull_request_prepare.py b/scripts/pull_request_prepare.py new file mode 100644 index 0000000..909a25d --- /dev/null +++ b/scripts/pull_request_prepare.py @@ -0,0 +1,22 @@ +import os + +try: + import isort + + print(f"isort version: {isort.__version__}") +except ModuleNotFoundError: + print("isort not installed\n\tInstall using pip install isort") + +try: + import black + + print(f"black version: {black.__version__}") +except ModuleNotFoundError: + print("black not installed\n\tInstall using pip install black") + +# uncomment if/when isort used +# print("running isort...") +# os.system("isort -v ../modflowapi") + +print("running black...") +os.system("black -v ../modflowapi") diff --git a/scripts/update_version.py b/scripts/update_version.py new file mode 100644 index 0000000..e3aa0fe --- /dev/null +++ b/scripts/update_version.py @@ -0,0 +1,152 @@ +import argparse +import textwrap +from datetime import datetime +from enum import Enum +from os import PathLike +from pathlib import Path +from typing import NamedTuple + +from filelock import FileLock + +_project_name = "modflowapi" +_project_root_path = Path(__file__).parent.parent +_version_py_path = _project_root_path / "modflowapi" / "version.py" +_citation_cff_path = _project_root_path / "CITATION.cff" + + +class Version(NamedTuple): + """Semantic version number""" + + major: int = 0 + minor: int = 0 + patch: int = 0 + + def __repr__(self): + return f"{self.major}.{self.minor}.{self.patch}" + + @classmethod + def from_string(cls, version: str) -> "Version": + t = version.split(".") + + vmajor = int(t[0]) + vminor = int(t[1]) + vpatch = int(t[2]) + + return cls(major=vmajor, minor=vminor, patch=vpatch) + + @classmethod + def from_file(cls, path: PathLike) -> "Version": + lines = [ + line.rstrip("\n") + for line in open(Path(path).expanduser().absolute(), "r") + ] + vmajor = vminor = vpatch = None + for line in lines: + line = line.strip() + if not any(line): + continue + + def get_ver(l): + return l.split("=")[1] + + if "__version__" not in line: + if "major" in line: + vmajor = int(get_ver(line)) + elif "minor" in line: + vminor = int(get_ver(line)) + elif "patch" in line or "micro" in line: + vpatch = int(get_ver(line)) + + assert ( + vmajor is not None and vminor is not None and vpatch is not None + ), "version string must follow semantic version format: major.minor.patch" + return cls(major=vmajor, minor=vminor, patch=vpatch) + + +_initial_version = Version(0, 0, 1) +_current_version = Version.from_file(_version_py_path) + + +def update_version_py(timestamp: datetime, version: Version): + with open(_version_py_path, "w") as f: + f.write( + f"# {_project_name} version file automatically created using " + f"{Path(__file__).name} on {timestamp:%B %d, %Y %H:%M:%S}\n\n" + ) + f.write(f"major = {version.major}\n") + f.write(f"minor = {version.minor}\n") + f.write(f"micro = {version.patch}\n") + f.write("__version__ = f'{major}.{minor}.{micro}'\n") + print(f"Updated {_version_py_path} to version {version}") + +def update_citation_cff(timestamp: datetime, version: Version): + lines = open(_citation_cff_path, "r").readlines() + with open(_citation_cff_path, "w") as f: + for line in lines: + if line.startswith("version:"): + line = f"version: {version}\n" + f.write(line) + print(f"Updated {_citation_cff_path} to version {version}") + +def update_version( + timestamp: datetime = datetime.now(), + version: Version = None, +): + lock_path = Path(_version_py_path.name + ".lock") + try: + lock = FileLock(lock_path) + previous = Version.from_file(_version_py_path) + version = ( + version + if version + else Version(previous.major, previous.minor, previous.patch) + ) + + with lock: + update_version_py(timestamp, version) + update_citation_cff(timestamp, version) + finally: + try: + lock_path.unlink() + except: + pass + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + prog=f"Update {_project_name} version", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=textwrap.dedent( + """\ + Update version information stored in version.txt in the project root, + as well as several other files in the repository. If --version is not + provided, the version number will not be changed. A file lock is held + to synchronize file access. The version tag must comply with standard + '..' format conventions for semantic versioning. + """ + ), + ) + parser.add_argument( + "-v", + "--version", + required=False, + help="Specify the release version", + ) + parser.add_argument( + "-g", + "--get", + required=False, + action="store_true", + help="Just get the current version number, don't update anything (defaults to false)", + ) + args = parser.parse_args() + + if args.get: + print(_current_version) + else: + update_version( + timestamp=datetime.now(), + version=Version.from_string(args.version) + if args.version + else _current_version, + ) From c0f681c5b7525388ead4df8c6363c1b4514d6de6 Mon Sep 17 00:00:00 2001 From: Joshua Larsen Date: Fri, 28 Apr 2023 15:49:24 -0700 Subject: [PATCH 14/34] Update(rhs, hcof): updates to allow setting values when rhs and hcof have not yet had pointers set. --- autotest/test_interface.py | 14 ++++++++++++++ modflowapi/extensions/pakbase.py | 12 ++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/autotest/test_interface.py b/autotest/test_interface.py index 45f11a3..43bb8cb 100644 --- a/autotest/test_interface.py +++ b/autotest/test_interface.py @@ -361,6 +361,20 @@ def callback(sim, step): err_msg="set advanced var method not working properly" ) + npf = model.npf + + try: + npf.hcof = [1, 2, 3] + raise AssertionError("hcof setter is not reporting errors") + except Exception: + pass + + try: + npf.rhs = [1, 2, 3] + raise AssertionError("rhs setter is not reporting errors") + except Exception: + pass + name = "dis_model" sim_pth = data_pth / name test_pth = tmpdir / name diff --git a/modflowapi/extensions/pakbase.py b/modflowapi/extensions/pakbase.py index 19be40c..3a1d9c2 100644 --- a/modflowapi/extensions/pakbase.py +++ b/modflowapi/extensions/pakbase.py @@ -348,7 +348,11 @@ def rhs(self): @rhs.setter def rhs(self, values): if self._rhs is None: - return + rhs = self.rhs + if rhs is None: + raise Exception( + f"{self.pkg_type} does not have a rhs array" + ) self._rhs[:] = values[:] @@ -369,7 +373,11 @@ def hcof(self): @hcof.setter def hcof(self, values): if self._hcof is None: - return + hcof = self.hcof + if hcof is None: + raise Exception( + f"{self.pkg_type} does not have an hcof array" + ) self._hcof[:] = values[:] From 32a36984046ae43a83c7a12afb475599a6cbfb98 Mon Sep 17 00:00:00 2001 From: Joshua Larsen Date: Fri, 28 Apr 2023 15:52:23 -0700 Subject: [PATCH 15/34] lint PR --- modflowapi/extensions/pakbase.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/modflowapi/extensions/pakbase.py b/modflowapi/extensions/pakbase.py index 3a1d9c2..0aafca4 100644 --- a/modflowapi/extensions/pakbase.py +++ b/modflowapi/extensions/pakbase.py @@ -350,9 +350,7 @@ def rhs(self, values): if self._rhs is None: rhs = self.rhs if rhs is None: - raise Exception( - f"{self.pkg_type} does not have a rhs array" - ) + raise Exception(f"{self.pkg_type} does not have a rhs array") self._rhs[:] = values[:] @@ -375,9 +373,7 @@ def hcof(self, values): if self._hcof is None: hcof = self.hcof if hcof is None: - raise Exception( - f"{self.pkg_type} does not have an hcof array" - ) + raise Exception(f"{self.pkg_type} does not have an hcof array") self._hcof[:] = values[:] From 3b6675aa687f5af01813abfdb143c7ddd4343646 Mon Sep 17 00:00:00 2001 From: Joshua Larsen Date: Mon, 17 Jul 2023 09:17:24 -0700 Subject: [PATCH 16/34] update(Quickstart.ipynb): fix error in callback_function --- examples/notebooks/Quickstart.ipynb | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/examples/notebooks/Quickstart.ipynb b/examples/notebooks/Quickstart.ipynb index 82524f8..ca5843d 100644 --- a/examples/notebooks/Quickstart.ipynb +++ b/examples/notebooks/Quickstart.ipynb @@ -101,7 +101,7 @@ " print(f\"updating wel flux: stress_period={ml.kper}, timestep={ml.kstp}\")\n", " ml.wel.stress_period_data[\"flux\"] -= ml.kstp * 1.5\n", " \n", - " if step == Callbacks.iteration_start:\n", + " if callback_step == Callbacks.iteration_start:\n", " # we can implement complex solutions to boundary conditions here!\n", " pass\n", " " @@ -135,13 +135,13 @@ " ListPackage objects:\n", " wel_0: \n", " drn_0: \n", - " ghb_0: \n", " rch_0: \n", " rcha_0: \n", " evt_0: \n", " chd_0: \n", " AdvancedPackage objects:\n", " buy: \n", + " vsc: \n", " gnc: \n", " hfb: \n", " csub: \n", @@ -306,19 +306,19 @@ "updating recharge: stress_period=5\n", "updating wel flux: stress_period=5, timestep=0\n", "updating wel flux: stress_period=5, timestep=1\n", - "updating wel flux: stress_period=5, timestep=2\n", - "updating wel flux: stress_period=5, timestep=3\n", - "updating wel flux: stress_period=5, timestep=4\n", - "updating wel flux: stress_period=5, timestep=5\n", - "updating wel flux: stress_period=5, timestep=6\n", - "updating wel flux: stress_period=5, timestep=7\n", - "updating wel flux: stress_period=5, timestep=8\n" + "updating wel flux: stress_period=5, timestep=2\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ + "updating wel flux: stress_period=5, timestep=3\n", + "updating wel flux: stress_period=5, timestep=4\n", + "updating wel flux: stress_period=5, timestep=5\n", + "updating wel flux: stress_period=5, timestep=6\n", + "updating wel flux: stress_period=5, timestep=7\n", + "updating wel flux: stress_period=5, timestep=8\n", "updating wel flux: stress_period=5, timestep=9\n", "updating wel flux: stress_period=5, timestep=10\n", "updating wel flux: stress_period=5, timestep=11\n", @@ -498,16 +498,16 @@ "updating wel flux: stress_period=11, timestep=1\n", "updating wel flux: stress_period=11, timestep=2\n", "updating wel flux: stress_period=11, timestep=3\n", - "updating wel flux: stress_period=11, timestep=4\n", - "updating wel flux: stress_period=11, timestep=5\n", - "updating wel flux: stress_period=11, timestep=6\n", - "updating wel flux: stress_period=11, timestep=7\n" + "updating wel flux: stress_period=11, timestep=4\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ + "updating wel flux: stress_period=11, timestep=5\n", + "updating wel flux: stress_period=11, timestep=6\n", + "updating wel flux: stress_period=11, timestep=7\n", "updating wel flux: stress_period=11, timestep=8\n", "updating wel flux: stress_period=11, timestep=9\n", "updating wel flux: stress_period=11, timestep=10\n", @@ -531,7 +531,7 @@ "updating wel flux: stress_period=11, timestep=28\n", "updating wel flux: stress_period=11, timestep=29\n", "updating wel flux: stress_period=11, timestep=30\n", - "SUCCESSFUL TERMINATION OF THE SIMULATION\n" + "NORMAL TERMINATION OF SIMULATION\n" ] } ], From e693282611d5863bafeece362230a4aadd02311f Mon Sep 17 00:00:00 2001 From: w-bonelli Date: Thu, 3 Aug 2023 14:29:06 -0400 Subject: [PATCH 17/34] refactor: update libmf6 path handling (#27) * introduce modflowapi/util.py with amend_libmf6_path() * test libmf6 discovery by name, relpath, abspath * use github.workspace context in ci.yml * run black/isort on some files --- .github/workflows/ci.yml | 12 +++---- autotest/__init__.py | 2 +- autotest/conftest.py | 1 + autotest/test_interface.py | 62 ++++++++++++++++++++++++++------- autotest/test_mf6_examples.py | 4 +-- modflowapi/extensions/runner.py | 19 +--------- modflowapi/modflowapi.py | 3 +- modflowapi/util.py | 21 +++++++++++ scripts/update_version.py | 2 ++ 9 files changed, 82 insertions(+), 44 deletions(-) create mode 100644 modflowapi/util.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3ba4fb1..1de562f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -128,15 +128,13 @@ jobs: - name: Install modflow executables uses: modflowpy/install-modflow-action@v1 with: - path: ~/work/modflowapi/modflowapi/autotest + path: ${{ github.workspace }}/autotest repo: modflow6-nightly-build - name: Run autotests working-directory: ./autotest shell: bash -l {0} - run: | - # chmod a+x libmf6* - pytest -n auto -m "not mf6" + run: pytest -v -n auto -m "not mf6" autotest_mf6_examples: name: modflowapi mf6 examples autotests @@ -173,12 +171,10 @@ jobs: - name: Install modflow executables uses: modflowpy/install-modflow-action@v1 with: - path: ~/work/modflowapi/modflowapi/autotest + path: ${{ github.workspace }}/autotest repo: modflow6-nightly-build - name: Run autotests working-directory: ./autotest shell: bash -l {0} - run: | - # chmod a+x libmf6* - pytest -n auto -m "mf6 and not extensions" + run: pytest -v -n auto -m "mf6 and not extensions" diff --git a/autotest/__init__.py b/autotest/__init__.py index 042b236..0f58320 100644 --- a/autotest/__init__.py +++ b/autotest/__init__.py @@ -1 +1 @@ -# init file for pytest \ No newline at end of file +# init file for pytest diff --git a/autotest/conftest.py b/autotest/conftest.py index 9413bdd..e417e43 100644 --- a/autotest/conftest.py +++ b/autotest/conftest.py @@ -31,6 +31,7 @@ def get_mf6_examples_path() -> Path: finally: __mf6_examples_lock.release() + def is_nested(namfile) -> bool: p = Path(namfile) if not p.is_file() or not p.name.endswith(".nam"): diff --git a/autotest/test_interface.py b/autotest/test_interface.py index 43bb8cb..1c7ce40 100644 --- a/autotest/test_interface.py +++ b/autotest/test_interface.py @@ -1,17 +1,54 @@ +import shutil +from pathlib import Path +from platform import system + +import numpy as np import pytest -import pathlib +from modflow_devtools.misc import set_dir + +from modflowapi import Callbacks, ModflowApi, run_simulation from modflowapi.extensions.pakbase import ( + AdvancedPackage, ArrayPackage, ListPackage, - AdvancedPackage, ) -from modflowapi import Callbacks, run_simulation -import shutil -import numpy as np +data_pth = Path("../examples/data") pytestmark = pytest.mark.extensions -so = "libmf6" -data_pth = pathlib.Path("../examples/data") +os = system() +so = "libmf6" + ( + ".so" + if os == "Linux" + else ".dylib" + if os == "Darwin" + else ".dll" + if os == "Windows" + else None +) +if so is None: + pytest.skip("Unsupported operating system", allow_module_level=True) + + +@pytest.mark.parametrize("use_str", [True, False]) +def test_ctor_finds_libmf6_by_name(use_str): + api = ModflowApi(so if use_str else Path(so)) + + +@pytest.mark.parametrize("use_str", [True, False]) +def test_ctor_finds_libmf6_by_relpath(tmpdir, use_str): + shutil.copy(so, tmpdir) + inner = tmpdir / "inner" + inner.mkdir() + with set_dir(inner): + so_path = f"../{so}" + api = ModflowApi(so_path if use_str else Path(so_path)) + + +@pytest.mark.parametrize("use_str", [True, False]) +def test_ctor_finds_libmf6_by_abspath(tmpdir, use_str): + shutil.copy(so, tmpdir) + so_path = tmpdir / so + api = ModflowApi(str(so_path) if use_str else so_path) def test_dis_model(tmpdir): @@ -329,7 +366,6 @@ def test_rhs_hcof_advanced(tmpdir): def callback(sim, step): model = sim.test_model if step == Callbacks.timestep_start: - wel = model.wel rhs = wel.rhs rhs[0:3] = [-150, -100, -50] @@ -341,7 +377,7 @@ def callback(sim, step): ) hcof = wel.hcof - hcof[0: 3] = np.abs(rhs)[0:3] / 2 + hcof[0:3] = np.abs(rhs)[0:3] / 2 wel.hcof = hcof @@ -352,13 +388,13 @@ def callback(sim, step): ) rhs *= 1.2 - wel.set_advanced_var('rhs', rhs) + wel.set_advanced_var("rhs", rhs) rhs3 = wel.rhs np.testing.assert_allclose( rhs, rhs3, - err_msg="set advanced var method not working properly" + err_msg="set advanced var method not working properly", ) npf = model.npf @@ -374,7 +410,7 @@ def callback(sim, step): raise AssertionError("rhs setter is not reporting errors") except Exception: pass - + name = "dis_model" sim_pth = data_pth / name test_pth = tmpdir / name @@ -383,4 +419,4 @@ def callback(sim, step): try: run_simulation(so, test_pth, callback) except Exception as e: - raise Exception(e) \ No newline at end of file + raise Exception(e) diff --git a/autotest/test_mf6_examples.py b/autotest/test_mf6_examples.py index 72c89d2..8ed392b 100644 --- a/autotest/test_mf6_examples.py +++ b/autotest/test_mf6_examples.py @@ -24,9 +24,7 @@ def test_mf6_example_simulations(tmpdir, mf6_example_namfiles): namfile = Path(mf6_example_namfiles[0]) nested = is_nested(namfile) - tmpdir = Path( - tmpdir / "workspace" - ) + tmpdir = Path(tmpdir / "workspace") copytree( src=namfile.parent.parent if nested else namfile.parent, dst=tmpdir diff --git a/modflowapi/extensions/runner.py b/modflowapi/extensions/runner.py index bd2a8d5..11e67fe 100644 --- a/modflowapi/extensions/runner.py +++ b/modflowapi/extensions/runner.py @@ -38,24 +38,7 @@ def run_simulation(dll, sim_path, callback, verbose=False, _develop=False): development purposes and bug fixes within the modflowapi python package. """ - ext = pathlib.Path(dll).suffix - dll = str(dll) - if not ext: - if platform.system().lower() == "windows": - dll += ".dll" - elif platform.system().lower() == "linux": - if not dll.startswith("./"): - if not dll.startswith("/"): - dll = "./" + dll + ".so" - else: - dll = "." + dll + ".so" - else: - dll += ".dylib" - - mf6 = ModflowApi( - dll, - working_directory=sim_path, - ) + mf6 = ModflowApi(dll, working_directory=sim_path) if verbose: version = mf6.get_version() diff --git a/modflowapi/modflowapi.py b/modflowapi/modflowapi.py index 882fa0a..23de9fa 100644 --- a/modflowapi/modflowapi.py +++ b/modflowapi/modflowapi.py @@ -1,4 +1,5 @@ from xmipy import XmiWrapper +from .util import amend_libmf6_path class ModflowApi(XmiWrapper): @@ -20,7 +21,7 @@ def __init__( timing: bool = False, ): super().__init__( - lib_path, + amend_libmf6_path(lib_path), lib_dependency=lib_dependency, working_directory=working_directory, timing=timing, diff --git a/modflowapi/util.py b/modflowapi/util.py new file mode 100644 index 0000000..3d37d8a --- /dev/null +++ b/modflowapi/util.py @@ -0,0 +1,21 @@ +from pathlib import Path +from platform import system + + +def amend_libmf6_path(path) -> str: + ext = Path(path).suffix + path = str(path) + os = system().lower() + if os == "windows": + if not ext: + path += ".dll" + path = str(Path(path).absolute()) + elif os == "linux": + if not ext: + path += ".so" + if not path.startswith("./"): + if not path.startswith("/"): + path = "./" + path + elif os == "darwin" and not ext: + path += ".dylib" + return path diff --git a/scripts/update_version.py b/scripts/update_version.py index e3aa0fe..de8074b 100644 --- a/scripts/update_version.py +++ b/scripts/update_version.py @@ -79,6 +79,7 @@ def update_version_py(timestamp: datetime, version: Version): f.write("__version__ = f'{major}.{minor}.{micro}'\n") print(f"Updated {_version_py_path} to version {version}") + def update_citation_cff(timestamp: datetime, version: Version): lines = open(_citation_cff_path, "r").readlines() with open(_citation_cff_path, "w") as f: @@ -88,6 +89,7 @@ def update_citation_cff(timestamp: datetime, version: Version): f.write(line) print(f"Updated {_citation_cff_path} to version {version}") + def update_version( timestamp: datetime = datetime.now(), version: Version = None, From 48af4d1ef820179322f05e4efcbf3d55b37384ec Mon Sep 17 00:00:00 2001 From: Mike Taves Date: Wed, 9 Aug 2023 01:15:25 +1200 Subject: [PATCH 18/34] docs: clean up duplicated notebooks (#28) --- examples/notebooks/Head Monitor Example.ipynb | 255 -- .../MODFLOW-API extensions objects.ipynb | 2047 ----------------- 2 files changed, 2302 deletions(-) delete mode 100644 examples/notebooks/Head Monitor Example.ipynb delete mode 100644 examples/notebooks/MODFLOW-API extensions objects.ipynb diff --git a/examples/notebooks/Head Monitor Example.ipynb b/examples/notebooks/Head Monitor Example.ipynb deleted file mode 100644 index 4e800ea..0000000 --- a/examples/notebooks/Head Monitor Example.ipynb +++ /dev/null @@ -1,255 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "ee31d799", - "metadata": {}, - "source": [ - "# MODFLOW-API Head monitor example\n", - "\n", - "In this example the modflow-api is used in a more complex callback function to create a Head Monitor that updates at the timestep level. This example reverses `CHD` boundary conditions each stress period on a simple 10 x 10 model and displays the head results for each timestep.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "4526a124", - "metadata": {}, - "outputs": [], - "source": [ - "from IPython.display import clear_output, display # remove this import if adapted to python script\n", - "\n", - "from modflowapi import run_simulation, Callbacks\n", - "from flopy.discretization import StructuredGrid\n", - "from flopy.plot import PlotMapView, styles\n", - "from pathlib import Path\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt" - ] - }, - { - "cell_type": "markdown", - "id": "3f7ac8a2", - "metadata": {}, - "source": [ - "### Create a class that includes a callback function\n", - "\n", - "This class handles changing the `CHD` boundary condition as well as updating the matplotlib plot." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "cdd38b59", - "metadata": {}, - "outputs": [], - "source": [ - "class StructuredHeadMonitor:\n", - " \"\"\"\n", - " An example class that reverses the model gradient by\n", - " swapping CHD boundary conditions each stress period, \n", - " and monitors the head at each timestep by updating\n", - " a matplotlib plot. This class could be adapted to \n", - " be used as a head monitor to observe other changes\n", - " in the model by modifying the callback class.\n", - " \n", - " Parameters\n", - " ----------\n", - " layer: int\n", - " zero based model layer to plot\n", - " vmin : float\n", - " minimum head value for color scaling on the plot\n", - " vmax : float\n", - " maximum head value for color scaling on the plot\n", - " \"\"\"\n", - "\n", - " def __init__(self, layer, vmin, vmax):\n", - " self.modelgrid = None\n", - " self.ax = None\n", - " self.pmv = None\n", - " self.pc = None\n", - " self.ax = None\n", - " self.layer = layer\n", - " self.vmin = vmin\n", - " self.vmax = vmax\n", - " self.kperold = None\n", - "\n", - " def build_modelgrid(self, ml):\n", - " \"\"\"\n", - " Method to update the matplotlib plot\n", - " \n", - " Parameters\n", - " ----------\n", - " ml : ApiModel\n", - " modflow-api ApiModel object\n", - " \"\"\"\n", - " delc = ml.dis.get_advanced_var(\"delc\")\n", - " delr = ml.dis.get_advanced_var(\"delr\")\n", - " top = ml.dis.top.values[0]\n", - " botm = ml.dis.bot.values\n", - " idomain = ml.dis.idomain.values\n", - " self.modelgrid = StructuredGrid(\n", - " delc=delc,\n", - " delr=delr,\n", - " top=top,\n", - " botm=botm,\n", - " idomain=idomain\n", - " )\n", - "\n", - " def initialize_plot(self):\n", - " \"\"\"\n", - " Method to initalize a matplotlib plot using flopy\n", - " \"\"\"\n", - " fig, ax = plt.subplots(figsize=(8, 8))\n", - " self.fig = fig\n", - " self.ax = ax\n", - " self.pmv = PlotMapView(modelgrid=self.modelgrid, ax=ax, layer=self.layer)\n", - " grid = self.pmv.plot_grid()\n", - " idm = self.pmv.plot_inactive()\n", - " initial = np.full(self.modelgrid.shape, np.nan)\n", - " self.pc = self.pmv.plot_array(initial, vmin=self.vmin, vmax=self.vmax)\n", - " plt.colorbar(self.pc)\n", - "\n", - " def update_plot(self, ml):\n", - " \"\"\"\n", - " Method to update the matplotlib plot\n", - " \n", - " Parameters\n", - " ----------\n", - " ml : ApiModel\n", - " modflow-api ApiModel object\n", - " \"\"\"\n", - " heads = ml.X\n", - " self.ax.cla()\n", - " grid = self.pmv.plot_grid()\n", - " idm = self.pmv.plot_inactive()\n", - " self.pc = self.pmv.plot_array(heads, vmin=self.vmin, vmax=self.vmax)\n", - " \n", - " # only applicable to jupyter notebooks, remove these two lines in python scipt\n", - " display(self.fig) \n", - " if ml.kper == (ml.nper - 1) and ml.kstp == (ml.nstp - 1):\n", - " pass\n", - " else:\n", - " clear_output(wait = True) \n", - " \n", - " # the pause time can be reduced if adapted in python script \n", - " plt.pause(0.1) \n", - "\n", - " def callback(self, sim, callback_step):\n", - " \"\"\"\n", - " A demonstration function that dynamically adjusts the CHD\n", - " boundary conditions each stress period in a modflow-6 model\n", - " through the MODFLOW-API and then updates heads on a matplotlib\n", - " plot for each timestep.\n", - "\n", - " Parameters\n", - " ----------\n", - " sim : modflowapi.Simulation\n", - " A simulation object for the solution group that is \n", - " currently being solved\n", - " callback_step : enumeration\n", - " modflowapi.Callbacks enumeration object that indicates\n", - " the part of the solution modflow is currently in.\n", - " \"\"\"\n", - " if callback_step == Callbacks.initialize:\n", - " ml = sim.get_model()\n", - " self.build_modelgrid(ml)\n", - " self.initialize_plot()\n", - "\n", - " if callback_step == Callbacks.timestep_start:\n", - " ml = sim.get_model()\n", - " if ml.kper == 0:\n", - " self.kperold = ml.kper\n", - " head = ml.chd.stress_period_data.dataframe[\"head\"].values\n", - " self.head = head\n", - " else:\n", - " df = ml.chd.stress_period_data.dataframe\n", - " if self.kperold != ml.kper:\n", - " self.kperold = ml.kper\n", - " self.head = self.head[::-1]\n", - "\n", - " df[\"head\"] = self.head\n", - " ml.chd.stress_period_data.dataframe = df\n", - "\n", - " if callback_step == Callbacks.timestep_end:\n", - " ml = sim.get_model()\n", - " self.update_plot(ml)\n" - ] - }, - { - "cell_type": "markdown", - "id": "ef5cf1d9", - "metadata": {}, - "source": [ - "Run the model using the and supply the `StructuredHeadMonitor`'s `callback` function" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "f2902aff", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Solving: Stress Period 12; Timestep 31\n" - ] - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "NORMAL TERMINATION OF SIMULATION\n" - ] - } - ], - "source": [ - "hdmon = StructuredHeadMonitor(layer=0, vmin=70, vmax=95)\n", - "dll = \"libmf6\"\n", - "sim_ws = Path(\"../data/dis_model\")\n", - "run_simulation(dll, sim_ws, hdmon.callback, verbose=True)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6ba6ce60", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "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.9.12" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/examples/notebooks/MODFLOW-API extensions objects.ipynb b/examples/notebooks/MODFLOW-API extensions objects.ipynb deleted file mode 100644 index d6637e1..0000000 --- a/examples/notebooks/MODFLOW-API extensions objects.ipynb +++ /dev/null @@ -1,2047 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "5acdb8ec", - "metadata": {}, - "source": [ - "# Interacting with MODFLOW-API Interface objects\n", - "\n", - "The purpose of this notebook is to show the MODFLOW-API interface objects and introduce the user to the data types and how to interact with the objects. \n", - "\n", - "**Note**: This notebook shows how to run a model using the modflow-api at the end of the notebook. However, the majority of the notebook is an illustration of how to access and work with the data types that are returned to a user defined callback function. " - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "4b0e6a93", - "metadata": {}, - "outputs": [], - "source": [ - "import modflowapi\n", - "from modflowapi.extensions import ApiSimulation\n", - "from pathlib import Path\n", - "import platform" - ] - }, - { - "cell_type": "markdown", - "id": "9e654316", - "metadata": {}, - "source": [ - "Define the paths to the model and the Modflow shared library" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "66c0f32c", - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "sim_ws = Path(\"../data/dis_model\")\n", - "dll = \"./libmf6\"\n", - "if platform.system().lower() == \"windows\":\n", - " ext = \".dll\"\n", - "elif platform.system().lower() == \"linux\":\n", - " ext = \".so\"\n", - "else:\n", - " ext = \".dylib\"\n", - " \n", - "dll = Path(dll + ext)" - ] - }, - { - "cell_type": "markdown", - "id": "d258b430", - "metadata": {}, - "source": [ - "#### Initializing the API model object\n", - "\n", - "The modflow api allows users to initialize an object that can be used to interact with the model. This processes is done automatically with the `modflowapi.run_model` function call. We're going to initialize an object outside of that call as a demonstration of the interface data objects" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "9c18c3bf", - "metadata": {}, - "outputs": [], - "source": [ - "mf6 = modflowapi.ModflowApi(dll, working_directory=sim_ws)\n", - "mf6.initialize()\n", - "\n", - "# let's advance the model to the first timestep\n", - "dt = mf6.get_time_step()\n", - "mf6.prepare_time_step(dt)" - ] - }, - { - "cell_type": "markdown", - "id": "424925fc", - "metadata": {}, - "source": [ - "## The `ApiSimulation` object \n", - "\n", - "The `ApiSimulation` object is the top level container for the modflowapi interface classes. This container holds methods and other objects that allow the user to access boundary condition pointer data without assembling the specific memory addresses of the modflow data. \n", - "\n", - "Let's take a look at the `ApiSimulation` object" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "b0e83b86", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "\n", - " ApiSimulation object that holds a modflow simulation info and loads\n", - " supported models.\n", - "\n", - " Parameters\n", - " ----------\n", - " mf6 : ModflowApi\n", - " initialized ModflowApi object\n", - " models : dict\n", - " dictionary of model_name: modflowapi.extensions.ApiModel objects\n", - " solutions : dict\n", - " dictionary of solution_id: solution_name\n", - " exchanges : dict\n", - " dictoinary of exchange_name: modflowapi.extensions.ApiExchange objects\n", - " tdis : ApiTdisPackage\n", - " time discretization (TDIS) ScalarPackage\n", - " ats : None or ApiAtsPackage\n", - " adaptive time step ScalarPackage object\n", - " Number of models: 1:\n", - "\ttest_model : \n", - "Simulation level packages include:\n", - "\tSLN: SLN Package: SLN_1 \n", - " Accessible variables include:\n", - " akappa \n", - " amomentum \n", - " breduc \n", - " btol \n", - " droptol \n", - " dvclose \n", - " gamma \n", - " ims_dvclose \n", - " iord \n", - " ipc \n", - " iscl \n", - " mxiter \n", - " niterc \n", - " north \n", - " numtrack \n", - " rclose \n", - " relax \n", - " res_lim \n", - " theta \n", - "\n", - "\tTDIS: TDIS Package: TDIS \n", - " Accessible variables include:\n", - " delt \n", - " itmuni \n", - " kper \n", - " kstp \n", - " nper \n", - " nstp \n", - " perlen \n", - " pertim \n", - " tsmult \n" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sim = ApiSimulation.load(mf6)\n", - "sim" - ] - }, - { - "cell_type": "markdown", - "id": "65030e7d", - "metadata": {}, - "source": [ - "The simulation object allows the user to access models by name and has a number of handy properties and contains simulation level packages such as `sln`, `tdis`, `ats`, and `exchanges`" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "c6930030", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['test_model']" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "mnames = sim.model_names\n", - "mnames" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "327a1c6e", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(0, 0)" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "kstp, kper = sim.kstp, sim.kper\n", - "kstp, kper" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "93c4c417", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "31" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "nstp = sim.nstp\n", - "nstp" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "77c77460", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "SLN Package: SLN_1 \n", - " Accessible variables include:\n", - " akappa \n", - " amomentum \n", - " breduc \n", - " btol \n", - " droptol \n", - " dvclose \n", - " gamma \n", - " ims_dvclose \n", - " iord \n", - " ipc \n", - " iscl \n", - " mxiter \n", - " niterc \n", - " north \n", - " numtrack \n", - " rclose \n", - " relax \n", - " res_lim \n", - " theta " - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "ims = sim.sln\n", - "ims" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "3805e031", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "0.1" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "ims.dvclose" - ] - }, - { - "cell_type": "markdown", - "id": "236d4a25", - "metadata": {}, - "source": [ - "## The `ApiModel` object\n", - "\n", - "`ApiModel` objects are accessed from the `ApiSimulation` object and are a container for packages. These objects allow the user to view which packages are available and access those packages. \n", - "\n", - "The following cells show the main attributes and functions available on the `ApiModel` object" - ] - }, - { - "cell_type": "markdown", - "id": "7e65a3f3", - "metadata": {}, - "source": [ - "Model objects are accessible through the `get_model` function and as attributes on the sim object" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "232c0660", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "TEST_MODEL, 1 Layer, 10 Row, 10 Column model\n", - "Packages accessible include: \n", - " ArrayPackage objects:\n", - " dis: \n", - " npf: \n", - " sto: \n", - " ic: \n", - " ListPackage objects:\n", - " wel_0: \n", - " drn_0: \n", - " rch_0: \n", - " rcha_0: \n", - " evt_0: \n", - " chd_0: \n", - " AdvancedPackage objects:\n", - " buy: \n", - " vsc: \n", - " gnc: \n", - " hfb: \n", - " csub: \n", - " mvr: " - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "model = sim.get_model('test_model')\n", - "model" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "bb9328af", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "TEST_MODEL, 1 Layer, 10 Row, 10 Column model\n", - "Packages accessible include: \n", - " ArrayPackage objects:\n", - " dis: \n", - " npf: \n", - " sto: \n", - " ic: \n", - " ListPackage objects:\n", - " wel_0: \n", - " drn_0: \n", - " rch_0: \n", - " rcha_0: \n", - " evt_0: \n", - " chd_0: \n", - " AdvancedPackage objects:\n", - " buy: \n", - " vsc: \n", - " gnc: \n", - " hfb: \n", - " csub: \n", - " mvr: " - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# approach 2\n", - "model = sim.test_model\n", - "model" - ] - }, - { - "cell_type": "markdown", - "id": "0ddc33e1", - "metadata": {}, - "source": [ - "There are also a number of other functions available including the following:" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "43aaed16", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(1, 10, 10)" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "model.shape" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "07b0b3e2", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "100" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "model.size" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "088578c0", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "model.solution_id" - ] - }, - { - "cell_type": "markdown", - "id": "4eafd365", - "metadata": {}, - "source": [ - "A list of all package names that are accesible is also available" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "eee1f0a5", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['dis',\n", - " 'npf',\n", - " 'buy',\n", - " 'vsc',\n", - " 'gnc',\n", - " 'hfb',\n", - " 'sto',\n", - " 'csub',\n", - " 'ic',\n", - " 'mvr',\n", - " 'wel_0',\n", - " 'drn_0',\n", - " 'rch_0',\n", - " 'rcha_0',\n", - " 'evt_0',\n", - " 'chd_0']" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "model.package_names" - ] - }, - { - "cell_type": "markdown", - "id": "073bb268", - "metadata": {}, - "source": [ - "## The `ApiPackage` object(s)\n", - "\n", - "Each package is contained in `ApiPackage` container. There are three types depending on the input data. We'll access and take a look at each of the types of `ApiPackage` containers." - ] - }, - { - "cell_type": "markdown", - "id": "79ac8066", - "metadata": {}, - "source": [ - "Packages can be accessed from the `Model` object using `get_package()` or by attribute" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "4914c509", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "RCH Package: RCHA_0" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# example 1: get a package using get_package\n", - "rch = model.get_package(\"rcha_0\")\n", - "rch" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "id": "cbc0aadf", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "WEL Package: WEL_0" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# example 2: get a package by package name attribute\n", - "wel = model.wel_0\n", - "wel" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "id": "1a705679", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[RCH Package: RCH_0, RCH Package: RCHA_0]" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# example 3: get all packages based on a package type\n", - "rch_pkgs = model.rch\n", - "rch_pkgs" - ] - }, - { - "cell_type": "markdown", - "id": "8d59405f", - "metadata": {}, - "source": [ - "### `ListPackage` objects\n", - "\n", - "`ListPackage` objects are the primary object type of stress period data. The exception to this rule is the advanced packages which will be discussed later. \n", - "\n", - "`ListPackage` objects allow users to access stress period data as a numpy recarray or as a pandas dataframe." - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "id": "fbc7ed8a", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "rec.array([((0, 9, 7), 1.00000e-03), ((0, 9, 7), 1.00000e-03),\n", - " ((0, 0, 2), 4.04496e+00), ((0, 0, 3), 4.04496e+00),\n", - " ((0, 0, 4), 4.04496e+00), ((0, 0, 5), 4.04496e+00),\n", - " ((0, 0, 6), 4.04496e+00), ((0, 0, 7), 4.04496e+00),\n", - " ((0, 9, 7), 1.00000e-03), ((0, 9, 7), 1.00000e-03)],\n", - " dtype=[('nodelist', 'O'), ('recharge', '\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
nodelistrecharge
0(0, 9, 7)0.00100
1(0, 9, 7)0.00100
2(0, 0, 2)4.04496
3(0, 0, 3)4.04496
4(0, 0, 4)4.04496
\n", - "" - ], - "text/plain": [ - " nodelist recharge\n", - "0 (0, 9, 7) 0.00100\n", - "1 (0, 9, 7) 0.00100\n", - "2 (0, 0, 2) 4.04496\n", - "3 (0, 0, 3) 4.04496\n", - "4 (0, 0, 4) 4.04496" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df = rch.stress_period_data.dataframe\n", - "df.head()" - ] - }, - { - "cell_type": "markdown", - "id": "62faee8b", - "metadata": {}, - "source": [ - "### Updating values for `ListPackage` based data\n", - "\n", - "There are multiple ways to update values for `ListPackage` based data. The `.values` and `.dataframe` attributes can be used, or the object can be directly indexed if the user knows the underlying data. Here are some examples" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "id": "0fecf116", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "rec.array([((0, 9, 7), 1.00000e-01), ((0, 9, 7), 1.00000e-03),\n", - " ((0, 0, 2), 4.04496e+00), ((0, 0, 3), 4.04496e+00),\n", - " ((0, 0, 4), 4.04496e+00)],\n", - " dtype=[('nodelist', 'O'), ('recharge', '\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
nodelistrecharge
0(0, 9, 7)0.10000
1(0, 9, 7)10000.00000
2(0, 0, 2)4.04496
3(0, 0, 3)4.04496
4(0, 0, 4)4.04496
\n", - "" - ], - "text/plain": [ - " nodelist recharge\n", - "0 (0, 9, 7) 0.10000\n", - "1 (0, 9, 7) 10000.00000\n", - "2 (0, 0, 2) 4.04496\n", - "3 (0, 0, 3) 4.04496\n", - "4 (0, 0, 4) 4.04496" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df = rch.stress_period_data.dataframe\n", - "df.loc[1, \"recharge\"] = 10000\n", - "rch.stress_period_data.dataframe = df\n", - "\n", - "# show that values have been updated\n", - "df = rch.stress_period_data.dataframe\n", - "df.head()" - ] - }, - { - "cell_type": "markdown", - "id": "fd85083e", - "metadata": {}, - "source": [ - "#### Interfacing directly with the `.stress_period_data` attribute\n", - "\n", - "The `.stress_period_data` attribute returns a container class that interacts with the internal modflow pointers. The data can be adjusted by interacting with `.stress_period_data` in the same fashion as changing data in a numpy recarray. " - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "id": "c1d21b67", - "metadata": {}, - "outputs": [], - "source": [ - "rch.stress_period_data[\"recharge\"] *= 100" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "id": "0a127471", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
nodelistrecharge
0(0, 9, 7)10.000
1(0, 9, 7)1000000.000
2(0, 0, 2)404.496
3(0, 0, 3)404.496
4(0, 0, 4)404.496
\n", - "
" - ], - "text/plain": [ - " nodelist recharge\n", - "0 (0, 9, 7) 10.000\n", - "1 (0, 9, 7) 1000000.000\n", - "2 (0, 0, 2) 404.496\n", - "3 (0, 0, 3) 404.496\n", - "4 (0, 0, 4) 404.496" - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df = rch.stress_period_data.dataframe\n", - "df.head()" - ] - }, - { - "cell_type": "markdown", - "id": "85f6922c", - "metadata": {}, - "source": [ - "#### Adding or removing a boundary condition\n", - "In list packages the user can add and remove specific boundary conditions. Note: if a user adds a boundary condition, such as another well during a stress period, the total number of wells cannot be greater than the wel package's `maxbound` variable. Here's an example" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "id": "4921081e", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "nbound=3 maxbound=10\n" - ] - } - ], - "source": [ - "wel = model.wel\n", - "maxbound = wel.maxbound\n", - "nbound = wel.nbound\n", - "print(f\"{nbound=}\", f\"{maxbound=}\")" - ] - }, - { - "cell_type": "markdown", - "id": "9639edaf", - "metadata": {}, - "source": [ - "For the current stress period there are two active wells `nbound=2`, but there can be up to ten `maxbound=10`." - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "id": "a9d7ba04", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "rec.array([((0, 5, 4), -150., 1., 2.), ((0, 1, 2), -100., 1., 2.),\n", - " ((0, 3, 5), -50., 1., 2.)],\n", - " dtype=[('nodelist', 'O'), ('flux', '\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
nodelistfluxTEST1TEST2
0(0, 5, 4)-150.01.02.0
1(0, 1, 2)-100.01.02.0
2(0, 3, 5)-50.01.02.0
3(0, 1, 5)-20.00.01.0
\n", - "" - ], - "text/plain": [ - " nodelist flux TEST1 TEST2\n", - "0 (0, 5, 4) -150.0 1.0 2.0\n", - "1 (0, 1, 2) -100.0 1.0 2.0\n", - "2 (0, 3, 5) -50.0 1.0 2.0\n", - "3 (0, 1, 5) -20.0 0.0 1.0" - ] - }, - "execution_count": 29, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "wel.stress_period_data.dataframe" - ] - }, - { - "cell_type": "markdown", - "id": "42b72baa", - "metadata": {}, - "source": [ - "### `ArrayPackage` objects\n", - "\n", - "The `ArrayPackage` class is used as a container for packages such as `DIS`, `NPF`, and `IC` that do not contain any sort of stress period data. These packages are used primarily to define model connectivity, initial conditions, and hydraulic parameters of the basin. " - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "id": "e9939cae", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "NPF Package: NPF \n", - " Accessible variables include:\n", - " angle1 \n", - " angle2 \n", - " angle3 \n", - " icelltype \n", - " k11 \n", - " k22 \n", - " k33 " - ] - }, - "execution_count": 30, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "npf = model.npf\n", - "npf" - ] - }, - { - "cell_type": "markdown", - "id": "f55215ba", - "metadata": {}, - "source": [ - "For an `ArrayPackage` type object, variable names can be viewed by calling the `.variable_names` property" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "id": "df4e7242", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['angle1', 'angle2', 'angle3', 'icelltype', 'k11', 'k22', 'k33']" - ] - }, - "execution_count": 31, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "npf.variable_names" - ] - }, - { - "cell_type": "markdown", - "id": "93c2006e", - "metadata": {}, - "source": [ - "### Updating values for `ArrayPackage` objects\n", - "\n", - "Two methods are available for accessing and updating data in `ArrayPackage` objects. `get_array()` and `set_array()` methods can be used to get and set data. Arrays can also be accessed as attributes on the object." - ] - }, - { - "cell_type": "markdown", - "id": "0f408dff", - "metadata": {}, - "source": [ - "Using `get_array()` and `set_array()`" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "id": "0d202974", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[[nan, nan, 1., 1., 1., 1., 1., 1., nan, nan],\n", - " [nan, 1., 1., 1., 1., 1., 1., 1., 1., nan],\n", - " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", - " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", - " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", - " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", - " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", - " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", - " [nan, 1., 1., 1., 1., 1., 1., 1., 1., nan],\n", - " [nan, nan, 1., 1., 1., 1., 1., 1., nan, nan]]])" - ] - }, - "execution_count": 32, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "hk = npf.get_array(\"k11\")\n", - "hk" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "id": "17ce597b", - "metadata": {}, - "outputs": [], - "source": [ - "hk[0, 0:5, 0:5] = 50\n", - "npf.set_array(\"k11\", hk)" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "id": "2ed869a9", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[[nan, nan, 50., 50., 50., 1., 1., 1., nan, nan],\n", - " [nan, 50., 50., 50., 50., 1., 1., 1., 1., nan],\n", - " [50., 50., 50., 50., 50., 1., 1., 1., 1., 1.],\n", - " [50., 50., 50., 50., 50., 1., 1., 1., 1., 1.],\n", - " [50., 50., 50., 50., 50., 1., 1., 1., 1., 1.],\n", - " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", - " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", - " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", - " [nan, 1., 1., 1., 1., 1., 1., 1., 1., nan],\n", - " [nan, nan, 1., 1., 1., 1., 1., 1., nan, nan]]])" - ] - }, - "execution_count": 34, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# confirm that the data has been updated\n", - "hk = npf.get_array(\"k11\")\n", - "hk" - ] - }, - { - "cell_type": "markdown", - "id": "7bdbdb1e", - "metadata": {}, - "source": [ - "Getting and setting data by attribute" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "id": "2b589b5f", - "metadata": {}, - "outputs": [], - "source": [ - "# needs an update for inplace operations....\n", - "npf.k33[0, 0:5, 0:5] = 5" - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "id": "38e79b05", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[[nan, nan, 5., 5., 5., 1., 1., 1., nan, nan],\n", - " [nan, 5., 5., 5., 5., 1., 1., 1., 1., nan],\n", - " [ 5., 5., 5., 5., 5., 1., 1., 1., 1., 1.],\n", - " [ 5., 5., 5., 5., 5., 1., 1., 1., 1., 1.],\n", - " [ 5., 5., 5., 5., 5., 1., 1., 1., 1., 1.],\n", - " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", - " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", - " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", - " [nan, 1., 1., 1., 1., 1., 1., 1., 1., nan],\n", - " [nan, nan, 1., 1., 1., 1., 1., 1., nan, nan]]])" - ] - }, - "execution_count": 36, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# confirm that the data has been updated\n", - "npf.k33.values" - ] - }, - { - "cell_type": "markdown", - "id": "f245911d", - "metadata": {}, - "source": [ - "## Accessing \"advanced variables\"\n", - "\n", - "Advanced variables in this context are variables that would not normally need to be accessed by the user, and in many cases changes to these variables would cause the Modflow simulation to do unexpected things. " - ] - }, - { - "cell_type": "markdown", - "id": "ff9a706b", - "metadata": {}, - "source": [ - "For each package object a list of avanced variables can be returned by calling the `advanced_vars` attribute" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "id": "4c943166", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['package_type',\n", - " 'id',\n", - " 'inunit',\n", - " 'iout',\n", - " 'inewton',\n", - " 'iasym',\n", - " 'iprpak',\n", - " 'iprflow',\n", - " 'ipakcb',\n", - " 'ionper',\n", - " 'lastonper',\n", - " 'listlabel',\n", - " 'isadvpak',\n", - " 'ibcnum',\n", - " 'ncolbnd',\n", - " 'iscloc',\n", - " 'inamedbound',\n", - " 'iauxmultcol',\n", - " 'inobspkg',\n", - " 'imover',\n", - " 'ivsc',\n", - " 'npakeq',\n", - " 'ioffset',\n", - " 'auxname',\n", - " 'iflowred',\n", - " 'flowred',\n", - " 'ioutafrcsv',\n", - " 'noupdateauxvar',\n", - " 'bound',\n", - " 'condinput',\n", - " 'hcof',\n", - " 'rhs',\n", - " 'simvals',\n", - " 'simtomvr',\n", - " 'boundname',\n", - " 'boundname_cst']" - ] - }, - "execution_count": 37, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "wel = model.wel_0\n", - "wel.advanced_vars" - ] - }, - { - "cell_type": "markdown", - "id": "dcd0e792", - "metadata": {}, - "source": [ - "The user can access and change these values, _at their own risk_, using the `.get_advanced_var()` and `.set_advanced_var()` methods. Data is returned to the user in the internal modflowapi structure. " - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "id": "5a8ee821", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([1])" - ] - }, - "execution_count": 38, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "wel.get_advanced_var(\"ibcnum\")" - ] - }, - { - "cell_type": "markdown", - "id": "b034954d", - "metadata": {}, - "source": [ - "### Advanced Packages\n", - "\n", - "Certain packages only support accessing data through the `.get_advanced_var()` and `.set_advanced_var()` methods. These packages, are sometimes refered to as \"advanced packages\" and include: BUY, CSUB, GNC, HFB, MAW, MVR, SFR, and UZF. " - ] - }, - { - "cell_type": "markdown", - "id": "2e2d960a", - "metadata": {}, - "source": [ - "-------" - ] - }, - { - "cell_type": "markdown", - "id": "853b6390", - "metadata": {}, - "source": [ - "Let's close the existing modflowapi shared library object and look at an example of how this is all used in practice" - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "id": "6896d260", - "metadata": {}, - "outputs": [], - "source": [ - "mf6.finalize()" - ] - }, - { - "cell_type": "markdown", - "id": "27d3baa1", - "metadata": {}, - "source": [ - "# Putting it all together and running a modflowapi simulation\n", - "\n", - "To run a simulation using the built in modflowapi runner the user needs to create a function that will receive callbacks at different steps in the simulation run. For the remainder of this notebook, we'll show how to create a callback function and use it with the `modflowapi.run_simulation()` method." - ] - }, - { - "cell_type": "markdown", - "id": "4404b2c2", - "metadata": {}, - "source": [ - "## Create a callback function for adjusting model data\n", - "\n", - "The callback function allows users to wrap function that updates the modflow model at different steps. The `modflowapi.Callbacks` object allows users to find the particular solution step that they are currently in. `modflowapi.Callbacks` includes:\n", - "\n", - " - `Callbacks.initalize`: the initialize callback sends loaded simulation data back to the user to make adjustments before the model begins solving. This callback only occurs once at the beginning of the MODFLOW6 simulation\n", - " - `Callbacks.stress_period_start`: the stress_period_start callback sends simulation data for each solution group to the user to make adjustments to stress packages at the beginning of each stress period.\n", - " - `Callbacks.stress_period_end`: the stress_period_end callback sends simulation data for each solution group to the user at the end of each stress period. This can be useful for writing custom output and coupling models\n", - " - `Callbacks.timestep_start`: the timestep_start callback sends simulation data for each solution group to the user to make adjustments to stress packages at the beginning of each timestep.\n", - " - `Callbacks.timestep_end`: the timestep_end callback sends simulation data for each solution group to the user at the end of each timestep. This can be useful for writing custom output and coupling models\n", - " - `Callbacks.iteration_start`: the iteration_start callback sends simulation data for each solution group to the user to make adjustments to stress packages at the beginning of each outer solution iteration.\n", - " - `Callbacks.iteration_end`: the iteration_end callback sends simulation data for each solution group to the user to make adjustments to stress packages and check values of stress packages at the end of each outer solution iteration.\n", - " - `Callbacks.finalize`: the finalize callback is useful for finalizing models coupled with the modflowapi.\n", - " \n", - "The user can use any or all of these callbacks within their callback function" - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "id": "c2783828", - "metadata": {}, - "outputs": [], - "source": [ - "from modflowapi import Callbacks" - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "id": "395327da", - "metadata": {}, - "outputs": [], - "source": [ - "def callback_function(sim, callback_step):\n", - " \"\"\"\n", - " A demonstration function that dynamically adjusts recharge\n", - " and pumping in a modflow-6 model through the MODFLOW-API\n", - " \n", - " Parameters\n", - " ----------\n", - " sim : modflowapi.Simulation\n", - " A simulation object for the solution group that is \n", - " currently being solved\n", - " callback_step : enumeration\n", - " modflowapi.Callbacks enumeration object that indicates\n", - " the part of the solution modflow is currently in.\n", - " \"\"\"\n", - " ml = sim.test_model\n", - " if callback_step == Callbacks.initialize:\n", - " print(sim.models)\n", - " \n", - " if callback_step == Callbacks.stress_period_start:\n", - " # adjust recharge for stress periods 1 through 7\n", - " if sim.kper <= 6:\n", - " rcha = ml.rcha_0\n", - " spd = rcha.stress_period_data\n", - " print(f\"updating recharge: stress_period={ml.kper}\")\n", - " spd[\"recharge\"] += 0.40 * sim.kper\n", - " \n", - " \n", - " if callback_step == Callbacks.timestep_start:\n", - " print(f\"updating wel flux: stress_period={ml.kper}, timestep={ml.kstp}\")\n", - " ml.wel.stress_period_data[\"flux\"] -= ml.kstp * 1.5\n", - " \n", - " if callback_step == Callbacks.iteration_start:\n", - " # we can implement complex solutions to boundary conditions here!\n", - " pass\n", - " " - ] - }, - { - "cell_type": "markdown", - "id": "b751eb41", - "metadata": {}, - "source": [ - "The callback function is then passed to `modflowapi.run_simulation`" - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "id": "0878e5b6", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[TEST_MODEL, 1 Layer, 10 Row, 10 Column model\n", - "Packages accessible include: \n", - " ArrayPackage objects:\n", - " dis: \n", - " npf: \n", - " sto: \n", - " ic: \n", - " ListPackage objects:\n", - " wel_0: \n", - " drn_0: \n", - " rch_0: \n", - " rcha_0: \n", - " evt_0: \n", - " chd_0: \n", - " AdvancedPackage objects:\n", - " buy: \n", - " vsc: \n", - " gnc: \n", - " hfb: \n", - " csub: \n", - " mvr: \n", - "]\n", - "updating recharge: stress_period=0\n", - "updating wel flux: stress_period=0, timestep=0\n", - "updating wel flux: stress_period=0, timestep=1\n", - "updating wel flux: stress_period=0, timestep=2\n", - "updating wel flux: stress_period=0, timestep=3\n", - "updating wel flux: stress_period=0, timestep=4\n", - "updating wel flux: stress_period=0, timestep=5\n", - "updating wel flux: stress_period=0, timestep=6\n", - "updating wel flux: stress_period=0, timestep=7\n", - "updating wel flux: stress_period=0, timestep=8\n", - "updating wel flux: stress_period=0, timestep=9\n", - "updating wel flux: stress_period=0, timestep=10\n", - "updating wel flux: stress_period=0, timestep=11\n", - "updating wel flux: stress_period=0, timestep=12\n", - "updating wel flux: stress_period=0, timestep=13\n", - "updating wel flux: stress_period=0, timestep=14\n", - "updating wel flux: stress_period=0, timestep=15\n", - "updating wel flux: stress_period=0, timestep=16\n", - "updating wel flux: stress_period=0, timestep=17\n", - "updating wel flux: stress_period=0, timestep=18\n", - "updating wel flux: stress_period=0, timestep=19\n", - "updating wel flux: stress_period=0, timestep=20\n", - "updating wel flux: stress_period=0, timestep=21\n", - "updating wel flux: stress_period=0, timestep=22\n", - "updating wel flux: stress_period=0, timestep=23\n", - "updating wel flux: stress_period=0, timestep=24\n", - "updating wel flux: stress_period=0, timestep=25\n", - "updating wel flux: stress_period=0, timestep=26\n", - "updating wel flux: stress_period=0, timestep=27\n", - "updating wel flux: stress_period=0, timestep=28\n", - "updating wel flux: stress_period=0, timestep=29\n", - "updating wel flux: stress_period=0, timestep=30\n", - "updating recharge: stress_period=1\n", - "updating wel flux: stress_period=1, timestep=0\n", - "updating wel flux: stress_period=1, timestep=1\n", - "updating wel flux: stress_period=1, timestep=2\n", - "updating wel flux: stress_period=1, timestep=3\n", - "updating wel flux: stress_period=1, timestep=4\n", - "updating wel flux: stress_period=1, timestep=5\n", - "updating wel flux: stress_period=1, timestep=6\n", - "updating wel flux: stress_period=1, timestep=7\n", - "updating wel flux: stress_period=1, timestep=8\n", - "updating wel flux: stress_period=1, timestep=9\n", - "updating wel flux: stress_period=1, timestep=10\n", - "updating wel flux: stress_period=1, timestep=11\n", - "updating wel flux: stress_period=1, timestep=12\n", - "updating wel flux: stress_period=1, timestep=13\n", - "updating wel flux: stress_period=1, timestep=14\n", - "updating wel flux: stress_period=1, timestep=15\n", - "updating wel flux: stress_period=1, timestep=16\n", - "updating wel flux: stress_period=1, timestep=17\n", - "updating wel flux: stress_period=1, timestep=18\n", - "updating wel flux: stress_period=1, timestep=19\n", - "updating wel flux: stress_period=1, timestep=20\n", - "updating wel flux: stress_period=1, timestep=21\n", - "updating wel flux: stress_period=1, timestep=22\n", - "updating wel flux: stress_period=1, timestep=23\n", - "updating wel flux: stress_period=1, timestep=24\n", - "updating wel flux: stress_period=1, timestep=25\n", - "updating wel flux: stress_period=1, timestep=26\n", - "updating wel flux: stress_period=1, timestep=27\n", - "updating recharge: stress_period=2\n", - "updating wel flux: stress_period=2, timestep=0\n", - "updating wel flux: stress_period=2, timestep=1\n", - "updating wel flux: stress_period=2, timestep=2\n", - "updating wel flux: stress_period=2, timestep=3\n", - "updating wel flux: stress_period=2, timestep=4\n", - "updating wel flux: stress_period=2, timestep=5\n", - "updating wel flux: stress_period=2, timestep=6\n", - "updating wel flux: stress_period=2, timestep=7\n", - "updating wel flux: stress_period=2, timestep=8\n", - "updating wel flux: stress_period=2, timestep=9\n", - "updating wel flux: stress_period=2, timestep=10\n", - "updating wel flux: stress_period=2, timestep=11\n", - "updating wel flux: stress_period=2, timestep=12\n", - "updating wel flux: stress_period=2, timestep=13\n", - "updating wel flux: stress_period=2, timestep=14\n", - "updating wel flux: stress_period=2, timestep=15\n", - "updating wel flux: stress_period=2, timestep=16\n", - "updating wel flux: stress_period=2, timestep=17\n", - "updating wel flux: stress_period=2, timestep=18\n", - "updating wel flux: stress_period=2, timestep=19\n", - "updating wel flux: stress_period=2, timestep=20\n", - "updating wel flux: stress_period=2, timestep=21\n", - "updating wel flux: stress_period=2, timestep=22\n", - "updating wel flux: stress_period=2, timestep=23\n", - "updating wel flux: stress_period=2, timestep=24\n", - "updating wel flux: stress_period=2, timestep=25\n", - "updating wel flux: stress_period=2, timestep=26\n", - "updating wel flux: stress_period=2, timestep=27\n", - "updating wel flux: stress_period=2, timestep=28\n", - "updating wel flux: stress_period=2, timestep=29\n", - "updating wel flux: stress_period=2, timestep=30\n", - "updating recharge: stress_period=3\n", - "updating wel flux: stress_period=3, timestep=0\n", - "updating wel flux: stress_period=3, timestep=1\n", - "updating wel flux: stress_period=3, timestep=2\n", - "updating wel flux: stress_period=3, timestep=3\n", - "updating wel flux: stress_period=3, timestep=4\n", - "updating wel flux: stress_period=3, timestep=5\n", - "updating wel flux: stress_period=3, timestep=6\n", - "updating wel flux: stress_period=3, timestep=7\n", - "updating wel flux: stress_period=3, timestep=8\n", - "updating wel flux: stress_period=3, timestep=9\n", - "updating wel flux: stress_period=3, timestep=10\n", - "updating wel flux: stress_period=3, timestep=11\n", - "updating wel flux: stress_period=3, timestep=12\n", - "updating wel flux: stress_period=3, timestep=13\n", - "updating wel flux: stress_period=3, timestep=14\n", - "updating wel flux: stress_period=3, timestep=15\n", - "updating wel flux: stress_period=3, timestep=16\n", - "updating wel flux: stress_period=3, timestep=17\n", - "updating wel flux: stress_period=3, timestep=18\n", - "updating wel flux: stress_period=3, timestep=19\n", - "updating wel flux: stress_period=3, timestep=20\n", - "updating wel flux: stress_period=3, timestep=21\n", - "updating wel flux: stress_period=3, timestep=22\n", - "updating wel flux: stress_period=3, timestep=23\n", - "updating wel flux: stress_period=3, timestep=24\n", - "updating wel flux: stress_period=3, timestep=25\n", - "updating wel flux: stress_period=3, timestep=26\n", - "updating wel flux: stress_period=3, timestep=27\n", - "updating wel flux: stress_period=3, timestep=28\n", - "updating wel flux: stress_period=3, timestep=29\n", - "updating recharge: stress_period=4\n", - "updating wel flux: stress_period=4, timestep=0\n", - "updating wel flux: stress_period=4, timestep=1\n", - "updating wel flux: stress_period=4, timestep=2\n", - "updating wel flux: stress_period=4, timestep=3\n", - "updating wel flux: stress_period=4, timestep=4\n", - "updating wel flux: stress_period=4, timestep=5\n", - "updating wel flux: stress_period=4, timestep=6\n", - "updating wel flux: stress_period=4, timestep=7\n", - "updating wel flux: stress_period=4, timestep=8\n", - "updating wel flux: stress_period=4, timestep=9\n", - "updating wel flux: stress_period=4, timestep=10\n", - "updating wel flux: stress_period=4, timestep=11\n", - "updating wel flux: stress_period=4, timestep=12\n", - "updating wel flux: stress_period=4, timestep=13\n", - "updating wel flux: stress_period=4, timestep=14\n", - "updating wel flux: stress_period=4, timestep=15\n", - "updating wel flux: stress_period=4, timestep=16\n", - "updating wel flux: stress_period=4, timestep=17\n", - "updating wel flux: stress_period=4, timestep=18\n", - "updating wel flux: stress_period=4, timestep=19\n", - "updating wel flux: stress_period=4, timestep=20\n", - "updating wel flux: stress_period=4, timestep=21\n", - "updating wel flux: stress_period=4, timestep=22\n", - "updating wel flux: stress_period=4, timestep=23\n", - "updating wel flux: stress_period=4, timestep=24\n", - "updating wel flux: stress_period=4, timestep=25\n", - "updating wel flux: stress_period=4, timestep=26\n", - "updating wel flux: stress_period=4, timestep=27\n", - "updating wel flux: stress_period=4, timestep=28\n", - "updating wel flux: stress_period=4, timestep=29\n", - "updating wel flux: stress_period=4, timestep=30\n", - "updating recharge: stress_period=5\n", - "updating wel flux: stress_period=5, timestep=0\n", - "updating wel flux: stress_period=5, timestep=1\n", - "updating wel flux: stress_period=5, timestep=2\n", - "updating wel flux: stress_period=5, timestep=3\n", - "updating wel flux: stress_period=5, timestep=4\n", - "updating wel flux: stress_period=5, timestep=5\n", - "updating wel flux: stress_period=5, timestep=6\n", - "updating wel flux: stress_period=5, timestep=7\n", - "updating wel flux: stress_period=5, timestep=8\n", - "updating wel flux: stress_period=5, timestep=9\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "updating wel flux: stress_period=5, timestep=10\n", - "updating wel flux: stress_period=5, timestep=11\n", - "updating wel flux: stress_period=5, timestep=12\n", - "updating wel flux: stress_period=5, timestep=13\n", - "updating wel flux: stress_period=5, timestep=14\n", - "updating wel flux: stress_period=5, timestep=15\n", - "updating wel flux: stress_period=5, timestep=16\n", - "updating wel flux: stress_period=5, timestep=17\n", - "updating wel flux: stress_period=5, timestep=18\n", - "updating wel flux: stress_period=5, timestep=19\n", - "updating wel flux: stress_period=5, timestep=20\n", - "updating wel flux: stress_period=5, timestep=21\n", - "updating wel flux: stress_period=5, timestep=22\n", - "updating wel flux: stress_period=5, timestep=23\n", - "updating wel flux: stress_period=5, timestep=24\n", - "updating wel flux: stress_period=5, timestep=25\n", - "updating wel flux: stress_period=5, timestep=26\n", - "updating wel flux: stress_period=5, timestep=27\n", - "updating wel flux: stress_period=5, timestep=28\n", - "updating wel flux: stress_period=5, timestep=29\n", - "updating recharge: stress_period=6\n", - "updating wel flux: stress_period=6, timestep=0\n", - "updating wel flux: stress_period=6, timestep=1\n", - "updating wel flux: stress_period=6, timestep=2\n", - "updating wel flux: stress_period=6, timestep=3\n", - "updating wel flux: stress_period=6, timestep=4\n", - "updating wel flux: stress_period=6, timestep=5\n", - "updating wel flux: stress_period=6, timestep=6\n", - "updating wel flux: stress_period=6, timestep=7\n", - "updating wel flux: stress_period=6, timestep=8\n", - "updating wel flux: stress_period=6, timestep=9\n", - "updating wel flux: stress_period=6, timestep=10\n", - "updating wel flux: stress_period=6, timestep=11\n", - "updating wel flux: stress_period=6, timestep=12\n", - "updating wel flux: stress_period=6, timestep=13\n", - "updating wel flux: stress_period=6, timestep=14\n", - "updating wel flux: stress_period=6, timestep=15\n", - "updating wel flux: stress_period=6, timestep=16\n", - "updating wel flux: stress_period=6, timestep=17\n", - "updating wel flux: stress_period=6, timestep=18\n", - "updating wel flux: stress_period=6, timestep=19\n", - "updating wel flux: stress_period=6, timestep=20\n", - "updating wel flux: stress_period=6, timestep=21\n", - "updating wel flux: stress_period=6, timestep=22\n", - "updating wel flux: stress_period=6, timestep=23\n", - "updating wel flux: stress_period=6, timestep=24\n", - "updating wel flux: stress_period=6, timestep=25\n", - "updating wel flux: stress_period=6, timestep=26\n", - "updating wel flux: stress_period=6, timestep=27\n", - "updating wel flux: stress_period=6, timestep=28\n", - "updating wel flux: stress_period=6, timestep=29\n", - "updating wel flux: stress_period=6, timestep=30\n", - "updating wel flux: stress_period=7, timestep=0\n", - "updating wel flux: stress_period=7, timestep=1\n", - "updating wel flux: stress_period=7, timestep=2\n", - "updating wel flux: stress_period=7, timestep=3\n", - "updating wel flux: stress_period=7, timestep=4\n", - "updating wel flux: stress_period=7, timestep=5\n", - "updating wel flux: stress_period=7, timestep=6\n", - "updating wel flux: stress_period=7, timestep=7\n", - "updating wel flux: stress_period=7, timestep=8\n", - "updating wel flux: stress_period=7, timestep=9\n", - "updating wel flux: stress_period=7, timestep=10\n", - "updating wel flux: stress_period=7, timestep=11\n", - "updating wel flux: stress_period=7, timestep=12\n", - "updating wel flux: stress_period=7, timestep=13\n", - "updating wel flux: stress_period=7, timestep=14\n", - "updating wel flux: stress_period=7, timestep=15\n", - "updating wel flux: stress_period=7, timestep=16\n", - "updating wel flux: stress_period=7, timestep=17\n", - "updating wel flux: stress_period=7, timestep=18\n", - "updating wel flux: stress_period=7, timestep=19\n", - "updating wel flux: stress_period=7, timestep=20\n", - "updating wel flux: stress_period=7, timestep=21\n", - "updating wel flux: stress_period=7, timestep=22\n", - "updating wel flux: stress_period=7, timestep=23\n", - "updating wel flux: stress_period=7, timestep=24\n", - "updating wel flux: stress_period=7, timestep=25\n", - "updating wel flux: stress_period=7, timestep=26\n", - "updating wel flux: stress_period=7, timestep=27\n", - "updating wel flux: stress_period=7, timestep=28\n", - "updating wel flux: stress_period=7, timestep=29\n", - "updating wel flux: stress_period=7, timestep=30\n", - "updating wel flux: stress_period=8, timestep=0\n", - "updating wel flux: stress_period=8, timestep=1\n", - "updating wel flux: stress_period=8, timestep=2\n", - "updating wel flux: stress_period=8, timestep=3\n", - "updating wel flux: stress_period=8, timestep=4\n", - "updating wel flux: stress_period=8, timestep=5\n", - "updating wel flux: stress_period=8, timestep=6\n", - "updating wel flux: stress_period=8, timestep=7\n", - "updating wel flux: stress_period=8, timestep=8\n", - "updating wel flux: stress_period=8, timestep=9\n", - "updating wel flux: stress_period=8, timestep=10\n", - "updating wel flux: stress_period=8, timestep=11\n", - "updating wel flux: stress_period=8, timestep=12\n", - "updating wel flux: stress_period=8, timestep=13\n", - "updating wel flux: stress_period=8, timestep=14\n", - "updating wel flux: stress_period=8, timestep=15\n", - "updating wel flux: stress_period=8, timestep=16\n", - "updating wel flux: stress_period=8, timestep=17\n", - "updating wel flux: stress_period=8, timestep=18\n", - "updating wel flux: stress_period=8, timestep=19\n", - "updating wel flux: stress_period=8, timestep=20\n", - "updating wel flux: stress_period=8, timestep=21\n", - "updating wel flux: stress_period=8, timestep=22\n", - "updating wel flux: stress_period=8, timestep=23\n", - "updating wel flux: stress_period=8, timestep=24\n", - "updating wel flux: stress_period=8, timestep=25\n", - "updating wel flux: stress_period=8, timestep=26\n", - "updating wel flux: stress_period=8, timestep=27\n", - "updating wel flux: stress_period=8, timestep=28\n", - "updating wel flux: stress_period=8, timestep=29\n", - "updating wel flux: stress_period=9, timestep=0\n", - "updating wel flux: stress_period=9, timestep=1\n", - "updating wel flux: stress_period=9, timestep=2\n", - "updating wel flux: stress_period=9, timestep=3\n", - "updating wel flux: stress_period=9, timestep=4\n", - "updating wel flux: stress_period=9, timestep=5\n", - "updating wel flux: stress_period=9, timestep=6\n", - "updating wel flux: stress_period=9, timestep=7\n", - "updating wel flux: stress_period=9, timestep=8\n", - "updating wel flux: stress_period=9, timestep=9\n", - "updating wel flux: stress_period=9, timestep=10\n", - "updating wel flux: stress_period=9, timestep=11\n", - "updating wel flux: stress_period=9, timestep=12\n", - "updating wel flux: stress_period=9, timestep=13\n", - "updating wel flux: stress_period=9, timestep=14\n", - "updating wel flux: stress_period=9, timestep=15\n", - "updating wel flux: stress_period=9, timestep=16\n", - "updating wel flux: stress_period=9, timestep=17\n", - "updating wel flux: stress_period=9, timestep=18\n", - "updating wel flux: stress_period=9, timestep=19\n", - "updating wel flux: stress_period=9, timestep=20\n", - "updating wel flux: stress_period=9, timestep=21\n", - "updating wel flux: stress_period=9, timestep=22\n", - "updating wel flux: stress_period=9, timestep=23\n", - "updating wel flux: stress_period=9, timestep=24\n", - "updating wel flux: stress_period=9, timestep=25\n", - "updating wel flux: stress_period=9, timestep=26\n", - "updating wel flux: stress_period=9, timestep=27\n", - "updating wel flux: stress_period=9, timestep=28\n", - "updating wel flux: stress_period=9, timestep=29\n", - "updating wel flux: stress_period=9, timestep=30\n", - "updating wel flux: stress_period=10, timestep=0\n", - "updating wel flux: stress_period=10, timestep=1\n", - "updating wel flux: stress_period=10, timestep=2\n", - "updating wel flux: stress_period=10, timestep=3\n", - "updating wel flux: stress_period=10, timestep=4\n", - "updating wel flux: stress_period=10, timestep=5\n", - "updating wel flux: stress_period=10, timestep=6\n", - "updating wel flux: stress_period=10, timestep=7\n", - "updating wel flux: stress_period=10, timestep=8\n", - "updating wel flux: stress_period=10, timestep=9\n", - "updating wel flux: stress_period=10, timestep=10\n", - "updating wel flux: stress_period=10, timestep=11\n", - "updating wel flux: stress_period=10, timestep=12\n", - "updating wel flux: stress_period=10, timestep=13\n", - "updating wel flux: stress_period=10, timestep=14\n", - "updating wel flux: stress_period=10, timestep=15\n", - "updating wel flux: stress_period=10, timestep=16\n", - "updating wel flux: stress_period=10, timestep=17\n", - "updating wel flux: stress_period=10, timestep=18\n", - "updating wel flux: stress_period=10, timestep=19\n", - "updating wel flux: stress_period=10, timestep=20\n", - "updating wel flux: stress_period=10, timestep=21\n", - "updating wel flux: stress_period=10, timestep=22\n", - "updating wel flux: stress_period=10, timestep=23\n", - "updating wel flux: stress_period=10, timestep=24\n", - "updating wel flux: stress_period=10, timestep=25\n", - "updating wel flux: stress_period=10, timestep=26\n", - "updating wel flux: stress_period=10, timestep=27\n", - "updating wel flux: stress_period=10, timestep=28\n", - "updating wel flux: stress_period=10, timestep=29\n", - "updating wel flux: stress_period=11, timestep=0\n", - "updating wel flux: stress_period=11, timestep=1\n", - "updating wel flux: stress_period=11, timestep=2\n", - "updating wel flux: stress_period=11, timestep=3\n", - "updating wel flux: stress_period=11, timestep=4\n", - "updating wel flux: stress_period=11, timestep=5\n", - "updating wel flux: stress_period=11, timestep=6\n", - "updating wel flux: stress_period=11, timestep=7\n", - "updating wel flux: stress_period=11, timestep=8\n", - "updating wel flux: stress_period=11, timestep=9\n", - "updating wel flux: stress_period=11, timestep=10\n", - "updating wel flux: stress_period=11, timestep=11\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "updating wel flux: stress_period=11, timestep=12\n", - "updating wel flux: stress_period=11, timestep=13\n", - "updating wel flux: stress_period=11, timestep=14\n", - "updating wel flux: stress_period=11, timestep=15\n", - "updating wel flux: stress_period=11, timestep=16\n", - "updating wel flux: stress_period=11, timestep=17\n", - "updating wel flux: stress_period=11, timestep=18\n", - "updating wel flux: stress_period=11, timestep=19\n", - "updating wel flux: stress_period=11, timestep=20\n", - "updating wel flux: stress_period=11, timestep=21\n", - "updating wel flux: stress_period=11, timestep=22\n", - "updating wel flux: stress_period=11, timestep=23\n", - "updating wel flux: stress_period=11, timestep=24\n", - "updating wel flux: stress_period=11, timestep=25\n", - "updating wel flux: stress_period=11, timestep=26\n", - "updating wel flux: stress_period=11, timestep=27\n", - "updating wel flux: stress_period=11, timestep=28\n", - "updating wel flux: stress_period=11, timestep=29\n", - "updating wel flux: stress_period=11, timestep=30\n", - "NORMAL TERMINATION OF SIMULATION\n" - ] - } - ], - "source": [ - "modflowapi.run_simulation(dll, sim_ws, callback_function, verbose=False)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "bc1e31af", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "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.9.12" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} From 5a631592f2da57bf1564c263e9602c46e5a5a50c Mon Sep 17 00:00:00 2001 From: Joshua Larsen Date: Tue, 8 Aug 2023 08:57:41 -0700 Subject: [PATCH 19/34] update(_ptr_to_recarray): slice pointers prior to setting data to recarray --- modflowapi/extensions/data.py | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/modflowapi/extensions/data.py b/modflowapi/extensions/data.py index 5449558..5079262 100644 --- a/modflowapi/extensions/data.py +++ b/modflowapi/extensions/data.py @@ -108,21 +108,19 @@ def _ptr_to_recarray(self): return recarray = np.recarray((self._nbound[0],), self._dtype) for name, ptr in self._ptrs.items(): + if name == "auxvar" and self._naux == 0: + continue values = np.copy(ptr) if name in self._boundvars: for ix, nm in enumerate(self.parent._bound_vars): - recarray[nm][0 : self._nbound[0]] = values[ - 0 : self._nbound[0], ix - ] + values = values[0 : self._nbound[0], ix] + recarray[nm][0 : self._nbound[0]] = values elif name == "auxvar": - if self._naux[0] == 0: - continue - else: - for ix in range(self._naux[0]): - nm = self._auxnames[ix] - recarray[nm][0 : self._nbound[0]] = values[ - 0 : self._nbound[0], ix - ] + for ix in range(self._naux[0]): + nm = self._auxnames[ix] + values = values[0 : self._nbound[0], ix] + recarray[nm][0 : self._nbound[0]] = values + elif name == "auxname_cst": pass @@ -135,9 +133,8 @@ def _ptr_to_recarray(self): zip(*np.unravel_index(values, self.parent.model.shape)) ) - recarray[name][0 : self._nbound[0]] = values[ - 0 : self._nbound[0] - ] + values = values[0 : self._nbound[0]] + recarray[name][0 : self._nbound[0]] = values return recarray From 0f159daa012c0524db55dfe390c28677f4dca01c Mon Sep 17 00:00:00 2001 From: Joshua Larsen Date: Tue, 8 Aug 2023 09:09:45 -0700 Subject: [PATCH 20/34] fix _naux check --- modflowapi/extensions/data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modflowapi/extensions/data.py b/modflowapi/extensions/data.py index 5079262..8a5f8b3 100644 --- a/modflowapi/extensions/data.py +++ b/modflowapi/extensions/data.py @@ -108,7 +108,7 @@ def _ptr_to_recarray(self): return recarray = np.recarray((self._nbound[0],), self._dtype) for name, ptr in self._ptrs.items(): - if name == "auxvar" and self._naux == 0: + if name == "auxvar" and self._naux[0] == 0: continue values = np.copy(ptr) if name in self._boundvars: From 8f0ec2fc707f0509eab54c58212d06fa47c9799c Mon Sep 17 00:00:00 2001 From: Joshua Larsen Date: Tue, 8 Aug 2023 09:22:18 -0700 Subject: [PATCH 21/34] fix auxvar and bound variable setting --- modflowapi/extensions/data.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modflowapi/extensions/data.py b/modflowapi/extensions/data.py index 8a5f8b3..4145ccf 100644 --- a/modflowapi/extensions/data.py +++ b/modflowapi/extensions/data.py @@ -113,13 +113,13 @@ def _ptr_to_recarray(self): values = np.copy(ptr) if name in self._boundvars: for ix, nm in enumerate(self.parent._bound_vars): - values = values[0 : self._nbound[0], ix] - recarray[nm][0 : self._nbound[0]] = values + bnd_values = values[0 : self._nbound[0], ix] + recarray[nm][0 : self._nbound[0]] = bnd_values elif name == "auxvar": for ix in range(self._naux[0]): nm = self._auxnames[ix] - values = values[0 : self._nbound[0], ix] - recarray[nm][0 : self._nbound[0]] = values + aux_values = values[0 : self._nbound[0], ix] + recarray[nm][0 : self._nbound[0]] = aux_values elif name == "auxname_cst": pass From c97339d06e7386055e486f6354825ec15cea4638 Mon Sep 17 00:00:00 2001 From: Joshua Larsen Date: Thu, 21 Dec 2023 09:56:32 -0800 Subject: [PATCH 22/34] update(extensions): add support for IDM changes * maintain backward support for "bound" storage in list packages --- examples/notebooks/Head_Monitor_Example.ipynb | 33 +- .../MODFLOW-API_extensions_objects.ipynb | 1361 +---------------- examples/notebooks/Quickstart.ipynb | 16 +- modflowapi/extensions/data.py | 97 +- modflowapi/extensions/pakbase.py | 11 +- 5 files changed, 187 insertions(+), 1331 deletions(-) diff --git a/examples/notebooks/Head_Monitor_Example.ipynb b/examples/notebooks/Head_Monitor_Example.ipynb index 4e800ea..91a2219 100644 --- a/examples/notebooks/Head_Monitor_Example.ipynb +++ b/examples/notebooks/Head_Monitor_Example.ipynb @@ -12,7 +12,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "id": "4526a124", "metadata": {}, "outputs": [], @@ -39,7 +39,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "cdd38b59", "metadata": {}, "outputs": [], @@ -186,35 +186,10 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "f2902aff", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Solving: Stress Period 12; Timestep 31\n" - ] - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "NORMAL TERMINATION OF SIMULATION\n" - ] - } - ], + "outputs": [], "source": [ "hdmon = StructuredHeadMonitor(layer=0, vmin=70, vmax=95)\n", "dll = \"libmf6\"\n", diff --git a/examples/notebooks/MODFLOW-API_extensions_objects.ipynb b/examples/notebooks/MODFLOW-API_extensions_objects.ipynb index d6637e1..87cb991 100644 --- a/examples/notebooks/MODFLOW-API_extensions_objects.ipynb +++ b/examples/notebooks/MODFLOW-API_extensions_objects.ipynb @@ -14,7 +14,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "id": "4b0e6a93", "metadata": {}, "outputs": [], @@ -35,7 +35,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "66c0f32c", "metadata": { "scrolled": true @@ -66,7 +66,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "9c18c3bf", "metadata": {}, "outputs": [], @@ -93,74 +93,10 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "b0e83b86", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "\n", - " ApiSimulation object that holds a modflow simulation info and loads\n", - " supported models.\n", - "\n", - " Parameters\n", - " ----------\n", - " mf6 : ModflowApi\n", - " initialized ModflowApi object\n", - " models : dict\n", - " dictionary of model_name: modflowapi.extensions.ApiModel objects\n", - " solutions : dict\n", - " dictionary of solution_id: solution_name\n", - " exchanges : dict\n", - " dictoinary of exchange_name: modflowapi.extensions.ApiExchange objects\n", - " tdis : ApiTdisPackage\n", - " time discretization (TDIS) ScalarPackage\n", - " ats : None or ApiAtsPackage\n", - " adaptive time step ScalarPackage object\n", - " Number of models: 1:\n", - "\ttest_model : \n", - "Simulation level packages include:\n", - "\tSLN: SLN Package: SLN_1 \n", - " Accessible variables include:\n", - " akappa \n", - " amomentum \n", - " breduc \n", - " btol \n", - " droptol \n", - " dvclose \n", - " gamma \n", - " ims_dvclose \n", - " iord \n", - " ipc \n", - " iscl \n", - " mxiter \n", - " niterc \n", - " north \n", - " numtrack \n", - " rclose \n", - " relax \n", - " res_lim \n", - " theta \n", - "\n", - "\tTDIS: TDIS Package: TDIS \n", - " Accessible variables include:\n", - " delt \n", - " itmuni \n", - " kper \n", - " kstp \n", - " nper \n", - " nstp \n", - " perlen \n", - " pertim \n", - " tsmult \n" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "sim = ApiSimulation.load(mf6)\n", "sim" @@ -176,21 +112,10 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "c6930030", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['test_model']" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "mnames = sim.model_names\n", "mnames" @@ -198,21 +123,10 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "id": "327a1c6e", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(0, 0)" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "kstp, kper = sim.kstp, sim.kper\n", "kstp, kper" @@ -220,21 +134,10 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "id": "93c4c417", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "31" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "nstp = sim.nstp\n", "nstp" @@ -242,41 +145,10 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "id": "77c77460", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "SLN Package: SLN_1 \n", - " Accessible variables include:\n", - " akappa \n", - " amomentum \n", - " breduc \n", - " btol \n", - " droptol \n", - " dvclose \n", - " gamma \n", - " ims_dvclose \n", - " iord \n", - " ipc \n", - " iscl \n", - " mxiter \n", - " niterc \n", - " north \n", - " numtrack \n", - " rclose \n", - " relax \n", - " res_lim \n", - " theta " - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "ims = sim.sln\n", "ims" @@ -284,21 +156,10 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "id": "3805e031", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "0.1" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "ims.dvclose" ] @@ -325,41 +186,10 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "id": "232c0660", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "TEST_MODEL, 1 Layer, 10 Row, 10 Column model\n", - "Packages accessible include: \n", - " ArrayPackage objects:\n", - " dis: \n", - " npf: \n", - " sto: \n", - " ic: \n", - " ListPackage objects:\n", - " wel_0: \n", - " drn_0: \n", - " rch_0: \n", - " rcha_0: \n", - " evt_0: \n", - " chd_0: \n", - " AdvancedPackage objects:\n", - " buy: \n", - " vsc: \n", - " gnc: \n", - " hfb: \n", - " csub: \n", - " mvr: " - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "model = sim.get_model('test_model')\n", "model" @@ -367,41 +197,10 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "id": "bb9328af", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "TEST_MODEL, 1 Layer, 10 Row, 10 Column model\n", - "Packages accessible include: \n", - " ArrayPackage objects:\n", - " dis: \n", - " npf: \n", - " sto: \n", - " ic: \n", - " ListPackage objects:\n", - " wel_0: \n", - " drn_0: \n", - " rch_0: \n", - " rcha_0: \n", - " evt_0: \n", - " chd_0: \n", - " AdvancedPackage objects:\n", - " buy: \n", - " vsc: \n", - " gnc: \n", - " hfb: \n", - " csub: \n", - " mvr: " - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "# approach 2\n", "model = sim.test_model\n", @@ -418,63 +217,30 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "id": "43aaed16", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(1, 10, 10)" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "model.shape" ] }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "id": "07b0b3e2", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "100" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "model.size" ] }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "id": "088578c0", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "model.solution_id" ] @@ -489,36 +255,10 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "id": "eee1f0a5", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['dis',\n", - " 'npf',\n", - " 'buy',\n", - " 'vsc',\n", - " 'gnc',\n", - " 'hfb',\n", - " 'sto',\n", - " 'csub',\n", - " 'ic',\n", - " 'mvr',\n", - " 'wel_0',\n", - " 'drn_0',\n", - " 'rch_0',\n", - " 'rcha_0',\n", - " 'evt_0',\n", - " 'chd_0']" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "model.package_names" ] @@ -543,21 +283,10 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "id": "4914c509", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "RCH Package: RCHA_0" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "# example 1: get a package using get_package\n", "rch = model.get_package(\"rcha_0\")\n", @@ -566,21 +295,10 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": null, "id": "cbc0aadf", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "WEL Package: WEL_0" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "# example 2: get a package by package name attribute\n", "wel = model.wel_0\n", @@ -589,21 +307,10 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": null, "id": "1a705679", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[RCH Package: RCH_0, RCH Package: RCHA_0]" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "# example 3: get all packages based on a package type\n", "rch_pkgs = model.rch\n", @@ -624,26 +331,10 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": null, "id": "fbc7ed8a", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "rec.array([((0, 9, 7), 1.00000e-03), ((0, 9, 7), 1.00000e-03),\n", - " ((0, 0, 2), 4.04496e+00), ((0, 0, 3), 4.04496e+00),\n", - " ((0, 0, 4), 4.04496e+00), ((0, 0, 5), 4.04496e+00),\n", - " ((0, 0, 6), 4.04496e+00), ((0, 0, 7), 4.04496e+00),\n", - " ((0, 9, 7), 1.00000e-03), ((0, 9, 7), 1.00000e-03)],\n", - " dtype=[('nodelist', 'O'), ('recharge', '\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
nodelistrecharge
0(0, 9, 7)0.00100
1(0, 9, 7)0.00100
2(0, 0, 2)4.04496
3(0, 0, 3)4.04496
4(0, 0, 4)4.04496
\n", - "" - ], - "text/plain": [ - " nodelist recharge\n", - "0 (0, 9, 7) 0.00100\n", - "1 (0, 9, 7) 0.00100\n", - "2 (0, 0, 2) 4.04496\n", - "3 (0, 0, 3) 4.04496\n", - "4 (0, 0, 4) 4.04496" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "df = rch.stress_period_data.dataframe\n", "df.head()" @@ -741,24 +363,10 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": null, "id": "0fecf116", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "rec.array([((0, 9, 7), 1.00000e-01), ((0, 9, 7), 1.00000e-03),\n", - " ((0, 0, 2), 4.04496e+00), ((0, 0, 3), 4.04496e+00),\n", - " ((0, 0, 4), 4.04496e+00)],\n", - " dtype=[('nodelist', 'O'), ('recharge', '\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
nodelistrecharge
0(0, 9, 7)0.10000
1(0, 9, 7)10000.00000
2(0, 0, 2)4.04496
3(0, 0, 3)4.04496
4(0, 0, 4)4.04496
\n", - "" - ], - "text/plain": [ - " nodelist recharge\n", - "0 (0, 9, 7) 0.10000\n", - "1 (0, 9, 7) 10000.00000\n", - "2 (0, 0, 2) 4.04496\n", - "3 (0, 0, 3) 4.04496\n", - "4 (0, 0, 4) 4.04496" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "df = rch.stress_period_data.dataframe\n", "df.loc[1, \"recharge\"] = 10000\n", @@ -865,7 +404,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": null, "id": "c1d21b67", "metadata": {}, "outputs": [], @@ -875,79 +414,10 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": null, "id": "0a127471", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
nodelistrecharge
0(0, 9, 7)10.000
1(0, 9, 7)1000000.000
2(0, 0, 2)404.496
3(0, 0, 3)404.496
4(0, 0, 4)404.496
\n", - "
" - ], - "text/plain": [ - " nodelist recharge\n", - "0 (0, 9, 7) 10.000\n", - "1 (0, 9, 7) 1000000.000\n", - "2 (0, 0, 2) 404.496\n", - "3 (0, 0, 3) 404.496\n", - "4 (0, 0, 4) 404.496" - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "df = rch.stress_period_data.dataframe\n", "df.head()" @@ -964,18 +434,10 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": null, "id": "4921081e", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "nbound=3 maxbound=10\n" - ] - } - ], + "outputs": [], "source": [ "wel = model.wel\n", "maxbound = wel.maxbound\n", @@ -993,23 +455,10 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": null, "id": "a9d7ba04", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "rec.array([((0, 5, 4), -150., 1., 2.), ((0, 1, 2), -100., 1., 2.),\n", - " ((0, 3, 5), -50., 1., 2.)],\n", - " dtype=[('nodelist', 'O'), ('flux', '\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
nodelistfluxTEST1TEST2
0(0, 5, 4)-150.01.02.0
1(0, 1, 2)-100.01.02.0
2(0, 3, 5)-50.01.02.0
3(0, 1, 5)-20.00.01.0
\n", - "" - ], - "text/plain": [ - " nodelist flux TEST1 TEST2\n", - "0 (0, 5, 4) -150.0 1.0 2.0\n", - "1 (0, 1, 2) -100.0 1.0 2.0\n", - "2 (0, 3, 5) -50.0 1.0 2.0\n", - "3 (0, 1, 5) -20.0 0.0 1.0" - ] - }, - "execution_count": 29, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "wel.stress_period_data.dataframe" ] @@ -1158,29 +510,10 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": null, "id": "e9939cae", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "NPF Package: NPF \n", - " Accessible variables include:\n", - " angle1 \n", - " angle2 \n", - " angle3 \n", - " icelltype \n", - " k11 \n", - " k22 \n", - " k33 " - ] - }, - "execution_count": 30, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "npf = model.npf\n", "npf" @@ -1196,21 +529,10 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": null, "id": "df4e7242", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['angle1', 'angle2', 'angle3', 'icelltype', 'k11', 'k22', 'k33']" - ] - }, - "execution_count": 31, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "npf.variable_names" ] @@ -1235,30 +557,10 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": null, "id": "0d202974", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[[nan, nan, 1., 1., 1., 1., 1., 1., nan, nan],\n", - " [nan, 1., 1., 1., 1., 1., 1., 1., 1., nan],\n", - " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", - " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", - " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", - " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", - " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", - " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", - " [nan, 1., 1., 1., 1., 1., 1., 1., 1., nan],\n", - " [nan, nan, 1., 1., 1., 1., 1., 1., nan, nan]]])" - ] - }, - "execution_count": 32, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "hk = npf.get_array(\"k11\")\n", "hk" @@ -1266,7 +568,7 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": null, "id": "17ce597b", "metadata": {}, "outputs": [], @@ -1277,30 +579,10 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": null, "id": "2ed869a9", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[[nan, nan, 50., 50., 50., 1., 1., 1., nan, nan],\n", - " [nan, 50., 50., 50., 50., 1., 1., 1., 1., nan],\n", - " [50., 50., 50., 50., 50., 1., 1., 1., 1., 1.],\n", - " [50., 50., 50., 50., 50., 1., 1., 1., 1., 1.],\n", - " [50., 50., 50., 50., 50., 1., 1., 1., 1., 1.],\n", - " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", - " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", - " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", - " [nan, 1., 1., 1., 1., 1., 1., 1., 1., nan],\n", - " [nan, nan, 1., 1., 1., 1., 1., 1., nan, nan]]])" - ] - }, - "execution_count": 34, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "# confirm that the data has been updated\n", "hk = npf.get_array(\"k11\")\n", @@ -1317,7 +599,7 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": null, "id": "2b589b5f", "metadata": {}, "outputs": [], @@ -1328,30 +610,10 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": null, "id": "38e79b05", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[[nan, nan, 5., 5., 5., 1., 1., 1., nan, nan],\n", - " [nan, 5., 5., 5., 5., 1., 1., 1., 1., nan],\n", - " [ 5., 5., 5., 5., 5., 1., 1., 1., 1., 1.],\n", - " [ 5., 5., 5., 5., 5., 1., 1., 1., 1., 1.],\n", - " [ 5., 5., 5., 5., 5., 1., 1., 1., 1., 1.],\n", - " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", - " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", - " [ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", - " [nan, 1., 1., 1., 1., 1., 1., 1., 1., nan],\n", - " [nan, nan, 1., 1., 1., 1., 1., 1., nan, nan]]])" - ] - }, - "execution_count": 36, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "# confirm that the data has been updated\n", "npf.k33.values" @@ -1377,56 +639,10 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": null, "id": "4c943166", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['package_type',\n", - " 'id',\n", - " 'inunit',\n", - " 'iout',\n", - " 'inewton',\n", - " 'iasym',\n", - " 'iprpak',\n", - " 'iprflow',\n", - " 'ipakcb',\n", - " 'ionper',\n", - " 'lastonper',\n", - " 'listlabel',\n", - " 'isadvpak',\n", - " 'ibcnum',\n", - " 'ncolbnd',\n", - " 'iscloc',\n", - " 'inamedbound',\n", - " 'iauxmultcol',\n", - " 'inobspkg',\n", - " 'imover',\n", - " 'ivsc',\n", - " 'npakeq',\n", - " 'ioffset',\n", - " 'auxname',\n", - " 'iflowred',\n", - " 'flowred',\n", - " 'ioutafrcsv',\n", - " 'noupdateauxvar',\n", - " 'bound',\n", - " 'condinput',\n", - " 'hcof',\n", - " 'rhs',\n", - " 'simvals',\n", - " 'simtomvr',\n", - " 'boundname',\n", - " 'boundname_cst']" - ] - }, - "execution_count": 37, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "wel = model.wel_0\n", "wel.advanced_vars" @@ -1442,21 +658,10 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": null, "id": "5a8ee821", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([1])" - ] - }, - "execution_count": 38, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "wel.get_advanced_var(\"ibcnum\")" ] @@ -1489,7 +694,7 @@ }, { "cell_type": "code", - "execution_count": 39, + "execution_count": null, "id": "6896d260", "metadata": {}, "outputs": [], @@ -1530,7 +735,7 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": null, "id": "c2783828", "metadata": {}, "outputs": [], @@ -1540,7 +745,7 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": null, "id": "395327da", "metadata": {}, "outputs": [], @@ -1574,7 +779,7 @@ " \n", " if callback_step == Callbacks.timestep_start:\n", " print(f\"updating wel flux: stress_period={ml.kper}, timestep={ml.kstp}\")\n", - " ml.wel.stress_period_data[\"flux\"] -= ml.kstp * 1.5\n", + " ml.wel.stress_period_data[\"q\"] -= ml.kstp * 1.5\n", " \n", " if callback_step == Callbacks.iteration_start:\n", " # we can implement complex solutions to boundary conditions here!\n", @@ -1592,424 +797,10 @@ }, { "cell_type": "code", - "execution_count": 42, + "execution_count": null, "id": "0878e5b6", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[TEST_MODEL, 1 Layer, 10 Row, 10 Column model\n", - "Packages accessible include: \n", - " ArrayPackage objects:\n", - " dis: \n", - " npf: \n", - " sto: \n", - " ic: \n", - " ListPackage objects:\n", - " wel_0: \n", - " drn_0: \n", - " rch_0: \n", - " rcha_0: \n", - " evt_0: \n", - " chd_0: \n", - " AdvancedPackage objects:\n", - " buy: \n", - " vsc: \n", - " gnc: \n", - " hfb: \n", - " csub: \n", - " mvr: \n", - "]\n", - "updating recharge: stress_period=0\n", - "updating wel flux: stress_period=0, timestep=0\n", - "updating wel flux: stress_period=0, timestep=1\n", - "updating wel flux: stress_period=0, timestep=2\n", - "updating wel flux: stress_period=0, timestep=3\n", - "updating wel flux: stress_period=0, timestep=4\n", - "updating wel flux: stress_period=0, timestep=5\n", - "updating wel flux: stress_period=0, timestep=6\n", - "updating wel flux: stress_period=0, timestep=7\n", - "updating wel flux: stress_period=0, timestep=8\n", - "updating wel flux: stress_period=0, timestep=9\n", - "updating wel flux: stress_period=0, timestep=10\n", - "updating wel flux: stress_period=0, timestep=11\n", - "updating wel flux: stress_period=0, timestep=12\n", - "updating wel flux: stress_period=0, timestep=13\n", - "updating wel flux: stress_period=0, timestep=14\n", - "updating wel flux: stress_period=0, timestep=15\n", - "updating wel flux: stress_period=0, timestep=16\n", - "updating wel flux: stress_period=0, timestep=17\n", - "updating wel flux: stress_period=0, timestep=18\n", - "updating wel flux: stress_period=0, timestep=19\n", - "updating wel flux: stress_period=0, timestep=20\n", - "updating wel flux: stress_period=0, timestep=21\n", - "updating wel flux: stress_period=0, timestep=22\n", - "updating wel flux: stress_period=0, timestep=23\n", - "updating wel flux: stress_period=0, timestep=24\n", - "updating wel flux: stress_period=0, timestep=25\n", - "updating wel flux: stress_period=0, timestep=26\n", - "updating wel flux: stress_period=0, timestep=27\n", - "updating wel flux: stress_period=0, timestep=28\n", - "updating wel flux: stress_period=0, timestep=29\n", - "updating wel flux: stress_period=0, timestep=30\n", - "updating recharge: stress_period=1\n", - "updating wel flux: stress_period=1, timestep=0\n", - "updating wel flux: stress_period=1, timestep=1\n", - "updating wel flux: stress_period=1, timestep=2\n", - "updating wel flux: stress_period=1, timestep=3\n", - "updating wel flux: stress_period=1, timestep=4\n", - "updating wel flux: stress_period=1, timestep=5\n", - "updating wel flux: stress_period=1, timestep=6\n", - "updating wel flux: stress_period=1, timestep=7\n", - "updating wel flux: stress_period=1, timestep=8\n", - "updating wel flux: stress_period=1, timestep=9\n", - "updating wel flux: stress_period=1, timestep=10\n", - "updating wel flux: stress_period=1, timestep=11\n", - "updating wel flux: stress_period=1, timestep=12\n", - "updating wel flux: stress_period=1, timestep=13\n", - "updating wel flux: stress_period=1, timestep=14\n", - "updating wel flux: stress_period=1, timestep=15\n", - "updating wel flux: stress_period=1, timestep=16\n", - "updating wel flux: stress_period=1, timestep=17\n", - "updating wel flux: stress_period=1, timestep=18\n", - "updating wel flux: stress_period=1, timestep=19\n", - "updating wel flux: stress_period=1, timestep=20\n", - "updating wel flux: stress_period=1, timestep=21\n", - "updating wel flux: stress_period=1, timestep=22\n", - "updating wel flux: stress_period=1, timestep=23\n", - "updating wel flux: stress_period=1, timestep=24\n", - "updating wel flux: stress_period=1, timestep=25\n", - "updating wel flux: stress_period=1, timestep=26\n", - "updating wel flux: stress_period=1, timestep=27\n", - "updating recharge: stress_period=2\n", - "updating wel flux: stress_period=2, timestep=0\n", - "updating wel flux: stress_period=2, timestep=1\n", - "updating wel flux: stress_period=2, timestep=2\n", - "updating wel flux: stress_period=2, timestep=3\n", - "updating wel flux: stress_period=2, timestep=4\n", - "updating wel flux: stress_period=2, timestep=5\n", - "updating wel flux: stress_period=2, timestep=6\n", - "updating wel flux: stress_period=2, timestep=7\n", - "updating wel flux: stress_period=2, timestep=8\n", - "updating wel flux: stress_period=2, timestep=9\n", - "updating wel flux: stress_period=2, timestep=10\n", - "updating wel flux: stress_period=2, timestep=11\n", - "updating wel flux: stress_period=2, timestep=12\n", - "updating wel flux: stress_period=2, timestep=13\n", - "updating wel flux: stress_period=2, timestep=14\n", - "updating wel flux: stress_period=2, timestep=15\n", - "updating wel flux: stress_period=2, timestep=16\n", - "updating wel flux: stress_period=2, timestep=17\n", - "updating wel flux: stress_period=2, timestep=18\n", - "updating wel flux: stress_period=2, timestep=19\n", - "updating wel flux: stress_period=2, timestep=20\n", - "updating wel flux: stress_period=2, timestep=21\n", - "updating wel flux: stress_period=2, timestep=22\n", - "updating wel flux: stress_period=2, timestep=23\n", - "updating wel flux: stress_period=2, timestep=24\n", - "updating wel flux: stress_period=2, timestep=25\n", - "updating wel flux: stress_period=2, timestep=26\n", - "updating wel flux: stress_period=2, timestep=27\n", - "updating wel flux: stress_period=2, timestep=28\n", - "updating wel flux: stress_period=2, timestep=29\n", - "updating wel flux: stress_period=2, timestep=30\n", - "updating recharge: stress_period=3\n", - "updating wel flux: stress_period=3, timestep=0\n", - "updating wel flux: stress_period=3, timestep=1\n", - "updating wel flux: stress_period=3, timestep=2\n", - "updating wel flux: stress_period=3, timestep=3\n", - "updating wel flux: stress_period=3, timestep=4\n", - "updating wel flux: stress_period=3, timestep=5\n", - "updating wel flux: stress_period=3, timestep=6\n", - "updating wel flux: stress_period=3, timestep=7\n", - "updating wel flux: stress_period=3, timestep=8\n", - "updating wel flux: stress_period=3, timestep=9\n", - "updating wel flux: stress_period=3, timestep=10\n", - "updating wel flux: stress_period=3, timestep=11\n", - "updating wel flux: stress_period=3, timestep=12\n", - "updating wel flux: stress_period=3, timestep=13\n", - "updating wel flux: stress_period=3, timestep=14\n", - "updating wel flux: stress_period=3, timestep=15\n", - "updating wel flux: stress_period=3, timestep=16\n", - "updating wel flux: stress_period=3, timestep=17\n", - "updating wel flux: stress_period=3, timestep=18\n", - "updating wel flux: stress_period=3, timestep=19\n", - "updating wel flux: stress_period=3, timestep=20\n", - "updating wel flux: stress_period=3, timestep=21\n", - "updating wel flux: stress_period=3, timestep=22\n", - "updating wel flux: stress_period=3, timestep=23\n", - "updating wel flux: stress_period=3, timestep=24\n", - "updating wel flux: stress_period=3, timestep=25\n", - "updating wel flux: stress_period=3, timestep=26\n", - "updating wel flux: stress_period=3, timestep=27\n", - "updating wel flux: stress_period=3, timestep=28\n", - "updating wel flux: stress_period=3, timestep=29\n", - "updating recharge: stress_period=4\n", - "updating wel flux: stress_period=4, timestep=0\n", - "updating wel flux: stress_period=4, timestep=1\n", - "updating wel flux: stress_period=4, timestep=2\n", - "updating wel flux: stress_period=4, timestep=3\n", - "updating wel flux: stress_period=4, timestep=4\n", - "updating wel flux: stress_period=4, timestep=5\n", - "updating wel flux: stress_period=4, timestep=6\n", - "updating wel flux: stress_period=4, timestep=7\n", - "updating wel flux: stress_period=4, timestep=8\n", - "updating wel flux: stress_period=4, timestep=9\n", - "updating wel flux: stress_period=4, timestep=10\n", - "updating wel flux: stress_period=4, timestep=11\n", - "updating wel flux: stress_period=4, timestep=12\n", - "updating wel flux: stress_period=4, timestep=13\n", - "updating wel flux: stress_period=4, timestep=14\n", - "updating wel flux: stress_period=4, timestep=15\n", - "updating wel flux: stress_period=4, timestep=16\n", - "updating wel flux: stress_period=4, timestep=17\n", - "updating wel flux: stress_period=4, timestep=18\n", - "updating wel flux: stress_period=4, timestep=19\n", - "updating wel flux: stress_period=4, timestep=20\n", - "updating wel flux: stress_period=4, timestep=21\n", - "updating wel flux: stress_period=4, timestep=22\n", - "updating wel flux: stress_period=4, timestep=23\n", - "updating wel flux: stress_period=4, timestep=24\n", - "updating wel flux: stress_period=4, timestep=25\n", - "updating wel flux: stress_period=4, timestep=26\n", - "updating wel flux: stress_period=4, timestep=27\n", - "updating wel flux: stress_period=4, timestep=28\n", - "updating wel flux: stress_period=4, timestep=29\n", - "updating wel flux: stress_period=4, timestep=30\n", - "updating recharge: stress_period=5\n", - "updating wel flux: stress_period=5, timestep=0\n", - "updating wel flux: stress_period=5, timestep=1\n", - "updating wel flux: stress_period=5, timestep=2\n", - "updating wel flux: stress_period=5, timestep=3\n", - "updating wel flux: stress_period=5, timestep=4\n", - "updating wel flux: stress_period=5, timestep=5\n", - "updating wel flux: stress_period=5, timestep=6\n", - "updating wel flux: stress_period=5, timestep=7\n", - "updating wel flux: stress_period=5, timestep=8\n", - "updating wel flux: stress_period=5, timestep=9\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "updating wel flux: stress_period=5, timestep=10\n", - "updating wel flux: stress_period=5, timestep=11\n", - "updating wel flux: stress_period=5, timestep=12\n", - "updating wel flux: stress_period=5, timestep=13\n", - "updating wel flux: stress_period=5, timestep=14\n", - "updating wel flux: stress_period=5, timestep=15\n", - "updating wel flux: stress_period=5, timestep=16\n", - "updating wel flux: stress_period=5, timestep=17\n", - "updating wel flux: stress_period=5, timestep=18\n", - "updating wel flux: stress_period=5, timestep=19\n", - "updating wel flux: stress_period=5, timestep=20\n", - "updating wel flux: stress_period=5, timestep=21\n", - "updating wel flux: stress_period=5, timestep=22\n", - "updating wel flux: stress_period=5, timestep=23\n", - "updating wel flux: stress_period=5, timestep=24\n", - "updating wel flux: stress_period=5, timestep=25\n", - "updating wel flux: stress_period=5, timestep=26\n", - "updating wel flux: stress_period=5, timestep=27\n", - "updating wel flux: stress_period=5, timestep=28\n", - "updating wel flux: stress_period=5, timestep=29\n", - "updating recharge: stress_period=6\n", - "updating wel flux: stress_period=6, timestep=0\n", - "updating wel flux: stress_period=6, timestep=1\n", - "updating wel flux: stress_period=6, timestep=2\n", - "updating wel flux: stress_period=6, timestep=3\n", - "updating wel flux: stress_period=6, timestep=4\n", - "updating wel flux: stress_period=6, timestep=5\n", - "updating wel flux: stress_period=6, timestep=6\n", - "updating wel flux: stress_period=6, timestep=7\n", - "updating wel flux: stress_period=6, timestep=8\n", - "updating wel flux: stress_period=6, timestep=9\n", - "updating wel flux: stress_period=6, timestep=10\n", - "updating wel flux: stress_period=6, timestep=11\n", - "updating wel flux: stress_period=6, timestep=12\n", - "updating wel flux: stress_period=6, timestep=13\n", - "updating wel flux: stress_period=6, timestep=14\n", - "updating wel flux: stress_period=6, timestep=15\n", - "updating wel flux: stress_period=6, timestep=16\n", - "updating wel flux: stress_period=6, timestep=17\n", - "updating wel flux: stress_period=6, timestep=18\n", - "updating wel flux: stress_period=6, timestep=19\n", - "updating wel flux: stress_period=6, timestep=20\n", - "updating wel flux: stress_period=6, timestep=21\n", - "updating wel flux: stress_period=6, timestep=22\n", - "updating wel flux: stress_period=6, timestep=23\n", - "updating wel flux: stress_period=6, timestep=24\n", - "updating wel flux: stress_period=6, timestep=25\n", - "updating wel flux: stress_period=6, timestep=26\n", - "updating wel flux: stress_period=6, timestep=27\n", - "updating wel flux: stress_period=6, timestep=28\n", - "updating wel flux: stress_period=6, timestep=29\n", - "updating wel flux: stress_period=6, timestep=30\n", - "updating wel flux: stress_period=7, timestep=0\n", - "updating wel flux: stress_period=7, timestep=1\n", - "updating wel flux: stress_period=7, timestep=2\n", - "updating wel flux: stress_period=7, timestep=3\n", - "updating wel flux: stress_period=7, timestep=4\n", - "updating wel flux: stress_period=7, timestep=5\n", - "updating wel flux: stress_period=7, timestep=6\n", - "updating wel flux: stress_period=7, timestep=7\n", - "updating wel flux: stress_period=7, timestep=8\n", - "updating wel flux: stress_period=7, timestep=9\n", - "updating wel flux: stress_period=7, timestep=10\n", - "updating wel flux: stress_period=7, timestep=11\n", - "updating wel flux: stress_period=7, timestep=12\n", - "updating wel flux: stress_period=7, timestep=13\n", - "updating wel flux: stress_period=7, timestep=14\n", - "updating wel flux: stress_period=7, timestep=15\n", - "updating wel flux: stress_period=7, timestep=16\n", - "updating wel flux: stress_period=7, timestep=17\n", - "updating wel flux: stress_period=7, timestep=18\n", - "updating wel flux: stress_period=7, timestep=19\n", - "updating wel flux: stress_period=7, timestep=20\n", - "updating wel flux: stress_period=7, timestep=21\n", - "updating wel flux: stress_period=7, timestep=22\n", - "updating wel flux: stress_period=7, timestep=23\n", - "updating wel flux: stress_period=7, timestep=24\n", - "updating wel flux: stress_period=7, timestep=25\n", - "updating wel flux: stress_period=7, timestep=26\n", - "updating wel flux: stress_period=7, timestep=27\n", - "updating wel flux: stress_period=7, timestep=28\n", - "updating wel flux: stress_period=7, timestep=29\n", - "updating wel flux: stress_period=7, timestep=30\n", - "updating wel flux: stress_period=8, timestep=0\n", - "updating wel flux: stress_period=8, timestep=1\n", - "updating wel flux: stress_period=8, timestep=2\n", - "updating wel flux: stress_period=8, timestep=3\n", - "updating wel flux: stress_period=8, timestep=4\n", - "updating wel flux: stress_period=8, timestep=5\n", - "updating wel flux: stress_period=8, timestep=6\n", - "updating wel flux: stress_period=8, timestep=7\n", - "updating wel flux: stress_period=8, timestep=8\n", - "updating wel flux: stress_period=8, timestep=9\n", - "updating wel flux: stress_period=8, timestep=10\n", - "updating wel flux: stress_period=8, timestep=11\n", - "updating wel flux: stress_period=8, timestep=12\n", - "updating wel flux: stress_period=8, timestep=13\n", - "updating wel flux: stress_period=8, timestep=14\n", - "updating wel flux: stress_period=8, timestep=15\n", - "updating wel flux: stress_period=8, timestep=16\n", - "updating wel flux: stress_period=8, timestep=17\n", - "updating wel flux: stress_period=8, timestep=18\n", - "updating wel flux: stress_period=8, timestep=19\n", - "updating wel flux: stress_period=8, timestep=20\n", - "updating wel flux: stress_period=8, timestep=21\n", - "updating wel flux: stress_period=8, timestep=22\n", - "updating wel flux: stress_period=8, timestep=23\n", - "updating wel flux: stress_period=8, timestep=24\n", - "updating wel flux: stress_period=8, timestep=25\n", - "updating wel flux: stress_period=8, timestep=26\n", - "updating wel flux: stress_period=8, timestep=27\n", - "updating wel flux: stress_period=8, timestep=28\n", - "updating wel flux: stress_period=8, timestep=29\n", - "updating wel flux: stress_period=9, timestep=0\n", - "updating wel flux: stress_period=9, timestep=1\n", - "updating wel flux: stress_period=9, timestep=2\n", - "updating wel flux: stress_period=9, timestep=3\n", - "updating wel flux: stress_period=9, timestep=4\n", - "updating wel flux: stress_period=9, timestep=5\n", - "updating wel flux: stress_period=9, timestep=6\n", - "updating wel flux: stress_period=9, timestep=7\n", - "updating wel flux: stress_period=9, timestep=8\n", - "updating wel flux: stress_period=9, timestep=9\n", - "updating wel flux: stress_period=9, timestep=10\n", - "updating wel flux: stress_period=9, timestep=11\n", - "updating wel flux: stress_period=9, timestep=12\n", - "updating wel flux: stress_period=9, timestep=13\n", - "updating wel flux: stress_period=9, timestep=14\n", - "updating wel flux: stress_period=9, timestep=15\n", - "updating wel flux: stress_period=9, timestep=16\n", - "updating wel flux: stress_period=9, timestep=17\n", - "updating wel flux: stress_period=9, timestep=18\n", - "updating wel flux: stress_period=9, timestep=19\n", - "updating wel flux: stress_period=9, timestep=20\n", - "updating wel flux: stress_period=9, timestep=21\n", - "updating wel flux: stress_period=9, timestep=22\n", - "updating wel flux: stress_period=9, timestep=23\n", - "updating wel flux: stress_period=9, timestep=24\n", - "updating wel flux: stress_period=9, timestep=25\n", - "updating wel flux: stress_period=9, timestep=26\n", - "updating wel flux: stress_period=9, timestep=27\n", - "updating wel flux: stress_period=9, timestep=28\n", - "updating wel flux: stress_period=9, timestep=29\n", - "updating wel flux: stress_period=9, timestep=30\n", - "updating wel flux: stress_period=10, timestep=0\n", - "updating wel flux: stress_period=10, timestep=1\n", - "updating wel flux: stress_period=10, timestep=2\n", - "updating wel flux: stress_period=10, timestep=3\n", - "updating wel flux: stress_period=10, timestep=4\n", - "updating wel flux: stress_period=10, timestep=5\n", - "updating wel flux: stress_period=10, timestep=6\n", - "updating wel flux: stress_period=10, timestep=7\n", - "updating wel flux: stress_period=10, timestep=8\n", - "updating wel flux: stress_period=10, timestep=9\n", - "updating wel flux: stress_period=10, timestep=10\n", - "updating wel flux: stress_period=10, timestep=11\n", - "updating wel flux: stress_period=10, timestep=12\n", - "updating wel flux: stress_period=10, timestep=13\n", - "updating wel flux: stress_period=10, timestep=14\n", - "updating wel flux: stress_period=10, timestep=15\n", - "updating wel flux: stress_period=10, timestep=16\n", - "updating wel flux: stress_period=10, timestep=17\n", - "updating wel flux: stress_period=10, timestep=18\n", - "updating wel flux: stress_period=10, timestep=19\n", - "updating wel flux: stress_period=10, timestep=20\n", - "updating wel flux: stress_period=10, timestep=21\n", - "updating wel flux: stress_period=10, timestep=22\n", - "updating wel flux: stress_period=10, timestep=23\n", - "updating wel flux: stress_period=10, timestep=24\n", - "updating wel flux: stress_period=10, timestep=25\n", - "updating wel flux: stress_period=10, timestep=26\n", - "updating wel flux: stress_period=10, timestep=27\n", - "updating wel flux: stress_period=10, timestep=28\n", - "updating wel flux: stress_period=10, timestep=29\n", - "updating wel flux: stress_period=11, timestep=0\n", - "updating wel flux: stress_period=11, timestep=1\n", - "updating wel flux: stress_period=11, timestep=2\n", - "updating wel flux: stress_period=11, timestep=3\n", - "updating wel flux: stress_period=11, timestep=4\n", - "updating wel flux: stress_period=11, timestep=5\n", - "updating wel flux: stress_period=11, timestep=6\n", - "updating wel flux: stress_period=11, timestep=7\n", - "updating wel flux: stress_period=11, timestep=8\n", - "updating wel flux: stress_period=11, timestep=9\n", - "updating wel flux: stress_period=11, timestep=10\n", - "updating wel flux: stress_period=11, timestep=11\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "updating wel flux: stress_period=11, timestep=12\n", - "updating wel flux: stress_period=11, timestep=13\n", - "updating wel flux: stress_period=11, timestep=14\n", - "updating wel flux: stress_period=11, timestep=15\n", - "updating wel flux: stress_period=11, timestep=16\n", - "updating wel flux: stress_period=11, timestep=17\n", - "updating wel flux: stress_period=11, timestep=18\n", - "updating wel flux: stress_period=11, timestep=19\n", - "updating wel flux: stress_period=11, timestep=20\n", - "updating wel flux: stress_period=11, timestep=21\n", - "updating wel flux: stress_period=11, timestep=22\n", - "updating wel flux: stress_period=11, timestep=23\n", - "updating wel flux: stress_period=11, timestep=24\n", - "updating wel flux: stress_period=11, timestep=25\n", - "updating wel flux: stress_period=11, timestep=26\n", - "updating wel flux: stress_period=11, timestep=27\n", - "updating wel flux: stress_period=11, timestep=28\n", - "updating wel flux: stress_period=11, timestep=29\n", - "updating wel flux: stress_period=11, timestep=30\n", - "NORMAL TERMINATION OF SIMULATION\n" - ] - } - ], + "outputs": [], "source": [ "modflowapi.run_simulation(dll, sim_ws, callback_function, verbose=False)" ] diff --git a/examples/notebooks/Quickstart.ipynb b/examples/notebooks/Quickstart.ipynb index ca5843d..9c6eff7 100644 --- a/examples/notebooks/Quickstart.ipynb +++ b/examples/notebooks/Quickstart.ipynb @@ -99,7 +99,7 @@ " \n", " if callback_step == Callbacks.timestep_start:\n", " print(f\"updating wel flux: stress_period={ml.kper}, timestep={ml.kstp}\")\n", - " ml.wel.stress_period_data[\"flux\"] -= ml.kstp * 1.5\n", + " ml.wel.stress_period_data[\"q\"] -= ml.kstp * 1.5\n", " \n", " if callback_step == Callbacks.iteration_start:\n", " # we can implement complex solutions to boundary conditions here!\n", @@ -304,15 +304,15 @@ "updating wel flux: stress_period=4, timestep=29\n", "updating wel flux: stress_period=4, timestep=30\n", "updating recharge: stress_period=5\n", - "updating wel flux: stress_period=5, timestep=0\n", - "updating wel flux: stress_period=5, timestep=1\n", - "updating wel flux: stress_period=5, timestep=2\n" + "updating wel flux: stress_period=5, timestep=0\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ + "updating wel flux: stress_period=5, timestep=1\n", + "updating wel flux: stress_period=5, timestep=2\n", "updating wel flux: stress_period=5, timestep=3\n", "updating wel flux: stress_period=5, timestep=4\n", "updating wel flux: stress_period=5, timestep=5\n", @@ -495,16 +495,16 @@ "updating wel flux: stress_period=10, timestep=28\n", "updating wel flux: stress_period=10, timestep=29\n", "updating wel flux: stress_period=11, timestep=0\n", - "updating wel flux: stress_period=11, timestep=1\n", - "updating wel flux: stress_period=11, timestep=2\n", - "updating wel flux: stress_period=11, timestep=3\n", - "updating wel flux: stress_period=11, timestep=4\n" + "updating wel flux: stress_period=11, timestep=1\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ + "updating wel flux: stress_period=11, timestep=2\n", + "updating wel flux: stress_period=11, timestep=3\n", + "updating wel flux: stress_period=11, timestep=4\n", "updating wel flux: stress_period=11, timestep=5\n", "updating wel flux: stress_period=11, timestep=6\n", "updating wel flux: stress_period=11, timestep=7\n", diff --git a/modflowapi/extensions/data.py b/modflowapi/extensions/data.py index 4145ccf..96670bf 100644 --- a/modflowapi/extensions/data.py +++ b/modflowapi/extensions/data.py @@ -33,7 +33,7 @@ def __init__(self, parent, var_addrs=None, mf6=None): self._ptrs = {} self._nodevars = ("nodelist", "nexg", "maxats") self._boundvars = ("bound",) - # self._auxname = [] + self._maxbound = [ 0, ] @@ -46,13 +46,79 @@ def __init__(self, parent, var_addrs=None, mf6=None): self._auxnames = [] self._dtype = [] self._reduced_to_var_addr = {} - self._set_stress_period_data() + if self.parent._idm_enabled: + for var in ("BOUND", "AUXVAR"): + self.var_addrs.pop( + self.var_addrs.index( + self.mf6.get_var_address( + var, self.parent.model.name, self.parent.pkg_name + ) + ) + ) + self.var_addrs.append( + self.mf6.get_var_address( + "AUXVAR_IDM", self.parent.model.name, self.parent.pkg_name + ) + ) + self._set_stress_period_data_idm() + else: + self._set_stress_period_data() + + def _set_stress_period_data_idm(self): + """ + Method to set stress period data variable pointers to the _ptrs + dictionary. Uses IDM updates instead of bound to access variable + pointers. + """ + # for now we need to add self.parent._bound_vars data to var_addrs + for var_addr in self.var_addrs: + try: + values = self.mf6.get_value_ptr(var_addr) + except xmipy.errors.InputError: + if self._naux[0] > 0: + values = self.mf6.get_value(var_addr) + else: + continue + + reduced = var_addr.split("/")[-1].lower() + if reduced in ("maxbound", "nbound"): + setattr(self, f"_{reduced}", values) + elif reduced in ("nexg", "maxats"): + setattr(self, "_maxbound", values) + setattr(self, "_nbound", values) + elif reduced in ("naux",): + setattr(self, "_naux", values) + elif reduced in ("auxname_cst"): + setattr(self, "_auxnames", list(values)) + else: + self._ptrs[reduced] = values + self._reduced_to_var_addr[reduced] = var_addr + if reduced in self.parent._bound_vars: + typ_str = values.dtype.str + dtype = (reduced, typ_str) + self._dtype.append(dtype) + elif reduced in self._nodevars: + dtype = (reduced, "O") + self._dtype.append(dtype) + elif reduced == "auxvar_idm": + if self._naux == 0: + continue + else: + for ix in range(self._naux[0]): + typ_str = values.dtype.str + dtype = (self._auxnames[ix], typ_str) + self._dtype.append(dtype) + else: + typ_str = values.dtype.str + dtype = (reduced, typ_str) + self._dtype.append(dtype) def _set_stress_period_data(self): """ Method to set stress period data variable pointers to the _ptrs dictionary + PENDING DEPRECATION AND REPLACEMENT by _set_stress_period_data_idm() """ for var_addr in self.var_addrs: try: @@ -108,14 +174,19 @@ def _ptr_to_recarray(self): return recarray = np.recarray((self._nbound[0],), self._dtype) for name, ptr in self._ptrs.items(): - if name == "auxvar" and self._naux[0] == 0: + if "auxvar" in name and self._naux[0] == 0: continue values = np.copy(ptr) if name in self._boundvars: + # note: block slated for deprecation for ix, nm in enumerate(self.parent._bound_vars): bnd_values = values[0 : self._nbound[0], ix] recarray[nm][0 : self._nbound[0]] = bnd_values - elif name == "auxvar": + elif name in self.parent._bound_vars and self.parent._idm_enabled: + # new IDM simplification method + bnd_values = values[0 : self._nbound[0]].ravel() + recarray[name][0 : self._nbound[0]] = bnd_values + elif "auxvar" in name: for ix in range(self._naux[0]): nm = self._auxnames[ix] aux_values = values[0 : self._nbound[0], ix] @@ -175,12 +246,22 @@ def _recarray_to_ptr(self, recarray): recarray[name] = self.parent.model.usertonode[nodes] + 1 if name in self.parent._bound_vars: - idx = self.parent._bound_vars.index(name) - bname = "bound" - self._ptrs[bname][0 : self._nbound[0], idx] = recarray[name] + if "bound" in self._ptrs: + # remove some time after IDM inclusion + idx = self.parent._bound_vars.index(name) + bname = "bound" + self._ptrs[bname][0 : self._nbound[0], idx] = recarray[name] + elif self.parent._idm_enabled: + # new IDM simplification + self._ptrs[name][0 : self._nbound[0]] = recarray[name].ravel() + else: + pass elif name in self._auxnames: + ptr_name = "auxvar" + if self.parent._idm_enabled: + ptr_name += "_idm" idx = self._auxnames.index(name) - self._ptrs["auxvar"][0 : self._nbound[0], idx] = recarray[name] + self._ptrs[ptr_name][0 : self._nbound[0], idx] = recarray[name] elif name == "auxname_cst": pass else: diff --git a/modflowapi/extensions/pakbase.py b/modflowapi/extensions/pakbase.py index 0aafca4..efb45be 100644 --- a/modflowapi/extensions/pakbase.py +++ b/modflowapi/extensions/pakbase.py @@ -86,7 +86,7 @@ "maxbound", "nbound", "nodelist", - ("bound", ("flux",)), + ("bound", ("q",)), "naux", "auxname_cst", "auxvar", @@ -202,6 +202,7 @@ def __init__(self, model, pkg_type, pkg_name, child_type, sim_package): self._hcof = None self._bound_vars = [] self._advanced_var_names = None + self._idm_enabled = False var_addrs = [] if self._child_type != "advanced": @@ -240,6 +241,14 @@ def __init__(self, model, pkg_type, pkg_name, child_type, sim_package): ) ) + for var in self._bound_vars: + addr_chk = self.model.mf6.get_var_address( + var.upper(), self.model.name, self.pkg_name + ) + if addr_chk in self.model.mf6.get_input_var_names(): + self._idm_enabled = True + var_addrs.append(addr_chk) + self.var_addrs = var_addrs self._variables_adv = AdvancedInput(self) From 8677b35fb9767484d357cc0c5bc1ec9e97e34bf8 Mon Sep 17 00:00:00 2001 From: Joshua Larsen Date: Thu, 21 Dec 2023 09:58:01 -0800 Subject: [PATCH 23/34] lint extension updates --- modflowapi/extensions/data.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/modflowapi/extensions/data.py b/modflowapi/extensions/data.py index 96670bf..d12432c 100644 --- a/modflowapi/extensions/data.py +++ b/modflowapi/extensions/data.py @@ -250,10 +250,14 @@ def _recarray_to_ptr(self, recarray): # remove some time after IDM inclusion idx = self.parent._bound_vars.index(name) bname = "bound" - self._ptrs[bname][0 : self._nbound[0], idx] = recarray[name] + self._ptrs[bname][0 : self._nbound[0], idx] = recarray[ + name + ] elif self.parent._idm_enabled: # new IDM simplification - self._ptrs[name][0 : self._nbound[0]] = recarray[name].ravel() + self._ptrs[name][0 : self._nbound[0]] = recarray[ + name + ].ravel() else: pass elif name in self._auxnames: From 97e195d71b8f29eb6de04fe5d5c93b0f763ea360 Mon Sep 17 00:00:00 2001 From: Joshua Larsen Date: Thu, 21 Dec 2023 10:06:49 -0800 Subject: [PATCH 24/34] update testing for IDM/backward compatibility --- autotest/test_interface.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/autotest/test_interface.py b/autotest/test_interface.py index 1c7ce40..bb2be31 100644 --- a/autotest/test_interface.py +++ b/autotest/test_interface.py @@ -11,6 +11,7 @@ AdvancedPackage, ArrayPackage, ListPackage, + pkgvars ) data_pth = Path("../examples/data") @@ -28,6 +29,14 @@ if so is None: pytest.skip("Unsupported operating system", allow_module_level=True) +wel_meta = pkgvars["wel"] +for var in wel_meta: + if isinstance(var, tuple): + if "q" in var[1]: + wellvar = "q" + else: + wellvar = "flux" + break @pytest.mark.parametrize("use_str", [True, False]) def test_ctor_finds_libmf6_by_name(use_str): @@ -120,10 +129,10 @@ def callback(sim, step): factor = ((1 + sim.kstp) / sim.nstp) * 0.5 spd = sim.test_model.wel.stress_period_data.values - sim.test_model.wel.stress_period_data["flux"] *= factor + sim.test_model.wel.stress_period_data[wellvar] *= factor spd2 = sim.test_model.wel.stress_period_data.values - if not np.allclose((spd["flux"] * factor), spd2["flux"]): + if not np.allclose((spd[wellvar] * factor), spd2[wellvar]): raise AssertionError("Pointer not being set properly") if sim.kper >= 3 and sim.kstp == 0: From e6558acbe6a31227c509815623d0df376b2666f9 Mon Sep 17 00:00:00 2001 From: Joshua Larsen Date: Thu, 21 Dec 2023 10:11:42 -0800 Subject: [PATCH 25/34] update flux to q --- autotest/test_interface.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/autotest/test_interface.py b/autotest/test_interface.py index bb2be31..44be4ce 100644 --- a/autotest/test_interface.py +++ b/autotest/test_interface.py @@ -29,14 +29,6 @@ if so is None: pytest.skip("Unsupported operating system", allow_module_level=True) -wel_meta = pkgvars["wel"] -for var in wel_meta: - if isinstance(var, tuple): - if "q" in var[1]: - wellvar = "q" - else: - wellvar = "flux" - break @pytest.mark.parametrize("use_str", [True, False]) def test_ctor_finds_libmf6_by_name(use_str): @@ -129,10 +121,10 @@ def callback(sim, step): factor = ((1 + sim.kstp) / sim.nstp) * 0.5 spd = sim.test_model.wel.stress_period_data.values - sim.test_model.wel.stress_period_data[wellvar] *= factor + sim.test_model.wel.stress_period_data["q"] *= factor spd2 = sim.test_model.wel.stress_period_data.values - if not np.allclose((spd[wellvar] * factor), spd2[wellvar]): + if not np.allclose((spd["q"] * factor), spd2["q"]): raise AssertionError("Pointer not being set properly") if sim.kper >= 3 and sim.kstp == 0: From a62e5d65d0907c001247fe5e739901b580f1fd2f Mon Sep 17 00:00:00 2001 From: Joshua Larsen Date: Thu, 21 Dec 2023 10:19:18 -0800 Subject: [PATCH 26/34] Add backward compatibility check to CI --- .github/workflows/ci.yml | 46 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1de562f..5a0c06a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -135,7 +135,51 @@ jobs: working-directory: ./autotest shell: bash -l {0} run: pytest -v -n auto -m "not mf6" - + + autotest_preidm_extensions: + name: modflowapi pre-idm extensions autotests + needs: lint + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ ubuntu-latest, macos-latest, windows-latest ] + python-version: [ 3.8, 3.9, "3.10", "3.11" ] + defaults: + run: + shell: bash + + steps: + # check out repo + - name: Checkout repo + uses: actions/checkout@v3 + + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + cache: 'pip' + cache-dependency-path: pyproject.toml + + - name: Install Python dependencies + run: | + python -m pip install --upgrade pip + pip install git+https://git@github.com/Deltares/xmipy@develop + pip install git+https://git@github.com/MODFLOW-USGS/modflow-devtools@develop + pip install .[test] + + - name: Install modflow executables + uses: modflowpy/install-modflow-action@v1 + with: + path: ${{ github.workspace }}/autotest + repo: executables + tag: 14.0 + + - name: Run autotests + working-directory: ./autotest + shell: bash -l {0} + run: pytest -v -n auto -m "not mf6" + autotest_mf6_examples: name: modflowapi mf6 examples autotests needs: lint From 0a0ac0be3c68a9d88ef743cdc99b3e8a714b598f Mon Sep 17 00:00:00 2001 From: Joshua Larsen Date: Thu, 21 Dec 2023 10:24:27 -0800 Subject: [PATCH 27/34] update executable tag number --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5a0c06a..7103192 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -173,7 +173,7 @@ jobs: with: path: ${{ github.workspace }}/autotest repo: executables - tag: 14.0 + tag: "14.0" - name: Run autotests working-directory: ./autotest From 10dcaca83ea4a01fa82921ae32dbd07db3596fc5 Mon Sep 17 00:00:00 2001 From: Joshua Larsen Date: Thu, 21 Dec 2023 11:12:35 -0800 Subject: [PATCH 28/34] update code comments, try to kick-start CI --- modflowapi/extensions/data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modflowapi/extensions/data.py b/modflowapi/extensions/data.py index d12432c..2f5116c 100644 --- a/modflowapi/extensions/data.py +++ b/modflowapi/extensions/data.py @@ -247,7 +247,7 @@ def _recarray_to_ptr(self, recarray): if name in self.parent._bound_vars: if "bound" in self._ptrs: - # remove some time after IDM inclusion + # Block slated for deprecation after IDM inclusion idx = self.parent._bound_vars.index(name) bname = "bound" self._ptrs[bname][0 : self._nbound[0], idx] = recarray[ From f3ab857960ad095c2efd757abce9cc5df54fa35f Mon Sep 17 00:00:00 2001 From: Joshua Larsen Date: Thu, 21 Dec 2023 11:31:12 -0800 Subject: [PATCH 29/34] Add IPRN integer record to IC files --- examples/data/disu_model/flow.ic | 2 +- examples/data/two_models/model1.ic | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/data/disu_model/flow.ic b/examples/data/disu_model/flow.ic index 3d1b93d..51ef1a0 100644 --- a/examples/data/disu_model/flow.ic +++ b/examples/data/disu_model/flow.ic @@ -4,7 +4,7 @@ end options BEGIN GRIDDATA strt -INTERNAL FACTOR 1 IPRN +INTERNAL FACTOR 1 IPRN 3 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 diff --git a/examples/data/two_models/model1.ic b/examples/data/two_models/model1.ic index 841d89f..70cc980 100644 --- a/examples/data/two_models/model1.ic +++ b/examples/data/two_models/model1.ic @@ -4,7 +4,7 @@ end options BEGIN GRIDDATA strt -INTERNAL FACTOR 1.0 IPRN +INTERNAL FACTOR 1.0 IPRN 3 1.0 1.0 1.0 1.0 1.0 1.0 0.0 1.0 1.0 1.0 1.0 1.0 1.0 0.0 1.0 1.0 1.0 1.0 1.0 1.0 0.0 From 1393eb6aea7e123102e8def5ba54aa3ea9b4d89f Mon Sep 17 00:00:00 2001 From: wpbonelli Date: Wed, 7 Feb 2024 16:26:11 -0500 Subject: [PATCH 30/34] ci(release): trusted pypi publishing in release.yml, backfill HISTORY.md (#35) --- .github/workflows/release.yml | 14 +++++++-- HISTORY.md | 54 +++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 HISTORY.md diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a071a43..27e2a1d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -177,6 +177,10 @@ jobs: permissions: contents: write pull-requests: write + id-token: write + environment: # requires a 'release' environment in repo settings + name: release + url: https://pypi.org/p/modflowapi steps: - name: Checkout main branch @@ -200,9 +204,15 @@ jobs: - name: Check package run: twine check --strict dist/* + + - name: Upload package + uses: actions/upload-artifact@v4 + with: + name: dist + path: dist - - name: Publish package - run: twine upload dist/* + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 reset: name: Draft reset PR diff --git a/HISTORY.md b/HISTORY.md new file mode 100644 index 0000000..44d5fa0 --- /dev/null +++ b/HISTORY.md @@ -0,0 +1,54 @@ +# Changelog +### Version 0.1.0 + +* Fix typo in README (https://github.com/MODFLOW-USGS/modflowapi/pull/4) +* modflowapi interface (https://github.com/MODFLOW-USGS/modflowapi/pull/8) +* update package: manual variable address assembly updated to use xmipy get_variable_addr() +* update additional manual variable address assembly statements +* Refactor code and added functionality: +* add stress_period_start, stress_period_end Callbacks +* fix ApiModel __repr__ +* added Exchanges, TDIS, ATS, and SLN support +* added ScalarInput and ScalarPackage support +* update autotests +* added parallel testing support through pytest-xdist +* updated markers and split the extensions tests from the mf6 examples tests +* added a test for ATS +* update setup.cfg +* update ci.yml +* update(ListInput): add auxvar to stress_period_data when auxiliary variables are used +* Allow None to be passed to stress_period_data.values to disable stresses for a package +* updates: ApiModel, ApiSimulation, run_simulation +* added a `totim` property on `ApiSimulation` and `ApiModel` +* added docstrings to ApiModel property methods +* updated termination message in run_simulation +* added a finalize callback to Callbacks and run_simulation +* add support for AUXNAME_CST +* add(Head Monitor Example): Add a head monitor example application +* ApiModel: adjust X based on nodetouser +* ApiPackage: enforce lower cased variable names in get_advanced_var +* ArrayPointer: trap for arrays that are not adjusted by reduced node numbers (ex. idomain) +* update setup.cfg +* try reformatting the xmipy installation instructions +* fix(get value): fixed error handling when modflowapi fails to get a pointer to a value from the API (https://github.com/MODFLOW-USGS/modflowapi/pull/9) +Co-authored-by: scottrp <45947939+scottrp@users.noreply.github.com> +* update(rhs, hcof, AdvancedInput): bug fixes for setting variable values for advanced inputs +* update rhs and hcof to copy values to pointer instead of overwriting the pointer +* add a check for AdvancedInput variables that do not have pointer support in xmipy +* update setting routine for AdvancedInput +* refactor(EOL): change CRLF to LF line endings for source files (https://github.com/MODFLOW-USGS/modflowapi/pull/12) +* Use pyproject.toml for project metadata, add citation info (https://github.com/MODFLOW-USGS/modflowapi/pull/11) +* add(test_rhs_hcof_advanced): add additional test (https://github.com/MODFLOW-USGS/modflowapi/pull/13) +* added test for getting and setting rhs, hcof, and advanced variable values +* update project to use unix line separators +* use np.testing.assert_allclose() instead of AssertionError +* Add missing RIV support to modflowapi (https://github.com/MODFLOW-USGS/modflowapi/pull/16) +* add(test_rhs_hcof_advanced): add additional test +* added test for getting and setting rhs, hcof, and advanced variable values +* update project to use unix line separators +* use np.testing.assert_allclose() instead of AssertionError +* Add missing riv package to modflowapi + +### Version 0.0.1 + +Initial release. \ No newline at end of file From 13739a76b594f5ac4a32b5cee95a473133d29307 Mon Sep 17 00:00:00 2001 From: wpbonelli Date: Wed, 7 Feb 2024 21:45:29 -0500 Subject: [PATCH 31/34] ci(release): fix changelog generation (#37) --- .github/workflows/release.yml | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 27e2a1d..798e6a2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -63,32 +63,26 @@ jobs: - name: Update changelog id: update-changelog run: | - # move changelog - clog="CHANGELOG_${{ steps.version.outputs.version }}.md" - echo "changelog=$clog" >> $GITHUB_OUTPUT - sudo cp "${{ steps.cliff.outputs.changelog }}" "$clog" - - # show current release changelog - cat "$clog" - # substitute full group names - sed -i 's/#### Ci/#### Continuous integration/' "$clog" - sed -i 's/#### Feat/#### New features/' "$clog" - sed -i 's/#### Fix/#### Bug fixes/' "$clog" - sed -i 's/#### Refactor/#### Refactoring/' "$clog" - sed -i 's/#### Test/#### Testing/' "$clog" - - cat "$clog" HISTORY.md > temp_history.md - sudo mv temp_history.md HISTORY.md + sed -i 's/#### Ci/#### Continuous integration/' CHANGELOG.md + sed -i 's/#### Feat/#### New features/' CHANGELOG.md + sed -i 's/#### Fix/#### Bug fixes/' CHANGELOG.md + sed -i 's/#### Refactor/#### Refactoring/' CHANGELOG.md + sed -i 's/#### Test/#### Testing/' CHANGELOG.md - # show full changelog - cat HISTORY.md + # prepend release changelog to cumulative changelog + clog="HISTORY.md" + temp="temp.md" + echo "$(tail -n +2 $clog)" > $clog + cat CHANGELOG.md $clog > $temp + sudo mv $temp $clog + sed -i '1i # Changelog' $clog - name: Upload changelog uses: actions/upload-artifact@v3 with: name: changelog - path: ${{ steps.update-changelog.outputs.changelog }} + path: CHANGELOG.md - name: Format Python files run: python scripts/pull_request_prepare.py From 76031f38e2f978eca07e89ef0c33ca77d7de37f5 Mon Sep 17 00:00:00 2001 From: wpbonelli Date: Wed, 7 Feb 2024 22:40:42 -0500 Subject: [PATCH 32/34] ci(release): multiple tweaks and fixes (#38) * add version.txt and modify update_version.py to support it * use packaging.version.Version in update_version.py * simplify version.py format (drop intermediate vars) * remove post-release reset PR step from release.yml * fix changelog reference in release.yml --- .github/workflows/release.yml | 70 +-------------------------- CITATION.cff | 2 +- modflowapi/version.py | 9 ++-- scripts/update_version.py | 89 ++++++++++------------------------- version.txt | 1 + 5 files changed, 30 insertions(+), 141 deletions(-) create mode 100644 version.txt diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 798e6a2..26e9a05 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -155,7 +155,7 @@ jobs: run: | version=$(python scripts/update_version.py -g) title="modflowapi $version" - notes=$(cat "changelog/CHANGELOG_$version.md" | grep -v "### Version $version") + notes=$(cat "changelog/CHANGELOG.md" | grep -v "### Version $version") gh release create "$version" \ --target main \ --title "$title" \ @@ -207,71 +207,3 @@ jobs: - name: Publish to PyPI uses: pypa/gh-action-pypi-publish@release/v1 - - reset: - name: Draft reset PR - if: ${{ github.event_name == 'release' }} - runs-on: ubuntu-22.04 - permissions: - contents: write - pull-requests: write - steps: - - - name: Checkout main branch - uses: actions/checkout@v3 - with: - ref: main - - - name: Setup Python - uses: actions/setup-python@v4 - with: - python-version: 3.8 - cache: 'pip' - cache-dependency-path: pyproject.toml - - - name: Install Python dependencies - run: | - pip install --upgrade pip - pip install . - pip install ".[lint, test]" - - - name: Get release tag - uses: oprypin/find-latest-tag@v1 - id: latest_tag - with: - repository: ${{ github.repository }} - releases-only: true - - - name: Draft pull request - env: - GITHUB_TOKEN: ${{ github.token }} - run: | - # create reset branch from main - reset_branch="post-release-${{ steps.latest_tag.outputs.tag }}-reset" - git switch -c $reset_branch - - # increment minor version - major_version=$(echo "${{ steps.latest_tag.outputs.tag }}" | cut -d. -f1) - minor_version=$(echo "${{ steps.latest_tag.outputs.tag }}" | cut -d. -f2) - patch_version=0 - version="$major_version.$((minor_version + 1)).$patch_version" - python scripts/update_version.py -v "$version" - - # format Python files - python scripts/pull_request_prepare.py - - # commit and push reset branch - git config core.sharedRepository true - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add -A - git commit -m "ci(release): update to development version $version" - git push -u origin $reset_branch - - # create PR into develop - body=' - # Reinitialize for development - - Updates the `develop` branch from `main` following a successful release. Increments the minor version number. - ' - gh pr create -B "develop" -H "$reset_branch" --title "Reinitialize develop branch" --draft --body "$body" \ No newline at end of file diff --git a/CITATION.cff b/CITATION.cff index ccd7d09..21bd4a0 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -3,7 +3,7 @@ message: If you use this software, please cite both the article from preferred-c and the software itself. type: software title: MODFLOW API -version: 0.2.0 +version: 0.2.0.dev0 date-released: '2023-04-19' abstract: An extension to xmipy for the MODFLOW API. repository-artifact: https://pypi.org/project/modflowapi diff --git a/modflowapi/version.py b/modflowapi/version.py index be5ce0b..c16cb60 100644 --- a/modflowapi/version.py +++ b/modflowapi/version.py @@ -1,6 +1,3 @@ -# version file for modflowapi - -major = 0 -minor = 2 -micro = 0 -__version__ = f"{major}.{minor}.{micro}" +# modflowapi version file automatically created using...update_version.py +# created on...February 07, 2024 22:13:12 +__version__ = "0.2.0.dev0" diff --git a/scripts/update_version.py b/scripts/update_version.py index de8074b..efbf1ac 100644 --- a/scripts/update_version.py +++ b/scripts/update_version.py @@ -1,93 +1,51 @@ import argparse import textwrap from datetime import datetime -from enum import Enum -from os import PathLike +from os.path import basename from pathlib import Path -from typing import NamedTuple +from packaging.version import Version from filelock import FileLock _project_name = "modflowapi" _project_root_path = Path(__file__).parent.parent +_version_txt_path = _project_root_path / "version.txt" _version_py_path = _project_root_path / "modflowapi" / "version.py" _citation_cff_path = _project_root_path / "CITATION.cff" +_initial_version = Version("0.0.1") +_current_version = Version(_version_txt_path.read_text().strip()) -class Version(NamedTuple): - """Semantic version number""" - major: int = 0 - minor: int = 0 - patch: int = 0 +def log_update(path, version: Version): + print(f"Updated {path} with version {version}") - def __repr__(self): - return f"{self.major}.{self.minor}.{self.patch}" - @classmethod - def from_string(cls, version: str) -> "Version": - t = version.split(".") - - vmajor = int(t[0]) - vminor = int(t[1]) - vpatch = int(t[2]) - - return cls(major=vmajor, minor=vminor, patch=vpatch) - - @classmethod - def from_file(cls, path: PathLike) -> "Version": - lines = [ - line.rstrip("\n") - for line in open(Path(path).expanduser().absolute(), "r") - ] - vmajor = vminor = vpatch = None - for line in lines: - line = line.strip() - if not any(line): - continue - - def get_ver(l): - return l.split("=")[1] - - if "__version__" not in line: - if "major" in line: - vmajor = int(get_ver(line)) - elif "minor" in line: - vminor = int(get_ver(line)) - elif "patch" in line or "micro" in line: - vpatch = int(get_ver(line)) - - assert ( - vmajor is not None and vminor is not None and vpatch is not None - ), "version string must follow semantic version format: major.minor.patch" - return cls(major=vmajor, minor=vminor, patch=vpatch) - - -_initial_version = Version(0, 0, 1) -_current_version = Version.from_file(_version_py_path) +def update_version_txt(version: Version): + with open(_version_txt_path, "w") as f: + f.write(str(version)) + log_update(_version_txt_path, version) def update_version_py(timestamp: datetime, version: Version): with open(_version_py_path, "w") as f: f.write( - f"# {_project_name} version file automatically created using " - f"{Path(__file__).name} on {timestamp:%B %d, %Y %H:%M:%S}\n\n" + f"# {_project_name} version file automatically " + + f"created using...{basename(__file__)}\n" ) - f.write(f"major = {version.major}\n") - f.write(f"minor = {version.minor}\n") - f.write(f"micro = {version.patch}\n") - f.write("__version__ = f'{major}.{minor}.{micro}'\n") - print(f"Updated {_version_py_path} to version {version}") + f.write("# created on..." + f"{timestamp.strftime('%B %d, %Y %H:%M:%S')}\n") + f.write(f'__version__ = "{version}"\n') + log_update(_version_py_path, version) -def update_citation_cff(timestamp: datetime, version: Version): +def update_citation_cff(version: Version): lines = open(_citation_cff_path, "r").readlines() with open(_citation_cff_path, "w") as f: for line in lines: if line.startswith("version:"): line = f"version: {version}\n" f.write(line) - print(f"Updated {_citation_cff_path} to version {version}") + log_update(_citation_cff_path, version) def update_version( @@ -97,7 +55,7 @@ def update_version( lock_path = Path(_version_py_path.name + ".lock") try: lock = FileLock(lock_path) - previous = Version.from_file(_version_py_path) + previous = Version(_version_txt_path.read_text().strip()) version = ( version if version @@ -105,8 +63,9 @@ def update_version( ) with lock: + update_version_txt(version) update_version_py(timestamp, version) - update_citation_cff(timestamp, version) + update_citation_cff(version) finally: try: lock_path.unlink() @@ -148,7 +107,7 @@ def update_version( else: update_version( timestamp=datetime.now(), - version=Version.from_string(args.version) - if args.version - else _current_version, + version=( + Version(args.version) if args.version else _current_version + ), ) diff --git a/version.txt b/version.txt new file mode 100644 index 0000000..9a058eb --- /dev/null +++ b/version.txt @@ -0,0 +1 @@ +0.2.0.dev0 \ No newline at end of file From 659b723f25961a3670fd57d63ec4ed0a95a532d4 Mon Sep 17 00:00:00 2001 From: wpbonelli Date: Thu, 8 Feb 2024 08:33:51 -0500 Subject: [PATCH 33/34] ci(release): fix changelog references in release.yml (#39) --- .github/workflows/release.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 26e9a05..db60173 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -61,7 +61,6 @@ jobs: OUTPUT: CHANGELOG.md - name: Update changelog - id: update-changelog run: | # substitute full group names sed -i 's/#### Ci/#### Continuous integration/' CHANGELOG.md @@ -92,11 +91,10 @@ jobs: GITHUB_TOKEN: ${{ github.token }} run: | ver="${{ steps.version.outputs.version }}" - changelog=$(cat ${{ steps.update-changelog.outputs.changelog }} | grep -v "### Version $ver") + changelog=$(cat CHANGELOG.md | grep -v "### Version $ver") # remove this release's changelog so we don't commit it # the changes have already been prepended to HISTORY.md - rm ${{ steps.update-changelog.outputs.changelog }} rm -f CHANGELOG.md # commit and push changes From 9de3c7f4a8f3d63aa947653433937dadb182c327 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 8 Feb 2024 13:36:52 +0000 Subject: [PATCH 34/34] ci(release): set version to 0.2.0, update changelog --- CITATION.cff | 2 +- HISTORY.md | 15 ++++++++++++++- autotest/test_interface.py | 8 ++------ modflowapi/version.py | 4 ++-- scripts/update_version.py | 4 +++- version.txt | 2 +- 6 files changed, 23 insertions(+), 12 deletions(-) diff --git a/CITATION.cff b/CITATION.cff index 21bd4a0..ccd7d09 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -3,7 +3,7 @@ message: If you use this software, please cite both the article from preferred-c and the software itself. type: software title: MODFLOW API -version: 0.2.0.dev0 +version: 0.2.0 date-released: '2023-04-19' abstract: An extension to xmipy for the MODFLOW API. repository-artifact: https://pypi.org/project/modflowapi diff --git a/HISTORY.md b/HISTORY.md index 44d5fa0..b774f65 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,4 +1,17 @@ # Changelog +### Version 0.2.0 + +#### Refactoring + +* [refactor(rhs, hcof)](https://github.com/MODFLOW-USGS/modflowapi/commit/c0f681c5b7525388ead4df8c6363c1b4514d6de6): Updates to allow setting values when rhs and hcof have not yet had pointers set.. Committed by Joshua Larsen on 2023-04-28. +* [refactor(Quickstart.ipynb)](https://github.com/MODFLOW-USGS/modflowapi/commit/3b6675aa687f5af01813abfdb143c7ddd4343646): Fix error in callback_function. Committed by Joshua Larsen on 2023-07-17. +* [refactor(rhs, hcof)](https://github.com/MODFLOW-USGS/modflowapi/commit/ce4e50286d66da51c6b05f0de29c7c646344f6ce): Allow setting rhs and hcof when pointers have not been previously set. Committed by Joshua Larsen on 2023-07-17. +* [refactor](https://github.com/MODFLOW-USGS/modflowapi/commit/e693282611d5863bafeece362230a4aadd02311f): Update libmf6 path handling (#27). Committed by w-bonelli on 2023-08-03. +* [refactor(_ptr_to_recarray)](https://github.com/MODFLOW-USGS/modflowapi/commit/5a631592f2da57bf1564c263e9602c46e5a5a50c): Slice pointers prior to setting data to recarray. Committed by Joshua Larsen on 2023-08-08. +* [refactor(_ptr_to_recarray)](https://github.com/MODFLOW-USGS/modflowapi/commit/959fe31abda263a52d01262af7dc4c2a878eadb5): Slice pointers prior to setting data to recarray. Committed by Joshua Larsen on 2023-08-08. +* [refactor(extensions)](https://github.com/MODFLOW-USGS/modflowapi/commit/c97339d06e7386055e486f6354825ec15cea4638): Add support for IDM changes. Committed by Joshua Larsen on 2023-12-21. +* [refactor(extensions)](https://github.com/MODFLOW-USGS/modflowapi/commit/de0aff9c21d5d925235f306fd2b3d148c3281efa): Add support for IDM changes. Committed by Joshua Larsen on 2023-12-21. + ### Version 0.1.0 * Fix typo in README (https://github.com/MODFLOW-USGS/modflowapi/pull/4) @@ -51,4 +64,4 @@ Co-authored-by: scottrp <45947939+scottrp@users.noreply.github.com> ### Version 0.0.1 -Initial release. \ No newline at end of file +Initial release. diff --git a/autotest/test_interface.py b/autotest/test_interface.py index 44be4ce..5027218 100644 --- a/autotest/test_interface.py +++ b/autotest/test_interface.py @@ -11,7 +11,7 @@ AdvancedPackage, ArrayPackage, ListPackage, - pkgvars + pkgvars, ) data_pth = Path("../examples/data") @@ -20,11 +20,7 @@ so = "libmf6" + ( ".so" if os == "Linux" - else ".dylib" - if os == "Darwin" - else ".dll" - if os == "Windows" - else None + else ".dylib" if os == "Darwin" else ".dll" if os == "Windows" else None ) if so is None: pytest.skip("Unsupported operating system", allow_module_level=True) diff --git a/modflowapi/version.py b/modflowapi/version.py index c16cb60..efc7e07 100644 --- a/modflowapi/version.py +++ b/modflowapi/version.py @@ -1,3 +1,3 @@ # modflowapi version file automatically created using...update_version.py -# created on...February 07, 2024 22:13:12 -__version__ = "0.2.0.dev0" +# created on...February 08, 2024 13:36:49 +__version__ = "0.2.0" diff --git a/scripts/update_version.py b/scripts/update_version.py index efbf1ac..bf3cc9f 100644 --- a/scripts/update_version.py +++ b/scripts/update_version.py @@ -33,7 +33,9 @@ def update_version_py(timestamp: datetime, version: Version): f"# {_project_name} version file automatically " + f"created using...{basename(__file__)}\n" ) - f.write("# created on..." + f"{timestamp.strftime('%B %d, %Y %H:%M:%S')}\n") + f.write( + "# created on..." + f"{timestamp.strftime('%B %d, %Y %H:%M:%S')}\n" + ) f.write(f'__version__ = "{version}"\n') log_update(_version_py_path, version) diff --git a/version.txt b/version.txt index 9a058eb..341cf11 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.2.0.dev0 \ No newline at end of file +0.2.0 \ No newline at end of file