Skip to content

Fix wshp array bounds error and sizing #10735

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Nov 8, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions src/EnergyPlus/UnitarySystem.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3153,7 +3153,7 @@ namespace UnitarySystems {
state.dataSize->DataFractionUsedForSizing = 1.0;
SizingMethod = HVAC::AutoCalculateSizing;
this->m_DesignHeatingCapacity = DataSizing::AutoSize;
if (this->m_CoolingCoilType_Num == HVAC::Coil_CoolingWaterToAirHPSimple)
if (this->m_CoolingCoilType_Num == HVAC::Coil_CoolingWaterToAirHPSimple) {
// adjusted cooling coil capacity
WaterToAirHeatPumpSimple::SimWatertoAirHPSimple(state,
blankString,
Expand All @@ -3164,9 +3164,10 @@ namespace UnitarySystems {
HVAC::CompressorOp::Off,
0.0,
FirstHVACIteration);
state.dataSize->DataConstantUsedForSizing = WaterToAirHeatPumpSimple::GetCoilCapacity(
state, HVAC::cAllCoilTypes(this->m_CoolingCoilType_Num), this->m_CoolingCoilName, ErrFound);
EqSizing.DesCoolingLoad = state.dataSize->DataConstantUsedForSizing;
state.dataSize->DataConstantUsedForSizing = WaterToAirHeatPumpSimple::GetCoilCapacity(
state, HVAC::cAllCoilTypes(this->m_CoolingCoilType_Num), this->m_CoolingCoilName, ErrFound);
EqSizing.DesCoolingLoad = state.dataSize->DataConstantUsedForSizing;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I just wrapped all this in 1 IF block. Still not sure if the code at the end of this block is needed.

Copy link
Contributor

Choose a reason for hiding this comment

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

The next step is to remove this IF block. There is no reason to call the cooling coil to report the UnitarySystem heating capacity. That's a cover up.

state.dataSize->DataFractionUsedForSizing = 1.0;
this->m_DesignCoolingCapacity = DataSizing::AutoSize;
// airflow sizing with multispeed fan
Expand Down
154 changes: 80 additions & 74 deletions src/EnergyPlus/WaterToAirHeatPumpSimple.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2580,86 +2580,92 @@ namespace WaterToAirHeatPumpSimple {

// determine adjusted cooling and heating coil capacity
simpleWatertoAirHP.RatedCapHeatAtRatedCdts = RatedCapHeatDes * RatedHeatCapTempModFac;
Copy link
Contributor

Choose a reason for hiding this comment

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

I believe what the code below is trying to do is to size a HP, so the coils would need to be the same size. In this case that's not necessary but an actual HP would need to be tested to make sure it works. I guess it does work since all WSHPs apparently size correctly, or do they?

auto &companionCoolingCoil(state.dataWaterToAirHeatPumpSimple->SimpleWatertoAirHP(simpleWatertoAirHP.CompanionCoolingCoilNum));
if (companionCoolingCoil.WAHPPlantType == DataPlant::PlantEquipmentType::CoilWAHPCoolingEquationFit &&
companionCoolingCoil.RatedCapCoolTotal == DataSizing::AutoSize) {
// case 1: companion coil is also of EquationFit type and is being autosized
RatedCapCoolTotalDes = state.dataSize->DXCoolCap;
RatedTotCapTempModFac = companionCoolingCoil.RatedCapCoolAtRatedCdts / RatedCapCoolTotalDes;
RatedCapCoolHeatDD =
simpleWatertoAirHP.RatedCapHeatAtRatedCdts / simpleWatertoAirHP.RatioRatedHeatRatedTotCoolCap / RatedTotCapTempModFac;
RatedCoolPowerTempModFac = companionCoolingCoil.RatedPowerCoolAtRatedCdts / companionCoolingCoil.RatedPowerCool;
if (RatedCapCoolHeatDD > RatedCapCoolTotalDes) {
// total cooling capacity
RatedCapCoolTotalDes = RatedCapCoolHeatDD;
// adjust for system air flow -- capacity is based on heating design day calcs
// adjust by ratio of system to heating air flow rate and temperature delta across the coil at these different airflow
if (HeatingAirVolFlowRateDes > 0) {
RatedCapCoolTotalDes *= (RatedAirVolFlowRateDes / HeatingAirVolFlowRateDes) * HeatdTratio;
if (simpleWatertoAirHP.CompanionCoolingCoilNum > 0) {
auto &companionCoolingCoil(state.dataWaterToAirHeatPumpSimple->SimpleWatertoAirHP(simpleWatertoAirHP.CompanionCoolingCoilNum));
if (companionCoolingCoil.WAHPPlantType == DataPlant::PlantEquipmentType::CoilWAHPCoolingEquationFit &&
companionCoolingCoil.RatedCapCoolTotal == DataSizing::AutoSize) {
// case 1: companion coil is also of EquationFit type and is being autosized
RatedCapCoolTotalDes = state.dataSize->DXCoolCap;
RatedTotCapTempModFac = companionCoolingCoil.RatedCapCoolAtRatedCdts / RatedCapCoolTotalDes;
RatedCapCoolHeatDD =
simpleWatertoAirHP.RatedCapHeatAtRatedCdts / simpleWatertoAirHP.RatioRatedHeatRatedTotCoolCap / RatedTotCapTempModFac;
RatedCoolPowerTempModFac = companionCoolingCoil.RatedPowerCoolAtRatedCdts / companionCoolingCoil.RatedPowerCool;
if (RatedCapCoolHeatDD > RatedCapCoolTotalDes) {
// total cooling capacity
RatedCapCoolTotalDes = RatedCapCoolHeatDD;
// adjust for system air flow -- capacity is based on heating design day calcs
// adjust by ratio of system to heating air flow rate and temperature delta across the coil at these different airflow
if (HeatingAirVolFlowRateDes > 0) {
RatedCapCoolTotalDes *= (RatedAirVolFlowRateDes / HeatingAirVolFlowRateDes) * HeatdTratio;
}
// calculate ajustment factor over previous capacity for sensible capacity adjustment
Real64 CapCoolAdjFac = RatedCapCoolTotalDes / state.dataSize->DXCoolCap;
// update cooling coil rated capacity after adjustments based on heating coil size
state.dataSize->DXCoolCap = RatedCapCoolTotalDes;
// sensible cooling capacity
RatedCapCoolSensDes = companionCoolingCoil.RatedCapCoolSens * CapCoolAdjFac; // Assume that SHR stays the same
companionCoolingCoil.RatedCapCoolSensDesAtRatedCdts *= CapCoolAdjFac;
companionCoolingCoil.RatedCapCoolSens = RatedCapCoolSensDes;
// update Water-to-Air Heat Pumps output reports
OutputReportPredefined::PreDefTableEntry(state,
state.dataOutRptPredefined->pdchWAHPRatedSensCapAtRatedCdts,
companionCoolingCoil.Name,
companionCoolingCoil.RatedCapCoolSensDesAtRatedCdts);
OutputReportPredefined::PreDefTableEntry(
state, state.dataOutRptPredefined->pdchWAHPDD, companionCoolingCoil.Name, "Heating");
OutputReportPredefined::PreDefTableEntry(
state, state.dataOutRptPredefined->pdchWAHPDD, simpleWatertoAirHP.Name, "Heating");
// update Cooling Coils output reports
OutputReportPredefined::PreDefTableEntry(state,
state.dataOutRptPredefined->pdchCoolCoilLatCap,
companionCoolingCoil.Name,
RatedCapCoolTotalDes - RatedCapCoolSensDes);
OutputReportPredefined::PreDefTableEntry(state,
state.dataOutRptPredefined->pdchCoolCoilSHR,
companionCoolingCoil.Name,
RatedCapCoolSensDes / RatedCapCoolTotalDes);
OutputReportPredefined::PreDefTableEntry(
state, state.dataOutRptPredefined->pdchCoolCoilSensCap, companionCoolingCoil.Name, RatedCapCoolSensDes);
} else {
OutputReportPredefined::PreDefTableEntry(
state, state.dataOutRptPredefined->pdchWAHPDD, companionCoolingCoil.Name, "Cooling");
OutputReportPredefined::PreDefTableEntry(
state, state.dataOutRptPredefined->pdchWAHPDD, simpleWatertoAirHP.Name, "Cooling");
}
// calculate ajustment factor over previous capacity for sensible capacity adjustment
Real64 CapCoolAdjFac = RatedCapCoolTotalDes / state.dataSize->DXCoolCap;
// update cooling coil rated capacity after adjustments based on heating coil size
state.dataSize->DXCoolCap = RatedCapCoolTotalDes;
// sensible cooling capacity
RatedCapCoolSensDes = companionCoolingCoil.RatedCapCoolSens * CapCoolAdjFac; // Assume that SHR stays the same
companionCoolingCoil.RatedCapCoolSensDesAtRatedCdts *= CapCoolAdjFac;
companionCoolingCoil.RatedCapCoolSens = RatedCapCoolSensDes;
RatedCapHeatDes =
RatedCapCoolTotalDes * RatedTotCapTempModFac * simpleWatertoAirHP.RatioRatedHeatRatedTotCoolCap / RatedHeatCapTempModFac;
companionCoolingCoil.RatedCapCoolTotal = RatedCapCoolTotalDes;
companionCoolingCoil.RatedCapCoolAtRatedCdts = RatedCapCoolTotalDes * RatedTotCapTempModFac;
companionCoolingCoil.RatedPowerCoolAtRatedCdts =
companionCoolingCoil.RatedCapCoolAtRatedCdts / companionCoolingCoil.RatedCOPCoolAtRatedCdts;
companionCoolingCoil.RatedPowerCool = companionCoolingCoil.RatedPowerCoolAtRatedCdts / RatedCoolPowerTempModFac;
// update Water-to-Air Heat Pumps output reports
OutputReportPredefined::PreDefTableEntry(state,
state.dataOutRptPredefined->pdchWAHPRatedSensCapAtRatedCdts,
state.dataOutRptPredefined->pdchWAHPRatedCapAtRatedCdts,
companionCoolingCoil.Name,
companionCoolingCoil.RatedCapCoolSensDesAtRatedCdts);
OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchWAHPDD, companionCoolingCoil.Name, "Heating");
OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchWAHPDD, simpleWatertoAirHP.Name, "Heating");
companionCoolingCoil.RatedCapCoolAtRatedCdts);
// update Cooling Coils output reports
OutputReportPredefined::PreDefTableEntry(state,
state.dataOutRptPredefined->pdchCoolCoilLatCap,
companionCoolingCoil.Name,
RatedCapCoolTotalDes - RatedCapCoolSensDes);
OutputReportPredefined::PreDefTableEntry(state,
state.dataOutRptPredefined->pdchCoolCoilSHR,
companionCoolingCoil.Name,
RatedCapCoolSensDes / RatedCapCoolTotalDes);
OutputReportPredefined::PreDefTableEntry(
state, state.dataOutRptPredefined->pdchCoolCoilSensCap, companionCoolingCoil.Name, RatedCapCoolSensDes);
} else {
OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchWAHPDD, companionCoolingCoil.Name, "Cooling");
OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchWAHPDD, simpleWatertoAirHP.Name, "Cooling");
state, state.dataOutRptPredefined->pdchCoolCoilTotCap, companionCoolingCoil.Name, RatedCapCoolTotalDes);
BaseSizer::reportSizerOutput(
state,
format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", WatertoAirHPNamesUC[static_cast<int>(companionCoolingCoil.WAHPType)]),
companionCoolingCoil.Name,
"Design Size Rated Total Cooling Capacity [W]",
companionCoolingCoil.RatedCapCoolTotal);
BaseSizer::reportSizerOutput(
state,
format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", WatertoAirHPNamesUC[static_cast<int>(companionCoolingCoil.WAHPType)]),
companionCoolingCoil.Name,
"Design Size Rated Sensible Cooling Capacity [W]",
companionCoolingCoil.RatedCapCoolSens);
} else if (companionCoolingCoil.WAHPPlantType ==
DataPlant::PlantEquipmentType::CoilWAHPCoolingEquationFit) { // case 2: companion coil is of EquationFit type but is
// not autosized
RatedCapHeatDes = companionCoolingCoil.RatedCapCoolTotal * simpleWatertoAirHP.RatioRatedHeatRatedTotCoolCap;
} else { // case 3: companion type is different than EquationFit
RatedCapHeatDes = state.dataSize->DXCoolCap;
}
RatedCapHeatDes =
RatedCapCoolTotalDes * RatedTotCapTempModFac * simpleWatertoAirHP.RatioRatedHeatRatedTotCoolCap / RatedHeatCapTempModFac;
companionCoolingCoil.RatedCapCoolTotal = RatedCapCoolTotalDes;
companionCoolingCoil.RatedCapCoolAtRatedCdts = RatedCapCoolTotalDes * RatedTotCapTempModFac;
companionCoolingCoil.RatedPowerCoolAtRatedCdts =
companionCoolingCoil.RatedCapCoolAtRatedCdts / companionCoolingCoil.RatedCOPCoolAtRatedCdts;
companionCoolingCoil.RatedPowerCool = companionCoolingCoil.RatedPowerCoolAtRatedCdts / RatedCoolPowerTempModFac;
// update Water-to-Air Heat Pumps output reports
OutputReportPredefined::PreDefTableEntry(state,
state.dataOutRptPredefined->pdchWAHPRatedCapAtRatedCdts,
companionCoolingCoil.Name,
companionCoolingCoil.RatedCapCoolAtRatedCdts);
// update Cooling Coils output reports
OutputReportPredefined::PreDefTableEntry(
state, state.dataOutRptPredefined->pdchCoolCoilTotCap, companionCoolingCoil.Name, RatedCapCoolTotalDes);
BaseSizer::reportSizerOutput(
state,
format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", WatertoAirHPNamesUC[static_cast<int>(companionCoolingCoil.WAHPType)]),
companionCoolingCoil.Name,
"Design Size Rated Total Cooling Capacity [W]",
companionCoolingCoil.RatedCapCoolTotal);
BaseSizer::reportSizerOutput(
state,
format("COIL:{}:WATERTOAIRHEATPUMP:EQUATIONFIT", WatertoAirHPNamesUC[static_cast<int>(companionCoolingCoil.WAHPType)]),
companionCoolingCoil.Name,
"Design Size Rated Sensible Cooling Capacity [W]",
companionCoolingCoil.RatedCapCoolSens);
} else if (companionCoolingCoil.WAHPPlantType ==
DataPlant::PlantEquipmentType::CoilWAHPCoolingEquationFit) { // case 2: companion coil is of EquationFit type but is
// not autosized
RatedCapHeatDes = companionCoolingCoil.RatedCapCoolTotal * simpleWatertoAirHP.RatioRatedHeatRatedTotCoolCap;
} else { // case 3: companion type is different than EquationFit
RatedCapHeatDes = state.dataSize->DXCoolCap;
}
// heating capacity final determination
simpleWatertoAirHP.RatedCapHeat = RatedCapHeatDes;
Expand Down Expand Up @@ -2734,7 +2740,7 @@ namespace WaterToAirHeatPumpSimple {

// user provided inputs are assumed to be at rated conditions
simpleWatertoAirHP.RatedPowerHeat = simpleWatertoAirHP.RatedCapHeat / simpleWatertoAirHP.RatedCOPHeatAtRatedCdts;
simpleWatertoAirHP.RatedCapHeatAtRatedCdts = 0;
simpleWatertoAirHP.RatedCapHeatAtRatedCdts = simpleWatertoAirHP.RatedCapHeat;
Copy link
Contributor

@rraustad rraustad Sep 19, 2024

Choose a reason for hiding this comment

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

Why would the rated capacity sizing variable be set to 0 if not autosized? And what about rated power below? and check the cooling coil code.

Real64 RatedCapHeatAtRatedCdts = 0.0;        // Rated Heating Capacity at Rated Conditions [W]

Copy link
Contributor

Choose a reason for hiding this comment

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

I guess I could have changed the water flow rate sizing to use RatedCapHeat instead.

if (simpleWatertoAirHP.WAHPType == WatertoAirHP::Heating) {
    RatedWaterVolFlowRateDes =
        simpleWatertoAirHP.RatedCapHeatAtRatedCdts / (state.dataSize->PlantSizData(PltSizNum).DeltaT * Cp * rho);

Copy link
Contributor

@rraustad rraustad Sep 19, 2024

Choose a reason for hiding this comment

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

There is likely a difference between RatedCapHeat and RatedCapHeatAtRatedCdts given the CapFT term applied. This is above at line 2743.

            simpleWatertoAirHP.RatedCapHeat = RatedCapHeatDes;
            simpleWatertoAirHP.RatedCapHeatAtRatedCdts = RatedCapHeatDes * RatedHeatCapTempModFac;

Copy link
Contributor

@rraustad rraustad Sep 19, 2024

Choose a reason for hiding this comment

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

I think these equations need to be moved up into the IF blocks in order to use the correct variable. If RatedCapHeat is the coil load and RatedCapHeatatRatedCdts is the coil size, when autosized, then declaring these variables AFTER the coil size is determined seems wrong (i.e., after the if/else). If autosized, RatedCapHeatatRatedCdts should be used as the capacity, if not autosized, RatedCapHeat should be used as the capacity.

Copy link
Contributor

@rraustad rraustad Sep 20, 2024

Choose a reason for hiding this comment

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

I actually want to revert this change and change the RatedWaterVolFlowRateDes sizing equation to use RatedCapHeat because that's what the sizing routine is setting as the final coil capacity. And the calc routine uses RatedCapHeat as the coil capacity. So RatedCapHeat should be the final coil size whether the coil is autosized or hard-sized.

HeatCapAtPeak = rhoair * VolFlowRate * Psychrometrics::PsyCpAirFnW(DataPrecisionGlobals::constant_zero) *
                (HeatSupTemp - HeatMixTemp); // heating coil load

RatedCapHeatDes = (PeakHeatCapTempModFac > 0.0) ? HeatCapAtPeak / PeakHeatCapTempModFac : HeatCapAtPeak;

// heating capacity final determination
simpleWatertoAirHP.RatedCapHeat = RatedCapHeatDes;
simpleWatertoAirHP.RatedCapHeatAtRatedCdts = RatedCapHeatDes * RatedHeatCapTempModFac;

void CalcHPHeatingSimple(EnergyPlusData &state,
    HeatCapRated = simpleWatertoAirHP.RatedCapHeat;

So it follows that the water flow rate should use RatedHeatCap because that's the coil size. You can't see an issue in model performance when the water flow rate is sized with either of these variables because only exit water temp changes, not performance. You would have to really critique the exiting water temp to see an issue and even then it would be hard to see.

if (simpleWatertoAirHP.WAHPType == WatertoAirHP::Heating) {
    RatedWaterVolFlowRateDes = 
        simpleWatertoAirHP.RatedCapHeatAtRatedCdts / (state.dataSize->PlantSizData(PltSizNum).DeltaT * Cp * rho);

And then I look at this line and it looks like RatedCapHeatAtRatedCdts is the correct variable to use to size the water flow rate. So I will leave this branch in this state for now even though I think it's wrong.

RatedHeatCapTempModFac =
    Curve::CurveValue(state, simpleWatertoAirHP.HeatCapCurveIndex, RatedHeatratioTDB, RatedHeatratioTS, 1.0, 1.0);

Copy link
Contributor

Choose a reason for hiding this comment

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

RatedCapHeatDes is the CapFT modified coil capacity, as is RatedCapHeat. The next line modifies this value by the rated CapFT, which should be 1 by definition (but I expect it's not 1). So now I'm back to using RatedCapHeat to size the water flow rate. This is so very confusing but I think I am more comfortable with this now. @mjwitte ?

simpleWatertoAirHP.RatedCapHeatAtRatedCdts = RatedCapHeatDes * RatedHeatCapTempModFac;

simpleWatertoAirHP.RatedPowerHeatAtRatedCdts = 0;
}
// Check that heat pump heating capacity is within 20% of cooling capacity. Check only for heating coil and report both.
Expand Down