Skip to content

Conversation

@bpulluta
Copy link
Collaborator

@bpulluta bpulluta commented Oct 10, 2025

Overview

This PR enables combining multiple load profiles from different source years (e.g., site load from 2016, EV load from 2024) with proper weekday alignment and leap year handling. Also includes JuMP expression building optimization for sub-hourly time resolutions.

Added

Multiple Load Components Support

  • load_components in ElectricLoad to combine profiles from different source years
  • src/core/load_alignment.jl module with centralized alignment functions:
    • align_series_to_year() - weekday alignment across years

Sub-hourly Support

  • Full support for 30-min, 15-min, 5-min time resolutions in load component alignment

Changed

Code Consolidation

  • Refactored day-of-week shifting logic in doe_commercial_reference_building_loads.jl and electric_utility.jl to use centralized align_series_to_year() function
  • Eliminated code duplication across load processing functions by consolidating leap year normalization logic

JuMP Performance Optimization

  • Problem: Sub-hourly time steps (e.g., 15-min = 35,040 steps/year) caused JuMP warnings with large sum() comprehensions
  • Solution: Replaced with efficient expression building using JuMP.AffExpr() and JuMP.add_to_expression!()
  • Impact: Cleaner code, no warnings, better performance for high-resolution models

Example Usage

{
  "ElectricLoad": {
    "load_components": [
      {"loads_kw": [...], "year": 2016, "label": "Building"},
      {"loads_kw": [...], "year": 2024, "label": "EV"}
    ],
    "year": 2024
  }
}

Testing

✅ All 1100+ existing tests pass

@bpulluta bpulluta changed the title added multiple loads option and alignment based on year of load Load Component Alignment & JuMP Performance Improvements Oct 16, 2025
@bpulluta bpulluta marked this pull request as ready for review October 16, 2025 16:02
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Implements multiple load component alignment (combining profiles from different source years with weekday/leap-year handling) and replaces large JuMP sum comprehensions with incremental AffExpr construction for sub-hourly performance improvements.

  • Adds load alignment module and extends ElectricLoad to support load_components, leap year policies, and component-level result reporting
  • Refactors existing weekday-shift logic to centralized align_series_to_year
  • Optimizes many constraint expressions to avoid JuMP warnings/performance issues at high temporal resolution

Reviewed Changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
test/runtests.jl Adds new multiple-load and sub-hourly tests; relaxes some tolerances and replaces a stricter end-of-year alignment assertion.
src/results/electric_load.jl Adds component-level result aggregation (annual, peak, average, metadata).
src/core/load_alignment.jl New module: normalization, weekday alignment, multi-component alignment, metadata.
src/core/electric_utility.jl Replaces custom emissions/profile alignment with centralized alignment function.
src/core/electric_load.jl Extends ElectricLoad to build from multiple components, store metadata, preprocess components.
src/core/doe_commercial_reference_building_loads.jl Refactors CRB alignment to use centralized alignment; adjusts monthly scaling flow and leap handling.
src/constraints/thermal_tech_constraints.jl Converts boiler cost expressions to incremental AffExpr construction.
src/constraints/storage_constraints.jl Optimizes average SOC expression construction.
src/constraints/steam_turbine_constraints.jl Optimizes steam turbine OM expression.
src/constraints/renewable_energy_constraints.jl Rewrites several annual energy expressions using AffExpr loops.
src/constraints/production_incentive_constraints.jl Optimizes production incentive constraint expression building.
src/constraints/generator_constraints.jl Optimizes generator OM and fuel cost expressions.
src/constraints/flexible_hvac.jl Optimizes comfort violation cost expression.
src/constraints/emissions_constraints.jl Optimizes emissions calculation expressions.
src/constraints/electric_utility_constraints.jl Refactors tier usage constraints to explicit loops with AffExpr.
src/constraints/chp_constraints.jl Optimizes CHP fuel and OM cost expressions.
src/REopt.jl Includes new load_alignment module.
CHANGELOG.md Documents new feature additions and performance changes.
Comments suppressed due to low confidence (1)

src/core/load_alignment.jl:1

  • This docstring snippet shows @Assert and println statements referencing metadata before it is introduced in the surrounding example context, which can confuse users (and the closing backticks appear unmatched relative to any opening fence). Consider removing these lines or moving them into a clearly marked example block with a proper opening code fence.
# REopt®, Copyright (c) Alliance for Sustainable Energy, LLC. See also https://github.com/NREL/REopt.jl/blob/master/LICENSE.

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

fix error reporting to be consistent

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@Bill-Becker
Copy link
Collaborator

@bpulluta it would be good if we could split the "add to expression" stuff into a separate PR, so just start from the develop branch and cherry-pick these four commits (I think):
image

And then as we talked about, probably removing the separate leap day policy option, and I'm curious how much simpler it would be to assume the user must put in the multiple load components with the same calendar year structure (e.g. 2017 and 2023 are the same). I'm open to seeing if the load year shift stuff could still be added while minimizing the extra complexity in core/electric_load.jl, but as I mentioned I don't think it's too inconvenient for the user to handle and necessary shifting. I'm mainly worried about maintainability/readability and future development flexibility (sorry for all the "ility's").

@bpulluta
Copy link
Collaborator Author

be good if we could split the "add to expression" stuff into a separate PR, so just start from the develop branch and cherry-pick these four commits (I think):

That sounds like a great idea, I'll do that and separate the load stuff from the JuMP expression bug fixes

@Bill-Becker
Copy link
Collaborator

@bpulluta FYI when I removed the SimpleLogger() wrapper around the two culprit tests that produced the JuMP warning, the warnings were still there in this branch. You may have tested locally and didn't get the warnings. My local testing has the same behavior, no warnings. So it seems there's something different about the GitHub Actions runner OS/environment that is causing these 15-min interval and multiple PV tests to produce the warning. I asked Copilot to dig deeper into the JuMP package source code and REopt code to understand. It pointed to the fact that in the load_balance.jl constraints, when we add two or more variables together, they are creating a GenericAffExpr and then when we do the 15-min interval analysis, it goes over the 20,000 limit that it found in the JuMP code to trigger that warning. I still have some open questions about that, and we also have the different local vs Actions mystery which may be from the environment differences (haven't tracked that down fully). Just thought you'd be interested in this update!

@bpulluta
Copy link
Collaborator Author

bpulluta commented Dec 30, 2025

@bpulluta FYI when I removed the SimpleLogger() wrapper around the two culprit tests that produced the JuMP warning, the warnings were still there in this branch. You may have tested locally and didn't get the warnings. My local testing has the same behavior, no warnings. So it seems there's something different about the GitHub Actions runner OS/environment that is causing these 15-min interval and multiple PV tests to produce the warning. I asked Copilot to dig deeper into the JuMP package source code and REopt code to understand. It pointed to the fact that in the load_balance.jl constraints, when we add two or more variables together, they are creating a GenericAffExpr and then when we do the 15-min interval analysis, it goes over the 20,000 limit that it found in the JuMP code to trigger that warning. I still have some open questions about that, and we also have the different local vs Actions mystery which may be from the environment differences (haven't tracked that down fully). Just thought you'd be interested in this update!

@Bill-Becker Thanks for checking it out and good to know. Interesting that there is a difference in environments and that you dont see it locally but still see it in the Github actions runner.

I've been working with other development groups and something that is used often is either Pixi or UV for python project and package management. It works really well at ensuring a consistent environments across all operating systems

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.

3 participants