Source code for mhm_tools.post.difference

"""
Calculate the spatial difference between reference and model datasets.

This script is intended for NetCDF files that represent *aggregated fields*
(such as long-term averages, climatologies, or single-time snapshots), rather
than full time series. It loads the reference and model datasets, interpolates
the model onto the reference grid, and then computes the difference
(reference - model). The result is visualized as a map and, optionally, written
to a NetCDF file.

Authors
-------
- Jeisson Leal
"""

from dataclasses import dataclass
from pathlib import Path
from typing import Optional

from mhm_tools.common.file_handler import write_xarray_to_file
from mhm_tools.common.netcdf import read_dataset
from mhm_tools.common.plotter import plot_map
from mhm_tools.common.xarray_utils import get_coord_key, normalize_lat_lon


[docs] @dataclass class PlotOptions: """Plotting options for the difference map.""" colorbar_label: str title: str cmap: str = "RdBu" vmin: Optional[float] = None vmax: Optional[float] = None x_min: Optional[float] = None x_max: Optional[float] = None y_min: Optional[float] = None y_max: Optional[float] = None
[docs] @dataclass class OutputOptions: """Output configuration for generated PNG/NetCDF files.""" output_dir: str output_file_png: str save_ncfile: bool output_file_nc: str
[docs] def calc_diff( ref_input_dir: str, mod_input_dir: str, reference_pattern: str, model_pattern: str, ref_var: str, mod_var: str, plot: PlotOptions, output: OutputOptions, ) -> None: """Compute long-term mean difference between model and reference datasets and plot the result.""" ds_ref = read_dataset(file_path=str(Path(ref_input_dir) / reference_pattern)) ds_mod = read_dataset(file_path=str(Path(mod_input_dir) / model_pattern)) # Get coordinate names ref_lat = get_coord_key(ds_ref, lat=True) ref_lon = get_coord_key(ds_ref, lon=True) mod_lat = get_coord_key(ds_mod, lat=True) mod_lon = get_coord_key(ds_mod, lon=True) # Normalize lat/lon names and squeeze time dimension da_ref = normalize_lat_lon(ds_ref, lat_key=ref_lat, lon_key=ref_lon)[ ref_var ].squeeze("time") da_mod = normalize_lat_lon(ds_mod, lat_key=mod_lat, lon_key=mod_lon)[ mod_var ].squeeze("time") # Interpolate model to reference grid to avoid alignment errors da_mod_interp = da_mod.interp_like(da_ref) # Compute difference diff = da_ref - da_mod_interp # Prepare output directory out_path_dir = Path(output.output_dir) out_path_dir.mkdir(parents=True, exist_ok=True) out_path = out_path_dir / output.output_file_png # Plot difference map plot_map( data=diff, cb_label=plot.colorbar_label, title=plot.title, out_path=out_path, cmap=plot.cmap, x_min=plot.x_min, x_max=plot.x_max, y_min=plot.y_min, y_max=plot.y_max, vmin=plot.vmin, vmax=plot.vmax, ) # Optionally save NetCDF if output.save_ncfile: write_xarray_to_file(ds=diff, file_path=out_path_dir / output.output_file_nc)