From c95600bd4f2492445d4d773e440424fb9f381d29 Mon Sep 17 00:00:00 2001 From: Rick Strand Date: Fri, 9 Aug 2024 13:05:21 -0500 Subject: [PATCH 1/6] 10634 Fix of Condenser Operation Issue This commit includes the fix to the problem for both condensers operating even when the operation scheme said that one of them should not be operating. It fixes this for all of the cooling tower models that were not set up to look at this. Results now should that the towers are operating when they are supposed to. --- src/EnergyPlus/CondenserLoopTowers.cc | 68 ++++++++++++------- src/EnergyPlus/CondenserLoopTowers.hh | 8 ++- .../unit/CondenserLoopTowers.unit.cc | 12 ++-- 3 files changed, 54 insertions(+), 34 deletions(-) diff --git a/src/EnergyPlus/CondenserLoopTowers.cc b/src/EnergyPlus/CondenserLoopTowers.cc index dfd6f8f7b5b..8460b789753 100644 --- a/src/EnergyPlus/CondenserLoopTowers.cc +++ b/src/EnergyPlus/CondenserLoopTowers.cc @@ -137,13 +137,13 @@ namespace CondenserLoopTowers { this->initialize(state); switch (this->TowerType) { case DataPlant::PlantEquipmentType::CoolingTower_SingleSpd: - this->calculateSingleSpeedTower(state); + this->calculateSingleSpeedTower(state, CurLoad); break; case DataPlant::PlantEquipmentType::CoolingTower_TwoSpd: - this->calculateTwoSpeedTower(state); + this->calculateTwoSpeedTower(state, CurLoad); break; case DataPlant::PlantEquipmentType::CoolingTower_VarSpd: - this->calculateVariableSpeedTower(state); + this->calculateVariableSpeedTower(state, CurLoad); break; case DataPlant::PlantEquipmentType::CoolingTower_VarSpdMerkel: this->calculateMerkelVariableSpeedTower(state, CurLoad); @@ -4535,7 +4535,7 @@ namespace CondenserLoopTowers { } } // namespace CondenserLoopTowers - void CoolingTower::calculateSingleSpeedTower(EnergyPlusData &state) + void CoolingTower::calculateSingleSpeedTower(EnergyPlusData &state, Real64 &MyLoad) { // SUBROUTINE INFORMATION: @@ -4695,13 +4695,9 @@ namespace CondenserLoopTowers { // Do not RETURN here if flow rate is less than SmallMassFlow. Check basin heater and then RETURN. - // MassFlowTolerance is a parameter to indicate a no flow condition - if (this->WaterMassFlowRate <= DataBranchAirLoopPlant::MassFlowTolerance) { - // for multiple cells, we assume that it's a common basin - CalcBasinHeaterPower( - state, this->BasinHeaterPowerFTempDiff, this->BasinHeaterSchedulePtr, this->BasinHeaterSetPointTemp, this->BasinHeaterPower); - return; - } + bool returnFlagSet; + this->checkMassFlowAndLoad(state, MyLoad, returnFlagSet); + if (returnFlagSet) return; bool IncrNumCellFlag = true; // determine if yes or no we increase the number of cells // set value to true to enter in the loop @@ -4847,7 +4843,7 @@ namespace CondenserLoopTowers { this->airFlowRateRatio = (AirFlowRate * this->NumCell) / this->HighSpeedAirFlowRate; } - void CoolingTower::calculateTwoSpeedTower(EnergyPlusData &state) + void CoolingTower::calculateTwoSpeedTower(EnergyPlusData &state, Real64 &MyLoad) { // SUBROUTINE INFORMATION: @@ -4974,12 +4970,9 @@ namespace CondenserLoopTowers { // Do not RETURN here if flow rate is less than SmallMassFlow. Check basin heater and then RETURN. if (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopSide(this->plantLoc.loopSideNum).FlowLock == DataPlant::FlowLock::Unlocked) return; // TODO: WTF - // MassFlowTolerance is a parameter to indicate a no flow condition - if (this->WaterMassFlowRate <= DataBranchAirLoopPlant::MassFlowTolerance) { - CalcBasinHeaterPower( - state, this->BasinHeaterPowerFTempDiff, this->BasinHeaterSchedulePtr, this->BasinHeaterSetPointTemp, this->BasinHeaterPower); - return; - } + bool returnFlagSet; + this->checkMassFlowAndLoad(state, MyLoad, returnFlagSet); + if (returnFlagSet) return; // Added for multi-cell. Determine the number of cells operating Real64 WaterMassFlowRatePerCellMin = 0.0; @@ -5089,7 +5082,7 @@ namespace CondenserLoopTowers { this->airFlowRateRatio = (AirFlowRate * this->NumCell) / this->HighSpeedAirFlowRate; } - void CoolingTower::calculateVariableSpeedTower(EnergyPlusData &state) + void CoolingTower::calculateVariableSpeedTower(EnergyPlusData &state, Real64 &MyLoad) { // SUBROUTINE INFORMATION: @@ -5209,12 +5202,10 @@ namespace CondenserLoopTowers { // Do not RETURN here if flow rate is less than MassFlowTolerance. Check basin heater and then RETURN. if (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopSide(this->plantLoc.loopSideNum).FlowLock == DataPlant::FlowLock::Unlocked) return; // TODO: WTF - // MassFlowTolerance is a parameter to indicate a no flow condition - if (this->WaterMassFlowRate <= DataBranchAirLoopPlant::MassFlowTolerance) { - CalcBasinHeaterPower( - state, this->BasinHeaterPowerFTempDiff, this->BasinHeaterSchedulePtr, this->BasinHeaterSetPointTemp, this->BasinHeaterPower); - return; - } + + bool returnFlagSet; + this->checkMassFlowAndLoad(state, MyLoad, returnFlagSet); + if (returnFlagSet) return; // loop to increment NumCell if we cannot meet the setpoint with the actual number of cells calculated above bool IncrNumCellFlag = true; @@ -5512,9 +5503,10 @@ namespace CondenserLoopTowers { } WaterMassFlowRatePerCell = this->WaterMassFlowRate / this->NumCellOn; + // MassFlowTolerance is a parameter to indicate a no flow condition if (this->WaterMassFlowRate <= DataBranchAirLoopPlant::MassFlowTolerance || (MyLoad > HVAC::SmallLoad)) { - // for multiple cells, we assume that it's a common bassin + // for multiple cells, we assume that it's a common basin CalcBasinHeaterPower( state, this->BasinHeaterPowerFTempDiff, this->BasinHeaterSchedulePtr, this->BasinHeaterSetPointTemp, this->BasinHeaterPower); return; @@ -6463,6 +6455,30 @@ namespace CondenserLoopTowers { } } + void CoolingTower::checkMassFlowAndLoad(EnergyPlusData &state, Real64 const MyLoad, bool &returnFlagSet) + { + returnFlagSet = false; + // MassFlowTolerance is a parameter to indicate a no flow condition + if (this->WaterMassFlowRate <= DataBranchAirLoopPlant::MassFlowTolerance) { + // for multiple cells, we assume that it's a common basin + CalcBasinHeaterPower( + state, this->BasinHeaterPowerFTempDiff, this->BasinHeaterSchedulePtr, this->BasinHeaterSetPointTemp, this->BasinHeaterPower); + returnFlagSet = true; + } + + // Also check to see if the tower is not running (zero MyLoad) + if (std::abs(MyLoad) <= HVAC::SmallLoad) { + // tower doesn't need to do anything + this->OutletWaterTemp = state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp; + this->FanPower = 0.0; + this->airFlowRateRatio = 0.0; + this->Qactual = 0.0; + CalcBasinHeaterPower( + state, this->BasinHeaterPowerFTempDiff, this->BasinHeaterSchedulePtr, this->BasinHeaterSetPointTemp, this->BasinHeaterPower); + returnFlagSet = true; + } + } + } // namespace CondenserLoopTowers } // namespace EnergyPlus diff --git a/src/EnergyPlus/CondenserLoopTowers.hh b/src/EnergyPlus/CondenserLoopTowers.hh index d1f128674ce..ef2da0f931a 100644 --- a/src/EnergyPlus/CondenserLoopTowers.hh +++ b/src/EnergyPlus/CondenserLoopTowers.hh @@ -387,13 +387,13 @@ namespace CondenserLoopTowers { void SizeVSMerkelTower(EnergyPlusData &state); - void calculateSingleSpeedTower(EnergyPlusData &state); + void calculateSingleSpeedTower(EnergyPlusData &state, Real64 &MyLoad); - void calculateTwoSpeedTower(EnergyPlusData &state); + void calculateTwoSpeedTower(EnergyPlusData &state, Real64 &MyLoad); void calculateMerkelVariableSpeedTower(EnergyPlusData &state, Real64 &MyLoad); - void calculateVariableSpeedTower(EnergyPlusData &state); + void calculateVariableSpeedTower(EnergyPlusData &state, Real64 &MyLoad); Real64 calculateSimpleTowerOutletTemp(EnergyPlusData &state, Real64 waterMassFlowRate, Real64 AirFlowRate, Real64 UAdesign); @@ -427,6 +427,8 @@ namespace CondenserLoopTowers { void report(EnergyPlusData &state, bool RunFlag); + void checkMassFlowAndLoad(EnergyPlusData &state, Real64 MyLoad, bool &returnFlagSet); + static CoolingTower *factory(EnergyPlusData &state, std::string_view objectName); }; diff --git a/tst/EnergyPlus/unit/CondenserLoopTowers.unit.cc b/tst/EnergyPlus/unit/CondenserLoopTowers.unit.cc index 99aac875025..76b9fc1f407 100644 --- a/tst/EnergyPlus/unit/CondenserLoopTowers.unit.cc +++ b/tst/EnergyPlus/unit/CondenserLoopTowers.unit.cc @@ -904,10 +904,11 @@ TEST_F(EnergyPlusFixture, CondenserLoopTowers_SingleSpeedSizing) SimulationManager::SetupSimulation(*state, ErrorsFound); CondenserLoopTowers::GetTowerInput(*state); + Real64 MyLoad = 0.0; state->dataCondenserLoopTowers->towers(1).initialize(*state); state->dataCondenserLoopTowers->towers(1).SizeTower(*state); state->dataCondenserLoopTowers->towers(1).initialize(*state); - state->dataCondenserLoopTowers->towers(1).calculateSingleSpeedTower(*state); + state->dataCondenserLoopTowers->towers(1).calculateSingleSpeedTower(*state, MyLoad); state->dataCondenserLoopTowers->towers(1).update(*state); state->dataCondenserLoopTowers->towers(1).report(*state, true); @@ -927,8 +928,8 @@ TEST_F(EnergyPlusFixture, CondenserLoopTowers_SingleSpeedSizing) outletNodeIndex = std::distance(state->dataLoopNodes->NodeID.begin(), outletNode); } // TODO: FIXME: This is failing. Actual is -10.409381032746095, expected is 30. - EXPECT_GT(state->dataLoopNodes->Node(inletNodeIndex).Temp, 30.0); // inlet node temperature - EXPECT_DOUBLE_EQ(30.0, state->dataLoopNodes->Node(outletNodeIndex).Temp); // outlet node temperature + EXPECT_GT(state->dataLoopNodes->Node(inletNodeIndex).Temp, 30.0); // inlet node temperature + EXPECT_DOUBLE_EQ(state->dataLoopNodes->Node(inletNodeIndex).Temp, state->dataLoopNodes->Node(outletNodeIndex).Temp); // outlet node temperature // input not needed for sizing (WasAutoSized = false) using NominalCapacity method but this variable should still size EXPECT_FALSE(state->dataCondenserLoopTowers->towers(1).HighSpeedTowerUAWasAutoSized); @@ -3967,7 +3968,8 @@ TEST_F(EnergyPlusFixture, VSCoolingTowers_WaterOutletTempTest) state->dataPlnt->PlantLoop(VSTower.plantLoc.loopNum).LoopSide(VSTower.plantLoc.loopSideNum).TempSetPoint = 30.0; VSTower.WaterMassFlowRate = VSTower.DesWaterMassFlowRate * WaterFlowRateRatio; - VSTower.calculateVariableSpeedTower(*state); + Real64 myLoad = 1000.0; + VSTower.calculateVariableSpeedTower(*state, myLoad); EXPECT_DOUBLE_EQ(30.0, VSTower.OutletWaterTemp); EXPECT_DOUBLE_EQ(1.0, VSTower.FanCyclingRatio); Real64 TowerOutletWaterTemp = VSTower.calculateVariableTowerOutletTemp(*state, WaterFlowRateRatio, VSTower.airFlowRateRatio, AirWetBulbTemp); @@ -3985,7 +3987,7 @@ TEST_F(EnergyPlusFixture, VSCoolingTowers_WaterOutletTempTest) VSTower.AirWetBulb = state->dataEnvrn->OutWetBulbTemp; VSTower.AirHumRat = state->dataEnvrn->OutHumRat; - VSTower.calculateVariableSpeedTower(*state); + VSTower.calculateVariableSpeedTower(*state, myLoad); EXPECT_DOUBLE_EQ(30.0, VSTower.OutletWaterTemp); EXPECT_NEAR(0.5424, VSTower.FanCyclingRatio, 0.0001); // outside air condition is favorable that fan only needs to cycle at min flow to meet the setpoint From 8f7c5de3d1741aae708a732fbe3ccba4f39af3af Mon Sep 17 00:00:00 2001 From: Rick Strand Date: Fri, 9 Aug 2024 13:35:38 -0500 Subject: [PATCH 2/6] 10634 Address Custom Check Error Something about the logical flag wasn't what the custom check wanted. This is an attempt to fix that. --- src/EnergyPlus/CondenserLoopTowers.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/EnergyPlus/CondenserLoopTowers.cc b/src/EnergyPlus/CondenserLoopTowers.cc index 8460b789753..ad8a019c43a 100644 --- a/src/EnergyPlus/CondenserLoopTowers.cc +++ b/src/EnergyPlus/CondenserLoopTowers.cc @@ -4695,7 +4695,7 @@ namespace CondenserLoopTowers { // Do not RETURN here if flow rate is less than SmallMassFlow. Check basin heater and then RETURN. - bool returnFlagSet; + bool returnFlagSet = false; this->checkMassFlowAndLoad(state, MyLoad, returnFlagSet); if (returnFlagSet) return; @@ -4970,7 +4970,7 @@ namespace CondenserLoopTowers { // Do not RETURN here if flow rate is less than SmallMassFlow. Check basin heater and then RETURN. if (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopSide(this->plantLoc.loopSideNum).FlowLock == DataPlant::FlowLock::Unlocked) return; // TODO: WTF - bool returnFlagSet; + bool returnFlagSet = false; this->checkMassFlowAndLoad(state, MyLoad, returnFlagSet); if (returnFlagSet) return; @@ -5203,7 +5203,7 @@ namespace CondenserLoopTowers { if (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopSide(this->plantLoc.loopSideNum).FlowLock == DataPlant::FlowLock::Unlocked) return; // TODO: WTF - bool returnFlagSet; + bool returnFlagSet = false; this->checkMassFlowAndLoad(state, MyLoad, returnFlagSet); if (returnFlagSet) return; @@ -6457,7 +6457,6 @@ namespace CondenserLoopTowers { void CoolingTower::checkMassFlowAndLoad(EnergyPlusData &state, Real64 const MyLoad, bool &returnFlagSet) { - returnFlagSet = false; // MassFlowTolerance is a parameter to indicate a no flow condition if (this->WaterMassFlowRate <= DataBranchAirLoopPlant::MassFlowTolerance) { // for multiple cells, we assume that it's a common basin From 712f23f9fc6f6eb39a32cad75f2eb04264bcca5e Mon Sep 17 00:00:00 2001 From: Rick Strand Date: Fri, 9 Aug 2024 15:02:26 -0500 Subject: [PATCH 3/6] 10634 Addition of Unit Test Unit test was added to exercise the new subroutine that is being used to allow condensers to factor in condenser loop operation schemes. --- .../unit/CondenserLoopTowers.unit.cc | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/tst/EnergyPlus/unit/CondenserLoopTowers.unit.cc b/tst/EnergyPlus/unit/CondenserLoopTowers.unit.cc index 76b9fc1f407..bb6f354a6f6 100644 --- a/tst/EnergyPlus/unit/CondenserLoopTowers.unit.cc +++ b/tst/EnergyPlus/unit/CondenserLoopTowers.unit.cc @@ -4307,4 +4307,69 @@ TEST_F(EnergyPlusFixture, CondenserLoopTowers_CalculateVariableTowerOutletTemp) EXPECT_NEAR(tower.WaterTemp - 22.2222, tOutlet, 0.01); } +TEST_F(EnergyPlusFixture, CondenserLoopTowers_checkMassFlowAndLoadTest) +{ + bool flagToReturn; + Real64 myLoad; + Real64 constexpr allowedTolerance = 0.0001; + Real64 expectedPower; + Real64 expectedTemp; + + state->dataCondenserLoopTowers->towers.allocate(1); + auto &tower = state->dataCondenserLoopTowers->towers(1); + state->dataLoopNodes->Node.allocate(1); + tower.WaterInletNodeNum = 1; + + // Test 1: Mass flow rate is low but myLoad is ok--flag should be set to true + flagToReturn = false; + myLoad = 1000.0; + state->dataEnvrn->OutDryBulbTemp = 27.0; + tower.WaterMassFlowRate = 0.0; + tower.BasinHeaterPowerFTempDiff = 1.0; + tower.BasinHeaterSchedulePtr = 0; + tower.BasinHeaterSetPointTemp = 26.0; + tower.BasinHeaterPower = 1.0; + expectedPower = 0.0; + tower.checkMassFlowAndLoad(*state, myLoad, flagToReturn); + EXPECT_TRUE(flagToReturn); + EXPECT_NEAR(expectedPower, tower.BasinHeaterPower, allowedTolerance); + + // Test 2: Mass flow rate is ok but myLoad is zero--flag should be set to true + flagToReturn = false; + myLoad = 0.0; + state->dataEnvrn->OutDryBulbTemp = 27.0; + tower.WaterMassFlowRate = 0.5; + tower.BasinHeaterPowerFTempDiff = 1.0; + tower.BasinHeaterSchedulePtr = 0; + tower.BasinHeaterSetPointTemp = 25.0; + tower.BasinHeaterPower = 2.0; + tower.FanPower = 1.0; + tower.airFlowRateRatio = 1.0; + tower.Qactual = 1.0; + expectedPower = 0.0; + expectedTemp = 23.0; + state->dataLoopNodes->Node(tower.WaterInletNodeNum).Temp = 23.0; + tower.checkMassFlowAndLoad(*state, myLoad, flagToReturn); + EXPECT_TRUE(flagToReturn); + EXPECT_NEAR(expectedPower, tower.BasinHeaterPower, allowedTolerance); + EXPECT_NEAR(expectedTemp, tower.OutletWaterTemp, allowedTolerance); + EXPECT_NEAR(0.0, tower.FanPower, allowedTolerance); + EXPECT_NEAR(0.0, tower.airFlowRateRatio, allowedTolerance); + EXPECT_NEAR(0.0, tower.Qactual, allowedTolerance); + + // Test 3: Mass flow rate and myLoad are both ok--nothing changes, power does not get calculated here + flagToReturn = false; + myLoad = 1000.0; + state->dataEnvrn->OutDryBulbTemp = 27.0; + tower.WaterMassFlowRate = 0.5; + tower.BasinHeaterPowerFTempDiff = 1.0; + tower.BasinHeaterSchedulePtr = 0; + tower.BasinHeaterSetPointTemp = 25.0; + tower.BasinHeaterPower = 3.0; + expectedPower = 3.0; + tower.checkMassFlowAndLoad(*state, myLoad, flagToReturn); + EXPECT_FALSE(flagToReturn); + EXPECT_NEAR(expectedPower, tower.BasinHeaterPower, allowedTolerance); +} + } // namespace EnergyPlus From eb0559cfae2b87e10cebd141c73c0f7549eb2ee7 Mon Sep 17 00:00:00 2001 From: Rick Strand Date: Fri, 9 Aug 2024 17:17:23 -0500 Subject: [PATCH 4/6] 10634 Mass Flow to Zero Corrected an issue with the fix where the mass flow rate when the load was zero was still positive in the defect idf when it should be zero. This is now corrected. --- src/EnergyPlus/CondenserLoopTowers.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/EnergyPlus/CondenserLoopTowers.cc b/src/EnergyPlus/CondenserLoopTowers.cc index ad8a019c43a..642f21bf2e9 100644 --- a/src/EnergyPlus/CondenserLoopTowers.cc +++ b/src/EnergyPlus/CondenserLoopTowers.cc @@ -6469,6 +6469,7 @@ namespace CondenserLoopTowers { if (std::abs(MyLoad) <= HVAC::SmallLoad) { // tower doesn't need to do anything this->OutletWaterTemp = state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp; + this->WaterMassFlowRate = 0.0; this->FanPower = 0.0; this->airFlowRateRatio = 0.0; this->Qactual = 0.0; From 92134b5847814dfa0a98eced09e047e673c03f3c Mon Sep 17 00:00:00 2001 From: Rick Strand Date: Tue, 13 Aug 2024 14:24:37 -0500 Subject: [PATCH 5/6] 10634 Addresses Review Comments Various review comments were received. These were all addressed in this commit. --- src/EnergyPlus/CondenserLoopTowers.cc | 58 +++++++++---------- src/EnergyPlus/CondenserLoopTowers.hh | 10 ++-- .../unit/CondenserLoopTowers.unit.cc | 38 ++++++++---- 3 files changed, 57 insertions(+), 49 deletions(-) diff --git a/src/EnergyPlus/CondenserLoopTowers.cc b/src/EnergyPlus/CondenserLoopTowers.cc index 642f21bf2e9..f365bd4e722 100644 --- a/src/EnergyPlus/CondenserLoopTowers.cc +++ b/src/EnergyPlus/CondenserLoopTowers.cc @@ -137,16 +137,16 @@ namespace CondenserLoopTowers { this->initialize(state); switch (this->TowerType) { case DataPlant::PlantEquipmentType::CoolingTower_SingleSpd: - this->calculateSingleSpeedTower(state, CurLoad); + this->calculateSingleSpeedTower(state, CurLoad, RunFlag); break; case DataPlant::PlantEquipmentType::CoolingTower_TwoSpd: - this->calculateTwoSpeedTower(state, CurLoad); + this->calculateTwoSpeedTower(state, CurLoad, RunFlag); break; case DataPlant::PlantEquipmentType::CoolingTower_VarSpd: - this->calculateVariableSpeedTower(state, CurLoad); + this->calculateVariableSpeedTower(state, CurLoad, RunFlag); break; case DataPlant::PlantEquipmentType::CoolingTower_VarSpdMerkel: - this->calculateMerkelVariableSpeedTower(state, CurLoad); + this->calculateMerkelVariableSpeedTower(state, CurLoad, RunFlag); break; default: ShowFatalError(state, format("Plant Equipment Type specified for {} is not a Cooling Tower.", this->Name)); @@ -4535,7 +4535,7 @@ namespace CondenserLoopTowers { } } // namespace CondenserLoopTowers - void CoolingTower::calculateSingleSpeedTower(EnergyPlusData &state, Real64 &MyLoad) + void CoolingTower::calculateSingleSpeedTower(EnergyPlusData &state, Real64 &MyLoad, bool RunFlag) { // SUBROUTINE INFORMATION: @@ -4696,7 +4696,7 @@ namespace CondenserLoopTowers { // Do not RETURN here if flow rate is less than SmallMassFlow. Check basin heater and then RETURN. bool returnFlagSet = false; - this->checkMassFlowAndLoad(state, MyLoad, returnFlagSet); + this->checkMassFlowAndLoad(state, MyLoad, RunFlag, returnFlagSet); if (returnFlagSet) return; bool IncrNumCellFlag = true; // determine if yes or no we increase the number of cells // set value to true to enter in the loop @@ -4843,7 +4843,7 @@ namespace CondenserLoopTowers { this->airFlowRateRatio = (AirFlowRate * this->NumCell) / this->HighSpeedAirFlowRate; } - void CoolingTower::calculateTwoSpeedTower(EnergyPlusData &state, Real64 &MyLoad) + void CoolingTower::calculateTwoSpeedTower(EnergyPlusData &state, Real64 &MyLoad, bool RunFlag) { // SUBROUTINE INFORMATION: @@ -4971,7 +4971,7 @@ namespace CondenserLoopTowers { if (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopSide(this->plantLoc.loopSideNum).FlowLock == DataPlant::FlowLock::Unlocked) return; // TODO: WTF bool returnFlagSet = false; - this->checkMassFlowAndLoad(state, MyLoad, returnFlagSet); + this->checkMassFlowAndLoad(state, MyLoad, RunFlag, returnFlagSet); if (returnFlagSet) return; // Added for multi-cell. Determine the number of cells operating @@ -5082,7 +5082,7 @@ namespace CondenserLoopTowers { this->airFlowRateRatio = (AirFlowRate * this->NumCell) / this->HighSpeedAirFlowRate; } - void CoolingTower::calculateVariableSpeedTower(EnergyPlusData &state, Real64 &MyLoad) + void CoolingTower::calculateVariableSpeedTower(EnergyPlusData &state, Real64 &MyLoad, bool RunFlag) { // SUBROUTINE INFORMATION: @@ -5204,7 +5204,7 @@ namespace CondenserLoopTowers { return; // TODO: WTF bool returnFlagSet = false; - this->checkMassFlowAndLoad(state, MyLoad, returnFlagSet); + this->checkMassFlowAndLoad(state, MyLoad, RunFlag, returnFlagSet); if (returnFlagSet) return; // loop to increment NumCell if we cannot meet the setpoint with the actual number of cells calculated above @@ -5418,7 +5418,7 @@ namespace CondenserLoopTowers { } } - void CoolingTower::calculateMerkelVariableSpeedTower(EnergyPlusData &state, Real64 &MyLoad) + void CoolingTower::calculateMerkelVariableSpeedTower(EnergyPlusData &state, Real64 &MyLoad, bool RunFlag) { // SUBROUTINE INFORMATION: @@ -5504,15 +5504,7 @@ namespace CondenserLoopTowers { WaterMassFlowRatePerCell = this->WaterMassFlowRate / this->NumCellOn; - // MassFlowTolerance is a parameter to indicate a no flow condition - if (this->WaterMassFlowRate <= DataBranchAirLoopPlant::MassFlowTolerance || (MyLoad > HVAC::SmallLoad)) { - // for multiple cells, we assume that it's a common basin - CalcBasinHeaterPower( - state, this->BasinHeaterPowerFTempDiff, this->BasinHeaterSchedulePtr, this->BasinHeaterSetPointTemp, this->BasinHeaterPower); - return; - } - - if (std::abs(MyLoad) <= HVAC::SmallLoad) { + if ((std::abs(MyLoad) <= HVAC::SmallLoad) || !RunFlag) { // tower doesn't need to do anything this->OutletWaterTemp = state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp; this->FanPower = 0.0; @@ -5521,6 +5513,11 @@ namespace CondenserLoopTowers { CalcBasinHeaterPower( state, this->BasinHeaterPowerFTempDiff, this->BasinHeaterSchedulePtr, this->BasinHeaterSetPointTemp, this->BasinHeaterPower); return; + } else if (this->WaterMassFlowRate <= DataBranchAirLoopPlant::MassFlowTolerance || (MyLoad > HVAC::SmallLoad)) { + // for multiple cells, we assume that it's a common basin + CalcBasinHeaterPower( + state, this->BasinHeaterPowerFTempDiff, this->BasinHeaterSchedulePtr, this->BasinHeaterSetPointTemp, this->BasinHeaterPower); + return; } // first find free convection cooling rate @@ -6455,24 +6452,21 @@ namespace CondenserLoopTowers { } } - void CoolingTower::checkMassFlowAndLoad(EnergyPlusData &state, Real64 const MyLoad, bool &returnFlagSet) + void CoolingTower::checkMassFlowAndLoad(EnergyPlusData &state, Real64 const MyLoad, bool RunFlag, bool &returnFlagSet) { - // MassFlowTolerance is a parameter to indicate a no flow condition - if (this->WaterMassFlowRate <= DataBranchAirLoopPlant::MassFlowTolerance) { - // for multiple cells, we assume that it's a common basin - CalcBasinHeaterPower( - state, this->BasinHeaterPowerFTempDiff, this->BasinHeaterSchedulePtr, this->BasinHeaterSetPointTemp, this->BasinHeaterPower); - returnFlagSet = true; - } - - // Also check to see if the tower is not running (zero MyLoad) - if (std::abs(MyLoad) <= HVAC::SmallLoad) { + if ((MyLoad > -HVAC::SmallLoad) || !RunFlag) { // tower doesn't need to do anything this->OutletWaterTemp = state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp; - this->WaterMassFlowRate = 0.0; this->FanPower = 0.0; this->airFlowRateRatio = 0.0; this->Qactual = 0.0; + this->WaterMassFlowRate = 0.0; + PlantUtilities::SetComponentFlowRate(state, this->WaterMassFlowRate, this->WaterInletNodeNum, this->WaterOutletNodeNum, this->plantLoc); + CalcBasinHeaterPower( + state, this->BasinHeaterPowerFTempDiff, this->BasinHeaterSchedulePtr, this->BasinHeaterSetPointTemp, this->BasinHeaterPower); + returnFlagSet = true; + } else if (this->WaterMassFlowRate <= DataBranchAirLoopPlant::MassFlowTolerance) { + // for multiple cells, we assume that it's a common basin CalcBasinHeaterPower( state, this->BasinHeaterPowerFTempDiff, this->BasinHeaterSchedulePtr, this->BasinHeaterSetPointTemp, this->BasinHeaterPower); returnFlagSet = true; diff --git a/src/EnergyPlus/CondenserLoopTowers.hh b/src/EnergyPlus/CondenserLoopTowers.hh index ef2da0f931a..f49d8b2ad8e 100644 --- a/src/EnergyPlus/CondenserLoopTowers.hh +++ b/src/EnergyPlus/CondenserLoopTowers.hh @@ -387,13 +387,13 @@ namespace CondenserLoopTowers { void SizeVSMerkelTower(EnergyPlusData &state); - void calculateSingleSpeedTower(EnergyPlusData &state, Real64 &MyLoad); + void calculateSingleSpeedTower(EnergyPlusData &state, Real64 &MyLoad, bool RunFlag); - void calculateTwoSpeedTower(EnergyPlusData &state, Real64 &MyLoad); + void calculateTwoSpeedTower(EnergyPlusData &state, Real64 &MyLoad, bool RunFlag); - void calculateMerkelVariableSpeedTower(EnergyPlusData &state, Real64 &MyLoad); + void calculateMerkelVariableSpeedTower(EnergyPlusData &state, Real64 &MyLoad, bool RunFlag); - void calculateVariableSpeedTower(EnergyPlusData &state, Real64 &MyLoad); + void calculateVariableSpeedTower(EnergyPlusData &state, Real64 &MyLoad, bool RunFlag); Real64 calculateSimpleTowerOutletTemp(EnergyPlusData &state, Real64 waterMassFlowRate, Real64 AirFlowRate, Real64 UAdesign); @@ -427,7 +427,7 @@ namespace CondenserLoopTowers { void report(EnergyPlusData &state, bool RunFlag); - void checkMassFlowAndLoad(EnergyPlusData &state, Real64 MyLoad, bool &returnFlagSet); + void checkMassFlowAndLoad(EnergyPlusData &state, Real64 MyLoad, bool RunFlag, bool &returnFlagSet); static CoolingTower *factory(EnergyPlusData &state, std::string_view objectName); }; diff --git a/tst/EnergyPlus/unit/CondenserLoopTowers.unit.cc b/tst/EnergyPlus/unit/CondenserLoopTowers.unit.cc index bb6f354a6f6..41e89f21271 100644 --- a/tst/EnergyPlus/unit/CondenserLoopTowers.unit.cc +++ b/tst/EnergyPlus/unit/CondenserLoopTowers.unit.cc @@ -515,7 +515,8 @@ TEST_F(EnergyPlusFixture, CondenserLoopTowers_MerkelNoCooling) state->dataCondenserLoopTowers->towers(1).SizeVSMerkelTower(*state); state->dataCondenserLoopTowers->towers(1).initialize(*state); Real64 MyLoad = 0.0; - state->dataCondenserLoopTowers->towers(1).calculateMerkelVariableSpeedTower(*state, MyLoad); + bool RunFlag = false; + state->dataCondenserLoopTowers->towers(1).calculateMerkelVariableSpeedTower(*state, MyLoad, RunFlag); state->dataCondenserLoopTowers->towers(1).update(*state); state->dataCondenserLoopTowers->towers(1).report(*state, true); @@ -905,10 +906,11 @@ TEST_F(EnergyPlusFixture, CondenserLoopTowers_SingleSpeedSizing) CondenserLoopTowers::GetTowerInput(*state); Real64 MyLoad = 0.0; + bool RunFlag = false; state->dataCondenserLoopTowers->towers(1).initialize(*state); state->dataCondenserLoopTowers->towers(1).SizeTower(*state); state->dataCondenserLoopTowers->towers(1).initialize(*state); - state->dataCondenserLoopTowers->towers(1).calculateSingleSpeedTower(*state, MyLoad); + state->dataCondenserLoopTowers->towers(1).calculateSingleSpeedTower(*state, MyLoad, RunFlag); state->dataCondenserLoopTowers->towers(1).update(*state); state->dataCondenserLoopTowers->towers(1).report(*state, true); @@ -927,7 +929,6 @@ TEST_F(EnergyPlusFixture, CondenserLoopTowers_SingleSpeedSizing) if (outletNode != state->dataLoopNodes->NodeID.end()) { outletNodeIndex = std::distance(state->dataLoopNodes->NodeID.begin(), outletNode); } - // TODO: FIXME: This is failing. Actual is -10.409381032746095, expected is 30. EXPECT_GT(state->dataLoopNodes->Node(inletNodeIndex).Temp, 30.0); // inlet node temperature EXPECT_DOUBLE_EQ(state->dataLoopNodes->Node(inletNodeIndex).Temp, state->dataLoopNodes->Node(outletNodeIndex).Temp); // outlet node temperature @@ -3968,8 +3969,9 @@ TEST_F(EnergyPlusFixture, VSCoolingTowers_WaterOutletTempTest) state->dataPlnt->PlantLoop(VSTower.plantLoc.loopNum).LoopSide(VSTower.plantLoc.loopSideNum).TempSetPoint = 30.0; VSTower.WaterMassFlowRate = VSTower.DesWaterMassFlowRate * WaterFlowRateRatio; - Real64 myLoad = 1000.0; - VSTower.calculateVariableSpeedTower(*state, myLoad); + Real64 myLoad = -1000.0; + bool RunFlag = true; + VSTower.calculateVariableSpeedTower(*state, myLoad, RunFlag); EXPECT_DOUBLE_EQ(30.0, VSTower.OutletWaterTemp); EXPECT_DOUBLE_EQ(1.0, VSTower.FanCyclingRatio); Real64 TowerOutletWaterTemp = VSTower.calculateVariableTowerOutletTemp(*state, WaterFlowRateRatio, VSTower.airFlowRateRatio, AirWetBulbTemp); @@ -3987,7 +3989,7 @@ TEST_F(EnergyPlusFixture, VSCoolingTowers_WaterOutletTempTest) VSTower.AirWetBulb = state->dataEnvrn->OutWetBulbTemp; VSTower.AirHumRat = state->dataEnvrn->OutHumRat; - VSTower.calculateVariableSpeedTower(*state, myLoad); + VSTower.calculateVariableSpeedTower(*state, myLoad, RunFlag); EXPECT_DOUBLE_EQ(30.0, VSTower.OutletWaterTemp); EXPECT_NEAR(0.5424, VSTower.FanCyclingRatio, 0.0001); // outside air condition is favorable that fan only needs to cycle at min flow to meet the setpoint @@ -4310,6 +4312,7 @@ TEST_F(EnergyPlusFixture, CondenserLoopTowers_CalculateVariableTowerOutletTemp) TEST_F(EnergyPlusFixture, CondenserLoopTowers_checkMassFlowAndLoadTest) { bool flagToReturn; + bool runFlag; Real64 myLoad; Real64 constexpr allowedTolerance = 0.0001; Real64 expectedPower; @@ -4317,12 +4320,21 @@ TEST_F(EnergyPlusFixture, CondenserLoopTowers_checkMassFlowAndLoadTest) state->dataCondenserLoopTowers->towers.allocate(1); auto &tower = state->dataCondenserLoopTowers->towers(1); - state->dataLoopNodes->Node.allocate(1); + state->dataPlnt->PlantLoop.allocate(1); + state->dataPlnt->PlantLoop(1).LoopSide(DataPlant::LoopSideLocation::Supply).Branch.allocate(1); + state->dataPlnt->PlantLoop(1).LoopSide(DataPlant::LoopSideLocation::Supply).Branch(1).Comp.allocate(1); + state->dataLoopNodes->Node.allocate(2); tower.WaterInletNodeNum = 1; + tower.WaterOutletNodeNum = 2; + tower.plantLoc.loopNum = 1; + tower.plantLoc.loopSideNum = DataPlant::LoopSideLocation::Supply; + tower.plantLoc.branchNum = 1; + tower.plantLoc.compNum = 1; // Test 1: Mass flow rate is low but myLoad is ok--flag should be set to true flagToReturn = false; - myLoad = 1000.0; + runFlag = true; + myLoad = -1000.0; state->dataEnvrn->OutDryBulbTemp = 27.0; tower.WaterMassFlowRate = 0.0; tower.BasinHeaterPowerFTempDiff = 1.0; @@ -4330,12 +4342,13 @@ TEST_F(EnergyPlusFixture, CondenserLoopTowers_checkMassFlowAndLoadTest) tower.BasinHeaterSetPointTemp = 26.0; tower.BasinHeaterPower = 1.0; expectedPower = 0.0; - tower.checkMassFlowAndLoad(*state, myLoad, flagToReturn); + tower.checkMassFlowAndLoad(*state, myLoad, runFlag, flagToReturn); EXPECT_TRUE(flagToReturn); EXPECT_NEAR(expectedPower, tower.BasinHeaterPower, allowedTolerance); // Test 2: Mass flow rate is ok but myLoad is zero--flag should be set to true flagToReturn = false; + runFlag = false; myLoad = 0.0; state->dataEnvrn->OutDryBulbTemp = 27.0; tower.WaterMassFlowRate = 0.5; @@ -4349,7 +4362,7 @@ TEST_F(EnergyPlusFixture, CondenserLoopTowers_checkMassFlowAndLoadTest) expectedPower = 0.0; expectedTemp = 23.0; state->dataLoopNodes->Node(tower.WaterInletNodeNum).Temp = 23.0; - tower.checkMassFlowAndLoad(*state, myLoad, flagToReturn); + tower.checkMassFlowAndLoad(*state, myLoad, runFlag, flagToReturn); EXPECT_TRUE(flagToReturn); EXPECT_NEAR(expectedPower, tower.BasinHeaterPower, allowedTolerance); EXPECT_NEAR(expectedTemp, tower.OutletWaterTemp, allowedTolerance); @@ -4359,7 +4372,8 @@ TEST_F(EnergyPlusFixture, CondenserLoopTowers_checkMassFlowAndLoadTest) // Test 3: Mass flow rate and myLoad are both ok--nothing changes, power does not get calculated here flagToReturn = false; - myLoad = 1000.0; + runFlag = true; + myLoad = -1000.0; state->dataEnvrn->OutDryBulbTemp = 27.0; tower.WaterMassFlowRate = 0.5; tower.BasinHeaterPowerFTempDiff = 1.0; @@ -4367,7 +4381,7 @@ TEST_F(EnergyPlusFixture, CondenserLoopTowers_checkMassFlowAndLoadTest) tower.BasinHeaterSetPointTemp = 25.0; tower.BasinHeaterPower = 3.0; expectedPower = 3.0; - tower.checkMassFlowAndLoad(*state, myLoad, flagToReturn); + tower.checkMassFlowAndLoad(*state, myLoad, runFlag, flagToReturn); EXPECT_FALSE(flagToReturn); EXPECT_NEAR(expectedPower, tower.BasinHeaterPower, allowedTolerance); } From 4d6159464238ae9bcecfe57ef7ddc02a657478df Mon Sep 17 00:00:00 2001 From: Brent Griffith Date: Wed, 14 Aug 2024 07:18:58 -0600 Subject: [PATCH 6/6] add SafeCopyPlantNode() to cooling towers --- src/EnergyPlus/CondenserLoopTowers.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/EnergyPlus/CondenserLoopTowers.cc b/src/EnergyPlus/CondenserLoopTowers.cc index f365bd4e722..a99dee14c4c 100644 --- a/src/EnergyPlus/CondenserLoopTowers.cc +++ b/src/EnergyPlus/CondenserLoopTowers.cc @@ -6344,6 +6344,7 @@ namespace CondenserLoopTowers { // This subroutine is for passing results to the outlet water node. // set node information + PlantUtilities::SafeCopyPlantNode(state, this->WaterInletNodeNum, this->WaterOutletNodeNum); state.dataLoopNodes->Node(this->WaterOutletNodeNum).Temp = this->OutletWaterTemp; if (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopSide(this->plantLoc.loopSideNum).FlowLock == DataPlant::FlowLock::Unlocked ||