Skip to content

AWHP cooling logic #111#116

Open
urwahah wants to merge 9 commits into
developmentfrom
AWHP-cooling-logic-#111
Open

AWHP cooling logic #111#116
urwahah wants to merge 9 commits into
developmentfrom
AWHP-cooling-logic-#111

Conversation

@urwahah

@urwahah urwahah commented Jun 19, 2026

Copy link
Copy Markdown
Collaborator

per #111:

  • added new awhp_sizing_priority input to choose load that drives AWHP sizing
  • added logic to size AWHP for cooling or larger of heating and cooling
    • revised the AWHP_NUM_H variables to just AWHP_NUM since the same number is used for both. AWHP_NUM_C is still kept to track the units actually used in cooling, per below
  • revised AWHP operation to allow simultaneous heating and cooling operation
    • heating is assumed to take priority. the available AWHP cooling capacity is calculated using the number of AWHP compressors not used to serve heating load in any given hour

@urwahah urwahah requested a review from t-kramer June 19, 2026 17:45
Comment thread src/energy.py

@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.

Thanks for working on this, @urwahah!

I had a quick look and found no major issues. I added some comments/questions. Please go through them if you have time. Below some more points from an AI reviewer. Might be worth checking them.


1. Potential NameError for sizing_priority == "larger" + sizing_mode == "fixed_num_units" (src/energy.py)

The "larger" branch only executes for integer_sizing_peak_load / fractional_sizing_peak_load. If a scenario somehow reaches the "Determine number of units" block with sizing_priority == "larger" and sizing_mode == "fixed_num_units", neither sizing_load nor cap_ref will have been set, crashing with a NameError. The UI disables the dropdown in this case, but there is no guard in the calculation code itself.

2. Division-by-zero in compressor allocation (src/energy.py ~Phase 5)

num_compressors_h = np.ceil(
    (df[Col.AWHP_HHW_W.value] / df[Col.AWHP_CAP_H_W.value]) * num_compressors
)

AWHP_CAP_H_W can be zero in hours where the unit has no capacity (e.g. extreme outdoor temperatures), producing NaN / Inf that propagates into num_compressors_c and awhp_num_c. The old code used an explicit mask for zero-heating hours.

3. num_compressors_c can go negative

If the heating load in an hour exceeds the unit's rated capacity (AWHP_HHW_W > AWHP_CAP_H_W), num_compressors_h > num_compressors, so num_compressors_c becomes negative. This silently produces negative cooling capacity and served cooling load.

4. _awhp_reference_capacity ignores its performance parameter for the actual lookup (src/energy.py)

The function accepts performance: PerformanceCurves, uses it only for the isinstance check, then re-fetches the same data via e.performance[load_type]. The parameter is redundant and the inconsistency is confusing — either use the passed-in object for the lookup too, or remove the parameter.

Comment thread src/energy.py Outdated

cap_total_c_W = awhp_cap_c * awhp_num_c
# assuming that AWHPs all have 50% turndown (2 compressors)
num_compressors = awhp_num * 2

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.

It looks like this assumption is central to the new simultaneous H+C logic and should be at minimum a named constant? Maybe even a configurable field on Equipment?

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.

good point.. i think 2 compressors is pretty standard for modular units, so will just add a named constant for now, and we can add to the class if needed?

Comment thread src/energy.py Outdated
Comment thread pages/equipment_page.py Outdated
Comment thread src/config.py
@urwahah

urwahah commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator Author
  1. the edge case of having sizing_priority == "larger" and sizing_mode == "fixed_num_units" is possible, but doesn't cause any downstream errors. when sizing with a fixed number, the code simply disregards the sizing priority and uses the provided # of units. the sizing_load and cap_ref parameters are only needed when sizing for a peak load percentage.
  2. added a check to replace any NaNs in num_compressors_h with 0 before further calculations
  3. it's not possible for AWHP_HHW_W to exceed AWHP_CAP_H_W. AWHP_HHW_W is determined as np.minimum(df[Col.HHW_REM_W.value].to_numpy(), AWHP_CAP_H_W). in any case, i added a check to set num_compressors_c to a maximum of 0 or the calculated value
  4. this is because the performance parameter passed to the function is the interpolated performance based on the provided HHW supply temperature(s), whereas a (possibly) different reference temperature is used to calculate reference capacity. but using performance in the isinstance check is the simplest way i can think of to check if a fixed capacity is used

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