Skip to content

Dynamic fuel switching #121 - #154

Open
urwahah wants to merge 4 commits into
developmentfrom
fuel-switching-#121
Open

Dynamic fuel switching #121#154
urwahah wants to merge 4 commits into
developmentfrom
fuel-switching-#121

Conversation

@urwahah

@urwahah urwahah commented Aug 18, 2026

Copy link
Copy Markdown
Collaborator

For #121:

  • Added a new fuel switching input "Use optimal heating fuel" under the backup heating equipment selection
  • Added new scenarios and scenario group to compare fuel switching
  • Added new columns to the loads_to_site dataframe:
    • FUEL_SWITCHING, HHW_REM_W_NG_MODE, BOILER_HHW_W_NG_MODE, GAS_BOILER_WH_NG_MODE, intermediate columns to store the "natural gas mode" load/energy use that it reverts to if gas emissions < electric emissions
    • BOILER_EQ_CALC, BOILER_CAP_W to store the scenario's boiler sizing information as it's used in the emissions function
  • Added fuel switching calculation in site_to_source
  • Moved the boiler sizing calculation to site_to_source

Here is a link to the change request to update docs for this.

A few minor changes unrelated to the fuel switching:

  • Updated the AWHP sizing logic to use the remaining HHW/CHW loads instead of the original load profile. For heat recovery scenarios this will allow the AWHP to be downsized. (This is the change causing the merge conflicts, I think all the new changes should be accepted but wasn't sure if me doing that would also merge the PR)
  • Added a 60% efficiency boiler

@urwahah urwahah added this to the 02 | Capability expansion milestone Aug 18, 2026
Comment thread src/energy.py
@urwahah
urwahah requested a review from t-kramer August 18, 2026 01:36

@t-kramer t-kramer left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Hi @urwahah, great work as always.

I added some minor comments/questions that should be pretty easy handle. Let me know if you have questions. When these are resolved, I'll go ahead with the merge and handle the merge conflicts.

Comment thread src/equipment.py Outdated
Comment thread pages/equipment_page.py Outdated
Comment thread src/energy.py
emissions_intensity_NG = gas_emissions_rate / merged[Col.BOILER_EFF.value]
NG_mode = (
merged[Col.FUEL_SWITCHING.value].to_numpy() # only evaluate if fuel switching is true
& (

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

For this block, I guess AWHP_COP_H can be 0 for hours when AWHP isn't operating? That would produce inf and inf > emissions_intensity_NG is True. Wouldn't that incorrectly trigger NG mode even when the AWHP wasn't running? Please double check, I don't know if I am right on this one. You could use AWHP_HHW_W > 0 is a condition.

@urwahah urwahah Sep 3, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

AWHP_COP is never 0, _capacity_constraints overrides the capacity to 0 for OATs outside the operating constraints, which prevents it from operating - but the COP is just interpolated once (_per_unit_heating_cop) and returns the min/max value when OAT is outside the curve. also even if COP were 0 and returned an infinite value, we would want the boiler to operate to serve the loads

Comment thread src/energy.py
Comment thread src/energy.py
results.append(final_df)

total_emissions_kg = sum(r[Col.TOTAL_EMISSIONS_KG_CO2E.value].sum() for r in results)
total_emissions_kg = final_df[Col.TOTAL_EMISSIONS_KG_CO2E.value].sum()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Can you double-check that the change you made in this line is correct? I just want to make sure we don't sum up total_emissions_kg across all scenarios.

@urwahah urwahah Sep 3, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

yep - that's what it was doing before - final_df is the results from the scenario currently being processed, and is appended to results iteratively. this will still print total emissions across all equipment scenarios, but i don't think it's needed to print those separately for a quick check

Comment thread src/energy.py
else 0
)
logger.debug(f"Phase 3 complete: Boiler covers {boiler_coverage:.1f}% of heating load")
df[Col.HHW_REM_W.value] -= boiler_served_W

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This and previous version are mathematically equivalent only if the boiler always serves exactly the remaining load, which should be true, right? Can you check?

@urwahah urwahah Sep 2, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

yes, have spot checked some results and they are equivalent. the reason to change this is that my understanding is there should never be a scenario in which we reach this stage and the boiler doesn't serve exactly all the remaining HHW load. there is a logger warning in case both gas and electric resistance operate (line 904) - but that warning doesn't really do anything until we make this change because currently the remaining load is manually set to 0 before that phase.

Comment thread data/input/equipment_data.JSON
Comment thread data/input/equipment_data.JSON Outdated
Comment thread src/energy.py Outdated
@urwahah

urwahah commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator Author

@t-kramer - updated based on your review, i left open a few comments with responses.
@praftery - could you take a look at the new scenario group before we merge? looking back on it i'm not 100% sure i have reasonable ones based on what we discussed a few weeks ago.

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.

2 participants