mf6adj 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mf6adj-1.0.0/.gitignore +145 -0
- mf6adj-1.0.0/PKG-INFO +178 -0
- mf6adj-1.0.0/README.md +76 -0
- mf6adj-1.0.0/examples/clear_output_all.py +58 -0
- mf6adj-1.0.0/examples/dewater_demo.ipynb +661 -0
- mf6adj-1.0.0/examples/sanpedro_demo.ipynb +477 -0
- mf6adj-1.0.0/examples/structured_freyberg_demo.ipynb +700 -0
- mf6adj-1.0.0/examples/synthdewater/buildmodel_workflow.py.txt +3980 -0
- mf6adj-1.0.0/examples/synthdewater/dewater.wel +28 -0
- mf6adj-1.0.0/examples/synthdewater/dewater.wel_stress_period_data_1.txt +40 -0
- mf6adj-1.0.0/examples/synthdewater/dewater.wel_stress_period_data_2.txt +40 -0
- mf6adj-1.0.0/examples/synthdewater/dewater.wel_stress_period_data_3.txt +40 -0
- mf6adj-1.0.0/examples/synthdewater/dewater.wel_stress_period_data_4.txt +40 -0
- mf6adj-1.0.0/examples/synthdewater/inflow.ghb +11 -0
- mf6adj-1.0.0/examples/synthdewater/inflow.ghb_stress_period_data_1.txt +100 -0
- mf6adj-1.0.0/examples/synthdewater/mar.wel +26 -0
- mf6adj-1.0.0/examples/synthdewater/mar.wel_stress_period_data_1.txt +10 -0
- mf6adj-1.0.0/examples/synthdewater/mar.wel_stress_period_data_2.txt +10 -0
- mf6adj-1.0.0/examples/synthdewater/mar.wel_stress_period_data_3.txt +10 -0
- mf6adj-1.0.0/examples/synthdewater/mar.wel_stress_period_data_4.txt +10 -0
- mf6adj-1.0.0/examples/synthdewater/mfsim.nam +20 -0
- mf6adj-1.0.0/examples/synthdewater/model.dis +24 -0
- mf6adj-1.0.0/examples/synthdewater/model.dis_botm.txt +500 -0
- mf6adj-1.0.0/examples/synthdewater/model.dis_delc.txt +5 -0
- mf6adj-1.0.0/examples/synthdewater/model.dis_delr.txt +5 -0
- mf6adj-1.0.0/examples/synthdewater/model.dis_idomain.txt +500 -0
- mf6adj-1.0.0/examples/synthdewater/model.dis_top.txt +500 -0
- mf6adj-1.0.0/examples/synthdewater/model.drn +13 -0
- mf6adj-1.0.0/examples/synthdewater/model.drn.obs +9 -0
- mf6adj-1.0.0/examples/synthdewater/model.drn.obs_continuous_model.obs.drn.csv.txt +1 -0
- mf6adj-1.0.0/examples/synthdewater/model.drn_stress_period_data_1.txt +100 -0
- mf6adj-1.0.0/examples/synthdewater/model.ic +6 -0
- mf6adj-1.0.0/examples/synthdewater/model.ic_strt.txt +500 -0
- mf6adj-1.0.0/examples/synthdewater/model.nam +20 -0
- mf6adj-1.0.0/examples/synthdewater/model.npf +11 -0
- mf6adj-1.0.0/examples/synthdewater/model.npf_icelltype.txt +500 -0
- mf6adj-1.0.0/examples/synthdewater/model.npf_k.txt +100 -0
- mf6adj-1.0.0/examples/synthdewater/model.obs +13 -0
- mf6adj-1.0.0/examples/synthdewater/model.obs_continuous_model.obs.head.pit.csv.txt +100 -0
- mf6adj-1.0.0/examples/synthdewater/model.obs_continuous_model.obs.head.wel-mar.csv.txt +10 -0
- mf6adj-1.0.0/examples/synthdewater/model.oc +11 -0
- mf6adj-1.0.0/examples/synthdewater/model.rcha +10 -0
- mf6adj-1.0.0/examples/synthdewater/model.rcha_recharge_1.txt +500 -0
- mf6adj-1.0.0/examples/synthdewater/model.sto +22 -0
- mf6adj-1.0.0/examples/synthdewater/model.sto_iconvert.txt +500 -0
- mf6adj-1.0.0/examples/synthdewater/model.sto_ss.txt +500 -0
- mf6adj-1.0.0/examples/synthdewater/model.sto_sy.txt +500 -0
- mf6adj-1.0.0/examples/synthdewater/sim.ims +21 -0
- mf6adj-1.0.0/examples/synthdewater/sim.tdis +16 -0
- mf6adj-1.0.0/examples/xd_box_chd_ana/mfsim.nam +21 -0
- mf6adj-1.0.0/examples/xd_box_chd_ana/test.adj +9 -0
- mf6adj-1.0.0/examples/xd_box_chd_ana/xdbox.cbb +0 -0
- mf6adj-1.0.0/examples/xd_box_chd_ana/xdbox.chd +171 -0
- mf6adj-1.0.0/examples/xd_box_chd_ana/xdbox.dis +103 -0
- mf6adj-1.0.0/examples/xd_box_chd_ana/xdbox.ic +89 -0
- mf6adj-1.0.0/examples/xd_box_chd_ana/xdbox.ims +16 -0
- mf6adj-1.0.0/examples/xd_box_chd_ana/xdbox.nam +16 -0
- mf6adj-1.0.0/examples/xd_box_chd_ana/xdbox.npf +13 -0
- mf6adj-1.0.0/examples/xd_box_chd_ana/xdbox.oc +12 -0
- mf6adj-1.0.0/examples/xd_box_chd_ana/xdbox.sto +17 -0
- mf6adj-1.0.0/examples/xd_box_chd_ana/xdbox.tdis +13 -0
- mf6adj-1.0.0/examples/xd_box_chd_ana/xdbox.wel +8011 -0
- mf6adj-1.0.0/examples/xdbox_demo.ipynb +555 -0
- mf6adj-1.0.0/examples/zaidel_demo.ipynb +739 -0
- mf6adj-1.0.0/mf6adj/__init__.py +14 -0
- mf6adj-1.0.0/mf6adj/adj.py +1324 -0
- mf6adj-1.0.0/mf6adj/pm.py +1454 -0
- mf6adj-1.0.0/mf6adj/utils/utils.py +197 -0
- mf6adj-1.0.0/mf6adj/utils/utils_fileio.py +126 -0
- mf6adj-1.0.0/mf6adj/utils/utils_logger.py +95 -0
- mf6adj-1.0.0/mf6adj/utils/utils_modflow.py +280 -0
- mf6adj-1.0.0/mf6adj/utils/utils_pm_read.py +633 -0
- mf6adj-1.0.0/mf6adj/version.py +4 -0
- mf6adj-1.0.0/pyproject.toml +163 -0
mf6adj-1.0.0/.gitignore
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
pip-wheel-metadata/
|
|
24
|
+
share/python-wheels/
|
|
25
|
+
*.egg-info/
|
|
26
|
+
.installed.cfg
|
|
27
|
+
*.egg
|
|
28
|
+
MANIFEST
|
|
29
|
+
|
|
30
|
+
# PyInstaller
|
|
31
|
+
# Usually these files are written by a python script from a template
|
|
32
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
33
|
+
*.manifest
|
|
34
|
+
*.spec
|
|
35
|
+
|
|
36
|
+
# Installer logs
|
|
37
|
+
pip-log.txt
|
|
38
|
+
pip-delete-this-directory.txt
|
|
39
|
+
|
|
40
|
+
# Unit test / coverage reports
|
|
41
|
+
htmlcov/
|
|
42
|
+
.tox/
|
|
43
|
+
.nox/
|
|
44
|
+
.coverage
|
|
45
|
+
.coverage.*
|
|
46
|
+
.cache
|
|
47
|
+
nosetests.xml
|
|
48
|
+
coverage.xml
|
|
49
|
+
*.cover
|
|
50
|
+
*.py,cover
|
|
51
|
+
.hypothesis/
|
|
52
|
+
.pytest_cache/
|
|
53
|
+
|
|
54
|
+
# Translations
|
|
55
|
+
*.mo
|
|
56
|
+
*.pot
|
|
57
|
+
|
|
58
|
+
# Django stuff:
|
|
59
|
+
*.log
|
|
60
|
+
local_settings.py
|
|
61
|
+
db.sqlite3
|
|
62
|
+
db.sqlite3-journal
|
|
63
|
+
|
|
64
|
+
# Flask stuff:
|
|
65
|
+
instance/
|
|
66
|
+
.webassets-cache
|
|
67
|
+
|
|
68
|
+
# Scrapy stuff:
|
|
69
|
+
.scrapy
|
|
70
|
+
|
|
71
|
+
# Sphinx documentation
|
|
72
|
+
docs/_build/
|
|
73
|
+
docs/source/_api/
|
|
74
|
+
docs/source/examples/
|
|
75
|
+
|
|
76
|
+
# PyBuilder
|
|
77
|
+
target/
|
|
78
|
+
|
|
79
|
+
# Jupyter Notebook
|
|
80
|
+
.ipynb_checkpoints
|
|
81
|
+
|
|
82
|
+
# IPython
|
|
83
|
+
profile_default/
|
|
84
|
+
ipython_config.py
|
|
85
|
+
|
|
86
|
+
# pyenv
|
|
87
|
+
.python-version
|
|
88
|
+
|
|
89
|
+
# pipenv
|
|
90
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
91
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
92
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
93
|
+
# install all needed dependencies.
|
|
94
|
+
#Pipfile.lock
|
|
95
|
+
|
|
96
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
|
97
|
+
__pypackages__/
|
|
98
|
+
|
|
99
|
+
# Celery stuff
|
|
100
|
+
celerybeat-schedule
|
|
101
|
+
celerybeat.pid
|
|
102
|
+
|
|
103
|
+
# SageMath parsed files
|
|
104
|
+
*.sage.py
|
|
105
|
+
|
|
106
|
+
# Environments
|
|
107
|
+
.env
|
|
108
|
+
.venv
|
|
109
|
+
env/
|
|
110
|
+
venv/
|
|
111
|
+
ENV/
|
|
112
|
+
env.bak/
|
|
113
|
+
venv.bak/
|
|
114
|
+
|
|
115
|
+
# Spyder project settings
|
|
116
|
+
.spyderproject
|
|
117
|
+
.spyproject
|
|
118
|
+
|
|
119
|
+
# Rope project settings
|
|
120
|
+
.ropeproject
|
|
121
|
+
|
|
122
|
+
# mkdocs documentation
|
|
123
|
+
/site
|
|
124
|
+
|
|
125
|
+
# mypy
|
|
126
|
+
.mypy_cache/
|
|
127
|
+
.dmypy.json
|
|
128
|
+
dmypy.json
|
|
129
|
+
|
|
130
|
+
# Pyre type checker
|
|
131
|
+
.pyre/
|
|
132
|
+
|
|
133
|
+
# MacOS files
|
|
134
|
+
.DS_Store
|
|
135
|
+
|
|
136
|
+
# Examples result directories
|
|
137
|
+
examples/ex-gwf-zaidel/
|
|
138
|
+
examples/freyberg/
|
|
139
|
+
examples/sanpedro/
|
|
140
|
+
examples/xd_box_chd_ana_working
|
|
141
|
+
examples/synthdewater_working
|
|
142
|
+
autotest/*_test*/
|
|
143
|
+
.figures/
|
|
144
|
+
|
|
145
|
+
.temp/
|
mf6adj-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mf6adj
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: mf6adj is a Python package for adjoint-state sensitivity analysis with MODFLOW 6
|
|
5
|
+
Project-URL: Documentation, https://mf6adj.readthedocs.io
|
|
6
|
+
Project-URL: Bug Tracker, https://github.com/INTERA-Inc/mf6adj/issues
|
|
7
|
+
Project-URL: Source Code, https://github.com/INTERA-Inc/mf6adj
|
|
8
|
+
Author: INTERA Incorporated
|
|
9
|
+
Maintainer: INTERA Incorporated
|
|
10
|
+
License: CC0-1.0
|
|
11
|
+
Keywords: MODFLOW,adjoint,groundwater,hydrogeology
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: License :: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
|
|
15
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Hydrology
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Requires-Dist: flopy>=3.10.0
|
|
22
|
+
Requires-Dist: geopandas>=1.0.0
|
|
23
|
+
Requires-Dist: h5py>=3.0.0
|
|
24
|
+
Requires-Dist: matplotlib>=3.5.0
|
|
25
|
+
Requires-Dist: modflowapi>=0.2.0
|
|
26
|
+
Requires-Dist: numpy>=2.0
|
|
27
|
+
Requires-Dist: pandas>=2.0.0
|
|
28
|
+
Requires-Dist: pyemu>=1.4.0
|
|
29
|
+
Requires-Dist: scipy>=1.7.0
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: boltons; extra == 'dev'
|
|
32
|
+
Requires-Dist: codespell[toml]>=2.2.2; extra == 'dev'
|
|
33
|
+
Requires-Dist: filelock; extra == 'dev'
|
|
34
|
+
Requires-Dist: flaky; extra == 'dev'
|
|
35
|
+
Requires-Dist: ipykernel; extra == 'dev'
|
|
36
|
+
Requires-Dist: jupyter; extra == 'dev'
|
|
37
|
+
Requires-Dist: jupyter-client>=8.4.0; extra == 'dev'
|
|
38
|
+
Requires-Dist: modflow-devtools>=1.9.1; extra == 'dev'
|
|
39
|
+
Requires-Dist: myst-parser; extra == 'dev'
|
|
40
|
+
Requires-Dist: nbconvert; extra == 'dev'
|
|
41
|
+
Requires-Dist: nbmake; extra == 'dev'
|
|
42
|
+
Requires-Dist: nbsphinx; extra == 'dev'
|
|
43
|
+
Requires-Dist: pytest-cov; extra == 'dev'
|
|
44
|
+
Requires-Dist: pytest-dotenv; extra == 'dev'
|
|
45
|
+
Requires-Dist: pytest-order; extra == 'dev'
|
|
46
|
+
Requires-Dist: pytest-xdist; extra == 'dev'
|
|
47
|
+
Requires-Dist: pytest>=9.0.2; extra == 'dev'
|
|
48
|
+
Requires-Dist: pyyaml; extra == 'dev'
|
|
49
|
+
Requires-Dist: rtds-action; extra == 'dev'
|
|
50
|
+
Requires-Dist: ruff; extra == 'dev'
|
|
51
|
+
Requires-Dist: shapely; extra == 'dev'
|
|
52
|
+
Requires-Dist: sphinx-rtd-theme>=1; extra == 'dev'
|
|
53
|
+
Requires-Dist: sphinx>=7.1.2; extra == 'dev'
|
|
54
|
+
Requires-Dist: tomli-w; extra == 'dev'
|
|
55
|
+
Provides-Extra: doc
|
|
56
|
+
Requires-Dist: boltons; extra == 'doc'
|
|
57
|
+
Requires-Dist: codespell[toml]>=2.2.2; extra == 'doc'
|
|
58
|
+
Requires-Dist: filelock; extra == 'doc'
|
|
59
|
+
Requires-Dist: flaky; extra == 'doc'
|
|
60
|
+
Requires-Dist: ipykernel; extra == 'doc'
|
|
61
|
+
Requires-Dist: jupyter; extra == 'doc'
|
|
62
|
+
Requires-Dist: jupyter-client>=8.4.0; extra == 'doc'
|
|
63
|
+
Requires-Dist: modflow-devtools>=1.9.1; extra == 'doc'
|
|
64
|
+
Requires-Dist: myst-parser; extra == 'doc'
|
|
65
|
+
Requires-Dist: nbconvert; extra == 'doc'
|
|
66
|
+
Requires-Dist: nbmake; extra == 'doc'
|
|
67
|
+
Requires-Dist: nbsphinx; extra == 'doc'
|
|
68
|
+
Requires-Dist: pytest-cov; extra == 'doc'
|
|
69
|
+
Requires-Dist: pytest-dotenv; extra == 'doc'
|
|
70
|
+
Requires-Dist: pytest-order; extra == 'doc'
|
|
71
|
+
Requires-Dist: pytest-xdist; extra == 'doc'
|
|
72
|
+
Requires-Dist: pytest>=9.0.2; extra == 'doc'
|
|
73
|
+
Requires-Dist: pyyaml; extra == 'doc'
|
|
74
|
+
Requires-Dist: rtds-action; extra == 'doc'
|
|
75
|
+
Requires-Dist: ruff; extra == 'doc'
|
|
76
|
+
Requires-Dist: shapely; extra == 'doc'
|
|
77
|
+
Requires-Dist: sphinx-rtd-theme>=1; extra == 'doc'
|
|
78
|
+
Requires-Dist: sphinx>=7.1.2; extra == 'doc'
|
|
79
|
+
Requires-Dist: tomli-w; extra == 'doc'
|
|
80
|
+
Provides-Extra: lint
|
|
81
|
+
Requires-Dist: codespell[toml]>=2.2.2; extra == 'lint'
|
|
82
|
+
Requires-Dist: ruff; extra == 'lint'
|
|
83
|
+
Provides-Extra: test
|
|
84
|
+
Requires-Dist: boltons; extra == 'test'
|
|
85
|
+
Requires-Dist: codespell[toml]>=2.2.2; extra == 'test'
|
|
86
|
+
Requires-Dist: filelock; extra == 'test'
|
|
87
|
+
Requires-Dist: flaky; extra == 'test'
|
|
88
|
+
Requires-Dist: ipykernel; extra == 'test'
|
|
89
|
+
Requires-Dist: jupyter; extra == 'test'
|
|
90
|
+
Requires-Dist: jupyter-client>=8.4.0; extra == 'test'
|
|
91
|
+
Requires-Dist: modflow-devtools>=1.9.1; extra == 'test'
|
|
92
|
+
Requires-Dist: nbmake; extra == 'test'
|
|
93
|
+
Requires-Dist: pytest-cov; extra == 'test'
|
|
94
|
+
Requires-Dist: pytest-dotenv; extra == 'test'
|
|
95
|
+
Requires-Dist: pytest-order; extra == 'test'
|
|
96
|
+
Requires-Dist: pytest-xdist; extra == 'test'
|
|
97
|
+
Requires-Dist: pytest>=9.0.2; extra == 'test'
|
|
98
|
+
Requires-Dist: ruff; extra == 'test'
|
|
99
|
+
Requires-Dist: shapely; extra == 'test'
|
|
100
|
+
Requires-Dist: tomli-w; extra == 'test'
|
|
101
|
+
Description-Content-Type: text/markdown
|
|
102
|
+
|
|
103
|
+
# mf6adj
|
|
104
|
+
|
|
105
|
+

|
|
106
|
+
|
|
107
|
+
**mf6adj** is a Python package for adjoint-state sensitivity analysis with
|
|
108
|
+
MODFLOW 6. It uses the [MODFLOW 6 API](https://github.com/MODFLOW-USGS/modflowapi)
|
|
109
|
+
to access the internal solution components at run time — no modifications to
|
|
110
|
+
MODFLOW 6 are required. Given one or more user-defined performance measures
|
|
111
|
+
(heads, boundary fluxes, or composite objectives), mf6adj computes the
|
|
112
|
+
sensitivity of each measure to model parameters across the full model domain.
|
|
113
|
+
|
|
114
|
+
## Installation
|
|
115
|
+
|
|
116
|
+
**pip**
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
pip install mf6adj
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**conda-forge**
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
conda install -c conda-forge mf6adj
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
mf6adj drives MODFLOW 6 through its shared library (`libmf6`). The easiest
|
|
129
|
+
way to get both is through the
|
|
130
|
+
[`flopy`](https://github.com/modflowpy/flopy) helper:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
get-modflow --subset mf6,libmf6 :python
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Quick start
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
import flopy
|
|
140
|
+
import mf6adj
|
|
141
|
+
|
|
142
|
+
# locate the MF6 binary and shared library in the active conda environment
|
|
143
|
+
mf6_bin, lib_name = mf6adj.get_conda_mf6_paths()
|
|
144
|
+
|
|
145
|
+
# run the baseline forward model
|
|
146
|
+
flopy.run_model(exe_name=mf6_bin, namefile=None, model_ws="path/to/model")
|
|
147
|
+
|
|
148
|
+
# write a performance-measure file
|
|
149
|
+
with open("path/to/model/model.adj", "w") as f:
|
|
150
|
+
f.write("begin performance_measure head_obs\n")
|
|
151
|
+
f.write("1 1 1 5 5 head direct 1.0 -1.0e+30\n")
|
|
152
|
+
f.write("end performance_measure\n")
|
|
153
|
+
|
|
154
|
+
# solve forward and adjoint
|
|
155
|
+
adj = mf6adj.Mf6Adj("model.adj", str(lib_name), working_directory="path/to/model")
|
|
156
|
+
adj.solve_forward_model()
|
|
157
|
+
sensitivity_dfs = adj.solve_adjoint()
|
|
158
|
+
adj.finalize()
|
|
159
|
+
|
|
160
|
+
print(sensitivity_dfs["head_obs"])
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Documentation
|
|
164
|
+
|
|
165
|
+
Full documentation, including API reference and example notebooks, is available
|
|
166
|
+
at [mf6adj.readthedocs.io](https://md6adj.readthedocs.io).
|
|
167
|
+
|
|
168
|
+
## How to cite
|
|
169
|
+
|
|
170
|
+
If you use mf6adj in your work, please cite:
|
|
171
|
+
|
|
172
|
+
> Hayek, M., White, J. T., Markovich, K. H., Hughes, J. D., & Lavenue, M. (2025).
|
|
173
|
+
> MF6-ADJ: A Non-Intrusive Adjoint Sensitivity Capability for MODFLOW 6.
|
|
174
|
+
> *Groundwater*, 63(6), 874–888. https://doi.org/10.1111/gwat.70025
|
|
175
|
+
|
|
176
|
+
## License
|
|
177
|
+
|
|
178
|
+
[CC0 1.0 Universal](https://creativecommons.org/publicdomain/zero/1.0/)
|
mf6adj-1.0.0/README.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# mf6adj
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
**mf6adj** is a Python package for adjoint-state sensitivity analysis with
|
|
6
|
+
MODFLOW 6. It uses the [MODFLOW 6 API](https://github.com/MODFLOW-USGS/modflowapi)
|
|
7
|
+
to access the internal solution components at run time — no modifications to
|
|
8
|
+
MODFLOW 6 are required. Given one or more user-defined performance measures
|
|
9
|
+
(heads, boundary fluxes, or composite objectives), mf6adj computes the
|
|
10
|
+
sensitivity of each measure to model parameters across the full model domain.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
**pip**
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install mf6adj
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**conda-forge**
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
conda install -c conda-forge mf6adj
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
mf6adj drives MODFLOW 6 through its shared library (`libmf6`). The easiest
|
|
27
|
+
way to get both is through the
|
|
28
|
+
[`flopy`](https://github.com/modflowpy/flopy) helper:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
get-modflow --subset mf6,libmf6 :python
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Quick start
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
import flopy
|
|
38
|
+
import mf6adj
|
|
39
|
+
|
|
40
|
+
# locate the MF6 binary and shared library in the active conda environment
|
|
41
|
+
mf6_bin, lib_name = mf6adj.get_conda_mf6_paths()
|
|
42
|
+
|
|
43
|
+
# run the baseline forward model
|
|
44
|
+
flopy.run_model(exe_name=mf6_bin, namefile=None, model_ws="path/to/model")
|
|
45
|
+
|
|
46
|
+
# write a performance-measure file
|
|
47
|
+
with open("path/to/model/model.adj", "w") as f:
|
|
48
|
+
f.write("begin performance_measure head_obs\n")
|
|
49
|
+
f.write("1 1 1 5 5 head direct 1.0 -1.0e+30\n")
|
|
50
|
+
f.write("end performance_measure\n")
|
|
51
|
+
|
|
52
|
+
# solve forward and adjoint
|
|
53
|
+
adj = mf6adj.Mf6Adj("model.adj", str(lib_name), working_directory="path/to/model")
|
|
54
|
+
adj.solve_forward_model()
|
|
55
|
+
sensitivity_dfs = adj.solve_adjoint()
|
|
56
|
+
adj.finalize()
|
|
57
|
+
|
|
58
|
+
print(sensitivity_dfs["head_obs"])
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Documentation
|
|
62
|
+
|
|
63
|
+
Full documentation, including API reference and example notebooks, is available
|
|
64
|
+
at [mf6adj.readthedocs.io](https://md6adj.readthedocs.io).
|
|
65
|
+
|
|
66
|
+
## How to cite
|
|
67
|
+
|
|
68
|
+
If you use mf6adj in your work, please cite:
|
|
69
|
+
|
|
70
|
+
> Hayek, M., White, J. T., Markovich, K. H., Hughes, J. D., & Lavenue, M. (2025).
|
|
71
|
+
> MF6-ADJ: A Non-Intrusive Adjoint Sensitivity Capability for MODFLOW 6.
|
|
72
|
+
> *Groundwater*, 63(6), 874–888. https://doi.org/10.1111/gwat.70025
|
|
73
|
+
|
|
74
|
+
## License
|
|
75
|
+
|
|
76
|
+
[CC0 1.0 Universal](https://creativecommons.org/publicdomain/zero/1.0/)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import pathlib as pl
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def find_files_with_extension(directory, extension):
|
|
6
|
+
"""
|
|
7
|
+
Finds all files with the specified extension in the given directory and
|
|
8
|
+
its subdirectories.
|
|
9
|
+
|
|
10
|
+
Args:
|
|
11
|
+
directory: The path to the directory to search.
|
|
12
|
+
extension: The file extension to search for (e.g., ".txt", ".pdf").
|
|
13
|
+
|
|
14
|
+
Returns:
|
|
15
|
+
A list of Path objects representing the files found.
|
|
16
|
+
"""
|
|
17
|
+
path = pl.Path(directory)
|
|
18
|
+
if not path.is_dir():
|
|
19
|
+
raise NotADirectoryError(f"'{directory}' is not a valid directory.")
|
|
20
|
+
|
|
21
|
+
return list(path.rglob(f"*{extension}"))
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
directory_path = ".."
|
|
25
|
+
file_extension = ".ipynb"
|
|
26
|
+
exclude_paths = (
|
|
27
|
+
".ipynb_checkpoints",
|
|
28
|
+
"site-packages",
|
|
29
|
+
".temp",
|
|
30
|
+
)
|
|
31
|
+
notebook_count = 0
|
|
32
|
+
try:
|
|
33
|
+
files = find_files_with_extension(directory_path, file_extension)
|
|
34
|
+
if files:
|
|
35
|
+
print(f"Files with extension '{file_extension}' found in '{directory_path}':")
|
|
36
|
+
for file in files:
|
|
37
|
+
exclude = False
|
|
38
|
+
for epath in exclude_paths:
|
|
39
|
+
if epath in str(file):
|
|
40
|
+
exclude = True
|
|
41
|
+
break
|
|
42
|
+
if exclude:
|
|
43
|
+
print(f"skipping...{file}")
|
|
44
|
+
else:
|
|
45
|
+
print(f"clearing...{file}")
|
|
46
|
+
os.system(
|
|
47
|
+
"jupyter nbconvert --ClearOutputPreprocessor.enabled=True "
|
|
48
|
+
+ f"--ClearMetadataPreprocessor.enabled=True --inplace {file}"
|
|
49
|
+
)
|
|
50
|
+
notebook_count += 1
|
|
51
|
+
else:
|
|
52
|
+
print(
|
|
53
|
+
f"No files with extension '{file_extension}' found in '{directory_path}'."
|
|
54
|
+
)
|
|
55
|
+
print(f"notebooks cleared...{notebook_count}")
|
|
56
|
+
|
|
57
|
+
except NotADirectoryError as e:
|
|
58
|
+
print(e)
|