Skip to content

Commit dfa3d53

Browse files
authored
Merge pull request #11068 from NREL/fix_gahp_flow
Fix GAHP flow request
2 parents 951d0fc + 3945b70 commit dfa3d53

File tree

3 files changed

+127
-187
lines changed

3 files changed

+127
-187
lines changed

src/EnergyPlus/PlantLoopHeatPumpEIR.cc

Lines changed: 78 additions & 170 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ void EIRPlantLoopHeatPump::simulate(
120120
}
121121
} else if (this->airSource) {
122122
this->setHeatRecoveryOperatingStatusASHP(state, FirstHVACIteration);
123-
this->setOperatingFlowRatesASHP(state, FirstHVACIteration);
123+
this->setOperatingFlowRatesASHP(state, FirstHVACIteration, CurLoad);
124124

125125
if (calledFromLocation.loopNum == this->heatRecoveryPlantLoc.loopNum) {
126126
if (this->heatRecoveryAvailable) {
@@ -245,7 +245,7 @@ void EIRPlantLoopHeatPump::setOperatingFlowRatesWSHP(EnergyPlusData &state, bool
245245
this->sourceSideMassFlowRate = (this->heatRecoveryHeatPump) ? state.dataLoopNodes->Node(this->sourceSideNodes.inlet).MassFlowRate
246246
: this->sourceSideDesignMassFlowRate;
247247

248-
if (!FirstHVACIteration && this->flowControl == DataPlant::FlowMode::VariableSpeedPump) {
248+
if (!FirstHVACIteration && this->flowMode == DataPlant::FlowMode::VariableSpeedPump) {
249249
if ((this->loadVSBranchPump || this->loadVSLoopPump) && !this->heatRecoveryHeatPump) {
250250
this->loadSideMassFlowRate *= std::max(this->partLoadRatio, this->minimumPLR);
251251
if (this->loadVSBranchPump) {
@@ -285,7 +285,7 @@ void EIRPlantLoopHeatPump::setOperatingFlowRatesWSHP(EnergyPlusData &state, bool
285285
}
286286
}
287287

288-
void EIRPlantLoopHeatPump::setOperatingFlowRatesASHP(EnergyPlusData &state, bool FirstHVACIteration)
288+
void EIRPlantLoopHeatPump::setOperatingFlowRatesASHP(EnergyPlusData &state, bool FirstHVACIteration, Real64 const currentLoad)
289289
{
290290
if (!this->running) {
291291
this->loadSideMassFlowRate = 0.0;
@@ -317,7 +317,7 @@ void EIRPlantLoopHeatPump::setOperatingFlowRatesASHP(EnergyPlusData &state, bool
317317
this->loadSideMassFlowRate = this->loadSideDesignMassFlowRate;
318318
this->sourceSideMassFlowRate = this->sourceSideDesignMassFlowRate;
319319

320-
if (!FirstHVACIteration && this->flowControl == DataPlant::FlowMode::VariableSpeedPump) {
320+
if (!FirstHVACIteration && this->flowMode == DataPlant::FlowMode::VariableSpeedPump) {
321321
if (this->loadVSBranchPump || this->loadVSLoopPump) {
322322
this->loadSideMassFlowRate *= std::max(this->partLoadRatio, this->minimumPLR);
323323
if (this->loadVSBranchPump) {
@@ -361,6 +361,72 @@ void EIRPlantLoopHeatPump::setOperatingFlowRatesASHP(EnergyPlusData &state, bool
361361
}
362362
}
363363

364+
void EIRFuelFiredHeatPump::setOperatingFlowRatesASHP(EnergyPlusData &state, bool FirstHVACIteration, Real64 const currentLoad)
365+
{
366+
if (!this->running) {
367+
this->loadSideMassFlowRate = 0.0;
368+
this->sourceSideMassFlowRate = 0.0;
369+
PlantUtilities::SetComponentFlowRate(
370+
state, this->loadSideMassFlowRate, this->loadSideNodes.inlet, this->loadSideNodes.outlet, this->loadSidePlantLoc);
371+
if (this->heatRecoveryAvailable) {
372+
// set the HR flow to zero if the heat pump is off
373+
this->heatRecoveryMassFlowRate = 0.0;
374+
PlantUtilities::SetComponentFlowRate(
375+
state, this->heatRecoveryMassFlowRate, this->heatRecoveryNodes.inlet, this->heatRecoveryNodes.outlet, this->heatRecoveryPlantLoc);
376+
}
377+
} else { // the heat pump must run
378+
this->loadSideMassFlowRate = this->loadSideDesignMassFlowRate;
379+
this->sourceSideMassFlowRate = this->sourceSideDesignMassFlowRate;
380+
381+
if (!FirstHVACIteration && this->flowMode == DataPlant::FlowMode::LeavingSetpointModulated) {
382+
auto &thisInletNode = state.dataLoopNodes->Node(this->loadSideNodes.inlet);
383+
auto &thisOutletNode = state.dataLoopNodes->Node(this->loadSideNodes.outlet);
384+
Real64 FFHPDeltaTemp = 0.0;
385+
Real64 CpLoad = this->loadSidePlantLoc.loop->glycol->getSpecificHeat(state, thisInletNode.Temp, "PLFFHPEIR::simulate()");
386+
if (this->EIRHPType == DataPlant::PlantEquipmentType::HeatPumpFuelFiredHeating) {
387+
if (this->loadSidePlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::SingleSetPoint) {
388+
FFHPDeltaTemp = thisOutletNode.TempSetPoint - thisInletNode.Temp;
389+
} else { // DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand
390+
FFHPDeltaTemp = thisOutletNode.TempSetPointLo - thisInletNode.Temp;
391+
}
392+
this->loadSideOutletTemp = FFHPDeltaTemp + thisInletNode.Temp;
393+
if ((FFHPDeltaTemp > 0.0) && currentLoad > 0.0) {
394+
this->loadSideMassFlowRate = currentLoad / (CpLoad * FFHPDeltaTemp);
395+
this->loadSideMassFlowRate = min(this->loadSideDesignMassFlowRate, this->loadSideMassFlowRate);
396+
} else {
397+
this->loadSideOutletTemp = thisInletNode.Temp;
398+
this->loadSideMassFlowRate = 0.0;
399+
}
400+
} else if (this->EIRHPType == DataPlant::PlantEquipmentType::HeatPumpFuelFiredCooling) {
401+
if (this->loadSidePlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::SingleSetPoint) {
402+
FFHPDeltaTemp = thisInletNode.Temp - thisOutletNode.TempSetPoint;
403+
} else { // DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand
404+
FFHPDeltaTemp = thisInletNode.Temp - thisOutletNode.TempSetPointHi;
405+
}
406+
this->loadSideOutletTemp = thisInletNode.Temp - FFHPDeltaTemp;
407+
if ((FFHPDeltaTemp > 0.0) && std::abs(currentLoad) > 0.0) {
408+
this->loadSideMassFlowRate = std::abs(currentLoad) / (CpLoad * FFHPDeltaTemp);
409+
this->loadSideMassFlowRate = min(this->loadSideDesignMassFlowRate, this->loadSideMassFlowRate);
410+
} else {
411+
this->loadSideOutletTemp = thisInletNode.Temp;
412+
this->loadSideMassFlowRate = 0.0;
413+
}
414+
}
415+
}
416+
PlantUtilities::SetComponentFlowRate(
417+
state, this->loadSideMassFlowRate, this->loadSideNodes.inlet, this->loadSideNodes.outlet, this->loadSidePlantLoc);
418+
419+
// if there's no flow in one, try to turn the entire heat pump off
420+
if (this->loadSideMassFlowRate <= 0.0) {
421+
this->loadSideMassFlowRate = 0.0;
422+
this->sourceSideMassFlowRate = 0.0;
423+
this->running = false;
424+
PlantUtilities::SetComponentFlowRate(
425+
state, this->loadSideMassFlowRate, this->loadSideNodes.inlet, this->loadSideNodes.outlet, this->loadSidePlantLoc);
426+
}
427+
}
428+
}
429+
364430
void EIRPlantLoopHeatPump::doPhysics(EnergyPlusData &state, Real64 currentLoad)
365431
{
366432
// ideally the plant is going to ensure that we don't have a runflag=true when the load is invalid, but
@@ -963,7 +1029,7 @@ void EIRPlantLoopHeatPump::onInitLoopEquip(EnergyPlusData &state, [[maybe_unused
9631029
}
9641030
}
9651031

966-
if (this->flowControl == DataPlant::FlowMode::VariableSpeedPump) {
1032+
if (this->flowMode == DataPlant::FlowMode::VariableSpeedPump) {
9671033
this->loadVSPumpMinLimitMassFlow =
9681034
PlantUtilities::MinFlowIfBranchHasVSPump(state, this->loadSidePlantLoc, this->loadVSBranchPump, this->loadVSLoopPump, true);
9691035
if (this->waterSource) {
@@ -1777,9 +1843,9 @@ void EIRPlantLoopHeatPump::processInputForEIRPLHP(EnergyPlusData &state)
17771843
fields, schemaProps, "thermosiphon_minimum_temperature_difference");
17781844
}
17791845

1780-
std::string flowControlTypeName =
1846+
std::string flowModeTypeName =
17811847
Util::makeUPPER(state.dataInputProcessing->inputProcessor->getAlphaFieldValue(fields, schemaProps, "flow_mode"));
1782-
thisPLHP.flowControl = static_cast<DataPlant::FlowMode>(getEnumValue(DataPlant::FlowModeNamesUC, flowControlTypeName));
1848+
thisPLHP.flowMode = static_cast<DataPlant::FlowMode>(getEnumValue(DataPlant::FlowModeNamesUC, flowModeTypeName));
17831849

17841850
// fields only in heating object
17851851
if (thisPLHP.EIRHPType == DataPlant::PlantEquipmentType::HeatPumpEIRHeating) {
@@ -2521,160 +2587,6 @@ void EIRFuelFiredHeatPump::doPhysics(EnergyPlusData &state, Real64 currentLoad)
25212587
// Set the current load equal to the FFHP load
25222588
Real64 FFHPloadSideLoad = currentLoad; // this->loadSidePlantLoad = MyLoad;
25232589

2524-
if (this->EIRHPType == DataPlant::PlantEquipmentType::HeatPumpFuelFiredHeating) {
2525-
2526-
// Initialize the delta temperature to zero
2527-
Real64 FFHPDeltaTemp = 0.0; // C - FFHP inlet to outlet temperature difference, set in all necessary code paths so no initialization required
2528-
2529-
if (this->loadSidePlantLoc.side->FlowLock == DataPlant::FlowLock::Unlocked) {
2530-
// Either set the flow to the Constant value or calculate the flow for the variable volume
2531-
if (this->flowMode == DataPlant::FlowMode::Constant) {
2532-
// Then find the flow rate and outlet temp
2533-
this->loadSideMassFlowRate = this->loadSideDesignMassFlowRate;
2534-
PlantUtilities::SetComponentFlowRate(
2535-
state, this->loadSideMassFlowRate, this->loadSideNodes.inlet, this->loadSideNodes.outlet, this->loadSidePlantLoc);
2536-
2537-
if ((this->loadSideMassFlowRate != 0.0) &&
2538-
((this->EIRHPType == DataPlant::PlantEquipmentType::HeatPumpFuelFiredHeating && currentLoad > 0.0))) {
2539-
FFHPDeltaTemp = currentLoad / (this->loadSideMassFlowRate * CpLoad);
2540-
} else {
2541-
FFHPDeltaTemp = 0.0;
2542-
}
2543-
this->loadSideOutletTemp = FFHPDeltaTemp + thisInletNode.Temp;
2544-
2545-
} else if (this->flowMode == DataPlant::FlowMode::LeavingSetpointModulated) {
2546-
// Calculate the Delta Temp from the inlet temp to the FFHP outlet setpoint
2547-
// Then find the flow rate and outlet temp
2548-
2549-
if (this->loadSidePlantLoc.loop->LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::SingleSetPoint) {
2550-
FFHPDeltaTemp = thisOutletNode.TempSetPoint - thisInletNode.Temp;
2551-
} else { // DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand
2552-
FFHPDeltaTemp = thisOutletNode.TempSetPointLo - thisInletNode.Temp;
2553-
}
2554-
2555-
this->loadSideOutletTemp = FFHPDeltaTemp + thisInletNode.Temp;
2556-
2557-
if ((FFHPDeltaTemp > 0.0) && ((this->EIRHPType == DataPlant::PlantEquipmentType::HeatPumpFuelFiredHeating && currentLoad > 0.0))) {
2558-
this->loadSideMassFlowRate = currentLoad / (CpLoad * FFHPDeltaTemp);
2559-
this->loadSideMassFlowRate = min(this->loadSideDesignMassFlowRate, this->loadSideMassFlowRate);
2560-
} else {
2561-
this->loadSideMassFlowRate = 0.0;
2562-
}
2563-
PlantUtilities::SetComponentFlowRate(
2564-
state, this->loadSideMassFlowRate, this->loadSideNodes.inlet, this->loadSideNodes.outlet, this->loadSidePlantLoc);
2565-
2566-
} // End of Constant/Variable Flow If Block
2567-
} else { // If FlowLock is True
2568-
// Set the boiler flow rate from inlet node and then check performance
2569-
this->loadSideMassFlowRate = thisInletNode.MassFlowRate;
2570-
2571-
if ((this->loadSideMassFlowRate > 0.0) &&
2572-
((this->EIRHPType == DataPlant::PlantEquipmentType::HeatPumpFuelFiredHeating && currentLoad > 0.0))) { // this FFHP has a heat load
2573-
// FFHPloadSideLoad = currentLoad;
2574-
// if (FFHPloadSideLoad > this->referenceCapacity * this->maxPLR) FFHPloadSideLoad = this->referenceCapacity * this->maxPLR;
2575-
// if (FFHPloadSideLoad < this->referenceCapacity * this->minPLR) FFHPloadSideLoad = this->referenceCapacity * this->minPLR;
2576-
FFHPloadSideLoad = std::clamp(FFHPloadSideLoad, this->referenceCapacity * this->minPLR, this->referenceCapacity * this->maxPLR);
2577-
this->loadSideOutletTemp = thisInletNode.Temp + FFHPloadSideLoad / (this->loadSideMassFlowRate * CpLoad);
2578-
} else {
2579-
FFHPloadSideLoad = 0.0;
2580-
this->loadSideOutletTemp = thisInletNode.Temp;
2581-
}
2582-
}
2583-
} else if (this->EIRHPType == DataPlant::PlantEquipmentType::HeatPumpFuelFiredCooling) {
2584-
if (this->loadSidePlantLoc.side->FlowLock == DataPlant::FlowLock::Unlocked) {
2585-
// this->PossibleSubcooling =
2586-
// !(state.dataPlnt->PlantLoop(PlantLoopNum).LoopSide(LoopSideNum).Branch(BranchNum).Comp(CompNum).CurOpSchemeType ==
2587-
// DataPlant::OpScheme::CompSetPtBased);
2588-
Real64 evapDeltaTemp = 0.0; // Evaporator temperature difference [C]
2589-
2590-
// Either set the flow to the Constant value or calculate the flow for the variable volume case
2591-
if (this->flowMode == DataPlant::FlowMode::Constant) {
2592-
// Set the evaporator mass flow rate to design
2593-
// Start by assuming max (design) flow
2594-
this->loadSideMassFlowRate = this->loadSideDesignMassFlowRate;
2595-
// Use PlantUtilities::SetComponentFlowRate to decide actual flow
2596-
PlantUtilities::SetComponentFlowRate(
2597-
state, this->loadSideMassFlowRate, this->loadSideNodes.inlet, this->loadSideNodes.outlet, this->loadSidePlantLoc);
2598-
if (this->loadSideMassFlowRate != 0.0) {
2599-
evapDeltaTemp = std::abs(currentLoad) / (this->loadSideMassFlowRate * CpLoad); // MyLoad = net evaporator capacity, QEvaporator
2600-
} else {
2601-
evapDeltaTemp = 0.0;
2602-
}
2603-
this->loadSideOutletTemp = thisInletNode.Temp - evapDeltaTemp;
2604-
} else if (this->flowMode == DataPlant::FlowMode::LeavingSetpointModulated) {
2605-
switch (this->loadSidePlantLoc.loop->LoopDemandCalcScheme) {
2606-
case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
2607-
// Calculate the Delta Temp from the inlet temp to the chiller outlet setpoint
2608-
evapDeltaTemp = thisInletNode.Temp - thisOutletNode.TempSetPoint;
2609-
} break;
2610-
case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
2611-
evapDeltaTemp = thisInletNode.Temp - thisOutletNode.TempSetPointHi;
2612-
} break;
2613-
default: {
2614-
assert(false);
2615-
} break;
2616-
}
2617-
2618-
if (evapDeltaTemp != 0) {
2619-
this->loadSideMassFlowRate = max(0.0, (std::abs(currentLoad) / (CpLoad * evapDeltaTemp)));
2620-
// Check to see if the Maximum is exceeded, if so set to maximum
2621-
this->loadSideMassFlowRate = min(this->loadSideDesignMassFlowRate, this->loadSideMassFlowRate);
2622-
// Use PlantUtilities::SetComponentFlowRate to decide actual flow
2623-
PlantUtilities::SetComponentFlowRate(
2624-
state, this->loadSideMassFlowRate, this->loadSideNodes.inlet, this->loadSideNodes.outlet, this->loadSidePlantLoc);
2625-
// Should we recalculate this with the corrected setpoint?
2626-
switch (this->loadSidePlantLoc.loop->LoopDemandCalcScheme) {
2627-
case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
2628-
this->loadSideOutletTemp = thisOutletNode.TempSetPoint;
2629-
} break;
2630-
case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
2631-
this->loadSideOutletTemp = thisOutletNode.TempSetPointHi;
2632-
} break;
2633-
default:
2634-
break;
2635-
}
2636-
} else {
2637-
// Try to request zero flow
2638-
this->loadSideMassFlowRate = 0.0;
2639-
// Use PlantUtilities::SetComponentFlowRate to decide actual flow
2640-
PlantUtilities::SetComponentFlowRate(
2641-
state, this->loadSideMassFlowRate, this->loadSideNodes.inlet, this->loadSideNodes.outlet, this->loadSidePlantLoc);
2642-
// No deltaT since component is not running
2643-
this->loadSideOutletTemp = thisInletNode.Temp;
2644-
// this->QEvaporator = 0.0;
2645-
// PartLoadRat = 0.0;
2646-
// this->ChillerPartLoadRatio = 0.0;
2647-
2648-
// if (this->DeltaTErrCount < 1 && !state.dataGlobal->WarmupFlag) {
2649-
if (!state.dataGlobal->WarmupFlag) {
2650-
// ++this->DeltaTErrCount;
2651-
ShowWarningError(state, "FFHP evaporator DeltaTemp = 0 in mass flow calculation (Tevapin = Tevapout setpoint temp).");
2652-
ShowContinueErrorTimeStamp(state, "");
2653-
// } else if (!state.dataGlobal->WarmupFlag) {
2654-
// ++this->ChillerCapFTError;
2655-
ShowWarningError( // RecurringWarningErrorAtEnd(
2656-
state,
2657-
format("{} \"{}\": FFHP evaporator DeltaTemp = 0 in mass flow calculation warning continues...",
2658-
DataPlant::PlantEquipTypeNames[static_cast<int>(this->EIRHPType)],
2659-
this->name));
2660-
// this->DeltaTErrCountIndex,
2661-
// evapDeltaTemp,
2662-
// evapDeltaTemp);
2663-
}
2664-
}
2665-
}
2666-
} else { // If FlowLock is True
2667-
this->loadSideMassFlowRate = thisInletNode.MassFlowRate;
2668-
PlantUtilities::SetComponentFlowRate(
2669-
state, this->loadSideMassFlowRate, this->loadSideNodes.inlet, this->loadSideNodes.outlet, this->loadSidePlantLoc);
2670-
// Some other component set the flow to 0. No reason to continue with calculations.
2671-
if (this->loadSideMassFlowRate == 0.0) {
2672-
FFHPloadSideLoad = 0.0;
2673-
// return;
2674-
}
2675-
} // This is the end of the FlowLock Block
2676-
}
2677-
26782590
// Determine which air variable to use for GAHP:
26792591
// Source (air) side variable to use
26802592
// auto &thisloadsideinletnode = state.dataLoopNodes->Node(this->loadSideNodes.inlet);
@@ -2879,17 +2791,13 @@ void EIRFuelFiredHeatPump::doPhysics(EnergyPlusData &state, Real64 currentLoad)
28792791
eirAuxElecFuncPLR = 0.0;
28802792
}
28812793

2882-
if (partLoadRatio < this->minPLR) {
2883-
this->fuelRate = 0.0;
2884-
this->powerUsage = 0.0;
2885-
} else {
2886-
this->fuelRate = this->loadSideHeatTransfer / (this->referenceCOP * CRF) * eirModifierFuncPLR * eirModifierFuncTemp * eirDefrost;
2794+
this->fuelRate = this->loadSideHeatTransfer / (this->referenceCOP * CRF) * eirModifierFuncPLR * eirModifierFuncTemp * eirDefrost;
28872795

2888-
this->powerUsage = this->nominalAuxElecPower * eirAuxElecFuncTemp * eirAuxElecFuncPLR;
2889-
if (this->defrostType == DefrostType::Timed) {
2890-
this->powerUsage += this->defrostResistiveHeaterCap * this->defrostOpTimeFrac * reportingInterval;
2891-
}
2796+
this->powerUsage = this->nominalAuxElecPower * eirAuxElecFuncTemp * eirAuxElecFuncPLR;
2797+
if (this->defrostType == DefrostType::Timed) {
2798+
this->powerUsage += this->defrostResistiveHeaterCap * this->defrostOpTimeFrac;
28922799
}
2800+
28932801
this->powerUsage += this->standbyElecPower;
28942802

28952803
// energy balance on heat pump

0 commit comments

Comments
 (0)