Skip to content

Commit

Permalink
Merge pull request #10804 from NREL/New-plant-function-for-MaxLoad
Browse files Browse the repository at this point in the history
Add plant worker function to get current equipment capacity
  • Loading branch information
Myoldmopar authored Jan 10, 2025
2 parents b3ae9b9 + b39d24b commit cba2624
Show file tree
Hide file tree
Showing 9 changed files with 139 additions and 4 deletions.
74 changes: 73 additions & 1 deletion src/EnergyPlus/CondenserLoopTowers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
// ObjexxFCL Headers
#include <ObjexxFCL/Array.functions.hh>
#include <ObjexxFCL/Fmath.hh>
#include <ObjexxFCL/string.functions.hh>
// #include <ObjexxFCL/string.functions.hh>

// EnergyPlus Headers
#include <EnergyPlus/Autosizing/Base.hh>
Expand Down Expand Up @@ -6316,6 +6316,78 @@ namespace CondenserLoopTowers {
}
}

Real64 CoolingTower::getDynamicMaxCapacity(EnergyPlusData &state)
{
// TODO: does not include faults object impact
static constexpr std::string_view routineName("getDynamicMaxCapacity");
Real64 outletWaterTemp = 0.0;
Real64 constexpr designWetBulb = 25.56;
Real64 constexpr airFlowRateRatio = 1.0;
Real64 constexpr waterFlowRateRatio = 1.0;
Real64 const CpWater = state.dataPlnt->PlantLoop(this->plantLoc.loopNum)
.glycol->getSpecificHeat(state, state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp, routineName);
// use operating max (i.e., at current plant flow rates, could be 0 if plant is off) or max available capacity?
// Real64 waterMassFlowRate = state.dataLoopNodes->Node(this->WaterInletNodeNum).MassFlowRateMaxAvail;
Real64 waterMassFlowRate = this->DesWaterMassFlowRate;
this->AirWetBulb = (this->OutdoorAirInletNodeNum > 0) ? state.dataLoopNodes->Node(this->OutdoorAirInletNodeNum).OutAirWetBulb
: state.dataEnvrn->OutWetBulbTemp;

switch (this->TowerType) {
case DataPlant::PlantEquipmentType::CoolingTower_SingleSpd:
case DataPlant::PlantEquipmentType::CoolingTower_TwoSpd: {
// only needed for calculateSimpleTowerOutletTemp
this->AirTemp =
(this->OutdoorAirInletNodeNum > 0) ? state.dataLoopNodes->Node(this->OutdoorAirInletNodeNum).Temp : state.dataEnvrn->OutDryBulbTemp;
Real64 WaterMassFlowRatePerCell = waterMassFlowRate / this->NumCell;
Real64 UAdesign = this->HighSpeedTowerUA / this->NumCell; // could save these calculations in e.g., this->DesUAPerCell
Real64 AirFlowRate = this->HighSpeedAirFlowRate / this->NumCell;
outletWaterTemp = this->calculateSimpleTowerOutletTemp(state, WaterMassFlowRatePerCell, AirFlowRate, UAdesign);
} break;
case DataPlant::PlantEquipmentType::CoolingTower_VarSpd: {
Real64 TrCapped; // range temp passed to VS tower model
Real64 TaCapped; // approach temp passed to VS tower model
Real64 Twb = this->AirWetBulb;
Real64 TwbCapped = this->AirWetBulb;
// water temperature setpoint
Real64 TempSetPoint(0.0); // Outlet water temperature setpoint (C)
switch (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopDemandCalcScheme) {
case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
TempSetPoint = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopSide(this->plantLoc.loopSideNum).TempSetPoint;
} break;
case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
TempSetPoint = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopSide(this->plantLoc.loopSideNum).TempSetPointHi;
} break;
default: {
assert(false);
} break;
}
Real64 Tr = state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp - TempSetPoint;
Real64 Ta = TempSetPoint - this->AirWetBulb;
Real64 waterFlowRateRatioCapped = 0.0; // Water flow rate ratio passed to VS tower model
// check independent inputs with respect to model boundaries
this->checkModelBounds(state, Twb, Tr, Ta, waterFlowRateRatio, TwbCapped, TrCapped, TaCapped, waterFlowRateRatioCapped);
outletWaterTemp = this->calculateVariableTowerOutletTemp(state, waterFlowRateRatioCapped, airFlowRateRatio, TwbCapped);
} break;
case DataPlant::PlantEquipmentType::CoolingTower_VarSpdMerkel: {
// only needed for calculateSimpleTowerOutletTemp
this->AirTemp =
(this->OutdoorAirInletNodeNum > 0) ? state.dataLoopNodes->Node(this->OutdoorAirInletNodeNum).Temp : state.dataEnvrn->OutDryBulbTemp;
Real64 const UAdesignPerCell = this->HighSpeedTowerUA / this->NumCell;
Real64 const airFlowRatePerCell = this->HighSpeedAirFlowRate / this->NumCell;
Real64 const waterMassFlowRatePerCell = waterMassFlowRate / this->NumCell;
Real64 const WaterFlowRateRatio = waterMassFlowRatePerCell / this->DesWaterMassFlowRatePerCell; // this should always be 1 ?
Real64 const UAwetbulbAdjFac = Curve::CurveValue(state, this->UAModFuncWetBulbDiffCurvePtr, (designWetBulb - this->AirWetBulb));
Real64 const UAairflowAdjFac = Curve::CurveValue(state, this->UAModFuncAirFlowRatioCurvePtr, airFlowRateRatio);
Real64 const UAwaterflowAdjFac = Curve::CurveValue(state, this->UAModFuncWaterFlowRatioCurvePtr, WaterFlowRateRatio);
Real64 const UAadjustedPerCell = UAdesignPerCell * UAwetbulbAdjFac * UAairflowAdjFac * UAwaterflowAdjFac;
outletWaterTemp = this->calculateSimpleTowerOutletTemp(state, waterMassFlowRatePerCell, airFlowRatePerCell, UAadjustedPerCell);
} break;
default:
assert(false);
}
return waterMassFlowRate * CpWater * (state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp - outletWaterTemp);
}

} // namespace CondenserLoopTowers

} // namespace EnergyPlus
2 changes: 2 additions & 0 deletions src/EnergyPlus/CondenserLoopTowers.hh
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,8 @@ namespace CondenserLoopTowers {
void checkMassFlowAndLoad(EnergyPlusData &state, Real64 MyLoad, bool RunFlag, bool &returnFlagSet);

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

Real64 getDynamicMaxCapacity(EnergyPlusData &state) override;
};

void GetTowerInput(EnergyPlusData &state);
Expand Down
6 changes: 6 additions & 0 deletions src/EnergyPlus/Plant/Component.cc
Original file line number Diff line number Diff line change
Expand Up @@ -126,5 +126,11 @@ namespace DataPlant {
return state.dataPlnt->PlantLoop(plantLoc.loopNum).LoopSide(plantLoc.loopSideNum).Branch(plantLoc.branchNum).Comp(plantLoc.compNum);
}

Real64 CompData::getDynamicMaxCapacity(EnergyPlusData &state) const
{
if (this->compPtr == NULL) return this->MaxLoad;
Real64 possibleLoad = this->compPtr->getDynamicMaxCapacity(state);
return (possibleLoad == 0) ? this->MaxLoad : possibleLoad;
}
} // namespace DataPlant
} // namespace EnergyPlus
2 changes: 2 additions & 0 deletions src/EnergyPlus/Plant/Component.hh
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,8 @@ namespace DataPlant {
void oneTimeInit(EnergyPlusData &state) const;

static CompData &getPlantComponent(EnergyPlusData &state, PlantLocation const &plantLoc);

Real64 getDynamicMaxCapacity(EnergyPlusData &state) const;
};
} // namespace DataPlant
} // namespace EnergyPlus
Expand Down
5 changes: 5 additions & 0 deletions src/EnergyPlus/PlantComponent.hh
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ public:
{
}

virtual Real64 getDynamicMaxCapacity([[maybe_unused]] EnergyPlusData &state)
{
return 0.0;
}

virtual void getCurrentPower([[maybe_unused]] EnergyPlusData &state, [[maybe_unused]] Real64 &power)
{
}
Expand Down
4 changes: 2 additions & 2 deletions src/EnergyPlus/PlantCondLoopOperation.cc
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ using HVAC::SmallLoad;

void ManagePlantLoadDistribution(EnergyPlusData &state,
PlantLocation const &plantLoc, // PlantLoop data structure Location struct
Real64 &LoopDemand,
Real64 const LoopDemand,
Real64 &RemLoopDemand,
bool const FirstHVACIteration,
bool &LoopShutDownFlag, // EMS flag to tell loop solver to shut down pumps
Expand Down Expand Up @@ -3659,7 +3659,7 @@ void FindCompSPLoad(EnergyPlusData &state,

// load local variables from the data structures
CompMinLoad = this_component.MinLoad;
CompMaxLoad = this_component.MaxLoad;
CompMaxLoad = this_component.getDynamicMaxCapacity(state);
CompOptLoad = this_component.OptLoad;
DemandNode = state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(OpSchemePtr).EquipList(ListPtr).Comp(CompPtr).DemandNodeNum;
SetPtNode = state.dataPlnt->PlantLoop(plantLoc.loopNum).OpScheme(OpSchemePtr).EquipList(ListPtr).Comp(CompPtr).SetPointNodeNum;
Expand Down
2 changes: 1 addition & 1 deletion src/EnergyPlus/PlantCondLoopOperation.hh
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ namespace PlantCondLoopOperation {

void ManagePlantLoadDistribution(EnergyPlusData &state,
PlantLocation const &plantLoc, // PlantLoop data structure Location struct
Real64 &LoopDemand,
Real64 const LoopDemand,
Real64 &RemLoopDemand,
bool const FirstHVACIteration,
bool &LoopShutDownFlag, // EMS flag to tell loop solver to shut down pumps
Expand Down
45 changes: 45 additions & 0 deletions src/EnergyPlus/PlantLoopHeatPumpEIR.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2444,6 +2444,15 @@ bool EIRPlantLoopHeatPump::thermosiphonDisabled(EnergyPlusData &state)
}
}

Real64 EIRPlantLoopHeatPump::getDynamicMaxCapacity(EnergyPlusData &state)
{
Real64 sourceInletTemp = state.dataLoopNodes->Node(this->sourceSideNodes.inlet).Temp;
Real64 loadSideOutletSetpointTemp = this->getLoadSideOutletSetPointTemp(state);
// evaluate capacity modifier curve and determine load side heat transfer
Real64 capacityModifierFuncTemp = Curve::CurveValue(state, this->capFuncTempCurveIndex, loadSideOutletSetpointTemp, sourceInletTemp);
return this->referenceCapacity * capacityModifierFuncTemp * heatingCapacityModifierASHP(state);
}

void EIRPlantLoopHeatPump::report(EnergyPlusData &state)
{

Expand Down Expand Up @@ -3697,4 +3706,40 @@ void EIRFuelFiredHeatPump::report(EnergyPlusData &state)
state.dataLoopNodes->Node(this->sourceSideNodes.outlet).Temp = this->sourceSideOutletTemp;
}

Real64 EIRFuelFiredHeatPump::getDynamicMaxCapacity(EnergyPlusData &state)
{
// Source (air) side temperature variable
auto &thisSourceSideInletNode = state.dataLoopNodes->Node(this->sourceSideNodes.inlet);
Real64 oaTempforCurve =
(this->oaTempCurveInputVar == OATempCurveVar::WetBulb)
? Psychrometrics::PsyTwbFnTdbWPb(
state, thisSourceSideInletNode.Temp, thisSourceSideInletNode.HumRat, thisSourceSideInletNode.Press, "PLFFHPEIR::doPhysics()")
: thisSourceSideInletNode.Temp;

// Load (water) side temperature variable
Real64 waterTempforCurve = state.dataLoopNodes->Node(this->loadSideNodes.inlet).Temp;
if (this->waterTempCurveInputVar == WaterTempCurveVar::LeavingCondenser || this->waterTempCurveInputVar == WaterTempCurveVar::LeavingEvaporator) {
if (this->flowMode == DataPlant::FlowMode::LeavingSetpointModulated) {
DataPlant::PlantLoopData &thisLoadPlantLoop = state.dataPlnt->PlantLoop(this->loadSidePlantLoc.loopNum);
auto &thisLoadSideOutletNode = state.dataLoopNodes->Node(this->loadSideNodes.outlet);
if (thisLoadPlantLoop.LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::SingleSetPoint) {
waterTempforCurve = thisLoadSideOutletNode.TempSetPoint;
} else {
if (this->EIRHPType == DataPlant::PlantEquipmentType::HeatPumpFuelFiredCooling) {
waterTempforCurve = thisLoadSideOutletNode.TempSetPointHi;
} else {
waterTempforCurve = thisLoadSideOutletNode.TempSetPointLo;
}
}
} else {
// If not SP modulated then use actual outlet temp from last iteration?
waterTempforCurve = state.dataLoopNodes->Node(this->loadSideNodes.outlet).Temp;
}
}

// evaluate capacity modifier curve and determine load side heat transfer
Real64 capacityModifierFuncTemp = Curve::CurveValue(state, this->capFuncTempCurveIndex, waterTempforCurve, oaTempforCurve);
return this->referenceCapacity * capacityModifierFuncTemp;
}

} // namespace EnergyPlus::EIRPlantLoopHeatPumps
3 changes: 3 additions & 0 deletions src/EnergyPlus/PlantLoopHeatPumpEIR.hh
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,8 @@ namespace EIRPlantLoopHeatPumps {
void oneTimeInit(EnergyPlusData &state) override;

bool thermosiphonDisabled(EnergyPlusData &state);

Real64 getDynamicMaxCapacity(EnergyPlusData &state) override;
};

struct EIRFuelFiredHeatPump : public EIRPlantLoopHeatPump
Expand Down Expand Up @@ -418,6 +420,7 @@ namespace EIRPlantLoopHeatPumps {
static void processInputForEIRPLHP(EnergyPlusData &state);
void oneTimeInit(EnergyPlusData &state);

Check warning on line 421 in src/EnergyPlus/PlantLoopHeatPumpEIR.hh

View workflow job for this annotation

GitHub Actions / Standard Build on Mac arm64

'oneTimeInit' overrides a member function but is not marked 'override' [-Winconsistent-missing-override]
void report(EnergyPlusData &state);

Check warning on line 422 in src/EnergyPlus/PlantLoopHeatPumpEIR.hh

View workflow job for this annotation

GitHub Actions / Standard Build on Mac arm64

'report' overrides a member function but is not marked 'override' [-Winconsistent-missing-override]
Real64 getDynamicMaxCapacity(EnergyPlusData &state) override;

// New or specialized functions for derived struct
virtual ~EIRFuelFiredHeatPump() = default;
Expand Down

3 comments on commit cba2624

@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-24.04-gcc-13.3: OK (2919 of 2919 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-24.04-gcc-13.3-UnitTestsCoverage-RelWithDebInfo: OK (2101 of 2101 tests passed, 0 test warnings)

Build Badge Test Badge Coverage 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-24.04-gcc-13.3-IntegrationCoverage-RelWithDebInfo: OK (801 of 801 tests passed, 0 test warnings)

Build Badge Test Badge Coverage Badge

Please sign in to comment.