Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
57 changes: 57 additions & 0 deletions src/EnergyPlus/ChillerElectricEIR.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2617,4 +2617,61 @@ bool ElectricEIRChillerSpecs::thermosiphonDisabled(EnergyPlusData &state)
return true;
}

Real64 ElectricEIRChillerSpecs::getDynamicMaxCapacity(EnergyPlusData &state)
{
Real64 sourceInletTemp = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
if (this->HeatRecActive && (this->QHeatRecovered + this->QCondenser) > 0.0) {
sourceInletTemp =
(this->QHeatRecovered * this->HeatRecInletTemp + this->QCondenser * this->CondInletTemp) / (this->QHeatRecovered + this->QCondenser);
}
Real64 loadSideOutletSetpointTemp = state.dataLoopNodes->Node(this->EvapOutletNodeNum).Temp;
switch (state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).LoopDemandCalcScheme) {
case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
if ((this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) ||
(DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).CurOpSchemeType == DataPlant::OpScheme::CompSetPtBased) ||
(state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint != Node::SensedNodeFlagValue)) {
// there will be a valid setpoint on outlet
loadSideOutletSetpointTemp = state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint;
} else { // use plant loop overall setpoint
loadSideOutletSetpointTemp =
state.dataLoopNodes->Node(state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).TempSetPointNodeNum).TempSetPoint;
}
} break;
case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
if ((this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) ||
(DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).CurOpSchemeType == DataPlant::OpScheme::CompSetPtBased) ||
(state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi != Node::SensedNodeFlagValue)) {
// there will be a valid setpoint on outlet
loadSideOutletSetpointTemp = state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi;
} else { // use plant loop overall setpoint
loadSideOutletSetpointTemp =
state.dataLoopNodes->Node(state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).TempSetPointNodeNum).TempSetPointHi;
}
} break;
default: {
assert(false);
} break;
}

// If there is a fault of Chiller SWT Sensor
if (this->FaultyChillerSWTFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) && (!state.dataGlobal->KickOffSimulation)) {
int FaultIndex = this->FaultyChillerSWTIndex;
Real64 EvapOutletTempSetPoint_ff = loadSideOutletSetpointTemp;

// calculate the sensor offset using fault information
this->FaultyChillerSWTOffset = state.dataFaultsMgr->FaultsChillerSWTSensor(FaultIndex).CalFaultOffsetAct(state);
// update the EvapOutletTempSetPoint
loadSideOutletSetpointTemp =
max(this->TempLowLimitEvapOut,
min(state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp, EvapOutletTempSetPoint_ff - this->FaultyChillerSWTOffset));
this->FaultyChillerSWTOffset = EvapOutletTempSetPoint_ff - loadSideOutletSetpointTemp;
}
if ((this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) && this->ModulatedFlowSetToLoop) {
loadSideOutletSetpointTemp = state.dataLoopNodes->Node(state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).TempSetPointNodeNum).TempSetPoint;
}
// evaluate capacity modifier curve and determine load side heat transfer
Real64 capacityModifierFuncTemp = Curve::CurveValue(state, this->ChillerCapFTIndex, loadSideOutletSetpointTemp, sourceInletTemp);
return this->RefCap * capacityModifierFuncTemp;
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I added this new function, wrote a unit test that tested this function, and then tried to prove the value using a test file. I found no changes at all between develop and this branch and then realized that the Plant Manager was not calling the getDynamicMaxCapacity function in places that mattered. The new calls were added to PlantCondLoopOperation such that the plant manager now knows the dynamic capacity of the EIR chiller.

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

bool thermosiphonDisabled(EnergyPlusData &state);

Real64 getDynamicMaxCapacity(EnergyPlusData &state) override;
};

void GetElectricEIRChillerInput(EnergyPlusData &state);
Expand Down
5 changes: 5 additions & 0 deletions src/EnergyPlus/PlantCondLoopOperation.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3090,6 +3090,7 @@ void DistributePlantLoad(EnergyPlusData &state,
}

NewLoad = this_component.MyLoad;
this_component.MaxLoad = this_component.getDynamicMaxCapacity(state);
NewLoad = min(this_component.MaxLoad, std::abs(NewLoad) + DivideLoad);
ChangeInLoad = NewLoad - std::abs(this_component.MyLoad);
this_component.MyLoad = sign(NewLoad, RemLoopDemand);
Expand Down Expand Up @@ -3143,6 +3144,7 @@ void DistributePlantLoad(EnergyPlusData &state,
continue;
}

this_component.MaxLoad = this_component.getDynamicMaxCapacity(state);
if (this_component.MaxLoad > 0.0) { // apply known limit
ChangeInLoad = min(this_component.MaxLoad, std::abs(RemLoopDemand));
} else {
Expand Down Expand Up @@ -3210,6 +3212,7 @@ void DistributePlantLoad(EnergyPlusData &state,
if (!this_component.Available) {
continue;
}
this_component.MaxLoad = this_component.getDynamicMaxCapacity(state);
if (this_component.MaxLoad > 0.0) {
ChangeInLoad = min(this_component.MaxLoad, UniformLoad);
} else {
Expand Down Expand Up @@ -3288,6 +3291,7 @@ void DistributePlantLoad(EnergyPlusData &state,
continue;
}

this_component.MaxLoad = this_component.getDynamicMaxCapacity(state);
PlantCapacity += this_component.MaxLoad;

if (this_component.MaxLoad < SmallLoad) {
Expand Down Expand Up @@ -3409,6 +3413,7 @@ void DistributePlantLoad(EnergyPlusData &state,
continue;
}

this_component.MaxLoad = this_component.getDynamicMaxCapacity(state);
PlantCapacity += this_component.MaxLoad;

if (this_component.MaxLoad < SmallLoad) {
Expand Down
21 changes: 16 additions & 5 deletions tst/EnergyPlus/unit/ChillerElectricEIR.unit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -328,8 +328,8 @@ TEST_F(EnergyPlusFixture, ChillerElectricEIR_AirCooledChiller)
" ThermoCapFracCurve; !- Thermosiphon Capacity Fraction Curve Name",

"Curve:Linear, ThermoCapFracCurve, 0.0, 0.06, 0.0, 10.0, 0.0, 1.0, Dimensionless, Dimensionless;",
"Curve:Biquadratic, Air cooled CentCapFT, 0.257896, 0.0389016, -0.00021708, 0.0468684, -0.00094284, -0.00034344, 5, 10, 24, 35, , , , , ;",
"Curve:Biquadratic, Air cooled CentEIRFT, 0.933884, -0.058212, 0.00450036, 0.00243, 0.000486, -0.001215, 5, 10, 24, 35, , , , , ;",
"Curve:Biquadratic, Air cooled CentCapFT, 0.257896, 0.0389016, -0.00021708, 0.0468684, -0.00094284, -0.00034344, 5, 10, 5, 35, , , , , ;",
"Curve:Biquadratic, Air cooled CentEIRFT, 0.933884, -0.058212, 0.00450036, 0.00243, 0.000486, -0.001215, 5, 10, 5, 35, , , , , ;",

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The minimum input limit for OAT in these curves was not providing the change expected when calling getDynamicMaxCapacity, because OAT was 12C and 5C in this unit test, so the minimum OAT limit for the curve object was expanded.

"Curve:Quadratic, Air cooled CentEIRFPLR, 0.222903, 0.313387, 0.46371, 0, 1, , , , ;",

});
Expand Down Expand Up @@ -400,17 +400,28 @@ TEST_F(EnergyPlusFixture, ChillerElectricEIR_AirCooledChiller)

thisEIR.initialize(*state, RunFlag, MyLoad);
thisEIR.calculate(*state, MyLoad, RunFlag);
EXPECT_GT(thisEIR.ChillerPartLoadRatio, 0.4); // load is large
EXPECT_GT(thisEIR.ChillerPartLoadRatio, 0.4); // load is largeMax
EXPECT_EQ(thisEIR.thermosiphonStatus, 0); // thermosiphon is off
EXPECT_GT(thisEIR.Power, 1500.0); // power is non-zero
EXPECT_GT(thisEIR.Power, 1300.0); // power is non-zero

// Test getDynamicMaxCapacity function for use by plant manager
PlantComponent *thisChiller = &thisEIR;
Real64 dynCap = thisChiller->getDynamicMaxCapacity(*state);
EXPECT_NEAR(18582.6, dynCap, 1.0); // capacity used by plant manager, calculated at 12 C OAT and 6 C leaving CHW temperature
EXPECT_NEAR(20987.5, thisEIR.RefCap, 1.0); // chiller reference capacity used by plant manager (prior to getDynamicMaxCapacity call)

state->dataLoopNodes->Node(thisEIR.CondInletNodeNum).OutAirDryBulb = 5.0; // condenser inlet temp < evap outlet temp

thisEIR.initialize(*state, RunFlag, MyLoad);
thisEIR.calculate(*state, MyLoad, RunFlag);
EXPECT_GT(thisEIR.ChillerPartLoadRatio, 0.4); // load is large
EXPECT_EQ(thisEIR.thermosiphonStatus, 0); // thermosiphon is off
EXPECT_GT(thisEIR.Power, 1500.0); // power is non-zero
EXPECT_GT(thisEIR.Power, 1200.0); // power is non-zero

// Test getDynamicMaxCapacity function for use by plant manager
dynCap = thisChiller->getDynamicMaxCapacity(*state);
EXPECT_NEAR(14354.6, dynCap, 1.0); // capacity used by plant manager, calculated at 5 C OAT and 6 C leaving CHW temperature
EXPECT_NEAR(20987.5, thisEIR.RefCap, 1.0); // chiller reference capacity used by plant manager (prior to getDynamicMaxCapacity call)

MyLoad /= 25.0; // reduce load such that thermosiphon can meet load
thisEIR.initialize(*state, RunFlag, MyLoad);
Expand Down
Loading