I/O

Readers for the three inputs DEBRA needs: calibrated L1b imagery, MERRA-2 skin temperature, and the surface emissivity climatology. None of this is on the import shachen path — each function needs the satellite or data extra.

Satellite imagery

Satellite L1b -> calibrated BT/reflectance fields on the 2-km IR grid.

satpy does the radiance -> BT / reflectance calibration and the native down-sampling of the VIS/NIR bands onto the coarsest (2 km) grid, so ABI netCDF and Himawari AHI HSD share one code path.

shachen.io.satellite.load_scene(files: Iterable[str | Path], reader: str = 'abi_l1b', roles: Iterable[Band] | None = None, bbox: tuple[float, float, float, float] | None = None) → Dataset[source]

Load L1b files and return a Dataset on the sensor’s 2-km fixed grid.

Variables are named by DEBRA role: bt_tir_104 etc. for emissive bands (K), refl_vis_064 etc. for reflective bands (%). The pyresample AreaDefinition is attached as ds.attrs["area"] and the scan start time as ds.attrs["start_time"].

roles restricts loading to a subset of DEBRA bands (e.g. shachen.composite.COMPOSITE_BANDS for TIR-only composite days, whose directories hold only those bands’ files); None loads all seven.

bbox = (lon_min, lat_min, lon_max, lat_max) in degrees crops the scene (satpy Scene.crop(ll_bbox=...)) after the native resample, so every variable and attrs["area"] describe the cropped grid — This trims AHI full disks (5500 x 5500 at 2 km) to the domain of interest. None keeps the full scene.

MERRA-2 reanalysis

MERRA-2 hourly surface skin temperature (TS from M2T1NXSLV).

Downloads via earthaccess using the Earthdata login in ~/.netrc. The full tavg1_2d_slv_Nx day file is large, so it is stripped after download to a small TS-only netCDF cache, which the pipeline regrids onto the satellite grid.

shachen.io.merra.SURFACE_MET_SLV_VARS = ('T2M', 'QV2M', 'PS', 'U10M', 'V10M')

Single-level variables the dust-PM10 matchup keeps from M2T1NXSLV.

shachen.io.merra.FLX_SHORT_NAME = 'M2T1NXFLX'

Boundary-layer height comes from the surface-flux collection.

shachen.io.merra.fetch_skin_temperature(day: date, out_dir: Path) → Path[source]

Download MERRA-2 TS for day; return path to a TS-only netCDF.

shachen.io.merra.fetch_surface_meteorology(day: date, out_dir: Path) → Path[source]

Download the dust-PM10 met covariates for day; return a cache path.

The cache merra2_met_<%Y%m%d>.nc merges SURFACE_MET_SLV_VARS from M2T1NXSLV with SURFACE_MET_FLX_VARS (PBLH) from M2T1NXFLX, both hourly on the native 0.5 x 0.625 degree grid.

shachen.io.merra.load_surface_meteorology(path: Path, when: datetime) → Dataset[source]

Load the met covariates interpolated to when.

Same half-past-the-hour time stamps, and the same clamping at the ends of the day, as load_skin_temperature().

shachen.io.merra.load_skin_temperature(path: Path, when: datetime) → DataArray[source]

Load TS (K) interpolated to when on the MERRA-2 grid.

Linear in time between the half-past-the-hour stamps, clamped to the file’s first and last hourly mean — see _interp_to_time().

Surface emissivity

IR surface emissivity climatology, interpolated to sensor band centers.

The paper uses the monthly UW Baseline Fit (UWBF, CIMSS) 0.05-degree climatology, which needs a separate CIMSS registration. The default here is its successor, CAMEL (CAM5K30EM on NASA LP DAAC), reachable with the same Earthdata credentials as MERRA-2. A downloaded UWBF file works too: both formats carry an emissivity cube on labelled hinge-point wavelengths, and interpolation is linear in wavelength, as the paper implies.

shachen.io.emissivity.EMISSIVE_BANDS = (Band.SWIR_39, Band.WV_62, Band.TIR_86, Band.TIR_104, Band.TIR_123)

DEBRA only needs emissivity for the emissive bands used by the background.

shachen.io.emissivity.fetch_emissivity(month: date, out_dir: Path, fallback_years: int = 8) → Path[source]

Download the CAMEL monthly emissivity file covering month.

CAM5K30EM V003 stops at 2023-12, so a scene after that has no emissivity file of its own. Rather than fail, fall back to the same calendar month of the most recent year that does have one, up to fallback_years back, and warn which file was used.

The substitution is smaller than it looks. What the paper actually uses is the UWBF monthly climatology, which carries no year at all: land emissivity in the thermal window is set by land cover and its seasonal cycle, and April over the Gobi looks much the same from one year to the next. Reading April 2023 for an April 2025 scene is the same kind of approximation the paper makes on purpose – what would not be acceptable is reading a different month, which is why the search only ever walks back in whole years.

shachen.io.emissivity.load_band_emissivity(path: Path, bands: tuple[Band, ...] = (Band.SWIR_39, Band.WV_62, Band.TIR_86, Band.TIR_104, Band.TIR_123)) → Dataset[source]

Load hinge-point emissivity and interpolate to DEBRA band centers.

Returns a Dataset with one emis_<band> variable per requested band on the climatology’s native lat/lon grid, values masked where the file has no retrieval (ocean/fill).