Skip to content

Conversation

@sunt05
Copy link

@sunt05 sunt05 commented Nov 26, 2025

Summary

Add a new diagnostic module that decomposes near-surface temperature (T2) differences between scenarios into physically attributable components using Shapley value decomposition.

Key Features

  • attribute_t2(): Compare two SUEWS scenarios, decompose ΔT2 into:

    • Flux contribution (with breakdown: Q*, QE, ΔQS, QF)
    • Resistance contribution (turbulent exchange efficiency)
    • Air properties contribution (ρ × cp)
  • diagnose_t2(): Automatic anomaly detection for single-run debugging:

    • 'anomaly': Detect timesteps > N σ from daily mean
    • 'extreme': Compare top/bottom 5% vs. middle 50%
    • 'diurnal': Compare afternoon peak vs. morning baseline
  • AttributionResult class with:

    • Clean __repr__ showing percentages
    • plot() method with 4 visualisation modes: bar, diurnal, line, heatmap
    • to_dataframe() for further analysis

Mathematical Foundation

Uses exact Shapley decomposition for the triple product T2 = r × QH × γ:

Φ_r + Φ_F + Φ_γ = ΔT2  (exact closure guaranteed)

Use Cases

  1. Debugging: "Why does T2 behave unexpectedly at certain times?"
  2. Green infrastructure: "Which mechanism drives cooling - evaporation or albedo?"
  3. Sensitivity analysis: Quantify relative importance of different processes

Files Changed

File Change
src/supy/util/_attribution.py New module (~600 lines)
src/supy/util/__init__.py Export new functions
docs/source/tutorials/python/attribution-tutorial.ipynb Tutorial notebook
docs/source/tutorials/python/tutorial.rst Add to learning path

Test plan

  • Shapley closure property verified (exact to machine precision)
  • Array operations preserve closure
  • Zero contributions for identical scenarios
  • AttributionResult __repr__ generates formatted output
  • All plot types (bar, diurnal, line) work correctly
  • Integration test with real SUEWS output (pending build fix)

🤖 Generated with Claude Code

@github-actions
Copy link

🤖 I've automatically formatted the code in this PR using:

  • Python: ruff v0.8.6
  • Fortran: fprettify v0.3.7

Please pull the latest changes before making further edits.

1 similar comment
@github-actions
Copy link

🤖 I've automatically formatted the code in this PR using:

  • Python: ruff v0.8.6
  • Fortran: fprettify v0.3.7

Please pull the latest changes before making further edits.

@sunt05 sunt05 force-pushed the feat/t2-attribution-module branch from 643db7d to e42529e Compare November 27, 2025 10:40
@github-actions
Copy link

🤖 I've automatically formatted the code in this PR using:

  • Python: ruff v0.8.6
  • Fortran: fprettify v0.3.7

Please pull the latest changes before making further edits.

@sunt05 sunt05 force-pushed the feat/t2-attribution-module branch from a205020 to b9b11d7 Compare November 27, 2025 12:52
sunt05 and others added 7 commits November 27, 2025 20:04
Add a new diagnostic module that decomposes near-surface temperature
differences between scenarios into physically attributable components
using Shapley value decomposition.

Features:
- attribute_t2(): Compare two scenarios, decompose delta-T2 into flux,
  resistance, and air property contributions
- diagnose_t2(): Automatic anomaly detection with methods: 'anomaly',
  'extreme', 'diurnal'
- AttributionResult class with plot() method (bar, diurnal, line, heatmap)
- Hierarchical flux breakdown into Q*, QE, dQS, QF components
- Exact closure guaranteed by Shapley decomposition

Use cases:
- Debug unexpected T2 values in simulations
- Understand why green infrastructure cools cities
- Quantify physical mechanisms driving temperature changes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-authored-by: sunt05 <1802656+sunt05@users.noreply.github.com>
Add multi-variable attribution capability following the same Shapley
decomposition framework used for T2. The q2 (2m specific humidity)
attribution uses latent heat flux (QE) and the scale factor gamma =
1/(rho*Lv) to decompose humidity differences into physical mechanisms.

New functions:
- attribute_q2(): Decompose q2 differences between two scenarios
- diagnose_q2(): Automatic anomaly detection for humidity
- attribute(): Generic dispatcher for T2/q2
- diagnose(): Generic dispatcher for T2/q2
- _cal_gamma_humidity(): Scale factor for latent heat
- _cal_r_eff_humidity(): Back-calculate moisture resistance

The design maximises code reuse - both T2 and q2 follow the same
flux-gradient physics pattern (X = X_ref + r * F * gamma).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-authored-by: sunt05 <1802656+sunt05@users.noreply.github.com>
Include the new attribution module in the meson build system.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add comprehensive test suite for T2/q2 attribution functions
- Improve error handling with numpy errstate for division operations
- Add input validation for required DataFrame columns
- Add warnings when forcing data not provided (affects accuracy)
- Add warnings when significant data loss during index alignment
- Add logging for low-flux timesteps producing NaN values
- Improve docstrings with mathematical references (Owen 1972)
- Fix Celsius to Kelvin conversion (273.16 -> 273.15)
- Fix British English spelling in tutorial documentation
Restructure _attribution.py into _attribution/ package with separate
modules for better maintainability. Add wind speed (U10) attribution
alongside existing T2 and Q2 support.

Co-Authored-By: Claude <noreply@anthropic.com>
@sunt05 sunt05 force-pushed the feat/t2-attribution-module branch from 525ea60 to 833d7dd Compare November 27, 2025 20:04
Co-authored-by: sunt05 <1802656+sunt05@users.noreply.github.com>
@github-actions
Copy link

🤖 I've automatically formatted the code in this PR using:

  • Python: ruff v0.8.6
  • Fortran: fprettify v0.3.7

Please pull the latest changes before making further edits.

Update test imports to reflect the refactored attribution module which
is now organised as a package with separate submodules for core Shapley
functions, physics calculations, and helper utilities.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants