aquimodpy 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.
- aquimodpy-1.0.0/.github/workflows/ci.yml +23 -0
- aquimodpy-1.0.0/.gitignore +19 -0
- aquimodpy-1.0.0/.python-version +1 -0
- aquimodpy-1.0.0/LICENSE +21 -0
- aquimodpy-1.0.0/PKG-INFO +134 -0
- aquimodpy-1.0.0/README.md +120 -0
- aquimodpy-1.0.0/docs/api.md +11 -0
- aquimodpy-1.0.0/docs/index.md +41 -0
- aquimodpy-1.0.0/mkdocs.yml +28 -0
- aquimodpy-1.0.0/pyproject.toml +50 -0
- aquimodpy-1.0.0/src/aquimodpy/CalibrationRunner.py +48 -0
- aquimodpy-1.0.0/src/aquimodpy/Components.py +726 -0
- aquimodpy-1.0.0/src/aquimodpy/EvaluationRunner.py +47 -0
- aquimodpy-1.0.0/src/aquimodpy/Model.py +262 -0
- aquimodpy-1.0.0/src/aquimodpy/Runner.py +99 -0
- aquimodpy-1.0.0/src/aquimodpy/__init__.py +45 -0
- aquimodpy-1.0.0/tests/test_all_components.py +125 -0
- aquimodpy-1.0.0/tests/test_components.py +40 -0
- aquimodpy-1.0.0/tests/test_model.py +65 -0
- aquimodpy-1.0.0/tests/test_model_setup.py +80 -0
- aquimodpy-1.0.0/tests/test_observations.py +92 -0
- aquimodpy-1.0.0/tests/test_runners.py +51 -0
- aquimodpy-1.0.0/uv.lock +1345 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on: [push, pull_request]
|
|
4
|
+
|
|
5
|
+
jobs:
|
|
6
|
+
test:
|
|
7
|
+
runs-on: ubuntu-latest
|
|
8
|
+
steps:
|
|
9
|
+
- uses: actions/checkout@v4
|
|
10
|
+
- name: Install uv
|
|
11
|
+
uses: astral-sh/setup-uv@v5
|
|
12
|
+
with:
|
|
13
|
+
enable-cache: true
|
|
14
|
+
- name: Set up Python
|
|
15
|
+
run: uv python install 3.14
|
|
16
|
+
- name: Install dependencies
|
|
17
|
+
run: uv sync --group dev --group test
|
|
18
|
+
- name: Check formatting (Black)
|
|
19
|
+
run: uv run black --check src tests
|
|
20
|
+
- name: Type checking (Mypy)
|
|
21
|
+
run: uv run mypy src
|
|
22
|
+
- name: Run tests (Pytest)
|
|
23
|
+
run: uv run pytest tests
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.14
|
aquimodpy-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 aquimodpy contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
aquimodpy-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: aquimodpy
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Python wrapper for Aquimod 2
|
|
5
|
+
Author: Arran Clarke
|
|
6
|
+
License: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Requires-Python: >=3.14
|
|
12
|
+
Requires-Dist: pandas>=3.0.3
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
|
|
15
|
+
# aquimodpy
|
|
16
|
+
|
|
17
|
+
A Python wrapper for the British Geological Survey's **AquiMod 2**, a lumped parameter groundwater model.
|
|
18
|
+
|
|
19
|
+
## Features
|
|
20
|
+
|
|
21
|
+
- **IDE Support**: Full autocompletion and parameter validation in modern editors.
|
|
22
|
+
- **Modular Design**: Support for all Soil Zone (FAO, NSSS, SMAP), Unsaturated Zone (Weibull), and Saturated Zone (Q3K3S1, VKD, SA1D, etc.) components.
|
|
23
|
+
- **Automated Configuration**: Generates all required input files (`Input.txt`, `Observations.txt`, and component-specific parameter files) with correct Windows-style formatting for Wine compatibility.
|
|
24
|
+
- **Simulation Modes**: Full support for Evaluation, Monte Carlo calibration, and SCE-UA global optimization.
|
|
25
|
+
- **Cross-Platform**: Flexible execution support; specify your preferred command prefix (e.g., `["wine"]`, `["box86"]`) for running the Windows binary on non-Windows systems.
|
|
26
|
+
- **Data Integration**: Seamless integration with Pandas for observation input and result parsing.
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# Clone the repository
|
|
32
|
+
git clone https://github.com/your-repo/aquimodpy.git
|
|
33
|
+
cd aquimodpy
|
|
34
|
+
|
|
35
|
+
# Install dependencies (using uv)
|
|
36
|
+
uv pip install -e .
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Quick Start
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
import pandas as pd
|
|
43
|
+
from aquimodpy import Model, FAO, Weibull, Q3K3S1, Observations, EvaluationRunner
|
|
44
|
+
|
|
45
|
+
# 1. Initialize the model
|
|
46
|
+
model = Model(
|
|
47
|
+
model_name="MySimulation",
|
|
48
|
+
executable_path="~/Documents/AquiMod2/AquiMod2.exe",
|
|
49
|
+
working_directory="./simulation_results",
|
|
50
|
+
exec_prefix=["wine"] # Use ["wine"] for Linux or [] for native Windows
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
# 2. Add components using named arguments
|
|
54
|
+
# Units and special characters are handled automatically!
|
|
55
|
+
FAO(
|
|
56
|
+
model,
|
|
57
|
+
theta_fc=0.4,
|
|
58
|
+
theta_wp=0.1,
|
|
59
|
+
Z_r=1000,
|
|
60
|
+
p=0.5,
|
|
61
|
+
BFI=0.8
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
Weibull(
|
|
65
|
+
model,
|
|
66
|
+
k=2.0,
|
|
67
|
+
lambda_=5.0 # Use lambda_ as 'lambda' is a Python keyword
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
Q3K3S1(
|
|
71
|
+
model,
|
|
72
|
+
dx=1000,
|
|
73
|
+
K3=10,
|
|
74
|
+
K2=5,
|
|
75
|
+
K1=1,
|
|
76
|
+
S=0.01,
|
|
77
|
+
z3=50,
|
|
78
|
+
z2=40,
|
|
79
|
+
z1=30,
|
|
80
|
+
alpha=1
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
# 3. Add observations and map column names
|
|
84
|
+
df = pd.read_csv("my_data.csv")
|
|
85
|
+
Observations(model, df, {
|
|
86
|
+
"DATE": "date_col",
|
|
87
|
+
"RAIN": "rainfall_mm",
|
|
88
|
+
"PET": "pet_mm",
|
|
89
|
+
"GWL": "gw_level_m"
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
# 4. Configure and run
|
|
93
|
+
model.set_runner(EvaluationRunner(model))
|
|
94
|
+
model.setup()
|
|
95
|
+
model.run()
|
|
96
|
+
|
|
97
|
+
# 5. Analyze results
|
|
98
|
+
results = model.get_results()
|
|
99
|
+
print(results['Sat'].head())
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Calibration and Optimization
|
|
103
|
+
|
|
104
|
+
### Monte Carlo Calibration
|
|
105
|
+
Provide `[min, max]` lists for parameters you wish to calibrate.
|
|
106
|
+
```python
|
|
107
|
+
from aquimodpy import CalibrationRunner
|
|
108
|
+
model.set_runner(CalibrationRunner(model))
|
|
109
|
+
model.set_simulation_mode('m', n_runs=10000, threshold=0.5, variable='g')
|
|
110
|
+
|
|
111
|
+
# Calibrate Z_r and BFI, keep others fixed
|
|
112
|
+
FAO(
|
|
113
|
+
model,
|
|
114
|
+
theta_fc=0.35,
|
|
115
|
+
theta_wp=0.1,
|
|
116
|
+
Z_r=[500, 3000],
|
|
117
|
+
p=0.5,
|
|
118
|
+
BFI=[0.1, 0.99]
|
|
119
|
+
)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### SCE-UA Optimization
|
|
123
|
+
```python
|
|
124
|
+
model.set_simulation_mode('s', n_loops=100, n_complexes=50, variable='g')
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## License and Attribution
|
|
128
|
+
|
|
129
|
+
This library is licensed under the **MIT License**.
|
|
130
|
+
|
|
131
|
+
This project provides a wrapper for **AquiMod 2**, which is owned by the British Geological Survey (BGS) and is licensed under the [Open Government Licence v3.0](https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/).
|
|
132
|
+
|
|
133
|
+
Please note that this library does not include the AquiMod 2 binary. You can download the AquiMod 2 software from the [official BGS website](https://www.bgs.ac.uk/technologies/software/aquimod/). Users are responsible for obtaining the binary independently and complying with the terms of the Open Government Licence as specified by the BGS.
|
|
134
|
+
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# aquimodpy
|
|
2
|
+
|
|
3
|
+
A Python wrapper for the British Geological Survey's **AquiMod 2**, a lumped parameter groundwater model.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **IDE Support**: Full autocompletion and parameter validation in modern editors.
|
|
8
|
+
- **Modular Design**: Support for all Soil Zone (FAO, NSSS, SMAP), Unsaturated Zone (Weibull), and Saturated Zone (Q3K3S1, VKD, SA1D, etc.) components.
|
|
9
|
+
- **Automated Configuration**: Generates all required input files (`Input.txt`, `Observations.txt`, and component-specific parameter files) with correct Windows-style formatting for Wine compatibility.
|
|
10
|
+
- **Simulation Modes**: Full support for Evaluation, Monte Carlo calibration, and SCE-UA global optimization.
|
|
11
|
+
- **Cross-Platform**: Flexible execution support; specify your preferred command prefix (e.g., `["wine"]`, `["box86"]`) for running the Windows binary on non-Windows systems.
|
|
12
|
+
- **Data Integration**: Seamless integration with Pandas for observation input and result parsing.
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# Clone the repository
|
|
18
|
+
git clone https://github.com/your-repo/aquimodpy.git
|
|
19
|
+
cd aquimodpy
|
|
20
|
+
|
|
21
|
+
# Install dependencies (using uv)
|
|
22
|
+
uv pip install -e .
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
import pandas as pd
|
|
29
|
+
from aquimodpy import Model, FAO, Weibull, Q3K3S1, Observations, EvaluationRunner
|
|
30
|
+
|
|
31
|
+
# 1. Initialize the model
|
|
32
|
+
model = Model(
|
|
33
|
+
model_name="MySimulation",
|
|
34
|
+
executable_path="~/Documents/AquiMod2/AquiMod2.exe",
|
|
35
|
+
working_directory="./simulation_results",
|
|
36
|
+
exec_prefix=["wine"] # Use ["wine"] for Linux or [] for native Windows
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
# 2. Add components using named arguments
|
|
40
|
+
# Units and special characters are handled automatically!
|
|
41
|
+
FAO(
|
|
42
|
+
model,
|
|
43
|
+
theta_fc=0.4,
|
|
44
|
+
theta_wp=0.1,
|
|
45
|
+
Z_r=1000,
|
|
46
|
+
p=0.5,
|
|
47
|
+
BFI=0.8
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
Weibull(
|
|
51
|
+
model,
|
|
52
|
+
k=2.0,
|
|
53
|
+
lambda_=5.0 # Use lambda_ as 'lambda' is a Python keyword
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
Q3K3S1(
|
|
57
|
+
model,
|
|
58
|
+
dx=1000,
|
|
59
|
+
K3=10,
|
|
60
|
+
K2=5,
|
|
61
|
+
K1=1,
|
|
62
|
+
S=0.01,
|
|
63
|
+
z3=50,
|
|
64
|
+
z2=40,
|
|
65
|
+
z1=30,
|
|
66
|
+
alpha=1
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# 3. Add observations and map column names
|
|
70
|
+
df = pd.read_csv("my_data.csv")
|
|
71
|
+
Observations(model, df, {
|
|
72
|
+
"DATE": "date_col",
|
|
73
|
+
"RAIN": "rainfall_mm",
|
|
74
|
+
"PET": "pet_mm",
|
|
75
|
+
"GWL": "gw_level_m"
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
# 4. Configure and run
|
|
79
|
+
model.set_runner(EvaluationRunner(model))
|
|
80
|
+
model.setup()
|
|
81
|
+
model.run()
|
|
82
|
+
|
|
83
|
+
# 5. Analyze results
|
|
84
|
+
results = model.get_results()
|
|
85
|
+
print(results['Sat'].head())
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Calibration and Optimization
|
|
89
|
+
|
|
90
|
+
### Monte Carlo Calibration
|
|
91
|
+
Provide `[min, max]` lists for parameters you wish to calibrate.
|
|
92
|
+
```python
|
|
93
|
+
from aquimodpy import CalibrationRunner
|
|
94
|
+
model.set_runner(CalibrationRunner(model))
|
|
95
|
+
model.set_simulation_mode('m', n_runs=10000, threshold=0.5, variable='g')
|
|
96
|
+
|
|
97
|
+
# Calibrate Z_r and BFI, keep others fixed
|
|
98
|
+
FAO(
|
|
99
|
+
model,
|
|
100
|
+
theta_fc=0.35,
|
|
101
|
+
theta_wp=0.1,
|
|
102
|
+
Z_r=[500, 3000],
|
|
103
|
+
p=0.5,
|
|
104
|
+
BFI=[0.1, 0.99]
|
|
105
|
+
)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### SCE-UA Optimization
|
|
109
|
+
```python
|
|
110
|
+
model.set_simulation_mode('s', n_loops=100, n_complexes=50, variable='g')
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## License and Attribution
|
|
114
|
+
|
|
115
|
+
This library is licensed under the **MIT License**.
|
|
116
|
+
|
|
117
|
+
This project provides a wrapper for **AquiMod 2**, which is owned by the British Geological Survey (BGS) and is licensed under the [Open Government Licence v3.0](https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/).
|
|
118
|
+
|
|
119
|
+
Please note that this library does not include the AquiMod 2 binary. You can download the AquiMod 2 software from the [official BGS website](https://www.bgs.ac.uk/technologies/software/aquimod/). Users are responsible for obtaining the binary independently and complying with the terms of the Open Government Licence as specified by the BGS.
|
|
120
|
+
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Welcome to aquimodpy
|
|
2
|
+
|
|
3
|
+
`aquimodpy` is a Python wrapper for the British Geological Survey's **AquiMod 2**, a lumped parameter groundwater model. It provides a clean, Pythonic interface to define complex hydrogeological models.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
This library allows you to:
|
|
7
|
+
- Define soil, unsaturated, and saturated zone components using intuitive named arguments.
|
|
8
|
+
- Seamlessly integrate with Pandas for input data and model observation.
|
|
9
|
+
- Manage simulation runs (evaluation, Monte Carlo calibration, and SCE-UA optimization) through dedicated runner classes.
|
|
10
|
+
- Run the original AquiMod 2 Windows binary on Linux environments using Wine.
|
|
11
|
+
|
|
12
|
+
## Quick Start
|
|
13
|
+
```python
|
|
14
|
+
import pandas as pd
|
|
15
|
+
from aquimodpy import Model, FAO, Weibull, Q3K3S1, Observations, EvaluationRunner
|
|
16
|
+
|
|
17
|
+
# Initialize the model
|
|
18
|
+
model = Model("MySim", "~/path/to/AquiMod2.exe", "./results")
|
|
19
|
+
|
|
20
|
+
# Configure components
|
|
21
|
+
FAO(model, theta_fc=0.4, theta_wp=0.1, Z_r=1000, p=0.5, BFI=0.8)
|
|
22
|
+
Weibull(model, k=2.0, lambda_=5.0)
|
|
23
|
+
Q3K3S1(model, dx=1000, K3=10, K2=5, K1=1, S=0.01, z3=50, z2=40, z1=30, alpha=1)
|
|
24
|
+
|
|
25
|
+
# Set observations and run
|
|
26
|
+
df = pd.read_csv("data.csv")
|
|
27
|
+
Observations(model, df, {"DATE": "date", "RAIN": "rain", "PET": "pet", "GWL": "gwl"})
|
|
28
|
+
|
|
29
|
+
model.set_runner(EvaluationRunner(model))
|
|
30
|
+
model.run()
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## API Reference
|
|
34
|
+
Navigate through the core components of the library:
|
|
35
|
+
|
|
36
|
+
- [Model Configuration](api.md#aquimodpy.Model)
|
|
37
|
+
- [Observation Handling](api.md#aquimodpy.Components.Observations)
|
|
38
|
+
- [Soil Components](api.md#aquimodpy.Components.FAO)
|
|
39
|
+
- [Unsaturated Zone](api.md#aquimodpy.Components.Weibull)
|
|
40
|
+
- [Saturated Zone](api.md#aquimodpy.Components.Q3K3S1)
|
|
41
|
+
- [Simulation Runners](api.md#aquimodpy.EvaluationRunner)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
site_name: aquimodpy
|
|
2
|
+
theme:
|
|
3
|
+
name: material
|
|
4
|
+
|
|
5
|
+
nav:
|
|
6
|
+
- Home: index.md
|
|
7
|
+
- API Reference: api.md
|
|
8
|
+
|
|
9
|
+
plugins:
|
|
10
|
+
- search
|
|
11
|
+
- mkdocstrings:
|
|
12
|
+
default_handler: python
|
|
13
|
+
handlers:
|
|
14
|
+
python:
|
|
15
|
+
paths: [src]
|
|
16
|
+
options:
|
|
17
|
+
show_source: true
|
|
18
|
+
show_root_heading: true
|
|
19
|
+
members_order: source
|
|
20
|
+
show_if_no_docstring: true
|
|
21
|
+
show_bases: true
|
|
22
|
+
show_source: true
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
markdown_extensions:
|
|
26
|
+
- admonition
|
|
27
|
+
- pymdownx.details
|
|
28
|
+
- pymdownx.superfences
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "aquimodpy"
|
|
3
|
+
version = "1.0.0"
|
|
4
|
+
description = "Python wrapper for Aquimod 2"
|
|
5
|
+
authors = [{name = "Arran Clarke"}]
|
|
6
|
+
license = {text = "MIT"}
|
|
7
|
+
readme = "README.md"
|
|
8
|
+
requires-python = ">=3.14"
|
|
9
|
+
dependencies = [
|
|
10
|
+
"pandas>=3.0.3",
|
|
11
|
+
]
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Programming Language :: Python :: 3",
|
|
14
|
+
"License :: OSI Approved :: MIT License",
|
|
15
|
+
"Operating System :: OS Independent",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
[build-system]
|
|
19
|
+
requires = ["hatchling"]
|
|
20
|
+
build-backend = "hatchling.build"
|
|
21
|
+
|
|
22
|
+
[tool.hatch.build.targets.wheel]
|
|
23
|
+
packages = ["src/aquimodpy"]
|
|
24
|
+
|
|
25
|
+
[dependency-groups]
|
|
26
|
+
dev = [
|
|
27
|
+
"black>=26.5.0",
|
|
28
|
+
"build>=1.5.0",
|
|
29
|
+
"mkdocs>=1.6.1",
|
|
30
|
+
"mkdocs-material>=9.7.6",
|
|
31
|
+
"mkdocstrings[python]>=1.0.4",
|
|
32
|
+
"mypy>=2.1.0",
|
|
33
|
+
"pandas-stubs>=3.0.0.260204",
|
|
34
|
+
"pytest>=9.0.3",
|
|
35
|
+
"pytest-cov>=7.1.0",
|
|
36
|
+
"twine>=6.2.0",
|
|
37
|
+
]
|
|
38
|
+
test = [
|
|
39
|
+
"matplotlib>=3.10.9",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
[tool.pytest.ini_options]
|
|
43
|
+
pythonpath = ["src"]
|
|
44
|
+
testpaths = ["tests"]
|
|
45
|
+
|
|
46
|
+
[tool.mypy]
|
|
47
|
+
python_version = "3.14"
|
|
48
|
+
warn_return_any = true
|
|
49
|
+
warn_unused_configs = true
|
|
50
|
+
disallow_untyped_defs = true
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING
|
|
2
|
+
from .Runner import Runner
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from .Model import Model
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class CalibrationRunner(Runner):
|
|
10
|
+
"""Runner for Monte Carlo and SCE-UA calibration simulations."""
|
|
11
|
+
|
|
12
|
+
def prepare(self) -> None:
|
|
13
|
+
"""Prepares calibration simulation."""
|
|
14
|
+
super().prepare()
|
|
15
|
+
# Generate component calibration files
|
|
16
|
+
self.write_component_calib_files()
|
|
17
|
+
|
|
18
|
+
def write_component_calib_files(self) -> None:
|
|
19
|
+
"""Writes *_calib.txt files in the Calibration directory."""
|
|
20
|
+
calib_dir = os.path.join(self.model.working_directory, "Calibration")
|
|
21
|
+
|
|
22
|
+
components = [self.model.soil_zone, self.model.unsat_zone, self.model.sat_zone]
|
|
23
|
+
|
|
24
|
+
for comp in components:
|
|
25
|
+
if comp:
|
|
26
|
+
comp_name = comp.__class__.__name__
|
|
27
|
+
file_path = os.path.join(calib_dir, f"{comp_name}_calib.txt")
|
|
28
|
+
|
|
29
|
+
# Ensure parameters are written in the correct order specified in REQUIRED_PARAMETERS
|
|
30
|
+
if isinstance(comp.parameters, dict):
|
|
31
|
+
with open(file_path, "w", newline="") as f:
|
|
32
|
+
for param_name in comp.REQUIRED_PARAMETERS:
|
|
33
|
+
bounds = comp.parameters.get(param_name)
|
|
34
|
+
if bounds is None:
|
|
35
|
+
continue # Should not happen due to validation
|
|
36
|
+
|
|
37
|
+
# Ensure bounds is a list/tuple of two values
|
|
38
|
+
if (
|
|
39
|
+
not isinstance(bounds, (list, tuple))
|
|
40
|
+
or len(bounds) != 2
|
|
41
|
+
):
|
|
42
|
+
# If it's a single value, treat it as fixed
|
|
43
|
+
b = [bounds, bounds]
|
|
44
|
+
else:
|
|
45
|
+
b = list(bounds)
|
|
46
|
+
|
|
47
|
+
f.write(f"{param_name}\r\n")
|
|
48
|
+
f.write(f"{b[0]} {b[1]}\r\n\r\n")
|