Skip to content
Merged
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
11 changes: 8 additions & 3 deletions src/EnergyPlus/UnitarySystem.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14130,6 +14130,7 @@ namespace UnitarySystems {

if (OutletHumRatLS > DesOutHumRat) {
CycRatio = 1.0;
this->m_CoolingSpeedNum = std::max(1, this->m_CoolingSpeedNum);

for (int speedNum = this->m_CoolingSpeedNum; speedNum <= this->m_NumOfSpeedCooling; ++speedNum) {
VariableSpeedCoils::SimVariableSpeedCoils(state,
Expand Down Expand Up @@ -14331,7 +14332,8 @@ namespace UnitarySystems {
++this->warnIndex.m_SensPLRIter;
ShowWarningError(state,
format("{} - Iteration limit exceeded calculating part-load ratio for unit = {}", this->UnitType, this->Name));
ShowContinueError(state, format("Estimated part-load ratio = {:.3R}", (ReqOutput / FullOutput)));
ShowContinueError(state,
format("Estimated part-load ratio = {:.3R}", (FullOutput != 0 ? (ReqOutput / FullOutput) : PartLoadFrac)));
ShowContinueError(state, format("Calculated part-load ratio = {:.3R}", PartLoadFrac));
ShowContinueErrorTimeStamp(state, "The calculated part-load ratio will be used and the simulation continues. Occurrence info:");
} else {
Expand All @@ -14345,7 +14347,9 @@ namespace UnitarySystems {
}
}
} else if (SolFla == -2) {
PartLoadFrac = ReqOutput / FullOutput;
if (FullOutput != 0) {
PartLoadFrac = ReqOutput / FullOutput;
}
Copy link
Collaborator

@rraustad rraustad Nov 25, 2025

Choose a reason for hiding this comment

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

There is likely a reason (a developer oversight) that FullOutput has not been calculated. Usually FullOutput is set near the beginning of this function when PLR is set to 1 and the system capacity is checked to see if that capacity exceeds the load, otherwise PLR = 1 and more calculations are not needed. See line 13249, 13681 and 13732. One thing is for sure, if this function is iterating with SolveRoot then the system does have a non-zero FullOutput (or maybe the coil is scheduled off? but I would think that would be caught early). To figure out the why you would need to step through this function at the time the error occurred.

Copy link
Collaborator

Choose a reason for hiding this comment

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

@rraustad I believe this catches the issue noted, but I'll hold this open for a little bit in case you want to take another quick look for any other higher level issues.

Copy link
Collaborator

@rraustad rraustad Dec 1, 2025

Choose a reason for hiding this comment

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

I added at line 14133:

if (OutletHumRatLS > DesOutHumRat) {
    CycRatio = 1.0;
    this->m_CoolingSpeedNum = std::max(1, this->m_CoolingSpeedNum);  <-- new line since speedNum was 0

    for (int speedNum = this->m_CoolingSpeedNum; speedNum <= this->m_NumOfSpeedCooling; ++speedNum) {

The reason SolveRoot was failing was that a sensible load did not exist and FullOutput was not calculated and remained 0 from initialization (line 12999). There was, however, a latent load when there should NOT have been a latent load given these inputs. Adding the line above did allow SolveRoot to find the correct PLR and no longer fails with SolFla = -2. But there is another logic issue somewhere, I have not found that yet. I guess this change is OK but avoiding this calculation if FullOutput = 0 is not really the correct thing to do (because calling SolveRoot means the system is trying to meet a load and therefore the system should have a non-zero capacity) since if SolveRoot does fail with -2 then PLR will default to 0 and it would be prudent to at least try to find an operating PLR, as faulty as this could be (i.e., trying to find PLR based on PartLoadFrac = ReqOutput / FullOutput).

CoilSystem:Cooling:DX,
  GUID11_SYS0SCC-1System,
  None,   !- Dehumidification Control Type
  Yes,    !- Run on Sensible Load
  No,     !- Run on Latent Load

CoilSystem:Cooling:DX,
  A10,  \field Run on Latent Load
    \type choice
    \key Yes
    \key No
    \default No
    \note If Yes, unit will run if there is a latent load.
    \note even if there is no sensible load.
    \note If No, unit will not run only if there is a latent load.
    \note Dehumidification controls will be active if specified.

Copy link
Collaborator

Choose a reason for hiding this comment

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

A more important point is that SolveRoot should never fail with -2. That in itself is a developer error.

if (!state.dataGlobal->WarmupFlag) {
if (this->warnIndex.m_SensPLRFail < 1) {
++this->warnIndex.m_SensPLRFail;
Expand Down Expand Up @@ -14373,7 +14377,8 @@ namespace UnitarySystems {
++this->warnIndex.m_LatPLRIter;
ShowWarningError(
state, format("{} - Iteration limit exceeded calculating latent part-load ratio for unit = {}", this->UnitType, this->Name));
ShowContinueError(state, format("Estimated part-load ratio = {:.3R}", (ReqOutput / FullOutput)));
ShowContinueError(state,
format("Estimated part-load ratio = {:.3R}", (FullOutput != 0 ? (ReqOutput / FullOutput) : PartLoadFrac)));
ShowContinueError(state, format("Calculated part-load ratio = {:.3R}", PartLoadFrac));
ShowContinueErrorTimeStamp(state, "The calculated part-load ratio will be used and the simulation continues. Occurrence info:");
}
Expand Down
34 changes: 34 additions & 0 deletions tst/EnergyPlus/unit/HVACDXSystem.unit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,23 @@ TEST_F(EnergyPlusFixture, VariableSpeedCoils_RHControl)
EXPECT_NEAR(state->dataLoopNodes->Node(ControlNode).HumRat, state->dataLoopNodes->Node(ControlNode).HumRatMax, 0.0000001);
// latent load needed to increase compressor speed to speed 4
EXPECT_EQ(4, thisSys->m_CoolingSpeedNum);

// test for divide by zero error in controlCoolingSystemToSP
thisSys->m_DesiredOutletTemp = 23.888888888888900;
thisSys->m_DesiredOutletHumRat = 0.0092857142857142895;
state->dataLoopNodes->Node(InletNode).MassFlowRate = 1.3840962084222401;
state->dataLoopNodes->Node(InletNode).Temp = 16.566173051926114;
state->dataLoopNodes->Node(InletNode).HumRat = 0.0092873376541228961;
state->dataLoopNodes->Node(InletNode).HumRatMax = -999;

has_err_output(true);
EXPECT_NO_THROW(thisSys->controlCoolingSystemToSP(*state, airLoopNum, FirstHVACIteration, HXUnitOn, CompressorOn));
EXPECT_EQ(thisSys->m_CoolingPartLoadFrac, 0);
std::string const expected_error =
" ** Warning ** CoilSystem:Cooling:DX - sensible part-load ratio calculation failed: part-load ratio limits exceeded, for unit = DX "
"COOLING COIL SYSTEM\n ** ~~~ ** Estimated part-load ratio = 0.000\n ** ~~~ ** The estimated part-load ratio will be used and "
"the simulation continues. Occurrence info:\n ** ~~~ ** Environment=, at Simulation time= 00:-15 - 00:00\n";
compare_err_stream(expected_error, true);
}

TEST_F(EnergyPlusFixture, VariableSpeedCoils_LatentDegradation_Test)
Expand Down Expand Up @@ -1149,6 +1166,23 @@ TEST_F(EnergyPlusFixture, NewDXCoilModel_RHControl)
EXPECT_LT(outHumRat3, outHumRat1); // lower outlet humrat with multimode's alternate operating mode
EXPECT_NEAR(outHumRat1, 0.01166, 0.0001); // sensible control yields higher outlet humrat
EXPECT_NEAR(outHumRat3, 0.01119, 0.0001); // multimode control yields lower outlet humrat

// test for divide by zero error in controlCoolingSystemToSP
thisSys->m_DesiredOutletTemp = 23.888888888888900;
thisSys->m_DesiredOutletHumRat = 0.0092857142857142895;
state->dataLoopNodes->Node(InletNode).MassFlowRate = 1.3840962084222401;
state->dataLoopNodes->Node(InletNode).Temp = 16.566173051926114;
state->dataLoopNodes->Node(InletNode).HumRat = 0.0092873376541228961;
state->dataLoopNodes->Node(InletNode).HumRatMax = -999;

has_err_output(true);
EXPECT_NO_THROW(thisSys->controlCoolingSystemToSP(*state, airLoopNum, FirstHVACIteration, HXUnitOn, CompOn));
EXPECT_EQ(thisSys->m_CoolingPartLoadFrac, 0);
std::string const expected_error =
" ** Warning ** CoilSystem:Cooling:DX - sensible part-load ratio calculation failed: part-load ratio limits exceeded, for unit = DX "
"COOLING COIL SYSTEM\n ** ~~~ ** Estimated part-load ratio = 0.000\n ** ~~~ ** The estimated part-load ratio will be used and "
"the simulation continues. Occurrence info:\n ** ~~~ ** Environment=, at Simulation time= 00:-15 - 00:00\n";
compare_err_stream(expected_error, true);
}

} // namespace EnergyPlus