mostlyright.qc
mostlyright.qc
Section titled “mostlyright.qc”Phase 3.4 — QC Engine Alpha + sidecar + crosscheck.
Phase 3.4 v0.1.0 scope: alpha QC engine that flags-and-keeps observation
rows + writes a sidecar parquet using QC_SIDECAR_SCHEMA. 5-8 alpha
rules cover the obvious physical-bounds + cross-source-disagreement
cases. Forecast QC + climate QC defer to v0.2.
Surface:
QCEngine— bitfield rule registry + apply().QCRule— Protocol every rule satisfies.ALPHA_RULES— the 5-8 rules registered in v0.1.0.crosscheck_iem_ghcnh(df)()— IEM vs GHCNh disagreement detection.
Module Attributes
Section titled “Module Attributes”ALPHA_RULES | The 5 alpha rules registered in v0.1.0. |
|---|
Functions
Section titled “Functions”crosscheck_iem_ghcnh(iem_df, ghcnh_df, *[, …]) | Cross-check IEM and GHCNh temperatures; return disagreement rows. |
|---|
Classes
Section titled “Classes”QCEngine() | Apply registered rules to observation DataFrames; emit bitfield + sidecar. |
|---|---|
QCRule(*args, **kwargs) | Protocol every QC rule satisfies. |
mostlyright.qc.ALPHA_RULES : tuple[_RuleSpec, …] = (_RuleSpec(rule_id=‘temp_c.out_of_range’, bit_position=0, description=‘Temperature outside [-89C, 57C] (world-record bounds).’, evaluator=<function _rule_temp_out_of_range>), _RuleSpec(rule_id=‘dew_point_c.exceeds_temp’, bit_position=1, description=‘Dewpoint greater than temperature (physically impossible).’, evaluator=<function _rule_dewpoint_exceeds_temp>), _RuleSpec(rule_id=‘wind_speed_ms.negative’, bit_position=2, description=‘Wind speed negative.’, evaluator=<function _rule_wind_speed_negative>), _RuleSpec(rule_id=‘wind_dir_deg.out_of_range’, bit_position=3, description=‘Wind direction outside [0, 360].’, evaluator=<function _rule_wind_dir_out_of_range>), _RuleSpec(rule_id=‘slp_hpa.out_of_range’, bit_position=4, description=‘Sea-level pressure outside [870, 1085] mb.’, evaluator=<function _rule_slp_out_of_range>))
Section titled “mostlyright.qc.ALPHA_RULES : tuple[_RuleSpec, …] = (_RuleSpec(rule_id=‘temp_c.out_of_range’, bit_position=0, description=‘Temperature outside [-89C, 57C] (world-record bounds).’, evaluator=<function _rule_temp_out_of_range>), _RuleSpec(rule_id=‘dew_point_c.exceeds_temp’, bit_position=1, description=‘Dewpoint greater than temperature (physically impossible).’, evaluator=<function _rule_dewpoint_exceeds_temp>), _RuleSpec(rule_id=‘wind_speed_ms.negative’, bit_position=2, description=‘Wind speed negative.’, evaluator=<function _rule_wind_speed_negative>), _RuleSpec(rule_id=‘wind_dir_deg.out_of_range’, bit_position=3, description=‘Wind direction outside [0, 360].’, evaluator=<function _rule_wind_dir_out_of_range>), _RuleSpec(rule_id=‘slp_hpa.out_of_range’, bit_position=4, description=‘Sea-level pressure outside [870, 1085] mb.’, evaluator=<function _rule_slp_out_of_range>))”The 5 alpha rules registered in v0.1.0. Bit positions are stable — Phase 3.4+ additions append at the next bit. Removal target: never (would break stored sidecar parquets).
class mostlyright.qc.QCEngine
Section titled “class mostlyright.qc.QCEngine”Bases: object
Apply registered rules to observation DataFrames; emit bitfield + sidecar.
apply(df)
Section titled “apply(df)”Apply all registered rules; return df with obs_qc_status
bitfield column appended (and the per-rule bit-position scheme
documented in ALPHA_RULES).
- Return type:
DataFrame - Parameters: df (pd.DataFrame)
build_sidecar_rows(df)
Section titled “build_sidecar_rows(df)”Build the QC sidecar rows for a flagged DataFrame.
Returns one dict per (row, rule_fired) pair conforming to
schema.observation_qc.v1.
rules : ClassVar[tuple[_RuleSpec, ...]] = (_RuleSpec(rule_id=‘temp_c.out_of_range’, bit_position=0, description=‘Temperature outside [-89C, 57C] (world-record bounds).’, evaluator=<function _rule_temp_out_of_range>), _RuleSpec(rule_id=‘dew_point_c.exceeds_temp’, bit_position=1, description=‘Dewpoint greater than temperature (physically impossible).’, evaluator=<function _rule_dewpoint_exceeds_temp>), _RuleSpec(rule_id=‘wind_speed_ms.negative’, bit_position=2, description=‘Wind speed negative.’, evaluator=<function _rule_wind_speed_negative>), _RuleSpec(rule_id=‘wind_dir_deg.out_of_range’, bit_position=3, description=‘Wind direction outside [0, 360].’, evaluator=<function _rule_wind_dir_out_of_range>), _RuleSpec(rule_id=‘slp_hpa.out_of_range’, bit_position=4, description=‘Sea-level pressure outside [870, 1085] mb.’, evaluator=<function _rule_slp_out_of_range>))
Section titled “rules : ClassVar[tuple[_RuleSpec, ...]] = (_RuleSpec(rule_id=‘temp_c.out_of_range’, bit_position=0, description=‘Temperature outside [-89C, 57C] (world-record bounds).’, evaluator=<function _rule_temp_out_of_range>), _RuleSpec(rule_id=‘dew_point_c.exceeds_temp’, bit_position=1, description=‘Dewpoint greater than temperature (physically impossible).’, evaluator=<function _rule_dewpoint_exceeds_temp>), _RuleSpec(rule_id=‘wind_speed_ms.negative’, bit_position=2, description=‘Wind speed negative.’, evaluator=<function _rule_wind_speed_negative>), _RuleSpec(rule_id=‘wind_dir_deg.out_of_range’, bit_position=3, description=‘Wind direction outside [0, 360].’, evaluator=<function _rule_wind_dir_out_of_range>), _RuleSpec(rule_id=‘slp_hpa.out_of_range’, bit_position=4, description=‘Sea-level pressure outside [870, 1085] mb.’, evaluator=<function _rule_slp_out_of_range>))”class mostlyright.qc.QCRule(*args, **kwargs)
Section titled “class mostlyright.qc.QCRule(*args, **kwargs)”Bases: Protocol
Protocol every QC rule satisfies.
bit_position : int
Section titled “bit_position : int”evaluate(df)
Section titled “evaluate(df)”Return a boolean Series where True = rule fired.
- Return type:
Series - Parameters: df (DataFrame)
rule_id : str
Section titled “rule_id : str”mostlyright.qc.crosscheck_iem_ghcnh(iem_df, ghcnh_df, , tol_c=2.0)
Section titled “mostlyright.qc.crosscheck_iem_ghcnh(iem_df, ghcnh_df, , tol_c=2.0)”Cross-check IEM and GHCNh temperatures; return disagreement rows.
For every (station, event_time) present in both inputs, compare
temp_c values. Rows where |iem.temp_c - ghcnh.temp_c| > tol_c
are returned with both values + delta so the QC engine can flag them.
- Parameters:
- iem_df (
DataFrame) – Observation DataFrame with source IEM. - ghcnh_df (
DataFrame) – Observation DataFrame with source GHCNh. - tol_c (
float) – Maximum acceptable delta in °C (default 2.0).
- iem_df (
- Return type:
DataFrame - Returns:
DataFrame with rows where the two sources disagree above
tol_c. Columns:station,event_time,temp_c_iem,temp_c_ghcnh,delta_c.
Phase 6 W2-T4: accepts pandas OR polars input for both arms; returns the same backend the caller passed (matches first arg’s backend if they differ — both polars or both pandas is the supported case).