Skip to content

Commit

Permalink
Additions, Unit Test, Docs for Defect #10508
Browse files Browse the repository at this point in the history
This commit includes:
1. Addition of a new report variable for the output parameter that spurred this defect.
2. A unit test was added to exercise the new subroutine through its various cases.
3. Documentation edits for both the input-output and engineering references.
Potential PR candidate.
  • Loading branch information
RKStrand committed Jun 21, 2024
1 parent 9ef7d61 commit 1ca21b8
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ \subsubsection{Inverse algorithm for zone capacitance multiplier}\label{Inverse-
\label{eq:InternalMassMultiplierforEachTimestep}
\end{equation}

The default value is 1.0. Ideally the zone heat capacity shall remain constant for the same condition of the interior environment in the zone heat balance equation. An underlying assumption is that the zone heat capacity is treated as constant for the equilibrium of the inversed heat balance model. However the measured temperatures are not the same as the simulated zone air temperatures which is the result of the energy simulation in Equations~\ref{eq:ZoneAirHeatCapacityforEachTimestep} and~\ref{eq:InternalMassMultiplierforEachTimestep}. This causes the internal mass multiplier, $C_T^t$, the result from the inverse model is not constant during the course of the simulation period. The hybrid model will determine a time span when $|T_z^t - T_z^{t-\delta t}| > 0.05^{\circ}C$ that $C_z^t$ remains more constant. Internal mass multiplier calculations are only done when the zone air temperature difference between timesteps meets the condition. This filter is needed for more reliable inverse calculation to avoid the anomaly conditions due to the use of the inverse model.
The default value is 1.0. Ideally the zone heat capacity shall remain constant for the same condition of the interior environment in the zone heat balance equation. An underlying assumption is that the zone heat capacity is treated as constant for the equilibrium of the inversed heat balance model. However the measured temperatures are not the same as the simulated zone air temperatures which is the result of the energy simulation in Equations~\ref{eq:ZoneAirHeatCapacityforEachTimestep} and~\ref{eq:InternalMassMultiplierforEachTimestep}. This causes the internal mass multiplier, $C_T^t$, the result from the inverse model is not constant during the course of the simulation period. The hybrid model will determine a time span when $|T_z^t - T_z^{t-\delta t}| > 0.05^{\circ}C$ that $C_z^t$ remains more constant. Internal mass multiplier calculations are only done when the zone air temperature difference between timesteps meets the condition. This filter is needed for more reliable inverse calculation to avoid the anomaly conditions due to the use of the inverse model. So, when the value for this parameter is 1.0, this means that any of the following conditions is met: $|T_z^t - T_z^{t-\delta t}| > 0.05^{\circ}C$, the simulation is not currently during the time period for which hybrid modeling is set to run, or the value calculated for this parameter using the above methodology results in a value less than 1.0. The value for this multiplier can be obtained as output as described in the Input/Output Reference (Object: HybridModel:Zone).

\subsection{Infiltration hybrid modeling method}\label{Infiltration hybrid modeling method}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ \subsubsection{Outputs}\label{outputs-030}
Zone,Average,Zone Infiltration Hybrid Model Air Change Rate [ACH]
Zone,Average,Zone Infiltration Hybrid Model Mass Flow Rate [kg/s]
Zone,Average,Zone Hybrid Model People Count
Zone,Average,Zone Hybrid Model Thermal Mass Multiplier
\end{lstlisting}

\paragraph{Zone Infiltration Hybrid Model Air Change Rate {[}ACH{]}}\label{zone-infiltration-hybrid-model-air-change-rate}
Expand All @@ -210,4 +211,8 @@ \subsubsection{Outputs}\label{outputs-030}

\paragraph{Zone Hybrid Model People Count}\label{zone-infiltration-hybrid-model-people-count}

The zone people count calculated by the hybrid model.
The zone people count calculated by the hybrid model.

\paragraph{Zone Hybrid Model Thermal Mass Multiplier}\label{zone-infiltration-hybrid-model-thermal-mass-multiplier}

This is the value of the thermal mass multiplier that is the ratio of the zone air heat capacity calculated for current conditions using a heat balance equation to the heat capacity of the volume of air contained in the zone. This value is 1.0 when one of the following conditions is met: $|T_z^t - T_z^{t-\delta t}| > 0.05^{\circ}C$, the simulation is not currently during the time period for which hybrid modeling is set to run, or the value calculated for this parameter using the above methodology results in a value less than 1.0. The first time that the value that is calculated for this parameter is greater than 30.0 for a particular zone a warning message is produced in the EnergyPlus Error File (*.err) to inform the user of this occurrence. A summary of the times for when this parameter is greater than 30.0 for each zone is produced at the end of the standard error file. Note: when the value does exceed this warning threshold, the value is NOT reset.
10 changes: 9 additions & 1 deletion src/EnergyPlus/HybridModel.cc
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,15 @@ namespace HybridModel {
OutputProcessor::StoreType::Average,
state.dataHeatBal->Zone(ZonePtr).Name);
}

if (state.dataHybridModel->HybridModelZone(ZonePtr).InternalThermalMassCalc_T) {
SetupOutputVariable(state,
"Zone Hybrid Model Thermal Mass Multiplier",
Constant::Units::None,
state.dataHeatBal->Zone(ZonePtr).ZoneVolCapMultpSensHM,
OutputProcessor::TimeStepType::Zone,
OutputProcessor::StoreType::Average,
state.dataHeatBal->Zone(ZonePtr).Name);
}
} else {
ShowSevereError(
state,
Expand Down
6 changes: 3 additions & 3 deletions src/EnergyPlus/ZoneTempPredictorCorrector.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5146,6 +5146,7 @@ void InverseModelTemperature(EnergyPlusData &state,

int ZoneMult = zone.Multiplier * zone.ListMultiplier;
zone.ZoneMeasuredTemperature = ScheduleManager::GetCurrentScheduleValue(state, hybridModelZone.ZoneMeasuredTemperatureSchedulePtr);
zone.ZoneVolCapMultpSensHM = 1.0; // Initialize to 1.0 in case hybrid not active

// HM calculation only HM calculation period start
if (state.dataEnvrn->DayOfYear >= hybridModelZone.HybridStartDayOfYear && state.dataEnvrn->DayOfYear <= hybridModelZone.HybridEndDayOfYear) {
Expand Down Expand Up @@ -5253,8 +5254,7 @@ void InverseModelTemperature(EnergyPlusData &state,

processInverseModelMultpHM(
state, MultpHM, zone.ZoneVolCapMultpSensHMSum, zone.ZoneVolCapMultpSensHMCountSum, zone.ZoneVolCapMultpSensHMAverage, ZoneNum);

zone.ZoneVolCapMultpSensHM = MultpHM; // For timestep output
zone.ZoneVolCapMultpSensHM = MultpHM;

} // Hybrid model internal thermal mass calcualtion end

Expand Down Expand Up @@ -5350,7 +5350,7 @@ void processInverseModelMultpHM(EnergyPlusData &state,
if (thisZoneHB.hmThermalMassMultErrIndex == 0) {
ShowWarningMessage(state, format("Hybrid model thermal mass multiplier higher than the limit for {}", zone.Name));
ShowContinueError(state, "This means that the ratio of the zone air heat capacity for the current time step to the");
ShowContinueError(state, format("zone air heat storage is higher than the maximum limit of {:.1R},", maxHMMultValue));
ShowContinueError(state, format("zone air heat storage is higher than the maximum limit of {:.1R}.", maxHMMultValue));
}
ShowRecurringWarningErrorAtEnd(
state, "Hybrid model thermal mass multiplier limit exceeded in zone " + zone.Name, thisZoneHB.hmThermalMassMultErrIndex);
Expand Down
90 changes: 90 additions & 0 deletions tst/EnergyPlus/unit/ZoneTempPredictorCorrector.unit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1695,3 +1695,93 @@ TEST_F(EnergyPlusFixture, DownInterpolate4HistoryValues_Test)
EXPECT_NEAR(oldValue[2], DSHistoryValue3, 0.000001);
EXPECT_NEAR(oldValue[3], DSHistoryValue4, 0.000001);
}

TEST_F(EnergyPlusFixture, HybridModel_processInverseModelMultpHMTest)
{
// Test added for fix to GitHub Issue #10508
Real64 calcHMmult;
Real64 calcHMsum = 0.0;
Real64 calcHMcount = 0.0;
Real64 calcHMavg = 0.0;
Real64 expectedHMmult;
Real64 expectedHMsum;
Real64 expectedHMcount;
Real64 expectedHMavg;
int numZones = 1;
Real64 constexpr allowableTolerance = 0.001;

state->dataHeatBal->Zone.allocate(numZones);
state->dataHeatBal->Zone(numZones).Name = "Hybrid Zone";
state->dataZoneTempPredictorCorrector->zoneHeatBalance.allocate(numZones);

// Test 1: Multiplier is less than the minimum. Reset to the minimum. Nothing added to averages.
calcHMmult = 0.5;
expectedHMmult = 1.0;
expectedHMsum = 0.0;
expectedHMcount = 0;
expectedHMavg = 0.0;
processInverseModelMultpHM(*state, calcHMmult, calcHMsum, calcHMcount, calcHMavg, numZones);
EXPECT_NEAR(calcHMmult, expectedHMmult, allowableTolerance);
EXPECT_NEAR(calcHMsum, expectedHMsum, allowableTolerance);
EXPECT_NEAR(calcHMcount, expectedHMcount, allowableTolerance);
EXPECT_NEAR(calcHMavg, expectedHMavg, allowableTolerance);
EXPECT_EQ(state->dataZoneTempPredictorCorrector->zoneHeatBalance(numZones).hmThermalMassMultErrIndex, 0);

// Test 2: Multiplier is equal to minimum. Reset to the minimum. Nothing added to averages.
calcHMmult = 1.0;
expectedHMmult = 1.0;
expectedHMsum = 0.0;
expectedHMcount = 0;
expectedHMavg = 0.0;
processInverseModelMultpHM(*state, calcHMmult, calcHMsum, calcHMcount, calcHMavg, numZones);
EXPECT_NEAR(calcHMmult, expectedHMmult, allowableTolerance);
EXPECT_NEAR(calcHMsum, expectedHMsum, allowableTolerance);
EXPECT_NEAR(calcHMcount, expectedHMcount, allowableTolerance);
EXPECT_NEAR(calcHMavg, expectedHMavg, allowableTolerance);
EXPECT_EQ(state->dataZoneTempPredictorCorrector->zoneHeatBalance(numZones).hmThermalMassMultErrIndex, 0);

// Test 3: Multiplier is greater than minimum but less than maximum. Set the statistical variables accordingly.
calcHMmult = 10.0;
expectedHMmult = 10.0;
expectedHMsum = 10.0;
expectedHMcount = 1;
expectedHMavg = 10.0;
processInverseModelMultpHM(*state, calcHMmult, calcHMsum, calcHMcount, calcHMavg, numZones);
EXPECT_NEAR(calcHMmult, expectedHMmult, allowableTolerance);
EXPECT_NEAR(calcHMsum, expectedHMsum, allowableTolerance);
EXPECT_NEAR(calcHMcount, expectedHMcount, allowableTolerance);
EXPECT_NEAR(calcHMavg, expectedHMavg, allowableTolerance);
EXPECT_EQ(state->dataZoneTempPredictorCorrector->zoneHeatBalance(numZones).hmThermalMassMultErrIndex, 0);

// Test 4: Multiplier is greater than maximum. Produce an error message but still set the statistical variables accordingly.
calcHMmult = 50.0;
expectedHMmult = 50.0;
expectedHMsum = 60.0;
expectedHMcount = 2;
expectedHMavg = 30.0;
processInverseModelMultpHM(*state, calcHMmult, calcHMsum, calcHMcount, calcHMavg, numZones);
EXPECT_NEAR(calcHMmult, expectedHMmult, allowableTolerance);
EXPECT_NEAR(calcHMsum, expectedHMsum, allowableTolerance);
EXPECT_NEAR(calcHMcount, expectedHMcount, allowableTolerance);
EXPECT_NEAR(calcHMavg, expectedHMavg, allowableTolerance);
EXPECT_NE(state->dataZoneTempPredictorCorrector->zoneHeatBalance(numZones).hmThermalMassMultErrIndex,
0); // This is now set, won't be zero anymore
std::string const error_string =
delimited_string({" ** Warning ** Hybrid model thermal mass multiplier higher than the limit for Hybrid Zone",
" ** ~~~ ** This means that the ratio of the zone air heat capacity for the current time step to the",
" ** ~~~ ** zone air heat storage is higher than the maximum limit of 30.0."});
EXPECT_TRUE(compare_err_stream(error_string, true));

// Test 5: Repeat of Test 1--verifying that it won't impact the statistical variables. No error message.
calcHMmult = 0.5;
expectedHMmult = 1.0;
expectedHMsum = 60.0;
expectedHMcount = 2;
expectedHMavg = 30.0;
processInverseModelMultpHM(*state, calcHMmult, calcHMsum, calcHMcount, calcHMavg, numZones);
EXPECT_NEAR(calcHMmult, expectedHMmult, allowableTolerance);
EXPECT_NEAR(calcHMsum, expectedHMsum, allowableTolerance);
EXPECT_NEAR(calcHMcount, expectedHMcount, allowableTolerance);
EXPECT_NEAR(calcHMavg, expectedHMavg, allowableTolerance);
EXPECT_NE(state->dataZoneTempPredictorCorrector->zoneHeatBalance(numZones).hmThermalMassMultErrIndex, 0);
}

0 comments on commit 1ca21b8

Please sign in to comment.