swatplus-bmi 0.1.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.
Files changed (42) hide show
  1. swatplus_bmi-0.1.0/.gitignore +9 -0
  2. swatplus_bmi-0.1.0/CHANGELOG.md +26 -0
  3. swatplus_bmi-0.1.0/CITATION.cff +31 -0
  4. swatplus_bmi-0.1.0/CODE_OF_CONDUCT.md +11 -0
  5. swatplus_bmi-0.1.0/COMPATIBILITY.md +39 -0
  6. swatplus_bmi-0.1.0/CONTRIBUTING.md +54 -0
  7. swatplus_bmi-0.1.0/LICENSE +10 -0
  8. swatplus_bmi-0.1.0/LICENSES/BSD-3-Clause.txt +28 -0
  9. swatplus_bmi-0.1.0/LICENSES/LGPL-2.1.txt +504 -0
  10. swatplus_bmi-0.1.0/PKG-INFO +415 -0
  11. swatplus_bmi-0.1.0/README.md +388 -0
  12. swatplus_bmi-0.1.0/build.sh +109 -0
  13. swatplus_bmi-0.1.0/docs/design.md +427 -0
  14. swatplus_bmi-0.1.0/docs/figures/tour-feedback.png +0 -0
  15. swatplus_bmi-0.1.0/docs/figures/tour-state.png +0 -0
  16. swatplus_bmi-0.1.0/docs/figures/tour-tradeoff.png +0 -0
  17. swatplus_bmi-0.1.0/docs/figures/tour-warmup.png +0 -0
  18. swatplus_bmi-0.1.0/docs/upstream-issue-aquifer-withdrawal.md +29 -0
  19. swatplus_bmi-0.1.0/docs/upstream-issue-recall-diversion.md +41 -0
  20. swatplus_bmi-0.1.0/docs/upstream-issue.md +37 -0
  21. swatplus_bmi-0.1.0/examples/tour.py +560 -0
  22. swatplus_bmi-0.1.0/fortran/bmi_exchange_module.f90 +931 -0
  23. swatplus_bmi-0.1.0/fortran/bmi_fork.c +53 -0
  24. swatplus_bmi-0.1.0/patches/62.0.1/0001-exchange-mode.patch +102 -0
  25. swatplus_bmi-0.1.0/patches/62.0.1/carried-locals.toml +12 -0
  26. swatplus_bmi-0.1.0/pyproject.toml +60 -0
  27. swatplus_bmi-0.1.0/src/swatplus_bmi/__init__.py +7 -0
  28. swatplus_bmi-0.1.0/src/swatplus_bmi/bmi.py +333 -0
  29. swatplus_bmi-0.1.0/src/swatplus_bmi/build.py +109 -0
  30. swatplus_bmi-0.1.0/src/swatplus_bmi/exchange.py +319 -0
  31. swatplus_bmi-0.1.0/tests/conftest.py +122 -0
  32. swatplus_bmi-0.1.0/tests/test_allocation.py +204 -0
  33. swatplus_bmi-0.1.0/tests/test_branch.py +101 -0
  34. swatplus_bmi-0.1.0/tests/test_reading.py +99 -0
  35. swatplus_bmi-0.1.0/tests/test_saved_locals.py +39 -0
  36. swatplus_bmi-0.1.0/tests/test_setting.py +163 -0
  37. swatplus_bmi-0.1.0/tests/test_state.py +151 -0
  38. swatplus_bmi-0.1.0/tests/test_stepping.py +165 -0
  39. swatplus_bmi-0.1.0/tools/carried_locals.py +90 -0
  40. swatplus_bmi-0.1.0/tools/gen_serializer.py +345 -0
  41. swatplus_bmi-0.1.0/tools/reset_saved_locals.py +198 -0
  42. swatplus_bmi-0.1.0/tools/state_inventory.py +230 -0
@@ -0,0 +1,9 @@
1
+ .cache/
2
+ build/
3
+ bin/
4
+ .venv/
5
+ __pycache__/
6
+ *.egg-info/
7
+ .pytest_cache/
8
+ tests/runs/
9
+ examples/runs/
@@ -0,0 +1,26 @@
1
+ # Changelog
2
+
3
+ Changes that matter to someone using swatplus-bmi. Versions follow semantic versioning; the
4
+ SWAT+ releases each version supports are in COMPATIBILITY.md.
5
+
6
+ ## 0.1.0 (2026-11-04)
7
+
8
+ First release, for SWAT+ 62.0.1.
9
+
10
+ - Exchange mode for SWAT+, off unless started with `--exchange`: SWAT+ pauses before each day
11
+ and takes commands on standard input. Six calls in three SWAT+ files, one Fortran module, and
12
+ a C helper for branching (Mac, Linux).
13
+ - Python BMI 2.0 wrapper (`SwatPlusBmi`): one-day steps, time in days since the start date, one
14
+ grid of points per object type, CSDMS-style names.
15
+ - Reading: channel outflow, inflow and storage; aquifer storage, depth to water, outflow and
16
+ recharge; point source flow; water allocation demand and withdrawal.
17
+ - Setting, for the next day: point source flow, water allocation demand.
18
+ - Snapshots:
19
+ - `branch()` forks the paused process (Mac, Linux);
20
+ - `save_state`/`load_state` and `get_state`/`set_state` work on every platform, with the
21
+ serializer generated from SWAT+'s module declarations;
22
+ - saved locals that carry state are listed per release and saved too.
23
+ - `swatplus-bmi build` fetches, patches and builds SWAT+ from an installed package.
24
+ - Tests against unpatched SWAT+: every output file byte for byte, every variable against SWAT+'s
25
+ daily output, water balances, branching and saving against unbroken runs.
26
+ - Example marimo notebook (`examples/tour.py`).
@@ -0,0 +1,31 @@
1
+ cff-version: 1.2.0
2
+ message: "If you use swatplus-bmi in your work, please cite it as below."
3
+ title: "swatplus-bmi: stepping the SWAT+ watershed model one day at a time through the Basic Model Interface"
4
+ type: software
5
+ authors:
6
+ - family-names: Sommerlot
7
+ given-names: Andrew
8
+ affiliation: Northline Hydrology
9
+ # orcid: https://orcid.org/0000-0000-0000-0000
10
+ version: 0.1.0
11
+ license:
12
+ - BSD-3-Clause
13
+ - LGPL-2.1-only
14
+ repository-code: "https://github.com/northlinehydrology/swatplus-bmi"
15
+ keywords:
16
+ - hydrology
17
+ - watershed modeling
18
+ - SWAT+
19
+ - Basic Model Interface
20
+ - BMI
21
+ - model coupling
22
+ references:
23
+ - type: article
24
+ title: "Introduction to SWAT+, a completely restructured version of the Soil and Water Assessment Tool"
25
+ authors:
26
+ - family-names: Bieger
27
+ given-names: Katrin
28
+ - name: "and others"
29
+ journal: "Journal of the American Water Resources Association"
30
+ year: 2017
31
+ doi: 10.1111/1752-1688.12482
@@ -0,0 +1,11 @@
1
+ # Code of conduct
2
+
3
+ This project follows the [Contributor Covenant, version 2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct/).
4
+
5
+ In short: be respectful and constructive, assume good faith, and keep discussion about the
6
+ work. Harassment and personal attacks aren't tolerated in issues, pull requests or any other
7
+ project space.
8
+
9
+ Report a problem to the maintainer, Andrew Sommerlot, at andrew@northlinehydrology.com. Reports
10
+ are kept confidential. The maintainer will respond, and may warn, suspend or remove anyone who
11
+ doesn't follow this code, as the Contributor Covenant's enforcement guidelines describe.
@@ -0,0 +1,39 @@
1
+ # SWAT+ versions
2
+
3
+ swatplus-bmi patches a specific SWAT+ release. A version is supported only if
4
+ it has a folder in `patches/` and passes the full test suite. `build.sh`
5
+ refuses any other version.
6
+
7
+ | SWAT+ | Released | Status | Tested on |
8
+ |---|---|---|---|
9
+ | 62.0.1 | 2026-10-19 | **Supported** | CI on every push: Ubuntu (gfortran from apt) and macOS 14 (Homebrew gcc). Locally: macOS 14 arm64, gfortran 16.1. |
10
+ | main | rolling | Watched: built and tested nightly with the 62.0.1 patch, as an early warning. Not supported. | nightly build |
11
+ | 62.0.0 | 2026-06-18 | Not supported: the patch doesn't apply (`time_control.f90` differs) | — |
12
+ | 61.x and earlier | 2024–2026 | Not supported: no water allocation places of use, and the patch doesn't apply | — |
13
+
14
+ Checked Nov 4, 2026: the patch applies unchanged to SWAT+ main as of commit
15
+ 6f51536 (Oct 16, 2026). `time_control.f90`, `command.f90` and `main.f90.in`
16
+ are identical to 62.0.1 there.
17
+
18
+ ## How SWAT+ versions work
19
+
20
+ SWAT+ numbers its releases by model revision (the "Revision" line in
21
+ `simulation.out`), not semantic versioning: the 60.x series came before 61.x,
22
+ and 62 is the current series. Full releases are infrequent: 61.0.1 (Jul 2024),
23
+ 61.0.2 (Aug 2024), 62.0.0 (Jun 2026), 62.0.1 (Oct 2026). Between them the
24
+ SWAT+ team tags prereleases (twelve 61.0.2.x tags, Nov 2024 to Jan 2026),
25
+ and the main branch takes merged pull requests continuously.
26
+
27
+ ## Policy
28
+
29
+ - Each supported release gets its own `patches/<tag>/` folder. A new SWAT+
30
+ release is added when the patch is moved onto it and the full suite
31
+ passes, including the byte-for-byte comparisons with stock SWAT+.
32
+ - Only full releases are supported, not prereleases or main.
33
+ - The nightly build tests main with the newest supported patch. When it
34
+ fails, a new SWAT+ release is likely to need a new patch.
35
+ - An older release stays supported as long as its patch still builds and
36
+ passes. It isn't fixed for new features.
37
+ - If the exchange mode is merged into SWAT+ itself, the patch is no longer
38
+ needed from that release on, and this table records which SWAT+ release
39
+ has it built in.
@@ -0,0 +1,54 @@
1
+ # Contributing
2
+
3
+ swatplus-bmi is meant to be used in studies whose results feed public decisions about water,
4
+ so a change has to keep the one promise the project makes: **SWAT+ stepped, branched or loaded
5
+ through swatplus-bmi gives exactly the output SWAT+ gives on its own.** Every rule below follows
6
+ from that.
7
+
8
+ ## Ways to contribute
9
+
10
+ - **Report a bug.** Open an issue with the SWAT+ version, your platform and compiler, what you
11
+ ran, and what happened. A SWAT+ project that shows the problem is the most useful thing you
12
+ can attach.
13
+ - **Share a test project.** The tests run on the two example projects that ship with SWAT+, and
14
+ those exercise about half of SWAT+'s code. A project that uses reservoirs, pesticides, salts,
15
+ gwflow or calibration, and can be made public, would widen the tests more than anything else.
16
+ - **Ask for a variable.** Say what you want to read or set, which SWAT+ variable holds it, and
17
+ what you'd check it against.
18
+ - **Pull requests** are welcome for fixes, variables, tests and documentation. For a larger
19
+ change (a new SWAT+ release, a protocol change), open an issue first.
20
+ - **Questions:** open an issue with the `question` label.
21
+
22
+ ## Rules for changes
23
+
24
+ 1. **Identical output.** The comparison tests against unpatched SWAT+ must pass. If a change
25
+ can't keep SWAT+'s output identical, it doesn't go in.
26
+ 2. **A test for every variable.** A new variable is checked against SWAT+'s own output files,
27
+ every day, in `tests/test_reading.py` or `tests/test_setting.py`.
28
+ 3. **Only fluxes can be set.** Storage, land use, soils and parameters stay scenario inputs.
29
+ 4. **The patch stays small.** Changes to SWAT+'s own files go in `patches/<tag>/`, and as few as
30
+ possible. Everything else goes in new files in `fortran/`.
31
+ 5. **Generated code is generated.** Don't edit `bmi_state_module.f90` or `bmi_locals_module.f90`;
32
+ change the generators in `tools/`.
33
+ 6. **A new SWAT+ release** gets its own `patches/<tag>/` folder, a `carried-locals.toml` checked
34
+ with `build.sh --nosave` and `pytest -m full`, and a line in COMPATIBILITY.md.
35
+ 7. **Plain writing.** Documentation and comments say what the code does and why, plainly.
36
+
37
+ ## Running the checks
38
+
39
+ ```bash
40
+ uv sync
41
+ uv run ./build.sh --stock --nosave
42
+ uv run pytest # about two minutes
43
+ uv run pytest -m full # about fifteen minutes more
44
+ ```
45
+
46
+ ## Conduct
47
+
48
+ Everyone taking part follows the [code of conduct](CODE_OF_CONDUCT.md).
49
+
50
+ ## License of contributions
51
+
52
+ Contributions to `fortran/` and `patches/` are under the GNU LGPL 2.1, like SWAT+. Everything
53
+ else is under the BSD 3-Clause license. By opening a pull request you agree to license your
54
+ contribution that way.
@@ -0,0 +1,10 @@
1
+ swatplus-bmi is under two licenses.
2
+
3
+ - fortran/ and patches/ (the exchange mode added to SWAT+) and any SWAT+
4
+ built with them: GNU Lesser General Public License, version 2.1, the
5
+ license of SWAT+ itself. See LICENSES/LGPL-2.1.txt.
6
+
7
+ - Everything else, including the Python wrapper in src/swatplus_bmi/, the
8
+ tests, tools and documentation: BSD 3-Clause. See LICENSES/BSD-3-Clause.txt. The wrapper is
9
+ a separate program: it starts SWAT+ as its own process and talks to it
10
+ over standard input and output, and is not linked with it.
@@ -0,0 +1,28 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2026, Andrew Sommerlot
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.