Metadata-Version: 2.4
Name: buildingcalibration
Version: 0.1.0
Summary: District-scale static calibration, validation and representative-district clustering for the building-energy model family
Author-email: Yassine Abdelouadoud <yassine.abdelouadoud@gmail.com>
Maintainer-email: Yassine Abdelouadoud <yassine.abdelouadoud@gmail.com>
License: The MIT License (MIT)
        =====================
        
        - Copyright © `2026` `Yoann Chiche`
        - Copyright © `2026` `Seddik Yassine Abdelouadoud`
        - Copyright © `2026` `Anna Cocchi`
        
        Permission is hereby granted, free of charge, to any person
        obtaining a copy of this software and associated documentation
        files (the “Software”), to deal in the Software without
        restriction, including without limitation the rights to use,
        copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the
        Software is furnished to do so, subject to the following
        conditions:
        
        The above copyright notice and this permission notice shall be
        included in all copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
        EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
        OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
        NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
        HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
        WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
        FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
        OTHER DEALINGS IN THE SOFTWARE.
        
Project-URL: Homepage, https://git.persee.minesparis.psl.eu/planeterr/buildingcalibration
Project-URL: Repository, https://git.persee.minesparis.psl.eu/planeterr/buildingcalibration
Project-URL: Changelog, https://git.persee.minesparis.psl.eu/planeterr/buildingcalibration/-/blob/main/CHANGELOG.md
Classifier: Development Status :: 3 - Alpha
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Physics
Requires-Python: <4.0.0,>=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: buildingmodel>=1.0.2
Requires-Dist: buildingdata>=0.2.0
Requires-Dist: colorlog
Requires-Dist: numpy
Requires-Dist: pandas
Requires-Dist: polars
Requires-Dist: geopandas
Requires-Dist: shapely
Requires-Dist: scipy
Requires-Dist: scikit-learn
Requires-Dist: fastcluster
Requires-Dist: matplotlib
Requires-Dist: seaborn
Requires-Dist: tqdm
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Requires-Dist: pytest-cov; extra == "dev"
Requires-Dist: ruff>=0.16; extra == "dev"
Dynamic: license-file

# 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`](https://gitlab.com/energytransition/buildingmodel)'s
  static inference.
- **Validation** — the Eq. 5 error decomposition of simulated versus *measured*
  district consumption (ORE / Enedis), read through
  [`buildingdata`](https://gitlab.com/energytransition/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

> **Pre-release.** The version is `0.1.0.dev0`: the modules have landed
> (extracted from `building_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`) and the test suite runs,
> but `0.1.0` has not been tagged and nothing is published to PyPI yet.

## Quick start

### Calibrate one district (static, annual)

```python
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

```python
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

```python
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
```

### 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
  `ValueError` naming 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
  [`buildingdata`](https://gitlab.com/energytransition/buildingdata) getter
  (`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`](https://gitlab.com/energytransition/buildingdata) | dataset access layer: BDTOPO/WFS, ERA5, INSEE census, Enedis/ORE, ELMAS | gitlab.com/energytransition |
| [`buildingmodel`](https://gitlab.com/energytransition/buildingmodel) | static inference engine: building-stock physical characteristics and annual demand | gitlab.com/energytransition |
| [`heatpumpmodel`](https://git.persee.minesparis.psl.eu/planeterr/heatpumpmodel) | shared heat-pump seasonal-performance physics (Rogeau et al. 2024) | git.persee |
| **`buildingcalibration`** | **static calibration, validation, representative-district clustering** | **git.persee** |
| [`building_eload`](https://git.persee.minesparis.psl.eu/planeterr/building_eload) | hourly dynamic simulation of district electric load | git.persee |
| [`building_eload_paper`](https://git.persee.minesparis.psl.eu/planeterr/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

```bash
pip install buildingcalibration
# or, from a checkout:
pip install -e ".[dev]"
```

Python 3.10–3.13.

## Tests

```bash
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).

## Licence

MIT — see `LICENSE`.
