Skip to content

feat: support comparing buildings across measure packages#31

Open
nllong wants to merge 1 commit into
feat/support-multiple-comstock-releasesfrom
feat/support-measure-package-comparison
Open

feat: support comparing buildings across measure packages#31
nllong wants to merge 1 commit into
feat/support-multiple-comstock-releasesfrom
feat/support-measure-package-comparison

Conversation

@nllong

@nllong nllong commented Jul 23, 2026

Copy link
Copy Markdown
Member

Summary

Adds support for downloading ComStock's measure/upgrade package definitions and comparing a building's results across those packages.

Stacked on #30 (multi-release support) — this targets that branch, not main, so it will show that PR's diff too until it merges.

Background

Each ComStock "upgrade" represents a different energy-efficiency measure package (e.g. a heat pump RTU, a VRF system, envelope upgrades, etc.) applied to the same baseline building sample. Every release also publishes:

  • upgrades_lookup.json — maps upgrade id → human-readable package name for that release.
  • measure_name_crosswalk.csv — maps a stable measure_id (e.g. hvac_0005) to the upgrade id/name used for that measure in that release and every earlier release — because upgrade ids are not stable across releases (e.g. "Heat Pump RTU" happens to be upgrade 1 in all three currently-supported releases, but that's not guaranteed for every measure, and I verified several measures do shift ids release to release).

What changed

  • list_upgrades(save_dir) — downloads/caches upgrades_lookup.json, returns {upgrade_id: package_name} for the processor's configured release.
  • get_measure_crosswalk(save_dir) — downloads/caches measure_name_crosswalk.csv as a DataFrame.
  • find_upgrade_id(save_dir, measure_id, target_release=None) — looks up the upgrade id for a stable measure_id in a specific release (defaults to the processor's own release). Returns None if the measure wasn't included in that release, and raises a clear ValueError if the target release isn't covered by the currently-loaded crosswalk (a release's crosswalk only covers itself + earlier releases — release_3's crosswalk covers all three currently-supported releases, so it's the one to use for full cross-release comparisons).
  • process_metadata_for_upgrades(save_dir, upgrades=None) — downloads and combines metadata for multiple upgrades into one DataFrame (defaults to every upgrade available for the release). Refactored process_metadata() into a thin wrapper around a new _download_metadata_for_upgrade(save_dir, upgrade) helper so both share the same download/caching logic, just parameterized by upgrade instead of hardcoded to self.upgrade. Every partition already includes an upgrade id and in.upgrade_name column, so grouping the combined result by bldg_id lets you compare a building's simulated performance across packages.
processor = ComStockProcessor(state="DE", county_name="All", building_type="SmallOffice", upgrade="0", base_dir=base_dir)

# Compare baseline vs. a heat pump RTU package for the same buildings
combined_df = processor.process_metadata_for_upgrades(save_dir=base_dir, upgrades=["0", "1"])
combined_df.groupby("bldg_id").apply(
    lambda g: g.set_index("upgrade")["out.site_energy.total.energy_consumption..kwh"]
)

# Find the "same" measure across releases (upgrade ids shift between releases)
processor.find_upgrade_id(save_dir=base_dir, measure_id="hvac_0005")                               # "1" (release_3)
processor.find_upgrade_id(save_dir=base_dir, measure_id="hvac_0005", target_release="release_1")   # "1"

Note: a building can appear more than once per upgrade in the "full" metadata (reused across census tracts, each with its own weight) — this is a pre-existing characteristic of the underlying dataset, not something introduced here. Documented in the docstring/README.

Validation

  • uv run pytest tests/ -m unit ✅ (8 passed — release/crosswalk validation, mocked default-upgrades behavior)
  • uv run pytest tests/ -m integration ✅ (17 passed, ~2 min — list_upgrades, get_measure_crosswalk, find_upgrade_id across releases, process_metadata_for_upgrades with an explicit upgrade list for DE/SmallOffice)
  • uv run mypy
  • uv run pre-commit run --all-files

Each ComStock "upgrade" is a different energy-efficiency measure package applied
to the same baseline building sample. Every release also publishes an
upgrades_lookup.json (upgrade id -> package name) and a measure_name_crosswalk.csv
(a stable measure_id crosswalked to the upgrade id/name used for that measure in
that release and earlier releases, since upgrade ids/measures are release-specific
and not stable across releases).

- Add ComStockProcessor.list_upgrades(save_dir) to download/cache
  upgrades_lookup.json and return {upgrade_id: package_name} for the configured
  release.
- Add ComStockProcessor.get_measure_crosswalk(save_dir) to download/cache
  measure_name_crosswalk.csv as a DataFrame, and find_upgrade_id(save_dir,
  measure_id, target_release=None) to look up the upgrade id for a stable
  measure_id in a specific release, raising a clear error if that release isn't
  covered by the currently loaded crosswalk (a release's crosswalk only covers
  itself and earlier releases -- release_3's crosswalk covers all three
  currently-supported releases).
- Refactor process_metadata() into a thin wrapper around a new
  _download_metadata_for_upgrade(save_dir, upgrade) helper parameterized by
  upgrade instead of hardcoded self.upgrade, and add
  process_metadata_for_upgrades(save_dir, upgrades=None) which downloads and
  combines metadata for multiple upgrades (defaulting to every upgrade from
  list_upgrades()) into one DataFrame. Every partition already includes an
  `upgrade` id and `in.upgrade_name` column, so grouping the combined result by
  bldg_id lets you compare a building's results across packages.
- Add unit tests (release validation, mocked default-to-every-upgrade behavior)
  and integration tests (list_upgrades, get_measure_crosswalk, find_upgrade_id
  across releases, and process_metadata_for_upgrades with an explicit small
  upgrade list for Delaware/SmallOffice).
- Document the new methods and a building-comparison usage example in
  README.md.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant