hydrosovereign 6.5.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.
- hydrosovereign-6.5.0/LICENSE +19 -0
- hydrosovereign-6.5.0/PKG-INFO +140 -0
- hydrosovereign-6.5.0/README.md +100 -0
- hydrosovereign-6.5.0/hydrosovereign/__init__.py +41 -0
- hydrosovereign-6.5.0/hydrosovereign/__main__.py +6 -0
- hydrosovereign-6.5.0/hydrosovereign/alerts.py +61 -0
- hydrosovereign-6.5.0/hydrosovereign/api.py +170 -0
- hydrosovereign-6.5.0/hydrosovereign/api_server.py +293 -0
- hydrosovereign-6.5.0/hydrosovereign/async_alerts.py +142 -0
- hydrosovereign-6.5.0/hydrosovereign/basins.py +113 -0
- hydrosovereign-6.5.0/hydrosovereign/cli.py +126 -0
- hydrosovereign-6.5.0/hydrosovereign/data/__init__.py +20 -0
- hydrosovereign-6.5.0/hydrosovereign/data/fetchers.py +647 -0
- hydrosovereign-6.5.0/hydrosovereign/data/nile_basin_sample.json +12801 -0
- hydrosovereign-6.5.0/hydrosovereign/hbv.py +344 -0
- hydrosovereign-6.5.0/hydrosovereign/indices.py +154 -0
- hydrosovereign-6.5.0/hydrosovereign/legal.py +94 -0
- hydrosovereign-6.5.0/hydrosovereign/models/__init__.py +11 -0
- hydrosovereign-6.5.0/hydrosovereign/models/hbv.py +193 -0
- hydrosovereign-6.5.0/hydrosovereign/viz/__init__.py +35 -0
- hydrosovereign-6.5.0/hydrosovereign/viz/maps.py +240 -0
- hydrosovereign-6.5.0/hydrosovereign/viz/plots.py +401 -0
- hydrosovereign-6.5.0/hydrosovereign.egg-info/PKG-INFO +140 -0
- hydrosovereign-6.5.0/hydrosovereign.egg-info/SOURCES.txt +30 -0
- hydrosovereign-6.5.0/hydrosovereign.egg-info/dependency_links.txt +1 -0
- hydrosovereign-6.5.0/hydrosovereign.egg-info/entry_points.txt +3 -0
- hydrosovereign-6.5.0/hydrosovereign.egg-info/requires.txt +22 -0
- hydrosovereign-6.5.0/hydrosovereign.egg-info/top_level.txt +1 -0
- hydrosovereign-6.5.0/pyproject.toml +54 -0
- hydrosovereign-6.5.0/setup.cfg +4 -0
- hydrosovereign-6.5.0/tests/test_core.py +189 -0
- hydrosovereign-6.5.0/tests/test_package.py +312 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
GNU GENERAL PUBLIC LICENSE
|
|
2
|
+
Version 3, 29 June 2007
|
|
3
|
+
|
|
4
|
+
Copyright (C) 2026 Seifeldin M.G. Alkedir
|
|
5
|
+
ORCID: 0000-0003-0821-2991
|
|
6
|
+
University of Khartoum
|
|
7
|
+
|
|
8
|
+
This program is free software: you can redistribute it and/or modify
|
|
9
|
+
it under the terms of the GNU General Public License as published by
|
|
10
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
11
|
+
(at your option) any later version.
|
|
12
|
+
|
|
13
|
+
This program is distributed in the hope that it will be useful,
|
|
14
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
15
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
16
|
+
GNU General Public License for more details.
|
|
17
|
+
|
|
18
|
+
You should have received a copy of the GNU General Public License
|
|
19
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hydrosovereign
|
|
3
|
+
Version: 6.5.0
|
|
4
|
+
Summary: HydroSovereign AI Engine — Python package for hydrological analysis, satellite data, and water sovereignty assessment
|
|
5
|
+
Author-email: "Seifeldin M.G. Alkedir" <saifeldinkhedir@gmail.com>
|
|
6
|
+
License: GPL-3.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/saifeldinkhedir-coder/hydrosovereign
|
|
8
|
+
Project-URL: DOI, https://doi.org/10.5281/zenodo.19180160
|
|
9
|
+
Keywords: hydrology,GEE,satellite,water,HSAE,reservoir
|
|
10
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
+
Classifier: Intended Audience :: Science/Research
|
|
12
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Hydrology
|
|
19
|
+
Requires-Python: >=3.9
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: numpy>=1.24
|
|
23
|
+
Requires-Dist: pandas>=2.0
|
|
24
|
+
Requires-Dist: scipy>=1.10
|
|
25
|
+
Requires-Dist: requests>=2.31
|
|
26
|
+
Provides-Extra: gee
|
|
27
|
+
Requires-Dist: earthengine-api>=0.1.400; extra == "gee"
|
|
28
|
+
Provides-Extra: viz
|
|
29
|
+
Requires-Dist: plotly>=5.18; extra == "viz"
|
|
30
|
+
Requires-Dist: folium>=0.16; extra == "viz"
|
|
31
|
+
Requires-Dist: matplotlib>=3.7; extra == "viz"
|
|
32
|
+
Provides-Extra: server
|
|
33
|
+
Requires-Dist: fastapi>=0.110; extra == "server"
|
|
34
|
+
Requires-Dist: uvicorn>=0.27; extra == "server"
|
|
35
|
+
Provides-Extra: alerts
|
|
36
|
+
Requires-Dist: python-telegram-bot>=20.0; extra == "alerts"
|
|
37
|
+
Provides-Extra: all
|
|
38
|
+
Requires-Dist: hydrosovereign[alerts,gee,server,viz]; extra == "all"
|
|
39
|
+
Dynamic: license-file
|
|
40
|
+
|
|
41
|
+
# HydroSovereign AI Engine (HSAE)
|
|
42
|
+
|
|
43
|
+
[](https://pypi.org/project/hydrosovereign/)
|
|
44
|
+
[](https://doi.org/10.5281/zenodo.19180160)
|
|
45
|
+
[](https://www.gnu.org/licenses/gpl-3.0)
|
|
46
|
+
[](https://www.python.org/downloads/)
|
|
47
|
+
|
|
48
|
+
**Author:** Seifeldin M.G. Alkedir · ORCID: [0000-0003-0821-2991](https://orcid.org/0000-0003-0821-2991)
|
|
49
|
+
**Affiliation:** University of Khartoum
|
|
50
|
+
**DOI:** [10.5281/zenodo.19180160](https://doi.org/10.5281/zenodo.19180160)
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Overview
|
|
55
|
+
|
|
56
|
+
HydroSovereign AI Engine (HSAE) v6.5.0 is a Python package for:
|
|
57
|
+
|
|
58
|
+
- **Hydrological basin analysis** — water balance, inflow, outflow, storage
|
|
59
|
+
- **Real satellite data ingestion** — GPM IMERG, GRACE-FO, Sentinel-1/2, SMAP, GloFAS, ERA5
|
|
60
|
+
- **Water sovereignty assessment** — Alkedir Transparency Deficit Index (ATDI)
|
|
61
|
+
- **Forensic hydrology** — closure error, mass balance analysis
|
|
62
|
+
- **HBV rainfall-runoff modelling** — calibration and simulation
|
|
63
|
+
- **AI ensemble forecasting** — Random Forest, ensemble methods
|
|
64
|
+
|
|
65
|
+
## Installation
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
pip install hydrosovereign
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
With optional dependencies:
|
|
72
|
+
```bash
|
|
73
|
+
pip install hydrosovereign[gee] # Google Earth Engine support
|
|
74
|
+
pip install hydrosovereign[viz] # Plotly + Folium visualizations
|
|
75
|
+
pip install hydrosovereign[all] # All dependencies
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Quick Start
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
import hydrosovereign as hsae
|
|
82
|
+
|
|
83
|
+
# Analyze a basin
|
|
84
|
+
result = hsae.analyze_basin(
|
|
85
|
+
basin_id = "GERD_ETH",
|
|
86
|
+
start_date = "2024-01-01",
|
|
87
|
+
end_date = "2024-12-31",
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
print(result["nse"]) # Nash-Sutcliffe Efficiency
|
|
91
|
+
print(result["atdi"]) # Alkedir Transparency Deficit Index
|
|
92
|
+
print(result["volume"]) # Reservoir volume (BCM)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
# Fetch real satellite data
|
|
97
|
+
from hydrosovereign.data import fetch_basin_forcing
|
|
98
|
+
|
|
99
|
+
forcing = fetch_basin_forcing("GERD_ETH", "2024-01-01", "2024-12-31")
|
|
100
|
+
print(forcing["gpm"]["mean_P"]) # GPM precipitation mm/day
|
|
101
|
+
print(forcing["grace"]["tws_cm"]) # GRACE-FO TWS anomaly
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
# HBV rainfall-runoff model
|
|
106
|
+
from hydrosovereign.models import HBVModel
|
|
107
|
+
|
|
108
|
+
model = HBVModel()
|
|
109
|
+
model.fit(P=forcing["P"], T=forcing["T"], Q_obs=forcing["Q"])
|
|
110
|
+
print(f"NSE = {model.nse:.3f}")
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## CLI
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
hydrosovereign analyze --basin GERD_ETH --year 2024
|
|
117
|
+
hydrosovereign fetch-gee --basin KAINJI_NGA --start 2023-01-01 --end 2023-12-31
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Live Application
|
|
121
|
+
|
|
122
|
+
The full HSAE v6.01 Streamlit application:
|
|
123
|
+
🌐 [https://hydrosovereign-ai-engine-hsae-v601-6euz2zxcmerkzxgordmvxf.streamlit.app](https://hydrosovereign-ai-engine-hsae-v601-6euz2zxcmerkzxgordmvxf.streamlit.app)
|
|
124
|
+
|
|
125
|
+
## Citation
|
|
126
|
+
|
|
127
|
+
```bibtex
|
|
128
|
+
@software{alkedir2026hsae,
|
|
129
|
+
author = {Alkedir, Seifeldin M.G.},
|
|
130
|
+
title = {HydroSovereign AI Engine (HSAE) v6.5.0},
|
|
131
|
+
year = {2026},
|
|
132
|
+
doi = {10.5281/zenodo.19180160},
|
|
133
|
+
url = {https://github.com/saifeldinkhedir-coder/hydrosovereign},
|
|
134
|
+
orcid = {0000-0003-0821-2991},
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## License
|
|
139
|
+
|
|
140
|
+
GNU General Public License v3.0 — see [LICENSE](LICENSE)
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# HydroSovereign AI Engine (HSAE)
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/hydrosovereign/)
|
|
4
|
+
[](https://doi.org/10.5281/zenodo.19180160)
|
|
5
|
+
[](https://www.gnu.org/licenses/gpl-3.0)
|
|
6
|
+
[](https://www.python.org/downloads/)
|
|
7
|
+
|
|
8
|
+
**Author:** Seifeldin M.G. Alkedir · ORCID: [0000-0003-0821-2991](https://orcid.org/0000-0003-0821-2991)
|
|
9
|
+
**Affiliation:** University of Khartoum
|
|
10
|
+
**DOI:** [10.5281/zenodo.19180160](https://doi.org/10.5281/zenodo.19180160)
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Overview
|
|
15
|
+
|
|
16
|
+
HydroSovereign AI Engine (HSAE) v6.5.0 is a Python package for:
|
|
17
|
+
|
|
18
|
+
- **Hydrological basin analysis** — water balance, inflow, outflow, storage
|
|
19
|
+
- **Real satellite data ingestion** — GPM IMERG, GRACE-FO, Sentinel-1/2, SMAP, GloFAS, ERA5
|
|
20
|
+
- **Water sovereignty assessment** — Alkedir Transparency Deficit Index (ATDI)
|
|
21
|
+
- **Forensic hydrology** — closure error, mass balance analysis
|
|
22
|
+
- **HBV rainfall-runoff modelling** — calibration and simulation
|
|
23
|
+
- **AI ensemble forecasting** — Random Forest, ensemble methods
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pip install hydrosovereign
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
With optional dependencies:
|
|
32
|
+
```bash
|
|
33
|
+
pip install hydrosovereign[gee] # Google Earth Engine support
|
|
34
|
+
pip install hydrosovereign[viz] # Plotly + Folium visualizations
|
|
35
|
+
pip install hydrosovereign[all] # All dependencies
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Quick Start
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
import hydrosovereign as hsae
|
|
42
|
+
|
|
43
|
+
# Analyze a basin
|
|
44
|
+
result = hsae.analyze_basin(
|
|
45
|
+
basin_id = "GERD_ETH",
|
|
46
|
+
start_date = "2024-01-01",
|
|
47
|
+
end_date = "2024-12-31",
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
print(result["nse"]) # Nash-Sutcliffe Efficiency
|
|
51
|
+
print(result["atdi"]) # Alkedir Transparency Deficit Index
|
|
52
|
+
print(result["volume"]) # Reservoir volume (BCM)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
# Fetch real satellite data
|
|
57
|
+
from hydrosovereign.data import fetch_basin_forcing
|
|
58
|
+
|
|
59
|
+
forcing = fetch_basin_forcing("GERD_ETH", "2024-01-01", "2024-12-31")
|
|
60
|
+
print(forcing["gpm"]["mean_P"]) # GPM precipitation mm/day
|
|
61
|
+
print(forcing["grace"]["tws_cm"]) # GRACE-FO TWS anomaly
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
# HBV rainfall-runoff model
|
|
66
|
+
from hydrosovereign.models import HBVModel
|
|
67
|
+
|
|
68
|
+
model = HBVModel()
|
|
69
|
+
model.fit(P=forcing["P"], T=forcing["T"], Q_obs=forcing["Q"])
|
|
70
|
+
print(f"NSE = {model.nse:.3f}")
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## CLI
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
hydrosovereign analyze --basin GERD_ETH --year 2024
|
|
77
|
+
hydrosovereign fetch-gee --basin KAINJI_NGA --start 2023-01-01 --end 2023-12-31
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Live Application
|
|
81
|
+
|
|
82
|
+
The full HSAE v6.01 Streamlit application:
|
|
83
|
+
🌐 [https://hydrosovereign-ai-engine-hsae-v601-6euz2zxcmerkzxgordmvxf.streamlit.app](https://hydrosovereign-ai-engine-hsae-v601-6euz2zxcmerkzxgordmvxf.streamlit.app)
|
|
84
|
+
|
|
85
|
+
## Citation
|
|
86
|
+
|
|
87
|
+
```bibtex
|
|
88
|
+
@software{alkedir2026hsae,
|
|
89
|
+
author = {Alkedir, Seifeldin M.G.},
|
|
90
|
+
title = {HydroSovereign AI Engine (HSAE) v6.5.0},
|
|
91
|
+
year = {2026},
|
|
92
|
+
doi = {10.5281/zenodo.19180160},
|
|
93
|
+
url = {https://github.com/saifeldinkhedir-coder/hydrosovereign},
|
|
94
|
+
orcid = {0000-0003-0821-2991},
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## License
|
|
99
|
+
|
|
100
|
+
GNU General Public License v3.0 — see [LICENSE](LICENSE)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""
|
|
2
|
+
HydroSovereign AI Engine (HSAE) v6.5.0
|
|
3
|
+
========================================
|
|
4
|
+
Author: Seifeldin M.G. Alkedir · ORCID: 0000-0003-0821-2991
|
|
5
|
+
DOI: 10.5281/zenodo.19180160
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
__version__ = "6.5.0"
|
|
9
|
+
__author__ = "Seifeldin M.G. Alkedir"
|
|
10
|
+
__email__ = "saifeldinkhedir@gmail.com"
|
|
11
|
+
__orcid__ = "0000-0003-0821-2991"
|
|
12
|
+
__doi__ = "10.5281/zenodo.19180160"
|
|
13
|
+
__license__ = "GPL-3.0"
|
|
14
|
+
__app_url__ = "https://hydrosovereign-ai-engine-hsae-v601-6euz2zxcmerkzxgordmvxf.streamlit.app"
|
|
15
|
+
|
|
16
|
+
# Core API — always available
|
|
17
|
+
from .api import analyze_basin, analyze_all_basins
|
|
18
|
+
|
|
19
|
+
# Models — always available (pure Python + numpy)
|
|
20
|
+
from .models import HBVModel
|
|
21
|
+
|
|
22
|
+
# Indices — always available
|
|
23
|
+
from .indices import compute_atdi, compute_kge, compute_nse
|
|
24
|
+
|
|
25
|
+
# Optional imports — only if dependencies installed
|
|
26
|
+
try:
|
|
27
|
+
from .data import fetch_basin_forcing, fetch_openmeteo
|
|
28
|
+
except ImportError:
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
try:
|
|
32
|
+
from .viz import plot_water_balance, plot_forcing
|
|
33
|
+
except ImportError:
|
|
34
|
+
pass
|
|
35
|
+
|
|
36
|
+
__all__ = [
|
|
37
|
+
"__version__", "__author__", "__orcid__", "__doi__",
|
|
38
|
+
"analyze_basin", "analyze_all_basins",
|
|
39
|
+
"HBVModel",
|
|
40
|
+
"compute_atdi", "compute_kge", "compute_nse",
|
|
41
|
+
]
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""
|
|
2
|
+
alerts.py — HSAE v6.01 Alert System
|
|
3
|
+
=====================================
|
|
4
|
+
4-level alert system for ATDI/HIFD thresholds.
|
|
5
|
+
|
|
6
|
+
Author: Seifeldin M.G. Alkedir · ORCID: 0000-0003-0821-2991
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
from enum import Enum
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class AlertLevel(Enum):
|
|
14
|
+
INFO = "INFO"
|
|
15
|
+
ALERT = "ALERT"
|
|
16
|
+
WARNING = "WARNING"
|
|
17
|
+
CRITICAL = "CRITICAL"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def check_atdi_alert(atdi: float) -> AlertLevel:
|
|
21
|
+
"""
|
|
22
|
+
Return alert level based on ATDI.
|
|
23
|
+
|
|
24
|
+
Thresholds:
|
|
25
|
+
- CRITICAL : ATDI >= 70%
|
|
26
|
+
- WARNING : ATDI >= 55%
|
|
27
|
+
- ALERT : ATDI >= 40%
|
|
28
|
+
- INFO : ATDI < 40%
|
|
29
|
+
"""
|
|
30
|
+
if atdi >= 70: return AlertLevel.CRITICAL
|
|
31
|
+
if atdi >= 55: return AlertLevel.WARNING
|
|
32
|
+
if atdi >= 40: return AlertLevel.ALERT
|
|
33
|
+
return AlertLevel.INFO
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def check_hifd_alert(hifd: float) -> AlertLevel:
|
|
37
|
+
"""
|
|
38
|
+
Return alert level based on HIFD.
|
|
39
|
+
|
|
40
|
+
Thresholds:
|
|
41
|
+
- CRITICAL : HIFD >= 60%
|
|
42
|
+
- WARNING : HIFD >= 40%
|
|
43
|
+
- ALERT : HIFD >= 25%
|
|
44
|
+
- INFO : HIFD < 25%
|
|
45
|
+
"""
|
|
46
|
+
if hifd >= 60: return AlertLevel.CRITICAL
|
|
47
|
+
if hifd >= 40: return AlertLevel.WARNING
|
|
48
|
+
if hifd >= 25: return AlertLevel.ALERT
|
|
49
|
+
return AlertLevel.INFO
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def format_alert_message(basin_name: str, atdi: float,
|
|
53
|
+
hifd: float, level: AlertLevel) -> str:
|
|
54
|
+
"""Format alert message for Telegram or logging."""
|
|
55
|
+
emoji = {"CRITICAL":"🔴","WARNING":"🟠","ALERT":"🟡","INFO":"🟢"}[level.value]
|
|
56
|
+
return (
|
|
57
|
+
f"{emoji} HSAE Alert — {level.value}\n"
|
|
58
|
+
f"Basin: {basin_name}\n"
|
|
59
|
+
f"ATDI: {atdi:.1f}% | HIFD: {hifd:.1f}%\n"
|
|
60
|
+
f"UNWC Arts: {', '.join(['Art.5','Art.9'] + (['Art.7'] if atdi>=40 else []) + (['Art.20'] if hifd>=25 else []))}"
|
|
61
|
+
)
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"""
|
|
2
|
+
api.py — HSAE v6.2.0 Unified High-Level API
|
|
3
|
+
=============================================
|
|
4
|
+
Single-call basin analysis as recommended by ChatGPT review:
|
|
5
|
+
"Add a clear entry point: analyze_basin(data)"
|
|
6
|
+
|
|
7
|
+
Author: Seifeldin M.G. Alkedir · ORCID: 0000-0003-0821-2991
|
|
8
|
+
"""
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
import logging
|
|
11
|
+
from typing import Optional, Dict
|
|
12
|
+
|
|
13
|
+
from .indices import compute_all_indices
|
|
14
|
+
from .legal import get_legal_assessment
|
|
15
|
+
from .alerts import check_atdi_alert, check_hifd_alert, AlertLevel
|
|
16
|
+
from .basins import BasinRegistry, BASINS_26
|
|
17
|
+
|
|
18
|
+
logger = logging.getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def analyze_basin(
|
|
22
|
+
name: Optional[str] = None,
|
|
23
|
+
runoff_c: Optional[float] = None,
|
|
24
|
+
cap_bcm: Optional[float] = None,
|
|
25
|
+
n_countries: Optional[int] = None,
|
|
26
|
+
dispute_level: Optional[int] = None,
|
|
27
|
+
area_km2: Optional[float] = None,
|
|
28
|
+
wqi_measurements: Optional[Dict] = None,
|
|
29
|
+
include_negotiation: bool = True,
|
|
30
|
+
include_legal: bool = True,
|
|
31
|
+
) -> dict:
|
|
32
|
+
"""
|
|
33
|
+
Full basin analysis in one call — HSAE unified entry point.
|
|
34
|
+
|
|
35
|
+
Provide either basin name (auto-loads parameters) or all parameters manually.
|
|
36
|
+
|
|
37
|
+
Parameters
|
|
38
|
+
----------
|
|
39
|
+
name : str, optional
|
|
40
|
+
Basin name from registry (e.g. "Blue Nile (GERD)"). Auto-fills parameters.
|
|
41
|
+
runoff_c : float, optional
|
|
42
|
+
Runoff coefficient 0–1. Required if name not given.
|
|
43
|
+
cap_bcm : float, optional
|
|
44
|
+
Dam storage capacity BCM.
|
|
45
|
+
n_countries : int, optional
|
|
46
|
+
Number of riparian states.
|
|
47
|
+
dispute_level : int, optional
|
|
48
|
+
TFDD/ICOW dispute level 0–4.
|
|
49
|
+
area_km2 : float, optional
|
|
50
|
+
Catchment area km². Used for conflict sensitivity.
|
|
51
|
+
wqi_measurements : dict, optional
|
|
52
|
+
Physicochemical measurements for WQI (ph, do, bod, turbidity...).
|
|
53
|
+
include_negotiation : bool
|
|
54
|
+
Include Negotiation AI prediction. Default = True.
|
|
55
|
+
include_legal : bool
|
|
56
|
+
Include UNWC legal assessment. Default = True.
|
|
57
|
+
|
|
58
|
+
Returns
|
|
59
|
+
-------
|
|
60
|
+
dict
|
|
61
|
+
Complete basin analysis:
|
|
62
|
+
- indices : atdi, hifd, wqi, ci, nse, kge
|
|
63
|
+
- alerts : atdi_alert, hifd_alert
|
|
64
|
+
- legal : articles, recommendation, pathway
|
|
65
|
+
- ai : negotiation result
|
|
66
|
+
- metadata : basin name, parameters used
|
|
67
|
+
|
|
68
|
+
Examples
|
|
69
|
+
--------
|
|
70
|
+
>>> # From registry
|
|
71
|
+
>>> result = analyze_basin("Blue Nile (GERD)")
|
|
72
|
+
>>> print(result["indices"]["atdi"]) # ~53.5
|
|
73
|
+
>>> print(result["ai"]["p_success"]) # ~0.37
|
|
74
|
+
>>> print(result["alerts"]["atdi_alert"]) # ALERT
|
|
75
|
+
|
|
76
|
+
>>> # Manual parameters
|
|
77
|
+
>>> result = analyze_basin(runoff_c=0.38, cap_bcm=74, n_countries=3, dispute_level=4)
|
|
78
|
+
"""
|
|
79
|
+
# Load from registry if name given
|
|
80
|
+
if name is not None:
|
|
81
|
+
reg = BasinRegistry()
|
|
82
|
+
basin = reg.get(name)
|
|
83
|
+
runoff_c = runoff_c or float(basin.get("runoff_c", 0.3))
|
|
84
|
+
cap_bcm = cap_bcm or float(basin.get("cap", basin.get("cap_bcm", 10)))
|
|
85
|
+
n_countries = n_countries or (len(basin["country"]) if isinstance(basin.get("country"),list) else int(basin.get("n_countries",2)))
|
|
86
|
+
dispute_level = dispute_level if dispute_level is not None else int(basin.get("dispute_level",0))
|
|
87
|
+
area_km2 = area_km2 or float(basin.get("eff_cat_km2", basin.get("area_km2",100000)))
|
|
88
|
+
else:
|
|
89
|
+
if any(v is None for v in [runoff_c, cap_bcm, n_countries, dispute_level]):
|
|
90
|
+
raise ValueError("Provide basin name or all of: runoff_c, cap_bcm, n_countries, dispute_level")
|
|
91
|
+
area_km2 = area_km2 or 100000.0
|
|
92
|
+
|
|
93
|
+
# Core indices
|
|
94
|
+
indices = compute_all_indices(runoff_c, cap_bcm, n_countries, dispute_level,
|
|
95
|
+
wqi_measurements=wqi_measurements)
|
|
96
|
+
|
|
97
|
+
# Alerts
|
|
98
|
+
atdi_alert = check_atdi_alert(indices["atdi"])
|
|
99
|
+
hifd_alert = check_hifd_alert(indices["hifd"])
|
|
100
|
+
|
|
101
|
+
result = {
|
|
102
|
+
"indices": indices,
|
|
103
|
+
"alerts": {
|
|
104
|
+
"atdi_alert": atdi_alert.value,
|
|
105
|
+
"hifd_alert": hifd_alert.value,
|
|
106
|
+
"overall": ("CRITICAL" if AlertLevel.CRITICAL in (atdi_alert,hifd_alert)
|
|
107
|
+
else "WARNING" if AlertLevel.WARNING in (atdi_alert,hifd_alert)
|
|
108
|
+
else "ALERT" if AlertLevel.ALERT in (atdi_alert,hifd_alert)
|
|
109
|
+
else "INFO"),
|
|
110
|
+
},
|
|
111
|
+
"legal": None,
|
|
112
|
+
"ai": None,
|
|
113
|
+
"metadata": {
|
|
114
|
+
"name": name or "custom",
|
|
115
|
+
"runoff_c": runoff_c,
|
|
116
|
+
"cap_bcm": cap_bcm,
|
|
117
|
+
"n_countries": n_countries,
|
|
118
|
+
"dispute_level": dispute_level,
|
|
119
|
+
"area_km2": area_km2,
|
|
120
|
+
"package_version": "6.2.0",
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if include_legal:
|
|
125
|
+
result["legal"] = get_legal_assessment(
|
|
126
|
+
indices["atdi"], indices["hifd"], dispute_level, n_countries)
|
|
127
|
+
|
|
128
|
+
if include_negotiation:
|
|
129
|
+
from .ai.negotiation import NegotiationAI
|
|
130
|
+
ai = NegotiationAI()
|
|
131
|
+
result["ai"] = ai.predict(indices["atdi"], indices["hifd"],
|
|
132
|
+
n_countries, dispute_level)
|
|
133
|
+
|
|
134
|
+
logger.info("analyze_basin(%s): ATDI=%.1f HIFD=%.1f CI=%.3f alert=%s",
|
|
135
|
+
name or "custom", indices["atdi"], indices["hifd"],
|
|
136
|
+
indices["ci"], result["alerts"]["overall"])
|
|
137
|
+
return result
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def analyze_all_basins(include_ai: bool = False) -> list:
|
|
141
|
+
"""
|
|
142
|
+
Analyze all 26 registered transboundary basins.
|
|
143
|
+
|
|
144
|
+
Parameters
|
|
145
|
+
----------
|
|
146
|
+
include_ai : bool
|
|
147
|
+
Include NegotiationAI for each basin (slower). Default = False.
|
|
148
|
+
|
|
149
|
+
Returns
|
|
150
|
+
-------
|
|
151
|
+
list of dict, sorted by conflict index descending.
|
|
152
|
+
|
|
153
|
+
Examples
|
|
154
|
+
--------
|
|
155
|
+
>>> results = analyze_all_basins()
|
|
156
|
+
>>> for r in results[:5]:
|
|
157
|
+
... print(r["metadata"]["name"], r["indices"]["atdi"])
|
|
158
|
+
"""
|
|
159
|
+
results = []
|
|
160
|
+
for basin in BASINS_26:
|
|
161
|
+
try:
|
|
162
|
+
r = analyze_basin(
|
|
163
|
+
name = basin["name"],
|
|
164
|
+
include_negotiation= include_ai,
|
|
165
|
+
include_legal = True,
|
|
166
|
+
)
|
|
167
|
+
results.append(r)
|
|
168
|
+
except Exception as e:
|
|
169
|
+
logger.warning("analyze_basin failed for %s: %s", basin.get("name","?"), e)
|
|
170
|
+
return sorted(results, key=lambda x: x["indices"]["ci"], reverse=True)
|