Skip to content
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

Correction of Mass Flow Rate Calculation for Pools Served by Low Heater Capacity #10551

Merged
merged 5 commits into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
39 changes: 25 additions & 14 deletions src/EnergyPlus/SwimmingPool.cc
Original file line number Diff line number Diff line change
Expand Up @@ -920,23 +920,14 @@ void SwimmingPoolData::calculate(EnergyPlusData &state)
FluidProperties::GetSpecificHeatGlycol(state, "WATER", this->PoolWaterTemp, this->GlycolIndex, RoutineName); // specific heat of pool water

Real64 TH22 = state.dataHeatBalSurf->SurfInsideTempHist(2)(
SurfNum); // inside surface temperature at the previous time step equals the old pool water temperature
Real64 TInSurf =
this->CurSetPtTemp; // Setpoint temperature for pool which is also the goal temperature and also the inside surface face temperature
Real64 Tmuw = this->CurMakeupWaterTemp; // Inlet makeup water temperature
SurfNum); // inside surface temperature at the previous time step equals the old pool water temperature
Real64 Tmuw = this->CurMakeupWaterTemp; // Inlet makeup water temperature
Real64 TLoopInletTemp = state.dataLoopNodes->Node(this->WaterInletNode).Temp; // Inlet water temperature from the plant loop
this->WaterInletTemp = TLoopInletTemp;

// Now calculate the requested mass flow rate from the plant loop to achieve the proper pool temperature
// old equation using surface heat balance form: MassFlowRate = CpDeltaTi * ( CondTerms + ConvTerm + SWtotal + LWtotal + PeopleGain +
// PoolMassTerm + MUWTerm + EvapEnergyLossPerArea );
Real64 MassFlowRate = (this->WaterMass / (state.dataHVACGlobal->TimeStepSysSec)) *
((TInSurf - TH22) / (TLoopInletTemp - TInSurf)); // Target mass flow rate to achieve the proper setpoint temperature
if (MassFlowRate > this->WaterMassFlowRateMax) {
MassFlowRate = this->WaterMassFlowRateMax;
} else if (MassFlowRate < 0.0) {
MassFlowRate = 0.0;
}
Real64 MassFlowRate;
this->calcMassFlowRate(state, MassFlowRate, TH22, TLoopInletTemp);

PlantUtilities::SetComponentFlowRate(state, MassFlowRate, this->WaterInletNode, this->WaterOutletNode, this->HWplantLoc);
this->WaterMassFlowRate = MassFlowRate;

Expand All @@ -953,6 +944,26 @@ void SwimmingPoolData::calculate(EnergyPlusData &state)
state.dataHeatBalFanSys->SumLatentPool(ZoneNum) += EvapRate * Psychrometrics::PsyHfgAirFnWTdb(thisZoneHB.airHumRat, thisZoneHB.MAT);
}

void SwimmingPoolData::calcMassFlowRate(EnergyPlusData &state, Real64 &massFlowRate, Real64 TH22, Real64 TLoopInletTemp)
Copy link
Contributor

@rraustad rraustad Jun 12, 2024

Choose a reason for hiding this comment

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

I just have a few nit pick comments.

  1. what is TH22 (I know it's the pool water temp, but what is TH22)?
  2. would be better to use the equation at line 951, 953, or 960 in the unit test instead of a scalar for expected answer as it would be more apparent as to the intent.
  3. knowing that RS made these changes I suspect that it is not possible for line 951 to calculate a negative number.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@rraustad Here are answers to your questions:

  1. TH22 comes from the temperature histories array. One of the twos is for the inside surface and the other is for the last temperature history (not the current time). So, yes, it is the pool water temperature and I guess it could have been better stated that way. It's also TH22 in the routine that calls it so I was trying to keep some continuity there to make it less confusing, but I can see that I perhaps wasn't successful since the meaning of TH22 is not obvious.
  2. That could be done. I guess I was calculating and fixing it at a scalar so that I wasn't using the same equation in both places. My thought was: I calculated this by hand so that it would be correct--does the code correctly calculate this using the subroutine?
  3. Actually, it is possible for this to calculate a negative number, but this is why there is the else if starting in line 957. These lines of code prevent returning a negative flow and also make sure that if the loop temperature is lower than the setpoint that it still sends flow in the case where heating could actually be taking place. Previously, it just set the flow to zero which is what led to this defect. Now, when the flow gets calculated as negative or zero, it checks to see if the loop temperature would still provide heating (that is, is higher than the pool temperature) even though the loop temperature is lower than the setpoint temperature. Before, the flow was set to zero and a low capacity heater would just quit heating. Now, the low capacity heater still runs and can eventually get back to the setpoint.

@Myoldmopar Based on comments by @rraustad, do you want me to do any additional commits?

Copy link
Contributor

Choose a reason for hiding this comment

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

@RKStrand my comments were more for closure on this branch. I don't really "need" to see these changes, they were just food for thought.

Copy link
Member

Choose a reason for hiding this comment

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

Perfect on all accounts. They are valid comments, but I agree we don't need more commits here. Thanks to you both, I think this is ready.

Copy link
Member

Choose a reason for hiding this comment

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

Ready - "was ready when I merged it"

{
// Calculate the mass flow rate to achieve the proper setpoint temperature
if (TLoopInletTemp != this->CurSetPtTemp) {
massFlowRate = this->WaterMass / state.dataHVACGlobal->TimeStepSysSec * (this->CurSetPtTemp - TH22) / (TLoopInletTemp - this->CurSetPtTemp);
} else { // avoid the divide by zero, reset later if necessary
massFlowRate = 0.0;
}
if (massFlowRate > this->WaterMassFlowRateMax) {
massFlowRate = this->WaterMassFlowRateMax;
} else if (massFlowRate <= 0.0) {
// trap case where loop temperature is lower than the setpoint but could still do heating Defect 10317
if (TLoopInletTemp > TH22 && TLoopInletTemp <= this->CurSetPtTemp) {
massFlowRate = this->WaterMassFlowRateMax;
} else {
massFlowRate = 0.0;
}
Copy link
Member

Choose a reason for hiding this comment

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

Looks good to me.

}
}

void SwimmingPoolData::calcSwimmingPoolEvap(EnergyPlusData &state,
Real64 &EvapRate, // evaporation rate of pool
int const SurfNum, // surface index
Expand Down
6 changes: 6 additions & 0 deletions src/EnergyPlus/SwimmingPool.hh
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,12 @@ namespace SwimmingPool {

void calculate(EnergyPlusData &state);

void calcMassFlowRate(EnergyPlusData &state,
Real64 &massFlowRate, // Mass Flow Rate (to be calculated)
Real64 TH22, // Pool water temperature from previous time step
Real64 TLoopInletTemp //
);

void calcSwimmingPoolEvap(EnergyPlusData &state,
Real64 &EvapRate, // Evaporation rate
int SurfNum, // Surface index
Expand Down
78 changes: 78 additions & 0 deletions tst/EnergyPlus/unit/SwimmingPool.unit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -541,3 +541,81 @@ TEST_F(EnergyPlusFixture, SwimmingPool_reportTest)
EXPECT_NEAR(expectedMakeUpWaterVolFlowRate, myPool.MakeUpWaterVolFlowRate, closeEnough);
EXPECT_NEAR(expectedMakeUpWaterVol, myPool.MakeUpWaterVol, closeEnough);
}

TEST_F(EnergyPlusFixture, SwimmingPool_calcMassFlowRateTest)
{
// Test routine added as a solution to Defect #10317
Real64 constexpr closeEnough = 0.00001;
Real64 tPoolWater;
Real64 tInletWaterLoop;
Real64 calculatedFlowRate;
Real64 expectedAnswer;
SwimmingPoolData testPool;

state->dataHVACGlobal->TimeStepSysSec = 60.0;

// Test 1: Normal pass through the routine, no limits violated
testPool.CurSetPtTemp = 27.0;
testPool.WaterMass = 1000.0;
testPool.WaterMassFlowRateMax = 20.0;
tPoolWater = 25.0;
tInletWaterLoop = 30.0;
expectedAnswer = 11.111111;
testPool.calcMassFlowRate(*state, calculatedFlowRate, tPoolWater, tInletWaterLoop);
EXPECT_NEAR(calculatedFlowRate, expectedAnswer, closeEnough);

// Test 2: Flow rate larger than max--limit to max
calculatedFlowRate = 0.0; // reset
testPool.CurSetPtTemp = 27.0;
testPool.WaterMass = 1000.0;
testPool.WaterMassFlowRateMax = 10.0;
tPoolWater = 25.0;
tInletWaterLoop = 30.0;
expectedAnswer = 10.0;
testPool.calcMassFlowRate(*state, calculatedFlowRate, tPoolWater, tInletWaterLoop);
EXPECT_NEAR(calculatedFlowRate, expectedAnswer, closeEnough);

// Test 3: Current setpoint is lower than the pool temperature--flow rate set to zero
calculatedFlowRate = -9999.9; // reset
testPool.CurSetPtTemp = 27.0;
testPool.WaterMass = 1000.0;
testPool.WaterMassFlowRateMax = 10.0;
tPoolWater = 32.0;
tInletWaterLoop = 30.0;
expectedAnswer = 0.0;
testPool.calcMassFlowRate(*state, calculatedFlowRate, tPoolWater, tInletWaterLoop);
EXPECT_NEAR(calculatedFlowRate, expectedAnswer, closeEnough);

// Test 4: Current setpoint and inlet temperature are equal--flow rate set to max when pool water temperature is lower
calculatedFlowRate = -9999.9; // reset
testPool.CurSetPtTemp = 27.0;
testPool.WaterMass = 1000.0;
testPool.WaterMassFlowRateMax = 20.0;
tPoolWater = 25.0;
tInletWaterLoop = 27.0;
expectedAnswer = 20.0;
testPool.calcMassFlowRate(*state, calculatedFlowRate, tPoolWater, tInletWaterLoop);
EXPECT_NEAR(calculatedFlowRate, expectedAnswer, closeEnough);

// Test 5: Current setpoint and inlet temperature are equal--flow rate set to zero when pool water temperature is higher
calculatedFlowRate = -9999.9; // reset
testPool.CurSetPtTemp = 27.0;
testPool.WaterMass = 1000.0;
testPool.WaterMassFlowRateMax = 20.0;
tPoolWater = 32.0;
tInletWaterLoop = 27.0;
expectedAnswer = 0.0;
testPool.calcMassFlowRate(*state, calculatedFlowRate, tPoolWater, tInletWaterLoop);
EXPECT_NEAR(calculatedFlowRate, expectedAnswer, closeEnough);

// Test 6: Water temp is below the setpoint but higher than the pool temp--flow rate set to max (this was the cause of the defect)
calculatedFlowRate = -9999.9; // reset
testPool.CurSetPtTemp = 27.0;
testPool.WaterMass = 1000.0;
testPool.WaterMassFlowRateMax = 17.0;
tPoolWater = 25.0;
tInletWaterLoop = 26.0;
expectedAnswer = 17.0;
testPool.calcMassFlowRate(*state, calculatedFlowRate, tPoolWater, tInletWaterLoop);
EXPECT_NEAR(calculatedFlowRate, expectedAnswer, closeEnough);
Copy link
Member

Choose a reason for hiding this comment

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

Great testing! That little function is getting exercised well in all these different conditions. 💯

}
Loading