Fault rules
Fault rules are YAML-defined checks run against pandas DataFrames. Each rule produces boolean fault flag columns (and related outputs) via RuleRunner.
Rules often use Brick class names as logical input keys; you supply a column_map from those keys to your actual DataFrame columns (dict, manifest, or custom resolver). See Column map resolvers and the Expression rule cookbook.
Where rules live
Keep rule YAML in a single directory (for example my_rules/) or pass parsed dicts to RuleRunner(rules=[...]). Example snippets live under examples/ and open_fdd/tests/fixtures/rules/ in this repository.
See the Expression rule cookbook to add or adapt rules. For how YAML becomes pandas operations, see YAML rules → Pandas (under the hood).
Hot reload
RuleRunner reads the rule list you give it at construction time. To pick up disk edits, call load_rules_from_dir again (or construct a new RuleRunner) before the next run().
Rule types
| Type | Purpose |
|---|---|
bounds | Value outside [low, high] |
flatline | Rolling spread < tolerance (stuck sensor) |
hunting | Excessive state changes (PID hunting) |
expression | Custom pandas/numpy expression; supports schedule/weather gating via params.schedule and params.weather_band |
oa_fraction | OA fraction vs design airflow error |
erv_efficiency | ERV effectiveness out of range |
These six values are the built-in type values in the engine. Occupied-hours and weather gating are not separate rule types; they are optional masks injected for type: expression rules (schedule_occupied, weather_allows_fdd). See the Expression rule cookbook.
YAML structure
Example with Brick-style logical keys (map them with column_map):
name: sensor_bounds
type: bounds
flag: bad_sensor
inputs:
Outside_Air_Temperature_Sensor:
brick: Outside_Air_Temperature_Sensor
Supply_Air_Temperature_Sensor:
brick: Supply_Air_Temperature_Sensor
params:
low: 40
high: 90
rolling_window: 6 # optional: require N consecutive True samples before flagging
Per-rule rolling window: Set params.rolling_window (e.g. 6) in a rule to require that many consecutive True samples before the fault is flagged. Omit for “flag on any True.” See fixtures such as sensor_flatline.yaml under open_fdd/tests/fixtures/rules/.
Running rules
from pathlib import Path
from open_fdd.engine.runner import RuleRunner
runner = RuleRunner(rules_path=Path("path/to/rules"))
out = runner.run(df, timestamp_col="timestamp", column_map={...})
Engineering metadata and analytics
Downstream analytics often combine fault flags from RuleRunner with equipment metadata and time series you already store. For Brick / 223P graph and API workflows, see open-fdd-afdd-stack docs and Data modeling & platform docs.
Cookbook
See Expression rule cookbook for AHU, chiller, weather, and advanced recipes.