From 612dd111259bcc8658026d14a3fc732f10771a88 Mon Sep 17 00:00:00 2001 From: jdhughes-usgs Date: Tue, 11 May 2021 17:46:36 -0400 Subject: [PATCH 1/2] Initial release v 0.0.1 --- .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 400780ea1ecf92233ad0a18ab14e58e2f0a3de1c Mon Sep 17 00:00:00 2001 From: jdhughes-usgs Date: Wed, 19 Apr 2023 16:41:57 -0500 Subject: [PATCH 2/2] V0.1.0 (#15) * Fix typo in README (#4) * 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 * 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> * 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 (#12) * Use pyproject.toml for project metadata, add citation info (#11) * 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 * 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 * release: v0.1.0 --------- Co-authored-by: Hofer-Julian <30049909+Hofer-Julian@users.noreply.github.com> Co-authored-by: Joshua Larsen Co-authored-by: spaulins-usgs Co-authored-by: scottrp <45947939+scottrp@users.noreply.github.com> Co-authored-by: Mike Taves --- .flake8 | 41 +- .gitattributes | 1 - .github/workflows/ci.yml | 123 +- CITATION.cff | 61 + README.md | 21 +- autotest/__init__.py | 1 + autotest/conftest.py | 138 ++ autotest/pytest.ini | 7 + autotest/test_interface.py | 372 +++ autotest/test_mf6_examples.py | 53 + etc/requirements.pip.txt | 11 - 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 +++++ guide-to-publish.md | 10 +- modflowapi/__init__.py | 4 +- modflowapi/extensions/__init__.py | 3 + modflowapi/extensions/apiexchange.py | 20 + modflowapi/extensions/apimodel.py | 384 ++++ modflowapi/extensions/apisimulation.py | 353 +++ modflowapi/extensions/data.py | 732 ++++++ modflowapi/extensions/pakbase.py | 726 ++++++ modflowapi/extensions/runner.py | 150 ++ modflowapi/version.py | 6 + pyproject.toml | 67 + setup.py | 54 +- 100 files changed, 9065 insertions(+), 112 deletions(-) create mode 100644 CITATION.cff 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 delete mode 100644 etc/requirements.pip.txt 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 pyproject.toml 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/.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/.github/workflows/ci.yml b/.github/workflows/ci.yml index e7d23ef..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: @@ -26,12 +26,12 @@ 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 + - name: Setup Python + uses: actions/setup-python@v4 with: - python-version: 3.8 + python-version: 3.x - name: Upgrade pip run: | @@ -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,31 +59,31 @@ 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 + - name: Setup Python + uses: actions/setup-python@v4 with: - python-version: 3.8 + python-version: 3.x - name: Print python version run: | python --version - - name: Install Python 3.8 packages + - name: Install Python packages run: | python -m pip install --upgrade pip - pip install -r etc/requirements.pip.txt + 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: | @@ -93,3 +93,92 @@ 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", "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: ~/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", "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: ~/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" diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 0000000..8e9e2ea --- /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.1.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 +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 8c77c70..f20da3a 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,25 @@ # 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. + +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. -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 +``` + +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/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..9413bdd --- /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.", + ) diff --git a/autotest/pytest.ini b/autotest/pytest.ini new file mode 100644 index 0000000..63e2571 --- /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 diff --git a/autotest/test_interface.py b/autotest/test_interface.py new file mode 100644 index 0000000..45f11a3 --- /dev/null +++ b/autotest/test_interface.py @@ -0,0 +1,372 @@ +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) + + +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/autotest/test_mf6_examples.py b/autotest/test_mf6_examples.py new file mode 100644 index 0000000..72c89d2 --- /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 deleted file mode 100644 index 7091d3b..0000000 --- a/etc/requirements.pip.txt +++ /dev/null @@ -1,11 +0,0 @@ -black -flake8 -pylint -nose -nose-timer -coverage -requests -appdirs -numpy -bmipy -xmipy diff --git a/examples/data/ats0/gwf_ats01a.ats b/examples/data/ats0/gwf_ats01a.ats new file mode 100644 index 0000000..703eb58 --- /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..d32b5a4 --- /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..d0cec89 --- /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..cdeae07 --- /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..40086cf --- /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..41819b1 --- /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..c44027f --- /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..bba9adf --- /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..909efb2 --- /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..5a82c66 --- /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..1427d85 --- /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..9fd3033 --- /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..3f95669 --- /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..f1ec84b --- /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..a3b56a2 --- /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..13e5658 --- /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..08afd2a --- /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..70e727f --- /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..2190fe4 --- /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..c644a65 --- /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..2a4522d --- /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..42b6bc6 --- /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..93314c0 --- /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..5803723 --- /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..18ffbcf --- /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..78af964 --- /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..cd7fa9e --- /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..c886096 --- /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..33d510d --- /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..2b4023a --- /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..844449b --- /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..fdebe57 --- /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..21df1fb --- /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..235104a --- /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..59c7597 --- /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..807b23a --- /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..c266a68 --- /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..1d515fc --- /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..47b311a --- /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/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/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..9fa55e0 --- /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..46de560 --- /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..d899d7d --- /dev/null +++ b/modflowapi/extensions/apimodel.py @@ -0,0 +1,384 @@ +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, + "riv": 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..5d96dde --- /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..5449558 --- /dev/null +++ b/modflowapi/extensions/data.py @@ -0,0 +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") diff --git a/modflowapi/extensions/pakbase.py b/modflowapi/extensions/pakbase.py new file mode 100644 index 0000000..19be40c --- /dev/null +++ b/modflowapi/extensions/pakbase.py @@ -0,0 +1,726 @@ +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", + ], + "riv": [ + "maxbound", + "nbound", + "nodelist", + ("bound", ("stage", "cond", "rbot")), + "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..bd2a8d5 --- /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..2f94b78 --- /dev/null +++ b/modflowapi/version.py @@ -0,0 +1,6 @@ +# version file for modflowapi + +major = 0 +minor = 1 +micro = 0 +__version__ = f"{major}.{minor}.{micro}" 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.py b/setup.py old mode 100755 new mode 100644 index f308c77..5507373 --- 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"], -) +# see pyproject.toml for project metadata +setup(name="modflowapi")