API reference

Every DEBRA module maps onto a numbered block of equations from Miller et al. (2017). Read down the table to follow the algorithm in the order it runs; the Equations page writes those equations out in full. The one entry marked “—” under Equations is the classic Dust RGB baseline, which is not part of the paper.

Equations

Module

What it does

shachen.io

L1b → calibrated fields; MERRA-2 and CAMEL ancillary

shachen.geo

lat/lon ancillary → satellite grid, land mask

shachen.solar

per-pixel solar zenith angle

Eq. 3

shachen.norm

the normalisation primitive every test uses

§3.2 A

shachen.background

semi-analytic clear-sky background

§3.2 B

shachen.composite

cloud-cleared composite background

Eqs. 1–12

shachen.cloudmask

cloud confidence with dust restoral

Eqs. 13–15

shachen.dust_tests

DT1–DT3 against the dynamic background

Eqs. 16–22

shachen.confidence

day/terminator/night blend → cf_comb

Eqs. 1–22

shachen.pipeline

the entry point per algorithm

Eqs. 23–29

shachen.imagery

baseline image and CF-modulated RGB

§4.2

shachen.render

georeferenced PNG with map overlays

shachen.dustrgb

classic Dust RGB comparison baseline

all

shachen.constants

every bound, offset and weight

Top-level namespace

shachen: infrared-channel dust algorithms for geostationary imagers.

DEBRA-Dust, the Dynamic Enhancement with Background Reduction Algorithm of Miller et al. (2017), doi:10.1002/2017JD027365 (with the 26 Feb 2020 erratum), is the primary one; the classic EUMETSAT Dust RGB ships alongside it as the baseline to compare against.

class shachen.Band[source]

Bases: StrEnum

Spectral roles the algorithms read (nominal wavelengths in um).

Seven of these are DEBRA’s inputs (DEBRA_BANDS); TIR_112 exists only for the classic Dust RGB green gun.

VIS_064 = 'vis_064'

cloud mask + day baseline image

NIR_160 = 'nir_160'

daytime cloud test (reserved)

SWIR_39 = 'swir_39'

night thin-cirrus test CM4

WV_62 = 'wv_62'

deep-convection test CM2

TIR_86 = 'tir_86'

dust test DT2 (8.4-8.6 um)

TIR_104 = 'tir_104'

clean window reference (10.3-10.4 um)

TIR_112 = 'tir_112'

classic Dust RGB green gun only (11.2 um; not a DEBRA input)

TIR_123 = 'tir_123'

dirty window, RSW / DT1 (12.3 um)

__new__(value)
shachen.normalize(x, bounds: Bounds)[source]

N(x) = clip((x - MIN) / (MAX - MIN), 0, 1) (Miller et al. 2017, Eq. 3).

Works on scalars, numpy arrays, and xarray DataArrays. bounds.min may exceed bounds.max (used for the cos-zenith blends specified in zenith-angle space): the sense of the ramp reverses.

shachen.run_debra(scene: Dataset, skin_temperature: DataArray, emissivity: Dataset | None = None, constants: DebraConstants = DebraConstants(cloud_mask=CloudMaskConstants(cm1_cold_offset_k=50.0, cm2=Bounds(min=0.0, max=25.0), cm3=Bounds(min=2.0, max=4.5), cm4=Bounds(min=5.0, max=8.0), r1=Bounds(min=0.0, max=3.5), r2=Bounds(min=-1.0, max=3.0), cm_norm=Bounds(min=0.45, max=0.8)), dust_tests=DustTestConstants(dt1_max_rsw_k=3.5, dt2_max_btd_k=3.0, dt3_shift_land_k=-10.0, dt3_shift_ocean_k=5.0, dt3_depth_k=50.0), confidence=ConfidenceConstants(dt3_weight_trm=0.5, dt3_weight_ngt=0.5, cf_norm=Bounds(min=0.25, max=2.5), blend_exponent=1.5, ngt_trm_zenith_deg=Bounds(min=105.0, max=90.0), trm_day_zenith_deg=Bounds(min=90.0, max=75.0)), imagery=ImageryConstants(bg_blend_zenith_deg=Bounds(min=79.0, max=89.0), bg_blend_exponent=1.5, cf_cap=0.5, blue_dimming=0.1, gun_max=1.2)), *, background: Dataset | None = None) Dataset[source]

Run DEBRA on one scene; returns CF_comb plus all intermediate fields.

scene is a shachen.io.satellite.load_scene() Dataset (bt_* in K on the 2-km grid, with area and start_time attrs); skin_temperature is MERRA-2 TS (K) on its native lat/lon grid, regridded here via shachen.geo.regrid_latlon(). The visible/NIR reflectance variables are not used here; they feed the enhanced imagery.

Exactly one background source must be given (ValueError otherwise):

  • emissivity: the CAMEL band Dataset (emis_*) on its native lat/lon grid; regridded here, then fed through shachen.background.background_signals() (semianalytic mode);

  • background: a precomputed Dataset already on the scene grid (e.g. shachen.composite.composite_background()) carrying rsw_bg, btd_bg and bt_bg_tir_86/104/123; missing variables or 2-D shapes differing from the scene raise ValueError. Its n_valid is passed through to the output when present.

Returns a Dataset on the scene grid carrying cf_comb, cf_day, cf_trm, cf_ngt, cm_norm_day, cm_norm_ngt, dt1-dt3, rsw_bg, btd_bg, and zenith_deg, with the scene’s area and start_time attrs preserved. Pixels with NaN inputs (off-disk, bad pixels) carry NaN confidence.

shachen.run_dust_rgb(scene: Dataset, constants: DustRGBConstants | None = None) Dataset[source]

Run the classic Dust RGB baseline on one scene.

The counterpart of run_debra() for the recipe in shachen.dustrgb: same scene in, but no ancillary data, no cloud mask and no confidence field — three fixed stretches of bt_tir_86/104/112/123 (11.2 um is the extra band DEBRA itself never reads). A scene loaded with roles=DEBRA_BANDS therefore raises ValueError here.

The stretches are per sensor. Unlike DEBRA, the Dust RGB has no one canonical set of numbers: it was tuned for SEVIRI and then re-tuned for each later imager, because the corresponding channels do not sit at the same wavelengths. With constants=None (the default) the set is chosen from scene.attrs["reader"] through shachen.constants.DUST_RGB_BY_READER — ABI gets the Quick Guide’s adjusted values, AHI the original SEVIRI ones — so the baseline matches that sensor’s operational product. An unknown or absent reader falls back to shachen.constants.DUST_RGB (SEVIRI); pass constants explicitly to pin one set across sensors, e.g. to compare the two.

Returns a Dataset carrying dust_rgb — dims (y, x, gun), floats in [0, 1], ready for shachen.imagery.to_uint8() — with the scene’s area and start_time attrs preserved, so it merges straight into a run_debra() result for side-by-side rendering.