Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2024, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // C++ Headers
49 : #include <cmath>
50 :
51 : // ObjexxFCL Headers
52 : #include <ObjexxFCL/Array.functions.hh>
53 : #include <ObjexxFCL/Fmath.hh>
54 :
55 : // EnergyPlus Headers
56 : #include <EnergyPlus/Autosizing/SystemAirFlowSizing.hh>
57 : #include <EnergyPlus/BranchNodeConnections.hh>
58 : #include <EnergyPlus/CurveManager.hh>
59 : #include <EnergyPlus/Data/EnergyPlusData.hh>
60 : #include <EnergyPlus/DataEnvironment.hh>
61 : #include <EnergyPlus/DataHVACGlobals.hh>
62 : #include <EnergyPlus/DataHeatBalance.hh>
63 : #include <EnergyPlus/DataLoopNode.hh>
64 : #include <EnergyPlus/DataSizing.hh>
65 : #include <EnergyPlus/DataZoneControls.hh>
66 : #include <EnergyPlus/DataZoneEquipment.hh>
67 : #include <EnergyPlus/Fans.hh>
68 : #include <EnergyPlus/General.hh>
69 : #include <EnergyPlus/GeneralRoutines.hh>
70 : #include <EnergyPlus/GlobalNames.hh>
71 : #include <EnergyPlus/HVACStandAloneERV.hh>
72 : #include <EnergyPlus/HeatRecovery.hh>
73 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
74 : #include <EnergyPlus/MixedAir.hh>
75 : #include <EnergyPlus/NodeInputManager.hh>
76 : #include <EnergyPlus/OutAirNodeManager.hh>
77 : #include <EnergyPlus/OutputProcessor.hh>
78 : #include <EnergyPlus/ScheduleManager.hh>
79 : #include <EnergyPlus/UtilityRoutines.hh>
80 :
81 : namespace EnergyPlus::HVACStandAloneERV {
82 :
83 : // Module containing the routines dealing with stand alone energy recovery ventilators (ERVs)
84 :
85 : // MODULE INFORMATION:
86 : // AUTHOR Richard Raustad, FSEC
87 : // DATE WRITTEN June 2003
88 :
89 : // PURPOSE OF THIS MODULE:
90 : // To encapsulate the data and algorithms needed to simulate stand alone
91 : // energy recovery ventilators that condition outdoor ventilation air and
92 : // supply that air directly to a zone.
93 :
94 : // METHODOLOGY EMPLOYED:
95 : // These units are modeled as a collection of components: air-to-air generic heat exchanger,
96 : // supply air fan, exhaust air fan and an optional controller to avoid overheating
97 : // of the supply air (economizer or free cooling operation).
98 :
99 653189 : void SimStandAloneERV(EnergyPlusData &state,
100 : std::string_view CompName, // name of the Stand Alone ERV unit
101 : int const ZoneNum, // number of zone being served unused1208
102 : bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
103 : Real64 &SensLoadMet, // net sensible load supplied by the ERV unit to the zone (W)
104 : Real64 &LatLoadMet, // net latent load supplied by ERV unit to the zone (kg/s),
105 : int &CompIndex // pointer to correct component
106 : )
107 : {
108 :
109 : // SUBROUTINE INFORMATION:
110 : // AUTHOR Richard Raustad, FSEC
111 : // DATE WRITTEN June 2003
112 : // MODIFIED Don Shirey, Aug 2009 (LatLoadMet)
113 :
114 : // PURPOSE OF THIS SUBROUTINE:
115 : // Manages the simulation of a Stand Alone ERV unit. Called from SimZoneEquipment
116 :
117 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
118 : int StandAloneERVNum; // index of Stand Alone ERV unit being simulated
119 :
120 : // First time SimStandAloneERV is called, get the input for all Stand Alone ERV units
121 653189 : if (state.dataHVACStandAloneERV->GetERVInputFlag) {
122 5 : GetStandAloneERV(state);
123 5 : state.dataHVACStandAloneERV->GetERVInputFlag = false;
124 : }
125 :
126 : // Find the correct Stand Alone ERV unit index
127 653189 : if (CompIndex == 0) {
128 107 : StandAloneERVNum = Util::FindItem(CompName, state.dataHVACStandAloneERV->StandAloneERV);
129 107 : if (StandAloneERVNum == 0) {
130 0 : ShowFatalError(state, format("SimStandAloneERV: Unit not found={}", CompName));
131 : }
132 107 : CompIndex = StandAloneERVNum;
133 : } else {
134 653082 : StandAloneERVNum = CompIndex;
135 653082 : if (StandAloneERVNum > state.dataHVACStandAloneERV->NumStandAloneERVs || StandAloneERVNum < 1) {
136 0 : ShowFatalError(state,
137 0 : format("SimStandAloneERV: Invalid CompIndex passed={}, Number of Units={}, Entered Unit name={}",
138 : StandAloneERVNum,
139 0 : state.dataHVACStandAloneERV->NumStandAloneERVs,
140 : CompName));
141 : }
142 653082 : if (state.dataHVACStandAloneERV->CheckEquipName(StandAloneERVNum)) {
143 107 : if (CompName != state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).Name) {
144 0 : ShowFatalError(state,
145 0 : format("SimStandAloneERV: Invalid CompIndex passed={}, Unit name={}, stored Unit Name for that index={}",
146 : StandAloneERVNum,
147 : CompName,
148 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).Name));
149 : }
150 107 : state.dataHVACStandAloneERV->CheckEquipName(StandAloneERVNum) = false;
151 : }
152 : }
153 :
154 : // Initialize the Stand Alone ERV unit
155 653189 : InitStandAloneERV(state, StandAloneERVNum, ZoneNum, FirstHVACIteration);
156 :
157 653189 : CalcStandAloneERV(state, StandAloneERVNum, FirstHVACIteration, SensLoadMet, LatLoadMet);
158 :
159 653189 : ReportStandAloneERV(state, StandAloneERVNum);
160 653189 : }
161 :
162 5 : void GetStandAloneERV(EnergyPlusData &state)
163 : {
164 :
165 : // SUBROUTINE INFORMATION:
166 : // AUTHOR Richard Raustad
167 : // DATE WRITTEN June 2003
168 : // MODIFIED July 2012, Chandan Sharma - FSEC: Added zone sys avail managers
169 :
170 : // PURPOSE OF THIS SUBROUTINE:
171 : // Obtains input data for Stand Alone ERV units and stores it in the Stand Alone ERV data structure
172 :
173 : // METHODOLOGY EMPLOYED:
174 : // Uses "Get" routines to read in data.
175 :
176 : static constexpr std::string_view routineName = "GetStandAloneERV";
177 :
178 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
179 5 : Array1D_string Alphas; // Alpha items for object
180 5 : Array1D<Real64> Numbers; // Numeric items for object
181 5 : Array1D_string cAlphaFields;
182 5 : Array1D_string cNumericFields;
183 5 : Array1D_bool lAlphaBlanks;
184 5 : Array1D_bool lNumericBlanks;
185 : int NumArg;
186 : int NumAlphas; // Number of Alphas for each GetObjectItem call
187 : int NumNumbers; // Number of Numbers for each GetObjectItem call
188 : int IOStatus; // Used in GetObjectItem
189 5 : bool ErrorsFound(false); // Set to true if errors in input, fatal at end of routine
190 : int NumERVCtrlrs; // total number of CONTROLLER:STAND ALONE ERV objects
191 : int ERVControllerNum; // index to ERV controller
192 : Real64 AirFlowRate; // used to find zone with humidistat
193 : int NodeNumber; // used to find zone with humidistat
194 : int HStatZoneNum; // used to find zone with humidistat
195 : int NumHstatZone; // index to humidity controlled zones
196 : Real64 HXSupAirFlowRate; // HX supply air flow rate [m3/s]
197 : int ZoneInletCZN; // used for warning when zone node not listed in equipment connections
198 : int ZoneExhaustCZN; // used for warning when zone node not listed in equipment connections
199 :
200 5 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "ZoneHVAC:EnergyRecoveryVentilator", NumArg, NumAlphas, NumNumbers);
201 5 : int MaxAlphas = NumAlphas;
202 5 : int MaxNumbers = NumNumbers;
203 5 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
204 : state, "ZoneHVAC:EnergyRecoveryVentilator:Controller", NumArg, NumAlphas, NumNumbers);
205 5 : MaxAlphas = max(MaxAlphas, NumAlphas);
206 5 : MaxNumbers = max(MaxNumbers, NumNumbers);
207 :
208 5 : Alphas.allocate(MaxAlphas);
209 5 : Numbers.dimension(MaxNumbers, 0.0);
210 5 : cAlphaFields.allocate(MaxAlphas);
211 5 : cNumericFields.allocate(MaxNumbers);
212 5 : lNumericBlanks.dimension(MaxNumbers, false);
213 5 : lAlphaBlanks.dimension(MaxAlphas, false);
214 :
215 5 : state.dataHVACStandAloneERV->GetERVInputFlag = false;
216 :
217 : // find the number of each type of Stand Alone ERV unit
218 5 : std::string CurrentModuleObject = "ZoneHVAC:EnergyRecoveryVentilator";
219 :
220 5 : state.dataHVACStandAloneERV->NumStandAloneERVs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
221 :
222 : // allocate the data structures
223 5 : state.dataHVACStandAloneERV->StandAloneERV.allocate(state.dataHVACStandAloneERV->NumStandAloneERVs);
224 5 : state.dataHVACStandAloneERV->HeatExchangerUniqueNames.reserve(static_cast<unsigned>(state.dataHVACStandAloneERV->NumStandAloneERVs));
225 5 : state.dataHVACStandAloneERV->SupplyAirFanUniqueNames.reserve(static_cast<unsigned>(state.dataHVACStandAloneERV->NumStandAloneERVs));
226 5 : state.dataHVACStandAloneERV->ExhaustAirFanUniqueNames.reserve(static_cast<unsigned>(state.dataHVACStandAloneERV->NumStandAloneERVs));
227 5 : state.dataHVACStandAloneERV->ControllerUniqueNames.reserve(static_cast<unsigned>(state.dataHVACStandAloneERV->NumStandAloneERVs));
228 5 : state.dataHVACStandAloneERV->CheckEquipName.dimension(state.dataHVACStandAloneERV->NumStandAloneERVs, true);
229 :
230 : // loop over Stand Alone ERV units; get and load the input data
231 112 : for (int StandAloneERVIndex = 1; StandAloneERVIndex <= state.dataHVACStandAloneERV->NumStandAloneERVs; ++StandAloneERVIndex) {
232 107 : auto &standAloneERV = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVIndex);
233 :
234 107 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
235 : CurrentModuleObject,
236 : StandAloneERVIndex,
237 : Alphas,
238 : NumAlphas,
239 : Numbers,
240 : NumNumbers,
241 : IOStatus,
242 : lNumericBlanks,
243 : lAlphaBlanks,
244 : cAlphaFields,
245 : cNumericFields);
246 :
247 107 : standAloneERV.Name = Alphas(1);
248 107 : standAloneERV.UnitType = CurrentModuleObject;
249 :
250 107 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, standAloneERV.Name};
251 :
252 107 : if (lAlphaBlanks(2)) {
253 0 : standAloneERV.SchedPtr = ScheduleManager::ScheduleAlwaysOn;
254 : } else {
255 107 : standAloneERV.SchedPtr = ScheduleManager::GetScheduleIndex(state, Alphas(2)); // convert schedule name to pointer
256 107 : if (standAloneERV.SchedPtr == 0) {
257 0 : ShowSevereError(state, format("{}, \"{}\" {} not found = {}", CurrentModuleObject, standAloneERV.Name, cAlphaFields(2), Alphas(2)));
258 0 : ErrorsFound = true;
259 : }
260 : }
261 :
262 107 : GlobalNames::IntraObjUniquenessCheck(
263 214 : state, Alphas(3), CurrentModuleObject, cAlphaFields(3), state.dataHVACStandAloneERV->HeatExchangerUniqueNames, ErrorsFound);
264 107 : standAloneERV.HeatExchangerName = Alphas(3);
265 107 : bool errFlag = false;
266 107 : standAloneERV.hxType = HeatRecovery::GetHeatExchangerObjectTypeNum(state, standAloneERV.HeatExchangerName, errFlag);
267 107 : if (errFlag) {
268 0 : ShowContinueError(state, format("... occurs in {} \"{}\"", CurrentModuleObject, standAloneERV.Name));
269 0 : ErrorsFound = true;
270 : }
271 :
272 107 : errFlag = false;
273 107 : HXSupAirFlowRate = HeatRecovery::GetSupplyAirFlowRate(state, standAloneERV.HeatExchangerName, errFlag);
274 107 : if (errFlag) {
275 0 : ShowContinueError(state, format("... occurs in {} \"{}\"", CurrentModuleObject, standAloneERV.Name));
276 0 : ErrorsFound = true;
277 : }
278 107 : standAloneERV.DesignHXVolFlowRate = HXSupAirFlowRate;
279 :
280 107 : standAloneERV.SupplyAirFanName = Alphas(4);
281 107 : GlobalNames::IntraObjUniquenessCheck(
282 214 : state, Alphas(4), CurrentModuleObject, cAlphaFields(4), state.dataHVACStandAloneERV->SupplyAirFanUniqueNames, ErrorsFound);
283 :
284 107 : if ((standAloneERV.SupplyAirFanIndex = Fans::GetFanIndex(state, standAloneERV.SupplyAirFanName)) == 0) {
285 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(4), standAloneERV.SupplyAirFanName);
286 0 : ErrorsFound = true;
287 : } else {
288 107 : auto *fan = state.dataFans->fans(standAloneERV.SupplyAirFanIndex);
289 107 : standAloneERV.supplyAirFanType = fan->type;
290 107 : standAloneERV.SupplyAirFanSchPtr = fan->availSchedNum;
291 107 : standAloneERV.DesignSAFanVolFlowRate = fan->maxAirFlowRate;
292 107 : standAloneERV.SupplyAirOutletNode = fan->outletNodeNum;
293 : }
294 :
295 107 : standAloneERV.ExhaustAirFanName = Alphas(5);
296 107 : GlobalNames::IntraObjUniquenessCheck(
297 214 : state, Alphas(5), CurrentModuleObject, cAlphaFields(5), state.dataHVACStandAloneERV->ExhaustAirFanUniqueNames, ErrorsFound);
298 :
299 107 : if ((standAloneERV.ExhaustAirFanIndex = Fans::GetFanIndex(state, standAloneERV.ExhaustAirFanName)) == 0) {
300 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(5), standAloneERV.ExhaustAirFanName);
301 0 : ErrorsFound = true;
302 :
303 : } else {
304 107 : auto *fan = state.dataFans->fans(standAloneERV.ExhaustAirFanIndex);
305 107 : standAloneERV.exhaustAirFanType = fan->type;
306 :
307 107 : standAloneERV.ExhaustAirFanSchPtr = fan->availSchedNum;
308 107 : standAloneERV.DesignEAFanVolFlowRate = fan->maxAirFlowRate;
309 107 : standAloneERV.ExhaustAirOutletNode = fan->outletNodeNum;
310 : }
311 :
312 107 : errFlag = false;
313 107 : standAloneERV.SupplyAirInletNode = HeatRecovery::GetSupplyInletNode(state, standAloneERV.HeatExchangerName, errFlag);
314 107 : standAloneERV.ExhaustAirInletNode = HeatRecovery::GetSecondaryInletNode(state, standAloneERV.HeatExchangerName, errFlag);
315 107 : if (errFlag) {
316 0 : ShowContinueError(state, format("... occurs in {} ={}", CurrentModuleObject, standAloneERV.Name));
317 0 : ErrorsFound = true;
318 : }
319 107 : standAloneERV.SupplyAirInletNode = GetOnlySingleNode(state,
320 107 : state.dataLoopNodes->NodeID(standAloneERV.SupplyAirInletNode),
321 : ErrorsFound,
322 : DataLoopNode::ConnectionObjectType::ZoneHVACEnergyRecoveryVentilator,
323 107 : Alphas(1),
324 : DataLoopNode::NodeFluidType::Air,
325 : DataLoopNode::ConnectionType::Inlet,
326 : NodeInputManager::CompFluidStream::Primary,
327 : DataLoopNode::ObjectIsParent);
328 107 : standAloneERV.SupplyAirOutletNode = GetOnlySingleNode(state,
329 107 : state.dataLoopNodes->NodeID(standAloneERV.SupplyAirOutletNode),
330 : ErrorsFound,
331 : DataLoopNode::ConnectionObjectType::ZoneHVACEnergyRecoveryVentilator,
332 107 : Alphas(1),
333 : DataLoopNode::NodeFluidType::Air,
334 : DataLoopNode::ConnectionType::Outlet,
335 : NodeInputManager::CompFluidStream::Primary,
336 : DataLoopNode::ObjectIsParent);
337 107 : standAloneERV.ExhaustAirInletNode = GetOnlySingleNode(state,
338 107 : state.dataLoopNodes->NodeID(standAloneERV.ExhaustAirInletNode),
339 : ErrorsFound,
340 : DataLoopNode::ConnectionObjectType::ZoneHVACEnergyRecoveryVentilator,
341 107 : Alphas(1),
342 : DataLoopNode::NodeFluidType::Air,
343 : DataLoopNode::ConnectionType::Inlet,
344 : NodeInputManager::CompFluidStream::Secondary,
345 : DataLoopNode::ObjectIsParent);
346 107 : standAloneERV.ExhaustAirOutletNode = GetOnlySingleNode(state,
347 107 : state.dataLoopNodes->NodeID(standAloneERV.ExhaustAirOutletNode),
348 : ErrorsFound,
349 : DataLoopNode::ConnectionObjectType::ZoneHVACEnergyRecoveryVentilator,
350 107 : Alphas(1),
351 : DataLoopNode::NodeFluidType::Air,
352 : DataLoopNode::ConnectionType::ReliefAir,
353 : NodeInputManager::CompFluidStream::Secondary,
354 : DataLoopNode::ObjectIsParent);
355 :
356 : // Check that supply air inlet node is an OA node
357 107 : if (!OutAirNodeManager::CheckOutAirNodeNumber(state, standAloneERV.SupplyAirInletNode)) {
358 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, standAloneERV.Name));
359 0 : ShowContinueError(state,
360 0 : format(" Node name of supply air inlet node not valid Outdoor Air Node = {}",
361 0 : state.dataLoopNodes->NodeID(standAloneERV.SupplyAirInletNode)));
362 0 : ShowContinueError(state, "...does not appear in an OutdoorAir:NodeList or as an OutdoorAir:Node.");
363 0 : ErrorsFound = true;
364 : }
365 :
366 : // Check to make sure inlet and exhaust nodes are listed in a ZoneHVAC:EquipmentConnections object
367 107 : bool ZoneInletNodeFound = false;
368 107 : bool ZoneExhaustNodeFound = false;
369 7851 : for (int ControlledZoneNum = 1; ControlledZoneNum <= state.dataGlobal->NumOfZones; ++ControlledZoneNum) {
370 7744 : if (!ZoneInletNodeFound) {
371 10783 : for (NodeNumber = 1; NodeNumber <= state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumInletNodes; ++NodeNumber) {
372 6988 : if (state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNode(NodeNumber) == standAloneERV.SupplyAirOutletNode) {
373 107 : ZoneInletNodeFound = true;
374 107 : ZoneInletCZN = ControlledZoneNum;
375 107 : break; // found zone inlet node
376 : }
377 : }
378 : }
379 7744 : if (!ZoneExhaustNodeFound) {
380 7245 : for (NodeNumber = 1; NodeNumber <= state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumExhaustNodes; ++NodeNumber) {
381 3450 : if (state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ExhaustNode(NodeNumber) == standAloneERV.ExhaustAirInletNode) {
382 107 : ZoneExhaustNodeFound = true;
383 107 : ZoneExhaustCZN = ControlledZoneNum;
384 107 : break; // found zone exhaust node
385 : }
386 : }
387 : }
388 : }
389 107 : if (!ZoneInletNodeFound) {
390 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, standAloneERV.Name));
391 0 : ShowContinueError(state, "... Node name of supply air outlet node does not appear in a ZoneHVAC:EquipmentConnections object.");
392 0 : ShowContinueError(state, format("... Supply air outlet node = {}", state.dataLoopNodes->NodeID(standAloneERV.SupplyAirOutletNode)));
393 0 : ErrorsFound = true;
394 : }
395 107 : if (!ZoneExhaustNodeFound) {
396 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, standAloneERV.Name));
397 0 : ShowContinueError(state, "... Node name of exhaust air inlet node does not appear in a ZoneHVAC:EquipmentConnections object.");
398 0 : ShowContinueError(state, format("... Exhaust air inlet node = {}", state.dataLoopNodes->NodeID(standAloneERV.ExhaustAirInletNode)));
399 0 : ErrorsFound = true;
400 : }
401 : // If nodes are found, make sure they are in the same zone
402 107 : if (ZoneInletNodeFound && ZoneExhaustNodeFound) {
403 107 : if (ZoneInletCZN != ZoneExhaustCZN) {
404 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, standAloneERV.Name));
405 0 : ShowContinueError(state,
406 : "... Node name of supply air outlet node and exhasut air inlet node must appear in the same "
407 : "ZoneHVAC:EquipmentConnections object.");
408 0 : ShowContinueError(state, format("... Supply air outlet node = {}", state.dataLoopNodes->NodeID(standAloneERV.SupplyAirOutletNode)));
409 0 : ShowContinueError(
410 0 : state, format("... ZoneHVAC:EquipmentConnections Zone Name = {}", state.dataZoneEquip->ZoneEquipConfig(ZoneInletCZN).ZoneName));
411 0 : ShowContinueError(state, format("... Exhaust air inlet node = {}", state.dataLoopNodes->NodeID(standAloneERV.ExhaustAirInletNode)));
412 0 : ShowContinueError(
413 0 : state, format("... ZoneHVAC:EquipmentConnections Zone Name = {}", state.dataZoneEquip->ZoneEquipConfig(ZoneExhaustCZN).ZoneName));
414 0 : ErrorsFound = true;
415 : }
416 : }
417 :
418 107 : standAloneERV.ControllerName = Alphas(6);
419 : // If controller name is blank the ERV unit will operate with no controller
420 107 : if (lAlphaBlanks(6)) {
421 3 : standAloneERV.ControllerName = "xxxxx";
422 3 : standAloneERV.ControllerNameDefined = false;
423 : } else {
424 : // Verify controller name in Stand Alone ERV object matches name of valid controller object
425 104 : GlobalNames::IntraObjUniquenessCheck(
426 208 : state, Alphas(6), CurrentModuleObject, cAlphaFields(6), state.dataHVACStandAloneERV->ControllerUniqueNames, ErrorsFound);
427 104 : standAloneERV.ControllerNameDefined = true;
428 104 : if (ErrorsFound) {
429 0 : standAloneERV.ControllerNameDefined = false;
430 : }
431 :
432 104 : if (state.dataInputProcessing->inputProcessor->getObjectItemNum(
433 104 : state, "ZoneHVAC:EnergyRecoveryVentilator:Controller", standAloneERV.ControllerName) <= 0) {
434 0 : ShowSevereError(
435 0 : state, format("{} controller type ZoneHVAC:EnergyRecoveryVentilator:Controller not found = {}", CurrentModuleObject, Alphas(6)));
436 0 : ErrorsFound = true;
437 0 : standAloneERV.ControllerNameDefined = false;
438 : }
439 : }
440 :
441 107 : if (!lAlphaBlanks(7)) {
442 0 : standAloneERV.AvailManagerListName = Alphas(7);
443 : }
444 :
445 : // Read supply and exhaust air flow rates
446 107 : standAloneERV.SupplyAirVolFlow = Numbers(1);
447 107 : standAloneERV.ExhaustAirVolFlow = Numbers(2);
448 :
449 : // Read ventilation rate per floor area for autosizing HX and fans
450 107 : standAloneERV.AirVolFlowPerFloorArea = Numbers(3);
451 107 : standAloneERV.AirVolFlowPerOccupant = Numbers(4);
452 :
453 107 : if (standAloneERV.SupplyAirVolFlow == DataSizing::AutoSize && standAloneERV.DesignSAFanVolFlowRate != DataSizing::AutoSize) {
454 0 : ShowSevereError(state, format("{} \"{}\"", CurrentModuleObject, standAloneERV.Name));
455 0 : ShowContinueError(state,
456 0 : format("... When autosizing ERV, supply air fan = {} \"{}\" must also be autosized.",
457 0 : HVAC::fanTypeNames[(int)standAloneERV.supplyAirFanType],
458 0 : standAloneERV.SupplyAirFanName));
459 : }
460 :
461 107 : if (standAloneERV.ExhaustAirVolFlow == DataSizing::AutoSize && standAloneERV.DesignEAFanVolFlowRate != DataSizing::AutoSize) {
462 0 : ShowSevereError(state, format("{} \"{}\"", CurrentModuleObject, standAloneERV.Name));
463 0 : ShowContinueError(state,
464 0 : format("... When autosizing ERV, exhaust air fan = {} \"{}\" must also be autosized.",
465 0 : HVAC::fanTypeNames[(int)standAloneERV.exhaustAirFanType],
466 0 : standAloneERV.ExhaustAirFanName));
467 : }
468 :
469 107 : if (standAloneERV.SupplyAirVolFlow == DataSizing::AutoSize && HXSupAirFlowRate != DataSizing::AutoSize) {
470 0 : ShowSevereError(state, format("{} \"{}\"", CurrentModuleObject, standAloneERV.Name));
471 0 : ShowContinueError(
472 : state,
473 0 : format("... When autosizing ERV {}, nominal supply air flow rate for heat exchanger with name = {} must also be autosized.",
474 : cNumericFields(1),
475 0 : standAloneERV.HeatExchangerName));
476 : }
477 :
478 107 : if (standAloneERV.ExhaustAirVolFlow == DataSizing::AutoSize && HXSupAirFlowRate != DataSizing::AutoSize) {
479 0 : ShowSevereError(state, format("{} \"{}\"", CurrentModuleObject, standAloneERV.Name));
480 0 : ShowContinueError(
481 : state,
482 0 : format("... When autosizing ERV {}, nominal supply air flow rate for heat exchanger with name = {} must also be autosized.",
483 : cNumericFields(2),
484 0 : standAloneERV.HeatExchangerName));
485 : }
486 :
487 : // Compare the ERV SA flow rates to SA fan object.
488 107 : if (standAloneERV.DesignSAFanVolFlowRate != DataSizing::AutoSize && standAloneERV.SupplyAirVolFlow != DataSizing::AutoSize) {
489 5 : if (standAloneERV.SupplyAirVolFlow > standAloneERV.DesignSAFanVolFlowRate) {
490 0 : ShowWarningError(state,
491 0 : format("{} = {} has a {} > Max Volume Flow Rate defined in the associated fan object, should be <=",
492 : CurrentModuleObject,
493 0 : standAloneERV.Name,
494 : cNumericFields(1)));
495 0 : ShowContinueError(state,
496 0 : format("... Entered value={:.2R}... Fan [{} \"{}\"] Max Value = {:.2R}",
497 0 : standAloneERV.SupplyAirVolFlow,
498 0 : HVAC::fanTypeNames[(int)standAloneERV.supplyAirFanType],
499 0 : standAloneERV.SupplyAirFanName,
500 0 : standAloneERV.DesignSAFanVolFlowRate));
501 0 : ShowContinueError(state,
502 0 : format(" The ERV {} is reset to the supply air fan flow rate and the simulation continues.", cNumericFields(1)));
503 0 : standAloneERV.SupplyAirVolFlow = standAloneERV.DesignSAFanVolFlowRate;
504 : }
505 : }
506 107 : if (standAloneERV.SupplyAirVolFlow != DataSizing::AutoSize) {
507 107 : if (standAloneERV.SupplyAirVolFlow <= 0.0) {
508 0 : ShowSevereError(state,
509 0 : format("{} = {} has a {} <= 0.0, it must be >0.0", CurrentModuleObject, standAloneERV.Name, cNumericFields(1)));
510 0 : ShowContinueError(state, format("... Entered value={:.2R}", standAloneERV.SupplyAirVolFlow));
511 0 : ErrorsFound = true;
512 : }
513 : } else {
514 0 : if (standAloneERV.AirVolFlowPerFloorArea == 0.0 && standAloneERV.AirVolFlowPerOccupant == 0.0) {
515 0 : ShowSevereError(state, format("{} \"{}\"", CurrentModuleObject, standAloneERV.Name));
516 0 : ShowContinueError(
517 : state,
518 0 : format("... Autosizing {} requires at least one input for {} or {}.", cNumericFields(1), cNumericFields(3), cNumericFields(4)));
519 0 : ErrorsFound = true;
520 : }
521 : // both inputs must be autosized
522 0 : if (standAloneERV.ExhaustAirVolFlow != DataSizing::AutoSize) {
523 0 : ShowSevereError(state, format("{} \"{}\"", CurrentModuleObject, standAloneERV.Name));
524 0 : ShowContinueError(state, format("... When autosizing, {} and {} must both be autosized.", cNumericFields(1), cNumericFields(2)));
525 0 : ErrorsFound = true;
526 : }
527 : }
528 :
529 : // Compare the ERV EA flow rates to EA fan object.
530 107 : if (standAloneERV.DesignEAFanVolFlowRate != DataSizing::AutoSize && standAloneERV.ExhaustAirVolFlow != DataSizing::AutoSize) {
531 5 : if (standAloneERV.ExhaustAirVolFlow > standAloneERV.DesignEAFanVolFlowRate) {
532 0 : ShowWarningError(state,
533 0 : format("{} = {} has an {} > Max Volume Flow Rate defined in the associated fan object, should be <=",
534 : CurrentModuleObject,
535 0 : standAloneERV.Name,
536 : cNumericFields(2)));
537 0 : ShowContinueError(state,
538 0 : format("... Entered value={:.2R}... Fan [{}:{}] Max Value = {:.2R}",
539 0 : standAloneERV.ExhaustAirVolFlow,
540 0 : HVAC::fanTypeNames[(int)standAloneERV.exhaustAirFanType],
541 0 : standAloneERV.ExhaustAirFanName,
542 0 : standAloneERV.DesignEAFanVolFlowRate));
543 0 : ShowContinueError(state,
544 0 : format(" The ERV {} is reset to the exhaust air fan flow rate and the simulation continues.", cNumericFields(2)));
545 0 : standAloneERV.ExhaustAirVolFlow = standAloneERV.DesignEAFanVolFlowRate;
546 : }
547 : }
548 107 : if (standAloneERV.ExhaustAirVolFlow != DataSizing::AutoSize) {
549 107 : if (standAloneERV.ExhaustAirVolFlow <= 0.0) {
550 0 : ShowSevereError(state,
551 0 : format("{} = {} has an {} <= 0.0, it must be >0.0", CurrentModuleObject, standAloneERV.Name, cNumericFields(2)));
552 0 : ShowContinueError(state, format("... Entered value={:.2R}", standAloneERV.ExhaustAirVolFlow));
553 0 : ErrorsFound = true;
554 : }
555 : } else {
556 0 : if (standAloneERV.AirVolFlowPerFloorArea == 0.0 && standAloneERV.AirVolFlowPerOccupant == 0.0) {
557 0 : ShowSevereError(state, format("{} \"{}\"", CurrentModuleObject, standAloneERV.Name));
558 0 : ShowContinueError(
559 : state,
560 0 : format("... Autosizing {} requires at least one input for {} or {}.", cNumericFields(2), cNumericFields(3), cNumericFields(4)));
561 0 : ErrorsFound = true;
562 : }
563 0 : if (standAloneERV.SupplyAirVolFlow != DataSizing::AutoSize) {
564 0 : ShowSevereError(state, format("{} \"{}\"", CurrentModuleObject, standAloneERV.Name));
565 0 : ShowContinueError(state, format("... When autosizing, {} and {} must both be autosized.", cNumericFields(1), cNumericFields(2)));
566 0 : ErrorsFound = true;
567 : }
568 : }
569 :
570 : // Add supply fan to component sets array
571 107 : std::string CompSetSupplyFanInlet = "UNDEFINED";
572 107 : std::string CompSetSupplyFanOutlet = state.dataLoopNodes->NodeID(standAloneERV.SupplyAirOutletNode);
573 :
574 : // Add exhaust fan to component sets array
575 107 : std::string CompSetExhaustFanInlet = "UNDEFINED";
576 107 : std::string CompSetExhaustFanOutlet = state.dataLoopNodes->NodeID(standAloneERV.ExhaustAirOutletNode);
577 :
578 : // Add HX to component sets array
579 107 : BranchNodeConnections::SetUpCompSets(
580 : state, standAloneERV.UnitType, standAloneERV.Name, "UNDEFINED", standAloneERV.HeatExchangerName, "UNDEFINED", "UNDEFINED");
581 :
582 : // Add supply fan to component sets array
583 107 : BranchNodeConnections::SetUpCompSets(state,
584 : standAloneERV.UnitType,
585 : standAloneERV.Name,
586 : "UNDEFINED",
587 : standAloneERV.SupplyAirFanName,
588 : CompSetSupplyFanInlet,
589 : CompSetSupplyFanOutlet);
590 :
591 : // Add exhaust fan to component sets array
592 107 : BranchNodeConnections::SetUpCompSets(state,
593 : standAloneERV.UnitType,
594 : standAloneERV.Name,
595 : "UNDEFINED",
596 : standAloneERV.ExhaustAirFanName,
597 : CompSetExhaustFanInlet,
598 : CompSetExhaustFanOutlet);
599 :
600 : // Verify HX name in Stand Alone ERV object matches name of valid HX object
601 107 : if (state.dataInputProcessing->inputProcessor->getObjectItemNum(
602 107 : state, "HeatExchanger:AirToAir:SensibleAndLatent", standAloneERV.HeatExchangerName) <= 0) {
603 0 : ShowSevereError(state,
604 0 : format("{} heat exchanger type HeatExchanger:AirToAir:SensibleAndLatent not found = {}",
605 : CurrentModuleObject,
606 0 : standAloneERV.HeatExchangerName));
607 0 : ErrorsFound = true;
608 : }
609 : // Verify supply air fan name in Stand Alone ERV object matches name of valid fan object
610 107 : if (standAloneERV.supplyAirFanType != HVAC::FanType::SystemModel) {
611 104 : if (state.dataInputProcessing->inputProcessor->getObjectItemNum(state, "Fan:OnOff", standAloneERV.SupplyAirFanName) <= 0) {
612 0 : ShowSevereError(state, format("{} supply fan type Fan:OnOff not found = {}", CurrentModuleObject, standAloneERV.SupplyAirFanName));
613 0 : ErrorsFound = true;
614 : }
615 : } else {
616 3 : if (state.dataInputProcessing->inputProcessor->getObjectItemNum(state, "Fan:SystemModel", standAloneERV.SupplyAirFanName) <= 0) {
617 0 : ShowSevereError(state,
618 0 : format("{} supply fan type Fan:SystemModel not found = {}", CurrentModuleObject, standAloneERV.SupplyAirFanName));
619 0 : ErrorsFound = true;
620 : }
621 : }
622 :
623 : // Verify exhaust air fan name in Stand Alone ERV object matches name of valid fan object
624 107 : if (standAloneERV.exhaustAirFanType != HVAC::FanType::SystemModel) {
625 104 : if (state.dataInputProcessing->inputProcessor->getObjectItemNum(state, "Fan:OnOff", standAloneERV.ExhaustAirFanName) <= 0) {
626 0 : ShowSevereError(state, format("{} exhaust fan type Fan:OnOff not found = {}", CurrentModuleObject, standAloneERV.ExhaustAirFanName));
627 0 : ErrorsFound = true;
628 : }
629 : } else {
630 3 : if (state.dataInputProcessing->inputProcessor->getObjectItemNum(state, "Fan:SystemModel", standAloneERV.ExhaustAirFanName) <= 0) {
631 0 : ShowSevereError(state,
632 0 : format("{} exhaust fan type Fan:SystemModel not found = {}", CurrentModuleObject, standAloneERV.ExhaustAirFanName));
633 0 : ErrorsFound = true;
634 : }
635 : }
636 107 : }
637 :
638 5 : int OutAirNum = 0;
639 5 : CurrentModuleObject = "ZoneHVAC:EnergyRecoveryVentilator:Controller";
640 5 : NumERVCtrlrs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
641 :
642 109 : for (ERVControllerNum = 1; ERVControllerNum <= NumERVCtrlrs; ++ERVControllerNum) {
643 104 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
644 : CurrentModuleObject,
645 : ERVControllerNum,
646 : Alphas,
647 : NumAlphas,
648 : Numbers,
649 : NumNumbers,
650 : IOStatus,
651 : lNumericBlanks,
652 : lAlphaBlanks,
653 : cAlphaFields,
654 : cNumericFields);
655 104 : MixedAir::CheckOAControllerName(state, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
656 104 : ++OutAirNum;
657 104 : auto &thisOAController = state.dataMixedAir->OAController(OutAirNum);
658 :
659 104 : thisOAController.Name = Alphas(1);
660 104 : thisOAController.ControllerType = MixedAir::MixedAirControllerType::ControllerStandAloneERV;
661 104 : int WhichERV = Util::FindItemInList(Alphas(1), state.dataHVACStandAloneERV->StandAloneERV, &StandAloneERVData::ControllerName);
662 104 : if (WhichERV != 0) {
663 104 : AirFlowRate = state.dataHVACStandAloneERV->StandAloneERV(WhichERV).SupplyAirVolFlow;
664 104 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).ControllerIndex = OutAirNum;
665 : } else {
666 0 : ShowSevereError(
667 0 : state, format("GetERVController: Could not find ZoneHVAC:EnergyRecoveryVentilator with {} = \"{}\"", cAlphaFields(1), Alphas(1)));
668 0 : ErrorsFound = true;
669 0 : AirFlowRate = -1000.0;
670 : }
671 104 : thisOAController.MaxOA = AirFlowRate;
672 104 : thisOAController.MinOA = AirFlowRate;
673 : // OAController(OutAirNum)%TempLim = Numbers(1)
674 104 : if (lNumericBlanks(1)) {
675 102 : thisOAController.TempLim = HVAC::BlankNumeric;
676 : } else {
677 2 : thisOAController.TempLim = Numbers(1);
678 : }
679 : // OAController(OutAirNum)%TempLowLim = Numbers(2)
680 104 : if (lNumericBlanks(2)) {
681 102 : thisOAController.TempLowLim = HVAC::BlankNumeric;
682 : } else {
683 2 : thisOAController.TempLowLim = Numbers(2);
684 : }
685 : // OAController(OutAirNum)%EnthLim = Numbers(3)
686 104 : if (lNumericBlanks(3)) {
687 104 : thisOAController.EnthLim = HVAC::BlankNumeric;
688 : } else {
689 0 : thisOAController.EnthLim = Numbers(3);
690 : }
691 : // OAController(OutAirNum)%DPTempLim = Numbers(4)
692 104 : if (lNumericBlanks(4)) {
693 102 : thisOAController.DPTempLim = HVAC::BlankNumeric;
694 : } else {
695 2 : thisOAController.DPTempLim = Numbers(4);
696 : }
697 :
698 104 : if (WhichERV != 0) {
699 104 : NodeNumber = state.dataHVACStandAloneERV->StandAloneERV(WhichERV).SupplyAirInletNode;
700 : } else {
701 0 : NodeNumber = 0;
702 : }
703 104 : thisOAController.OANode = NodeNumber;
704 : // set the inlet node to also equal the OA node because this is a special controller for economizing stand alone ERV
705 : // with the assumption that equipment is bypassed....(moved from module MixedAir)
706 104 : thisOAController.InletNode = NodeNumber;
707 :
708 104 : if (WhichERV != 0) {
709 104 : NodeNumber = state.dataHVACStandAloneERV->StandAloneERV(WhichERV).ExhaustAirInletNode;
710 : } else {
711 0 : NodeNumber = 0;
712 : }
713 104 : thisOAController.RetNode = NodeNumber;
714 :
715 104 : if (!lAlphaBlanks(2)) {
716 1 : thisOAController.EnthalpyCurvePtr = Curve::GetCurveIndex(state, Alphas(2));
717 1 : if (Curve::GetCurveIndex(state, Alphas(2)) == 0) {
718 0 : ShowSevereError(state, format("{} \"{}\"", CurrentModuleObject, Alphas(1)));
719 0 : ShowContinueError(state, format("...{} not found:{}", cAlphaFields(2), Alphas(2)));
720 0 : ErrorsFound = true;
721 : } else {
722 : // Verify Curve Object, only legal types are Quadratic and Cubic
723 1 : ErrorsFound |= Curve::CheckCurveDims(state,
724 : thisOAController.EnthalpyCurvePtr, // Curve index
725 : {1}, // Valid dimensions
726 : "GetStandAloneERV: ", // Routine name
727 : CurrentModuleObject, // Object Type
728 : thisOAController.Name, // Object Name
729 1 : cAlphaFields(2)); // Field Name
730 : }
731 : }
732 :
733 : // Changed by AMIT for new implementation of the controller:outside air
734 104 : if (Alphas(3) == "EXHAUSTAIRTEMPERATURELIMIT" && Alphas(4) == "EXHAUSTAIRENTHALPYLIMIT") {
735 0 : thisOAController.Econo = MixedAir::EconoOp::DifferentialDryBulbAndEnthalpy;
736 104 : } else if (Alphas(3) == "EXHAUSTAIRTEMPERATURELIMIT" && Alphas(4) == "NOEXHAUSTAIRENTHALPYLIMIT") {
737 0 : thisOAController.Econo = MixedAir::EconoOp::DifferentialDryBulb;
738 104 : } else if (Alphas(3) == "NOEXHAUSTAIRTEMPERATURELIMIT" && Alphas(4) == "EXHAUSTAIRENTHALPYLIMIT") {
739 0 : thisOAController.Econo = MixedAir::EconoOp::DifferentialEnthalpy;
740 104 : } else if (Alphas(3) == "NOEXHAUSTAIRTEMPERATURELIMIT" && Alphas(4) == "NOEXHAUSTAIRENTHALPYLIMIT") {
741 104 : if ((!lNumericBlanks(1)) || (!lNumericBlanks(3)) || (!lNumericBlanks(4)) || (!lAlphaBlanks(2))) {
742 : // This means that any of the FIXED DRY BULB, FIXED ENTHALPY, FIXED DEW POINT AND DRY BULB OR
743 : // ELECTRONIC ENTHALPY ECONOMIZER STRATEGY is present
744 2 : thisOAController.Econo = MixedAir::EconoOp::FixedDryBulb;
745 : }
746 0 : } else if ((!lAlphaBlanks(3)) && (!lAlphaBlanks(4))) {
747 0 : if ((lNumericBlanks(1)) && (lNumericBlanks(3)) && (lNumericBlanks(4)) && lAlphaBlanks(2)) {
748 0 : ShowWarningError(state, format("{} \"{}\"", CurrentModuleObject, Alphas(1)));
749 0 : ShowContinueError(state, format("... Invalid {}{} = {}{}", cAlphaFields(3), cAlphaFields(4), Alphas(3), Alphas(4)));
750 0 : ShowContinueError(state, "... Assumed NO EXHAUST AIR TEMP LIMIT and NO EXHAUST AIR ENTHALPY LIMIT.");
751 0 : thisOAController.Econo = MixedAir::EconoOp::NoEconomizer;
752 : } else {
753 : // This means that any of the FIXED DRY BULB, FIXED ENTHALPY, FIXED DEW POINT AND DRY BULB OR
754 : // ELECTRONIC ENTHALPY ECONOMIZER STRATEGY is present
755 0 : thisOAController.Econo = MixedAir::EconoOp::FixedDryBulb;
756 : }
757 0 : } else if ((lAlphaBlanks(3)) && (!lAlphaBlanks(4))) {
758 0 : if ((lNumericBlanks(1)) && (lNumericBlanks(3)) && (lNumericBlanks(4)) && lAlphaBlanks(2)) {
759 0 : ShowWarningError(state, format("{} \"{}\"", CurrentModuleObject, Alphas(1)));
760 0 : ShowContinueError(state, format("... Invalid {} = {}", cAlphaFields(4), Alphas(4)));
761 0 : ShowContinueError(state, "... Assumed NO EXHAUST AIR ENTHALPY LIMIT.");
762 0 : thisOAController.Econo = MixedAir::EconoOp::NoEconomizer;
763 : } else {
764 : // This means that any of the FIXED DRY BULB, FIXED ENTHALPY, FIXED DEW POINT AND DRY BULB OR
765 : // ELECTRONIC ENTHALPY ECONOMIZER STRATEGY is present
766 0 : thisOAController.Econo = MixedAir::EconoOp::FixedDryBulb;
767 : }
768 0 : } else if ((!lAlphaBlanks(3)) && (lAlphaBlanks(4))) {
769 0 : if ((lNumericBlanks(1)) && (lNumericBlanks(3)) && (lNumericBlanks(4)) && lAlphaBlanks(2)) {
770 0 : ShowWarningError(state, format("{} \"{}\"", CurrentModuleObject, Alphas(1)));
771 0 : ShowContinueError(state, format("... Invalid {} = {}", cAlphaFields(3), Alphas(3)));
772 0 : ShowContinueError(state, "... Assumed NO EXHAUST AIR TEMP LIMIT ");
773 0 : thisOAController.Econo = MixedAir::EconoOp::NoEconomizer;
774 : } else {
775 : // This means that any of the FIXED DRY BULB, FIXED ENTHALPY, FIXED DEW POINT AND DRY BULB OR
776 : // ELECTRONIC ENTHALPY ECONOMIZER STRATEGY is present
777 0 : thisOAController.Econo = MixedAir::EconoOp::FixedDryBulb;
778 : }
779 : } else { // NO Economizer
780 0 : thisOAController.Econo = MixedAir::EconoOp::NoEconomizer;
781 : }
782 :
783 104 : thisOAController.FixedMin = false;
784 104 : thisOAController.EconBypass = true;
785 :
786 : // Initialize to one in case high humidity control is NOT used
787 104 : Real64 HighRHOARatio = 1.0;
788 : // READ Modify Air Flow Data
789 : // High humidity control option is YES, read in additional data
790 104 : if (Util::SameString(Alphas(6), "Yes")) {
791 :
792 1 : HStatZoneNum = Util::FindItemInList(Alphas(7), state.dataHeatBal->Zone);
793 1 : thisOAController.HumidistatZoneNum = HStatZoneNum;
794 :
795 : // Get the node number for the zone with the humidistat
796 1 : if (HStatZoneNum > 0) {
797 1 : bool ZoneNodeFound = false;
798 1 : if (state.dataZoneEquip->ZoneEquipConfig(HStatZoneNum).IsControlled) {
799 : // Find the controlled zone number for the specified humidistat location
800 1 : thisOAController.NodeNumofHumidistatZone = state.dataZoneEquip->ZoneEquipConfig(HStatZoneNum).ZoneNode;
801 1 : ZoneNodeFound = true;
802 : }
803 1 : if (!ZoneNodeFound) {
804 0 : ShowSevereError(state, format("{} \"{}\"", CurrentModuleObject, Alphas(1)));
805 0 : ShowContinueError(state, "... Did not find Air Node (Zone with Humidistat)");
806 0 : ShowContinueError(state, format("... Specified {} = {}", cAlphaFields(7), Alphas(7)));
807 0 : ShowContinueError(state, "... A ZoneHVAC:EquipmentConnections object must be specified for this zone.");
808 0 : ErrorsFound = true;
809 : } else {
810 1 : bool HStatFound = false;
811 1 : for (NumHstatZone = 1; NumHstatZone <= state.dataZoneCtrls->NumHumidityControlZones; ++NumHstatZone) {
812 1 : if (state.dataZoneCtrls->HumidityControlZone(NumHstatZone).ActualZoneNum != HStatZoneNum) continue;
813 1 : HStatFound = true;
814 1 : break;
815 : }
816 1 : if (!HStatFound) {
817 0 : ShowSevereError(state, format("{} \"{}\"", CurrentModuleObject, Alphas(1)));
818 0 : ShowContinueError(state, "... Did not find zone humidistat");
819 0 : ShowContinueError(state, "... A ZoneControl:Humidistat object must be specified for this zone.");
820 0 : ErrorsFound = true;
821 : }
822 : }
823 : } else {
824 0 : ShowSevereError(state, format("{} \"{}\"", CurrentModuleObject, Alphas(1)));
825 0 : ShowContinueError(state, "... Did not find Air Node (Zone with Humidistat)");
826 0 : ShowContinueError(state, "... A ZoneHVAC:EquipmentConnections object must be specified for this zone.");
827 0 : ErrorsFound = true;
828 : }
829 :
830 1 : if (Numbers(5) <= 0.0 && NumNumbers > 4) {
831 :
832 0 : ShowWarningError(state, format("{} \"{}\"", CurrentModuleObject, Alphas(1)));
833 0 : ShowContinueError(state, format("... {} must be greater than 0.", cNumericFields(5)));
834 0 : ShowContinueError(state, format("... {} is reset to 1 and the simulation continues.", cNumericFields(5)));
835 :
836 0 : HighRHOARatio = 1.0;
837 :
838 1 : } else if (NumNumbers > 4) {
839 :
840 1 : HighRHOARatio = Numbers(5);
841 :
842 : } else {
843 :
844 0 : HighRHOARatio = 1.0;
845 : }
846 :
847 1 : if (Util::SameString(Alphas(8), "Yes")) {
848 1 : thisOAController.ModifyDuringHighOAMoisture = false;
849 : } else {
850 0 : thisOAController.ModifyDuringHighOAMoisture = true;
851 : }
852 :
853 103 : } else if (!Util::SameString(Alphas(6), "No") && NumAlphas > 4 && (!lAlphaBlanks(5))) {
854 0 : ShowWarningError(state, format("{} \"{}\"", CurrentModuleObject, Alphas(1)));
855 0 : ShowContinueError(state, format("... Invalid {} = {}", cAlphaFields(6), Alphas(6)));
856 0 : ShowContinueError(state, format("... {} is assumed to be \"No\" and the simulation continues.", cAlphaFields(6)));
857 : } // IF(Util::SameString(Alphas(6),'Yes'))THEN
858 :
859 104 : thisOAController.HighRHOAFlowRatio = HighRHOARatio;
860 104 : if (WhichERV != 0) {
861 104 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).HighRHOAFlowRatio = HighRHOARatio;
862 : }
863 :
864 : // Check for a time of day outside air schedule
865 104 : thisOAController.EconomizerOASchedPtr = ScheduleManager::GetScheduleIndex(state, Alphas(5));
866 :
867 104 : if (WhichERV != 0) {
868 104 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).EconomizerOASchedPtr = ScheduleManager::GetScheduleIndex(state, Alphas(5));
869 :
870 : // Compare the ERV SA fan flow rates to modified air flow rate.
871 105 : if (HighRHOARatio > 1.0 && state.dataHVACStandAloneERV->StandAloneERV(WhichERV).SupplyAirVolFlow != DataSizing::AutoSize &&
872 1 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).DesignSAFanVolFlowRate != DataSizing::AutoSize) {
873 1 : if (state.dataHVACStandAloneERV->StandAloneERV(WhichERV).SupplyAirVolFlow * HighRHOARatio >
874 1 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).DesignSAFanVolFlowRate) {
875 0 : ShowWarningError(state, format("{} \"{}\"", CurrentModuleObject, Alphas(1)));
876 0 : ShowContinueError(state, format("... A {} was entered as {:.4R}", cNumericFields(5), HighRHOARatio));
877 0 : ShowContinueError(state,
878 : "... This flow ratio results in a Supply Air Volume Flow Rate through the ERV which is greater than the "
879 : "Max Volume specified in the supply air fan object.");
880 0 : ShowContinueError(state,
881 0 : format("... Associated fan object = {} \"{}\"",
882 0 : HVAC::fanTypeNames[(int)state.dataHVACStandAloneERV->StandAloneERV(WhichERV).supplyAirFanType],
883 0 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).SupplyAirFanName));
884 0 : ShowContinueError(state,
885 0 : format("... Modified value = {:.2R}",
886 0 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).SupplyAirVolFlow * HighRHOARatio));
887 0 : ShowContinueError(state,
888 0 : format(" ... Supply Fan Max Volume Flow Rate = {:.2R}",
889 0 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).DesignSAFanVolFlowRate));
890 0 : ShowContinueError(state, "... The ERV supply air fan will limit the air flow through the ERV and the simulation continues.");
891 : }
892 : }
893 :
894 : // Compare the ERV EA fan flow rates to modified air flow rate.
895 105 : if (HighRHOARatio > 1.0 && state.dataHVACStandAloneERV->StandAloneERV(WhichERV).ExhaustAirVolFlow != DataSizing::AutoSize &&
896 1 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).DesignEAFanVolFlowRate != DataSizing::AutoSize) {
897 1 : if (state.dataHVACStandAloneERV->StandAloneERV(WhichERV).ExhaustAirVolFlow * HighRHOARatio >
898 1 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).DesignEAFanVolFlowRate) {
899 0 : ShowWarningError(state, format("ZoneHVAC:EnergyRecoveryVentilator:Controller \"{}\"", Alphas(1)));
900 0 : ShowContinueError(state, format("... A {} was entered as {:.4R}", cNumericFields(5), HighRHOARatio));
901 0 : ShowContinueError(state,
902 : "... This flow ratio results in an Exhaust Air Volume Flow Rate through the ERV which is greater than the "
903 : "Max Volume specified in the exhaust air fan object.");
904 0 : ShowContinueError(state,
905 0 : format("... Associated fan object = {} \"{}\"",
906 0 : HVAC::fanTypeNames[(int)state.dataHVACStandAloneERV->StandAloneERV(WhichERV).exhaustAirFanType],
907 0 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).ExhaustAirFanName));
908 0 : ShowContinueError(state,
909 0 : format("... Modified value = {:.2R}",
910 0 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).ExhaustAirVolFlow * HighRHOARatio));
911 0 : ShowContinueError(state,
912 0 : format(" ... Exhaust Fan Max Volume Flow Rate = {:.2R}",
913 0 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).DesignEAFanVolFlowRate));
914 0 : ShowContinueError(state, "... The ERV exhaust air fan will limit the air flow through the ERV and the simulation continues.");
915 : }
916 : }
917 : } // IF(WhichERV /= 0)THEN
918 : }
919 :
920 5 : if (ErrorsFound) {
921 0 : ShowFatalError(state, "Errors found in getting ZoneHVAC:EnergyRecoveryVentilator input.");
922 : }
923 :
924 : // Setup report variables for the stand alone ERVs
925 112 : for (int StandAloneERVIndex = 1; StandAloneERVIndex <= state.dataHVACStandAloneERV->NumStandAloneERVs; ++StandAloneERVIndex) {
926 107 : auto &standAloneERV = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVIndex);
927 214 : SetupOutputVariable(state,
928 : "Zone Ventilator Sensible Cooling Rate",
929 : Constant::Units::W,
930 107 : standAloneERV.SensCoolingRate,
931 : OutputProcessor::TimeStepType::System,
932 : OutputProcessor::StoreType::Average,
933 107 : standAloneERV.Name);
934 214 : SetupOutputVariable(state,
935 : "Zone Ventilator Sensible Cooling Energy",
936 : Constant::Units::J,
937 107 : standAloneERV.SensCoolingEnergy,
938 : OutputProcessor::TimeStepType::System,
939 : OutputProcessor::StoreType::Sum,
940 107 : standAloneERV.Name);
941 214 : SetupOutputVariable(state,
942 : "Zone Ventilator Latent Cooling Rate",
943 : Constant::Units::W,
944 107 : standAloneERV.LatCoolingRate,
945 : OutputProcessor::TimeStepType::System,
946 : OutputProcessor::StoreType::Average,
947 107 : standAloneERV.Name);
948 214 : SetupOutputVariable(state,
949 : "Zone Ventilator Latent Cooling Energy",
950 : Constant::Units::J,
951 107 : standAloneERV.LatCoolingEnergy,
952 : OutputProcessor::TimeStepType::System,
953 : OutputProcessor::StoreType::Sum,
954 107 : standAloneERV.Name);
955 214 : SetupOutputVariable(state,
956 : "Zone Ventilator Total Cooling Rate",
957 : Constant::Units::W,
958 107 : standAloneERV.TotCoolingRate,
959 : OutputProcessor::TimeStepType::System,
960 : OutputProcessor::StoreType::Average,
961 107 : standAloneERV.Name);
962 214 : SetupOutputVariable(state,
963 : "Zone Ventilator Total Cooling Energy",
964 : Constant::Units::J,
965 107 : standAloneERV.TotCoolingEnergy,
966 : OutputProcessor::TimeStepType::System,
967 : OutputProcessor::StoreType::Sum,
968 107 : standAloneERV.Name);
969 :
970 214 : SetupOutputVariable(state,
971 : "Zone Ventilator Sensible Heating Rate",
972 : Constant::Units::W,
973 107 : standAloneERV.SensHeatingRate,
974 : OutputProcessor::TimeStepType::System,
975 : OutputProcessor::StoreType::Average,
976 107 : standAloneERV.Name);
977 214 : SetupOutputVariable(state,
978 : "Zone Ventilator Sensible Heating Energy",
979 : Constant::Units::J,
980 107 : standAloneERV.SensHeatingEnergy,
981 : OutputProcessor::TimeStepType::System,
982 : OutputProcessor::StoreType::Sum,
983 107 : standAloneERV.Name);
984 214 : SetupOutputVariable(state,
985 : "Zone Ventilator Latent Heating Rate",
986 : Constant::Units::W,
987 107 : standAloneERV.LatHeatingRate,
988 : OutputProcessor::TimeStepType::System,
989 : OutputProcessor::StoreType::Average,
990 107 : standAloneERV.Name);
991 214 : SetupOutputVariable(state,
992 : "Zone Ventilator Latent Heating Energy",
993 : Constant::Units::J,
994 107 : standAloneERV.LatHeatingEnergy,
995 : OutputProcessor::TimeStepType::System,
996 : OutputProcessor::StoreType::Sum,
997 107 : standAloneERV.Name);
998 214 : SetupOutputVariable(state,
999 : "Zone Ventilator Total Heating Rate",
1000 : Constant::Units::W,
1001 107 : standAloneERV.TotHeatingRate,
1002 : OutputProcessor::TimeStepType::System,
1003 : OutputProcessor::StoreType::Average,
1004 107 : standAloneERV.Name);
1005 214 : SetupOutputVariable(state,
1006 : "Zone Ventilator Total Heating Energy",
1007 : Constant::Units::J,
1008 107 : standAloneERV.TotHeatingEnergy,
1009 : OutputProcessor::TimeStepType::System,
1010 : OutputProcessor::StoreType::Sum,
1011 107 : standAloneERV.Name);
1012 :
1013 214 : SetupOutputVariable(state,
1014 : "Zone Ventilator Electricity Rate",
1015 : Constant::Units::W,
1016 107 : standAloneERV.ElecUseRate,
1017 : OutputProcessor::TimeStepType::System,
1018 : OutputProcessor::StoreType::Average,
1019 107 : standAloneERV.Name);
1020 214 : SetupOutputVariable(state,
1021 : "Zone Ventilator Electricity Energy",
1022 : Constant::Units::J,
1023 107 : standAloneERV.ElecUseEnergy,
1024 : OutputProcessor::TimeStepType::System,
1025 : OutputProcessor::StoreType::Sum,
1026 107 : standAloneERV.Name);
1027 107 : SetupOutputVariable(state,
1028 : "Zone Ventilator Supply Fan Availability Status",
1029 : Constant::Units::None,
1030 107 : (int &)standAloneERV.availStatus,
1031 : OutputProcessor::TimeStepType::System,
1032 : OutputProcessor::StoreType::Average,
1033 107 : standAloneERV.Name);
1034 : }
1035 :
1036 5 : Alphas.deallocate();
1037 5 : Numbers.deallocate();
1038 5 : cAlphaFields.deallocate();
1039 5 : cNumericFields.deallocate();
1040 5 : lNumericBlanks.deallocate();
1041 5 : lAlphaBlanks.deallocate();
1042 5 : }
1043 :
1044 653189 : void InitStandAloneERV(EnergyPlusData &state,
1045 : int const StandAloneERVNum, // number of the current Stand Alone ERV unit being simulated
1046 : int const ZoneNum, // number of zone being served unused1208
1047 : bool const FirstHVACIteration // TRUE if first HVAC iteration
1048 : )
1049 : {
1050 :
1051 : // SUBROUTINE INFORMATION:
1052 : // AUTHOR Richard Raustad, FSEC
1053 : // DATE WRITTEN June 2003
1054 : // MODIFIED July 2012, Chandan Sharma - FSEC: Added zone sys avail managers
1055 :
1056 : // PURPOSE OF THIS SUBROUTINE:
1057 : // This subroutine is for initializations of the Stand Alone ERV unit information.
1058 :
1059 : // METHODOLOGY EMPLOYED:
1060 : // Uses the status flags to trigger initializations.
1061 :
1062 : // Do the one time initializations
1063 653189 : if (state.dataHVACStandAloneERV->MyOneTimeFlag) {
1064 :
1065 5 : state.dataHVACStandAloneERV->MyEnvrnFlag.allocate(state.dataHVACStandAloneERV->NumStandAloneERVs);
1066 5 : state.dataHVACStandAloneERV->MySizeFlag_InitStandAloneERV.allocate(state.dataHVACStandAloneERV->NumStandAloneERVs);
1067 5 : state.dataHVACStandAloneERV->MyZoneEqFlag.allocate(state.dataHVACStandAloneERV->NumStandAloneERVs);
1068 5 : state.dataHVACStandAloneERV->MyEnvrnFlag = true;
1069 5 : state.dataHVACStandAloneERV->MySizeFlag_InitStandAloneERV = true;
1070 5 : state.dataHVACStandAloneERV->MyZoneEqFlag = true;
1071 5 : state.dataHVACStandAloneERV->MyOneTimeFlag = false;
1072 : }
1073 :
1074 653189 : if (allocated(state.dataAvail->ZoneComp)) {
1075 653166 : auto &availMgr = state.dataAvail->ZoneComp(DataZoneEquipment::ZoneEquipType::EnergyRecoveryVentilator).ZoneCompAvailMgrs(StandAloneERVNum);
1076 653166 : if (state.dataHVACStandAloneERV->MyZoneEqFlag(StandAloneERVNum)) { // initialize the name of each availability manager list and zone number
1077 107 : availMgr.AvailManagerListName = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).AvailManagerListName;
1078 107 : availMgr.ZoneNum = ZoneNum;
1079 107 : state.dataHVACStandAloneERV->MyZoneEqFlag(StandAloneERVNum) = false;
1080 : }
1081 653166 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).availStatus = availMgr.availStatus;
1082 : }
1083 :
1084 : // need to check all units to see if they are on Zone Equipment List or issue warning
1085 653189 : if (!state.dataHVACStandAloneERV->ZoneEquipmentListChecked && state.dataZoneEquip->ZoneEquipInputsFilled) {
1086 5 : state.dataHVACStandAloneERV->ZoneEquipmentListChecked = true;
1087 112 : for (int Loop = 1; Loop <= state.dataHVACStandAloneERV->NumStandAloneERVs; ++Loop) {
1088 214 : if (DataZoneEquipment::CheckZoneEquipmentList(
1089 107 : state, state.dataHVACStandAloneERV->StandAloneERV(Loop).UnitType, state.dataHVACStandAloneERV->StandAloneERV(Loop).Name))
1090 107 : continue;
1091 0 : ShowSevereError(state,
1092 0 : format("InitStandAloneERV: Unit=[{},{}] is not on any ZoneHVAC:EquipmentList. It will not be simulated.",
1093 0 : state.dataHVACStandAloneERV->StandAloneERV(Loop).UnitType,
1094 0 : state.dataHVACStandAloneERV->StandAloneERV(Loop).Name));
1095 : }
1096 : }
1097 :
1098 653189 : if (!state.dataGlobal->SysSizingCalc && state.dataHVACStandAloneERV->MySizeFlag_InitStandAloneERV(StandAloneERVNum)) {
1099 107 : SizeStandAloneERV(state, StandAloneERVNum);
1100 107 : state.dataHVACStandAloneERV->MySizeFlag_InitStandAloneERV(StandAloneERVNum) = false;
1101 : }
1102 :
1103 : // Do the Begin Environment initializations
1104 653189 : if (state.dataGlobal->BeginEnvrnFlag && state.dataHVACStandAloneERV->MyEnvrnFlag(StandAloneERVNum)) {
1105 742 : int SupInNode = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirInletNode;
1106 742 : int ExhInNode = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirInletNode;
1107 : // set the mass flow rates from the input volume flow rates
1108 742 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).MaxSupAirMassFlow =
1109 742 : state.dataEnvrn->StdRhoAir * state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirVolFlow;
1110 742 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).MaxExhAirMassFlow =
1111 742 : state.dataEnvrn->StdRhoAir * state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirVolFlow;
1112 742 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignSAFanMassFlowRate =
1113 742 : state.dataEnvrn->StdRhoAir * state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignSAFanVolFlowRate;
1114 742 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignEAFanMassFlowRate =
1115 742 : state.dataEnvrn->StdRhoAir * state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignEAFanVolFlowRate;
1116 : // set the node max and min mass flow rates
1117 742 : auto &supInNode = state.dataLoopNodes->Node(SupInNode);
1118 742 : auto &exhInNode = state.dataLoopNodes->Node(ExhInNode);
1119 :
1120 742 : supInNode.MassFlowRateMax = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).MaxSupAirMassFlow;
1121 742 : supInNode.MassFlowRateMin = 0.0;
1122 742 : exhInNode.MassFlowRateMax = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).MaxExhAirMassFlow;
1123 742 : exhInNode.MassFlowRateMin = 0.0;
1124 742 : state.dataHVACStandAloneERV->MyEnvrnFlag(StandAloneERVNum) = false;
1125 : // Initialize OA Controller on BeginEnvrnFlag
1126 742 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerNameDefined) {
1127 1452 : MixedAir::SimOAController(state,
1128 726 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerName,
1129 726 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerIndex,
1130 : FirstHVACIteration,
1131 : 0);
1132 : }
1133 : } // end one time inits
1134 :
1135 653189 : if (!state.dataGlobal->BeginEnvrnFlag) {
1136 649419 : state.dataHVACStandAloneERV->MyEnvrnFlag(StandAloneERVNum) = true;
1137 : }
1138 :
1139 : // These initializations are done every iteration
1140 653189 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ElecUseRate = 0.0;
1141 653189 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SensCoolingRate = 0.0;
1142 653189 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).LatCoolingRate = 0.0;
1143 653189 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).TotCoolingRate = 0.0;
1144 653189 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SensHeatingRate = 0.0;
1145 653189 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).LatHeatingRate = 0.0;
1146 653189 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).TotHeatingRate = 0.0;
1147 653189 : int SupInNode = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirInletNode;
1148 653189 : int ExhInNode = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirInletNode;
1149 653189 : auto &supInNode = state.dataLoopNodes->Node(SupInNode);
1150 653189 : auto &exhInNode = state.dataLoopNodes->Node(ExhInNode);
1151 :
1152 : // Set the inlet node mass flow rate
1153 653189 : if (ScheduleManager::GetCurrentScheduleValue(state, state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SchedPtr) > 0.0) {
1154 :
1155 : // IF optional ControllerName is defined SimOAController ONLY to set economizer and Modifyairflow flags
1156 647090 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerNameDefined) {
1157 : // Initialize a flow rate for controller
1158 563255 : supInNode.MassFlowRate = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).MaxSupAirMassFlow;
1159 1126510 : MixedAir::SimOAController(state,
1160 563255 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerName,
1161 563255 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerIndex,
1162 : FirstHVACIteration,
1163 : 0);
1164 : }
1165 :
1166 647090 : if (ScheduleManager::GetCurrentScheduleValue(state, state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirFanSchPtr) > 0 ||
1167 0 : (state.dataHVACGlobal->TurnFansOn && !state.dataHVACGlobal->TurnFansOff)) {
1168 647090 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerNameDefined) {
1169 563255 : if (state.dataMixedAir->OAController(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerIndex)
1170 563255 : .HighHumCtrlActive) {
1171 202 : supInNode.MassFlowRate = min(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignSAFanMassFlowRate,
1172 202 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).MaxSupAirMassFlow *
1173 202 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).HighRHOAFlowRatio);
1174 : } else {
1175 563053 : supInNode.MassFlowRate = min(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignSAFanMassFlowRate,
1176 563053 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).MaxSupAirMassFlow);
1177 : }
1178 : } else {
1179 83835 : supInNode.MassFlowRate = min(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignSAFanMassFlowRate,
1180 83835 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).MaxSupAirMassFlow);
1181 : }
1182 : } else {
1183 0 : supInNode.MassFlowRate = 0.0;
1184 : }
1185 647090 : supInNode.MassFlowRateMaxAvail = supInNode.MassFlowRate;
1186 647090 : supInNode.MassFlowRateMinAvail = supInNode.MassFlowRate;
1187 :
1188 647090 : if (ScheduleManager::GetCurrentScheduleValue(state, state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirFanSchPtr) > 0) {
1189 647090 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerNameDefined) {
1190 563255 : if (state.dataMixedAir->OAController(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerIndex)
1191 563255 : .HighHumCtrlActive) {
1192 202 : exhInNode.MassFlowRate = min(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignEAFanMassFlowRate,
1193 202 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).MaxExhAirMassFlow *
1194 202 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).HighRHOAFlowRatio);
1195 : } else {
1196 563053 : exhInNode.MassFlowRate = min(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignEAFanMassFlowRate,
1197 563053 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).MaxExhAirMassFlow);
1198 : }
1199 : } else {
1200 83835 : exhInNode.MassFlowRate = min(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignEAFanMassFlowRate,
1201 83835 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).MaxExhAirMassFlow);
1202 : }
1203 : } else {
1204 0 : exhInNode.MassFlowRate = 0.0;
1205 : }
1206 647090 : exhInNode.MassFlowRateMaxAvail = exhInNode.MassFlowRate;
1207 647090 : exhInNode.MassFlowRateMinAvail = exhInNode.MassFlowRate;
1208 : } else {
1209 6099 : supInNode.MassFlowRate = 0.0;
1210 6099 : supInNode.MassFlowRateMaxAvail = 0.0;
1211 6099 : supInNode.MassFlowRateMinAvail = 0.0;
1212 6099 : exhInNode.MassFlowRate = 0.0;
1213 6099 : exhInNode.MassFlowRateMaxAvail = 0.0;
1214 6099 : exhInNode.MassFlowRateMinAvail = 0.0;
1215 : }
1216 653189 : }
1217 :
1218 107 : void SizeStandAloneERV(EnergyPlusData &state, int const StandAloneERVNum)
1219 : {
1220 :
1221 : // SUBROUTINE INFORMATION:
1222 : // AUTHOR Richard Raustad
1223 : // DATE WRITTEN October 2007
1224 : // MODIFIED August 2013 Daeho Kang, add component sizing table entries
1225 :
1226 : // PURPOSE OF THIS SUBROUTINE:
1227 : // This subroutine is for sizing Stand Alone ERV Components for which flow rates have not been
1228 : // specified in the input.
1229 :
1230 : // METHODOLOGY EMPLOYED:
1231 : // Obtains flow rates from the zone or system sizing arrays.
1232 :
1233 : static constexpr std::string_view RoutineName("SizeStandAloneERV: ");
1234 :
1235 107 : bool IsAutoSize = false;
1236 107 : Real64 SupplyAirVolFlowDes = 0.0;
1237 107 : Real64 DesignSAFanVolFlowRateDes = 0.0;
1238 107 : Real64 DesignSAFanVolFlowRateUser = 0.0;
1239 107 : Real64 ExhaustAirVolFlowDes = 0.0;
1240 107 : std::string CompType = "ZoneHVAC:EnergyRecoveryVentilator";
1241 107 : std::string CompName = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).Name;
1242 107 : bool PrintFlag = true;
1243 107 : bool ErrorsFound = false;
1244 :
1245 107 : auto &zoneEqSizing = state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum);
1246 :
1247 107 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirVolFlow == DataSizing::AutoSize) {
1248 0 : IsAutoSize = true;
1249 : }
1250 :
1251 107 : if (state.dataSize->CurZoneEqNum > 0) {
1252 :
1253 : // Sizing objects are not required for stand alone ERV
1254 : // CALL CheckZoneSizing('ZoneHVAC:EnergyRecoveryVentilator',StandAloneERV(StandAloneERVNum)%Name)
1255 107 : int ZoneNum = state.dataSize->CurZoneEqNum;
1256 107 : Real64 ZoneMult = state.dataHeatBal->Zone(ZoneNum).Multiplier * state.dataHeatBal->Zone(ZoneNum).ListMultiplier;
1257 107 : Real64 FloorArea = state.dataHeatBal->Zone(ZoneNum).FloorArea;
1258 107 : Real64 NumberOfPeople = 0.0;
1259 107 : Real64 MaxPeopleSch = 0.0;
1260 6990 : for (int PeopleNum = 1; PeopleNum <= state.dataHeatBal->TotPeople; ++PeopleNum) {
1261 6883 : if (ZoneNum != state.dataHeatBal->People(PeopleNum).ZonePtr) continue;
1262 107 : int PeopleSchPtr = state.dataHeatBal->People(PeopleNum).NumberOfPeoplePtr;
1263 107 : MaxPeopleSch = ScheduleManager::GetScheduleMaxValue(state, PeopleSchPtr);
1264 107 : NumberOfPeople = NumberOfPeople + (state.dataHeatBal->People(PeopleNum).NumberOfPeople * MaxPeopleSch);
1265 : }
1266 107 : SupplyAirVolFlowDes = FloorArea * state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).AirVolFlowPerFloorArea +
1267 107 : NumberOfPeople * state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).AirVolFlowPerOccupant;
1268 107 : SupplyAirVolFlowDes = ZoneMult * SupplyAirVolFlowDes;
1269 :
1270 107 : if (SupplyAirVolFlowDes < HVAC::SmallAirVolFlow) {
1271 107 : SupplyAirVolFlowDes = 0.0;
1272 : }
1273 :
1274 : // Size ERV supply flow rate
1275 107 : Real64 TempSize = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirVolFlow;
1276 107 : if (IsAutoSize) {
1277 0 : state.dataSize->DataConstantUsedForSizing = SupplyAirVolFlowDes;
1278 0 : state.dataSize->DataFractionUsedForSizing = 1.0;
1279 0 : TempSize = SupplyAirVolFlowDes;
1280 0 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerNameDefined) {
1281 0 : state.dataMixedAir->OAController(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerIndex).MaxOA =
1282 0 : SupplyAirVolFlowDes * state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).HighRHOAFlowRatio;
1283 0 : state.dataMixedAir->OAController(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerIndex).MinOA =
1284 : SupplyAirVolFlowDes;
1285 : }
1286 : } else {
1287 107 : state.dataSize->DataConstantUsedForSizing = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirVolFlow;
1288 107 : state.dataSize->DataFractionUsedForSizing = 1.0;
1289 : }
1290 107 : if (TempSize > 0.0) {
1291 107 : std::string SizingString = "Supply Air Flow Rate [m3/s]";
1292 107 : SystemAirFlowSizer sizerSystemAirFlow;
1293 107 : sizerSystemAirFlow.overrideSizingString(SizingString);
1294 107 : sizerSystemAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1295 107 : TempSize = sizerSystemAirFlow.size(state, TempSize, ErrorsFound);
1296 107 : }
1297 107 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirVolFlow = TempSize;
1298 : }
1299 :
1300 : // Size ERV exhaust flow rate
1301 107 : state.dataSize->DataFractionUsedForSizing = 1.0;
1302 107 : IsAutoSize = false;
1303 107 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirVolFlow == DataSizing::AutoSize) {
1304 0 : IsAutoSize = true;
1305 : }
1306 :
1307 107 : if (state.dataSize->CurZoneEqNum > 0) {
1308 :
1309 107 : ExhaustAirVolFlowDes = SupplyAirVolFlowDes;
1310 :
1311 107 : if (ExhaustAirVolFlowDes < HVAC::SmallAirVolFlow) {
1312 107 : ExhaustAirVolFlowDes = 0.0;
1313 : }
1314 :
1315 107 : if (ExhaustAirVolFlowDes > state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirVolFlow) {
1316 0 : ExhaustAirVolFlowDes = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirVolFlow;
1317 : }
1318 :
1319 107 : Real64 TempSize = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirVolFlow;
1320 107 : if (IsAutoSize) {
1321 0 : TempSize = ExhaustAirVolFlowDes;
1322 0 : state.dataSize->DataConstantUsedForSizing = ExhaustAirVolFlowDes;
1323 : } else {
1324 107 : state.dataSize->DataConstantUsedForSizing = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirVolFlow;
1325 : }
1326 107 : state.dataSize->DataFractionUsedForSizing = 1.0;
1327 107 : if (TempSize > 0.0) {
1328 107 : std::string SizingString = "Exhaust Air Flow Rate [m3/s]";
1329 107 : SystemAirFlowSizer sizerSystemAirFlow;
1330 107 : sizerSystemAirFlow.overrideSizingString(SizingString);
1331 107 : sizerSystemAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1332 107 : TempSize = sizerSystemAirFlow.size(state, TempSize, ErrorsFound);
1333 107 : }
1334 107 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirVolFlow = TempSize;
1335 107 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignEAFanVolFlowRate =
1336 107 : TempSize * state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).HighRHOAFlowRatio;
1337 : }
1338 :
1339 : // Set Zone equipment sizing data for autosizing the fans and heat exchanger
1340 107 : zoneEqSizing.AirVolFlow = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirVolFlow *
1341 107 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).HighRHOAFlowRatio;
1342 107 : zoneEqSizing.OAVolFlow = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirVolFlow;
1343 107 : zoneEqSizing.SystemAirFlow = true;
1344 107 : zoneEqSizing.DesignSizeFromParent = true;
1345 :
1346 : // Check supply fan flow rate or set flow rate if autosized in fan object
1347 107 : IsAutoSize = false;
1348 107 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignSAFanVolFlowRate == DataSizing::AutoSize) {
1349 102 : IsAutoSize = true;
1350 : }
1351 107 : DesignSAFanVolFlowRateDes = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirVolFlow *
1352 107 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).HighRHOAFlowRatio;
1353 107 : if (IsAutoSize) {
1354 102 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignSAFanVolFlowRate = DesignSAFanVolFlowRateDes;
1355 : } else {
1356 5 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignSAFanVolFlowRate > 0.0 && DesignSAFanVolFlowRateDes > 0.0) {
1357 5 : DesignSAFanVolFlowRateUser = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignSAFanVolFlowRate;
1358 5 : if (state.dataGlobal->DisplayExtraWarnings) {
1359 0 : if ((std::abs(DesignSAFanVolFlowRateDes - DesignSAFanVolFlowRateUser) / DesignSAFanVolFlowRateUser) >
1360 0 : state.dataSize->AutoVsHardSizingThreshold) {
1361 0 : ShowMessage(state,
1362 0 : format("SizeStandAloneERV: Potential issue with equipment sizing for ZoneHVAC:EnergyRecoveryVentilator {} {}",
1363 0 : HVAC::fanTypeNames[(int)state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).supplyAirFanType],
1364 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirFanName));
1365 0 : ShowContinueError(state, format("User-Specified Supply Fan Maximum Flow Rate of {:.5R} [m3/s]", DesignSAFanVolFlowRateUser));
1366 0 : ShowContinueError(state, format("differs from the ERV Supply Air Flow Rate of {:.5R} [m3/s]", DesignSAFanVolFlowRateDes));
1367 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1368 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1369 : }
1370 : }
1371 : }
1372 : }
1373 :
1374 : // simulate the fan to size using the flow rate specified above
1375 : // (i.e., ZoneEqSizing( CurZoneEqNum ).AirVolFlow = StandAloneERV( StandAloneERVNum ).SupplyAirVolFlow * StandAloneERV( StandAloneERVNum
1376 : // ).HighRHOAFlowRatio;)
1377 107 : state.dataFans->fans(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirFanIndex)->simulate(state, true, _, _);
1378 :
1379 107 : state.dataFans->fans(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirFanIndex)->simulate(state, true, _, _);
1380 :
1381 : // now reset the ZoneEqSizing variable to NOT use the multiplier for HighRHOAFlowRatio for sizing HXs
1382 107 : zoneEqSizing.AirVolFlow = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirVolFlow;
1383 107 : }
1384 :
1385 653189 : void CalcStandAloneERV(EnergyPlusData &state,
1386 : int const StandAloneERVNum, // Unit index in ERV data structure
1387 : bool const FirstHVACIteration, // flag for 1st HVAC iteration in the time step
1388 : Real64 &SensLoadMet, // sensible zone load met by unit (W)
1389 : Real64 &LatentMassLoadMet // latent zone load met by unit (kg/s), dehumid = negative
1390 : )
1391 : {
1392 :
1393 : // SUBROUTINE INFORMATION:
1394 : // AUTHOR Richard Raustad, FSEC
1395 : // DATE WRITTEN June 2003
1396 : // MODIFIED Don Shirey, Aug 2009 (LatentMassLoadMet)
1397 : // July 2012, Chandan Sharma - FSEC: Added zone sys avail managers
1398 :
1399 : // PURPOSE OF THIS SUBROUTINE:
1400 : // Simulate the components making up the Stand Alone ERV unit.
1401 :
1402 : // METHODOLOGY EMPLOYED:
1403 : // Simulates the unit components sequentially in the air flow direction.
1404 :
1405 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1406 : Real64 TotLoadMet; // total zone load met by unit (W)
1407 : Real64 LatLoadMet; // latent zone load met by unit (W)
1408 : bool EconomizerFlag; // economizer signal from OA controller
1409 : bool HighHumCtrlFlag; // high humditiy control signal from OA controller
1410 :
1411 653189 : int SupInletNode = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirInletNode;
1412 653189 : int SupOutletNode = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirOutletNode;
1413 653189 : int ExhaustInletNode = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirInletNode;
1414 :
1415 : // Stand alone ERV's HX is ON by default
1416 653189 : bool HXUnitOn = true;
1417 :
1418 : // Get stand alone ERV's controller economizer and high humidity control status
1419 653189 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerNameDefined) {
1420 567321 : EconomizerFlag = state.dataMixedAir->OAController(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerIndex).EconoActive;
1421 567321 : HighHumCtrlFlag =
1422 567321 : state.dataMixedAir->OAController(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerIndex).HighHumCtrlActive;
1423 : } else {
1424 85868 : EconomizerFlag = false;
1425 85868 : HighHumCtrlFlag = false;
1426 : }
1427 :
1428 1306378 : HeatRecovery::SimHeatRecovery(state,
1429 653189 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).HeatExchangerName,
1430 : FirstHVACIteration,
1431 653189 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).HeatExchangerIndex,
1432 : HVAC::FanOp::Continuous,
1433 : _,
1434 : HXUnitOn,
1435 : _,
1436 : _,
1437 : EconomizerFlag,
1438 : HighHumCtrlFlag);
1439 653189 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ElecUseRate = state.dataHVACGlobal->AirToAirHXElecPower;
1440 :
1441 653189 : state.dataFans->fans(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirFanIndex)->simulate(state, FirstHVACIteration, _, _);
1442 653189 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ElecUseRate +=
1443 653189 : state.dataFans->fans(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirFanIndex)->totalPower;
1444 :
1445 653189 : state.dataFans->fans(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirFanIndex)->simulate(state, FirstHVACIteration, _, _);
1446 653189 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ElecUseRate +=
1447 653189 : state.dataFans->fans(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirFanIndex)->totalPower;
1448 :
1449 : // total mass flow through supply side of the ERV (supply air outlet node)
1450 653189 : Real64 AirMassFlow = state.dataLoopNodes->Node(SupOutletNode).MassFlowRate;
1451 2612756 : CalcZoneSensibleLatentOutput(AirMassFlow,
1452 653189 : state.dataLoopNodes->Node(SupOutletNode).Temp,
1453 653189 : state.dataLoopNodes->Node(SupOutletNode).HumRat,
1454 653189 : state.dataLoopNodes->Node(ExhaustInletNode).Temp,
1455 653189 : state.dataLoopNodes->Node(ExhaustInletNode).HumRat,
1456 : SensLoadMet,
1457 : LatLoadMet,
1458 : TotLoadMet);
1459 653189 : LatentMassLoadMet = AirMassFlow * (state.dataLoopNodes->Node(SupOutletNode).HumRat -
1460 653189 : state.dataLoopNodes->Node(ExhaustInletNode).HumRat); // kg/s, dehumidification = negative
1461 :
1462 653189 : if (SensLoadMet < 0.0) {
1463 454606 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SensCoolingRate = std::abs(SensLoadMet);
1464 454606 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SensHeatingRate = 0.0;
1465 : } else {
1466 198583 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SensCoolingRate = 0.0;
1467 198583 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SensHeatingRate = SensLoadMet;
1468 : }
1469 653189 : if (TotLoadMet < 0.0) {
1470 538229 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).TotCoolingRate = std::abs(TotLoadMet);
1471 538229 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).TotHeatingRate = 0.0;
1472 : } else {
1473 114960 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).TotCoolingRate = 0.0;
1474 114960 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).TotHeatingRate = TotLoadMet;
1475 : }
1476 653189 : if (LatLoadMet < 0.0) {
1477 635921 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).LatCoolingRate = std::abs(LatLoadMet);
1478 635921 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).LatHeatingRate = 0.0;
1479 : } else {
1480 17268 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).LatCoolingRate = 0.0;
1481 17268 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).LatHeatingRate = LatLoadMet;
1482 : }
1483 :
1484 : // Provide a one time message when exhaust flow rate is greater than supply flow rate
1485 653189 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).FlowError && !state.dataGlobal->WarmupFlag) {
1486 89694 : Real64 TotalExhaustMassFlow = state.dataLoopNodes->Node(ExhaustInletNode).MassFlowRate;
1487 89694 : Real64 TotalSupplyMassFlow = state.dataLoopNodes->Node(SupInletNode).MassFlowRate;
1488 89694 : if (TotalExhaustMassFlow > TotalSupplyMassFlow && !state.dataHeatBal->ZoneAirMassFlow.EnforceZoneMassBalance) {
1489 0 : ShowWarningError(state,
1490 0 : format("For {} \"{}\" there is unbalanced exhaust air flow.",
1491 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).UnitType,
1492 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).Name));
1493 0 : ShowContinueError(state, format("... The exhaust air mass flow rate = {:.6R}", state.dataLoopNodes->Node(ExhaustInletNode).MassFlowRate));
1494 0 : ShowContinueError(state, format("... The supply air mass flow rate = {:.6R}", state.dataLoopNodes->Node(SupInletNode).MassFlowRate));
1495 0 : ShowContinueErrorTimeStamp(state, "");
1496 0 : ShowContinueError(state, "... Unless there is balancing infiltration / ventilation air flow, this will result in");
1497 0 : ShowContinueError(state, "... load due to induced outside air being neglected in the simulation.");
1498 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).FlowError = false;
1499 : }
1500 : }
1501 653189 : }
1502 :
1503 653189 : void ReportStandAloneERV(EnergyPlusData &state, int const StandAloneERVNum) // number of the current Stand Alone ERV being simulated
1504 : {
1505 :
1506 : // SUBROUTINE INFORMATION:
1507 : // AUTHOR Richard Raustad, FSEC
1508 : // DATE WRITTEN June 2003
1509 :
1510 653189 : Real64 ReportingConstant = state.dataHVACGlobal->TimeStepSysSec;
1511 653189 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ElecUseEnergy =
1512 653189 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ElecUseRate * ReportingConstant;
1513 653189 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SensCoolingEnergy =
1514 653189 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SensCoolingRate * ReportingConstant;
1515 653189 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).LatCoolingEnergy =
1516 653189 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).LatCoolingRate * ReportingConstant;
1517 653189 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).TotCoolingEnergy =
1518 653189 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).TotCoolingRate * ReportingConstant;
1519 653189 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SensHeatingEnergy =
1520 653189 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SensHeatingRate * ReportingConstant;
1521 653189 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).LatHeatingEnergy =
1522 653189 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).LatHeatingRate * ReportingConstant;
1523 653189 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).TotHeatingEnergy =
1524 653189 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).TotHeatingRate * ReportingConstant;
1525 :
1526 653189 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).FirstPass) { // reset sizing flags so other zone equipment can size normally
1527 211 : if (!state.dataGlobal->SysSizingCalc) {
1528 107 : DataSizing::resetHVACSizingGlobals(
1529 107 : state, state.dataSize->CurZoneEqNum, 0, state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).FirstPass);
1530 : }
1531 : }
1532 653189 : }
1533 :
1534 : // Utility subroutines/functions for the HeatingCoil Module
1535 :
1536 0 : Real64 GetSupplyAirFlowRate(EnergyPlusData &state,
1537 : std::string const &ERVType, // must be "ZoneHVAC:EnergyRecoveryVentilator"
1538 : std::string const &ERVCtrlName, // must match a controller name in the ERV data structure
1539 : bool &ErrorsFound // set to true if problem
1540 : )
1541 : {
1542 :
1543 : // FUNCTION INFORMATION:
1544 : // AUTHOR Linda Lawrie
1545 : // DATE WRITTEN October 2006
1546 :
1547 : // PURPOSE OF THIS FUNCTION:
1548 : // This function looks up the ERVCtrlName in the ERV Stand Alone list and returns the
1549 : // Supply Air Flow rate, if found. If incorrect name is given, ErrorsFound is returned as true
1550 : // and supply air flow rate as negative.
1551 :
1552 0 : if (state.dataHVACStandAloneERV->GetERVInputFlag) {
1553 0 : GetStandAloneERV(state);
1554 0 : state.dataHVACStandAloneERV->GetERVInputFlag = false;
1555 : }
1556 :
1557 0 : if (Util::SameString(ERVType, "ZoneHVAC:EnergyRecoveryVentilator")) {
1558 0 : int WhichERV = Util::FindItem(ERVCtrlName, state.dataHVACStandAloneERV->StandAloneERV, &StandAloneERVData::ControllerName);
1559 0 : if (WhichERV != 0) {
1560 0 : return state.dataHVACStandAloneERV->StandAloneERV(WhichERV).SupplyAirVolFlow;
1561 : }
1562 : }
1563 :
1564 0 : ShowSevereError(state, format("Could not find ZoneHVAC:EnergyRecoveryVentilator with Controller Name=\"{}\"", ERVCtrlName));
1565 0 : ErrorsFound = true;
1566 0 : return -1000.0;
1567 : }
1568 :
1569 21418 : int GetStandAloneERVOutAirNode(EnergyPlusData &state, int const StandAloneERVNum)
1570 : {
1571 : // FUNCTION INFORMATION:
1572 : // AUTHOR B Griffith
1573 : // DATE WRITTEN Dec 2006
1574 :
1575 : // PURPOSE OF THIS FUNCTION:
1576 : // lookup function for OA inlet node for ventilation rate reporting
1577 :
1578 21418 : if (state.dataHVACStandAloneERV->GetERVInputFlag) {
1579 0 : GetStandAloneERV(state);
1580 0 : state.dataHVACStandAloneERV->GetERVInputFlag = false;
1581 : }
1582 :
1583 21418 : if (StandAloneERVNum > 0 && StandAloneERVNum <= state.dataHVACStandAloneERV->NumStandAloneERVs) {
1584 21418 : return state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirInletNode;
1585 : }
1586 :
1587 0 : return 0;
1588 : }
1589 :
1590 21418 : int GetStandAloneERVZoneInletAirNode(EnergyPlusData &state, int const StandAloneERVNum)
1591 : {
1592 : // FUNCTION INFORMATION:
1593 : // AUTHOR B Griffith
1594 : // DATE WRITTEN Dec 2006
1595 :
1596 : // PURPOSE OF THIS FUNCTION:
1597 : // lookup function for OA inlet node for ventilation rate reporting
1598 :
1599 21418 : if (state.dataHVACStandAloneERV->GetERVInputFlag) {
1600 0 : GetStandAloneERV(state);
1601 0 : state.dataHVACStandAloneERV->GetERVInputFlag = false;
1602 : }
1603 :
1604 21418 : if (StandAloneERVNum > 0 && StandAloneERVNum <= state.dataHVACStandAloneERV->NumStandAloneERVs) {
1605 21418 : return state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirOutletNode;
1606 : }
1607 :
1608 0 : return 0;
1609 : }
1610 :
1611 21418 : int GetStandAloneERVReturnAirNode(EnergyPlusData &state, int const StandAloneERVNum)
1612 : {
1613 : // FUNCTION INFORMATION:
1614 : // AUTHOR B Griffith
1615 : // DATE WRITTEN Dec 2006
1616 :
1617 : // PURPOSE OF THIS FUNCTION:
1618 : // lookup function for OA inlet node for ventilation rate reporting
1619 :
1620 21418 : if (state.dataHVACStandAloneERV->GetERVInputFlag) {
1621 0 : GetStandAloneERV(state);
1622 0 : state.dataHVACStandAloneERV->GetERVInputFlag = false;
1623 : }
1624 :
1625 21418 : if (StandAloneERVNum > 0 && StandAloneERVNum <= state.dataHVACStandAloneERV->NumStandAloneERVs) {
1626 21418 : return state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirInletNode;
1627 : }
1628 :
1629 0 : return 0;
1630 : }
1631 :
1632 16 : bool GetStandAloneERVNodeNumber(EnergyPlusData &state, int const NodeNumber)
1633 : {
1634 : // PURPOSE OF THIS FUNCTION:
1635 : // Check if a node is used by a stand alone ERV
1636 : // and can be excluded from an airflow network.
1637 :
1638 16 : if (state.dataHVACStandAloneERV->GetERVInputFlag) {
1639 0 : GetStandAloneERV(state);
1640 0 : state.dataHVACStandAloneERV->GetERVInputFlag = false;
1641 : }
1642 :
1643 26 : for (int StandAloneERVIndex = 1; StandAloneERVIndex <= state.dataHVACStandAloneERV->NumStandAloneERVs; ++StandAloneERVIndex) {
1644 :
1645 16 : auto &StandAloneERV = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVIndex);
1646 16 : int SupplyFanInletNodeIndex = 0;
1647 16 : int SupplyFanOutletNodeIndex = 0;
1648 16 : int ExhaustFanInletNodeIndex = 0;
1649 16 : int ExhaustFanOutletNodeIndex = 0;
1650 : Real64 SupplyFanAirFlow;
1651 : Real64 ExhaustFanAirFlow;
1652 :
1653 : // Get supply air fan inlet and outlet node index and air flow
1654 : // ZoneHVAC:EnergyRecoveryVentilator only accepts Fan:SystemModel or Fan:OnOff
1655 16 : SupplyFanInletNodeIndex = state.dataFans->fans(StandAloneERV.SupplyAirFanIndex)->inletNodeNum;
1656 16 : SupplyFanOutletNodeIndex = state.dataFans->fans(StandAloneERV.SupplyAirFanIndex)->outletNodeNum;
1657 16 : SupplyFanAirFlow = state.dataFans->fans(StandAloneERV.SupplyAirFanIndex)->maxAirFlowRate;
1658 :
1659 : // Get exhaust air fan inlet and outlet node index and air flow
1660 16 : ExhaustFanInletNodeIndex = state.dataFans->fans(StandAloneERV.ExhaustAirFanIndex)->inletNodeNum;
1661 16 : ExhaustFanOutletNodeIndex = state.dataFans->fans(StandAloneERV.ExhaustAirFanIndex)->outletNodeNum;
1662 16 : ExhaustFanAirFlow = state.dataFans->fans(StandAloneERV.ExhaustAirFanIndex)->maxAirFlowRate;
1663 :
1664 : // If a standalone ERV's airflow is unbalanced it shouldn't be model along with an AFN
1665 32 : if (std::abs(SupplyFanAirFlow - ExhaustFanAirFlow) >= 1E-20 ||
1666 16 : std::abs(StandAloneERV.DesignSAFanVolFlowRate - StandAloneERV.DesignEAFanVolFlowRate) >= 1E-20) {
1667 0 : break;
1668 : }
1669 :
1670 : // Supply air fan nodes
1671 16 : if (NodeNumber == SupplyFanInletNodeIndex || NodeNumber == SupplyFanOutletNodeIndex || NodeNumber == ExhaustFanInletNodeIndex ||
1672 : NodeNumber == ExhaustFanOutletNodeIndex) {
1673 4 : return true;
1674 : }
1675 :
1676 : // Supply air inlet node
1677 12 : if (NodeNumber == StandAloneERV.SupplyAirInletNode) {
1678 2 : return true;
1679 : }
1680 : }
1681 :
1682 10 : return false;
1683 : }
1684 :
1685 0 : int getEqIndex(EnergyPlusData &state, std::string_view CompName)
1686 : {
1687 0 : if (state.dataHVACStandAloneERV->GetERVInputFlag) {
1688 0 : GetStandAloneERV(state);
1689 0 : state.dataHVACStandAloneERV->GetERVInputFlag = false;
1690 : }
1691 :
1692 0 : for (int StandAloneERVNum = 1; StandAloneERVNum <= state.dataHVACStandAloneERV->NumStandAloneERVs; StandAloneERVNum++) {
1693 0 : if (Util::SameString(CompName, state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).Name)) {
1694 0 : return StandAloneERVNum;
1695 : }
1696 : }
1697 0 : return 0;
1698 : }
1699 :
1700 : } // namespace EnergyPlus::HVACStandAloneERV
|