-
Notifications
You must be signed in to change notification settings - Fork 448
Fix #10831 - HeatPump:PlantLoop:EIR:Heating with Setpoint control not operating when no setpoint on component outlet node #11247
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Conversation
…e=Setpoint and missing one at outlet
I have a MCVE on DevSupport too, where I do see the new warning.
|
if (this->sysControlType == ControlType::Setpoint) { | ||
|
||
// check if setpoint on outlet node | ||
if ((state.dataLoopNodes->Node(this->loadSideNodes.outlet).TempSetPoint == DataLoopNode::SensedNodeFlagValue) && | ||
(state.dataLoopNodes->Node(this->loadSideNodes.outlet).TempSetPointHi == DataLoopNode::SensedNodeFlagValue)) { | ||
if (!state.dataGlobal->AnyEnergyManagementSystemInModel) { | ||
if (!this->SetpointSetToLoopErrDone) { | ||
ShowWarningError(state, | ||
format("{}: Missing temperature setpoint for Setpoint Controlled {} name = \"{}\"", | ||
routineName, | ||
DataPlant::PlantEquipTypeNames[static_cast<int>(this->EIRHPType)], | ||
this->name)); | ||
ShowContinueError(state, " A temperature setpoint is needed at the load side outlet node, use a SetpointManager"); | ||
ShowContinueError(state, " The overall loop setpoint will be assumed for the Heat Pump. The simulation continues ... "); | ||
this->SetpointSetToLoopErrDone = true; | ||
} | ||
} else { | ||
// need call to EMS to check node | ||
bool fatalError = false; // but not really fatal yet, but should be. | ||
EMSManager::CheckIfNodeSetPointManagedByEMS(state, this->loadSideNodes.outlet, HVAC::CtrlVarType::Temp, fatalError); | ||
state.dataLoopNodes->NodeSetpointCheck(this->loadSideNodes.outlet).needsSetpointChecking = false; | ||
if (fatalError) { | ||
if (!this->SetpointSetToLoopErrDone) { | ||
ShowWarningError(state, | ||
format("{}: Missing temperature setpoint for Setpoint Controlled {} name = \"{}\"", | ||
routineName, | ||
DataPlant::PlantEquipTypeNames[static_cast<int>(this->EIRHPType)], | ||
this->name)); | ||
ShowContinueError(state, " A temperature setpoint is needed at the load side outlet node when ControlType = Setpoint"); | ||
ShowContinueError(state, " use a Setpoint Manager to establish a setpoint at the outlet node "); | ||
ShowContinueError(state, " or use an EMS actuator to establish a setpoint at the outlet node "); | ||
ShowContinueError(state, " The overall loop setpoint will be assumed for the Heat Pump. The simulation continues ... "); | ||
this->SetpointSetToLoopErrDone = true; | ||
} | ||
} | ||
} | ||
this->SetpointSetToLoop = true; | ||
state.dataLoopNodes->Node(this->loadSideNodes.outlet).TempSetPoint = | ||
state.dataLoopNodes->Node(this->loadSidePlantLoc.loop->TempSetPointNodeNum).TempSetPoint; | ||
state.dataLoopNodes->Node(this->loadSideNodes.outlet).TempSetPointLo = | ||
state.dataLoopNodes->Node(this->loadSidePlantLoc.loop->TempSetPointNodeNum).TempSetPointLo; | ||
state.dataLoopNodes->Node(this->loadSideNodes.outlet).TempSetPointHi = | ||
state.dataLoopNodes->Node(this->loadSidePlantLoc.loop->TempSetPointNodeNum).TempSetPointHi; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In oneTimeInit, when SetpointCOntrolled, we check if there's no setpoint, and assume the overall loop setpoint.
Error is dumped once only, and the "SetpointSetToLoop" is set to true.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am surprised this model does not check for a valid set point since it's been around for quite some time. It points to a set point node but where is the check for DataLoopNode::SensedNodeFlagValue? Maybe at a higher level in the plant manager. Anyway, I think getLoadSideOutletSetPointTemp
already handles where the set point is located. I think you just need to correct old line 142 to new line 155 and always call this function. Once you made that 1-line change you fixed it. The new warnings are nice but I have to believe someone has already thought of plant node set point temperatures and warnings for all the plant equipment that can be controlled to a set point, at the component outlet or loop outlet based on the control type scheme.
Real64 EIRPlantLoopHeatPump::getLoadSideOutletSetPointTemp(EnergyPlusData &state)
if (thisLoadPlantLoop.LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::SingleSetPoint) {
if (thisLoadComp.CurOpSchemeType == DataPlant::OpScheme::CompSetPtBased) {
// there will be a valid set-point on outlet
return state.dataLoopNodes->Node(this->loadSideNodes.outlet).TempSetPoint;
} else { // use plant loop overall set-point
return state.dataLoopNodes->Node(thisLoadPlantLoop.TempSetPointNodeNum).TempSetPoint;
}
} else if (thisLoadPlantLoop.LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand) {
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PlantManager line 2483:
if (this->SupplyEnvrnFlag && state.dataGlobal->BeginEnvrnFlag) {
for (int LoopNum = 1; LoopNum <= this->plant->TotNumLoops; ++LoopNum) {
// check if setpoints being placed on node properly
if (this->plant->PlantLoop(LoopNum).LoopDemandCalcScheme == DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand) {
if (state.dataLoopNodes->Node(this->plant->PlantLoop(LoopNum).TempSetPointNodeNum).TempSetPointHi == SensedNodeFlagValue) {
if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that the boiler and chillers use this as the equipment set point control node. I searched for TempSetPointNodeNum
and it shows up in most/all plant equipment. Maybe that needs to be used instead of what getLoadSideOutletSetPointTemp does? This is weird, the EIR HP can be set point controlled while the plant can use other control types at the same time. If the EIR HP is SP controlled and has SPs at it's outlet node, and the plant is SP controlled and has SPs at the loop outlet node then which node has the priority for use as the SP? Maybe what you have done is more accurate for equipment that have a ControlType input field where the SP should be at the equipment outlet. I am, however, thinking it would be better to figure this out early and use a new this->setPointNodeNum
variable that just points to the correct node and jetison copying node data each iteration. Maybe that would be a good follow up to this PR and fix all this hokeyness in the equipment models after thinking this through.
this->plant->PlantLoop(LoopNum).TempSetPointNodeNum
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Summary of what is needed to complete this work. If the EIR HP is set point controlled then a warning that the SP is missing at the outlet is fine. The plant does have a SP at the plant outlet node. But getLoadSideOutletSetPointTemp will only use that SP if the plant op scheme is NOT CompSetPtBased. I just don't like the idea of copying node data each iteration so I would rather find a different solution. What I would do is either fatal out if there is not SP at the EIR HP outlet node, or right here check if state.dataLoopNodes->Node(this->loadSideNodes.outlet).TempSetPoint == DataLoopNode::SensedNodeFlagValue
and use the plant loop outlet node SP instead. @mjwitte ?
if (this->loadSidePlantLoc.comp->CurOpSchemeType == DataPlant::OpScheme::CompSetPtBased) {
// there will be a valid set-point on outlet
return state.dataLoopNodes->Node(this->loadSideNodes.outlet).TempSetPoint;
} else { // use plant loop overall set-point
return state.dataLoopNodes->Node(this->loadSidePlantLoc.loop->TempSetPointNodeNum).TempSetPoint;
}
I do like the idea of using this in the future, but for this issue what this change is doing is fine. setPointNodeNum would be set up early to point to the correct node, either the EIR HP outlet node or the plant loop outlet node.
return state.dataLoopNodes->Node(this->setPointNodeNum).TempSetPoint;
in getInput or Init choose either:
this->setPointNodeNum = this->loadSideNodes.outlet, or
this->setPointNodeNum = this->loadSidePlantLoc.loop->TempSetPointNodeNum
This would simplify the code in getLoadSideOutletSetPointTemp.
bool SetpointSetToLoop = false; // True if the setpoint is missing at the outlet node | ||
bool SetpointSetToLoopErrDone = false; // True if setpoint warning issued |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New state vars
if (this->running) { | ||
if (this->sysControlType == ControlType::Setpoint) { | ||
Real64 leavingSetpoint = state.dataLoopNodes->Node(this->loadSideNodes.outlet).TempSetPoint; | ||
if (this->SetpointSetToLoop) { | ||
// Copy the overall loop setpoints to the Heat Pump outlet node | ||
state.dataLoopNodes->Node(this->loadSideNodes.outlet).TempSetPoint = | ||
state.dataLoopNodes->Node(this->loadSidePlantLoc.loop->TempSetPointNodeNum).TempSetPoint; | ||
// Hi is used when (this->EIRHPType == DataPlant::PlantEquipmentType::HeatPumpEIRCooling) { | ||
state.dataLoopNodes->Node(this->loadSideNodes.outlet).TempSetPointHi = | ||
state.dataLoopNodes->Node(this->loadSidePlantLoc.loop->TempSetPointNodeNum).TempSetPointHi; | ||
// Lo when HeatPumpEIRHeating | ||
state.dataLoopNodes->Node(this->loadSideNodes.outlet).TempSetPointLo = | ||
state.dataLoopNodes->Node(this->loadSidePlantLoc.loop->TempSetPointNodeNum).TempSetPointLo; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If SetpointSetToLoop is true, in simulate we just copy the plant overall setpoints onto the outlet node.
// Call the helper so we handle SingleSetpoint versus DualSetpointDeadband instead of just grabbing TempSetPoint; | ||
Real64 leavingSetpoint = this->getLoadSideOutletSetPointTemp(state); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was prexisting as
Real64 leavingSetpoint = state.dataLoopNodes->Node(this->loadSideNodes.outlet).TempSetPoint;
But in case the Setpoint is actually DualSetpointWithDeadband, I don't think this is working as intended. So we call the helper instead.
I hope I got that right?
EXPECT_NEAR(30.0, thisHeatingPLHP->getLoadSideOutletSetPointTemp(*state), 0.001); | ||
EXPECT_NEAR(30.0, state->dataLoopNodes->Node(thisHeatingPLHP->loadSideNodes.outlet).TempSetPoint, 0.001); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
before fix, -999...
EXPECT_NEAR(10.0, thisHeatingPLHP->getLoadSideOutletSetPointTemp(*state), 0.001); | ||
EXPECT_NEAR(DataLoopNode::SensedNodeFlagValue, state->dataLoopNodes->Node(thisHeatingPLHP->loadSideNodes.outlet).TempSetPoint, 0.001); | ||
EXPECT_NEAR(30.0, state->dataLoopNodes->Node(thisHeatingPLHP->loadSideNodes.outlet).TempSetPointHi, 0.001); | ||
EXPECT_NEAR(10.0, state->dataLoopNodes->Node(thisHeatingPLHP->loadSideNodes.outlet).TempSetPointLo, 0.001); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, not 10.0 (or 30.0) but -999 before fix
|
|
Pull request overview
Description of the purpose of this PR
Pull Request Author
Reviewer