Skip to content

Commit

Permalink
Merge pull request #10653 from NREL/10634CondenserNotFollowingPlanOpS…
Browse files Browse the repository at this point in the history
…cheme

Correction of Condensers Not Operating Based on Operation Scheme
  • Loading branch information
Myoldmopar committed Aug 16, 2024
2 parents 9f28e62 + 4d61594 commit 9a7218c
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 46 deletions.
81 changes: 46 additions & 35 deletions src/EnergyPlus/CondenserLoopTowers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -137,16 +137,16 @@ namespace CondenserLoopTowers {
this->initialize(state);
switch (this->TowerType) {
case DataPlant::PlantEquipmentType::CoolingTower_SingleSpd:
this->calculateSingleSpeedTower(state);
this->calculateSingleSpeedTower(state, CurLoad, RunFlag);
break;
case DataPlant::PlantEquipmentType::CoolingTower_TwoSpd:
this->calculateTwoSpeedTower(state);
this->calculateTwoSpeedTower(state, CurLoad, RunFlag);
break;
case DataPlant::PlantEquipmentType::CoolingTower_VarSpd:
this->calculateVariableSpeedTower(state);
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));
Expand Down Expand Up @@ -4535,7 +4535,7 @@ namespace CondenserLoopTowers {
}
} // namespace CondenserLoopTowers

void CoolingTower::calculateSingleSpeedTower(EnergyPlusData &state)
void CoolingTower::calculateSingleSpeedTower(EnergyPlusData &state, Real64 &MyLoad, bool RunFlag)
{

// SUBROUTINE INFORMATION:
Expand Down Expand Up @@ -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 = false;
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

Expand Down Expand Up @@ -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, bool RunFlag)
{

// SUBROUTINE INFORMATION:
Expand Down Expand Up @@ -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 = false;
this->checkMassFlowAndLoad(state, MyLoad, RunFlag, returnFlagSet);
if (returnFlagSet) return;

// Added for multi-cell. Determine the number of cells operating
Real64 WaterMassFlowRatePerCellMin = 0.0;
Expand Down Expand Up @@ -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, bool RunFlag)
{

// SUBROUTINE INFORMATION:
Expand Down Expand Up @@ -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 = false;
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
bool IncrNumCellFlag = true;
Expand Down Expand Up @@ -5427,7 +5418,7 @@ namespace CondenserLoopTowers {
}
}

void CoolingTower::calculateMerkelVariableSpeedTower(EnergyPlusData &state, Real64 &MyLoad)
void CoolingTower::calculateMerkelVariableSpeedTower(EnergyPlusData &state, Real64 &MyLoad, bool RunFlag)
{

// SUBROUTINE INFORMATION:
Expand Down Expand Up @@ -5512,15 +5503,8 @@ 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
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;
Expand All @@ -5529,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
Expand Down Expand Up @@ -6355,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 ||
Expand Down Expand Up @@ -6463,6 +6453,27 @@ namespace CondenserLoopTowers {
}
}

void CoolingTower::checkMassFlowAndLoad(EnergyPlusData &state, Real64 const MyLoad, bool RunFlag, bool &returnFlagSet)
{
if ((MyLoad > -HVAC::SmallLoad) || !RunFlag) {
// 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;
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;
}
}

} // namespace CondenserLoopTowers

} // namespace EnergyPlus
10 changes: 6 additions & 4 deletions src/EnergyPlus/CondenserLoopTowers.hh
Original file line number Diff line number Diff line change
Expand Up @@ -387,13 +387,13 @@ namespace CondenserLoopTowers {

void SizeVSMerkelTower(EnergyPlusData &state);

void calculateSingleSpeedTower(EnergyPlusData &state);
void calculateSingleSpeedTower(EnergyPlusData &state, Real64 &MyLoad, bool RunFlag);

void calculateTwoSpeedTower(EnergyPlusData &state);
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);
void calculateVariableSpeedTower(EnergyPlusData &state, Real64 &MyLoad, bool RunFlag);

Real64 calculateSimpleTowerOutletTemp(EnergyPlusData &state, Real64 waterMassFlowRate, Real64 AirFlowRate, Real64 UAdesign);

Expand Down Expand Up @@ -427,6 +427,8 @@ namespace CondenserLoopTowers {

void report(EnergyPlusData &state, bool RunFlag);

void checkMassFlowAndLoad(EnergyPlusData &state, Real64 MyLoad, bool RunFlag, bool &returnFlagSet);

static CoolingTower *factory(EnergyPlusData &state, std::string_view objectName);
};

Expand Down
95 changes: 88 additions & 7 deletions tst/EnergyPlus/unit/CondenserLoopTowers.unit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -904,10 +905,12 @@ TEST_F(EnergyPlusFixture, CondenserLoopTowers_SingleSpeedSizing)
SimulationManager::SetupSimulation(*state, ErrorsFound);
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);
state->dataCondenserLoopTowers->towers(1).calculateSingleSpeedTower(*state, MyLoad, RunFlag);
state->dataCondenserLoopTowers->towers(1).update(*state);
state->dataCondenserLoopTowers->towers(1).report(*state, true);

Expand All @@ -926,9 +929,8 @@ 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(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);
Expand Down Expand Up @@ -3967,7 +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;

VSTower.calculateVariableSpeedTower(*state);
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);
Expand All @@ -3985,7 +3989,7 @@ TEST_F(EnergyPlusFixture, VSCoolingTowers_WaterOutletTempTest)
VSTower.AirWetBulb = state->dataEnvrn->OutWetBulbTemp;
VSTower.AirHumRat = state->dataEnvrn->OutHumRat;

VSTower.calculateVariableSpeedTower(*state);
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
Expand Down Expand Up @@ -4305,4 +4309,81 @@ TEST_F(EnergyPlusFixture, CondenserLoopTowers_CalculateVariableTowerOutletTemp)
EXPECT_NEAR(tower.WaterTemp - 22.2222, tOutlet, 0.01);
}

TEST_F(EnergyPlusFixture, CondenserLoopTowers_checkMassFlowAndLoadTest)
{
bool flagToReturn;
bool runFlag;
Real64 myLoad;
Real64 constexpr allowedTolerance = 0.0001;
Real64 expectedPower;
Real64 expectedTemp;

state->dataCondenserLoopTowers->towers.allocate(1);
auto &tower = state->dataCondenserLoopTowers->towers(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;
runFlag = true;
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, 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;
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, runFlag, 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;
runFlag = true;
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, runFlag, flagToReturn);
EXPECT_FALSE(flagToReturn);
EXPECT_NEAR(expectedPower, tower.BasinHeaterPower, allowedTolerance);
}

} // namespace EnergyPlus

8 comments on commit 9a7218c

@nrel-bot-2c
Copy link

Choose a reason for hiding this comment

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

develop (Myoldmopar) - x86_64-Linux-Ubuntu-22.04-gcc-11.4: OK (2891 of 2891 tests passed, 0 test warnings)

Build Badge Test Badge

@nrel-bot-3
Copy link

Choose a reason for hiding this comment

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

develop (Myoldmopar) - x86_64-MacOS-10.18-clang-15.0.0: OK (2870 of 2870 tests passed, 0 test warnings)

Build Badge Test Badge

@nrel-bot
Copy link

Choose a reason for hiding this comment

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

develop (Myoldmopar) - Win64-Windows-10-VisualStudio-16: OK (2869 of 2869 tests passed, 0 test warnings)

Build Badge Test Badge

@nrel-bot-2
Copy link

Choose a reason for hiding this comment

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

develop (Myoldmopar) - x86_64-Linux-Ubuntu-22.04-gcc-11.4-IntegrationCoverage-Debug: OK (796 of 796 tests passed, 0 test warnings)

Build Badge Test Badge Coverage Badge

@nrel-bot-2c
Copy link

Choose a reason for hiding this comment

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

develop (Myoldmopar) - x86_64-Linux-Ubuntu-22.04-gcc-11.4-UnitTestsCoverage-Debug: OK (2076 of 2076 tests passed, 0 test warnings)

Build Badge Test Badge Coverage Badge

@nrel-bot-2c
Copy link

Choose a reason for hiding this comment

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

10638VRFSizingBasedOnWrongSizingType (Myoldmopar) - x86_64-Linux-Ubuntu-22.04-gcc-11.4: OK (3703 of 3703 tests passed, 0 test warnings)

Build Badge Test Badge

@nrel-bot-2b
Copy link

Choose a reason for hiding this comment

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

10638VRFSizingBasedOnWrongSizingType (Myoldmopar) - x86_64-Linux-Ubuntu-22.04-gcc-11.4-UnitTestsCoverage-Debug: OK (2076 of 2076 tests passed, 0 test warnings)

Build Badge Test Badge Coverage Badge

@nrel-bot-2c
Copy link

Choose a reason for hiding this comment

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

10638VRFSizingBasedOnWrongSizingType (Myoldmopar) - x86_64-Linux-Ubuntu-22.04-gcc-11.4-IntegrationCoverage-Debug: OK (796 of 796 tests passed, 0 test warnings)

Build Badge Test Badge Coverage Badge

Please sign in to comment.