Skip to content

Conversation

@jmarrec
Copy link
Contributor

@jmarrec jmarrec commented Oct 2, 2025

Pull request overview

Description of the purpose of this PR

Pull Request Author

  • Title of PR should be user-synopsis style (clearly understandable in a standalone changelog context)
  • Label the PR with at least one of: Defect, Refactoring, NewFeature, Performance, and/or DoNoPublish
  • Pull requests that impact EnergyPlus code must also include unit tests to cover enhancement or defect repair
  • Author should provide a "walkthrough" of relevant code changes using a GitHub code review comment process
  • If any diffs are expected, author must demonstrate they are justified using plots and descriptions
  • If changes fix a defect, the fix should be demonstrated in plots and descriptions
  • If any defect files are updated to a more recent version, upload new versions here or on DevSupport
  • If IDD requires transition, transition source, rules, ExpandObjects, and IDFs must be updated, and add IDDChange label
  • If structural output changes, add to output rules file and add OutputChange label
  • If adding/removing any LaTeX docs or figures, update that document's CMakeLists file dependencies

Reviewer

  • Perform a Code Review on GitHub
  • If branch is behind develop, merge develop and build locally to check for side effects of the merge
  • If defect, verify by running develop branch and reproducing defect, then running PR and reproducing fix
  • If feature, test running new feature, try creative ways to break it
  • CI status: all green or justified
  • Check that performance is not impacted (CI Linux results include performance check)
  • Run Unit Test(s) locally
  • Check any new function arguments for performance impacts
  • Verify IDF naming conventions and styles, memos and notes and defaults
  • If new idf included, locally check the err file and other outputs

@jmarrec jmarrec self-assigned this Oct 2, 2025
@jmarrec jmarrec added Defect Includes code to repair a defect in EnergyPlus NotIDDChange Code does not impact IDD (can be merged after IO freeze) labels Oct 2, 2025
@jmarrec
Copy link
Contributor Author

jmarrec commented Oct 2, 2025

Running the defect files on dev support.

  • primary_school_setpoint_ctrl_v2420.idf: this is Setpoint Controlled, but there is no setpoint on the component outlet
  • primary_school_setpoint_ctrl-addSetPoint_v2420.idf: this places the same setpoint as the overall loop setpoint on the component outlet
    • It is provided as a reference point

Diff of the two files:

image

Now, the result. As expected, the addSetPoint case is unchanged with this branch. The other one correctly assumes the overall loop setpoint in the after case.

image

Note that the eplusout.err does not include the new warning because that file has EMS.

@jmarrec
Copy link
Contributor Author

jmarrec commented Oct 2, 2025

I have a MCVE on DevSupport too, where I do see the new warning.

   ** Warning ** EIRPlantLoopHeatPump : oneTimeInit: Missing temperature setpoint for Setpoint Controlled HeatPump:PlantLoop:EIR:Heating name = "HEATING COIL"
   **   ~~~   **   A temperature setpoint is needed at the load side outlet node, use a SetpointManager
   **   ~~~   **   The overall loop setpoint will be assumed for the Heat Pump. The simulation continues ... 
   ** Warning ** EIRPlantLoopHeatPump : oneTimeInit: Missing temperature setpoint for Setpoint Controlled HeatPump:PlantLoop:EIR:Cooling name = "COOLING COIL"
   **   ~~~   **   A temperature setpoint is needed at the load side outlet node, use a SetpointManager
   **   ~~~   **   The overall loop setpoint will be assumed for the Heat Pump. The simulation continues ... 

Comment on lines 2672 to 2696
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;
}
}
Copy link
Contributor Author

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.

Copy link
Contributor

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) {

Copy link
Contributor

@rraustad rraustad Oct 8, 2025

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) {

Copy link
Contributor

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

Copy link
Contributor

@rraustad rraustad Oct 11, 2025

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@rraustad I've tried to follow your request and implement it in 493d41f but I'm not sure whether this is sufficient or simply (hopefully) in the right track. Can you take a quick look please?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is creating a bunch of failed tests. Is it really worth pursuing?

Comment on lines 126 to 127
bool SetpointSetToLoop = false; // True if the setpoint is missing at the outlet node
bool SetpointSetToLoopErrDone = false; // True if setpoint warning issued
Copy link
Contributor Author

Choose a reason for hiding this comment

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

New state vars

Comment on lines 140 to 152
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;
}
Copy link
Contributor Author

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.

Comment on lines +154 to +143
// Call the helper so we handle SingleSetpoint versus DualSetpointDeadband instead of just grabbing TempSetPoint;
Real64 leavingSetpoint = this->getLoadSideOutletSetPointTemp(state);
Copy link
Contributor Author

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?

Copy link
Contributor

Choose a reason for hiding this comment

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

This appears to be the right thing to do but looking at this function it checks the plant control type and I'm not sure the EIR HP Setpoint control type is meant to be this flexible (i.e., to allow multiple set point types at the equipment outlet node). It's as if the getLoadSideOutletSetPointTemp function should look to the equipment Node(this->loadSideNodes.outlet).TempSetpoint variable when using Setpoint control type and this function doesn't do that. In the case of the plant DualSetPointDeadBand control scheme the equipment outlet node would need to find the TempSetpointHi/Lo set points but who's to say that the user intended to control to set point based on the plant control scheme. I got the feeling that @mjwitte would have fatal'd out if the correct set point was not found and I don't disagree with that. i.e., if the user chooses Setpoint then there better be a set point of the correct type at the equipment outlet node. There needs to be more thought on when EIR HP Setpoint control is SingleSetPoint (cooling or heating plant) or DualSetPointDeadBand (mixed plant), I can see both being useful but now only SingleSetPoint is used. Maybe the defect file should not have been using Setpoint control in this case as there was no set point manager used for the EIR HP outlet node?

Comment on lines 2009 to 2010
EXPECT_NEAR(30.0, thisHeatingPLHP->getLoadSideOutletSetPointTemp(*state), 0.001);
EXPECT_NEAR(30.0, state->dataLoopNodes->Node(thisHeatingPLHP->loadSideNodes.outlet).TempSetPoint, 0.001);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

before fix, -999...

Comment on lines 2037 to 2040
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);
Copy link
Contributor Author

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

@github-actions
Copy link

github-actions bot commented Oct 2, 2025

⚠️ Regressions detected on macos-14 for commit 5339267

Regression Summary
  • EIO: 3
  • ERR: 3
  • ESO Big Diffs: 3
  • Table Big Diffs: 1
  • Table Small Diffs: 1

@github-actions
Copy link

github-actions bot commented Oct 2, 2025

⚠️ Regressions detected on ubuntu-24.04 for commit 5339267

Regression Summary
  • EIO: 3
  • ERR: 3
  • ESO Big Diffs: 3
  • Table Big Diffs: 1
  • Table Small Diffs: 1

@mitchute mitchute requested review from mitchute and rraustad October 8, 2025 19:58
@jmarrec jmarrec force-pushed the 10831_HeatPumpPlantLoopEIR_Setpoint branch from cca3edc to 493d41f Compare November 10, 2025 16:18
@github-actions
Copy link

⚠️ Regressions detected on macos-14 for commit 5ddfbd1

Regression Summary
  • EIO: 3
  • ERR: 3
  • ESO Big Diffs: 3
  • Table Big Diffs: 1
  • Table Small Diffs: 1

@github-actions
Copy link

⚠️ Regressions detected on ubuntu-24.04 for commit 5ddfbd1

Regression Summary
  • EIO: 3
  • ERR: 3
  • ESO Big Diffs: 3
  • Table Big Diffs: 1
  • Table Small Diffs: 1


// 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)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure TempSetPointHi (or Lo) should be included here for the "equipment" setpoint control type. However, I haven't investigated this recently and am not sure which Node().TempSetPoint variables are used in the Setpoint control case.

HeatPump:PlantLoop:EIR:Cooling,
   A13, \field Control Type
        \note Heat pump can be controlled on leaving water temperature set point or plant load
        \type choice
        \key Setpoint
        \key Load
        \default Load

@jmarrec jmarrec force-pushed the 10831_HeatPumpPlantLoopEIR_Setpoint branch from 493d41f to 1031924 Compare November 21, 2025 10:45
@github-actions
Copy link

⚠️ Regressions detected on macos-14 for commit 40c185a

Regression Summary
  • EIO: 3
  • ERR: 3
  • ESO Big Diffs: 3
  • Table Big Diffs: 1
  • Table Small Diffs: 1

@github-actions
Copy link

⚠️ Regressions detected on ubuntu-24.04 for commit 40c185a

Regression Summary
  • EIO: 3
  • ERR: 3
  • ESO Big Diffs: 3
  • Table Big Diffs: 1
  • Table Small Diffs: 1

@jmarrec jmarrec force-pushed the 10831_HeatPumpPlantLoopEIR_Setpoint branch from 1031924 to af6451d Compare November 27, 2025 14:07
@github-actions
Copy link

⚠️ Regressions detected on ubuntu-24.04 for commit 3530023

Regression Summary
  • EIO: 3
  • ERR: 3
  • ESO Big Diffs: 3
  • Table Big Diffs: 1
  • Table Small Diffs: 1

@github-actions
Copy link

⚠️ Regressions detected on macos-14 for commit 3530023

Regression Summary
  • EIO: 3
  • ERR: 3
  • ESO Big Diffs: 3
  • Table Big Diffs: 1
  • Table Small Diffs: 1

@jmarrec jmarrec force-pushed the 10831_HeatPumpPlantLoopEIR_Setpoint branch from af6451d to 5c352d5 Compare December 16, 2025 14:14
@github-actions
Copy link

⚠️ Regressions detected on macos-14 for commit 89caa80

Regression Summary
  • EIO: 3
  • ERR: 3
  • ESO Big Diffs: 3
  • Table Big Diffs: 1
  • Table Small Diffs: 1

@github-actions
Copy link

⚠️ Regressions detected on ubuntu-24.04 for commit 89caa80

Regression Summary
  • EIO: 3
  • ERR: 3
  • ESO Big Diffs: 3
  • Table Big Diffs: 1
  • Table Small Diffs: 1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Defect Includes code to repair a defect in EnergyPlus NotIDDChange Code does not impact IDD (can be merged after IO freeze)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

HeatPump:PlantLoop:EIR:Heating with Setpoint control not operating

5 participants