Skip to content

Commit

Permalink
10065 Fixes for ChillerHeater
Browse files Browse the repository at this point in the history
This commit includes fixes for two separate issues.  First, when in heating mode, the evaporator and compressor power was always at full power, not at the power that the condenser needed.  Second, there were random times when in simultaneously heating and cooling mode that no evaporator load or compressor energy due to a logic flaw in the code.  This should fix those issues though there are probably more issues with this model.  This at least addresses those two issues that have caused users problems.
  • Loading branch information
RKStrand committed Jul 29, 2024
1 parent 2fa11f3 commit a71222b
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 17 deletions.
75 changes: 64 additions & 11 deletions src/EnergyPlus/PlantCentralGSHP.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2364,11 +2364,14 @@ void WrapperSpecs::CalcChillerHeaterModel(EnergyPlusData &state)

// Mode 3 and 5 use cooling side data stored from the chilled water loop
// Mode 4 uses all data from the chilled water loop due to no heating demand
if (this->SimulClgDominant || CurrentMode == 3) {
// Fix for Defect #10065: When the heating load is dominant and the Current Mode is 3,
// simulation must go through the "heating" side to properly update the power consumption.
// Otherwise, the power consumption could come back zero for heating and cooling.
if (this->SimulClgDominant || (CurrentMode == 3 && !this->SimulHtgDominant)) {
CurrentMode = 3;
QCondenser = this->ChillerHeater(ChillerHeaterNum).Report.QCondSimul;
this->adjustChillerHeaterFlowTemp(state, QCondenser, CondMassFlowRate, CondOutletTemp, CondInletTemp, CondDeltaTemp);
} else { // Either Mode 2 or 3 or 5
this->adjustChillerHeaterCondFlowTemp(state, QCondenser, CondMassFlowRate, CondOutletTemp, CondInletTemp, CondDeltaTemp);
} else { // Either Mode 2 or 3 (heating dominant) or 5
if (this->SimulHtgDominant) {
CurrentMode = 5;
} else {
Expand Down Expand Up @@ -2459,6 +2462,7 @@ void WrapperSpecs::CalcChillerHeaterModel(EnergyPlusData &state)

QCondenser =
CHPower * this->ChillerHeater(ChillerHeaterNum).OpenMotorEff + QEvaporator + state.dataPlantCentralGSHP->ChillerFalseLoadRate;
Real64 qCondenserFullLoad = QCondenser;

// Determine heating load for this heater and pass the remaining load to the next chiller heater
Real64 CondenserCapMin = QCondenser * MinPartLoadRat;
Expand All @@ -2473,11 +2477,32 @@ void WrapperSpecs::CalcChillerHeaterModel(EnergyPlusData &state)
// then recalculate heating load this chiller heater can meet
if (CurrentMode == 2 || this->SimulHtgDominant) {
if (CondMassFlowRate > DataBranchAirLoopPlant::MassFlowTolerance && CondDeltaTemp > 0.0) {
this->adjustChillerHeaterFlowTemp(state, QCondenser, CondMassFlowRate, CondOutletTemp, CondInletTemp, CondDeltaTemp);
this->adjustChillerHeaterCondFlowTemp(state, QCondenser, CondMassFlowRate, CondOutletTemp, CondInletTemp, CondDeltaTemp);
if (qCondenserFullLoad > 0.0) {
Real64 constexpr diffTolerance = 0.0001;
if (((qCondenserFullLoad - QCondenser) / qCondenserFullLoad) > diffTolerance) {
// QCondenser was reduced, so reduce evaporator side quantities by a factor of the condenser based PLR
PartLoadRat = max(MinPartLoadRat, min((QCondenser / qCondenserFullLoad), MaxPartLoadRat));
QCondenser = PartLoadRat * qCondenserFullLoad;
this->adjustChillerHeaterCondFlowTemp(
state, QCondenser, CondMassFlowRate, CondOutletTemp, CondInletTemp, CondDeltaTemp);
// In most situations here, QCondenser will not be reduced here, but it has to be taken into account. This will
// potentially violate the minPLR but this will keep the solution simple for now.
// So, basically multiply all terms in the energy balance by the same factor to maintain the energy balance.
Real64 modifiedPLR = QCondenser / qCondenserFullLoad;
QEvaporator *= modifiedPLR;
CHPower *= modifiedPLR;
PartLoadRat = modifiedPLR;
state.dataPlantCentralGSHP->ChillerFalseLoadRate *= modifiedPLR;
// Now re-adjust things on the evaporator side to get the correct flows/temperatures
this->adjustChillerHeaterEvapFlowTemp(state, QEvaporator, EvapMassFlowRate, EvapOutletTemp, EvapInletTemp);
}
}
} else {
QCondenser = 0.0;
CondOutletTemp = CondInletTemp;
}
state.dataPlantCentralGSHP->ChillerPartLoadRatio = PartLoadRat;
}

} // End of calculation depending on the modes
Expand Down Expand Up @@ -2554,15 +2579,15 @@ void WrapperSpecs::CalcChillerHeaterModel(EnergyPlusData &state)
}
}

void WrapperSpecs::adjustChillerHeaterFlowTemp(EnergyPlusData &state,
Real64 &QCondenser,
Real64 &CondMassFlowRate,
Real64 &CondOutletTemp,
Real64 const CondInletTemp,
Real64 const CondDeltaTemp)
void WrapperSpecs::adjustChillerHeaterCondFlowTemp(EnergyPlusData &state,
Real64 &QCondenser,
Real64 &CondMassFlowRate,
Real64 &CondOutletTemp,
Real64 const CondInletTemp,
Real64 const CondDeltaTemp)
{
// Based on whether this is variable or constant flow, adjust either flow or outlet temperature and also the load
static constexpr std::string_view RoutineName("adjustChillerHeaterFlow");
static constexpr std::string_view RoutineName("adjustChillerHeaterCondFlowTemp");
Real64 Cp = FluidProperties::GetSpecificHeatGlycol(state,
state.dataPlnt->PlantLoop(this->HWPlantLoc.loopNum).FluidName,
CondInletTemp,
Expand Down Expand Up @@ -2590,6 +2615,34 @@ void WrapperSpecs::adjustChillerHeaterFlowTemp(EnergyPlusData &state,
}
}

void WrapperSpecs::adjustChillerHeaterEvapFlowTemp(
EnergyPlusData &state, Real64 const qEvaporator, Real64 &evapMassFlowRate, Real64 &evapOutletTemp, Real64 const evapInletTemp)
{
// Adjust flow and outlet temperature for the evaporator side without modifying the heat transfer rate
Real64 constexpr lowLoad = 0.001;
static constexpr std::string_view routineName("adjustChillerHeaterEvapFlowTemp");
Real64 Cp = FluidProperties::GetSpecificHeatGlycol(state,
state.dataPlnt->PlantLoop(this->HWPlantLoc.loopNum).FluidName,
evapInletTemp,
state.dataPlnt->PlantLoop(this->HWPlantLoc.loopNum).FluidIndex,
routineName);
Real64 evapDeltaTemp = evapInletTemp - evapOutletTemp;

if ((qEvaporator < lowLoad) || (evapDeltaTemp <= 0.0)) {
evapMassFlowRate = 0.0;
evapOutletTemp = evapInletTemp;
} else {
if (this->VariableFlowCH) { // for variable flow, adjust flow if higher than max value passed in
Real64 evapMassFlowRateCalc = qEvaporator / evapDeltaTemp / Cp;
if (evapMassFlowRateCalc > evapMassFlowRate) evapMassFlowRateCalc = evapMassFlowRate;
evapMassFlowRate = evapMassFlowRateCalc;
}
// Adjust temperature for either flow type to maintain agreement with qEvaporator
evapDeltaTemp = qEvaporator / evapMassFlowRate / Cp;
evapOutletTemp = evapInletTemp - evapDeltaTemp;
}
}

Real64
WrapperSpecs::setChillerHeaterCondTemp(EnergyPlusData &state, int const numChillerHeater, Real64 const condEnteringTemp, Real64 const condLeavingTemp)
{
Expand Down
15 changes: 9 additions & 6 deletions src/EnergyPlus/PlantCentralGSHP.hh
Original file line number Diff line number Diff line change
Expand Up @@ -415,12 +415,15 @@ namespace PlantCentralGSHP {

void CalcChillerHeaterModel(EnergyPlusData &state);

void adjustChillerHeaterFlowTemp(EnergyPlusData &state,
Real64 &QCondenser,
Real64 &CondMassFlowRate,
Real64 &CondOutletTemp,
Real64 const CondInletTemp,
Real64 const CondDeltaTemp);
void adjustChillerHeaterCondFlowTemp(EnergyPlusData &state,
Real64 &QCondenser,
Real64 &CondMassFlowRate,
Real64 &CondOutletTemp,
Real64 const CondInletTemp,
Real64 const CondDeltaTemp);

void adjustChillerHeaterEvapFlowTemp(
EnergyPlusData &state, Real64 const qEvaporator, Real64 &evapMassFlowRate, Real64 &evapOutletTemp, Real64 const evapInletTemp);

Real64
setChillerHeaterCondTemp(EnergyPlusData &state, int const numChillerHeater, Real64 const condEnteringTemp, Real64 const condLeavingTemp);
Expand Down

5 comments on commit a71222b

@nrel-bot
Copy link

Choose a reason for hiding this comment

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

10065ChillerHeaterFix (RKStrand) - Win64-Windows-10-VisualStudio-16: OK (2862 of 2862 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.

10065ChillerHeaterFix (RKStrand) - x86_64-MacOS-10.18-clang-15.0.0: OK (3652 of 3654 tests passed, 0 test warnings)

Messages:\n

  • 2 tests had: EIO diffs.
  • 2 tests had: ESO big diffs.
  • 2 tests had: MTR big diffs.
  • 2 tests had: Table big diffs.
  • 2 tests had: Table string diffs.

Failures:\n

regression Test Summary

  • Passed: 789
  • Failed: 2

Build Badge Test 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.

10065ChillerHeaterFix (RKStrand) - x86_64-Linux-Ubuntu-22.04-gcc-11.4: OK (3693 of 3695 tests passed, 0 test warnings)

Messages:\n

  • 2 tests had: EIO diffs.
  • 2 tests had: ESO big diffs.
  • 2 tests had: MTR big diffs.
  • 2 tests had: Table big diffs.
  • 2 tests had: Table string diffs.

Failures:\n

regression Test Summary

  • Passed: 809
  • Failed: 2

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.

10065ChillerHeaterFix (RKStrand) - x86_64-Linux-Ubuntu-22.04-gcc-11.4-UnitTestsCoverage-Debug: OK (2070 of 2070 tests passed, 0 test warnings)

Build Badge Test Badge Coverage 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.

10065ChillerHeaterFix (RKStrand) - x86_64-Linux-Ubuntu-22.04-gcc-11.4-IntegrationCoverage-Debug: OK (795 of 795 tests passed, 0 test warnings)

Build Badge Test Badge Coverage Badge

Please sign in to comment.