aridkpi.core
Core KPIs of the aridkpi package.
Implements the 5 CORE-tier indicators from the KPI Comparison Matrix v1.0:
IOD — Indoor Overheating Degree
CCOR — Climate Change Overheating Resistivity
UDH — Unmet Degree Hours during power outage (Passive Survivability)
DEDT — Energy sensitivity to climate (delta E / delta T)
DTDT_MAX — Maximum indoor thermal change rate (dT/dt max)
All formulas follow the canonical definitions in the matrix. Each function takes pandas DataFrames or Series with a DatetimeIndex and returns either a scalar or a pandas Series, depending on the indicator.
References for each KPI are listed in the matrix entry; this module only re-states the operational form.
- aridkpi.core.ccor(iod_baseline: float, iod_strategy: float, delta_T_climate: float) float[source]
Climate Change Overheating Resistivity (CCOR).
Measures the effectiveness of a passive strategy under a climate-driven temperature shift:
CCOR = (IOD_baseline - IOD_strategy) / Delta_T_climate
Higher CCOR ⇒ better resistivity to climate-change-induced overheating.
- Parameters:
iod_baseline – IOD of the baseline building (no passive strategy), in °C·h.
iod_strategy – IOD of the same building with the passive strategy applied, in °C·h.
delta_T_climate – Mean annual temperature increase under the SSP scenario considered relative to the baseline period, in °C. Must be positive.
- Returns:
float – CCOR in (°C·h)/°C.
- Raises:
ValueError – If
delta_T_climate <= 0.
Notes
Formula source: Rahif et al. (2022); IEA EBC Annex 80. Limitation in BWk/BSk: a locally meaningful baseline is required (importing a European baseline produces non-comparable results). See KPI Matrix v1.0.
Examples
>>> round(ccor(iod_baseline=120.0, iod_strategy=80.0, delta_T_climate=2.5), 2) 16.0
- aridkpi.core.energy_climate_sensitivity(df: DataFrame, eui_col: str = 'EUI', tmean_col: str = 'T_mean') dict[str, float][source]
Energy sensitivity to climate (delta E / delta T).
Linear regression slope of EUI vs mean annual outdoor temperature across SSP scenarios and time horizons:
delta_E / delta_T = slope of regression EUI ~ T_mean
- Parameters:
df – DataFrame with one row per (SSP × horizon) combination. Must contain columns
eui_col(Energy Use Intensity, kWh/m²/yr) andtmean_col(mean annual outdoor temperature, °C).eui_col – Column names.
tmean_col – Column names.
- Returns:
dict – Dict with keys
slope(kWh·m⁻²·yr⁻¹/°C),intercept(kWh·m⁻²·yr⁻¹),r_squared(dimensionless),p_value(dimensionless),std_err(slope standard error) andn_points(int).
Notes
Formula source: this work, building on Flores Larsen, Filippín & Barea (2019). Linearity must be tested empirically: highly insulated envelopes can produce non-linear responses. See KPI Matrix v1.0.
Examples
>>> import pandas as pd >>> data = pd.DataFrame({ ... "T_mean": [16.0, 17.5, 19.0, 20.5], ... "EUI": [80.0, 85.0, 92.0, 98.0], ... }) >>> r = energy_climate_sensitivity(data) >>> round(r["slope"], 2) 4.04
- aridkpi.core.iod(T_op: Series, T_comf: Series | float = 26.0, occupancy: Series | None = None, dt_hours: float | None = None) float[source]
Indoor Overheating Degree (IOD).
Computes the magnitude of overheating during occupied hours, weighted by the duration of each exceedance:
- IOD = sum_t max(T_op(t) - T_comf(t), 0) * dt * occ(t)
/ sum_t occ(t) * dt
The result is reported in °C·h, normalised by occupied hours (so it can be compared between buildings with different occupancy patterns).
- Parameters:
T_op – Operative temperature time series (°C). DatetimeIndex required.
T_comf – Comfort threshold. Either a constant (°C) or a Series aligned with
T_opfor an adaptive comfort model. Defaults toDEFAULT_TCOMF_FIXED.occupancy – Boolean Series aligned with
T_op.Truewhere the zone is occupied. IfNone, every step is considered occupied.dt_hours – Sampling step in hours. If
None, inferred from the index.
- Returns:
float – IOD in °C·h, occupancy-weighted average. Returns
0.0if there are no occupied hours.
Notes
Formula source: Hamdy, Carlucci, Hoes & Hensen (2017). Limitation in BWk/BSk:
T_comfshould be derived from a locally validated adaptive comfort model. See KPI Matrix v1.0 entry for IOD.Examples
>>> import pandas as pd >>> idx = pd.date_range("2026-01-01", periods=24, freq="h") >>> T = pd.Series([20]*8 + [28]*8 + [22]*8, index=idx, dtype=float) >>> round(iod(T, T_comf=26.0), 2) 0.67
- aridkpi.core.max_thermal_change_rate(T_in: Series, smoothing_window: int = 3) float[source]
Maximum indoor thermal change rate (dT/dt max).
Computes the peak indoor temperature change rate over the time series:
max_t | dT_in(t) / dt |
A 3-point moving average is applied by default to reduce sensor noise contribution to the maximum.
- Parameters:
T_in – Indoor temperature time series (°C). DatetimeIndex required.
smoothing_window – Window size for the moving average pre-smoothing (in samples). Use
smoothing_window=1to disable smoothing.
- Returns:
float – Maximum |dT/dt| in °C/h.
Notes
Formula source: this work. Rationale: in arid climates with diurnal range > 15 °C, dT/dt is a primary discriminator of envelope thermal mass. See KPI Matrix v1.0.
Examples
>>> import numpy as np >>> import pandas as pd >>> idx = pd.date_range("2026-01-01", periods=12, freq="h") >>> # Linear ramp 1 °C/h >>> T = pd.Series(np.arange(12, dtype=float), index=idx) >>> round(max_thermal_change_rate(T, smoothing_window=1), 2) 1.0
- aridkpi.core.udh(T_op: Series, outage_start: Timestamp | str, window: Literal['24h', '72h', '7d'] = '72h', threshold: float = 30.0, dt_hours: float | None = None) float[source]
Unmet Degree Hours during a sustained power outage.
Quantifies habitability during a power outage triggered at the peak of an Extreme Weather Year (EWY). Computed as:
UDH_w = sum_{t in W} max(T_op(t) - T_threshold, 0) * dt
where
Wis the time window starting atoutage_start.- Parameters:
T_op – Operative temperature time series during the simulated outage (°C). DatetimeIndex required. Must include the entire
windowfromoutage_start.outage_start – Timestamp at which the outage begins. Can be a pd.Timestamp or any string parseable by pandas.
window – Length of the outage window:
"24h","72h"or"7d".threshold – Upper temperature threshold (°C). Defaults to
DEFAULT_PASSIVE_THRESHOLD.dt_hours – Sampling step in hours. If
None, inferred from the index.
- Returns:
float – UDH in °C·h.
- Raises:
ValueError – If the window does not fit within the supplied series.
Notes
Formula source: Sun et al. (2021); IEA EBC Annex 80. Limitation in BWk/BSk: the 30 °C threshold inherits the North American convention. In the arid regime characterised by low RH (often < 30 %), the apparent temperature differs significantly from the dry-bulb. Recalibrate using SET / WBGT / UTCI when reporting in BWk/BSk. See KPI Matrix v1.0.
Examples
>>> import pandas as pd >>> idx = pd.date_range("2026-01-15", periods=72, freq="h") >>> T = pd.Series([32.0]*72, index=idx) >>> round(udh(T, outage_start="2026-01-15", window="72h", threshold=30.0), 2) 144.0