Skip to content

Commit

Permalink
Merge pull request #8577 from NREL/177124326_Issue8567New
Browse files Browse the repository at this point in the history
Addresses zone air mass flow balance enforcing problem when there is "balanced" exhaust flow
  • Loading branch information
mjwitte authored Mar 16, 2021
2 parents 48528a9 + 7679563 commit 3a5929c
Show file tree
Hide file tree
Showing 9 changed files with 501 additions and 30 deletions.
2 changes: 1 addition & 1 deletion doc/input-output-reference/src/overview/group-fans.tex
Original file line number Diff line number Diff line change
Expand Up @@ -618,7 +618,7 @@ \subsubsection{Inputs}\label{inputs-3-014}

\paragraph{Field: Balanced Exhaust Fraction Schedule Name}\label{field-balanced-exhaust-fraction-schedule-name}

This field is optional. If it is not used, then all the exhaust air flow is assumed to be unbalanced by any simple airflows, such as infiltration, ventilation, or zone mixing. Unbalanced exhaust is then modeled as being provided by the outdoor air system in the central air system. The modeling of unbalanced will reduce the flow rates at the zone's return air node by the flow rate that is being exhausted and will ensure that the outdoor air flow rate is sufficient to serve the exhaust. If this field is used, then enter the name of a schedule with fractional values between 0.0 and 1.0, inclusive. This fraction is applied to the exhaust fan flow rate and the model tracks the portion of the exhaust that is balanced. Balanced exhaust is then modeled as being provided by simple airflows and does not impact the central air system return air or outdoor air flow rates. For example, if a kitchen zone with an exhaust fan is designed to draw half of its make up air from a neighboring dining room and the other half from the outdoor air system, then a schedule value of 0.5 could be used here.
This field is optional. If it is not used, then all the exhaust air flow is assumed to be unbalanced by any simple airflows, such as infiltration, ventilation, or zone mixing. Unbalanced exhaust is then modeled as being provided by the outdoor air system in the central air system. The modeling of unbalanced will reduce the flow rates at the zone's return air node by the flow rate that is being exhausted and will ensure that the outdoor air flow rate is sufficient to serve the exhaust. If this field is used, then enter the name of a schedule with fractional values between 0.0 and 1.0, inclusive. This fraction is applied to the exhaust fan flow rate and the model tracks the portion of the exhaust that is balanced. Balanced exhaust is then modeled as being provided by simple airflows and does not impact the central air system return air or outdoor air flow rates. For example, if a kitchen zone with an exhaust fan is designed to draw half of its make up air from a neighboring dining room and the other half from the outdoor air system, then a schedule value of 0.5 could be used here. This input field must be blank when the zone air flow balance is enforced. If user specifies a schedule and zone air flow balance is enforced, then EnergyPlus throws a warning error message, ignores the schedule and simulation continues.

\subsubsection{Outputs}\label{outputs-3-007}

Expand Down
8 changes: 6 additions & 2 deletions src/EnergyPlus/DataHeatBalance.hh
Original file line number Diff line number Diff line change
Expand Up @@ -1054,10 +1054,13 @@ namespace DataHeatBalance {
// AdjustReturnThenMixing, None)
int InfiltrationTreatment; // determines how infiltration is treated for zone mass balance
int InfiltrationZoneType; // specifies which types of zones allow infiltration to be changed
bool AdjustZoneMixingFlow; // used to adjust zone mixing air flows to enforce air flow balance
bool AdjustZoneInfiltrationFlow; // used to adjust zone infiltration air flows to enforce air flow balance
// Note, unique global object

// Default Constructor
ZoneAirMassFlowConservation() : EnforceZoneMassBalance(false), ZoneFlowAdjustment(0), InfiltrationTreatment(0), InfiltrationZoneType(0)
ZoneAirMassFlowConservation()
: EnforceZoneMassBalance(false), ZoneFlowAdjustment(0), InfiltrationTreatment(0), InfiltrationZoneType(0), AdjustZoneMixingFlow(false), AdjustZoneInfiltrationFlow(false)
{
}
};
Expand All @@ -1075,6 +1078,7 @@ namespace DataHeatBalance {
int NumSourceZonesMixingObject; // number of zone mixing object references as a source zone
int NumReceivingZonesMixingObject; // number of zone mixing object references as a receiving zone
bool IsOnlySourceZone; // true only if used only as a source zone in zone mixing object
bool IsSourceAndReceivingZone; // true only if a zone is used as a source and receiving zone in zone mixing objects
int InfiltrationPtr; // pointer to infiltration object
Real64 InfiltrationMassFlowRate; // infiltration added to enforced source zone mass balance, kg/s
int IncludeInfilToZoneMassBal; // not self-balanced, include infiltration in zone air mass balance
Expand All @@ -1086,7 +1090,7 @@ namespace DataHeatBalance {
// Default Constructor
ZoneMassConservationData()
: ZonePtr(0), InMassFlowRate(0.0), ExhMassFlowRate(0.0), RetMassFlowRate(0.0), MixingMassFlowRate(0.0), MixingSourceMassFlowRate(0.0),
NumSourceZonesMixingObject(0), NumReceivingZonesMixingObject(0), IsOnlySourceZone(false), InfiltrationPtr(0),
NumSourceZonesMixingObject(0), NumReceivingZonesMixingObject(0), IsOnlySourceZone(false), IsSourceAndReceivingZone(false), InfiltrationPtr(0),
InfiltrationMassFlowRate(0.0), IncludeInfilToZoneMassBal(0)
{
}
Expand Down
36 changes: 25 additions & 11 deletions src/EnergyPlus/Fans.cc
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
#include <EnergyPlus/Data/EnergyPlusData.hh>
#include <EnergyPlus/DataContaminantBalance.hh>
#include <EnergyPlus/DataEnvironment.hh>
#include <EnergyPlus/DataHeatBalance.hh>
#include <EnergyPlus/DataLoopNode.hh>
#include <EnergyPlus/DataPrecisionGlobals.hh>
#include <EnergyPlus/DataSizing.hh>
Expand Down Expand Up @@ -591,18 +592,31 @@ namespace EnergyPlus::Fans {
}

if (NumAlphas > 8 && !lAlphaFieldBlanks(9)) {
Fan(FanNum).BalancedFractSchedNum = GetScheduleIndex(state, cAlphaArgs(9));
if (Fan(FanNum).BalancedFractSchedNum == 0) {
ShowSevereError(state, RoutineName + cCurrentModuleObject + ": invalid " + cAlphaFieldNames(9) + " entered =" + cAlphaArgs(9) + " for " +
cAlphaFieldNames(1) + '=' + cAlphaArgs(1));
ErrorsFound = true;
} else if (Fan(FanNum).BalancedFractSchedNum > 0) {
if (!CheckScheduleValueMinMax(state, Fan(FanNum).BalancedFractSchedNum, ">=", 0.0, "<=", 1.0)) {
ShowSevereError(state, RoutineName + cCurrentModuleObject + ": invalid " + cAlphaFieldNames(9) + " for " + cAlphaFieldNames(1) +
'=' + cAlphaArgs(1));
ShowContinueError(state, "Error found in " + cAlphaFieldNames(9) + " = " + cAlphaArgs(9));
ShowContinueError(state, "Schedule values must be (>=0., <=1.)");

if (state.dataHeatBal->ZoneAirMassFlow.ZoneFlowAdjustment != DataHeatBalance::NoAdjustReturnAndMixing) {
// do not include adjusted for "balanced" exhaust flow in the zone total return calculation
ShowWarningError(state,
RoutineName + cCurrentModuleObject + ": invalid " + cAlphaFieldNames(9) + " = " + cAlphaArgs(9) +
" for " + cAlphaFieldNames(1) + '=' + cAlphaArgs(1));
ShowContinueError(state, "When zone air mass flow balance is enforced, this input field should be left blank.");
ShowContinueError(state, "This schedule will be ignored in the simulation.");
Fan(FanNum).BalancedFractSchedNum = 0;
} else {
Fan(FanNum).BalancedFractSchedNum = GetScheduleIndex(state, cAlphaArgs(9));
if (Fan(FanNum).BalancedFractSchedNum == 0) {
ShowSevereError(state,
RoutineName + cCurrentModuleObject + ": invalid " + cAlphaFieldNames(9) + " entered =" + cAlphaArgs(9) +
" for " + cAlphaFieldNames(1) + '=' + cAlphaArgs(1));
ErrorsFound = true;
} else if (Fan(FanNum).BalancedFractSchedNum > 0) {
if (!CheckScheduleValueMinMax(state, Fan(FanNum).BalancedFractSchedNum, ">=", 0.0, "<=", 1.0)) {
ShowSevereError(state,
RoutineName + cCurrentModuleObject + ": invalid " + cAlphaFieldNames(9) + " for " + cAlphaFieldNames(1) +
'=' + cAlphaArgs(1));
ShowContinueError(state, "Error found in " + cAlphaFieldNames(9) + " = " + cAlphaArgs(9));
ShowContinueError(state, "Schedule values must be (>=0., <=1.)");
ErrorsFound = true;
}
}
}
} else {
Expand Down
15 changes: 12 additions & 3 deletions src/EnergyPlus/HeatBalanceAirManager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2715,6 +2715,10 @@ namespace EnergyPlus::HeatBalanceAirManager {
state.dataHeatBal->MassConservation(ZoneNum).ZoneMixingReceivingPtr(Loop) = ZoneMixingNum(Loop);
}
}
// flag zones used as both source and receiving zone
if (state.dataHeatBal->MassConservation(ZoneNum).NumSourceZonesMixingObject > 0 && state.dataHeatBal->MassConservation(ZoneNum).NumReceivingZonesMixingObject > 0) {
state.dataHeatBal->MassConservation(ZoneNum).IsSourceAndReceivingZone = true;
}
}
if (allocated(ZoneMixingNum)) ZoneMixingNum.deallocate();
}
Expand All @@ -2723,7 +2727,13 @@ namespace EnergyPlus::HeatBalanceAirManager {
// and then proceeds to source zones
Loop = 0;
for (ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
if (!state.dataHeatBal->MassConservation(ZoneNum).IsOnlySourceZone) {
if (!state.dataHeatBal->MassConservation(ZoneNum).IsOnlySourceZone && !state.dataHeatBal->MassConservation(ZoneNum).IsSourceAndReceivingZone) {
Loop += 1;
state.dataHeatBalFanSys->ZoneReOrder(Loop) = ZoneNum;
}
}
for (ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
if (state.dataHeatBal->MassConservation(ZoneNum).IsSourceAndReceivingZone) {
Loop += 1;
state.dataHeatBalFanSys->ZoneReOrder(Loop) = ZoneNum;
}
Expand All @@ -2734,7 +2744,6 @@ namespace EnergyPlus::HeatBalanceAirManager {
state.dataHeatBalFanSys->ZoneReOrder(Loop) = ZoneNum;
}
}

cCurrentModuleObject = "ZoneCrossMixing";
int inputCrossMixing = inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
state.dataHeatBal->TotCrossMixing = inputCrossMixing + state.dataHeatBal->NumAirBoundaryMixing;
Expand Down Expand Up @@ -3754,7 +3763,7 @@ namespace EnergyPlus::HeatBalanceAirManager {
// Check for infiltration in zone which are only a mixing source zone
for (ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
if ((state.dataHeatBal->ZoneAirMassFlow.ZoneFlowAdjustment != DataHeatBalance::NoAdjustReturnAndMixing && state.dataHeatBal->MassConservation(ZoneNum).IsOnlySourceZone) &&
(state.dataHeatBal->ZoneAirMassFlow.InfiltrationTreatment != NoInfiltrationFlow)) {
(state.dataHeatBal->ZoneAirMassFlow.InfiltrationTreatment != DataHeatBalance::NoInfiltrationFlow)) {
if (state.dataHeatBal->MassConservation(ZoneNum).InfiltrationPtr == 0) {
ShowSevereError(state, RoutineName + ": Infiltration object is not defined for zone = " + state.dataHeatBal->Zone(ZoneNum).Name);
ShowContinueError(state, "Zone air mass flow balance requires infiltration object for source zones of mixing objects");
Expand Down
2 changes: 2 additions & 0 deletions src/EnergyPlus/HeatBalanceManager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1246,6 +1246,7 @@ namespace HeatBalanceManager {
ShowWarningError(state, CurrentModuleObject + ": Invalid input of " + cAlphaFieldNames(1) + ". The default choice is assigned = None");
}
}
if (state.dataHeatBal->ZoneAirMassFlow.ZoneFlowAdjustment != DataHeatBalance::NoAdjustReturnAndMixing) state.dataHeatBal->ZoneAirMassFlow.AdjustZoneMixingFlow = true;
}
if (NumAlpha > 1) {
{
Expand Down Expand Up @@ -1303,6 +1304,7 @@ namespace HeatBalanceManager {
} else {
state.dataHeatBal->ZoneAirMassFlow.EnforceZoneMassBalance = false;
}
if (state.dataHeatBal->ZoneAirMassFlow.InfiltrationTreatment != DataHeatBalance::NoInfiltrationFlow) state.dataHeatBal->ZoneAirMassFlow.AdjustZoneInfiltrationFlow = true;

constexpr const char * Format_732(
"! <Zone Air Mass Flow Balance Simulation>, Enforce Mass Balance, Adjust Zone Mixing and Return {{AdjustMixingOnly | AdjustReturnOnly | AdjustMixingThenReturn | AdjustReturnThenMixing | None}}, Adjust Zone Infiltration "
Expand Down
2 changes: 1 addition & 1 deletion src/EnergyPlus/SimulationManager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3086,7 +3086,7 @@ void Resimulate(EnergyPlusData &state,
// HVAC simulation
ManageZoneAirUpdates(state, iGetZoneSetPoints, ZoneTempChange, false, UseZoneTimeStepHistory, 0.0);
if (state.dataContaminantBalance->Contaminant.SimulateContaminants) ManageZoneContaminanUpdates(state, iGetZoneSetPoints, false, UseZoneTimeStepHistory, 0.0);
CalcAirFlowSimple(state, 0, state.dataHeatBal->ZoneAirMassFlow.EnforceZoneMassBalance, state.dataHeatBal->ZoneAirMassFlow.EnforceZoneMassBalance);
CalcAirFlowSimple(state, 0, state.dataHeatBal->ZoneAirMassFlow.AdjustZoneMixingFlow, state.dataHeatBal->ZoneAirMassFlow.AdjustZoneInfiltrationFlow);
ManageZoneAirUpdates(state, iPredictStep, ZoneTempChange, false, UseZoneTimeStepHistory, 0.0);
if (state.dataContaminantBalance->Contaminant.SimulateContaminants) ManageZoneContaminanUpdates(state, iPredictStep, false, UseZoneTimeStepHistory, 0.0);
SimHVAC(state);
Expand Down
4 changes: 2 additions & 2 deletions src/EnergyPlus/VariableSpeedCoils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7474,8 +7474,8 @@ namespace VariableSpeedCoils {
// Calculate apparatus dew point conditions using TotCap and CBF
Real64 hDelta = TotCapCalc / AirMassFlow; // Change in air enthalpy across the cooling coil [J/kg]
Real64 hADP = InletEnthalpy - hDelta / (1.0 - localCBF); // Apparatus dew point enthalpy [J/kg]
Real64 tADP = PsyTsatFnHPb(state, hADP, Pressure); // Apparatus dew point temperature [C]
Real64 wADP = PsyWFnTdbH(state, tADP, hADP); // Apparatus dew point humidity ratio [kg/kg]
Real64 tADP = PsyTsatFnHPb(state, hADP, Pressure, RoutineName); // Apparatus dew point temperature [C]
Real64 wADP = PsyWFnTdbH(state, tADP, hADP, RoutineName); // Apparatus dew point humidity ratio [kg/kg]
Real64 hTinwADP = PsyHFnTdbW(InletDryBulb, wADP); // Enthalpy at inlet dry-bulb and wADP [J/kg]
SHRCalc = min((hTinwADP - hADP) / (InletEnthalpy - hADP), 1.0); // temporary calculated value of SHR

Expand Down
17 changes: 7 additions & 10 deletions src/EnergyPlus/ZoneEquipmentManager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2622,11 +2622,6 @@ namespace EnergyPlus::ZoneEquipmentManager {

// Determine flow rate and temperature of supply air based on type of damper

//bool AdjustZoneMassFlowFlag(true); // holds zone mixing and infiltration flow calc status

bool AdjustZoneMixingFlowFlag(true); // holds zone mixing air flow calc status
bool AdjustZoneInfiltrationFlowFlag(true); // holds zone infiltration air flow calc status

FirstCall = true;
ErrorFlag = false;

Expand Down Expand Up @@ -2673,11 +2668,12 @@ namespace EnergyPlus::ZoneEquipmentManager {

// Loop over all the primary air loop; simulate their components (equipment)
// and controllers

if (state.dataHeatBal->ZoneAirMassFlow.EnforceZoneMassBalance) {
if (state.dataHeatBal->ZoneAirMassFlow.ZoneFlowAdjustment == DataHeatBalance::NoAdjustReturnAndMixing) AdjustZoneMixingFlowFlag = false;
if (state.dataHeatBal->ZoneAirMassFlow.ZoneFlowAdjustment == DataHeatBalance::NoInfiltrationFlow) AdjustZoneInfiltrationFlowFlag = false;
CalcAirFlowSimple(state, 0, AdjustZoneMixingFlowFlag, AdjustZoneInfiltrationFlowFlag);
if (FirstHVACIteration) {
CalcAirFlowSimple(state, 0);
} else {
CalcAirFlowSimple(state, 0, state.dataHeatBal->ZoneAirMassFlow.AdjustZoneMixingFlow, state.dataHeatBal->ZoneAirMassFlow.AdjustZoneInfiltrationFlow);
}
}

for (ControlledZoneNum = 1; ControlledZoneNum <= state.dataGlobal->NumOfZones; ++ControlledZoneNum) {
Expand Down Expand Up @@ -3993,7 +3989,8 @@ namespace EnergyPlus::ZoneEquipmentManager {

// Calculate standard return air flow rate using default method of inlets minus exhausts adjusted for "balanced" exhaust flow
StdTotalReturnMassFlow = TotInletAirMassFlowRate + ZoneMixingNetAirMassFlowRate -
(TotExhaustAirMassFlowRate - state.dataZoneEquip->ZoneEquipConfig(ZoneNum).ZoneExhBalanced);
(TotExhaustAirMassFlowRate - state.dataZoneEquip->ZoneEquipConfig(ZoneNum).ZoneExhBalanced);

if (!state.dataHeatBal->ZoneAirMassFlow.EnforceZoneMassBalance) {
if (StdTotalReturnMassFlow < 0.0) {
state.dataZoneEquip->ZoneEquipConfig(ZoneNum).ExcessZoneExh = -StdTotalReturnMassFlow;
Expand Down
Loading

1 comment on commit 3a5929c

@nrel-bot-3
Copy link

Choose a reason for hiding this comment

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

develop (mjwitte) - x86_64-MacOS-10.15-clang-11.0.0: OK (2342 of 2342 tests passed, 0 test warnings)

Build Badge Test Badge

Please sign in to comment.