Features

All feature classes follow the same interface: instantiate, then call .compute(df) which returns a copy of the DataFrame with new feat_ columns added.

ThermalStressIndex

class climagrid.features.thermal.ThermalStressIndex(temp_col='hrrr_temperature_2m', hotspot_rise=25.0, heat_threshold_c=35.0, rolling_window_h=168)[source]

Bases: object

Computes transformer thermal aging features from ambient temperature data.

Parameters:
  • temp_col (str) – Column name for ambient temperature in °C.

  • hotspot_rise (float) – Hotspot temperature rise above ambient in °C. Default 25°C is a typical value for distribution transformers (IEEE C57.91 Table 2).

  • heat_threshold_c (float) – Temperature threshold in °C for counting heat-stress hours. Default 35°C (common threshold for transformer derating advisories).

  • rolling_window_h (int) – Rolling window size in hours for cumulative heat-hour calculation. Default 168 (one week).

Example

>>> tsi = ThermalStressIndex()
>>> df = tsi.compute(asset_env_df)
>>> df[["feat_thermal_aging_factor", "feat_heat_hours_above_35c"]]
compute(df)[source]

Add thermal stress columns to df in-place (returns a copy).

The DataFrame must contain a temperature column in °C and an ‘asset_id’ column for grouping. Timestamp ordering is assumed.

Parameters:

df (DataFrame) – Asset-level environmental DataFrame from AssetEnvironmentJoiner.

Returns:

Input df with two new columns added: - feat_thermal_aging_factor - feat_heat_hours_above_35c

Return type:

DataFrame

ConductorSagIndex

class climagrid.features.conductor_sag.ConductorSagIndex(temp_col='hrrr_temperature_2m', solar_col='hrrr_solar_irradiance_ghi', wind_col='hrrr_wind_speed_10m', max_sag_temp_c=75.0, conductor_absorptivity=0.5, conductor_emissivity=0.5, conductor_diameter_mm=28.1)[source]

Bases: object

Computes normalized conductor thermal sag index from weather inputs.

Simplified IEEE 738-2012 heat balance:

T_conductor ≈ T_ambient + (I²R + Q_solar - Q_convective) / (thermal_capacity)

For stress feature purposes (not full current rating), we approximate the conductor temperature as ambient + solar heating - convective cooling, then compute sag as a fraction of the maximum design sag.

Parameters:
  • temp_col (str) – Ambient temperature column in °C.

  • solar_col (str) – Global horizontal irradiance column in W/m².

  • wind_col (str) – Wind speed column in m/s. Wind is the primary cooling mechanism.

  • max_sag_temp_c (float) – Conductor temperature at which sag reaches the design maximum. Default 75°C (typical for ACSR “Drake” conductor per IEEE 738).

  • conductor_absorptivity (float) – Solar absorptivity of the conductor surface (0-1). Default 0.5.

  • conductor_emissivity (float) – Emissivity for radiated cooling (0-1). Default 0.5.

  • conductor_diameter_mm (float) – Conductor outer diameter for convective heat loss. Default 28.1 mm (Drake ACSR).

Example

>>> csi = ConductorSagIndex()
>>> df = csi.compute(env_df)
>>> df["feat_conductor_sag_index"]
compute(df)[source]

Add feat_conductor_sag_index column [0, 1]. Returns a copy.

Return type:

DataFrame

Parameters:

df (DataFrame)

FreezeThawtCycleCounter

class climagrid.features.freeze_thaw.FreezeThawtCycleCounter(temp_col='hrrr_temperature_2m', freeze_threshold_c=0.0, rolling_window_h=720)[source]

Bases: object

Counts freeze-thaw transitions from an hourly temperature time series.

Parameters:
  • temp_col (str) – Column containing temperature in °C.

  • freeze_threshold_c (float) – Temperature below which the asset is considered “frozen”. Default 0°C (water freezing point).

  • rolling_window_h (int) – Rolling window in hours over which to count cycles. Default 720 (30 days).

Example

>>> ftc = FreezeThawtCycleCounter()
>>> df = ftc.compute(asset_env_df)
>>> df["feat_freeze_thaw_cycles"]
compute(df)[source]

Add feat_freeze_thaw_cycles column. Returns a copy.

Return type:

DataFrame

Parameters:

df (DataFrame)

IceLoadingRisk

class climagrid.features.ice_loading.IceLoadingRisk(temp_col='hrrr_temperature_2m', precip_col='hrrr_precipitation_rate', wind_col='hrrr_wind_speed_10m', temp_ice_min_c=-10.0, temp_ice_max_c=2.0, precip_threshold=0.1)[source]

Bases: object

Computes normalized ice loading risk for overhead T&D conductors.

Parameters:
  • temp_col (str) – Temperature in °C.

  • precip_col (str) – Precipitation rate in mm/hr.

  • wind_col (str) – Wind speed in m/s.

  • temp_ice_min_c (float) – Lower temperature bound for ice accretion (default -10°C).

  • temp_ice_max_c (float) – Upper temperature bound for ice accretion (default +2°C).

  • precip_threshold (float) – Minimum precipitation rate (mm/hr) to trigger ice risk scoring.

Example

>>> ilr = IceLoadingRisk()
>>> df = ilr.compute(env_df)
>>> df["feat_ice_loading_risk"]
compute(df)[source]

Add feat_ice_loading_risk column [0, 1]. Returns a copy.

Return type:

DataFrame

Parameters:

df (DataFrame)

SoilSaturationIndex

class climagrid.features.soil.SoilSaturationIndex(soil_col='nrcs_soil_moisture_pct', precip_col='hrrr_precipitation_rate', field_capacity_pct=40.0, wilting_point_pct=12.0, rolling_window_h=72, precip_saturation_mm=100.0)[source]

Bases: object

Computes normalized soil saturation index [0, 1].

Strategy

  1. If NRCS soil moisture % is available, normalize against field capacity (nominally 40% VWC for loam soils; configurable).

  2. If NRCS data is unavailable, estimate from cumulative precipitation using a simple linear proxy (saturates at 100mm cumulative precip over the rolling window).

type soil_col:

str

param soil_col:

NRCS volumetric soil moisture column (%).

type precip_col:

str

param precip_col:

Precipitation column for fallback estimation.

type field_capacity_pct:

float

param field_capacity_pct:

Volumetric water content at field capacity (%). Default 40%.

type wilting_point_pct:

float

param wilting_point_pct:

Volumetric water content at wilting point (%). Default 12%.

type rolling_window_h:

int

param rolling_window_h:

Rolling window for precipitation accumulation fallback.

Example

>>> ssi = SoilSaturationIndex()
>>> df = ssi.compute(env_df)
>>> df["feat_soil_saturation_index"]
compute(df)[source]

Add feat_soil_saturation_index column [0, 1]. Returns a copy.

Return type:

DataFrame

Parameters:

df (DataFrame)

Parameters:
  • soil_col (str)

  • precip_col (str)

  • field_capacity_pct (float)

  • wilting_point_pct (float)

  • rolling_window_h (int)

  • precip_saturation_mm (float)

WildfireProximityScore

class climagrid.features.wildfire.WildfireProximityScore(max_risk_distance_km=1.0, zero_risk_distance_km=200.0, use_fire_weather=True, temp_col='hrrr_temperature_2m', rh_col='hrrr_relative_humidity_2m', wind_col='hrrr_wind_speed_10m')[source]

Bases: object

Computes a normalized wildfire proximity score [0, 1] for asset locations.

Parameters:
  • max_risk_distance_km (float) – Distance within which risk = 1.0 (fire perimeter adjacent). Default 1 km.

  • zero_risk_distance_km (float) – Distance beyond which risk ≈ 0. Default 200 km.

  • use_fire_weather (bool) – If True and fire weather columns are present, modulate score by fire weather conditions (temperature, humidity, wind).

  • temp_col (str) – Temperature column for fire weather modulation.

  • rh_col (str) – Relative humidity column.

  • wind_col (str) – Wind speed column.

Example

>>> wfigs = WfigsAdapter()
>>> fires_df = wfigs.fetch(bbox, start_dt, end_dt)
>>> score = WildfireProximityScore()
>>> df = score.compute(asset_df, fires_df)
>>> df["feat_wildfire_proximity"]
compute(df, fires_df)[source]

Add feat_wildfire_proximity column to df.

Parameters:
  • df (DataFrame) – Asset-level environmental DataFrame with lat/lon columns.

  • fires_df (DataFrame) – DataFrame returned by WfigsAdapter.fetch() with fire perimeter data.

Returns:

Input df with feat_wildfire_proximity [0,1] and wfigs_nearest_fire_km, wfigs_fire_active, wfigs_fire_area_ha added.

Return type:

DataFrame