Skip to content

Rb/callmip phase1a#1626

Open
braghiere wants to merge 5 commits intomainfrom
rb/callmip-Phase1a
Open

Rb/callmip phase1a#1626
braghiere wants to merge 5 commits intomainfrom
rb/callmip-Phase1a

Conversation

@braghiere
Copy link
Copy Markdown
Member

@braghiere braghiere commented Feb 4, 2026

Purpose

Implement CalMIP Phase 1a test site (DK-Sor) simulation infrastructure with three model configurations, CalMIP-compliant snow partitioning, NetCDF output support, and validation against FLUXNET observations. This enables participation in the Calibration Land Model Intercomparison Project and provides a framework for evaluating ClimaLand against standardized flux tower benchmarks.

Related: CalMIP Phase 1 Protocol - https://github.com/callmip-org/Phase1
Reference: Default and PModel configurations follow patterns established by Eva-Marie Metz on branch EM/siteruns_Neon_globalParam (high-level LandModel constructor and PModel overrides)

Content

Core Infrastructure:

  • Add DK-Sor site configuration (ext/fluxnet_simulations/DK-Sor.jl) with ~50 site-specific parameters
  • Switch simulation output from DictWriter to NetCDFWriter for file-based diagnostics
  • Extend DK-Sor simulation period from 1-day test to full year 2008 (365 days)
  • Add CalMIP site support to initial_conditions.jl with site detection logic
  • Update Artifacts.jl with callmip_data_path() function for external data management
  • Configure 16 diagnostic variables with half-hourly (30-minute) output frequency
  • Add NEE and ER diagnostics with ILAMB support

Three Simulation Configurations:

  1. Explicit (callmip_dksor.jl): SoilCanopyModel with site-specific parameters from DK-Sor.jl (Farquhar, Medlyn, no snow model)
  2. Default LandModel (callmip_dksor_default.jl): High-level LandModel constructor with all defaults and snow model — auto-configured from spatial/toml parameters (following Eva-Marie's NEON_cper_pft.jl pattern)
  3. PModel LandModel (callmip_dksor_pmodel.jl): LandModel with PModel photosynthesis, PModelConductance, and PiecewiseMoistureStressModel overrides (following Eva-Marie's NEON_cper_pmodel.jl pattern)

CalMIP Snow Partitioning:

  • Add :callmip option to split_precip in forcing.jl implementing CalMIP Phase 1 binary threshold (Tair < 273.15K → snow, ≥ 273.15K → rain)
  • Existing Jennings et al. (2018) logistic function preserved as split_precip=true or :jennings
  • Applied across all CalMIP experiment configurations

Bug Fix:

  • Fix broadcast issue in initial_conditions.jl (model.parameters.ν ./ 2 instead of / 2) — needed because LandModel auto-constructor produces ClimaCore Fields from spatial data lookup, not scalar Float64

Site Configuration:

  • DK-Sor (Denmark Sorø): Deciduous broadleaf forest, beech dominated
  • Location: 55.486°N, 11.6446°E, UTC+1
  • Forcing data: 1997-2015 FLUXNET2015 format (315,552 timesteps)
  • Domain: 1D column, -10m to 30m (soil + canopy), 20 exponentially-stretched layers

Documentation:

  • Comprehensive README with setup instructions, data flow pipeline, and troubleshooting
  • CalMIP quickstart guide, setup guide, and summary documents

Validation Results:
Full year 2008 simulation for all 3 configurations compared against FLUXNET daily observations:

Latent Heat Flux (LE):

Config RMSE (W/m²) Bias (W/m²) R
Explicit 32.1 -19.1 0.852
Default 41.4 -25.9 0.455
PModel 27.9 -17.0 0.854

Sensible Heat Flux (H):

Config RMSE (W/m²) Bias (W/m²) R
Explicit 62.1 +47.5 0.756
Default 58.4 +42.2 0.748
PModel 52.2 +35.1 0.773

PModel configuration performs best overall. All configs underestimate LE and overestimate H, indicating insufficient energy partitioning to latent heat — a known area for calibration improvement.

image image image image

Technical Details:

  • Timestep: 450 seconds (7.5 minutes)
  • Integration: IMEX scheme with ARS111 timestepper
  • Model components: EnergyHydrology soil, CanopyModel with plant hydraulics, SoilCO2 biogeochemistry, SnowModel (Default/PModel configs)
  • Output format: NetCDF with CF-compliant metadata
  • Simulation time: ~6 minutes for full year on typical workstation (~210-565 SYPD depending on config)

Notes

  • Python analysis scripts developed locally but not included in this PR (follow ClimaLand convention of Julia-only high-level code)
  • CalMIP forcing data stored externally on Sampo cluster (/net/sampo/data1/renatob/callmip_forcing/)
  • Output files (~60 MB NetCDF) excluded by .gitignore as intended
  • Follows existing FLUXNET site pattern established by US-MOz, US-NR1, US-Ha1, US-Var

  • I have read and checked the items on the review checklist.

- Add DK-Sor (Denmark Sorø) CalMIP test site configuration
- Implement callmip_data_path() in Artifacts.jl for external data management
- Update data_processing.jl to support CalMIP sites
- Add comprehensive documentation (setup guide, quickstart, summary)
- Follow ClimaLand artifact pattern (data not in git repo)

CalMIP forcing data should be stored externally via:
- Environment variable: CALLMIP_DATA_PATH
- Local path: ../callmip_data/
- Or added to ClimaArtifacts (recommended for production)

Related to CalMIP Phase 1 protocol:
https://github.com/callmip-org/Phase1
- Switch from DictWriter to NetCDFWriter for file output
- Extend simulation period to full year 2008
- Add CalMIP site support to initial_conditions.jl
- Update Artifacts.jl with default data path for Sampo cluster
- Add comprehensive README with setup and usage instructions

Successfully ran full year simulation with 16 diagnostic variables.
Validation against FLUXNET observations shows:
- Latent heat: R=0.85, RMSE=32 W/m²
- Sensible heat: R=0.76, RMSE=62 W/m²
Copilot AI review requested due to automatic review settings February 4, 2026 20:11
@braghiere braghiere requested a review from kmdeck February 4, 2026 20:14
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds CalMIP Phase 1a (DK-Sor) support to the Fluxnet simulation framework, including a new site configuration, experiment runner, and documentation, with CalMIP forcing-data path handling.

Changes:

  • Introduce callmip_data_path() and route CalMIP sites to it from Fluxnet data reading + IC initialization.
  • Add DK-Sor site configuration (get_domain_info, get_location, get_parameters, etc.) and include it in the FluxnetSimulations extension.
  • Add a DK-Sor CalMIP experiment runner plus multiple CalMIP setup/quickstart docs.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 17 comments.

Show a summary per file
File Description
src/Artifacts.jl Adds callmip_data_path() for CalMIP forcing CSV location.
ext/fluxnet_simulations/initial_conditions.jl Routes DK-Sor IC initialization to CalMIP forcing path.
ext/fluxnet_simulations/data_processing.jl Routes DK-Sor forcing reads to CalMIP forcing path.
ext/fluxnet_simulations/DK-Sor.jl New DK-Sor site/domain/parameter definitions for CalMIP.
ext/FluxnetSimulationsExt.jl Includes the new DK-Sor site config file.
experiments/integrated/fluxnet/callmip_dksor.jl New CalMIP DK-Sor experiment runner with NetCDF diagnostics output.
experiments/integrated/fluxnet/CALLMIP_README.md Adds a DK-Sor CalMIP run/usage guide.
docs/CALLMIP_SUMMARY.md Adds high-level CalMIP integration summary.
docs/CALLMIP_SETUP.md Adds detailed CalMIP site setup instructions.
docs/CALLMIP_QUICKSTART.md Adds CalMIP quickstart/checklist.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread experiments/integrated/fluxnet/callmip_dksor.jl Outdated
SAI = FT(1.0),
f_root_to_shoot = FT(3.0),
# Plant hydraulics parameters
K_sat_plant = 8e-8,
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get_parameters is parameterized by FT, but K_sat_plant is a Float64 literal. If callers pass FT = Float32 (or other types), this introduces unintended type promotion. Wrap it as FT(8e-8) so the returned parameter tuple stays consistently typed (and downstream models remain type-stable).

Suggested change
K_sat_plant = 8e-8,
K_sat_plant = FT(8e-8),

Copilot uses AI. Check for mistakes.
nelements = 20, zmin = FT(-10), zmax = FT(0))

Gets and returns primary domain information for the DK-Sor (Denmark Sorø) CalMIP site.
Default parameters are provided and can be overriden using keyword arguments.
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in docstring: "overriden" should be "overridden".

Suggested change
Default parameters are provided and can be overriden using keyword arguments.
Default parameters are provided and can be overridden using keyword arguments.

Copilot uses AI. Check for mistakes.
Comment on lines +320 to +321
# Close the output writers to flush diagnostics to files
ClimaLand.Diagnostics.close_output_writers(diags)
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

solve!(simulation) already closes diagnostics writers in a finally block (see src/simulations/Simulations.jl). Calling close_output_writers(diags) again here can double-close the underlying NetCDF resources and may error depending on the writer implementation. Remove this extra close call (or guard it so it only runs when needed).

Suggested change
# Close the output writers to flush diagnostics to files
ClimaLand.Diagnostics.close_output_writers(diags)
# Output files have been written by the simulation

Copilot uses AI. Check for mistakes.
Comment thread docs/CALLMIP_SUMMARY.md
Comment on lines +15 to +18
- **`data/callmip_sites/DK-Sor.csv`** - Example CSV template with forcing data format
- Contains 24 rows of example meteorological data
- Shows required column structure and units
- **Note:** Replace with actual CalMIP data before running real simulations
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doc claims a committed example forcing file exists at data/callmip_sites/DK-Sor.csv, but the repository has no data/ directory and the code currently expects CALLMIP_DATA_PATH (or a cluster-specific path). Please correct the documentation to match the actual data distribution strategy (external path/env var vs. committed template file).

Suggested change
- **`data/callmip_sites/DK-Sor.csv`** - Example CSV template with forcing data format
- Contains 24 rows of example meteorological data
- Shows required column structure and units
- **Note:** Replace with actual CalMIP data before running real simulations
- **`$CALLMIP_DATA_PATH/callmip_sites/DK-Sor.csv`** (or cluster-specific equivalent) - Example CSV template path for forcing data
- Expected to contain meteorological forcing data for DK-Sor in the required column structure and units
- Not committed to this repository; users must obtain CalMIP forcing data separately
- **Note:** Set `CALLMIP_DATA_PATH` (or use your cluster-specific data path) and place the DK-Sor forcing file there before running real simulations

Copilot uses AI. Check for mistakes.

# Set up the timestepping information for the simulation
dt = Float64(450) # 7.5 minutes
# Define simulation period - short 1-day test
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The simulation-period comment is stale: it says "short 1-day test" but stop_date is set for a full-year run. Please update/remove the comment to avoid confusing users about the intended run length.

Suggested change
# Define simulation period - short 1-day test
# Define simulation period - full year 2008

Copilot uses AI. Check for mistakes.
Comment on lines +36 to +40
- **File**: `compare_callmip_observations.py`
- **Purpose**: Compare simulation outputs with flux observations
- **Features**:
- Reads HDF5 simulation outputs
- Reads NetCDF flux observations
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section says the comparison script reads HDF5 simulation outputs, but the experiment uses NetCDFWriter (NetCDF output). Please update the README (and any filenames/examples) so users don’t try to read the wrong format.

Copilot uses AI. Check for mistakes.
Comment thread docs/CALLMIP_SETUP.md
Comment on lines +69 to +73
**Option 2: Default Local Path**
```bash
# ClimaLand will look in: ../callmip_data/ (relative to ClimaLand.jl)
mkdir ../callmip_data
# Place your CSV files there
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docs describe a "Default Local Path" of ../callmip_data/, but callmip_data_path currently falls back to /net/sampo/data1/renatob/... when CALLMIP_DATA_PATH is unset. Please align the documented default with the implemented behavior (or update the code to match the docs).

Suggested change
**Option 2: Default Local Path**
```bash
# ClimaLand will look in: ../callmip_data/ (relative to ClimaLand.jl)
mkdir ../callmip_data
# Place your CSV files there
**Option 2: Built‑in Cluster Default (Caltech deployment)**
```bash
# If CALLMIP_DATA_PATH is NOT set, ClimaLand currently falls back to:
# /net/sampo/data1/renatob/... (Caltech cluster path, not portable)
# External users should NOT rely on this. Instead, choose a local directory,
# e.g. ../callmip_data relative to ClimaLand.jl:
mkdir -p ../callmip_data
# and point CALLMIP_DATA_PATH there:
export CALLMIP_DATA_PATH="../callmip_data"
# Place your CSV files there, e.g.: ../callmip_data/DK-Sor.csv

Copilot uses AI. Check for mistakes.
Comment thread docs/CALLMIP_SETUP.md
Comment thread docs/CALLMIP_SETUP.md
Comment thread experiments/integrated/fluxnet/callmip_dksor.jl
Comment thread experiments/integrated/fluxnet/callmip_dksor.jl
Comment thread experiments/integrated/fluxnet/callmip_dksor.jl
Comment thread experiments/integrated/fluxnet/callmip_dksor.jl
Comment thread experiments/integrated/fluxnet/callmip_dksor.jl
Comment thread experiments/integrated/fluxnet/callmip_dksor.jl
Comment thread ext/fluxnet_simulations/DK-Sor.jl
- Add `:callmip` option to `split_precip` in forcing.jl implementing
  CalMIP Phase 1 binary threshold (Tair < 273.15K → snow, else rain)
- Fix broadcast issue in initial_conditions.jl (ν ./ 2) for LandModel
  which produces ClimaCore Fields instead of scalar Float64
- Add callmip_dksor_default.jl: high-level LandModel with all defaults
  (Farquhar, Medlyn, TwoStream, Snow)
- Add callmip_dksor_pmodel.jl: LandModel with PModel photosynthesis,
  PModelConductance, and PiecewiseMoistureStressModel overrides
- Apply CalMIP snow partitioning across all experiment configs
- Fix CalMIP acronym in README (Calibration, not California)
@CliMA CliMA deleted a comment from Copilot AI Feb 11, 2026
@CliMA CliMA deleted a comment from Copilot AI Feb 11, 2026
@CliMA CliMA deleted a comment from Copilot AI Feb 11, 2026
@CliMA CliMA deleted a comment from Copilot AI Feb 11, 2026
@CliMA CliMA deleted a comment from Copilot AI Feb 11, 2026
@CliMA CliMA deleted a comment from Copilot AI Feb 11, 2026
@CliMA CliMA deleted a comment from Copilot AI Feb 11, 2026
@CliMA CliMA deleted a comment from Copilot AI Feb 11, 2026
@CliMA CliMA deleted a comment from Copilot AI Feb 11, 2026
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.

3 participants