comfio
A multi-domain IEQ & performance contract framework for smart buildings.
comfio bridges the gap between raw building sensor data and actionable smart building management. It breaks the silos between different building physics disciplines — bringing together Thermal, Visual, Acoustic, and Indoor Air Quality (IAQ) metrics into a unified Global IEQ Index.
Designed for time-series data (IoT sensors, edge computing) and comfort-based performance contracts, comfio enables researchers and building managers to automate compliance tracking and generate smart-contract-ready outputs.
Why comfio?
- Silo-Breaking: Unifies separated domains (Thermal, Acoustic, Visual, IAQ) under a single Python API
- Data-Native: Built to ingest massive arrays of time-series data (Pandas/NumPy) rather than single-point calculations
- Actionable Output: Translates physical equations into compliance rates for building performance contracts
- Smart Contract Ready: Generates structured JSON outputs with formal ABI schemas for blockchain Oracle integration
- ML/DL Compatible: NumPy-native core with optional adapters for scikit-learn, PyTorch, and TensorFlow/Keras
- Advanced Physics Modules: Optional extras for Radiance daylighting, CRI/CCT color quality, RT60 reverberation, STI speech intelligibility, CO₂ decay ventilation, and full psychrometrics
- Pollutant IAQ: PM2.5, PM10, TVOC, formaldehyde, and CO evaluation against WHO, EPA NAAQS, and WELL Building Standard v2 thresholds
- Adaptive Thermal Comfort: ASHRAE 55-2023 and EN 16798-1:2019 adaptive models for naturally ventilated buildings
- Simplified PMV (sPMV): Buratti et al. (2009) seasonal model requiring only temperature and humidity
- TSV Augmentation: CDF-based remapping (quantile mapping) to augment sparse occupant votes to dense sensor timestamps while preserving the empirical distribution
- Personalised Comfort: OLS regression-based personalisation of model predictions to match occupant feedback (TSV), with per-season support
- Fast & Light: Core depends only on numpy, pandas, and pythermalcomfort
Installation
pip install comfio
With ML/DL framework support:
pip install comfio[ml] # scikit-learn
pip install comfio[torch] # PyTorch
pip install comfio[keras] # TensorFlow/Keras
pip install comfio[all] # All frameworks + advanced domains
Advanced physics-based domain evaluation (optional extras):
pip install comfio[daylighting] # pyradiance (Radiance ray-tracing)
pip install comfio[color] # colour-science (CRI, CCT)
pip install comfio[acoustics] # python-acoustics + pyroomacoustics (RT60, STI)
pip install comfio[psychrometrics] # PsychroLib (psychrometric properties, CO₂ decay ACH)
Try on Google Colab
Run the tutorials instantly in your browser — no local install required.
Examples
Docs Tutorials
Tip: In Colab, run
!pip install comfio[all]in the first cell to install all optional dependencies.
Quick Start
1. Evaluate Individual Domains
import numpy as np
from comfio import evaluate_thermal, evaluate_visual, evaluate_acoustic, evaluate_iaq
# Thermal comfort (ISO 7730 / ASHRAE 55)
thermal = evaluate_thermal(
tdb=np.array([24.0, 25.0, 26.0]), # air temp °C
tr=np.array([24.0, 25.0, 26.0]), # radiant temp °C
vr=np.array([0.1, 0.1, 0.1]), # air velocity m/s
rh=np.array([50.0, 50.0, 50.0]), # relative humidity %
met=1.2, # metabolic rate
clo=0.5, # clothing insulation
category="B", # ISO 7730 category
)
print(f"PMV: {thermal.pmv}, PPD: {thermal.ppd}")
# Visual comfort (EN 12464-1)
visual = evaluate_visual(
illuminance=np.array([450.0, 500.0, 600.0]),
task_type="office_writing",
)
# Acoustic comfort (NC curves)
acoustic = evaluate_acoustic(
laeq=np.array([35.0, 40.0, 45.0]),
nc_level="NC-35",
)
# IAQ (ASHRAE 62.1 indicators)
iaq = evaluate_iaq(
co2=np.array([700.0, 900.0, 1100.0]),
threshold_level="good",
)
2. Calculate Global IEQ Index
from comfio import calculate_global_ieq, default_weights
# Merge all domains into a single 0-100 score
ieq = calculate_global_ieq(
thermal=thermal,
visual=visual,
acoustic=acoustic,
iaq=iaq,
weights=default_weights(), # thermal=40%, iaq=25%, visual=20%, acoustic=15%
)
print(f"Global IEQ Index: {ieq.index}")
print(f"Domain scores: {ieq.domain_scores}")
3. Compliance Tracking & Contract Outputs
from comfio import calculate_compliance
report = calculate_compliance(ieq, threshold=80.0)
print(f"Compliance rate: {report.compliance_rate_pct:.1f}%")
print(f"Average IEQ: {report.ieq_index_avg:.1f}")
# Generate JSON for blockchain Oracle
contract_json = report.to_contract_json()
print(contract_json)
4. Time-Series Data with SensorData
import pandas as pd
from comfio import SensorData
# Load your sensor DataFrame
df = pd.read_csv("sensor_data.csv")
sensor = SensorData(df=df)
# Auto-detects column names (tdb, ta, temperature → air_temp_c, etc.)
print(sensor.available_domains()) # ['thermal', 'visual', 'acoustic', 'iaq']
# Validate data (NaN handling, physical bounds checking)
sensor.validate()
clean_temp = sensor.get_validated("air_temp_c")
ML/DL Integration
scikit-learn Pipeline
from sklearn.pipeline import Pipeline
from sklearn.ensemble import RandomForestRegressor
from comfio.ml.sklearn_transformers import IEQFeatureExtractor
pipe = Pipeline([
("ieq", IEQFeatureExtractor()),
("model", RandomForestRegressor()),
])
pipe.fit(train_df, train_labels)
predictions = pipe.predict(test_df)
PyTorch DataLoader
from torch.utils.data import DataLoader
from comfio.ml.torch_dataset import IEQTimeSeriesDataset
dataset = IEQTimeSeriesDataset(df, window_size=24, stride=1)
loader = DataLoader(dataset, batch_size=32, shuffle=True)
for batch in loader:
raw = batch["raw"] # (32, 24, n_sensors)
ieq = batch["ieq_index"] # (32, 24)
TensorFlow/Keras
from comfio.ml.keras_adapter import IEQPreprocessingLayer
layer = IEQPreprocessingLayer()
layer.adapt(train_df)
features = layer(train_df) # tf.Tensor of IEQ features
Advanced Domain Evaluation
comfio offers optional physics-based modules that go beyond simple threshold checks. These require separate extras but integrate seamlessly with the Global IEQ Index.
from comfio import (
evaluate_reverberation, evaluate_speech_intelligibility,
evaluate_ventilation, get_psychrometrics,
calculate_global_ieq,
)
# Reverberation time (python-acoustics)
reverb = evaluate_reverberation(surfaces, absorption, volume, room_type="office")
# Speech intelligibility from impulse response (pyroomacoustics)
sti = evaluate_speech_intelligibility(ir_signal, sample_rate=16000)
# Ventilation rate from CO₂ decay (psychrolib)
vent = evaluate_ventilation(co2_array, timestamps, occupancy_type="office")
# Psychrometric properties (psychrolib)
psych = get_psychrometrics(tdb=25.0, rh=0.50)
# Blend advanced results into Global IEQ Index
result = calculate_global_ieq(
thermal=thermal, visual=visual, acoustic=acoustic, iaq=iaq,
reverberation=reverb, speech_intelligibility=sti, ventilation=vent,
)
See the User Guide for full documentation.
New Domain Modules
Pollutant IAQ
Evaluate PM2.5, PM10, TVOC, formaldehyde, and CO against health-based thresholds:
from comfio import evaluate_iaq_pollutants
pollutant = evaluate_iaq_pollutants(
pm25=np.array([8.0, 12.0, 35.0]),
tvoc=np.array([150.0, 300.0, 500.0]),
formaldehyde=np.array([20.0, 27.0, 50.0]),
co=np.array([1.5, 5.0, 10.0]),
threshold_level="good",
)
print(f"Pollutant IAQ score: {pollutant.score}")
Adaptive Thermal Comfort
from comfio import evaluate_adaptive_ashrae, evaluate_adaptive_en
# ASHRAE 55-2023 (naturally ventilated buildings)
ashrae = evaluate_adaptive_ashrae(
tdb=np.array([24.0, 25.0, 26.0]),
tr=np.array([24.0, 25.0, 26.0]),
t_prevail=20.0, # prevailing mean outdoor temp
acceptability=80,
)
# EN 16798-1:2019
en = evaluate_adaptive_en(
tdb=np.array([24.0, 25.0, 26.0]),
tr=np.array([24.0, 25.0, 26.0]),
t_running_mean=20.0,
category="ii",
)
Simplified PMV (sPMV)
from comfio import evaluate_spmv
spmv = evaluate_spmv(
indoor_temp=np.array([23.0, 24.0, 25.0]),
indoor_rh=np.array([50.0, 50.0, 50.0]),
season="mid", # or "winter" / "summer"
)
print(f"sPMV: {spmv.spmv}, score: {spmv.score}")
TSV Augmentation & Evaluation
from comfio import augment_tsv_cdf, evaluate_tsv
# Augment sparse occupant votes to dense sensor timestamps
augmented = augment_tsv_cdf(
sparse_votes=np.array([-2, -1, 0, 0, 1, 1, 2, -1, 0, 1]),
vote_timestamps=np.arange(10),
target_timestamps=np.arange(100), # dense sensor timestamps
)
# Evaluate TSV for compliance (ASHRAE 55-2023 Appendix L)
tsv_result = evaluate_tsv(augmented)
print(f"Mean TSV: {tsv_result.mean_tsv}")
print(f"Compliance rate: {tsv_result.compliance_rate:.1%}")
Personalised Thermal Comfort
from comfio import train_personalisation, evaluate_personalised_pmv
# Train: fit OLS regression TSV = alpha * PMV + beta
index = train_personalisation(
pmv=historical_pmv_array,
tsv=historical_tsv_array,
)
# Apply: personalise future PMV predictions
result = evaluate_personalised_pmv(
tdb=tdb, tr=tr, vr=vr, rh=rh, met=1.2, clo=0.5,
personalisation_index=index,
)
print(f"Personalised PMV: {result.personalised_pmv}")
Integration with Global IEQ Index
from comfio import calculate_global_ieq
ieq = calculate_global_ieq(
thermal=thermal_res,
visual=visual_res,
acoustic=acoustic_res,
iaq=iaq_res,
pollutant_iaq=pollutant_res, # blends 50/50 with IAQ score
tsv=tsv_res, # overrides thermal score (occupant feedback is ground truth)
)
v0.1.6 New Features
Local Thermal Discomfort
Ankle draft and vertical temperature gradient — the two local discomfort indices required for full ISO 7730 / ASHRAE 55 compliance:
from comfio import evaluate_ankle_draft, evaluate_vertical_gradient, local_discomfort_score
# Ankle draft (ASHRAE 55-2023 §5.3.3)
ad = evaluate_ankle_draft(
tdb=np.array([24.0, 25.0]),
tr=np.array([24.0, 25.0]),
vr=np.array([0.1, 0.1]),
rh=np.array([50.0, 50.0]),
met=1.2, clo=0.5,
v_ankle=np.array([0.15, 0.30]),
)
print(f"Ankle draft PPD: {ad.ppd_ad}")
# Vertical temperature gradient (ISO 7730 §6.1)
vg = evaluate_vertical_gradient(
tdb=np.array([24.0, 25.0]),
tr=np.array([24.0, 25.0]),
vr=np.array([0.1, 0.1]),
rh=np.array([50.0, 50.0]),
met=1.2, clo=0.5,
vertical_tmp_grad=np.array([2.0, 7.0]),
)
# Combined local discomfort score (0-100)
score = local_discomfort_score(ppd_ad=ad.ppd_ad, ppd_vg=vg.ppd_vg)
Weather Integration (meteostat)
Fetch historical outdoor temperature for adaptive comfort models — no more manual t_prevail / t_running_mean calculation:
from datetime import date
from comfio import fetch_prevailing_temp, fetch_running_mean
# ASHRAE 55 prevailing mean (7-day arithmetic mean)
t_prevail = fetch_prevailing_temp(
lat=50.11, lon=8.68, # Frankfurt
end_date=date(2025, 6, 30),
days=7,
)
# EN 16798-1 running mean (exponentially weighted, α=0.8)
t_rm = fetch_running_mean(
lat=50.11, lon=8.68,
end_date=date(2025, 6, 30),
)
# Feed directly into adaptive comfort evaluation
from comfio import evaluate_adaptive_ashrae
result = evaluate_adaptive_ashrae(
tdb=np.array([24.0, 25.0, 26.0]),
tr=np.array([24.0, 25.0, 26.0]),
t_prevail=float(t_prevail),
)
Results are cached under ~/.cache/comfio/weather/ to minimize network calls.
Result Serialization
All Result dataclasses now provide to_dict(), to_json(), and to_dataframe():
from comfio import evaluate_thermal
import numpy as np
result = evaluate_thermal(
tdb=np.array([24.0, 25.0]),
tr=np.array([24.0, 25.0]),
vr=np.array([0.1, 0.1]),
rh=np.array([50.0, 50.0]),
met=1.2, clo=0.5,
)
result.to_dict() # → {"pmv": ..., "ppd": ..., ...}
result.to_json() # → JSON string (numpy arrays → lists)
result.to_dataframe() # → pandas.DataFrame
Logging
comfio now uses Python's logging module. Pipeline failures that were previously silent are now logged:
import comfio
comfio.setup_logging(level="INFO") # see pipeline warnings in stderr
Architecture
comfio operates on a 4-layer data flow:
Layer 1: Data Ingestion (SensorData)
↓ Pandas/NumPy time-series arrays
Layer 2: Single-Domain Modules (domains/)
↓ Thermal (pythermalcomfort) | Visual (EN 12464-1) | Acoustic (NC) | IAQ (ASHRAE 62.1)
Layer 3: Multi-Domain Integration (integration/)
↓ Global IEQ Index (0-100) with configurable weighting
Layer 4: Application & Contracts (performance/)
→ Compliance rates, JSON reports, smart contract ABI schemas
Key design principle — Decoupling: integration/ only talks to domains/, never to pythermalcomfort directly. If pythermalcomfort releases a breaking change, only domains/thermal.py needs updating.
Weighting Presets
| Preset | Thermal | IAQ | Visual | Acoustic | Use Case |
|---|---|---|---|---|---|
default |
40% | 25% | 20% | 15% | General (Pierson et al. 2019) |
equal |
25% | 25% | 25% | 25% | Equal weighting |
school |
27% | 26% | 24% | 23% | School children (Yang et al. 2020) |
office |
45% | 30% | 15% | 10% | Office workers |
healthcare |
25% | 40% | 15% | 20% | Healthcare facilities |
from comfio.integration.weights import preset_weights, custom_weights
weights = preset_weights("office")
weights = custom_weights(thermal=0.5, visual=0.2, acoustic=0.1, iaq=0.2)
Standards Referenced
- ISO 7730: Thermal comfort — PMV/PPD calculation
- ASHRAE 55: Thermal environmental conditions for human occupancy
- ASHRAE 55-2023 Appendix L: TSV compliance threshold (|TSV| ≤ 1.5)
- EN 16798-1:2019: Adaptive thermal comfort for naturally ventilated buildings
- EN 12464-1: Light and lighting — lighting of work places
- ASHRAE 62.1: Ventilation for acceptable indoor air quality
- WHO Air Quality Guidelines (2021): PM2.5, PM10 thresholds
- EPA NAAQS: Criteria pollutant thresholds
- WELL Building Standard v2: Feature A01 pollutant thresholds
Academic Attribution
comfio utilizes the validated pythermalcomfort library as its core engine for thermal metrics, while focusing its novel architecture on multi-domain integration and temporal performance evaluation.
Tartarini, F., Schiavon, S., 2020. pythermalcomfort: A Python package for thermal comfort research. SoftwareX 12, 100578. https://doi.org/10.1016/j.softx.2020.100578
Development
# Install with dev dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Lint
ruff check src/ tests/
ruff format src/ tests/
# Type check
mypy src/comfio/
# Build
python -m build
Citation
A formal academic paper for comfio is in preparation. In the meantime, if you use comfio in your research, please cite it as:
@software{comfio,
author = {ABO ALZAHAB, Nibras},
title = {comfio: A Multi-Domain IEQ \& Performance Contract Framework for Smart Buildings},
year = {2026},
url = {https://github.com/NibrasAz7/comfio},
version = {0.1.6},
}
Per-function citation
comfio wraps and implements methods from multiple peer-reviewed sources. When you use a specific function, please also cite the underlying work:
| comfio function | Underlying method | Reference |
|---|---|---|
evaluate_thermal |
Fanger PMV/PPD | Fanger (1970); ISO 7730:2005; pythermalcomfort — Tartarini & Schiavon (2020) |
evaluate_spmv |
Simplified PMV | Buratti, Ricciardi & Vergoni (2009), Building and Environment 44(3), 441–449 |
evaluate_adaptive_ashrae |
ASHRAE 55 adaptive | de Dear & Brager (1998), ASHRAE RP-884; ASHRAE 55-2023 Appendix L |
evaluate_adaptive_en |
EN 16798-1 adaptive | Nicol & Humphreys (2010), Energy and Buildings 42(10), 1793–1801; EN 16798-1:2019 |
evaluate_visual |
Illuminance & UGR | EN 12464-1:2021; CIE 117-1995 (UGR) |
evaluate_acoustic |
Noise Criteria | Beranek (1957), Noise Control 3(1), 19–27; ASHRAE Handbook — HVAC Applications |
evaluate_iaq |
CO₂ ventilation indicator | ASHRAE 62.1-2022; Persily (2015), Building and Environment 91, 61–69 |
evaluate_pollutant_iaq |
PM2.5/TVOC/HCHO/CO | WHO (2021), Global air quality guidelines; WHO (2010), IAQ selected pollutants |
evaluate_color_quality |
CRI / CCT / D_uv | CIE 13.3-1995; CIE 015:2018 |
evaluate_reverberation |
RT60 (Sabine/Eyring) | Sabine (1922); Eyring (1930), JASA 1(2A), 217–241; ISO 3382-2:2008 |
evaluate_speech_intelligibility |
STI | Houtgast & Steeneken (1971), Acustica 25, 355–367; IEC 60268-16:2020 |
evaluate_ventilation |
CO₂ decay method | ASHRAE 62.1-2022; ASTM D7297-14 |
get_psychrometrics |
Psychrometric properties | Hyland & Wexler (1983), ASHRAE Transactions 89(2A); PsychroLib |
calculate_global_ieq |
Weighted IEQ index | Pierson et al. (2019), Building and Environment 150, 230–239 |
train_personalisation |
OLS personalisation | Schweiker et al. (2020), Building and Environment 176, 106834 |
augment_tsv_cdf |
CDF remapping | ASHRAE 55-2023 Appendix L |
BibTeX entries for the most commonly cited works:
@book{fanger1970,
author = {Fanger, Povl Ole},
title = {Thermal Comfort},
publisher = {Danish Technical Press},
year = {1970},
}
@article{tartarini2020,
author = {Tartarini, Federico and Schiavon, Stefano},
title = {pythermalcomfort: A Python package for thermal comfort research},
journal = {SoftwareX},
volume = {12},
pages = {100578},
year = {2020},
doi = {10.1016/j.softx.2020.100578},
}
@article{buratti2009,
author = {Buratti, C. and Ricciardi, P. and Vergoni, M.},
title = {Simplified PMV model for HVAC systems control},
journal = {Building and Environment},
volume = {44},
number = {3},
pages = {441--449},
year = {2009},
}
@article{dedear1998,
author = {de Dear, R. and Brager, G. S.},
title = {Developing an adaptive model of thermal comfort and preference},
journal = {ASHRAE Transactions},
volume = {104},
number = {1},
year = {1998},
}
@article{pierson2019,
author = {Pierson, A. and others},
title = {Indoor environmental quality: Development of a weight-based scoring system},
journal = {Building and Environment},
volume = {150},
pages = {230--239},
year = {2019},
}
@misc{who2021,
author = {{World Health Organization}},
title = {WHO global air quality guidelines},
year = {2021},
url = {https://www.who.int/publications/i/item/9789240034221},
}
License
MIT — see LICENSE.
Metadata
Release files for comfio 0.1.6
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| comfio-0.1.6.tar.gz | 112.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| comfio-0.1.6-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 222.4 kB
Release files / comfio-0.1.6.tar.gz
| Download URL | comfio-0.1.6.tar.gz |
|---|---|
| Size | 112.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4cf60632f99f9097e7f2be486906ff4306843f44c6d88af507ab72e548e33b78
|
|
BLAKE2b-256 checksum How to use checksums |
1e57ca0f1904974a8681655e3355dcfb6091353eab72b05ce679a14444e6da22
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 18, 2026.
Transparency logRelease files / comfio-0.1.6-py3-none-any.whl
| Download URL | comfio-0.1.6-py3-none-any.whl |
|---|---|
| Size | 109.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
25605c8ec62f9942ad00f15c691540c69c3b646c058b5eed46fe5310cfdf0f2d
|
|
BLAKE2b-256 checksum How to use checksums |
8021aef4b426e43c3bbef22358b2e84e86b28adb618856df36ca35b5e5f4f99e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 18, 2026.
Transparency log