Skip to content
Open
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
2 changes: 2 additions & 0 deletions src/EnergyPlus/ChillerElectricEIR.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1145,6 +1145,8 @@ void ElectricEIRChillerSpecs::oneTimeInit(EnergyPlusData &state)
if (this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) {
// reset flow priority
DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).FlowPriority = DataPlant::LoopFlowStatus::NeedyIfLoopOn;
// this chiller sets its own evaporator flow rate to hold the leaving setpoint
DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).ModulatedFlow = true;
// check if setpoint on outlet node
if ((state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint == Node::SensedNodeFlagValue) &&
(state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi == Node::SensedNodeFlagValue)) {
Expand Down
2 changes: 2 additions & 0 deletions src/EnergyPlus/ChillerIndirectAbsorption.cc
Original file line number Diff line number Diff line change
Expand Up @@ -833,6 +833,8 @@ void IndirectAbsorberSpecs::oneTimeInit(EnergyPlusData &state)
if (this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) {
// reset flow priority
this->CWPlantLoc.comp->FlowPriority = DataPlant::LoopFlowStatus::NeedyIfLoopOn;
// this chiller sets its own evaporator flow rate to hold the leaving setpoint
this->CWPlantLoc.comp->ModulatedFlow = true;

if ((state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint == Node::SensedNodeFlagValue) &&
(state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi == Node::SensedNodeFlagValue)) {
Expand Down
2 changes: 2 additions & 0 deletions src/EnergyPlus/ChillerReformulatedEIR.cc
Original file line number Diff line number Diff line change
Expand Up @@ -936,6 +936,8 @@ void ReformulatedEIRChillerSpecs::oneTimeInit(EnergyPlusData &state)
if (this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) {
// reset flow priority
DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).FlowPriority = DataPlant::LoopFlowStatus::NeedyIfLoopOn;
// this chiller sets its own evaporator flow rate to hold the leaving setpoint
DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).ModulatedFlow = true;
// check if setpoint on outlet node
if ((state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint == Node::SensedNodeFlagValue) &&
(state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi == Node::SensedNodeFlagValue)) {
Expand Down
3 changes: 2 additions & 1 deletion src/EnergyPlus/Plant/Component.hh
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@ namespace DataPlant {
DataPlant::HowMet HowLoadServed; // nature of component in terms of how it can meet load
Real64 MinOutletTemp; // Component exit lower limit temperature
Real64 MaxOutletTemp; // Component exit upper limit temperature
bool ModulatedFlow; // true if this component modulates its own flow to hold a leaving setpoint
bool FreeCoolCntrlShutDown; // true if component was shut down because of free cooling
Real64 FreeCoolCntrlMinCntrlTemp; // current control temp value for free cooling controls
DataPlant::FreeCoolControlMode FreeCoolCntrlMode; // type of sensor used for free cooling controls
Expand All @@ -325,7 +326,7 @@ namespace DataPlant {
FlowPriority(LoopFlowStatus::Invalid), ON(false), Available(false), NodeNumIn(0), NodeNumOut(0), MyLoad(0.0), MaxLoad(0.0),
MinLoad(0.0), OptLoad(0.0), SizFac(0.0), CurOpSchemeType(DataPlant::OpScheme::Invalid), NumOpSchemes(0), CurCompLevelOpNum(0),
EquipDemand(0.0), EMSLoadOverrideOn(false), EMSLoadOverrideValue(0.0), HowLoadServed(DataPlant::HowMet::Invalid), MinOutletTemp(0.0),
MaxOutletTemp(0.0), FreeCoolCntrlShutDown(false), FreeCoolCntrlMinCntrlTemp(0.0),
MaxOutletTemp(0.0), ModulatedFlow(false), FreeCoolCntrlShutDown(false), FreeCoolCntrlMinCntrlTemp(0.0),
FreeCoolCntrlMode(DataPlant::FreeCoolControlMode::Invalid), FreeCoolCntrlNodeNum(0), IndexInLoopSidePumps(0), TempDesCondIn(0.0),
TempDesEvapOut(0.0), compPtr(nullptr)
{
Expand Down
6 changes: 6 additions & 0 deletions src/EnergyPlus/PlantChillers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2082,6 +2082,8 @@ namespace PlantChillers {
if (this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) {
// reset flow priority
DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).FlowPriority = DataPlant::LoopFlowStatus::NeedyIfLoopOn;
// this chiller sets its own evaporator flow rate to hold the leaving setpoint
DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).ModulatedFlow = true;

// check if setpoint on outlet node
if ((state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint == Node::SensedNodeFlagValue) &&
Expand Down Expand Up @@ -4145,6 +4147,8 @@ namespace PlantChillers {
if (this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) {
// reset flow priority
DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).FlowPriority = DataPlant::LoopFlowStatus::NeedyIfLoopOn;
// this chiller sets its own evaporator flow rate to hold the leaving setpoint
DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).ModulatedFlow = true;
// check if setpoint on outlet node
if ((state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint == Node::SensedNodeFlagValue) &&
(state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi == Node::SensedNodeFlagValue)) {
Expand Down Expand Up @@ -6106,6 +6110,8 @@ namespace PlantChillers {
if (this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) {
// reset flow priority
DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).FlowPriority = DataPlant::LoopFlowStatus::NeedyIfLoopOn;
// this chiller sets its own evaporator flow rate to hold the leaving setpoint
DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).ModulatedFlow = true;

// check if setpoint on outlet node
if ((state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint == Node::SensedNodeFlagValue) &&
Expand Down
10 changes: 9 additions & 1 deletion src/EnergyPlus/PlantCondLoopOperation.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3604,6 +3604,12 @@ void AdjustChangeInLoadByHowServed(EnergyPlusData &state,

//- Retrieve data from the plant loop data structure
CurMassFlowRate = state.dataLoopNodes->Node(this_component.NodeNumIn).MassFlowRate;
// A component in a modulated flow mode controls its own flow rate to hold the leaving setpoint, so it can raise
// its flow up to whatever the branch can deliver. Judging its capacity by the current flow, which may still be
// sitting at the branch pump minimum, understates it and spills load onto the next machine in the list.
if (this_component.ModulatedFlow) {
CurMassFlowRate = max(CurMassFlowRate, state.dataLoopNodes->Node(this_component.NodeNumIn).MassFlowRateMaxAvail);
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

You could add an else here and avoid setting CurMassFlowRate twice (i.e., move line 3606 to the else at 3612 since the conditional at line 3610 will always execute).

ToutLowLimit = this_component.MinOutletTemp;
Tinlet = state.dataLoopNodes->Node(this_component.NodeNumIn).Temp;
CurSpecHeat = plantLoc.loop->glycol->getSpecificHeat(state, Tinlet, RoutineName);
Expand Down Expand Up @@ -3688,11 +3694,13 @@ void AdjustChangeInLoadByHowServed(EnergyPlusData &state,
this_component.Available = true;
this_component.FreeCoolCntrlShutDown = false;
CurMassFlowRate = state.dataLoopNodes->Node(this_component.NodeNumIn).MassFlowRate;
if (this_component.ModulatedFlow) {
CurMassFlowRate = max(CurMassFlowRate, state.dataLoopNodes->Node(this_component.NodeNumIn).MassFlowRateMaxAvail);
}
ToutLowLimit = this_component.MinOutletTemp;
Tinlet = state.dataLoopNodes->Node(this_component.NodeNumIn).Temp;
CurSpecHeat = plantLoc.loop->glycol->getSpecificHeat(state, Tinlet, RoutineName);
QdotTmp = CurMassFlowRate * CurSpecHeat * (Tinlet - ToutLowLimit);

// !- Don't correct if Q is zero, as this could indicate a component which this hasn't been implemented or not yet turned
// on
if (CurMassFlowRate > 0.0) {
Expand Down
42 changes: 42 additions & 0 deletions tst/EnergyPlus/unit/PlantCondLoopOperation.unit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@
#include <EnergyPlus/BranchInputManager.hh>
#include <EnergyPlus/Data/EnergyPlusData.hh>
#include <EnergyPlus/DataEnvironment.hh>
#include <EnergyPlus/DataLoopNode.hh>
#include <EnergyPlus/FluidProperties.hh>
#include <EnergyPlus/Plant/DataPlant.hh>
#include <EnergyPlus/Plant/PlantManager.hh>
#include <EnergyPlus/PlantCondLoopOperation.hh>
Expand Down Expand Up @@ -1445,3 +1447,43 @@ TEST_F(EnergyPlusFixture, OperationSchemePriority)
EXPECT_EQ(coolingTower(1).CurCompLevelOpNum, 1);
EXPECT_EQ(coolingTower(1).CurOpSchemeType, DataPlant::OpScheme::Uncontrolled);
}

TEST_F(EnergyPlusFixture, AdjustChangeInLoadByHowServed_ModulatedFlowChiller)
{
// A chiller in LeavingSetpointModulated mode sets its own flow rate, so its capacity must not be truncated using the current (branch pump
// minimum) flow rate.

state->dataPlnt->PlantLoop.allocate(1);
auto &thisLoop = state->dataPlnt->PlantLoop(1);
thisLoop.glycol = Fluid::GetWater(*state);
thisLoop.LoopSide(DataPlant::LoopSideLocation::Supply).Branch.allocate(1);
thisLoop.LoopSide(DataPlant::LoopSideLocation::Supply).Branch(1).Comp.allocate(1);

state->dataLoopNodes->Node.allocate(1);
state->dataLoopNodes->Node(1).Temp = 8.0; // chiller inlet, low load return temp
state->dataLoopNodes->Node(1).MassFlowRate = 1.0; // currently at the pump minimum
state->dataLoopNodes->Node(1).MassFlowRateMaxAvail = 10.0; // what the chiller could pull

auto &thisComp = thisLoop.LoopSide(DataPlant::LoopSideLocation::Supply).Branch(1).Comp(1);
thisComp.HowLoadServed = DataPlant::HowMet::ByNominalCapLowOutLimit;
thisComp.NodeNumIn = 1;
thisComp.MinOutletTemp = 6.7; // same as the loop setpoint, as in the defect file

PlantLocation plantLoc(1, DataPlant::LoopSideLocation::Supply, 1, 1);
PlantUtilities::SetPlantLocationLinks(*state, plantLoc);

Real64 const Cp = thisLoop.glycol->getSpecificHeat(*state, 8.0, "AdjustChangeInLoadByHowServed_ModulatedFlowChiller");
Real64 constexpr dispatchedLoad = 20000.0;

// Constant flow chiller: capacity is limited by the flow it actually has
thisComp.ModulatedFlow = false;
Real64 changeInLoad = dispatchedLoad;
PlantCondLoopOperation::AdjustChangeInLoadByHowServed(*state, plantLoc, changeInLoad);
EXPECT_NEAR(changeInLoad, 1.0 * Cp * (8.0 - 6.7), 0.001);

// Variable flow chiller: it can raise its own flow, so the full dispatched load stands
thisComp.ModulatedFlow = true;
changeInLoad = dispatchedLoad;
PlantCondLoopOperation::AdjustChangeInLoadByHowServed(*state, plantLoc, changeInLoad);
EXPECT_NEAR(changeInLoad, dispatchedLoad, 0.001);
}
Loading