snowpack-elevation-warming-utac 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.
@@ -0,0 +1,44 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: ["main", "master", "claude/**"]
6
+ pull_request:
7
+ branches: ["main", "master"]
8
+
9
+ concurrency:
10
+ group: ${{ github.workflow }}-${{ github.ref }}
11
+ cancel-in-progress: true
12
+
13
+ jobs:
14
+ lint:
15
+ name: Lint (ruff + mypy)
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+ - uses: actions/setup-python@v5
20
+ with:
21
+ python-version: "3.11"
22
+ - name: Install dev dependencies
23
+ run: pip install -e ".[dev]"
24
+ - name: Run ruff
25
+ run: ruff check src tests
26
+ - name: Run mypy
27
+ run: mypy src
28
+
29
+ test:
30
+ name: Tests (Python ${{ matrix.python-version }})
31
+ runs-on: ubuntu-latest
32
+ strategy:
33
+ fail-fast: false
34
+ matrix:
35
+ python-version: ["3.11", "3.12"]
36
+ steps:
37
+ - uses: actions/checkout@v4
38
+ - uses: actions/setup-python@v5
39
+ with:
40
+ python-version: ${{ matrix.python-version }}
41
+ - name: Install dependencies
42
+ run: pip install -e ".[dev]"
43
+ - name: Run pytest with coverage
44
+ run: pytest --cov=src --cov-report=xml
@@ -0,0 +1,118 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*.*.*"
7
+ - "v*.*.*-rc*"
8
+ - "v*.*.*-alpha*"
9
+ - "v*.*.*-beta*"
10
+
11
+ permissions:
12
+ contents: write
13
+ id-token: write # for PyPI trusted publishing, if configured
14
+
15
+ jobs:
16
+ build:
17
+ name: Build distribution
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ with:
22
+ fetch-depth: 0
23
+
24
+ - name: Set up Python
25
+ uses: actions/setup-python@v5
26
+ with:
27
+ python-version: "3.12"
28
+
29
+ - name: Install build tooling
30
+ run: python -m pip install --upgrade pip build
31
+
32
+ - name: Build sdist and wheel
33
+ run: python -m build
34
+
35
+ - name: Upload build artifacts
36
+ uses: actions/upload-artifact@v4
37
+ with:
38
+ name: dist
39
+ path: dist/
40
+
41
+ test:
42
+ name: Run test suite
43
+ runs-on: ubuntu-latest
44
+ steps:
45
+ - uses: actions/checkout@v4
46
+
47
+ - name: Set up Python
48
+ uses: actions/setup-python@v5
49
+ with:
50
+ python-version: "3.12"
51
+
52
+ - name: Install package with dev/test extras
53
+ run: |
54
+ python -m pip install --upgrade pip
55
+ if python -c "import tomllib" 2>/dev/null; then :; fi
56
+ pip install -e ".[dev]" 2>/dev/null || pip install -e ".[test]" 2>/dev/null || pip install -e "."
57
+ pip install pytest pytest-cov
58
+
59
+ - name: Run tests
60
+ run: pytest -q || pytest -q --no-header
61
+
62
+ publish-canary:
63
+ name: Publish canary (TestPyPI + pre-release)
64
+ needs: [build, test]
65
+ if: contains(github.ref_name, '-rc') || contains(github.ref_name, '-alpha') || contains(github.ref_name, '-beta')
66
+ runs-on: ubuntu-latest
67
+ environment: testpypi
68
+ steps:
69
+ - uses: actions/download-artifact@v4
70
+ with:
71
+ name: dist
72
+ path: dist/
73
+
74
+ - name: Publish to TestPyPI
75
+ uses: pypa/gh-action-pypi-publish@release/v1
76
+ with:
77
+ repository-url: https://test.pypi.org/legacy/
78
+ password: ${{ secrets.TEST_PYPI_API_TOKEN }}
79
+ skip-existing: true
80
+
81
+ - name: Create GitHub pre-release
82
+ uses: softprops/action-gh-release@v2
83
+ with:
84
+ files: dist/*
85
+ prerelease: true
86
+ generate_release_notes: true
87
+
88
+ publish-production:
89
+ name: Publish production (PyPI + release + Zenodo archive)
90
+ needs: [build, test]
91
+ if: ${{ !contains(github.ref_name, '-rc') && !contains(github.ref_name, '-alpha') && !contains(github.ref_name, '-beta') }}
92
+ runs-on: ubuntu-latest
93
+ environment: pypi
94
+ steps:
95
+ - uses: actions/download-artifact@v4
96
+ with:
97
+ name: dist
98
+ path: dist/
99
+
100
+ - name: Publish to PyPI
101
+ uses: pypa/gh-action-pypi-publish@release/v1
102
+ with:
103
+ password: ${{ secrets.PYPI_API_TOKEN }}
104
+ skip-existing: true
105
+
106
+ - name: Create GitHub Release
107
+ uses: softprops/action-gh-release@v2
108
+ with:
109
+ files: dist/*
110
+ prerelease: false
111
+ generate_release_notes: true
112
+
113
+ # NOTE: Zenodo archival of this GitHub Release happens automatically
114
+ # IF this repo has Zenodo-GitHub integration enabled at
115
+ # https://zenodo.org/account/settings/github/ (a per-repo, per-owner
116
+ # OAuth toggle on zenodo.org — cannot be set from a workflow file).
117
+ # Once enabled, every GitHub Release like this one mints/updates a
118
+ # Zenodo DOI automatically using the .zenodo.json metadata in this repo.
@@ -0,0 +1,22 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .eggs/
6
+ dist/
7
+ build/
8
+ .venv/
9
+ .uv/
10
+
11
+ # Testing
12
+ .coverage
13
+ htmlcov/
14
+ .pytest_cache/
15
+
16
+ # Docs
17
+ site/
18
+
19
+ # Editors
20
+ .vscode/
21
+ .idea/
22
+ *.swp
@@ -0,0 +1,14 @@
1
+ repos:
2
+ - repo: https://github.com/astral-sh/ruff-pre-commit
3
+ rev: v0.6.0
4
+ hooks:
5
+ - id: ruff
6
+ args: [--fix]
7
+ - id: ruff-format
8
+ - repo: https://github.com/pre-commit/pre-commit-hooks
9
+ rev: v4.6.0
10
+ hooks:
11
+ - id: trailing-whitespace
12
+ - id: end-of-file-fixer
13
+ - id: check-yaml
14
+ - id: check-toml
@@ -0,0 +1,28 @@
1
+ {
2
+ "title": "snowpack-elevation-warming-utac — P110: The seasonal snow buffer is eroding",
3
+ "description": "<p>Pepin et al. 2015's elevation-dependent-warming mechanism review, Matiu et al. 2021's European Alps snow depth trends (1971-2019, 2000+ stations), Notarnicola 2022's global mountain snow cover trends (1982-2020, incl. the Karakoram anomaly and winter/spring divergence), and Mote et al. 2018's western US snowpack decline (since 1915, 1766 sites). Quantifies distributed-buffer-resilience-utac's (P103) unquantified 'snow (seasonal)' buffer category and extends glacier-buffer-utac's (P99) peak-water framing. Deliberately not one-sided. Deliberately has NO UTAC/CREP/AFET bridge. See DISCLAIMER.md. Part of the <strong>GenesisAeon</strong> ecosystem (P110, domain: climate / cryosphere / mountain hydrology).</p>",
4
+ "creators": [
5
+ {
6
+ "name": "Römer, Johann",
7
+ "affiliation": "Independent Researcher / MOR Research Collective"
8
+ }
9
+ ],
10
+ "license": "MIT",
11
+ "upload_type": "software",
12
+ "access_right": "open",
13
+ "version": "1.0.0",
14
+ "keywords": [
15
+ "GenesisAeon",
16
+ "P110",
17
+ "climate",
18
+ "snowpack",
19
+ "cryosphere",
20
+ "elevation-dependent-warming",
21
+ "open-science"
22
+ ],
23
+ "communities": [
24
+ {
25
+ "identifier": "genesisaeon"
26
+ }
27
+ ]
28
+ }
@@ -0,0 +1,73 @@
1
+ cff-version: 1.2.0
2
+ message: "If you use this software, please cite it as below."
3
+ type: software
4
+ authors:
5
+ - family-names: Römer
6
+ given-names: Johann
7
+ affiliation: "MOR Research Collective"
8
+ title: "snowpack-elevation-warming-utac"
9
+ version: "1.0.0"
10
+ date-released: "2026-08-17"
11
+ url: "https://github.com/GenesisAeon/snowpack-elevation-warming-utac"
12
+ repository-code: "https://github.com/GenesisAeon/snowpack-elevation-warming-utac"
13
+ license: MIT
14
+ abstract: "The seasonal snow buffer is eroding: Pepin et al. 2015's elevation-dependent-warming mechanism review, Matiu et al. 2021's European Alps snow depth trends (1971-2019), Notarnicola 2022's global mountain snow cover trends (1982-2020, incl. the Karakoram anomaly and winter/spring divergence), and Mote et al. 2018's western US snowpack decline (since 1915). Quantifies distributed-buffer-resilience-utac's (P103) unquantified 'snow (seasonal)' buffer category and extends glacier-buffer-utac's (P99) peak-water framing. Deliberately includes findings that complicate its own headline narrative. Deliberately no UTAC/CREP/AFET bridge. GenesisAeon P110."
15
+ keywords:
16
+ - GenesisAeon
17
+ - P110
18
+ - climate
19
+ - snowpack
20
+ - cryosphere
21
+ - elevation-dependent-warming
22
+ - open-science
23
+ references:
24
+ - type: article
25
+ title: "Elevation-dependent warming in mountain regions of the world"
26
+ authors:
27
+ - name: "Pepin, N."
28
+ - name: "Bradley, R.S."
29
+ - name: "Diaz, H.F."
30
+ - name: "Baraer, M."
31
+ - name: "Caceres, E.B."
32
+ - name: "Forsythe, N."
33
+ year: 2015
34
+ journal: "Nature Climate Change"
35
+ volume: 5
36
+ start: 424
37
+ doi: "10.1038/nclimate2563"
38
+ - type: article
39
+ title: "Observed snow depth trends in the European Alps: 1971 to 2019"
40
+ authors:
41
+ - name: "Matiu, M."
42
+ - name: "Crespi, A."
43
+ - name: "Bertoldi, G."
44
+ - name: "Carmagnola, C.M."
45
+ - name: "Marty, C."
46
+ - name: "Morin, S."
47
+ year: 2021
48
+ journal: "The Cryosphere"
49
+ volume: 15
50
+ start: 1343
51
+ doi: "10.5194/tc-15-1343-2021"
52
+ - type: article
53
+ title: "Overall negative trends for snow cover extent and duration in global mountain regions over 1982-2020"
54
+ authors:
55
+ - name: "Notarnicola, C."
56
+ year: 2022
57
+ journal: "Scientific Reports"
58
+ volume: 12
59
+ start: 13731
60
+ doi: "10.1038/s41598-022-16743-w"
61
+ - type: article
62
+ title: "Dramatic declines in snowpack in the western US"
63
+ authors:
64
+ - name: "Mote, P.W."
65
+ - name: "Li, S."
66
+ - name: "Lettenmaier, D.P."
67
+ - name: "Xiao, M."
68
+ - name: "Engel, R."
69
+ year: 2018
70
+ journal: "npj Climate and Atmospheric Science"
71
+ volume: 1
72
+ start: 2
73
+ doi: "10.1038/s41612-018-0012-1"
@@ -0,0 +1,87 @@
1
+ # DISCLAIMER — Real Science, Deliberately Includes a Complication, No Framework Bridge
2
+
3
+ **Status: Real, independently verified science, including findings
4
+ that complicate the package's own headline narrative. NO UTAC/CREP/
5
+ AFET bridge.**
6
+
7
+ ## What this is
8
+
9
+ Every citation was checked directly against the paper (DOI lookup or
10
+ publisher page) on 2026-08-16.
11
+
12
+ - **Pepin, N., Bradley, R.S., Diaz, H.F., Baraer, M., Caceres, E.B.,
13
+ Forsythe, N., et al. (2015)**, *Nature Climate Change*, 5, 424-430,
14
+ DOI: 10.1038/nclimate2563 — a real synthesis review of
15
+ elevation-dependent warming (EDW) mechanisms. Deliberately NOT used
16
+ to claim a single global warming-amplification rate: the paper
17
+ itself frames EDW as producing contrasting regional patterns from
18
+ up to five candidate mechanisms, not one number.
19
+ - **Matiu, M., Crespi, A., Bertoldi, G., Carmagnola, C.M., Marty, C.,
20
+ Morin, S., et al. (2021)**, *The Cryosphere*, 15, 1343-1382,
21
+ DOI: 10.5194/tc-15-1343-2021 — a real, large station-network study
22
+ (2,000+ stations, 800+ used for trend assessment, six Alpine
23
+ countries, 1971-2019).
24
+ - **Notarnicola, C. (2022)**, *Scientific Reports*, 12, 13731,
25
+ DOI: 10.1038/s41598-022-16743-w — a real satellite-based global
26
+ mountain snow cover analysis (1982-2020), deliberately included
27
+ because it complicates rather than only confirms the "snow is
28
+ disappearing everywhere" narrative.
29
+ - **Mote, P.W., Li, S., Lettenmaier, D.P., Xiao, M., Engel, R.
30
+ (2018)**, *npj Climate and Atmospheric Science*, 1, 2,
31
+ DOI: 10.1038/s41612-018-0012-1 — a real, large western US
32
+ snow-course/SNOTEL network analysis (1,766 sites, since 1915).
33
+
34
+ ## Why the complications are included on purpose
35
+
36
+ It would have been easy to build this package from only the
37
+ Alps-wide and western-US decline figures — both real, both show a
38
+ clear, large-sample decline. But Notarnicola (2022) found that
39
+ global-mean decline hides two real internal contradictions: spring
40
+ (MAM) snow cover extent trends *positive* even as winter (DJF)
41
+ declines steeply, and northern High Mountain Asia (Karakoram, Kunlun
42
+ Shan, Pamir) shows a *positive* snow cover extent trend while
43
+ southern High Mountain Asia declines — consistent with the
44
+ independently documented "Karakoram anomaly" in glacier mass balance.
45
+
46
+ This is not a contradiction to hide; it is the responsible way to
47
+ present the science. A single global percentage would misrepresent
48
+ regions and seasons where the pattern runs the other way. Presenting
49
+ only the confirming Alps/western-US cases while omitting the global
50
+ satellite record's own internal nuance would have been a one-sided
51
+ picture of a genuinely more heterogeneous real literature.
52
+
53
+ ## What this is NOT
54
+
55
+ - **Not a claim of a single global warming-amplification rate.**
56
+ Pepin et al. (2015) is a mechanism review, not a global measurement
57
+ — this package does not invent a number the paper itself does not
58
+ report.
59
+ - **Not a claim that every mountain range or season is declining.**
60
+ Karakoram/Kunlun Shan/Pamir and boreal spring are real,
61
+ independently documented exceptions.
62
+ - **No UTAC/CREP/AFET bridge.** This is a real, standalone
63
+ cryosphere-climatology topic; the cited papers already provide the
64
+ relevant quantitative structure without this ecosystem's
65
+ cross-domain vocabulary.
66
+
67
+ ## References
68
+
69
+ - Pepin, N., Bradley, R.S., Diaz, H.F., Baraer, M., Caceres, E.B.,
70
+ Forsythe, N., et al. (2015). *Nature Climate Change*, 5, 424-430.
71
+ DOI: 10.1038/nclimate2563.
72
+ - Matiu, M., Crespi, A., Bertoldi, G., Carmagnola, C.M., Marty, C.,
73
+ Morin, S., et al. (2021). *The Cryosphere*, 15, 1343-1382.
74
+ DOI: 10.5194/tc-15-1343-2021.
75
+ - Notarnicola, C. (2022). *Scientific Reports*, 12, 13731.
76
+ DOI: 10.1038/s41598-022-16743-w.
77
+ - Mote, P.W., Li, S., Lettenmaier, D.P., Xiao, M., Engel, R. (2018).
78
+ *npj Climate and Atmospheric Science*, 1, 2.
79
+ DOI: 10.1038/s41612-018-0012-1.
80
+
81
+ All verified directly (2026-08-16) via WebSearch/WebFetch against
82
+ publisher pages and DOI records. Originating context: identified
83
+ 2026-08-15 as the runner-up candidate during the P109 selection
84
+ research ("snowpack/elevation-dependent warming ... a real structural
85
+ gap, P103's storage_portfolio.py even has an unquantified 'snow
86
+ (seasonal)' placeholder"), formally researched and built 2026-08-16
87
+ alongside P111 at Johann's request.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 JohannRömer
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.
@@ -0,0 +1,116 @@
1
+ Metadata-Version: 2.5
2
+ Name: snowpack-elevation-warming-utac
3
+ Version: 1.0.0
4
+ Summary: The seasonal snow buffer is eroding -- Pepin et al. 2015's elevation-dependent-warming mechanism review, Matiu et al. 2021's European Alps snow depth trends, Notarnicola 2022's global mountain snow cover trends (incl. the Karakoram anomaly), and Mote et al. 2018's western US snowpack decline -- quantifies P103's unquantified 'snow (seasonal)' buffer category, no UTAC/CREP bridge
5
+ Project-URL: Homepage, https://github.com/GenesisAeon/snowpack-elevation-warming-utac
6
+ Project-URL: Repository, https://github.com/GenesisAeon/snowpack-elevation-warming-utac
7
+ Author: Römer, Johann
8
+ License: MIT
9
+ License-File: LICENSE
10
+ Requires-Python: >=3.11
11
+ Provides-Extra: dev
12
+ Requires-Dist: mypy>=1.10.0; extra == 'dev'
13
+ Requires-Dist: pre-commit>=3.7.0; extra == 'dev'
14
+ Requires-Dist: pytest-cov>=5.0.0; extra == 'dev'
15
+ Requires-Dist: pytest>=8.0.0; extra == 'dev'
16
+ Requires-Dist: ruff>=0.6.0; extra == 'dev'
17
+ Description-Content-Type: text/markdown
18
+
19
+ # snowpack-elevation-warming-utac
20
+
21
+ GenesisAeon Package 110 — the seasonal snow buffer is eroding.
22
+ Quantifies a buffer type that
23
+ [distributed-buffer-resilience-utac](https://github.com/GenesisAeon/distributed-buffer-resilience-utac)
24
+ (P103) names but leaves unquantified: "snow (seasonal)" as one of
25
+ five hydrological buffer types. Also extends
26
+ [glacier-buffer-utac](https://github.com/GenesisAeon/glacier-buffer-utac)
27
+ (P99)'s "peak water" framing to the faster, annually-recurring
28
+ seasonal snowpack. **Deliberately has no UTAC/CREP/AFET bridge** —
29
+ see [DISCLAIMER.md](DISCLAIMER.md).
30
+
31
+ ## Deliberately not one-sided
32
+
33
+ This package includes a real, important **complication** of the
34
+ "snow is disappearing everywhere, in every season" narrative, not
35
+ just confirmation of it. `is_snow_decline_spatially_universal()`
36
+ returns `False` on purpose — northern High Mountain Asia (Karakoram,
37
+ Kunlun Shan, Pamir) shows a *positive* snow cover extent trend, and
38
+ global spring (MAM) snow cover extent trends positive even as winter
39
+ (DJF) declines steeply.
40
+
41
+ ## What's real here
42
+
43
+ - **Pepin, Bradley, Diaz, Baraer, Caceres, Forsythe et al. (2015,
44
+ *Nature Climate Change*)** — a real synthesis review: warming is
45
+ amplified with elevation in many mountain regions, via up to five
46
+ candidate mechanisms (snow-albedo feedback, water vapor/latent
47
+ heat, radiative flux, surface heat loss, aerosols) that produce
48
+ **contrasting regional patterns**, not one uniform global rate —
49
+ this package deliberately does not attribute a single global
50
+ degrees-per-decade figure to this citation, because the paper
51
+ itself does not report one.
52
+ - **Matiu, Crespi, Bertoldi, Carmagnola, Marty, Morin et al. (2021,
53
+ *The Cryosphere*)** — a real, large European Alps station network
54
+ (2,000+ stations, 800+ used for trend assessment, six countries,
55
+ 1971–2019): seasonal mean snow depth declined **-8.4%/decade**,
56
+ maximum snow depth and snow cover duration each declined
57
+ **-5.6%/decade**, with southern Alpine regions declining measurably
58
+ faster than northern ones.
59
+ - **Notarnicola (2022, *Scientific Reports*)** — the honesty check: a
60
+ real satellite-based global mountain analysis (1982–2020) found
61
+ overall snow cover extent down **-3.6%±2.7%** and duration down
62
+ **-15.1±11.6 days**, but winter (DJF) declined steeply
63
+ (**-11.5%±6.9%**) while spring (MAM) trended **positive**
64
+ (**+10.0%±5.9%**), and northern High Mountain Asia (Karakoram,
65
+ Kunlun Shan, Pamir) shows a positive trend — consistent with the
66
+ independently documented "Karakoram anomaly" in glacier mass
67
+ balance — while southern High Mountain Asia declines.
68
+ - **Mote, Li, Lettenmaier, Xiao, Engel (2018, *npj Climate and
69
+ Atmospheric Science*)** — a real, large western US snow-course/
70
+ SNOTEL network (1,766 sites, since 1915): more than 90% of sites
71
+ show a decline, about a third of those declines are individually
72
+ statistically significant, and the average decline is 15–30% since
73
+ the start of record.
74
+
75
+ ## Quickstart
76
+
77
+ ```bash
78
+ pip install snowpack-elevation-warming-utac
79
+ ```
80
+
81
+ ```python
82
+ from snowpack_elevation_warming_utac import (
83
+ edw_candidate_mechanisms,
84
+ is_globally_uniform_pattern,
85
+ ALPINE_SNOW_TREND,
86
+ is_decline_spatially_uniform,
87
+ GLOBAL_SNOW_TREND,
88
+ winter_vs_spring_extent_trend_pct,
89
+ is_snow_decline_spatially_universal,
90
+ WEST_US_SNOWPACK_TREND,
91
+ majority_of_sites_declining,
92
+ )
93
+
94
+ print(edw_candidate_mechanisms())
95
+ print(is_globally_uniform_pattern()) # False
96
+ print(ALPINE_SNOW_TREND.seasonal_mean_depth_pct_per_decade) # -8.4
97
+ print(GLOBAL_SNOW_TREND.extent_pct) # -3.6
98
+ print(winter_vs_spring_extent_trend_pct()) # {"winter_djf": -11.5, "spring_mam": 10.0}
99
+ print(is_snow_decline_spatially_universal()) # False
100
+ print(WEST_US_SNOWPACK_TREND.pct_sites_declining) # 90
101
+ print(majority_of_sites_declining()) # True
102
+ ```
103
+
104
+ ## Development
105
+
106
+ ```bash
107
+ pip install -e ".[dev]"
108
+ pre-commit install
109
+ ruff check src tests
110
+ mypy src
111
+ pytest
112
+ ```
113
+
114
+ ## Citation
115
+
116
+ See [CITATION.cff](CITATION.cff) and [.zenodo.json](.zenodo.json).
@@ -0,0 +1,98 @@
1
+ # snowpack-elevation-warming-utac
2
+
3
+ GenesisAeon Package 110 — the seasonal snow buffer is eroding.
4
+ Quantifies a buffer type that
5
+ [distributed-buffer-resilience-utac](https://github.com/GenesisAeon/distributed-buffer-resilience-utac)
6
+ (P103) names but leaves unquantified: "snow (seasonal)" as one of
7
+ five hydrological buffer types. Also extends
8
+ [glacier-buffer-utac](https://github.com/GenesisAeon/glacier-buffer-utac)
9
+ (P99)'s "peak water" framing to the faster, annually-recurring
10
+ seasonal snowpack. **Deliberately has no UTAC/CREP/AFET bridge** —
11
+ see [DISCLAIMER.md](DISCLAIMER.md).
12
+
13
+ ## Deliberately not one-sided
14
+
15
+ This package includes a real, important **complication** of the
16
+ "snow is disappearing everywhere, in every season" narrative, not
17
+ just confirmation of it. `is_snow_decline_spatially_universal()`
18
+ returns `False` on purpose — northern High Mountain Asia (Karakoram,
19
+ Kunlun Shan, Pamir) shows a *positive* snow cover extent trend, and
20
+ global spring (MAM) snow cover extent trends positive even as winter
21
+ (DJF) declines steeply.
22
+
23
+ ## What's real here
24
+
25
+ - **Pepin, Bradley, Diaz, Baraer, Caceres, Forsythe et al. (2015,
26
+ *Nature Climate Change*)** — a real synthesis review: warming is
27
+ amplified with elevation in many mountain regions, via up to five
28
+ candidate mechanisms (snow-albedo feedback, water vapor/latent
29
+ heat, radiative flux, surface heat loss, aerosols) that produce
30
+ **contrasting regional patterns**, not one uniform global rate —
31
+ this package deliberately does not attribute a single global
32
+ degrees-per-decade figure to this citation, because the paper
33
+ itself does not report one.
34
+ - **Matiu, Crespi, Bertoldi, Carmagnola, Marty, Morin et al. (2021,
35
+ *The Cryosphere*)** — a real, large European Alps station network
36
+ (2,000+ stations, 800+ used for trend assessment, six countries,
37
+ 1971–2019): seasonal mean snow depth declined **-8.4%/decade**,
38
+ maximum snow depth and snow cover duration each declined
39
+ **-5.6%/decade**, with southern Alpine regions declining measurably
40
+ faster than northern ones.
41
+ - **Notarnicola (2022, *Scientific Reports*)** — the honesty check: a
42
+ real satellite-based global mountain analysis (1982–2020) found
43
+ overall snow cover extent down **-3.6%±2.7%** and duration down
44
+ **-15.1±11.6 days**, but winter (DJF) declined steeply
45
+ (**-11.5%±6.9%**) while spring (MAM) trended **positive**
46
+ (**+10.0%±5.9%**), and northern High Mountain Asia (Karakoram,
47
+ Kunlun Shan, Pamir) shows a positive trend — consistent with the
48
+ independently documented "Karakoram anomaly" in glacier mass
49
+ balance — while southern High Mountain Asia declines.
50
+ - **Mote, Li, Lettenmaier, Xiao, Engel (2018, *npj Climate and
51
+ Atmospheric Science*)** — a real, large western US snow-course/
52
+ SNOTEL network (1,766 sites, since 1915): more than 90% of sites
53
+ show a decline, about a third of those declines are individually
54
+ statistically significant, and the average decline is 15–30% since
55
+ the start of record.
56
+
57
+ ## Quickstart
58
+
59
+ ```bash
60
+ pip install snowpack-elevation-warming-utac
61
+ ```
62
+
63
+ ```python
64
+ from snowpack_elevation_warming_utac import (
65
+ edw_candidate_mechanisms,
66
+ is_globally_uniform_pattern,
67
+ ALPINE_SNOW_TREND,
68
+ is_decline_spatially_uniform,
69
+ GLOBAL_SNOW_TREND,
70
+ winter_vs_spring_extent_trend_pct,
71
+ is_snow_decline_spatially_universal,
72
+ WEST_US_SNOWPACK_TREND,
73
+ majority_of_sites_declining,
74
+ )
75
+
76
+ print(edw_candidate_mechanisms())
77
+ print(is_globally_uniform_pattern()) # False
78
+ print(ALPINE_SNOW_TREND.seasonal_mean_depth_pct_per_decade) # -8.4
79
+ print(GLOBAL_SNOW_TREND.extent_pct) # -3.6
80
+ print(winter_vs_spring_extent_trend_pct()) # {"winter_djf": -11.5, "spring_mam": 10.0}
81
+ print(is_snow_decline_spatially_universal()) # False
82
+ print(WEST_US_SNOWPACK_TREND.pct_sites_declining) # 90
83
+ print(majority_of_sites_declining()) # True
84
+ ```
85
+
86
+ ## Development
87
+
88
+ ```bash
89
+ pip install -e ".[dev]"
90
+ pre-commit install
91
+ ruff check src tests
92
+ mypy src
93
+ pytest
94
+ ```
95
+
96
+ ## Citation
97
+
98
+ See [CITATION.cff](CITATION.cff) and [.zenodo.json](.zenodo.json).
@@ -0,0 +1,47 @@
1
+ [project]
2
+ name = "snowpack-elevation-warming-utac"
3
+ version = "1.0.0"
4
+ description = "The seasonal snow buffer is eroding -- Pepin et al. 2015's elevation-dependent-warming mechanism review, Matiu et al. 2021's European Alps snow depth trends, Notarnicola 2022's global mountain snow cover trends (incl. the Karakoram anomaly), and Mote et al. 2018's western US snowpack decline -- quantifies P103's unquantified 'snow (seasonal)' buffer category, no UTAC/CREP bridge"
5
+ readme = "README.md"
6
+ license = { text = "MIT" }
7
+ authors = [{ name = "Römer, Johann" }]
8
+ requires-python = ">=3.11"
9
+ dependencies = []
10
+
11
+ [project.urls]
12
+ Homepage = "https://github.com/GenesisAeon/snowpack-elevation-warming-utac"
13
+ Repository = "https://github.com/GenesisAeon/snowpack-elevation-warming-utac"
14
+
15
+ [project.optional-dependencies]
16
+ dev = [
17
+ "ruff>=0.6.0",
18
+ "mypy>=1.10.0",
19
+ "pre-commit>=3.7.0",
20
+ "pytest>=8.0.0",
21
+ "pytest-cov>=5.0.0",
22
+ ]
23
+
24
+ [build-system]
25
+ requires = ["hatchling"]
26
+ build-backend = "hatchling.build"
27
+
28
+ [tool.hatch.build.targets.wheel]
29
+ packages = ["src/snowpack_elevation_warming_utac"]
30
+
31
+ [tool.ruff]
32
+ line-length = 100
33
+ target-version = "py311"
34
+
35
+ [tool.ruff.lint]
36
+ select = ["E", "F", "B", "I", "W", "UP"]
37
+
38
+ [tool.mypy]
39
+ python_version = "3.11"
40
+ strict = true
41
+ warn_return_any = true
42
+ warn_unused_configs = true
43
+ ignore_missing_imports = true
44
+
45
+ [tool.pytest.ini_options]
46
+ testpaths = ["tests"]
47
+ addopts = "--cov=snowpack_elevation_warming_utac --cov-report=term-missing -v"
@@ -0,0 +1,66 @@
1
+ """snowpack-elevation-warming-utac -- the seasonal snow buffer is eroding.
2
+
3
+ GenesisAeon Package 110. Quantifies a buffer type that P103
4
+ (distributed-buffer-resilience-utac) names but leaves unquantified:
5
+ "snow (seasonal)". Also extends P99 (glacier-buffer-utac)'s "peak
6
+ water" framing to the faster, annually-recurring seasonal snowpack.
7
+ Deliberately no UTAC/CREP/AFET bridge -- see DISCLAIMER.md.
8
+
9
+ Deliberately NOT one-sided: includes a real complication of the "snow
10
+ is declining everywhere" narrative (Notarnicola et al. 2022's winter/
11
+ spring divergence and the Karakoram anomaly), not just confirmation.
12
+
13
+ All citations independently verified 2026-08-16.
14
+ """
15
+
16
+ from .alpine_snow_decline import (
17
+ ALPINE_SNOW_TREND,
18
+ AlpineSnowTrend,
19
+ is_decline_spatially_uniform,
20
+ )
21
+ from .constants import (
22
+ BRIDGE_NOTE,
23
+ MATIU_2021_CITATION,
24
+ MOTE_2018_CITATION,
25
+ NOTARNICOLA_2022_CITATION,
26
+ PACKAGE_ID,
27
+ PEPIN_2015_CITATION,
28
+ )
29
+ from .elevation_dependent_warming import (
30
+ edw_candidate_mechanisms,
31
+ is_globally_uniform_pattern,
32
+ )
33
+ from .global_snow_trends import (
34
+ GLOBAL_SNOW_TREND,
35
+ GlobalSnowTrend,
36
+ is_snow_decline_spatially_universal,
37
+ winter_vs_spring_extent_trend_pct,
38
+ )
39
+ from .west_us_snowpack import (
40
+ WEST_US_SNOWPACK_TREND,
41
+ WestUsSnowpackTrend,
42
+ majority_of_sites_declining,
43
+ )
44
+
45
+ __version__ = "1.0.0"
46
+
47
+ __all__ = [
48
+ "ALPINE_SNOW_TREND",
49
+ "BRIDGE_NOTE",
50
+ "GLOBAL_SNOW_TREND",
51
+ "MATIU_2021_CITATION",
52
+ "MOTE_2018_CITATION",
53
+ "NOTARNICOLA_2022_CITATION",
54
+ "PACKAGE_ID",
55
+ "PEPIN_2015_CITATION",
56
+ "WEST_US_SNOWPACK_TREND",
57
+ "AlpineSnowTrend",
58
+ "GlobalSnowTrend",
59
+ "WestUsSnowpackTrend",
60
+ "edw_candidate_mechanisms",
61
+ "is_decline_spatially_uniform",
62
+ "is_globally_uniform_pattern",
63
+ "is_snow_decline_spatially_universal",
64
+ "majority_of_sites_declining",
65
+ "winter_vs_spring_extent_trend_pct",
66
+ ]
@@ -0,0 +1,58 @@
1
+ """European Alps snow depth trends, 1971-2019 (Matiu et al. 2021).
2
+
3
+ Core module -- a real, large station network (2000+ stations, 800+
4
+ used for trend assessment across six Alpine countries).
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from dataclasses import dataclass
10
+
11
+ from .constants import (
12
+ ALPS_DURATION_PCT_PER_DECADE,
13
+ ALPS_MAX_DEPTH_PCT_PER_DECADE,
14
+ ALPS_REGIONAL_ASYMMETRY_NOTE,
15
+ ALPS_SEASONAL_MEAN_DEPTH_PCT_PER_DECADE,
16
+ ALPS_STATION_COUNT,
17
+ ALPS_TREND_PERIOD,
18
+ ALPS_TREND_STATION_COUNT,
19
+ MATIU_2021_CITATION,
20
+ )
21
+
22
+
23
+ @dataclass(frozen=True)
24
+ class AlpineSnowTrend:
25
+ """Matiu et al. (2021)'s observed European Alps snow depth trend."""
26
+
27
+ period: str
28
+ station_count: int
29
+ trend_station_count: int
30
+ seasonal_mean_depth_pct_per_decade: float
31
+ max_depth_pct_per_decade: float
32
+ duration_pct_per_decade: float
33
+ citation: str
34
+
35
+
36
+ ALPINE_SNOW_TREND = AlpineSnowTrend(
37
+ period=ALPS_TREND_PERIOD,
38
+ station_count=ALPS_STATION_COUNT,
39
+ trend_station_count=ALPS_TREND_STATION_COUNT,
40
+ seasonal_mean_depth_pct_per_decade=ALPS_SEASONAL_MEAN_DEPTH_PCT_PER_DECADE,
41
+ max_depth_pct_per_decade=ALPS_MAX_DEPTH_PCT_PER_DECADE,
42
+ duration_pct_per_decade=ALPS_DURATION_PCT_PER_DECADE,
43
+ citation=MATIU_2021_CITATION,
44
+ )
45
+
46
+
47
+ def is_decline_spatially_uniform() -> bool:
48
+ """Whether the Alps-wide snow decline is spatially uniform.
49
+
50
+ Always False. Southern Alpine (south-facing) regions decline
51
+ measurably faster than northern regions -- see
52
+ ALPS_REGIONAL_ASYMMETRY_NOTE.
53
+ """
54
+ return False
55
+
56
+
57
+ REGIONAL_ASYMMETRY_NOTE = ALPS_REGIONAL_ASYMMETRY_NOTE
58
+ CITATION = MATIU_2021_CITATION
@@ -0,0 +1,163 @@
1
+ """Verified constants for elevation-dependent warming and mountain snowpack decline.
2
+
3
+ Quantifies a buffer type that P103's storage_portfolio.py names but
4
+ leaves unquantified: "snow (seasonal)" as one of five hydrological
5
+ buffer types (alongside reservoirs, soil moisture, wetlands,
6
+ groundwater). This package documents that the snow buffer itself is
7
+ measurably eroding -- and that the erosion is not spatially uniform,
8
+ which is the deliberate honesty check for this package (see
9
+ global_snow_trends.py). Deliberately no UTAC/CREP/AFET bridge.
10
+
11
+ All citations independently verified via direct source lookup on
12
+ 2026-08-16.
13
+ """
14
+
15
+ PACKAGE_ID = 110
16
+
17
+ # =====================================================================
18
+ # Pepin et al. 2015: elevation-dependent warming (EDW), mechanism review
19
+ # =====================================================================
20
+
21
+ PEPIN_2015_CITATION = (
22
+ "Pepin, N., Bradley, R.S., Diaz, H.F., Baraer, M., Caceres, E.B., "
23
+ "Forsythe, N., et al. (2015). Elevation-dependent warming in "
24
+ "mountain regions of the world. Nature Climate Change, 5, "
25
+ "424-430. DOI: 10.1038/nclimate2563"
26
+ )
27
+ PEPIN_2015_DOI = "10.1038/nclimate2563"
28
+
29
+ EDW_CANDIDATE_MECHANISMS = (
30
+ "snow albedo and surface-based feedbacks",
31
+ "water vapor changes and latent heat release",
32
+ "radiative flux changes related to surface moisture",
33
+ "surface heat loss and temperature change",
34
+ "aerosol effects",
35
+ )
36
+
37
+ EDW_NOTE = (
38
+ "Pepin et al. (2015) is a synthesis review, not a single global "
39
+ "measurement: it establishes that the rate of warming is "
40
+ "amplified with elevation in many mountain regions, driven by up "
41
+ "to five candidate mechanisms, but explicitly frames these "
42
+ "mechanisms as producing CONTRASTING REGIONAL PATTERNS rather "
43
+ "than one uniform global amplification rate. This package does "
44
+ "not attribute a single global degrees-per-decade EDW figure to "
45
+ "this citation, because the paper itself does not report one -- "
46
+ "doing so would overclaim past the paper's own scope."
47
+ )
48
+
49
+ # =====================================================================
50
+ # Matiu et al. 2021: European Alps snow depth trends, 1971-2019
51
+ # =====================================================================
52
+
53
+ MATIU_2021_CITATION = (
54
+ "Matiu, M., Crespi, A., Bertoldi, G., Carmagnola, C.M., Marty, C., "
55
+ "Morin, S., et al. (2021). Observed snow depth trends in the "
56
+ "European Alps: 1971 to 2019. The Cryosphere, 15, 1343-1382. "
57
+ "DOI: 10.5194/tc-15-1343-2021"
58
+ )
59
+ MATIU_2021_DOI = "10.5194/tc-15-1343-2021"
60
+
61
+ ALPS_STATION_COUNT = 2000
62
+ ALPS_TREND_STATION_COUNT = 800
63
+ ALPS_TREND_PERIOD = "1971-2019"
64
+ ALPS_SEASONAL_MEAN_DEPTH_PCT_PER_DECADE = -8.4
65
+ ALPS_MAX_DEPTH_PCT_PER_DECADE = -5.6
66
+ ALPS_DURATION_PCT_PER_DECADE = -5.6
67
+
68
+ ALPS_REGIONAL_ASYMMETRY_NOTE = (
69
+ "Southern Alpine regions show stronger declines than northern "
70
+ "regions -- e.g. mid-elevation (1000-2000 m) March snow depth "
71
+ "declined ~-7.0 cm/decade on south-facing/southern slopes vs. "
72
+ "~-3.9 cm/decade in northern regions. The decline is real and "
73
+ "widespread (~85% of station-months show a declining trend, ~26% "
74
+ "statistically significant at p<0.05) but not spatially uniform."
75
+ )
76
+
77
+ # =====================================================================
78
+ # Notarnicola 2022: global mountain snow cover extent/duration, 1982-2020
79
+ # (satellite-based; the deliberate honesty-check citation for this package)
80
+ # =====================================================================
81
+
82
+ NOTARNICOLA_2022_CITATION = (
83
+ "Notarnicola, C. (2022). Overall negative trends for snow cover "
84
+ "extent and duration in global mountain regions over 1982-2020. "
85
+ "Scientific Reports, 12, 13731. "
86
+ "DOI: 10.1038/s41598-022-16743-w"
87
+ )
88
+ NOTARNICOLA_2022_DOI = "10.1038/s41598-022-16743-w"
89
+
90
+ GLOBAL_TREND_PERIOD = "1982-2020"
91
+ GLOBAL_SNOW_EXTENT_PCT = -3.6
92
+ GLOBAL_SNOW_EXTENT_PCT_UNCERTAINTY = 2.7
93
+ GLOBAL_SNOW_DURATION_DAYS = -15.1
94
+ GLOBAL_SNOW_DURATION_DAYS_UNCERTAINTY = 11.6
95
+
96
+ WINTER_EXTENT_PCT = -11.5
97
+ WINTER_EXTENT_PCT_UNCERTAINTY = 6.9
98
+ SPRING_EXTENT_PCT = 10.0
99
+ SPRING_EXTENT_PCT_UNCERTAINTY = 5.9
100
+
101
+ KARAKORAM_ANOMALY_NOTE = (
102
+ "The decline is real at the global-mean level but NOT spatially "
103
+ "or seasonally uniform -- the deliberate honesty check for this "
104
+ "package. Two real complications: (1) spring (MAM) snow cover "
105
+ "extent shows a positive trend on average (+10.0%+/-5.9%) even as "
106
+ "winter (DJF) shows the steepest decline (-11.5%+/-6.9%); (2) the "
107
+ "northern High Mountain Asia ranges -- Karakoram, Kunlun Shan, "
108
+ "Pamir -- show POSITIVE snow cover extent trends, consistent with "
109
+ "the independently documented 'Karakoram anomaly' in glacier mass "
110
+ "balance, while southern High Mountain Asia declines. The trend "
111
+ "also decelerated after ~2000 relative to 1982-1999. A single "
112
+ "global percentage does not describe every region or season."
113
+ )
114
+
115
+ # =====================================================================
116
+ # Mote et al. 2018: western US snowpack decline, since 1915
117
+ # =====================================================================
118
+
119
+ MOTE_2018_CITATION = (
120
+ "Mote, P.W., Li, S., Lettenmaier, D.P., Xiao, M., Engel, R. "
121
+ "(2018). Dramatic declines in snowpack in the western US. npj "
122
+ "Climate and Atmospheric Science, 1, 2. "
123
+ "DOI: 10.1038/s41612-018-0012-1"
124
+ )
125
+ MOTE_2018_DOI = "10.1038/s41612-018-0012-1"
126
+
127
+ WEST_US_SITE_COUNT = 1766
128
+ WEST_US_TREND_START_YEAR = 1915
129
+ WEST_US_PCT_SITES_DECLINING = 90
130
+ WEST_US_PCT_DECLINES_SIGNIFICANT = 33
131
+ WEST_US_DECLINE_RANGE_PCT = (15, 30)
132
+
133
+ WEST_US_NOTE = (
134
+ "A real, independently large station network (1,766 sites, "
135
+ "primarily April 1 snow water equivalent measurements since "
136
+ "1915): more than 90% of sites show a decline, about one-third of "
137
+ "those declines are statistically significant, and the average "
138
+ "decline across sites is 15-30% since the start of record. "
139
+ "Impacts were largest in spring, in Pacific-coast states, and in "
140
+ "locations with mild winter climates."
141
+ )
142
+
143
+ # =====================================================================
144
+ # Bridge note: connects to P99 (glacier peak water) and P103
145
+ # (distributed-buffer-resilience-utac's unquantified "snow (seasonal)"
146
+ # buffer category in storage_portfolio.py)
147
+ # =====================================================================
148
+
149
+ BRIDGE_NOTE = (
150
+ "distributed-buffer-resilience-utac (P103) names snow (seasonal) "
151
+ "as one of five hydrological buffer types in its "
152
+ "STORAGE_PORTFOLIO_NOTE, alongside reservoirs, soil moisture, "
153
+ "wetlands and groundwater, but leaves it unquantified. This "
154
+ "package fills that gap: the seasonal snow buffer itself is "
155
+ "measurably eroding, in both mountain snow depth/duration "
156
+ "(Matiu et al. 2021, European Alps; Notarnicola 2022, global) "
157
+ "and in the driving warming pattern (Pepin et al. 2015). It also "
158
+ "extends glacier-buffer-utac (P99)'s 'peak water' framing: while "
159
+ "P99 documents the transient glacier-melt buffer, this package "
160
+ "documents the shorter, annually-recurring snowpack buffer that "
161
+ "operates on a faster (seasonal, not multi-decadal) timescale but "
162
+ "is eroding by the same underlying warming."
163
+ )
@@ -0,0 +1,35 @@
1
+ """Elevation-dependent warming (EDW) mechanism review (Pepin et al. 2015).
2
+
3
+ Core module -- a synthesis of candidate mechanisms, not a single
4
+ global measurement. See EDW_NOTE for why this package does not
5
+ attribute one global degrees-per-decade figure to this citation.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from .constants import (
11
+ EDW_CANDIDATE_MECHANISMS,
12
+ EDW_NOTE,
13
+ PEPIN_2015_CITATION,
14
+ )
15
+
16
+
17
+ def edw_candidate_mechanisms() -> tuple[str, ...]:
18
+ """The five candidate mechanisms Pepin et al. (2015) identify for EDW."""
19
+ return EDW_CANDIDATE_MECHANISMS
20
+
21
+
22
+ def is_globally_uniform_pattern() -> bool:
23
+ """Whether elevation-dependent warming follows one uniform global rate.
24
+
25
+ Always False. Pepin et al. (2015) explicitly frame EDW as arising
26
+ from combinations of mechanisms that vary by region, producing
27
+ contrasting regional patterns -- not a single global amplification
28
+ rate. Treating EDW as spatially uniform would overclaim past what
29
+ the review itself supports.
30
+ """
31
+ return False
32
+
33
+
34
+ CITATION = PEPIN_2015_CITATION
35
+ MECHANISM_NOTE = EDW_NOTE
@@ -0,0 +1,72 @@
1
+ """Global mountain snow cover extent/duration, 1982-2020 (Notarnicola 2022).
2
+
3
+ Core module -- the deliberate honesty check for this package. The
4
+ global-mean decline is real, but this module exists specifically to
5
+ prevent the package from becoming a one-sided "snow is disappearing
6
+ everywhere, in every season" narrative. See KARAKORAM_ANOMALY_NOTE.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from dataclasses import dataclass
12
+
13
+ from .constants import (
14
+ GLOBAL_SNOW_DURATION_DAYS,
15
+ GLOBAL_SNOW_DURATION_DAYS_UNCERTAINTY,
16
+ GLOBAL_SNOW_EXTENT_PCT,
17
+ GLOBAL_SNOW_EXTENT_PCT_UNCERTAINTY,
18
+ GLOBAL_TREND_PERIOD,
19
+ KARAKORAM_ANOMALY_NOTE,
20
+ NOTARNICOLA_2022_CITATION,
21
+ SPRING_EXTENT_PCT,
22
+ WINTER_EXTENT_PCT,
23
+ )
24
+
25
+
26
+ @dataclass(frozen=True)
27
+ class GlobalSnowTrend:
28
+ """Notarnicola (2022)'s satellite-based global mountain snow cover trend."""
29
+
30
+ period: str
31
+ extent_pct: float
32
+ extent_pct_uncertainty: float
33
+ duration_days: float
34
+ duration_days_uncertainty: float
35
+ citation: str
36
+
37
+
38
+ GLOBAL_SNOW_TREND = GlobalSnowTrend(
39
+ period=GLOBAL_TREND_PERIOD,
40
+ extent_pct=GLOBAL_SNOW_EXTENT_PCT,
41
+ extent_pct_uncertainty=GLOBAL_SNOW_EXTENT_PCT_UNCERTAINTY,
42
+ duration_days=GLOBAL_SNOW_DURATION_DAYS,
43
+ duration_days_uncertainty=GLOBAL_SNOW_DURATION_DAYS_UNCERTAINTY,
44
+ citation=NOTARNICOLA_2022_CITATION,
45
+ )
46
+
47
+
48
+ def winter_vs_spring_extent_trend_pct() -> dict[str, float]:
49
+ """Seasonal split of global mountain snow cover extent trend.
50
+
51
+ Winter (DJF) shows the steepest decline; spring (MAM) shows a
52
+ positive trend on average -- the two seasons move in opposite
53
+ directions, which is why a single annual-mean percentage does not
54
+ describe every season.
55
+ """
56
+ return {"winter_djf": WINTER_EXTENT_PCT, "spring_mam": SPRING_EXTENT_PCT}
57
+
58
+
59
+ def is_snow_decline_spatially_universal() -> bool:
60
+ """Whether every mountain range shows a snow cover decline.
61
+
62
+ Always False. Northern High Mountain Asia (Karakoram, Kunlun Shan,
63
+ Pamir) shows a POSITIVE snow cover extent trend, consistent with
64
+ the independently documented "Karakoram anomaly" in glacier mass
65
+ balance -- while southern High Mountain Asia declines. See
66
+ KARAKORAM_ANOMALY_NOTE.
67
+ """
68
+ return False
69
+
70
+
71
+ NUANCE_NOTE = KARAKORAM_ANOMALY_NOTE
72
+ CITATION = NOTARNICOLA_2022_CITATION
@@ -0,0 +1,55 @@
1
+ """Western US snowpack decline since 1915 (Mote et al. 2018).
2
+
3
+ Core module -- a real, large (1,766-site) long-term snow-course/SNOTEL
4
+ station network analysis, independent of the two European studies.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from dataclasses import dataclass
10
+
11
+ from .constants import (
12
+ MOTE_2018_CITATION,
13
+ WEST_US_DECLINE_RANGE_PCT,
14
+ WEST_US_NOTE,
15
+ WEST_US_PCT_DECLINES_SIGNIFICANT,
16
+ WEST_US_PCT_SITES_DECLINING,
17
+ WEST_US_SITE_COUNT,
18
+ WEST_US_TREND_START_YEAR,
19
+ )
20
+
21
+
22
+ @dataclass(frozen=True)
23
+ class WestUsSnowpackTrend:
24
+ """Mote et al. (2018)'s observed western US snowpack decline."""
25
+
26
+ trend_start_year: int
27
+ site_count: int
28
+ pct_sites_declining: float
29
+ pct_declines_significant: float
30
+ decline_range_pct: tuple[int, int]
31
+ citation: str
32
+
33
+
34
+ WEST_US_SNOWPACK_TREND = WestUsSnowpackTrend(
35
+ trend_start_year=WEST_US_TREND_START_YEAR,
36
+ site_count=WEST_US_SITE_COUNT,
37
+ pct_sites_declining=WEST_US_PCT_SITES_DECLINING,
38
+ pct_declines_significant=WEST_US_PCT_DECLINES_SIGNIFICANT,
39
+ decline_range_pct=WEST_US_DECLINE_RANGE_PCT,
40
+ citation=MOTE_2018_CITATION,
41
+ )
42
+
43
+
44
+ def majority_of_sites_declining() -> bool:
45
+ """Whether more than half of the 1,766 monitored sites show a decline.
46
+
47
+ Always True -- more than 90% of sites decline, though only about
48
+ a third of those declines are individually statistically
49
+ significant (see pct_declines_significant on the dataclass).
50
+ """
51
+ return WEST_US_SNOWPACK_TREND.pct_sites_declining > 50.0
52
+
53
+
54
+ CITATION = MOTE_2018_CITATION
55
+ NOTE = WEST_US_NOTE
@@ -0,0 +1,101 @@
1
+ """Tests for snowpack-elevation-warming-utac."""
2
+
3
+ from snowpack_elevation_warming_utac import (
4
+ ALPINE_SNOW_TREND,
5
+ GLOBAL_SNOW_TREND,
6
+ PACKAGE_ID,
7
+ WEST_US_SNOWPACK_TREND,
8
+ __version__,
9
+ edw_candidate_mechanisms,
10
+ is_decline_spatially_uniform,
11
+ is_globally_uniform_pattern,
12
+ is_snow_decline_spatially_universal,
13
+ majority_of_sites_declining,
14
+ winter_vs_spring_extent_trend_pct,
15
+ )
16
+
17
+
18
+ def test_version():
19
+ assert __version__ == "1.0.0"
20
+
21
+
22
+ def test_package_id():
23
+ assert PACKAGE_ID == 110
24
+
25
+
26
+ # --- elevation_dependent_warming.py (core) --------------------------------
27
+
28
+
29
+ def test_edw_candidate_mechanisms_count_and_content():
30
+ mechanisms = edw_candidate_mechanisms()
31
+ assert len(mechanisms) == 5
32
+ assert any("albedo" in m for m in mechanisms)
33
+ assert any("aerosol" in m for m in mechanisms)
34
+
35
+
36
+ def test_is_globally_uniform_pattern_always_false():
37
+ assert is_globally_uniform_pattern() is False
38
+
39
+
40
+ # --- alpine_snow_decline.py (core) -----------------------------------------
41
+
42
+
43
+ def test_alpine_snow_trend_values():
44
+ assert ALPINE_SNOW_TREND.period == "1971-2019"
45
+ assert ALPINE_SNOW_TREND.station_count == 2000
46
+ assert ALPINE_SNOW_TREND.trend_station_count == 800
47
+ assert ALPINE_SNOW_TREND.seasonal_mean_depth_pct_per_decade == -8.4
48
+ assert ALPINE_SNOW_TREND.max_depth_pct_per_decade == -5.6
49
+ assert ALPINE_SNOW_TREND.duration_pct_per_decade == -5.6
50
+ assert ALPINE_SNOW_TREND.citation
51
+
52
+
53
+ def test_is_decline_spatially_uniform_always_false():
54
+ assert is_decline_spatially_uniform() is False
55
+
56
+
57
+ # --- global_snow_trends.py (core, honesty-check module) --------------------
58
+
59
+
60
+ def test_global_snow_trend_values():
61
+ assert GLOBAL_SNOW_TREND.period == "1982-2020"
62
+ assert GLOBAL_SNOW_TREND.extent_pct == -3.6
63
+ assert GLOBAL_SNOW_TREND.duration_days == -15.1
64
+ assert GLOBAL_SNOW_TREND.citation
65
+
66
+
67
+ def test_winter_vs_spring_extent_trend_opposite_signs():
68
+ trend = winter_vs_spring_extent_trend_pct()
69
+ assert trend["winter_djf"] < 0
70
+ assert trend["spring_mam"] > 0
71
+
72
+
73
+ def test_is_snow_decline_spatially_universal_always_false():
74
+ # The key honesty check: not every mountain range declines --
75
+ # northern High Mountain Asia shows a positive trend.
76
+ assert is_snow_decline_spatially_universal() is False
77
+
78
+
79
+ # --- west_us_snowpack.py (core) ---------------------------------------------
80
+
81
+
82
+ def test_west_us_snowpack_trend_values():
83
+ assert WEST_US_SNOWPACK_TREND.trend_start_year == 1915
84
+ assert WEST_US_SNOWPACK_TREND.site_count == 1766
85
+ assert WEST_US_SNOWPACK_TREND.pct_sites_declining == 90
86
+ assert WEST_US_SNOWPACK_TREND.pct_declines_significant == 33
87
+ assert WEST_US_SNOWPACK_TREND.decline_range_pct == (15, 30)
88
+ assert WEST_US_SNOWPACK_TREND.citation
89
+
90
+
91
+ def test_majority_of_sites_declining_true():
92
+ assert majority_of_sites_declining() is True
93
+
94
+
95
+ def test_nuance_does_not_contradict_measured_decline():
96
+ # Both can be true at once: the global-mean decline is real
97
+ # (measured across three independent datasets), AND it is not
98
+ # spatially/seasonally universal (Karakoram anomaly, spring uptick).
99
+ assert majority_of_sites_declining() is True
100
+ assert is_decline_spatially_uniform() is False
101
+ assert is_snow_decline_spatially_universal() is False