Skip to content

Use condenser capacity instead of evaporator capacity to determine water flow rate of WAHP coils#11019

Merged
mitchute merged 13 commits intodevelopfrom
wahp_wtr_flow_calcs_fix
Sep 30, 2025
Merged

Use condenser capacity instead of evaporator capacity to determine water flow rate of WAHP coils#11019
mitchute merged 13 commits intodevelopfrom
wahp_wtr_flow_calcs_fix

Conversation

@lymereJ
Copy link
Collaborator

@lymereJ lymereJ commented Apr 2, 2025

Pull request overview

Address some code comment: use condenser capacity instead of evaporator capacity to determine water flow rate of WAHP coils.

Description of the purpose of this PR

Pull Request Author

  • Title of PR should be user-synopsis style (clearly understandable in a standalone changelog context)
  • Label the PR with at least one of: Defect, Refactoring, NewFeature, Performance, and/or DoNoPublish
  • Pull requests that impact EnergyPlus code must also include unit tests to cover enhancement or defect repair
  • Author should provide a "walkthrough" of relevant code changes using a GitHub code review comment process
  • If any diffs are expected, author must demonstrate they are justified using plots and descriptions
  • If changes fix a defect, the fix should be demonstrated in plots and descriptions

Reviewer

  • Perform a Code Review on GitHub
  • If branch is behind develop, merge develop and build locally to check for side effects of the merge
  • If defect, verify by running develop branch and reproducing defect, then running PR and reproducing fix
  • If feature, test running new feature, try creative ways to break it
  • CI status: all green or justified
  • Check that performance is not impacted (CI Linux results include performance check)
  • Run Unit Test(s) locally
  • Check any new function arguments for performance impacts
  • Verify IDF naming conventions and styles, memos and notes and defaults
  • If new idf included, locally check the err file and other outputs

@lymereJ lymereJ added the Defect Includes code to repair a defect in EnergyPlus label Apr 2, 2025
@lymereJ lymereJ added this to the EnergyPlus 25.2 IO Freeze milestone Apr 2, 2025
@github-actions
Copy link

github-actions bot commented Apr 2, 2025

⚠️ Regressions detected on macos-14 for commit 60f3325

Regression Summary
  • EIO: 16
  • ERR: 14
  • MTR Big Diffs: 6
  • Table Big Diffs: 16
  • Table String Diffs: 12
  • ESO Small Diffs: 1
  • ESO Big Diffs: 13

Copy link
Collaborator Author

@lymereJ lymereJ left a comment

Choose a reason for hiding this comment

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

Walkthrough:

Comment on lines +2874 to +2882
RatedWaterVolFlowRateDes =
(1 + 1 / RatedHeatCOP) * simpleWatertoAirHP.RatedCapHeat / (state.dataSize->PlantSizData(PltSizNum).DeltaT * Cp * rho);
if (simpleWatertoAirHP.CompanionCoolingCoilNum > 0) {
auto const &companionCoolingCoil =
state.dataWaterToAirHeatPumpSimple->SimpleWatertoAirHP(simpleWatertoAirHP.CompanionCoolingCoilNum);
RatedWaterVolFlowRateDes = max(RatedWaterVolFlowRateDes,
(1 + 1 / RatedCoolCOP) * companionCoolingCoil.RatedCapCoolTotal /
(state.dataSize->PlantSizData(PltSizNum).DeltaT * Cp * rho));
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Determine the water flow rate using the condenser capacity:

Q_c = Q_e + P
Q_c = Q_e + Q_e / COP
Q_c = Q_e * (1 + 1 / COP)

Where Q_c and Q_e are respectively the condenser and evaporator capacity, and P is the input power.

The calculation is done for both the heating and companion cooling coil and set to the maximum of the two.
Set the water flow rate to be the maximum of heating or cooling coil water flow rate

Copy link
Collaborator

Choose a reason for hiding this comment

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

This doesn't seem right. RatedCapHeat is the condenser heat, it just happens to be the evaporator or load side. Yes, confusing. So heating flow rate sizing should simply be based on RatedCapHeat. So I think it should be simpleWatertoAirHP.RatedCapHeat for the heating object and just companionCoolingCoil.RatedCapCoolTotal for the cooling object. Probably need to talk this through more like we did for the Plant EIR HP. It matters which flow rate is being sized. If it's the load side then the flow should be the larger of flows to meet the load. Probably need to review how the PlantLoopHeatPumpEIR is sized.

@Nigusse made some changes to the Plant EIR HP on #10382:

    if (this->EIRHPType == DataPlant::PlantEquipmentType::HeatPumpEIRHeating) {
        designSourceSideHeatTransfer = tmpCapacity * (1 - 1 / this->referenceCOP);
    } else {
        designSourceSideHeatTransfer = tmpCapacity * (1 + 1 / this->referenceCOP);
    }

Copy link
Collaborator Author

@lymereJ lymereJ Apr 3, 2025

Choose a reason for hiding this comment

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

Oh, yes, that makes sense. I propagated the cooling coil adjustments to the heating coil but I see that it is incorrect. I'll push a correction. Thanks for catching that.

state->dataWaterToAirHeatPumpSimple->SimpleWatertoAirHP(1).RatedCapCoolTotal = AutoSize;
state->dataWaterToAirHeatPumpSimple->SimpleWatertoAirHP(1).RatedCapCoolSens = AutoSize;
state->dataWaterToAirHeatPumpSimple->SimpleWatertoAirHP(1).RatedWaterVolFlowRate = 0.0;
state->dataWaterToAirHeatPumpSimple->SimpleWatertoAirHP(1).RatedWaterVolFlowRate = AutoSize;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Repurpose existing test to let the rated water flow rate be autosized and test the outcome.

@github-actions
Copy link

github-actions bot commented Apr 2, 2025

⚠️ Regressions detected on macos-14 for commit 36c7190

Regression Summary
  • EIO: 16
  • ERR: 14
  • MTR Big Diffs: 6
  • Table Big Diffs: 16
  • Table String Diffs: 12
  • ESO Small Diffs: 1
  • ESO Big Diffs: 13

Comment on lines +2874 to +2875
if (simpleWatertoAirHP.WAHPType == WatertoAirHP::Heating) {
RatedWaterVolFlowRateDes = simpleWatertoAirHP.RatedCapHeat / (state.dataSize->PlantSizData(PltSizNum).DeltaT * Cp * rho);
RatedWaterVolFlowRateDes =
(1 + 1 / RatedHeatCOP) * simpleWatertoAirHP.RatedCapHeat / (state.dataSize->PlantSizData(PltSizNum).DeltaT * Cp * rho);
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Here we're dealing with the heating coil so the evaporator is on the source side and the condenser is on the load side.

So if we start with Qc = Qe + P and because we're dealing with heating operation COP = Qc / P so Qe = Source Side Load = Qc - P = Qc (1 - 1 / COP) and Qc = simpleWatertoAirHP.RatedCapHeat. So I think that the + sign should be changed to -.

Instead of:

RatedWaterVolFlowRateDes =
(1 + 1 / RatedHeatCOP) * simpleWatertoAirHP.RatedCapHeat / (state.dataSize->PlantSizData(PltSizNum).DeltaT * Cp * rho);

We should have:

RatedWaterVolFlowRateDes =
(1 - 1 / RatedHeatCOP) * simpleWatertoAirHP.RatedCapHeat / (state.dataSize->PlantSizData(PltSizNum).DeltaT * Cp * rho);

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree with the suggested change. See the equation below for reference:

The source side (evaporator coil) fluid mass flow rate can be calculated from the load side heating capacity and from the heating mode COP_h as follows:

m_dot_source = Q_load_side * (1 - 1/cop_h) / (cp_source * deltaT_source)

Alternatively:

m_dot_source = Q_source_side * / (cp_source * deltaT_source)

Where,

Q_source_side = Q_load_side * (1 - 1/COP_h)

Comment on lines +2877 to +2881
auto const &companionCoolingCoil =
state.dataWaterToAirHeatPumpSimple->SimpleWatertoAirHP(simpleWatertoAirHP.CompanionCoolingCoilNum);
RatedWaterVolFlowRateDes = max(RatedWaterVolFlowRateDes,
(1 + 1 / RatedCoolCOP) * companionCoolingCoil.RatedCapCoolTotal /
(state.dataSize->PlantSizData(PltSizNum).DeltaT * Cp * rho));
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Here we're dealing with the companion cooling coil so the evaporator is on the load side and the condenser is on the source side.

So if we start with Qc = Qe + P and because we're dealing with heating operation COP = Qe / P so Qc = Source Side Load = Qe + P = Qe (1 + 1 / COP) and Qe = companionCoolingCoil.RatedCapCoolTotal. So I think this is correct.

Then, we're taking the maximum of either the calculated heating coil evaporator flow rate or the cooling coil condenser flow rate.

Copy link
Contributor

Choose a reason for hiding this comment

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

We must be cautious about which COP value is used to relate the source-side and load-side heat transfer rates. In your equation, Qc = Qe + P = Qe (1 + 1/COP), the COP should be the cooling COP as shown below:

COP_c = Q_evap / P 
COP_h = Q_cond / P

So,

Q_cond = Q_evap + P = Q_evap * (1 + 1/COP_c)

Why do you have to take the maximum?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Right, cooling coil COP for the cooling coil calculations and heating coil COP for heating coil calculations.

If we have companion coils in the system (both water-to-air heating and cooling coils), we could end-up with different calculated water flow rates. Since we need only one value for the system, I assumed that we would want to keep the larger of the two. Do you have a suggestion?

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't see a problem taking the maximum flow as long as the flow rates are determined based on their respective design loads, design delta T, and CP values appropriate for cooling and heating loops. In this case, it is how you arrive at the Design Load that leads to different flow rates.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Also, the assumption here for the companion coil is that it has already been sized. You might want to check if RatedCapCoolTotal == DataSizing::AutoSize before this calculation?

@lymereJ lymereJ marked this pull request as draft April 3, 2025 19:14
@lymereJ lymereJ marked this pull request as ready for review April 4, 2025 20:12
if (simpleWatertoAirHP.WAHPType == WatertoAirHP::Heating) {
RatedWaterVolFlowRateDes = simpleWatertoAirHP.RatedCapHeat / (state.dataSize->PlantSizData(PltSizNum).DeltaT * Cp * rho);
RatedWaterVolFlowRateDes =
(1 - 1 / RatedHeatCOP) * simpleWatertoAirHP.RatedCapHeat / (state.dataSize->PlantSizData(PltSizNum).DeltaT * Cp * rho);
Copy link
Collaborator

Choose a reason for hiding this comment

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

I do not think this is correct. Since when does Q = M * Cp * deltaT include COP? You have a load and a plant delta T, from those you calculate mass flow rate. I think this equation was correct to begin with. Also for the equation below for the companion coil, don't use (1 + 1/COP) but do use the correct plant Delta T from the Sizing:Plant object for the cooling plant. I believe PltSizNum here is for the heating plant. @Nigusse ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

COP comes into play because as @Nigusse pointed out above, for the heating coil we have m_dot_source = Q_load_side * (1 - 1/cop_h) / (cp_source * deltaT_source). Where simpleWatertoAirHP.RatedCapHeat is the load side capacity.

These are water to air coils, so the plant loop associated with them should be a condenser plant loop, meaning that both the heating and cooling coil should be on the demand side of that plant loop. So unless I'm missing something, the design dT should be the same for both coils. One thing I could do, to be safe, is to get the sizing plant object for the companion coil and use it to determine the cooling coil water flow rate instead of using the same value for both. I'll make that change.

Copy link
Collaborator

Choose a reason for hiding this comment

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

If this is for source side sizing then this is fine. I see that RatedCapHeat is the air-side heating capacity on the load side. So these equations make sense for adjustment to the source side. Yes, use the correct Sizing:Plant information.

@github-actions
Copy link

github-actions bot commented Apr 4, 2025

⚠️ Regressions detected on macos-14 for commit 6b6e071

Regression Summary
  • EIO: 16
  • ERR: 14
  • MTR Big Diffs: 6
  • Table Big Diffs: 16
  • Table String Diffs: 11
  • ESO Small Diffs: 1
  • ESO Big Diffs: 13

@github-actions
Copy link

github-actions bot commented Apr 4, 2025

⚠️ Regressions detected on macos-14 for commit 83df71c

Regression Summary
  • EIO: 16
  • ERR: 14
  • MTR Big Diffs: 6
  • Table Big Diffs: 16
  • Table String Diffs: 11
  • ESO Small Diffs: 1
  • ESO Big Diffs: 13

@github-actions
Copy link

github-actions bot commented Apr 4, 2025

⚠️ Regressions detected on macos-14 for commit a7f16ee

Regression Summary
  • EIO: 16
  • ERR: 14
  • MTR Big Diffs: 6
  • Table Big Diffs: 16
  • Table String Diffs: 11
  • ESO Small Diffs: 1
  • ESO Big Diffs: 13

@rraustad
Copy link
Collaborator

rraustad commented Apr 9, 2025

The EngRef could use an update (pg 563 - 567):

10.7.7 Coil:Cooling:WaterToAirHeatPump:EquationFit Sizing
The sizing is done in subroutine SizeHVACWaterToAir.
10.7.7.1 Rated Air Flow Rate
The calculation is identical to that done for Coil:Cooling:Water.
10.7. COMPONENT SIZING
10.7.7.2 Rated Water Flow Rate
The calculation is identical to that done for Coil:Cooling:Water, which is the coil design load divided
by the Loop Design Temperature Difference user input from Sizing:Plant. If there is a companion
heating coil, the heating coil design load is used so that both modes will have the same rated water
flow rate. For sizing the plant loop serving this coil, only one half of this flow rate is used since
both the cooling and heating coil will save a flow rate but only one of these coils will operate at a
time.

10.7.9 Coil:Heating:WaterToAirHeatPump:EquationFit Sizing
The sizing is done in subroutine SizeHVACWaterToAir.
10.7.9.1 Rated Air Flow Rate
The calculation is identical to that done for Coil:Cooling:Water.
10.7.9.2 Rated Water Flow Rate
The calculation is identical to that done for Coil:Cooling:Water , which is the coil design load
divided by the Loop Design Temperature Difference user input from Sizing:Plant. For sizing the
plant loop serving this coil, only one half of this flow rate is used since both the cooling and heating
coil will save a flow rate but only one of these coils will operate at a time.

@github-actions
Copy link

⚠️ Regressions detected on macos-14 for commit 0b4a591

Regression Summary
  • EIO: 16
  • ERR: 14
  • MTR Big Diffs: 6
  • Table Big Diffs: 16
  • Table String Diffs: 11
  • ESO Small Diffs: 1
  • ESO Big Diffs: 13

@github-actions
Copy link

⚠️ Regressions detected on macos-14 for commit 0011518

Regression Summary
  • EIO: 16
  • ERR: 14
  • MTR Big Diffs: 6
  • Table Big Diffs: 16
  • Table String Diffs: 11
  • ESO Small Diffs: 1
  • ESO Big Diffs: 13

if (simpleWatertoAirHP.CompanionCoolingCoilNum > 0) {
auto const &companionCoolingCoil =
state.dataWaterToAirHeatPumpSimple->SimpleWatertoAirHP(simpleWatertoAirHP.CompanionCoolingCoilNum);
if (companionCoolingCoil.RatedCapCoolTotal != DataSizing::AutoSize) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

What happens if the companion cooling coil is hard-sized? There may not be a plant sizing object for the companion coil. And you couldn't then use the max of each if this coil's flow was less than that value. Not sure what to easily do about that. Up at line 2857 it's already determined that this coil's water flow rate is autosized so it's assumed that both flow rates are autosized? At the very least I think line 2890 should be protected with if (PltSizNumCompanionCoil > 0)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I assume that you mean that the companion cooling coil water flow rate is hard-sized by the user. If so, since we only need to have one value for the system, shouldn't we use the cooling coil water flow rate to not overwrite user inputs? If it is fine to overwrite user inputs we could perhaps take the maximum of the hard sized value and the value calculated for the heating coil, or, check if there's a plant loop sizing object and if so take the maximum of the three (heating coil value, hard-sized value, value determined using the dT of the plant loop).

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes, companion cooling coil is hard-sized and this coil is autosized. I did say I couldn't think of an easy way to fix this. 1) I don't think we should ever overwrite a user input, 2) what happens if a user hard-sizes both coils and those values are different?, are there any example files that are hard-sized and these values are different? does real equipment always use the same flow rates? 3) if you really do want the flow rates to be the same, you could just use the companion value but then you need to know if it was hard-sized. This could also lead to very low or high delta T on the water side. So there is no easy answer. So unless you can think of something robust, you might just go with if (PltSizNumCompanionCoil > 0) and wait for these other issues to actually cause a problem. I do think it would be VERY rare that one is hard-sized and the other is autosized. The work-around for a future issue would be to use the same method for both coils.

@github-actions
Copy link

github-actions bot commented May 9, 2025

⚠️ Regressions detected on macos-14 for commit d9a1f83

Regression Summary
  • EIO: 16
  • ERR: 14
  • MTR Big Diffs: 6
  • Table Big Diffs: 16
  • Table String Diffs: 13
  • ESO Big Diffs: 14

@github-actions
Copy link

github-actions bot commented May 9, 2025

⚠️ Regressions detected on macos-14 for commit 4b70fca

Regression Summary
  • EIO: 16
  • ERR: 14
  • MTR Big Diffs: 6
  • Table Big Diffs: 16
  • Table String Diffs: 11
  • ESO Small Diffs: 1
  • ESO Big Diffs: 13

@nrel-bot-2c
Copy link

@lymereJ @Myoldmopar it has been 34 days since this pull request was last updated.

@nrel-bot-2
Copy link

@lymereJ @Myoldmopar it has been 28 days since this pull request was last updated.

@nrel-bot-2
Copy link

@lymereJ @Myoldmopar it has been 42 days since this pull request was last updated.

@nrel-bot-2
Copy link

@lymereJ @Myoldmopar it has been 33 days since this pull request was last updated.

@mitchute
Copy link
Collaborator

Last call on this one. Test failures are unrelated to this.

@mitchute
Copy link
Collaborator

@lymereJ can you confirm the regression diffs are expected?

@github-actions
Copy link

⚠️ Regressions detected on macos-14 for commit dc59786

Regression Summary
  • EIO: 16
  • ERR: 14
  • Table Big Diffs: 16
  • Table String Diffs: 11
  • MTR Big Diffs: 6
  • ESO Small Diffs: 1
  • ESO Big Diffs: 13

@github-actions
Copy link

⚠️ Regressions detected on ubuntu-24.04 for commit dc59786

Regression Summary
  • EIO: 16
  • ERR: 14
  • Table Big Diffs: 16
  • Table String Diffs: 11
  • ESO Small Diffs: 1
  • ESO Big Diffs: 13
  • MTR Big Diffs: 6

@mitchute mitchute merged commit 62e55c9 into develop Sep 30, 2025
11 checks passed
@mitchute mitchute deleted the wahp_wtr_flow_calcs_fix branch February 24, 2026 17:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Defect Includes code to repair a defect in EnergyPlus

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants