Skip to content

Commit

Permalink
Merge pull request #10628 from NREL/Issue10626_EIR_ashp_tempLimit
Browse files Browse the repository at this point in the history
Source side outlet tempearture calculation uses loadside heat tranfer rate
  • Loading branch information
Myoldmopar committed Aug 12, 2024
2 parents c89c5c9 + 374613f commit 351c68d
Show file tree
Hide file tree
Showing 2 changed files with 160 additions and 4 deletions.
13 changes: 9 additions & 4 deletions src/EnergyPlus/PlantLoopHeatPumpEIR.cc
Original file line number Diff line number Diff line change
Expand Up @@ -487,13 +487,18 @@ void EIRPlantLoopHeatPump::calcAvailableCapacity(EnergyPlusData &state, Real64 c
}
}
if (this->heatRecoveryHeatPump) {
this->calcLoadSideHeatTransfer(state, availableCapacity);
this->calcPowerUsage(state);
Real64 sourceSideHeatTransfer = this->calcQsource(availableCapacity * partLoadRatio, this->powerUsage);
// check to see if souce side outlet temp exceeds limit and reduce PLR if necessary
auto &thisSourcePlantLoop = state.dataPlnt->PlantLoop(this->sourceSidePlantLoc.loopNum);
Real64 const CpSrc = FluidProperties::GetSpecificHeatGlycol(
state, thisSourcePlantLoop.FluidName, this->sourceSideInletTemp, thisSourcePlantLoop.FluidIndex, "EIRPlantLoopHeatPump::doPhysics()");
Real64 const CpSrc = FluidProperties::GetSpecificHeatGlycol(state,
thisSourcePlantLoop.FluidName,
this->sourceSideInletTemp,
thisSourcePlantLoop.FluidIndex,
"EIRPlantLoopHeatPump::calcLoadSideHeatTransfer()");
Real64 const sourceMCp = this->sourceSideMassFlowRate * CpSrc;
Real64 const tempSourceOutletTemp =
this->calcSourceOutletTemp(this->sourceSideInletTemp, (availableCapacity * partLoadRatio) / sourceMCp);
Real64 const tempSourceOutletTemp = this->calcSourceOutletTemp(this->sourceSideInletTemp, sourceSideHeatTransfer / sourceMCp);
if (this->EIRHPType == DataPlant::PlantEquipmentType::HeatPumpEIRHeating && tempSourceOutletTemp < this->minSourceTempLimit) {
partLoadRatio *= (this->sourceSideInletTemp - this->minSourceTempLimit) / (this->sourceSideInletTemp - tempSourceOutletTemp);
} else if (tempSourceOutletTemp > this->maxSourceTempLimit) {
Expand Down
151 changes: 151 additions & 0 deletions tst/EnergyPlus/unit/PlantLoopHeatPumpEIR.unit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5242,5 +5242,156 @@ TEST_F(EnergyPlusFixture, HeatingwithHeatRecoverySimulate_AirSource)
}
}

TEST_F(EnergyPlusFixture, CoolingSimulate_WSHP_SourceSideOutletTemp)
{
std::string const idf_objects = delimited_string({"HeatPump:PlantLoop:EIR:Cooling,",
" hp cooling side,",
" node 1,",
" node 2,",
" WaterSource,",
" node 3,",
" node 4,",
" ,",
" ,",
" ,",
" 0.0002,",
" 0.0002,",
" ,",
" 2000,",
" 3.00,",
" ,",
" dummyCurve,",
" dummyCurve,",
" dummyCurve;",
"Curve:Linear,",
" dummyCurve,",
" 0.95,",
" 0,",
" 1,",
" 1;"});
ASSERT_TRUE(process_idf(idf_objects));

// set up the plant loops
// first the load side
state->dataPlnt->TotNumLoops = 2;
state->dataPlnt->PlantLoop.allocate(2);

state->dataPlnt->PlantLoop(1).LoopDemandCalcScheme = DataPlant::LoopDemandCalcScheme::SingleSetPoint;
state->dataPlnt->PlantLoop(1).LoopSide(DataPlant::LoopSideLocation::Supply).TotalBranches = 1;
state->dataPlnt->PlantLoop(1).LoopSide(DataPlant::LoopSideLocation::Supply).Branch.allocate(1);
state->dataPlnt->PlantLoop(1).LoopSide(DataPlant::LoopSideLocation::Supply).Branch(1).TotalComponents = 1;
state->dataPlnt->PlantLoop(1).LoopSide(DataPlant::LoopSideLocation::Supply).Branch(1).Comp.allocate(1);
auto &PLHPPlantLoadSideComp = state->dataPlnt->PlantLoop(1).LoopSide(DataPlant::LoopSideLocation::Supply).Branch(1).Comp(1);
PLHPPlantLoadSideComp.Type = DataPlant::PlantEquipmentType::HeatPumpEIRCooling;
PLHPPlantLoadSideComp.CurOpSchemeType = DataPlant::OpScheme::CompSetPtBased;
// then the source side

state->dataPlnt->PlantLoop(2).LoopSide(DataPlant::LoopSideLocation::Demand).TotalBranches = 1;
state->dataPlnt->PlantLoop(2).LoopSide(DataPlant::LoopSideLocation::Demand).Branch.allocate(1);
state->dataPlnt->PlantLoop(2).LoopSide(DataPlant::LoopSideLocation::Demand).Branch(1).TotalComponents = 1;
state->dataPlnt->PlantLoop(2).LoopSide(DataPlant::LoopSideLocation::Demand).Branch(1).Comp.allocate(1);
auto &PLHPPlantLoadSourceComp = state->dataPlnt->PlantLoop(2).LoopSide(DataPlant::LoopSideLocation::Demand).Branch(1).Comp(1);
PLHPPlantLoadSourceComp.Type = DataPlant::PlantEquipmentType::HeatPumpEIRCooling;

// the init call expects a "from" calling point
PlantLocation myLoadLocation = PlantLocation(1, DataPlant::LoopSideLocation::Supply, 1, 1);
PlantLocation mySourceLocation = PlantLocation(2, DataPlant::LoopSideLocation::Demand, 1, 1);

// call the factory with a valid name to trigger reading inputs
EIRPlantLoopHeatPump::factory(*state, DataPlant::PlantEquipmentType::HeatPumpEIRCooling, "HP COOLING SIDE");

// verify the size of the vector and the processed condition
EXPECT_EQ(1u, state->dataEIRPlantLoopHeatPump->heatPumps.size());

// for now we know the order is maintained, so get each heat pump object
EIRPlantLoopHeatPump *thisCoolingPLHP = &state->dataEIRPlantLoopHeatPump->heatPumps[0];

// do a bit of extra wiring up to the plant
PLHPPlantLoadSideComp.Name = thisCoolingPLHP->name;
PLHPPlantLoadSideComp.NodeNumIn = thisCoolingPLHP->loadSideNodes.inlet;
PLHPPlantLoadSourceComp.Name = thisCoolingPLHP->name;
PLHPPlantLoadSourceComp.NodeNumIn = thisCoolingPLHP->sourceSideNodes.inlet;

// call for all initialization
state->dataGlobal->BeginEnvrnFlag = true;
state->dataPlnt->PlantFirstSizesOkayToFinalize = true;
thisCoolingPLHP->onInitLoopEquip(*state, myLoadLocation);

// call from load side location, firsthvac, no load, not running, verify the unit doesn't have any values lingering
thisCoolingPLHP->loadSideHeatTransfer = 2000;
thisCoolingPLHP->loadSideInletTemp = 23.0;
thisCoolingPLHP->loadSideOutletTemp = 42.0;
thisCoolingPLHP->powerUsage = 400.0;
thisCoolingPLHP->sourceSideHeatTransfer = 2000.0;
thisCoolingPLHP->sourceSideInletTemp = 45.0;
thisCoolingPLHP->sourceSideOutletTemp = 83.0;
bool firstHVAC = true;
Real64 curLoad = 0.0;
bool runFlag = false;
thisCoolingPLHP->heatRecoveryHeatPump = true;
thisCoolingPLHP->simulate(*state, myLoadLocation, firstHVAC, curLoad, runFlag);
EXPECT_NEAR(0.0, thisCoolingPLHP->loadSideHeatTransfer, 0.001);
EXPECT_NEAR(0.0, thisCoolingPLHP->sourceSideHeatTransfer, 0.001);
EXPECT_NEAR(0.0, thisCoolingPLHP->powerUsage, 0.001);
EXPECT_NEAR(thisCoolingPLHP->loadSideInletTemp, thisCoolingPLHP->loadSideOutletTemp, 0.001);
EXPECT_NEAR(thisCoolingPLHP->sourceSideInletTemp, thisCoolingPLHP->sourceSideOutletTemp, 0.001);

// call from source side location, firsthvac, no load, not running, connected loop should be triggered to resimulate
state->dataPlnt->PlantLoop(1).LoopSide(DataPlant::LoopSideLocation::Supply).SimLoopSideNeeded = false;
state->dataPlnt->PlantLoop(2).LoopSide(DataPlant::LoopSideLocation::Demand).SimLoopSideNeeded = false;
thisCoolingPLHP->simulate(*state, mySourceLocation, firstHVAC, curLoad, runFlag);
EXPECT_TRUE(state->dataPlnt->PlantLoop(2).LoopSide(DataPlant::LoopSideLocation::Demand).SimLoopSideNeeded);

// now we can call it again from the load side, but this time there is load (still firsthvac, unit can meet load)
{
firstHVAC = true;
curLoad = -1900;
runFlag = true;
Real64 constexpr expectedLoadMassFlowRate = 0.200;
state->dataLoopNodes->Node(thisCoolingPLHP->loadSideNodes.inlet).MassFlowRate = expectedLoadMassFlowRate;
state->dataLoopNodes->Node(thisCoolingPLHP->sourceSideNodes.inlet).MassFlowRate = expectedLoadMassFlowRate;
Real64 constexpr expectedCp = 4183;
Real64 constexpr specifiedLoadSetpoint = 15;
Real64 const calculatedLoadInletTemp = specifiedLoadSetpoint - curLoad / (expectedLoadMassFlowRate * expectedCp);
state->dataLoopNodes->Node(thisCoolingPLHP->loadSideNodes.outlet).TempSetPoint = specifiedLoadSetpoint;
state->dataLoopNodes->Node(thisCoolingPLHP->loadSideNodes.inlet).Temp = calculatedLoadInletTemp;
state->dataLoopNodes->Node(thisCoolingPLHP->sourceSideNodes.inlet).Temp = 45;
thisCoolingPLHP->maxSourceTempLimit = 50.0;
thisCoolingPLHP->simulate(*state, myLoadLocation, firstHVAC, curLoad, runFlag);
// expect it to meet setpoint and have some pre-evaluated conditions
EXPECT_NEAR(1.000, thisCoolingPLHP->partLoadRatio, 0.01);
EXPECT_NEAR(specifiedLoadSetpoint, thisCoolingPLHP->loadSideOutletTemp, 0.01);
EXPECT_NEAR(-curLoad, thisCoolingPLHP->loadSideHeatTransfer, 0.01);
EXPECT_NEAR(2471.583, thisCoolingPLHP->sourceSideHeatTransfer, 0.01);
EXPECT_NEAR(47.957, thisCoolingPLHP->sourceSideOutletTemp, 0.01);
}

// now we can call it again from the load side, but this time there is source side temperature limit exceeded
{
firstHVAC = true;
curLoad = -1900;
runFlag = true;
Real64 constexpr expectedLoadMassFlowRate = 0.200;
state->dataLoopNodes->Node(thisCoolingPLHP->loadSideNodes.inlet).MassFlowRate = expectedLoadMassFlowRate;
state->dataLoopNodes->Node(thisCoolingPLHP->sourceSideNodes.inlet).MassFlowRate = expectedLoadMassFlowRate;
Real64 constexpr expectedCp = 4183;
Real64 constexpr specifiedLoadSetpoint = 15;
Real64 const calculatedLoadInletTemp = specifiedLoadSetpoint - curLoad / (expectedLoadMassFlowRate * expectedCp);
state->dataLoopNodes->Node(thisCoolingPLHP->loadSideNodes.outlet).TempSetPoint = specifiedLoadSetpoint;
state->dataLoopNodes->Node(thisCoolingPLHP->loadSideNodes.inlet).Temp = calculatedLoadInletTemp;
state->dataLoopNodes->Node(thisCoolingPLHP->sourceSideNodes.inlet).Temp = 48;
thisCoolingPLHP->maxSourceTempLimit = 50.0;
thisCoolingPLHP->simulate(*state, myLoadLocation, firstHVAC, curLoad, runFlag);
// expect it to meet setpoint and have some pre-evaluated conditions
// reduced PLR to meet the source side outlet temperature limit specified
EXPECT_NEAR(0.68, thisCoolingPLHP->partLoadRatio, 0.01);
EXPECT_NEAR(15.73, thisCoolingPLHP->loadSideOutletTemp, 0.01);
EXPECT_NEAR(1285.38, thisCoolingPLHP->loadSideHeatTransfer, 0.01);
EXPECT_NEAR(386.69, thisCoolingPLHP->powerUsage, 0.01);
EXPECT_NEAR(1672.07, thisCoolingPLHP->loadSideHeatTransfer + thisCoolingPLHP->powerUsage, 0.01);
EXPECT_NEAR(1672.07, thisCoolingPLHP->sourceSideHeatTransfer, 0.01);
EXPECT_NEAR(50.0, thisCoolingPLHP->sourceSideOutletTemp, 0.01);
}
}
#pragma clang diagnostic pop
#pragma clang diagnostic pop

0 comments on commit 351c68d

Please sign in to comment.