Skip to content

Commit

Permalink
Merge pull request NREL#10763 from NREL/10762-VAV-Reheat-shows-reheat…
Browse files Browse the repository at this point in the history
…-fraction-less-than-1

Correct VAV maximum air flow fraction during reheat for heating dominated use cases
  • Loading branch information
Myoldmopar authored Feb 7, 2025
2 parents a402772 + 83351a9 commit a339be9
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 18 deletions.
39 changes: 31 additions & 8 deletions src/EnergyPlus/SingleDuct.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2335,8 +2335,15 @@ void SingleDuctAirTerminal::SizeSys(EnergyPlusData &state)

CheckZoneSizing(state, this->sysType, this->SysName);

MaxAirVolFlowRateDes = max(state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesCoolVolFlow,
state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlow);
Real64 heatingMaxFlow;
if (this->DamperHeatingAction == Action::ReverseWithLimits &&
state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlow >
state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlowMax) {
heatingMaxFlow = state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlowMax;
} else {
heatingMaxFlow = state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlow;
}
MaxAirVolFlowRateDes = max(state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesCoolVolFlow, heatingMaxFlow);

if (MaxAirVolFlowRateDes < SmallAirVolFlow) {
MaxAirVolFlowRateDes = 0.0;
Expand Down Expand Up @@ -2385,7 +2392,13 @@ void SingleDuctAirTerminal::SizeSys(EnergyPlusData &state)
}
} else {
CheckZoneSizing(state, this->sysType, this->SysName);
MaxHeatAirVolFlowRateDes = state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlow;
if (this->DamperHeatingAction == Action::ReverseWithLimits &&
state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlow >
state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlowMax) {
MaxHeatAirVolFlowRateDes = state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlowMax;
} else {
MaxHeatAirVolFlowRateDes = state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlow;
}
if (MaxHeatAirVolFlowRateDes < SmallAirVolFlow) {
MaxHeatAirVolFlowRateDes = 0.0;
}
Expand Down Expand Up @@ -2672,7 +2685,13 @@ void SingleDuctAirTerminal::SizeSys(EnergyPlusData &state)
if (state.dataSize->ZoneSizingRunDone) {
if (state.dataSize->CurTermUnitSizingNum > 0) {
// if zone sizing run done, set the design max reheat air flow to the value from the design calcs
MaxAirVolFlowRateDuringReheatDes = state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlowMax;
if (state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlow >
state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlowMax) {
MaxAirVolFlowRateDuringReheatDes =
state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlowMax;
} else {
MaxAirVolFlowRateDuringReheatDes = state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlow;
}
}
} else {
// if no design calc use 0.002032 [m3/s-m2] times floor area. That's .40 cfm/ft2
Expand Down Expand Up @@ -2868,9 +2887,13 @@ void SingleDuctAirTerminal::SizeSys(EnergyPlusData &state)
max(state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).NonAirSysDesHeatVolFlow,
this->MaxAirVolFlowRate * this->ZoneTurndownMinAirFrac);
} else {
TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow =
max(state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).NonAirSysDesHeatVolFlow,
this->MaxAirVolFlowRate * this->ZoneMinAirFracDes * this->ZoneTurndownMinAirFrac);
if (this->SysType_Num == SysType::SingleDuctVAVReheat && this->DamperHeatingAction == Action::ReverseWithLimits) {
TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow = this->MaxAirVolFlowRateDuringReheat;
} else {
TermUnitSizing(state.dataSize->CurTermUnitSizingNum).AirVolFlow =
max(state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).NonAirSysDesHeatVolFlow,
this->MaxAirVolFlowRate * this->ZoneMinAirFracDes * this->ZoneTurndownMinAirFrac);
}
}
} else {
if (this->SysType_Num == SysType::SingleDuctVAVReheatVSFan) {
Expand Down Expand Up @@ -3530,7 +3553,7 @@ void SingleDuctAirTerminal::SimVAV(EnergyPlusData &state, bool const FirstHVACIt
this->ControlCompTypeNum,
this->CompErrIndex,
ZoneNodeNum,
SysOutletNode); // why not QZnReq ?
SysOutletNode);
// air flow controller, not on plant, don't pass plant topology info
// reset terminal unit inlet air mass flow to new value.
state.dataLoopNodes->Node(this->OutletNodeNum).MassFlowRateMaxAvail = this->sd_airterminalInlet.AirMassFlowRateMaxAvail;
Expand Down
64 changes: 55 additions & 9 deletions tst/EnergyPlus/unit/SingleDuct.unit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1294,7 +1294,7 @@ TEST_F(EnergyPlusFixture, SingleDuct_ZeroFloorAreaTest)
// zone floor area of zone 1 = 0, zone 2 > 0. Expect TU MaxAirVolFlowRateDuringReheat = 0 only for zone 1.
// this test isn't relevant anymore since defaulting is done differently
Real64 MaxAirVolFlowRateDuringReheatDes =
min(state->dataSize->FinalZoneSizing(1).DesHeatVolFlowMax, state->dataSingleDuct->sd_airterminal(1).MaxAirVolFlowRate);
min(state->dataSize->FinalZoneSizing(1).DesHeatVolFlow, state->dataSingleDuct->sd_airterminal(1).MaxAirVolFlowRate);
// Real64 MaxAirVolFlowRateDuringReheatDes = min( 0.002032 * state->dataSingleDuct->sd_airterminal( 1 ).ZoneFloorArea,
// state->dataSingleDuct->sd_airterminal( 1 ).MaxAirVolFlowRate ); apply limit based on min stop
MaxAirVolFlowRateDuringReheatDes =
Expand All @@ -1303,7 +1303,7 @@ TEST_F(EnergyPlusFixture, SingleDuct_ZeroFloorAreaTest)

// This isn't relevant any more since the default is calculated differently
Real64 MaxAirVolFractionDuringReheatDes =
min(1.0, (state->dataSize->FinalZoneSizing(1).DesHeatVolFlowMax / state->dataSingleDuct->sd_airterminal(1).MaxAirVolFlowRate));
min(1.0, (state->dataSize->FinalZoneSizing(1).DesHeatVolFlow / state->dataSingleDuct->sd_airterminal(1).MaxAirVolFlowRate));
// Real64 MaxAirVolFractionDuringReheatDes = min( 1.0, ( 0.002032 * state->dataSingleDuct->sd_airterminal( 1 ).ZoneFloorArea /
// state->dataSingleDuct->sd_airterminal( 1 ).MaxAirVolFlowRate )
// ); apply limit based on min stop
Expand All @@ -1318,12 +1318,12 @@ TEST_F(EnergyPlusFixture, SingleDuct_ZeroFloorAreaTest)
EXPECT_NEAR(MaxAirVolFractionDuringReheatDes, state->dataSingleDuct->sd_airterminal(1).MaxAirVolFractionDuringReheat, 0.0000000000001);

MaxAirVolFlowRateDuringReheatDes =
min(state->dataSize->FinalZoneSizing(2).DesHeatVolFlowMax, state->dataSingleDuct->sd_airterminal(2).MaxAirVolFlowRate);
min(state->dataSize->FinalZoneSizing(2).DesHeatVolFlow, state->dataSingleDuct->sd_airterminal(2).MaxAirVolFlowRate);
MaxAirVolFlowRateDuringReheatDes =
max(MaxAirVolFlowRateDuringReheatDes,
(state->dataSingleDuct->sd_airterminal(2).MaxAirVolFlowRate * state->dataSingleDuct->sd_airterminal(2).ZoneMinAirFrac));
MaxAirVolFractionDuringReheatDes =
min(1.0, (state->dataSize->FinalZoneSizing(2).DesHeatVolFlowMax / state->dataSingleDuct->sd_airterminal(2).MaxAirVolFlowRate));
min(1.0, (state->dataSize->FinalZoneSizing(2).DesHeatVolFlow / state->dataSingleDuct->sd_airterminal(2).MaxAirVolFlowRate));
MaxAirVolFractionDuringReheatDes = max(MaxAirVolFractionDuringReheatDes, state->dataSingleDuct->sd_airterminal(2).ZoneMinAirFrac);
MaxAirVolFlowRateDuringReheatDes =
min(max(MaxAirVolFlowRateDuringReheatDes, MaxAirVolFractionDuringReheatDes * state->dataSingleDuct->sd_airterminal(2).MaxAirVolFlowRate),
Expand Down Expand Up @@ -2750,23 +2750,69 @@ TEST_F(EnergyPlusFixture, VAVReheatTerminal_SizeMinFrac)
EXPECT_TRUE(compare_err_stream(""));

int SysNum = 1;
auto &thisSys = state->dataSingleDuct->sd_airterminal(SysNum);

// First test - design min flow < max flow
state->dataSize->ZoneSizingRunDone = true;
state->dataSize->CurZoneEqNum = 1;
state->dataSize->CurTermUnitSizingNum = 1;
state->dataSize->TermUnitFinalZoneSizing(1).DesCoolVolFlowMin = 0.5;
state->dataSingleDuct->sd_airterminal(SysNum).SizeSys(*state);
EXPECT_EQ(0.5, state->dataSingleDuct->sd_airterminal(SysNum).ZoneMinAirFracDes);
thisSys.SizeSys(*state);
EXPECT_EQ(0.5, thisSys.ZoneMinAirFracDes);

// Second test - design min flow > max flow
state->dataSize->ZoneSizingRunDone = true;
state->dataSize->CurZoneEqNum = 1;
state->dataSize->CurTermUnitSizingNum = 1;
state->dataSingleDuct->sd_airterminal(SysNum).ZoneMinAirFracDes = AutoSize; // need to reset this so it sizes again
thisSys.ZoneMinAirFracDes = AutoSize; // need to reset this so it sizes again
state->dataSize->TermUnitFinalZoneSizing(1).DesCoolVolFlowMin = 1.5;
state->dataSingleDuct->sd_airterminal(SysNum).SizeSys(*state);
EXPECT_EQ(1.0, state->dataSingleDuct->sd_airterminal(SysNum).ZoneMinAirFracDes);
thisSys.SizeSys(*state);
EXPECT_EQ(1.0, thisSys.ZoneMinAirFracDes);

// test Maximum Flow Fraction During Reheat for heating dominated
thisSys.MaxAirVolFlowRate = DataSizing::AutoSize;
thisSys.ZoneMinAirFracDes = DataSizing::AutoSize;
thisSys.MaxAirVolFlowRateDuringReheat = DataSizing::AutoSize;
thisSys.MaxAirVolFractionDuringReheat = DataSizing::AutoSize;
state->dataSize->TermUnitFinalZoneSizing(1).DesHeatVolFlow = 1.7;
state->dataSize->TermUnitFinalZoneSizing(1).DesHeatVolFlowMax = 1.6;
thisSys.SizeSys(*state);
Real64 expectedZoneMinAirFracDes = std::min(1.0, state->dataSize->TermUnitFinalZoneSizing(1).DesCoolVolFlowMin / thisSys.MaxAirVolFlowRate);
// DesHeatVolFlowMax is limiting flow rate
Real64 expectedMaxAirVolFractionDuringReheat = state->dataSize->TermUnitFinalZoneSizing(1).DesHeatVolFlowMax / thisSys.MaxAirVolFlowRate;
EXPECT_EQ(expectedZoneMinAirFracDes, thisSys.ZoneMinAirFracDes);
EXPECT_EQ(1.0, thisSys.MaxAirVolFractionDuringReheat);
EXPECT_EQ(expectedMaxAirVolFractionDuringReheat, thisSys.MaxAirVolFractionDuringReheat);

// switch magnitude of DesHeatVolFlow and DesHeatVolFlowMax, still heating dominated
thisSys.MaxAirVolFlowRate = DataSizing::AutoSize;
thisSys.ZoneMinAirFracDes = DataSizing::AutoSize;
thisSys.MaxAirVolFlowRateDuringReheat = DataSizing::AutoSize;
thisSys.MaxAirVolFractionDuringReheat = DataSizing::AutoSize;
state->dataSize->TermUnitFinalZoneSizing(1).DesHeatVolFlow = 1.6;
state->dataSize->TermUnitFinalZoneSizing(1).DesHeatVolFlowMax = 1.7;
thisSys.SizeSys(*state);
expectedZoneMinAirFracDes = std::min(1.0, state->dataSize->TermUnitFinalZoneSizing(1).DesCoolVolFlowMin / thisSys.MaxAirVolFlowRate);
// DesHeatVolFlowMax is NOT limiting flow rate
expectedMaxAirVolFractionDuringReheat = state->dataSize->TermUnitFinalZoneSizing(1).DesHeatVolFlow / thisSys.MaxAirVolFlowRate;
EXPECT_EQ(expectedZoneMinAirFracDes, thisSys.ZoneMinAirFracDes);
EXPECT_EQ(1.0, thisSys.MaxAirVolFractionDuringReheat);
EXPECT_EQ(expectedMaxAirVolFractionDuringReheat, thisSys.MaxAirVolFractionDuringReheat);

// test Maximum Flow Fraction During Reheat for cooling dominated
thisSys.MaxAirVolFlowRate = DataSizing::AutoSize;
thisSys.ZoneMinAirFracDes = DataSizing::AutoSize;
thisSys.MaxAirVolFlowRateDuringReheat = DataSizing::AutoSize;
thisSys.MaxAirVolFractionDuringReheat = DataSizing::AutoSize;
state->dataSize->TermUnitFinalZoneSizing(1).DesHeatVolFlow = 1.4;
state->dataSize->TermUnitFinalZoneSizing(1).DesHeatVolFlowMax = 1.3;
thisSys.SizeSys(*state);
expectedZoneMinAirFracDes = std::min(1.0, state->dataSize->TermUnitFinalZoneSizing(1).DesCoolVolFlowMin / thisSys.MaxAirVolFlowRate);
// DesHeatVolFlowMax is limiting flow rate
expectedMaxAirVolFractionDuringReheat = state->dataSize->TermUnitFinalZoneSizing(1).DesHeatVolFlowMax / thisSys.MaxAirVolFlowRate;
EXPECT_EQ(expectedZoneMinAirFracDes, thisSys.ZoneMinAirFracDes);
EXPECT_EQ(1.0, thisSys.MaxAirVolFractionDuringReheat);
EXPECT_EQ(expectedMaxAirVolFractionDuringReheat, thisSys.MaxAirVolFractionDuringReheat);
}

TEST_F(EnergyPlusFixture, setATMixerSizingProperties_Test)
Expand Down
6 changes: 5 additions & 1 deletion tst/EnergyPlus/unit/VAVDefMinMaxFlow.unit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -483,8 +483,12 @@ TEST_F(EnergyPlusFixture, VAVDefMinMaxFlowTestSizing2)
state->dataSingleDuct->sd_airterminal(1).ZoneFloorArea = state->dataHeatBal->Zone(1).FloorArea;
UpdateTermUnitFinalZoneSizing(*state); // Fills the TermUnitFinalZoneSizing array
state->dataSingleDuct->sd_airterminal(1).SizeSys(*state);
Real64 heatVolFlow = (state->dataSize->FinalZoneSizing(state->dataSize->CurZoneEqNum).DesHeatVolFlow >
state->dataSize->FinalZoneSizing(state->dataSize->CurZoneEqNum).DesHeatVolFlowMax)
? state->dataSize->FinalZoneSizing(state->dataSize->CurZoneEqNum).DesHeatVolFlowMax
: state->dataSize->FinalZoneSizing(state->dataSize->CurZoneEqNum).DesHeatVolFlow;
EXPECT_NEAR(state->dataSingleDuct->sd_airterminal(state->dataSize->CurZoneEqNum).ZoneMinAirFracDes, 0.348739, 0.000001);
EXPECT_NEAR(state->dataSingleDuct->sd_airterminal(state->dataSize->CurZoneEqNum).MaxAirVolFlowRateDuringReheat, 0.196047, 0.000001);
EXPECT_NEAR(state->dataSingleDuct->sd_airterminal(state->dataSize->CurZoneEqNum).MaxAirVolFlowRateDuringReheat, heatVolFlow, 0.000001);

state->dataLoopNodes->Node.deallocate();
state->dataZoneEquip->ZoneEquipConfig.deallocate();
Expand Down

0 comments on commit a339be9

Please sign in to comment.