Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Follow up to #10617 and allow other ZoneHVAC:* component with Airflow Network simulations #10637

Merged
merged 7 commits into from
Aug 16, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ \subsubsection{Inputs}\label{inputs-004}

\paragraph{Field: Allow Unsupported Zone Equipment}\label{allow-unsupported-zone-equipment}

This is an optional field. Input is Yes or No. The default is No. Set this input to Yes to have zone equipment that are currently unsupported in the AirflowNetwork model allowed in the simulation. Setting this field to Yes, allows the following equipment to be modeled along an AirflowNetwork model: ZoneHVAC:Dehumidifier, ZoneHVAC:EnergyRecoveryVentilator, WaterHeater:HeatPump:*, and ZoneHVAC:WindowAirConditioner. The AirflowNetwork model will exclude mass balance in these equipment objects and assume the mass flows are self-balanced in the equipment objects.
This is an optional field. Input is Yes or No. The default is No. Set this input to Yes to have zone equipment that are currently unsupported in the AirflowNetwork model allowed in the simulation. Setting this field to Yes, allows the following equipment to be modeled along an AirflowNetwork model: ZoneHVAC:Dehumidifier, ZoneHVAC:EnergyRecoveryVentilator, WaterHeater:HeatPump:*, ZoneHVAC:WindowAirConditioner, ZoneHVAC:WaterToAirHeatPump, ZoneHVAC:PackagedTerminalAirConditioner, ZoneHVAC:PackagedTerminalHeatPump, and ZoneHVAC:TerminalUnit:VariableRefrigerantFlow. The AirflowNetwork model will exclude mass balance in these equipment objects and assume the mass flows are self-balanced in the equipment objects. These objects should be modeled with no outdoor air flow rate, or in the case of a ZoneHVAC:EnergyRecoveryVentilator with a balanced air flow (same supply airflow rate as exhaust airflow rate).

\paragraph{Field: Do Distribution Duct Sizing Calculation}\label{do-distribution-duct-sizing-calculation}

Expand Down
53 changes: 42 additions & 11 deletions src/EnergyPlus/AirflowNetwork/src/Solver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
#include <EnergyPlus/GlobalNames.hh>
#include <EnergyPlus/HVACHXAssistedCoolingCoil.hh>
#include <EnergyPlus/HVACStandAloneERV.hh>
#include <EnergyPlus/HVACVariableRefrigerantFlow.hh>
#include <EnergyPlus/HeatingCoils.hh>
#include <EnergyPlus/InputProcessing/InputProcessor.hh>
#include <EnergyPlus/MixedAir.hh>
Expand All @@ -100,6 +101,7 @@
#include <EnergyPlus/SingleDuct.hh>
#include <EnergyPlus/SplitterComponent.hh>
#include <EnergyPlus/ThermalComfort.hh>
#include <EnergyPlus/UnitarySystem.hh>
#include <EnergyPlus/UtilityRoutines.hh>
#include <EnergyPlus/WaterThermalTanks.hh>
#include <EnergyPlus/WindowAC.hh>
Expand Down Expand Up @@ -10141,10 +10143,12 @@ namespace AirflowNetwork {
using DXCoils::SetDXCoilAirLoopNumber;
using HeatingCoils::SetHeatingCoilAirLoopNumber;
using HVACStandAloneERV::GetStandAloneERVNodeNumber;
using HVACVariableRefrigerantFlow::getVRFTUNodeNumber;
using SplitterComponent::GetSplitterNodeNumbers;
using SplitterComponent::GetSplitterOutletNumber;
using UnitarySystems::getUnitarySystemNodeNumber;
using WaterThermalTanks::GetHeatPumpWaterHeaterNodeNumber;
using WindowAC::GetWindowACNodeNumber;
using WindowAC::getWindowACNodeNumber;
using ZoneDehumidifier::GetZoneDehumidifierNodeNumber;

// SUBROUTINE PARAMETER DEFINITIONS:
Expand All @@ -10161,9 +10165,12 @@ namespace AirflowNetwork {
EPVector<DataLoopNode::ConnectionType> NodeConnectionType; // Specifies the type of node connection
std::string CurrentModuleObject;

bool HPWHFound(false); // Flag for HPWH identification
bool StandaloneERVFound(false); // Flag for Standalone ERV (ZoneHVAC:EnergyRecoveryVentilator) identification
bool WindowACFound(false); // Flag for Window AC (ZoneHVAC:WindowAirConditioner) identification
bool hpwhFound(false); // Flag for HPWH identification
bool standaloneERVFound(false); // Flag for Standalone ERV (ZoneHVAC:EnergyRecoveryVentilator) identification
bool packagedUnitaryFound(false); // Flag for packaged unitary systems (ZoneHVAC:PackagedTerminalAirConditioner,
// ZoneHVAC:PackagedTerminalHeatPump, ZoneHVAC:WaterToAirHeatPump) identification
bool vrfTUFound(false);
bool windowACFound(false); // Flag for Window AC (ZoneHVAC:WindowAirConditioner) identification

// Validate supply and return connections
NodeFound.dimension(m_state.dataLoopNodes->NumOfNodes, false);
Expand Down Expand Up @@ -10268,19 +10275,31 @@ namespace AirflowNetwork {
// Skip HPWH nodes that don't have to be included in the AFN
if (GetHeatPumpWaterHeaterNodeNumber(m_state, i)) {
NodeFound(i) = true;
HPWHFound = true;
hpwhFound = true;
}

// Skip Standalone ERV nodes that don't have to be included in the AFN
if (GetStandAloneERVNodeNumber(m_state, i)) {
NodeFound(i) = true;
StandaloneERVFound = true;
standaloneERVFound = true;
}

// Skip zonal unitary system based nodes that don't have to be included in the AFN
if (getUnitarySystemNodeNumber(m_state, i)) {
NodeFound(i) = true;
packagedUnitaryFound = true;
}

// Skip zonal vrf terminal nodes that don't have to be included in the AFN
if (getVRFTUNodeNumber(m_state, i)) {
NodeFound(i) = true;
vrfTUFound = true;
}

// Skip Window AC with no OA
if (GetWindowACNodeNumber(m_state, i)) {
if (getWindowACNodeNumber(m_state, i)) {
NodeFound(i) = true;
WindowACFound = true;
windowACFound = true;
}
}

Expand Down Expand Up @@ -10412,17 +10431,29 @@ namespace AirflowNetwork {
}
}
}
if (HPWHFound) {
if (hpwhFound) {
ShowWarningError(m_state,
format(RoutineName) + "Heat pump water heater is simulated along with an AirflowNetwork but is not included in "
"the AirflowNetwork.");
}
if (StandaloneERVFound) {
if (standaloneERVFound) {
ShowWarningError(m_state,
format(RoutineName) + "A ZoneHVAC:EnergyRecoveryVentilator is simulated along with an AirflowNetwork but is not "
"included in the AirflowNetwork.");
}
if (WindowACFound) {
if (packagedUnitaryFound) {
ShowWarningError(m_state,
format(RoutineName) + "A ZoneHVAC:PackagedTerminalAirConditioner, ZoneHVAC:PackagedTerminalHeatPump, or "
"ZoneHVAC:WaterToAirHeatPump is simulated along with an AirflowNetwork but is not "
"included in the AirflowNetwork.");
}
if (vrfTUFound) {
ShowWarningError(m_state,
format(RoutineName) +
"A ZoneHVAC:TerminalUnit:VariableRefrigerantFlow is simulated along with an AirflowNetwork but is not "
"included in the AirflowNetwork.");
}
if (windowACFound) {
ShowWarningError(m_state,
format(RoutineName) + "A ZoneHVAC:WindowAirConditioner is simulated along with an AirflowNetwork but is not "
"included in the AirflowNetwork.");
Expand Down
22 changes: 22 additions & 0 deletions src/EnergyPlus/HVACVariableRefrigerantFlow.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10841,6 +10841,28 @@ void getVRFTUZoneLoad(
}
}

bool getVRFTUNodeNumber(EnergyPlusData &state, int const nodeNumber)
{
for (int vrfTUIndex = 1; vrfTUIndex <= state.dataHVACVarRefFlow->NumVRFTU; ++vrfTUIndex) {
auto &vrfTU = state.dataHVACVarRefFlow->VRFTU(vrfTUIndex);

bool noVrfTUOutdoorAir = false;
if (vrfTU.CoolOutAirVolFlow == 0 && vrfTU.HeatOutAirVolFlow == 0 && vrfTU.NoCoolHeatOutAirVolFlow == 0) {
noVrfTUOutdoorAir = true;
}

if (noVrfTUOutdoorAir &&
(nodeNumber == vrfTU.VRFTUInletNodeNum || nodeNumber == vrfTU.VRFTUOutletNodeNum || nodeNumber == vrfTU.fanInletNode ||
nodeNumber == vrfTU.fanOutletNode || nodeNumber == vrfTU.heatCoilAirOutNode || nodeNumber == vrfTU.coolCoilAirOutNode ||
nodeNumber == vrfTU.VRFTUOAMixerOANodeNum || nodeNumber == vrfTU.VRFTUOAMixerRelNodeNum || nodeNumber == vrfTU.VRFTUOAMixerRetNodeNum ||
nodeNumber == vrfTU.VRFTUOAMixerMixedNodeNum || nodeNumber == vrfTU.SuppHeatCoilAirInletNode ||
nodeNumber == vrfTU.SuppHeatCoilAirOutletNode)) {
return true;
}
}
return false;
}

Comment on lines +10844 to +10865
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

New function to identify nodes used by VRF terminal units that don't use any OA so they can be excluded from the AFN distribution validation.

void VRFCondenserEquipment::CalcVRFIUTeTc_FluidTCtrl(EnergyPlusData &state)
{
// SUBROUTINE INFORMATION:
Expand Down
2 changes: 2 additions & 0 deletions src/EnergyPlus/HVACVariableRefrigerantFlow.hh
Original file line number Diff line number Diff line change
Expand Up @@ -931,6 +931,8 @@ namespace HVACVariableRefrigerantFlow {
void getVRFTUZoneLoad(
EnergyPlusData &state, int const VRFTUNum, Real64 &zoneLoad, Real64 &LoadToHeatingSP, Real64 &LoadToCoolingSP, bool const InitFlag);

bool getVRFTUNodeNumber(EnergyPlusData &state, int const nodeNumber);

void ReportVRFTerminalUnit(EnergyPlusData &state, int VRFTUNum); // index to VRF terminal unit

void ReportVRFCondenser(EnergyPlusData &state, int VRFCond); // index to VRF condensing unit
Expand Down
51 changes: 43 additions & 8 deletions src/EnergyPlus/UnitarySystem.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10149,7 +10149,8 @@ namespace UnitarySystems {
Real64 TotalOutputDelta = 0.0; // delta total output rate, {W}
int ZoneInNode = this->m_ZoneInletNode;
Real64 MassFlowRate = state.dataLoopNodes->Node(ZoneInNode).MassFlowRate / this->ControlZoneMassFlowFrac;
if (state.afn->distribution_simulated) {
if (state.afn->distribution_simulated && this->m_sysType != SysType::PackagedAC && this->m_sysType != SysType::PackagedHP &&
this->m_sysType != SysType::PackagedWSHP) {
Comment on lines +10152 to +10153
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Exclude PTHP/PTAC/WSHP since they are excluded from AFN simulation with distribution.

DeltaMassRate = state.dataLoopNodes->Node(this->AirOutNode).MassFlowRate -
state.dataLoopNodes->Node(ZoneInNode).MassFlowRate / this->ControlZoneMassFlowFrac;
if (DeltaMassRate < 0.0) DeltaMassRate = 0.0;
Expand Down Expand Up @@ -12143,7 +12144,8 @@ namespace UnitarySystems {
Real64 DesOutHumRat = this->m_DesiredOutletHumRat;
int CoilType_Num = this->m_CoolingCoilType_Num;
Real64 LoopDXCoilMaxRTFSave = 0.0;
if (state.afn->distribution_simulated) {
if (state.afn->distribution_simulated && this->m_sysType != SysType::PackagedAC && this->m_sysType != SysType::PackagedHP &&
this->m_sysType != SysType::PackagedWSHP) {
LoopDXCoilMaxRTFSave = state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).AFNLoopDXCoilRTF;
state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).AFNLoopDXCoilRTF = 0.0;
}
Expand Down Expand Up @@ -13897,7 +13899,8 @@ namespace UnitarySystems {
this->m_CoolingCycRatio = CycRatio;
this->m_DehumidificationMode = DehumidMode;

if (state.afn->distribution_simulated) {
if (state.afn->distribution_simulated && this->m_sysType != SysType::PackagedAC && this->m_sysType != SysType::PackagedHP &&
this->m_sysType != SysType::PackagedWSHP) {
state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).AFNLoopDXCoilRTF =
max(state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).AFNLoopDXCoilRTF, LoopDXCoilMaxRTFSave);
}
Expand Down Expand Up @@ -13952,7 +13955,8 @@ namespace UnitarySystems {

Real64 LoopHeatingCoilMaxRTFSave = 0.0;
Real64 LoopDXCoilMaxRTFSave = 0.0;
if (state.afn->distribution_simulated) {
if (state.afn->distribution_simulated && this->m_sysType != SysType::PackagedAC && this->m_sysType != SysType::PackagedHP &&
this->m_sysType != SysType::PackagedWSHP) {
LoopHeatingCoilMaxRTFSave = state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).AFNLoopHeatingCoilMaxRTF;
state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).AFNLoopHeatingCoilMaxRTF = 0.0;
LoopDXCoilMaxRTFSave = state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).AFNLoopDXCoilRTF;
Expand Down Expand Up @@ -14571,7 +14575,8 @@ namespace UnitarySystems {
this->m_HeatingCycRatio = CycRatio;
HeatCoilLoad = ReqOutput;

if (state.afn->distribution_simulated) {
if (state.afn->distribution_simulated && this->m_sysType != SysType::PackagedAC && this->m_sysType != SysType::PackagedHP &&
this->m_sysType != SysType::PackagedWSHP) {
state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).AFNLoopHeatingCoilMaxRTF =
max(state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).AFNLoopHeatingCoilMaxRTF, LoopHeatingCoilMaxRTFSave);
state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).AFNLoopDXCoilRTF =
Expand Down Expand Up @@ -14622,7 +14627,8 @@ namespace UnitarySystems {

Real64 LoopHeatingCoilMaxRTFSave = 0.0;
Real64 LoopDXCoilMaxRTFSave = 0.0;
if (state.afn->distribution_simulated) {
if (state.afn->distribution_simulated && this->m_sysType != SysType::PackagedAC && this->m_sysType != SysType::PackagedHP &&
this->m_sysType != SysType::PackagedWSHP) {
auto &afnInfo = state.dataAirLoop->AirLoopAFNInfo(AirLoopNum);
LoopHeatingCoilMaxRTFSave = afnInfo.AFNLoopHeatingCoilMaxRTF;
afnInfo.AFNLoopHeatingCoilMaxRTF = 0.0;
Expand Down Expand Up @@ -14975,7 +14981,8 @@ namespace UnitarySystems {
} // IF((GetCurrentScheduleValue(state, UnitarySystem(UnitarySysNum)%m_SysAvailSchedPtr) > 0.0d0) .AND. &

// LoopHeatingCoilMaxRTF used for AirflowNetwork gets set in child components (gas and fuel)
if (state.afn->distribution_simulated) {
if (state.afn->distribution_simulated && this->m_sysType != SysType::PackagedAC && this->m_sysType != SysType::PackagedHP &&
this->m_sysType != SysType::PackagedWSHP) {
auto &afnInfo = state.dataAirLoop->AirLoopAFNInfo(AirLoopNum);
afnInfo.AFNLoopHeatingCoilMaxRTF = max(afnInfo.AFNLoopHeatingCoilMaxRTF, LoopHeatingCoilMaxRTFSave);
afnInfo.AFNLoopDXCoilRTF = max(afnInfo.AFNLoopDXCoilRTF, LoopDXCoilMaxRTFSave);
Expand Down Expand Up @@ -15664,7 +15671,8 @@ namespace UnitarySystems {
this->m_ElecPower = locFanElecPower + elecCoolingPower + elecHeatingPower + suppHeatingPower + defrostElecPower + this->m_TotalAuxElecPower;
this->m_ElecPowerConsumption = this->m_ElecPower * ReportingConstant;

if (state.afn->distribution_simulated) {
if (state.afn->distribution_simulated && this->m_sysType != SysType::PackagedAC && this->m_sysType != SysType::PackagedHP &&
this->m_sysType != SysType::PackagedWSHP) {
state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopSystemOnMassFlowrate = state.dataUnitarySystems->CompOnMassFlow;
state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopSystemOffMassFlowrate = state.dataUnitarySystems->CompOffMassFlow;
state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopFanOperationMode = this->m_FanOpMode;
Expand Down Expand Up @@ -16739,6 +16747,33 @@ namespace UnitarySystems {
return false;
}

bool getUnitarySystemNodeNumber(EnergyPlusData &state, int const nodeNumber)
{
for (int unitarySysIndex = 0; unitarySysIndex <= state.dataUnitarySystems->numUnitarySystems - 1; ++unitarySysIndex) {
auto &unitarySys = state.dataUnitarySystems->unitarySys[unitarySysIndex];

int FanInletNodeIndex = state.dataFans->fans(unitarySys.m_FanIndex)->inletNodeNum;
int FanOutletNodeIndex = state.dataFans->fans(unitarySys.m_FanIndex)->outletNodeNum;

bool noUnitarySysOutdoorAir = false;
if (unitarySys.m_CoolOutAirVolFlow == 0 && unitarySys.m_HeatOutAirVolFlow == 0 && unitarySys.m_NoCoolHeatOutAirVolFlow == 0) {
noUnitarySysOutdoorAir = true;
}

if (unitarySys.m_sysType == UnitarySys::SysType::PackagedWSHP || unitarySys.m_sysType == UnitarySys::SysType::PackagedAC ||
unitarySys.m_sysType == UnitarySys::SysType::PackagedHP) {
if (noUnitarySysOutdoorAir && (nodeNumber == FanInletNodeIndex || nodeNumber == FanOutletNodeIndex ||
nodeNumber == unitarySys.AirInNode || nodeNumber == unitarySys.m_OAMixerNodes[0] ||
nodeNumber == unitarySys.m_OAMixerNodes[1] || nodeNumber == unitarySys.m_OAMixerNodes[2]) ||
nodeNumber == unitarySys.m_OAMixerNodes[3] || nodeNumber == unitarySys.CoolCoilOutletNodeNum ||
nodeNumber == unitarySys.HeatCoilOutletNodeNum) {
return true;
}
}
}
return false;
}

Comment on lines +16750 to +16776
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

New function to identify nodes used by PTAC/PTHP/WSHP that don't use any OA so they can be excluded from the AFN distribution validation.

void setupAllOutputVars(EnergyPlusData &state, int const numAllSystemTypes)
{
// setup reports only once
Expand Down
1 change: 1 addition & 0 deletions src/EnergyPlus/UnitarySystem.hh
Original file line number Diff line number Diff line change
Expand Up @@ -952,6 +952,7 @@ namespace UnitarySystems {

int getDesignSpecMSHPIndex(EnergyPlusData &state, std::string_view objectName);
int getUnitarySystemIndex(EnergyPlusData &state, std::string_view objectName);
bool getUnitarySystemNodeNumber(EnergyPlusData &state, int const nodeNumber);

bool searchZoneInletNodes(EnergyPlusData &state, int nodeToFind, int &ZoneEquipConfigIndex, int &InletNodeIndex);
bool searchZoneInletNodesByEquipmentIndex(EnergyPlusData &state, int nodeToFind, int zoneEquipmentIndex);
Expand Down
25 changes: 9 additions & 16 deletions src/EnergyPlus/WindowAC.cc
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@ namespace WindowAC {
} else {
state.dataWindowAC->WindAC(WindACNum).OutsideAirNode = OANodeNums(1);
state.dataWindowAC->WindAC(WindACNum).AirReliefNode = OANodeNums(2);
state.dataWindowAC->WindAC(WindACNum).ReturnAirNode = OANodeNums(3);
state.dataWindowAC->WindAC(WindACNum).MixedAirNode = OANodeNums(4);
}
}
Expand Down Expand Up @@ -1499,30 +1500,22 @@ namespace WindowAC {
} // WindAC(WindACNum)%DXCoilType_Num == CoilDX_CoolingHXAssisted && *
}

bool GetWindowACNodeNumber(EnergyPlusData &state, int const NodeNumber)
bool getWindowACNodeNumber(EnergyPlusData &state, int const nodeNumber)
{
if (state.dataWindowAC->GetWindowACInputFlag) {
GetWindowAC(state);
state.dataWindowAC->GetWindowACInputFlag = false;
}

bool windowACOutdoorAir = false;

for (int windowACIndex = 1; windowACIndex <= state.dataWindowAC->NumWindAC; ++windowACIndex) {
auto &windowAC = state.dataWindowAC->WindAC(windowACIndex);
if (windowAC.OutAirVolFlow == 0) {
windowACOutdoorAir = true;
} else {
windowACOutdoorAir = false;
}
int FanInletNodeIndex = 0;
int FanOutletNodeIndex = 0;
FanInletNodeIndex = state.dataFans->fans(windowAC.FanIndex)->inletNodeNum;
FanOutletNodeIndex = state.dataFans->fans(windowAC.FanIndex)->outletNodeNum;

if (windowACOutdoorAir &&
(NodeNumber == windowAC.OutsideAirNode || NodeNumber == windowAC.MixedAirNode || NodeNumber == windowAC.AirReliefNode ||
NodeNumber == FanInletNodeIndex || NodeNumber == FanOutletNodeIndex || NodeNumber == windowAC.AirInNode)) {
int FanInletNodeIndex = state.dataFans->fans(windowAC.FanIndex)->inletNodeNum;
int FanOutletNodeIndex = state.dataFans->fans(windowAC.FanIndex)->outletNodeNum;

if (windowAC.OutAirVolFlow == 0 &&
(nodeNumber == windowAC.OutsideAirNode || nodeNumber == windowAC.MixedAirNode || nodeNumber == windowAC.AirReliefNode ||
nodeNumber == FanInletNodeIndex || nodeNumber == FanOutletNodeIndex || nodeNumber == windowAC.AirInNode ||
nodeNumber == windowAC.CoilOutletNodeNum || nodeNumber == windowAC.AirOutNode || nodeNumber == windowAC.ReturnAirNode)) {
Comment on lines -1502 to +1518
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Address review comments from #10617.

return true;
}
}
Expand Down
Loading
Loading