buildingcalibration
District-scale static calibration, validation and representative-district clustering for the building-energy model family.
It covers the annual (non-hourly) half of the modelling chain:
- Calibration — the annual static calibration loop that fits a building
stock's energy model over
buildingmodel's static inference. - Validation — the Eq. 5 error decomposition of simulated versus measured
district consumption (ORE / Enedis), read through
buildingdata. - Clustering — reduction of a national building stock to representative districts, plus screening of districts whose measured data cannot support calibration.
- Plots — the figures for both stages.
Status
0.2.0is released (tagged and on PyPI).0.1.0shipped the modules extracted frombuilding_eload's core —core/static_simulation,core/validation,core/clustering.py,core/unreliable_districts.py,core/building_loader.py,utils/district_list.py,plots/static_calibration.py,plots/validation.py.0.2.0added the two API items the paper-reproduction workflow was missing —build_representative_districts/write_representative_districtsandrun_validation_sweep/average_over_years— plusplots.clustering. See the CHANGELOG for the full history.
Tutorials
doc/tutorials/ has two worked examples, rebuilt against the current API
(not carried over from building_eload's retired copies):
tutorial_01_static_simulation.ipynb—StaticParameters/StaticSimulation/StaticResultsfor one district.tutorial_03_validation.ipynb— district clustering (cluster_districts,build_representative_districts/write_representative_districts) thenValidationagainst measured consumption, plusrun_validation_sweep/average_over_yearsfor parametric studies.
The clustering steps run on synthetic data with no network needed; steps
that need real BDTOPO/census/ORE/Enedis data or a real dynamic-simulation
run are marked and left unexecuted. building_eload's own
doc/tutorials/tutorial_00_data_download.ipynb and
tutorial_02_dynamic_simulation.ipynb cover reference-data acquisition and
the hourly stage these two hand off to/from.
Quick start
Calibrate one district (static, annual)
from buildingcalibration import StaticParameters, StaticSimulation
parameters = StaticParameters(
n_inference=5, # stochastic building-stock draws to average over
calibration_year=2023,
climate_year=2023,
output_root="results", # -> results/static_simulation/2023/
)
results = StaticSimulation("751010101", parameters).run()
results.save_results()
Nothing else is needed: the building footprints (BDTOPO), the IRIS district
layer and the ORE per-IRIS annual consumption the calibration fits against are
all fetched through buildingdata. Pass calibration_file= (a frame or a path)
to pin a vintage, or building_footprint_folder= to use a local BDTOPO mirror.
Validate reconstructed load curves against measurements
from buildingcalibration import Validation
validation = Validation(
year=2023,
n_clusters=20,
scope="national",
building_type="residential",
input_path="results/dynamic_simulation/2023", # hourly parquets
output_path="results/validation/2023",
clustering_file=clustering_frame, # frame or path
unreliable_districts=unreliable_iris_frame, # frame, ids or path
)
validation.run()
error = validation.get_error() # paper Eq. 5 terms
The measured Enedis load curves come from buildingdata
(get_enedis_national() / get_enedis_regional()) when
validation_residential_file= is left unset.
Reduce a stock to representative districts
from buildingcalibration import cluster_districts
from buildingcalibration.clustering import screen_unreliable_iris_from_parquet
unreliable = screen_unreliable_iris_from_parquet("enedis_iris_consumption.parquet")
result = cluster_districts(
district_data, # one row per district
n_clusters=20,
feature_columns=["heating_needs", "dhw_needs", "specific_needs"],
unreliable_ids=unreliable["code_iris"], # never pick these as medoids
seed=42,
)
result.medoid_ids # the districts to simulate
result.scaling_weights # count-based multiplier per medoid
Publish the representative-districts table the rest of the chain reads
cluster_districts() answers one cut at a time; the validation stage and the
medoid selectors read a single wide table holding several cuts side by side
(cluster_label_<key> / cluster_medoid_<key> per cut, plus the district
attributes). build_representative_districts() is the converter and
write_representative_districts() the thin writer:
from buildingcalibration import write_representative_districts
from buildingcalibration.clustering import (
cluster_districts,
cluster_key_from_fraction,
representative_districts_file,
)
results = {n: cluster_districts(features, n_clusters=n, seed=42) for n in (10, 20)}
write_representative_districts(
results,
features, # one row per district
representative_districts_file("results/clustering", scope="national"),
)
Key convention — the column suffix is always a positive integer: the
cluster count for a national table (cluster_medoid_20), the integer
percent of districts kept for a regional one (cluster_medoid_5 is 5 %).
Fractions are rejected, not guessed: convert once with
cluster_key_from_fraction(0.05) -> 5. representative_districts_file() is the
single definition of the conventional file name, shared with the readers
(get_representative_districts(), Validation(clustering_path=...)), so a
table can never be written under one name and looked up under another.
Sweep a parameter and decompose the error per variant
from buildingcalibration import average_over_years, run_validation_sweep
frame = run_validation_sweep(
{
f"heating_threshold={value:g}": [
{"year": year, "input_path": f"results/dynamic/{value:g}/{year}"}
for year in (2021, 2022, 2023)
]
for value in (14.0, 15.0, 16.0)
},
common={"n_clusters": 20, "scope": "national", "clustering_file": table,
"unreliable_districts": unreliable},
)
# frame: long, one row per (label, year, metric) -- the full Eq. 5 terms
average_over_years(frame) # one row per (label, metric)
Each case carries its own inputs (frames or explicit paths); the sweep invents no path and writes nothing.
Doctrine: frames first, no path registry
Nothing in this package resolves a filesystem path at import time, and there is
no data/ tree to install:
- Pipeline intermediates — dynamic-simulation results, clustering tables,
the unreliable-district list, output directories — are passed in as in-memory
frames or as explicit paths, and have no default. A missing one raises a
ValueErrornaming the parameter rather than reading from somewhere you did not choose. - External open data — BDTOPO footprints, IRIS districts, ORE annual
consumption, Enedis measured load curves — defaults to a
buildingdatagetter (get_bdtopo(),get_districts(),get_ore(),get_enedis_national()/get_enedis_regional()), which owns the download, the cache and the vintage. Pass a frame or a path to pin a specific vintage instead.
The one exception is the SDES parc résidentiel workbook read by
plots.validation.read_sdes_data(): buildingdata has no getter for it yet, so
it is a required frame-or-path argument (and reading the .xlsx form needs
openpyxl, which is not a declared dependency).
Relationship to building_eload
buildingcalibration and building_eload have no import relationship in
either direction. building_eload becomes a pure hourly dynamic-simulation
library; this package owns the static/annual side. The two are coupled only by
parquet data contracts on disk — a calibrated stock written here is read
there, and vice versa. That seam already existed inside the old monolith; the
split just makes it a package boundary. A structural test
(tests/test_data_path_doctrine.py) enforces both halves of that: no path
registry, and no building_eload import anywhere in the package.
The family
| Package | Role | Host |
|---|---|---|
buildingdata |
dataset access layer: BDTOPO/WFS, ERA5, INSEE census, Enedis/ORE, ELMAS | gitlab.com/energytransition |
buildingmodel |
static inference engine: building-stock physical characteristics and annual demand | gitlab.com/energytransition |
heatpumpmodel |
shared heat-pump seasonal-performance physics (Rogeau et al. 2024) | git.persee |
buildingcalibration |
static calibration, validation, representative-district clustering | git.persee |
building_eload |
hourly dynamic simulation of district electric load | git.persee |
building_eload_paper |
Snakemake reproduction workflow for the published paper; pinned to building_eload==0.4.3 and unaffected by this split |
git.persee |
Install
pip install buildingcalibration
# or, from a checkout:
pip install -e ".[dev]"
Python 3.10–3.13.
Tests
pytest # full suite
pytest -m "not integration" # hermetic subset, what CI runs
The hermetic subset needs no data and no network. The integration tests run
the calibration and validation stages on real districts; they read a local
reference-data tree, <repo>/data by default, overridable with the
BUILDING_ELOAD_DATA environment variable (the name is shared with
building_eload on purpose, so one setting covers both checkouts).
One integration test — tests/integration/test_static_to_dynamic_seam.py,
the cross-package end-to-end seam — additionally needs building_eload
installed. It is an optional test-time requirement only: building_eload is
not a runtime dependency, not part of the dev extra, and the library itself
must never import it (a structural test enforces that). Install it yourself if
you want to run that test; otherwise it skips.
Licence
MIT — see LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file buildingcalibration-0.2.2.tar.gz.
File metadata
- Download URL: buildingcalibration-0.2.2.tar.gz
- Upload date:
- Size: 100.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fe30dac9c6e91e026f17a34c37c7a7604b87f398b1ccdf60bcef2da11bb35c7e
|
|
| MD5 |
6f06812ca31edfbeb236882ec06490a4
|
|
| BLAKE2b-256 |
18e13a78b000fe49e123c430a365bc43b6ed7c2997c5083e56c3dd339d14247a
|
File details
Details for the file buildingcalibration-0.2.2-py3-none-any.whl.
File metadata
- Download URL: buildingcalibration-0.2.2-py3-none-any.whl
- Upload date:
- Size: 113.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
61ad37d14c25779231b99315d018ac99bb0afa2aee13db41a80f113c32cf969c
|
|
| MD5 |
962bc40e31b19d4cba8fa34d1b640c39
|
|
| BLAKE2b-256 |
8e12d2e29e41e1b792c53ea9f75326b227ae040d12e16e1908899af96b82a16f
|