met_qaqc¶
met_qaqc ¶
PyAERMOD Meteorological Data QA/QC
Quality assurance checks and diagnostics for processed met data (SFC / PFL files, or intermediate hourly records). These checks catch common AERMET output problems that cause silent AERMOD failures:
- Missing-data run lengths (AERMOD tolerates <10% missing; longer gaps mean the hour will be skipped, biasing statistics).
- Physical-extreme flags (temperature, wind speed, mixing heights, Monin-Obukhov length, friction velocity).
- Stability-class consistency between surface heat-flux sign and mixing-height regime (e.g. L<0 should align with CBL, not SBL).
- Low-wind bias screening (high fraction of sub-threshold speeds).
- Temperature-profile monotonicity flags for upper-air soundings.
The functions here operate on plain Python dicts / lists so they can
be applied both to AERMET .SFC output (via read_surface_file) and to
raw ingested hourly data (e.g. from ISDFetcher.read_hourly).
QAQCFinding
dataclass
¶
One QA/QC issue found in a met record set.
QAQCReport
dataclass
¶
Aggregated QA/QC report for a dataset.
find_missing_runs ¶
find_missing_runs(records: Sequence[Dict[str, Any]], field_name: str, min_run: int = 6) -> List[tuple]
Return (start_idx, end_idx, length) for runs of missing data.
A value is "missing" if it is None. Runs shorter than min_run
are ignored (default 6 hours = AERMET Stage 1 'substantive gap').
check_missing_data ¶
check_missing_data(records: Sequence[Dict[str, Any]], fields: Iterable[str] = ('wind_speed_ms', 'wind_dir', 'temp_c'), max_missing_fraction: float = 0.1, long_run_hours: int = 24) -> QAQCReport
Report missing-data issues across a time series.
Raises warnings for long missing runs and an error if any field
exceeds max_missing_fraction (default 10% — AERMET guidance).
check_extremes ¶
Flag records whose values are outside physically plausible ranges.
check_stability_consistency ¶
Flag mismatches between Monin-Obukhov length sign and mixing height.
In a convective boundary layer (CBL): L < 0 and both zic (convective
mixing height) and zim (mechanical mixing height) should be
populated, with zic > zim typically.
In a stable boundary layer (SBL): L > 0 and zic should be 0/unused.
AERMET writes an SFC record with both; inconsistency is a red flag that the MMIF or raw obs data were misinterpreted.
check_low_wind_bias ¶
check_low_wind_bias(records: Sequence[Dict[str, Any]], threshold_ms: float = LOW_WIND_THRESHOLD_MS, warn_fraction: float = LOW_WIND_FRACTION_WARN) -> QAQCReport
Flag datasets where an unusually high fraction of hours are near-calm.
An inflated calm fraction is a strong signal of bad anemometer placement, poor starting threshold, or incorrect AERMINUTE processing. AERMOD has its own LOWWIND options; this is a data quality alarm, not a runtime config check.
check_profile_monotonic ¶
Flag sounding levels whose pressure is not strictly decreasing.
Radiosonde ascents must have monotonically decreasing pressure. Any reversal is an instrument/QC artifact AERMET Stage 1 will either drop or mis-process.
run_all_qaqc ¶
Run every surface-data QA/QC check and return a merged report.