Skip to content

Commit

Permalink
Merge pull request #10617 from NREL/allow_windowac_afn
Browse files Browse the repository at this point in the history
Allow `ZoneHVAC:WindowAirConditioner` with Airflow Network simulations
  • Loading branch information
Myoldmopar authored Jul 25, 2024
2 parents 047575a + 096c7e6 commit 980120d
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 1 deletion.
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:*. 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:*, 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.

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

Expand Down
14 changes: 14 additions & 0 deletions src/EnergyPlus/AirflowNetwork/src/Solver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
#include <EnergyPlus/ThermalComfort.hh>
#include <EnergyPlus/UtilityRoutines.hh>
#include <EnergyPlus/WaterThermalTanks.hh>
#include <EnergyPlus/WindowAC.hh>
#include <EnergyPlus/ZoneDehumidifier.hh>
#include <EnergyPlus/ZoneTempPredictorCorrector.hh>

Expand Down Expand Up @@ -10143,6 +10144,7 @@ namespace AirflowNetwork {
using SplitterComponent::GetSplitterNodeNumbers;
using SplitterComponent::GetSplitterOutletNumber;
using WaterThermalTanks::GetHeatPumpWaterHeaterNodeNumber;
using WindowAC::GetWindowACNodeNumber;
using ZoneDehumidifier::GetZoneDehumidifierNodeNumber;

// SUBROUTINE PARAMETER DEFINITIONS:
Expand All @@ -10161,6 +10163,7 @@ namespace AirflowNetwork {

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

// Validate supply and return connections
NodeFound.dimension(m_state.dataLoopNodes->NumOfNodes, false);
Expand Down Expand Up @@ -10273,6 +10276,12 @@ namespace AirflowNetwork {
NodeFound(i) = true;
StandaloneERVFound = true;
}

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

for (int zoneNum = 1; zoneNum <= m_state.dataGlobal->NumOfZones; ++zoneNum) {
Expand Down Expand Up @@ -10413,6 +10422,11 @@ namespace AirflowNetwork {
format(RoutineName) + "A ZoneHVAC:EnergyRecoveryVentilator 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.");
}
NodeFound.deallocate();

// Assign AirLoop Number to every node and linkage
Expand Down
30 changes: 30 additions & 0 deletions src/EnergyPlus/WindowAC.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1499,6 +1499,36 @@ namespace WindowAC {
} // WindAC(WindACNum)%DXCoilType_Num == CoilDX_CoolingHXAssisted && *
}

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)) {
return true;
}
}
return false;
}

int GetWindowACZoneInletAirNode(EnergyPlusData &state, int const WindACNum)
{

Expand Down
2 changes: 2 additions & 0 deletions src/EnergyPlus/WindowAC.hh
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ namespace WindowAC {
bool &HXUnitOn // Used to control HX heat recovery as needed
);

bool GetWindowACNodeNumber(EnergyPlusData &state, int const WindACNum);

int GetWindowACZoneInletAirNode(EnergyPlusData &state, int const WindACNum);

int GetWindowACOutAirNode(EnergyPlusData &state, int const WindACNum);
Expand Down
137 changes: 137 additions & 0 deletions tst/EnergyPlus/unit/AirflowNetworkHVAC.unit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
#include <EnergyPlus/SurfaceGeometry.hh>
#include <EnergyPlus/UtilityRoutines.hh>
#include <EnergyPlus/WaterThermalTanks.hh>
#include <EnergyPlus/WindowAC.hh>
#include <EnergyPlus/ZoneAirLoopEquipmentManager.hh>
#include <EnergyPlus/ZoneEquipmentManager.hh>
#include <EnergyPlus/ZoneTempPredictorCorrector.hh>
Expand Down Expand Up @@ -19767,4 +19768,140 @@ TEST_F(EnergyPlusFixture, AirflowNetwork_ZoneOrderTest)
state->afn->AirflowNetworkNodeData(3).EPlusNodeNum = 0;
}

TEST_F(EnergyPlusFixture, AirflowNetwork_TestZoneEqpSupportZoneWindowAC)
{
// Create zone
state->dataGlobal->NumOfZones = 1;
state->dataHeatBal->Zone.allocate(1);
state->dataHeatBal->Zone(1).Name = "ZONE 1";

// Create surfaces
state->dataSurface->Surface.allocate(1);
state->dataSurface->Surface(1).Name = "ZN004:ROOF001";
state->dataSurface->Surface(1).Zone = 1;
state->dataSurface->Surface(1).ZoneName = "ZONE 1";
state->dataSurface->Surface(1).Azimuth = 0.0;
state->dataSurface->Surface(1).ExtBoundCond = 0;
state->dataSurface->Surface(1).HeatTransSurf = true;
state->dataSurface->Surface(1).Tilt = 180.0;
state->dataSurface->Surface(1).Sides = 4;
state->dataSurface->Surface(1).Name = "ZN004:ROOF002";
state->dataSurface->Surface(1).Zone = 1;
state->dataSurface->Surface(1).ZoneName = "ZONE 1";
state->dataSurface->Surface(1).Azimuth = 0.0;
state->dataSurface->Surface(1).ExtBoundCond = 0;
state->dataSurface->Surface(1).HeatTransSurf = true;
state->dataSurface->Surface(1).Tilt = 180.0;
state->dataSurface->Surface(1).Sides = 4;

state->dataSurface->Surface(1).OriginalClass = DataSurfaces::SurfaceClass::Window;

// Create air system
state->dataAirSystemsData->PrimaryAirSystems.allocate(1);
state->dataAirSystemsData->PrimaryAirSystems(1).NumBranches = 1;
state->dataAirSystemsData->PrimaryAirSystems(1).Branch.allocate(1);
state->dataAirSystemsData->PrimaryAirSystems(1).Branch(1).TotalComponents = 1;
state->dataAirSystemsData->PrimaryAirSystems(1).Branch(1).Comp.allocate(1);
state->dataAirSystemsData->PrimaryAirSystems(1).Branch(1).Comp(1).TypeOf = "Fan:ConstantVolume";

// Create air nodes
state->dataLoopNodes->NumOfNodes = 3;
state->dataLoopNodes->Node.allocate(3);
state->dataLoopNodes->Node(1).FluidType = DataLoopNode::NodeFluidType::Air;
state->dataLoopNodes->Node(2).FluidType = DataLoopNode::NodeFluidType::Air;
state->dataLoopNodes->Node(3).FluidType = DataLoopNode::NodeFluidType::Air;
state->dataLoopNodes->NodeID.allocate(3);
state->dataLoopNodes->NodeID(1) = "ZONE 1 AIR NODE";
bool errFlag{false};
BranchNodeConnections::RegisterNodeConnection(*state,
1,
"ZONE 1 AIR NODE",
DataLoopNode::ConnectionObjectType::FanOnOff,
"Object1",
DataLoopNode::ConnectionType::ZoneNode,
NodeInputManager::CompFluidStream::Primary,
false,
errFlag);
EXPECT_FALSE(errFlag);

// Connect zone to air node
state->dataZoneEquip->ZoneEquipConfig.allocate(1);
state->dataZoneEquip->ZoneEquipConfig(1).IsControlled = true;
state->dataZoneEquip->ZoneEquipConfig(1).ZoneName = "ZONE 1";
state->dataZoneEquip->ZoneEquipConfig(1).ZoneNode = 1;
state->dataZoneEquip->ZoneEquipConfig(1).NumInletNodes = 0;
state->dataZoneEquip->ZoneEquipConfig(1).NumReturnNodes = 0;
state->dataZoneEquip->ZoneEquipConfig(1).IsControlled = true;

// One AirflowNetwork:MultiZone:Zone object
state->afn->AirflowNetworkNumOfZones = 1;
state->afn->MultizoneZoneData.allocate(1);
state->afn->MultizoneZoneData(1).ZoneNum = 1;
state->afn->MultizoneZoneData(1).ZoneName = "ZONE 1";

// Assume only one AirflowNetwork:Distribution:Node object is set for the Zone Air Node
state->afn->AirflowNetworkNumOfNodes = 1;
state->afn->AirflowNetworkNodeData.allocate(1);
state->afn->AirflowNetworkNodeData(1).Name = "ZONE 1";
state->afn->AirflowNetworkNodeData(1).EPlusZoneNum = 1;

state->afn->SplitterNodeNumbers.allocate(2);
state->afn->SplitterNodeNumbers(1) = 0;
state->afn->SplitterNodeNumbers(2) = 0;

// Set flag to support zone equipment
state->afn->simulation_control.allow_unsupported_zone_equipment = true;

// Create Fans
Real64 supplyFlowRate = 0.005;
Real64 exhaustFlowRate = 0.005;

auto *fan1 = new Fans::FanComponent;
fan1->Name = "SupplyFan";

fan1->inletNodeNum = 2;
fan1->outletNodeNum = 3;
fan1->type = HVAC::FanType::OnOff;
fan1->maxAirFlowRate = supplyFlowRate;

state->dataFans->fans.push_back(fan1);
state->dataFans->fanMap.insert_or_assign(fan1->Name, state->dataFans->fans.size());

state->dataLoopNodes->NodeID(2) = "SupplyFanInletNode";
BranchNodeConnections::RegisterNodeConnection(*state,
2,
state->dataLoopNodes->NodeID(2),
DataLoopNode::ConnectionObjectType::FanOnOff,
state->dataFans->fans(1)->Name,
DataLoopNode::ConnectionType::Inlet,
NodeInputManager::CompFluidStream::Primary,
false,
errFlag);
state->dataLoopNodes->NodeID(3) = "SupplyFanOutletNode";
BranchNodeConnections::RegisterNodeConnection(*state,
3,
state->dataLoopNodes->NodeID(3),
DataLoopNode::ConnectionObjectType::FanOnOff,
state->dataFans->fans(1)->Name,
DataLoopNode::ConnectionType::Outlet,
NodeInputManager::CompFluidStream::Primary,
false,
errFlag);

// Create Window AC
state->dataWindowAC->WindAC.allocate(1);
state->dataWindowAC->GetWindowACInputFlag = false;
state->dataWindowAC->NumWindAC = 1;
state->dataWindowAC->WindAC(1).OutAirVolFlow = 0.0;
state->dataWindowAC->WindAC(1).FanName = state->dataFans->fans(1)->Name;
state->dataWindowAC->WindAC(1).FanIndex = 1;

// Check validation and expected warning
state->afn->validate_distribution();

EXPECT_TRUE(compare_err_stream(" ** Warning ** AirflowNetwork::Solver::validate_distribution: A ZoneHVAC:WindowAirConditioner is simulated "
"along with an AirflowNetwork but is not included in the AirflowNetwork.\n",
true));
}

} // namespace EnergyPlus

0 comments on commit 980120d

Please sign in to comment.