Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2025, 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 653192 : 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 653192 : 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 653192 : 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 653085 : StandAloneERVNum = CompIndex;
135 653085 : 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 653085 : 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 653192 : InitStandAloneERV(state, StandAloneERVNum, ZoneNum, FirstHVACIteration);
156 :
157 653192 : CalcStandAloneERV(state, StandAloneERVNum, FirstHVACIteration, SensLoadMet, LatLoadMet);
158 :
159 653192 : ReportStandAloneERV(state, StandAloneERVNum);
160 653192 : }
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.availSched = Sched::GetScheduleAlwaysOn(state);
254 107 : } else if ((standAloneERV.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
255 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
256 0 : ErrorsFound = true;
257 : }
258 :
259 107 : GlobalNames::IntraObjUniquenessCheck(
260 214 : state, Alphas(3), CurrentModuleObject, cAlphaFields(3), state.dataHVACStandAloneERV->HeatExchangerUniqueNames, ErrorsFound);
261 107 : standAloneERV.HeatExchangerName = Alphas(3);
262 107 : bool errFlag = false;
263 107 : standAloneERV.hxType = HeatRecovery::GetHeatExchangerObjectTypeNum(state, standAloneERV.HeatExchangerName, errFlag);
264 107 : if (errFlag) {
265 0 : ShowContinueError(state, format("... occurs in {} \"{}\"", CurrentModuleObject, standAloneERV.Name));
266 0 : ErrorsFound = true;
267 : }
268 :
269 107 : errFlag = false;
270 107 : HXSupAirFlowRate = HeatRecovery::GetSupplyAirFlowRate(state, standAloneERV.HeatExchangerName, errFlag);
271 107 : if (errFlag) {
272 0 : ShowContinueError(state, format("... occurs in {} \"{}\"", CurrentModuleObject, standAloneERV.Name));
273 0 : ErrorsFound = true;
274 : }
275 107 : standAloneERV.DesignHXVolFlowRate = HXSupAirFlowRate;
276 :
277 107 : standAloneERV.SupplyAirFanName = Alphas(4);
278 107 : GlobalNames::IntraObjUniquenessCheck(
279 214 : state, Alphas(4), CurrentModuleObject, cAlphaFields(4), state.dataHVACStandAloneERV->SupplyAirFanUniqueNames, ErrorsFound);
280 :
281 107 : if ((standAloneERV.SupplyAirFanIndex = Fans::GetFanIndex(state, standAloneERV.SupplyAirFanName)) == 0) {
282 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(4), standAloneERV.SupplyAirFanName);
283 0 : ErrorsFound = true;
284 : } else {
285 107 : auto *fan = state.dataFans->fans(standAloneERV.SupplyAirFanIndex);
286 107 : standAloneERV.supplyAirFanType = fan->type;
287 107 : standAloneERV.supplyAirFanSched = fan->availSched;
288 107 : standAloneERV.DesignSAFanVolFlowRate = fan->maxAirFlowRate;
289 107 : standAloneERV.SupplyAirOutletNode = fan->outletNodeNum;
290 : }
291 :
292 107 : standAloneERV.ExhaustAirFanName = Alphas(5);
293 107 : GlobalNames::IntraObjUniquenessCheck(
294 214 : state, Alphas(5), CurrentModuleObject, cAlphaFields(5), state.dataHVACStandAloneERV->ExhaustAirFanUniqueNames, ErrorsFound);
295 :
296 107 : if ((standAloneERV.ExhaustAirFanIndex = Fans::GetFanIndex(state, standAloneERV.ExhaustAirFanName)) == 0) {
297 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(5), standAloneERV.ExhaustAirFanName);
298 0 : ErrorsFound = true;
299 :
300 : } else {
301 107 : auto *fan = state.dataFans->fans(standAloneERV.ExhaustAirFanIndex);
302 107 : standAloneERV.exhaustAirFanType = fan->type;
303 :
304 107 : standAloneERV.exhaustAirFanSched = fan->availSched;
305 107 : standAloneERV.DesignEAFanVolFlowRate = fan->maxAirFlowRate;
306 107 : standAloneERV.ExhaustAirOutletNode = fan->outletNodeNum;
307 : }
308 :
309 107 : errFlag = false;
310 107 : standAloneERV.SupplyAirInletNode = HeatRecovery::GetSupplyInletNode(state, standAloneERV.HeatExchangerName, errFlag);
311 107 : standAloneERV.ExhaustAirInletNode = HeatRecovery::GetSecondaryInletNode(state, standAloneERV.HeatExchangerName, errFlag);
312 107 : if (errFlag) {
313 0 : ShowContinueError(state, format("... occurs in {} ={}", CurrentModuleObject, standAloneERV.Name));
314 0 : ErrorsFound = true;
315 : }
316 107 : standAloneERV.SupplyAirInletNode = GetOnlySingleNode(state,
317 107 : state.dataLoopNodes->NodeID(standAloneERV.SupplyAirInletNode),
318 : ErrorsFound,
319 : DataLoopNode::ConnectionObjectType::ZoneHVACEnergyRecoveryVentilator,
320 107 : Alphas(1),
321 : DataLoopNode::NodeFluidType::Air,
322 : DataLoopNode::ConnectionType::Inlet,
323 : NodeInputManager::CompFluidStream::Primary,
324 : DataLoopNode::ObjectIsParent);
325 107 : standAloneERV.SupplyAirOutletNode = GetOnlySingleNode(state,
326 107 : state.dataLoopNodes->NodeID(standAloneERV.SupplyAirOutletNode),
327 : ErrorsFound,
328 : DataLoopNode::ConnectionObjectType::ZoneHVACEnergyRecoveryVentilator,
329 107 : Alphas(1),
330 : DataLoopNode::NodeFluidType::Air,
331 : DataLoopNode::ConnectionType::Outlet,
332 : NodeInputManager::CompFluidStream::Primary,
333 : DataLoopNode::ObjectIsParent);
334 107 : standAloneERV.ExhaustAirInletNode = GetOnlySingleNode(state,
335 107 : state.dataLoopNodes->NodeID(standAloneERV.ExhaustAirInletNode),
336 : ErrorsFound,
337 : DataLoopNode::ConnectionObjectType::ZoneHVACEnergyRecoveryVentilator,
338 107 : Alphas(1),
339 : DataLoopNode::NodeFluidType::Air,
340 : DataLoopNode::ConnectionType::Inlet,
341 : NodeInputManager::CompFluidStream::Secondary,
342 : DataLoopNode::ObjectIsParent);
343 107 : standAloneERV.ExhaustAirOutletNode = GetOnlySingleNode(state,
344 107 : state.dataLoopNodes->NodeID(standAloneERV.ExhaustAirOutletNode),
345 : ErrorsFound,
346 : DataLoopNode::ConnectionObjectType::ZoneHVACEnergyRecoveryVentilator,
347 107 : Alphas(1),
348 : DataLoopNode::NodeFluidType::Air,
349 : DataLoopNode::ConnectionType::ReliefAir,
350 : NodeInputManager::CompFluidStream::Secondary,
351 : DataLoopNode::ObjectIsParent);
352 :
353 : // Check that supply air inlet node is an OA node
354 107 : if (!OutAirNodeManager::CheckOutAirNodeNumber(state, standAloneERV.SupplyAirInletNode)) {
355 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, standAloneERV.Name));
356 0 : ShowContinueError(state,
357 0 : format(" Node name of supply air inlet node not valid Outdoor Air Node = {}",
358 0 : state.dataLoopNodes->NodeID(standAloneERV.SupplyAirInletNode)));
359 0 : ShowContinueError(state, "...does not appear in an OutdoorAir:NodeList or as an OutdoorAir:Node.");
360 0 : ErrorsFound = true;
361 : }
362 :
363 : // Check to make sure inlet and exhaust nodes are listed in a ZoneHVAC:EquipmentConnections object
364 107 : bool ZoneInletNodeFound = false;
365 107 : bool ZoneExhaustNodeFound = false;
366 7851 : for (int ControlledZoneNum = 1; ControlledZoneNum <= state.dataGlobal->NumOfZones; ++ControlledZoneNum) {
367 7744 : if (!ZoneInletNodeFound) {
368 10783 : for (NodeNumber = 1; NodeNumber <= state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumInletNodes; ++NodeNumber) {
369 6988 : if (state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNode(NodeNumber) == standAloneERV.SupplyAirOutletNode) {
370 107 : ZoneInletNodeFound = true;
371 107 : ZoneInletCZN = ControlledZoneNum;
372 107 : break; // found zone inlet node
373 : }
374 : }
375 : }
376 7744 : if (!ZoneExhaustNodeFound) {
377 7245 : for (NodeNumber = 1; NodeNumber <= state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumExhaustNodes; ++NodeNumber) {
378 3450 : if (state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ExhaustNode(NodeNumber) == standAloneERV.ExhaustAirInletNode) {
379 107 : ZoneExhaustNodeFound = true;
380 107 : ZoneExhaustCZN = ControlledZoneNum;
381 107 : break; // found zone exhaust node
382 : }
383 : }
384 : }
385 : }
386 107 : if (!ZoneInletNodeFound) {
387 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, standAloneERV.Name));
388 0 : ShowContinueError(state, "... Node name of supply air outlet node does not appear in a ZoneHVAC:EquipmentConnections object.");
389 0 : ShowContinueError(state, format("... Supply air outlet node = {}", state.dataLoopNodes->NodeID(standAloneERV.SupplyAirOutletNode)));
390 0 : ErrorsFound = true;
391 : }
392 107 : if (!ZoneExhaustNodeFound) {
393 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, standAloneERV.Name));
394 0 : ShowContinueError(state, "... Node name of exhaust air inlet node does not appear in a ZoneHVAC:EquipmentConnections object.");
395 0 : ShowContinueError(state, format("... Exhaust air inlet node = {}", state.dataLoopNodes->NodeID(standAloneERV.ExhaustAirInletNode)));
396 0 : ErrorsFound = true;
397 : }
398 : // If nodes are found, make sure they are in the same zone
399 107 : if (ZoneInletNodeFound && ZoneExhaustNodeFound) {
400 107 : if (ZoneInletCZN != ZoneExhaustCZN) {
401 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, standAloneERV.Name));
402 0 : ShowContinueError(state,
403 : "... Node name of supply air outlet node and exhasut air inlet node must appear in the same "
404 : "ZoneHVAC:EquipmentConnections object.");
405 0 : ShowContinueError(state, format("... Supply air outlet node = {}", state.dataLoopNodes->NodeID(standAloneERV.SupplyAirOutletNode)));
406 0 : ShowContinueError(
407 0 : state, format("... ZoneHVAC:EquipmentConnections Zone Name = {}", state.dataZoneEquip->ZoneEquipConfig(ZoneInletCZN).ZoneName));
408 0 : ShowContinueError(state, format("... Exhaust air inlet node = {}", state.dataLoopNodes->NodeID(standAloneERV.ExhaustAirInletNode)));
409 0 : ShowContinueError(
410 0 : state, format("... ZoneHVAC:EquipmentConnections Zone Name = {}", state.dataZoneEquip->ZoneEquipConfig(ZoneExhaustCZN).ZoneName));
411 0 : ErrorsFound = true;
412 : }
413 : }
414 :
415 107 : standAloneERV.ControllerName = Alphas(6);
416 : // If controller name is blank the ERV unit will operate with no controller
417 107 : if (lAlphaBlanks(6)) {
418 3 : standAloneERV.ControllerName = "xxxxx";
419 3 : standAloneERV.ControllerNameDefined = false;
420 : } else {
421 : // Verify controller name in Stand Alone ERV object matches name of valid controller object
422 104 : GlobalNames::IntraObjUniquenessCheck(
423 208 : state, Alphas(6), CurrentModuleObject, cAlphaFields(6), state.dataHVACStandAloneERV->ControllerUniqueNames, ErrorsFound);
424 104 : standAloneERV.ControllerNameDefined = true;
425 104 : if (ErrorsFound) {
426 0 : standAloneERV.ControllerNameDefined = false;
427 : }
428 :
429 104 : if (state.dataInputProcessing->inputProcessor->getObjectItemNum(
430 104 : state, "ZoneHVAC:EnergyRecoveryVentilator:Controller", standAloneERV.ControllerName) <= 0) {
431 0 : ShowSevereError(
432 0 : state, format("{} controller type ZoneHVAC:EnergyRecoveryVentilator:Controller not found = {}", CurrentModuleObject, Alphas(6)));
433 0 : ErrorsFound = true;
434 0 : standAloneERV.ControllerNameDefined = false;
435 : }
436 : }
437 :
438 107 : if (!lAlphaBlanks(7)) {
439 0 : standAloneERV.AvailManagerListName = Alphas(7);
440 : }
441 :
442 : // Read supply and exhaust air flow rates
443 107 : standAloneERV.SupplyAirVolFlow = Numbers(1);
444 107 : standAloneERV.ExhaustAirVolFlow = Numbers(2);
445 :
446 : // Read ventilation rate per floor area for autosizing HX and fans
447 107 : standAloneERV.AirVolFlowPerFloorArea = Numbers(3);
448 107 : standAloneERV.AirVolFlowPerOccupant = Numbers(4);
449 :
450 107 : if (standAloneERV.SupplyAirVolFlow == DataSizing::AutoSize && standAloneERV.DesignSAFanVolFlowRate != DataSizing::AutoSize) {
451 0 : ShowSevereError(state, format("{} \"{}\"", CurrentModuleObject, standAloneERV.Name));
452 0 : ShowContinueError(state,
453 0 : format("... When autosizing ERV, supply air fan = {} \"{}\" must also be autosized.",
454 0 : HVAC::fanTypeNames[(int)standAloneERV.supplyAirFanType],
455 0 : standAloneERV.SupplyAirFanName));
456 : }
457 :
458 107 : if (standAloneERV.ExhaustAirVolFlow == DataSizing::AutoSize && standAloneERV.DesignEAFanVolFlowRate != DataSizing::AutoSize) {
459 0 : ShowSevereError(state, format("{} \"{}\"", CurrentModuleObject, standAloneERV.Name));
460 0 : ShowContinueError(state,
461 0 : format("... When autosizing ERV, exhaust air fan = {} \"{}\" must also be autosized.",
462 0 : HVAC::fanTypeNames[(int)standAloneERV.exhaustAirFanType],
463 0 : standAloneERV.ExhaustAirFanName));
464 : }
465 :
466 107 : if (standAloneERV.SupplyAirVolFlow == DataSizing::AutoSize && HXSupAirFlowRate != DataSizing::AutoSize) {
467 0 : ShowSevereError(state, format("{} \"{}\"", CurrentModuleObject, standAloneERV.Name));
468 0 : ShowContinueError(
469 : state,
470 0 : format("... When autosizing ERV {}, nominal supply air flow rate for heat exchanger with name = {} must also be autosized.",
471 : cNumericFields(1),
472 0 : standAloneERV.HeatExchangerName));
473 : }
474 :
475 107 : if (standAloneERV.ExhaustAirVolFlow == DataSizing::AutoSize && HXSupAirFlowRate != DataSizing::AutoSize) {
476 0 : ShowSevereError(state, format("{} \"{}\"", CurrentModuleObject, standAloneERV.Name));
477 0 : ShowContinueError(
478 : state,
479 0 : format("... When autosizing ERV {}, nominal supply air flow rate for heat exchanger with name = {} must also be autosized.",
480 : cNumericFields(2),
481 0 : standAloneERV.HeatExchangerName));
482 : }
483 :
484 : // Compare the ERV SA flow rates to SA fan object.
485 107 : if (standAloneERV.DesignSAFanVolFlowRate != DataSizing::AutoSize && standAloneERV.SupplyAirVolFlow != DataSizing::AutoSize) {
486 5 : if (standAloneERV.SupplyAirVolFlow > standAloneERV.DesignSAFanVolFlowRate) {
487 0 : ShowWarningError(state,
488 0 : format("{} = {} has a {} > Max Volume Flow Rate defined in the associated fan object, should be <=",
489 : CurrentModuleObject,
490 0 : standAloneERV.Name,
491 : cNumericFields(1)));
492 0 : ShowContinueError(state,
493 0 : format("... Entered value={:.2R}... Fan [{} \"{}\"] Max Value = {:.2R}",
494 0 : standAloneERV.SupplyAirVolFlow,
495 0 : HVAC::fanTypeNames[(int)standAloneERV.supplyAirFanType],
496 0 : standAloneERV.SupplyAirFanName,
497 0 : standAloneERV.DesignSAFanVolFlowRate));
498 0 : ShowContinueError(state,
499 0 : format(" The ERV {} is reset to the supply air fan flow rate and the simulation continues.", cNumericFields(1)));
500 0 : standAloneERV.SupplyAirVolFlow = standAloneERV.DesignSAFanVolFlowRate;
501 : }
502 : }
503 107 : if (standAloneERV.SupplyAirVolFlow != DataSizing::AutoSize) {
504 107 : if (standAloneERV.SupplyAirVolFlow <= 0.0) {
505 0 : ShowSevereError(state,
506 0 : format("{} = {} has a {} <= 0.0, it must be >0.0", CurrentModuleObject, standAloneERV.Name, cNumericFields(1)));
507 0 : ShowContinueError(state, format("... Entered value={:.2R}", standAloneERV.SupplyAirVolFlow));
508 0 : ErrorsFound = true;
509 : }
510 : } else {
511 0 : if (standAloneERV.AirVolFlowPerFloorArea == 0.0 && standAloneERV.AirVolFlowPerOccupant == 0.0) {
512 0 : ShowSevereError(state, format("{} \"{}\"", CurrentModuleObject, standAloneERV.Name));
513 0 : ShowContinueError(
514 : state,
515 0 : format("... Autosizing {} requires at least one input for {} or {}.", cNumericFields(1), cNumericFields(3), cNumericFields(4)));
516 0 : ErrorsFound = true;
517 : }
518 : // both inputs must be autosized
519 0 : if (standAloneERV.ExhaustAirVolFlow != DataSizing::AutoSize) {
520 0 : ShowSevereError(state, format("{} \"{}\"", CurrentModuleObject, standAloneERV.Name));
521 0 : ShowContinueError(state, format("... When autosizing, {} and {} must both be autosized.", cNumericFields(1), cNumericFields(2)));
522 0 : ErrorsFound = true;
523 : }
524 : }
525 :
526 : // Compare the ERV EA flow rates to EA fan object.
527 107 : if (standAloneERV.DesignEAFanVolFlowRate != DataSizing::AutoSize && standAloneERV.ExhaustAirVolFlow != DataSizing::AutoSize) {
528 5 : if (standAloneERV.ExhaustAirVolFlow > standAloneERV.DesignEAFanVolFlowRate) {
529 0 : ShowWarningError(state,
530 0 : format("{} = {} has an {} > Max Volume Flow Rate defined in the associated fan object, should be <=",
531 : CurrentModuleObject,
532 0 : standAloneERV.Name,
533 : cNumericFields(2)));
534 0 : ShowContinueError(state,
535 0 : format("... Entered value={:.2R}... Fan [{}:{}] Max Value = {:.2R}",
536 0 : standAloneERV.ExhaustAirVolFlow,
537 0 : HVAC::fanTypeNames[(int)standAloneERV.exhaustAirFanType],
538 0 : standAloneERV.ExhaustAirFanName,
539 0 : standAloneERV.DesignEAFanVolFlowRate));
540 0 : ShowContinueError(state,
541 0 : format(" The ERV {} is reset to the exhaust air fan flow rate and the simulation continues.", cNumericFields(2)));
542 0 : standAloneERV.ExhaustAirVolFlow = standAloneERV.DesignEAFanVolFlowRate;
543 : }
544 : }
545 107 : if (standAloneERV.ExhaustAirVolFlow != DataSizing::AutoSize) {
546 107 : if (standAloneERV.ExhaustAirVolFlow <= 0.0) {
547 0 : ShowSevereError(state,
548 0 : format("{} = {} has an {} <= 0.0, it must be >0.0", CurrentModuleObject, standAloneERV.Name, cNumericFields(2)));
549 0 : ShowContinueError(state, format("... Entered value={:.2R}", standAloneERV.ExhaustAirVolFlow));
550 0 : ErrorsFound = true;
551 : }
552 : } else {
553 0 : if (standAloneERV.AirVolFlowPerFloorArea == 0.0 && standAloneERV.AirVolFlowPerOccupant == 0.0) {
554 0 : ShowSevereError(state, format("{} \"{}\"", CurrentModuleObject, standAloneERV.Name));
555 0 : ShowContinueError(
556 : state,
557 0 : format("... Autosizing {} requires at least one input for {} or {}.", cNumericFields(2), cNumericFields(3), cNumericFields(4)));
558 0 : ErrorsFound = true;
559 : }
560 0 : if (standAloneERV.SupplyAirVolFlow != DataSizing::AutoSize) {
561 0 : ShowSevereError(state, format("{} \"{}\"", CurrentModuleObject, standAloneERV.Name));
562 0 : ShowContinueError(state, format("... When autosizing, {} and {} must both be autosized.", cNumericFields(1), cNumericFields(2)));
563 0 : ErrorsFound = true;
564 : }
565 : }
566 :
567 : // Add supply fan to component sets array
568 107 : std::string CompSetSupplyFanInlet = "UNDEFINED";
569 107 : std::string CompSetSupplyFanOutlet = state.dataLoopNodes->NodeID(standAloneERV.SupplyAirOutletNode);
570 :
571 : // Add exhaust fan to component sets array
572 107 : std::string CompSetExhaustFanInlet = "UNDEFINED";
573 107 : std::string CompSetExhaustFanOutlet = state.dataLoopNodes->NodeID(standAloneERV.ExhaustAirOutletNode);
574 :
575 : // Add HX to component sets array
576 107 : BranchNodeConnections::SetUpCompSets(
577 : state, standAloneERV.UnitType, standAloneERV.Name, "UNDEFINED", standAloneERV.HeatExchangerName, "UNDEFINED", "UNDEFINED");
578 :
579 : // Add supply fan to component sets array
580 107 : BranchNodeConnections::SetUpCompSets(state,
581 : standAloneERV.UnitType,
582 : standAloneERV.Name,
583 : "UNDEFINED",
584 : standAloneERV.SupplyAirFanName,
585 : CompSetSupplyFanInlet,
586 : CompSetSupplyFanOutlet);
587 :
588 : // Add exhaust fan to component sets array
589 107 : BranchNodeConnections::SetUpCompSets(state,
590 : standAloneERV.UnitType,
591 : standAloneERV.Name,
592 : "UNDEFINED",
593 : standAloneERV.ExhaustAirFanName,
594 : CompSetExhaustFanInlet,
595 : CompSetExhaustFanOutlet);
596 :
597 : // Verify HX name in Stand Alone ERV object matches name of valid HX object
598 107 : if (state.dataInputProcessing->inputProcessor->getObjectItemNum(
599 107 : state, "HeatExchanger:AirToAir:SensibleAndLatent", standAloneERV.HeatExchangerName) <= 0) {
600 0 : ShowSevereError(state,
601 0 : format("{} heat exchanger type HeatExchanger:AirToAir:SensibleAndLatent not found = {}",
602 : CurrentModuleObject,
603 0 : standAloneERV.HeatExchangerName));
604 0 : ErrorsFound = true;
605 : }
606 : // Verify supply air fan name in Stand Alone ERV object matches name of valid fan object
607 107 : if (standAloneERV.supplyAirFanType != HVAC::FanType::SystemModel) {
608 104 : if (state.dataInputProcessing->inputProcessor->getObjectItemNum(state, "Fan:OnOff", standAloneERV.SupplyAirFanName) <= 0) {
609 0 : ShowSevereError(state, format("{} supply fan type Fan:OnOff not found = {}", CurrentModuleObject, standAloneERV.SupplyAirFanName));
610 0 : ErrorsFound = true;
611 : }
612 : } else {
613 3 : if (state.dataInputProcessing->inputProcessor->getObjectItemNum(state, "Fan:SystemModel", standAloneERV.SupplyAirFanName) <= 0) {
614 0 : ShowSevereError(state,
615 0 : format("{} supply fan type Fan:SystemModel not found = {}", CurrentModuleObject, standAloneERV.SupplyAirFanName));
616 0 : ErrorsFound = true;
617 : }
618 : }
619 :
620 : // Verify exhaust air fan name in Stand Alone ERV object matches name of valid fan object
621 107 : if (standAloneERV.exhaustAirFanType != HVAC::FanType::SystemModel) {
622 104 : if (state.dataInputProcessing->inputProcessor->getObjectItemNum(state, "Fan:OnOff", standAloneERV.ExhaustAirFanName) <= 0) {
623 0 : ShowSevereError(state, format("{} exhaust fan type Fan:OnOff not found = {}", CurrentModuleObject, standAloneERV.ExhaustAirFanName));
624 0 : ErrorsFound = true;
625 : }
626 : } else {
627 3 : if (state.dataInputProcessing->inputProcessor->getObjectItemNum(state, "Fan:SystemModel", standAloneERV.ExhaustAirFanName) <= 0) {
628 0 : ShowSevereError(state,
629 0 : format("{} exhaust fan type Fan:SystemModel not found = {}", CurrentModuleObject, standAloneERV.ExhaustAirFanName));
630 0 : ErrorsFound = true;
631 : }
632 : }
633 107 : }
634 :
635 5 : int OutAirNum = 0;
636 5 : CurrentModuleObject = "ZoneHVAC:EnergyRecoveryVentilator:Controller";
637 5 : NumERVCtrlrs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
638 :
639 109 : for (ERVControllerNum = 1; ERVControllerNum <= NumERVCtrlrs; ++ERVControllerNum) {
640 104 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
641 : CurrentModuleObject,
642 : ERVControllerNum,
643 : Alphas,
644 : NumAlphas,
645 : Numbers,
646 : NumNumbers,
647 : IOStatus,
648 : lNumericBlanks,
649 : lAlphaBlanks,
650 : cAlphaFields,
651 : cNumericFields);
652 104 : MixedAir::CheckOAControllerName(state, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
653 104 : ++OutAirNum;
654 104 : auto &thisOAController = state.dataMixedAir->OAController(OutAirNum);
655 :
656 104 : thisOAController.Name = Alphas(1);
657 104 : thisOAController.ControllerType = MixedAir::MixedAirControllerType::ControllerStandAloneERV;
658 104 : int WhichERV = Util::FindItemInList(Alphas(1), state.dataHVACStandAloneERV->StandAloneERV, &StandAloneERVData::ControllerName);
659 104 : if (WhichERV != 0) {
660 104 : AirFlowRate = state.dataHVACStandAloneERV->StandAloneERV(WhichERV).SupplyAirVolFlow;
661 104 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).ControllerIndex = OutAirNum;
662 : } else {
663 0 : ShowSevereError(
664 0 : state, format("GetERVController: Could not find ZoneHVAC:EnergyRecoveryVentilator with {} = \"{}\"", cAlphaFields(1), Alphas(1)));
665 0 : ErrorsFound = true;
666 0 : AirFlowRate = -1000.0;
667 : }
668 104 : thisOAController.MaxOA = AirFlowRate;
669 104 : thisOAController.MinOA = AirFlowRate;
670 : // OAController(OutAirNum)%TempLim = Numbers(1)
671 104 : if (lNumericBlanks(1)) {
672 102 : thisOAController.TempLim = HVAC::BlankNumeric;
673 : } else {
674 2 : thisOAController.TempLim = Numbers(1);
675 : }
676 : // OAController(OutAirNum)%TempLowLim = Numbers(2)
677 104 : if (lNumericBlanks(2)) {
678 102 : thisOAController.TempLowLim = HVAC::BlankNumeric;
679 : } else {
680 2 : thisOAController.TempLowLim = Numbers(2);
681 : }
682 : // OAController(OutAirNum)%EnthLim = Numbers(3)
683 104 : if (lNumericBlanks(3)) {
684 104 : thisOAController.EnthLim = HVAC::BlankNumeric;
685 : } else {
686 0 : thisOAController.EnthLim = Numbers(3);
687 : }
688 : // OAController(OutAirNum)%DPTempLim = Numbers(4)
689 104 : if (lNumericBlanks(4)) {
690 102 : thisOAController.DPTempLim = HVAC::BlankNumeric;
691 : } else {
692 2 : thisOAController.DPTempLim = Numbers(4);
693 : }
694 :
695 104 : if (WhichERV != 0) {
696 104 : NodeNumber = state.dataHVACStandAloneERV->StandAloneERV(WhichERV).SupplyAirInletNode;
697 : } else {
698 0 : NodeNumber = 0;
699 : }
700 104 : thisOAController.OANode = NodeNumber;
701 : // set the inlet node to also equal the OA node because this is a special controller for economizing stand alone ERV
702 : // with the assumption that equipment is bypassed....(moved from module MixedAir)
703 104 : thisOAController.InletNode = NodeNumber;
704 :
705 104 : if (WhichERV != 0) {
706 104 : NodeNumber = state.dataHVACStandAloneERV->StandAloneERV(WhichERV).ExhaustAirInletNode;
707 : } else {
708 0 : NodeNumber = 0;
709 : }
710 104 : thisOAController.RetNode = NodeNumber;
711 :
712 104 : if (!lAlphaBlanks(2)) {
713 1 : thisOAController.EnthalpyCurvePtr = Curve::GetCurveIndex(state, Alphas(2));
714 1 : if (Curve::GetCurveIndex(state, Alphas(2)) == 0) {
715 0 : ShowSevereError(state, format("{} \"{}\"", CurrentModuleObject, Alphas(1)));
716 0 : ShowContinueError(state, format("...{} not found:{}", cAlphaFields(2), Alphas(2)));
717 0 : ErrorsFound = true;
718 : } else {
719 : // Verify Curve Object, only legal types are Quadratic and Cubic
720 3 : ErrorsFound |= Curve::CheckCurveDims(state,
721 : thisOAController.EnthalpyCurvePtr, // Curve index
722 : {1}, // Valid dimensions
723 : "GetStandAloneERV: ", // Routine name
724 : CurrentModuleObject, // Object Type
725 : thisOAController.Name, // Object Name
726 1 : cAlphaFields(2)); // Field Name
727 : }
728 : }
729 :
730 : // Changed by AMIT for new implementation of the controller:outside air
731 104 : if (Alphas(3) == "EXHAUSTAIRTEMPERATURELIMIT" && Alphas(4) == "EXHAUSTAIRENTHALPYLIMIT") {
732 0 : thisOAController.Econo = MixedAir::EconoOp::DifferentialDryBulbAndEnthalpy;
733 104 : } else if (Alphas(3) == "EXHAUSTAIRTEMPERATURELIMIT" && Alphas(4) == "NOEXHAUSTAIRENTHALPYLIMIT") {
734 0 : thisOAController.Econo = MixedAir::EconoOp::DifferentialDryBulb;
735 104 : } else if (Alphas(3) == "NOEXHAUSTAIRTEMPERATURELIMIT" && Alphas(4) == "EXHAUSTAIRENTHALPYLIMIT") {
736 0 : thisOAController.Econo = MixedAir::EconoOp::DifferentialEnthalpy;
737 104 : } else if (Alphas(3) == "NOEXHAUSTAIRTEMPERATURELIMIT" && Alphas(4) == "NOEXHAUSTAIRENTHALPYLIMIT") {
738 104 : if ((!lNumericBlanks(1)) || (!lNumericBlanks(3)) || (!lNumericBlanks(4)) || (!lAlphaBlanks(2))) {
739 : // This means that any of the FIXED DRY BULB, FIXED ENTHALPY, FIXED DEW POINT AND DRY BULB OR
740 : // ELECTRONIC ENTHALPY ECONOMIZER STRATEGY is present
741 2 : thisOAController.Econo = MixedAir::EconoOp::FixedDryBulb;
742 : }
743 0 : } else if ((!lAlphaBlanks(3)) && (!lAlphaBlanks(4))) {
744 0 : if ((lNumericBlanks(1)) && (lNumericBlanks(3)) && (lNumericBlanks(4)) && lAlphaBlanks(2)) {
745 0 : ShowWarningError(state, format("{} \"{}\"", CurrentModuleObject, Alphas(1)));
746 0 : ShowContinueError(state, format("... Invalid {}{} = {}{}", cAlphaFields(3), cAlphaFields(4), Alphas(3), Alphas(4)));
747 0 : ShowContinueError(state, "... Assumed NO EXHAUST AIR TEMP LIMIT and NO EXHAUST AIR ENTHALPY LIMIT.");
748 0 : thisOAController.Econo = MixedAir::EconoOp::NoEconomizer;
749 : } else {
750 : // This means that any of the FIXED DRY BULB, FIXED ENTHALPY, FIXED DEW POINT AND DRY BULB OR
751 : // ELECTRONIC ENTHALPY ECONOMIZER STRATEGY is present
752 0 : thisOAController.Econo = MixedAir::EconoOp::FixedDryBulb;
753 : }
754 0 : } else if ((lAlphaBlanks(3)) && (!lAlphaBlanks(4))) {
755 0 : if ((lNumericBlanks(1)) && (lNumericBlanks(3)) && (lNumericBlanks(4)) && lAlphaBlanks(2)) {
756 0 : ShowWarningError(state, format("{} \"{}\"", CurrentModuleObject, Alphas(1)));
757 0 : ShowContinueError(state, format("... Invalid {} = {}", cAlphaFields(4), Alphas(4)));
758 0 : ShowContinueError(state, "... Assumed NO EXHAUST AIR ENTHALPY LIMIT.");
759 0 : thisOAController.Econo = MixedAir::EconoOp::NoEconomizer;
760 : } else {
761 : // This means that any of the FIXED DRY BULB, FIXED ENTHALPY, FIXED DEW POINT AND DRY BULB OR
762 : // ELECTRONIC ENTHALPY ECONOMIZER STRATEGY is present
763 0 : thisOAController.Econo = MixedAir::EconoOp::FixedDryBulb;
764 : }
765 0 : } else if ((!lAlphaBlanks(3)) && (lAlphaBlanks(4))) {
766 0 : if ((lNumericBlanks(1)) && (lNumericBlanks(3)) && (lNumericBlanks(4)) && lAlphaBlanks(2)) {
767 0 : ShowWarningError(state, format("{} \"{}\"", CurrentModuleObject, Alphas(1)));
768 0 : ShowContinueError(state, format("... Invalid {} = {}", cAlphaFields(3), Alphas(3)));
769 0 : ShowContinueError(state, "... Assumed NO EXHAUST AIR TEMP LIMIT ");
770 0 : thisOAController.Econo = MixedAir::EconoOp::NoEconomizer;
771 : } else {
772 : // This means that any of the FIXED DRY BULB, FIXED ENTHALPY, FIXED DEW POINT AND DRY BULB OR
773 : // ELECTRONIC ENTHALPY ECONOMIZER STRATEGY is present
774 0 : thisOAController.Econo = MixedAir::EconoOp::FixedDryBulb;
775 : }
776 : } else { // NO Economizer
777 0 : thisOAController.Econo = MixedAir::EconoOp::NoEconomizer;
778 : }
779 :
780 104 : thisOAController.FixedMin = false;
781 104 : thisOAController.EconBypass = true;
782 :
783 : // Initialize to one in case high humidity control is NOT used
784 104 : Real64 HighRHOARatio = 1.0;
785 : // READ Modify Air Flow Data
786 : // High humidity control option is YES, read in additional data
787 104 : if (Util::SameString(Alphas(6), "Yes")) {
788 :
789 1 : HStatZoneNum = Util::FindItemInList(Alphas(7), state.dataHeatBal->Zone);
790 1 : thisOAController.HumidistatZoneNum = HStatZoneNum;
791 :
792 : // Get the node number for the zone with the humidistat
793 1 : if (HStatZoneNum > 0) {
794 1 : bool ZoneNodeFound = false;
795 1 : if (state.dataZoneEquip->ZoneEquipConfig(HStatZoneNum).IsControlled) {
796 : // Find the controlled zone number for the specified humidistat location
797 1 : thisOAController.NodeNumofHumidistatZone = state.dataZoneEquip->ZoneEquipConfig(HStatZoneNum).ZoneNode;
798 1 : ZoneNodeFound = true;
799 : }
800 1 : if (!ZoneNodeFound) {
801 0 : ShowSevereError(state, format("{} \"{}\"", CurrentModuleObject, Alphas(1)));
802 0 : ShowContinueError(state, "... Did not find Air Node (Zone with Humidistat)");
803 0 : ShowContinueError(state, format("... Specified {} = {}", cAlphaFields(7), Alphas(7)));
804 0 : ShowContinueError(state, "... A ZoneHVAC:EquipmentConnections object must be specified for this zone.");
805 0 : ErrorsFound = true;
806 : } else {
807 1 : bool HStatFound = false;
808 1 : for (NumHstatZone = 1; NumHstatZone <= state.dataZoneCtrls->NumHumidityControlZones; ++NumHstatZone) {
809 1 : if (state.dataZoneCtrls->HumidityControlZone(NumHstatZone).ActualZoneNum != HStatZoneNum) {
810 0 : continue;
811 : }
812 1 : HStatFound = true;
813 1 : break;
814 : }
815 1 : if (!HStatFound) {
816 0 : ShowSevereError(state, format("{} \"{}\"", CurrentModuleObject, Alphas(1)));
817 0 : ShowContinueError(state, "... Did not find zone humidistat");
818 0 : ShowContinueError(state, "... A ZoneControl:Humidistat object must be specified for this zone.");
819 0 : ErrorsFound = true;
820 : }
821 : }
822 : } else {
823 0 : ShowSevereError(state, format("{} \"{}\"", CurrentModuleObject, Alphas(1)));
824 0 : ShowContinueError(state, "... Did not find Air Node (Zone with Humidistat)");
825 0 : ShowContinueError(state, "... A ZoneHVAC:EquipmentConnections object must be specified for this zone.");
826 0 : ErrorsFound = true;
827 : }
828 :
829 1 : if (Numbers(5) <= 0.0 && NumNumbers > 4) {
830 :
831 0 : ShowWarningError(state, format("{} \"{}\"", CurrentModuleObject, Alphas(1)));
832 0 : ShowContinueError(state, format("... {} must be greater than 0.", cNumericFields(5)));
833 0 : ShowContinueError(state, format("... {} is reset to 1 and the simulation continues.", cNumericFields(5)));
834 :
835 0 : HighRHOARatio = 1.0;
836 :
837 1 : } else if (NumNumbers > 4) {
838 :
839 1 : HighRHOARatio = Numbers(5);
840 :
841 : } else {
842 :
843 0 : HighRHOARatio = 1.0;
844 : }
845 :
846 1 : if (Util::SameString(Alphas(8), "Yes")) {
847 1 : thisOAController.ModifyDuringHighOAMoisture = false;
848 : } else {
849 0 : thisOAController.ModifyDuringHighOAMoisture = true;
850 : }
851 :
852 103 : } else if (!Util::SameString(Alphas(6), "No") && NumAlphas > 4 && (!lAlphaBlanks(5))) {
853 0 : ShowWarningError(state, format("{} \"{}\"", CurrentModuleObject, Alphas(1)));
854 0 : ShowContinueError(state, format("... Invalid {} = {}", cAlphaFields(6), Alphas(6)));
855 0 : ShowContinueError(state, format("... {} is assumed to be \"No\" and the simulation continues.", cAlphaFields(6)));
856 : } // IF(Util::SameString(Alphas(6),'Yes'))THEN
857 :
858 104 : thisOAController.HighRHOAFlowRatio = HighRHOARatio;
859 104 : if (WhichERV != 0) {
860 104 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).HighRHOAFlowRatio = HighRHOARatio;
861 : }
862 :
863 : // Check for a time of day outside air schedule
864 104 : thisOAController.economizerOASched = Sched::GetSchedule(state, Alphas(5));
865 :
866 104 : if (WhichERV != 0) {
867 104 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).economizerOASched = Sched::GetSchedule(state, Alphas(5));
868 :
869 : // Compare the ERV SA fan flow rates to modified air flow rate.
870 105 : if (HighRHOARatio > 1.0 && state.dataHVACStandAloneERV->StandAloneERV(WhichERV).SupplyAirVolFlow != DataSizing::AutoSize &&
871 1 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).DesignSAFanVolFlowRate != DataSizing::AutoSize) {
872 1 : if (state.dataHVACStandAloneERV->StandAloneERV(WhichERV).SupplyAirVolFlow * HighRHOARatio >
873 1 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).DesignSAFanVolFlowRate) {
874 0 : ShowWarningError(state, format("{} \"{}\"", CurrentModuleObject, Alphas(1)));
875 0 : ShowContinueError(state, format("... A {} was entered as {:.4R}", cNumericFields(5), HighRHOARatio));
876 0 : ShowContinueError(state,
877 : "... This flow ratio results in a Supply Air Volume Flow Rate through the ERV which is greater than the "
878 : "Max Volume specified in the supply air fan object.");
879 0 : ShowContinueError(state,
880 0 : format("... Associated fan object = {} \"{}\"",
881 0 : HVAC::fanTypeNames[(int)state.dataHVACStandAloneERV->StandAloneERV(WhichERV).supplyAirFanType],
882 0 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).SupplyAirFanName));
883 0 : ShowContinueError(state,
884 0 : format("... Modified value = {:.2R}",
885 0 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).SupplyAirVolFlow * HighRHOARatio));
886 0 : ShowContinueError(state,
887 0 : format(" ... Supply Fan Max Volume Flow Rate = {:.2R}",
888 0 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).DesignSAFanVolFlowRate));
889 0 : ShowContinueError(state, "... The ERV supply air fan will limit the air flow through the ERV and the simulation continues.");
890 : }
891 : }
892 :
893 : // Compare the ERV EA fan flow rates to modified air flow rate.
894 105 : if (HighRHOARatio > 1.0 && state.dataHVACStandAloneERV->StandAloneERV(WhichERV).ExhaustAirVolFlow != DataSizing::AutoSize &&
895 1 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).DesignEAFanVolFlowRate != DataSizing::AutoSize) {
896 1 : if (state.dataHVACStandAloneERV->StandAloneERV(WhichERV).ExhaustAirVolFlow * HighRHOARatio >
897 1 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).DesignEAFanVolFlowRate) {
898 0 : ShowWarningError(state, format("ZoneHVAC:EnergyRecoveryVentilator:Controller \"{}\"", Alphas(1)));
899 0 : ShowContinueError(state, format("... A {} was entered as {:.4R}", cNumericFields(5), HighRHOARatio));
900 0 : ShowContinueError(state,
901 : "... This flow ratio results in an Exhaust Air Volume Flow Rate through the ERV which is greater than the "
902 : "Max Volume specified in the exhaust air fan object.");
903 0 : ShowContinueError(state,
904 0 : format("... Associated fan object = {} \"{}\"",
905 0 : HVAC::fanTypeNames[(int)state.dataHVACStandAloneERV->StandAloneERV(WhichERV).exhaustAirFanType],
906 0 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).ExhaustAirFanName));
907 0 : ShowContinueError(state,
908 0 : format("... Modified value = {:.2R}",
909 0 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).ExhaustAirVolFlow * HighRHOARatio));
910 0 : ShowContinueError(state,
911 0 : format(" ... Exhaust Fan Max Volume Flow Rate = {:.2R}",
912 0 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).DesignEAFanVolFlowRate));
913 0 : ShowContinueError(state, "... The ERV exhaust air fan will limit the air flow through the ERV and the simulation continues.");
914 : }
915 : }
916 : } // IF(WhichERV /= 0)THEN
917 : }
918 :
919 5 : if (ErrorsFound) {
920 0 : ShowFatalError(state, "Errors found in getting ZoneHVAC:EnergyRecoveryVentilator input.");
921 : }
922 :
923 : // Setup report variables for the stand alone ERVs
924 112 : for (int StandAloneERVIndex = 1; StandAloneERVIndex <= state.dataHVACStandAloneERV->NumStandAloneERVs; ++StandAloneERVIndex) {
925 107 : auto &standAloneERV = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVIndex);
926 214 : SetupOutputVariable(state,
927 : "Zone Ventilator Sensible Cooling Rate",
928 : Constant::Units::W,
929 107 : standAloneERV.SensCoolingRate,
930 : OutputProcessor::TimeStepType::System,
931 : OutputProcessor::StoreType::Average,
932 107 : standAloneERV.Name);
933 214 : SetupOutputVariable(state,
934 : "Zone Ventilator Sensible Cooling Energy",
935 : Constant::Units::J,
936 107 : standAloneERV.SensCoolingEnergy,
937 : OutputProcessor::TimeStepType::System,
938 : OutputProcessor::StoreType::Sum,
939 107 : standAloneERV.Name);
940 214 : SetupOutputVariable(state,
941 : "Zone Ventilator Latent Cooling Rate",
942 : Constant::Units::W,
943 107 : standAloneERV.LatCoolingRate,
944 : OutputProcessor::TimeStepType::System,
945 : OutputProcessor::StoreType::Average,
946 107 : standAloneERV.Name);
947 214 : SetupOutputVariable(state,
948 : "Zone Ventilator Latent Cooling Energy",
949 : Constant::Units::J,
950 107 : standAloneERV.LatCoolingEnergy,
951 : OutputProcessor::TimeStepType::System,
952 : OutputProcessor::StoreType::Sum,
953 107 : standAloneERV.Name);
954 214 : SetupOutputVariable(state,
955 : "Zone Ventilator Total Cooling Rate",
956 : Constant::Units::W,
957 107 : standAloneERV.TotCoolingRate,
958 : OutputProcessor::TimeStepType::System,
959 : OutputProcessor::StoreType::Average,
960 107 : standAloneERV.Name);
961 214 : SetupOutputVariable(state,
962 : "Zone Ventilator Total Cooling Energy",
963 : Constant::Units::J,
964 107 : standAloneERV.TotCoolingEnergy,
965 : OutputProcessor::TimeStepType::System,
966 : OutputProcessor::StoreType::Sum,
967 107 : standAloneERV.Name);
968 :
969 214 : SetupOutputVariable(state,
970 : "Zone Ventilator Sensible Heating Rate",
971 : Constant::Units::W,
972 107 : standAloneERV.SensHeatingRate,
973 : OutputProcessor::TimeStepType::System,
974 : OutputProcessor::StoreType::Average,
975 107 : standAloneERV.Name);
976 214 : SetupOutputVariable(state,
977 : "Zone Ventilator Sensible Heating Energy",
978 : Constant::Units::J,
979 107 : standAloneERV.SensHeatingEnergy,
980 : OutputProcessor::TimeStepType::System,
981 : OutputProcessor::StoreType::Sum,
982 107 : standAloneERV.Name);
983 214 : SetupOutputVariable(state,
984 : "Zone Ventilator Latent Heating Rate",
985 : Constant::Units::W,
986 107 : standAloneERV.LatHeatingRate,
987 : OutputProcessor::TimeStepType::System,
988 : OutputProcessor::StoreType::Average,
989 107 : standAloneERV.Name);
990 214 : SetupOutputVariable(state,
991 : "Zone Ventilator Latent Heating Energy",
992 : Constant::Units::J,
993 107 : standAloneERV.LatHeatingEnergy,
994 : OutputProcessor::TimeStepType::System,
995 : OutputProcessor::StoreType::Sum,
996 107 : standAloneERV.Name);
997 214 : SetupOutputVariable(state,
998 : "Zone Ventilator Total Heating Rate",
999 : Constant::Units::W,
1000 107 : standAloneERV.TotHeatingRate,
1001 : OutputProcessor::TimeStepType::System,
1002 : OutputProcessor::StoreType::Average,
1003 107 : standAloneERV.Name);
1004 214 : SetupOutputVariable(state,
1005 : "Zone Ventilator Total Heating Energy",
1006 : Constant::Units::J,
1007 107 : standAloneERV.TotHeatingEnergy,
1008 : OutputProcessor::TimeStepType::System,
1009 : OutputProcessor::StoreType::Sum,
1010 107 : standAloneERV.Name);
1011 :
1012 214 : SetupOutputVariable(state,
1013 : "Zone Ventilator Electricity Rate",
1014 : Constant::Units::W,
1015 107 : standAloneERV.ElecUseRate,
1016 : OutputProcessor::TimeStepType::System,
1017 : OutputProcessor::StoreType::Average,
1018 107 : standAloneERV.Name);
1019 214 : SetupOutputVariable(state,
1020 : "Zone Ventilator Electricity Energy",
1021 : Constant::Units::J,
1022 107 : standAloneERV.ElecUseEnergy,
1023 : OutputProcessor::TimeStepType::System,
1024 : OutputProcessor::StoreType::Sum,
1025 107 : standAloneERV.Name);
1026 107 : SetupOutputVariable(state,
1027 : "Zone Ventilator Supply Fan Availability Status",
1028 : Constant::Units::None,
1029 107 : (int &)standAloneERV.availStatus,
1030 : OutputProcessor::TimeStepType::System,
1031 : OutputProcessor::StoreType::Average,
1032 107 : standAloneERV.Name);
1033 : }
1034 :
1035 5 : Alphas.deallocate();
1036 5 : Numbers.deallocate();
1037 5 : cAlphaFields.deallocate();
1038 5 : cNumericFields.deallocate();
1039 5 : lNumericBlanks.deallocate();
1040 5 : lAlphaBlanks.deallocate();
1041 5 : }
1042 :
1043 653192 : void InitStandAloneERV(EnergyPlusData &state,
1044 : int const StandAloneERVNum, // number of the current Stand Alone ERV unit being simulated
1045 : int const ZoneNum, // number of zone being served unused1208
1046 : bool const FirstHVACIteration // TRUE if first HVAC iteration
1047 : )
1048 : {
1049 :
1050 : // SUBROUTINE INFORMATION:
1051 : // AUTHOR Richard Raustad, FSEC
1052 : // DATE WRITTEN June 2003
1053 : // MODIFIED July 2012, Chandan Sharma - FSEC: Added zone sys avail managers
1054 :
1055 : // PURPOSE OF THIS SUBROUTINE:
1056 : // This subroutine is for initializations of the Stand Alone ERV unit information.
1057 :
1058 : // METHODOLOGY EMPLOYED:
1059 : // Uses the status flags to trigger initializations.
1060 :
1061 : // Do the one time initializations
1062 653192 : if (state.dataHVACStandAloneERV->MyOneTimeFlag) {
1063 :
1064 5 : state.dataHVACStandAloneERV->MyEnvrnFlag.allocate(state.dataHVACStandAloneERV->NumStandAloneERVs);
1065 5 : state.dataHVACStandAloneERV->MySizeFlag_InitStandAloneERV.allocate(state.dataHVACStandAloneERV->NumStandAloneERVs);
1066 5 : state.dataHVACStandAloneERV->MyZoneEqFlag.allocate(state.dataHVACStandAloneERV->NumStandAloneERVs);
1067 5 : state.dataHVACStandAloneERV->MyEnvrnFlag = true;
1068 5 : state.dataHVACStandAloneERV->MySizeFlag_InitStandAloneERV = true;
1069 5 : state.dataHVACStandAloneERV->MyZoneEqFlag = true;
1070 5 : state.dataHVACStandAloneERV->MyOneTimeFlag = false;
1071 : }
1072 :
1073 653192 : if (allocated(state.dataAvail->ZoneComp)) {
1074 653169 : auto &availMgr = state.dataAvail->ZoneComp(DataZoneEquipment::ZoneEquipType::EnergyRecoveryVentilator).ZoneCompAvailMgrs(StandAloneERVNum);
1075 653169 : if (state.dataHVACStandAloneERV->MyZoneEqFlag(StandAloneERVNum)) { // initialize the name of each availability manager list and zone number
1076 107 : availMgr.AvailManagerListName = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).AvailManagerListName;
1077 107 : availMgr.ZoneNum = ZoneNum;
1078 107 : state.dataHVACStandAloneERV->MyZoneEqFlag(StandAloneERVNum) = false;
1079 : }
1080 653169 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).availStatus = availMgr.availStatus;
1081 : }
1082 :
1083 : // need to check all units to see if they are on Zone Equipment List or issue warning
1084 653192 : if (!state.dataHVACStandAloneERV->ZoneEquipmentListChecked && state.dataZoneEquip->ZoneEquipInputsFilled) {
1085 5 : state.dataHVACStandAloneERV->ZoneEquipmentListChecked = true;
1086 112 : for (int Loop = 1; Loop <= state.dataHVACStandAloneERV->NumStandAloneERVs; ++Loop) {
1087 214 : if (DataZoneEquipment::CheckZoneEquipmentList(
1088 107 : state, state.dataHVACStandAloneERV->StandAloneERV(Loop).UnitType, state.dataHVACStandAloneERV->StandAloneERV(Loop).Name)) {
1089 107 : continue;
1090 : }
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 653192 : 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 653192 : 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 653192 : if (!state.dataGlobal->BeginEnvrnFlag) {
1136 649422 : state.dataHVACStandAloneERV->MyEnvrnFlag(StandAloneERVNum) = true;
1137 : }
1138 :
1139 : // These initializations are done every iteration
1140 653192 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ElecUseRate = 0.0;
1141 653192 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SensCoolingRate = 0.0;
1142 653192 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).LatCoolingRate = 0.0;
1143 653192 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).TotCoolingRate = 0.0;
1144 653192 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SensHeatingRate = 0.0;
1145 653192 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).LatHeatingRate = 0.0;
1146 653192 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).TotHeatingRate = 0.0;
1147 653192 : int SupInNode = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirInletNode;
1148 653192 : int ExhInNode = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirInletNode;
1149 653192 : auto &supInNode = state.dataLoopNodes->Node(SupInNode);
1150 653192 : auto &exhInNode = state.dataLoopNodes->Node(ExhInNode);
1151 :
1152 : // Set the inlet node mass flow rate
1153 653192 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).availSched->getCurrentVal() > 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 (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).supplyAirFanSched->getCurrentVal() > 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 (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).exhaustAirFanSched->getCurrentVal() > 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 6102 : supInNode.MassFlowRate = 0.0;
1210 6102 : supInNode.MassFlowRateMaxAvail = 0.0;
1211 6102 : supInNode.MassFlowRateMinAvail = 0.0;
1212 6102 : exhInNode.MassFlowRate = 0.0;
1213 6102 : exhInNode.MassFlowRateMaxAvail = 0.0;
1214 6102 : exhInNode.MassFlowRateMinAvail = 0.0;
1215 : }
1216 653192 : }
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) {
1262 6776 : continue;
1263 : }
1264 107 : MaxPeopleSch = state.dataHeatBal->People(PeopleNum).sched->getMaxVal(state);
1265 107 : NumberOfPeople = NumberOfPeople + (state.dataHeatBal->People(PeopleNum).NumberOfPeople * MaxPeopleSch);
1266 : }
1267 107 : SupplyAirVolFlowDes = FloorArea * state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).AirVolFlowPerFloorArea +
1268 107 : NumberOfPeople * state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).AirVolFlowPerOccupant;
1269 107 : SupplyAirVolFlowDes = ZoneMult * SupplyAirVolFlowDes;
1270 :
1271 107 : if (SupplyAirVolFlowDes < HVAC::SmallAirVolFlow) {
1272 107 : SupplyAirVolFlowDes = 0.0;
1273 : }
1274 :
1275 : // Size ERV supply flow rate
1276 107 : Real64 TempSize = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirVolFlow;
1277 107 : if (IsAutoSize) {
1278 0 : state.dataSize->DataConstantUsedForSizing = SupplyAirVolFlowDes;
1279 0 : state.dataSize->DataFractionUsedForSizing = 1.0;
1280 0 : TempSize = SupplyAirVolFlowDes;
1281 0 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerNameDefined) {
1282 0 : state.dataMixedAir->OAController(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerIndex).MaxOA =
1283 0 : SupplyAirVolFlowDes * state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).HighRHOAFlowRatio;
1284 0 : state.dataMixedAir->OAController(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerIndex).MinOA =
1285 : SupplyAirVolFlowDes;
1286 : }
1287 : } else {
1288 107 : state.dataSize->DataConstantUsedForSizing = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirVolFlow;
1289 107 : state.dataSize->DataFractionUsedForSizing = 1.0;
1290 : }
1291 107 : if (TempSize > 0.0) {
1292 107 : std::string SizingString = "Supply Air Flow Rate [m3/s]";
1293 107 : SystemAirFlowSizer sizerSystemAirFlow;
1294 107 : sizerSystemAirFlow.overrideSizingString(SizingString);
1295 107 : sizerSystemAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1296 107 : TempSize = sizerSystemAirFlow.size(state, TempSize, ErrorsFound);
1297 107 : }
1298 107 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirVolFlow = TempSize;
1299 : }
1300 :
1301 : // Size ERV exhaust flow rate
1302 107 : state.dataSize->DataFractionUsedForSizing = 1.0;
1303 107 : IsAutoSize = false;
1304 107 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirVolFlow == DataSizing::AutoSize) {
1305 0 : IsAutoSize = true;
1306 : }
1307 :
1308 107 : if (state.dataSize->CurZoneEqNum > 0) {
1309 :
1310 107 : ExhaustAirVolFlowDes = SupplyAirVolFlowDes;
1311 :
1312 107 : if (ExhaustAirVolFlowDes < HVAC::SmallAirVolFlow) {
1313 107 : ExhaustAirVolFlowDes = 0.0;
1314 : }
1315 :
1316 107 : if (ExhaustAirVolFlowDes > state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirVolFlow) {
1317 0 : ExhaustAirVolFlowDes = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirVolFlow;
1318 : }
1319 :
1320 107 : Real64 TempSize = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirVolFlow;
1321 107 : if (IsAutoSize) {
1322 0 : TempSize = ExhaustAirVolFlowDes;
1323 0 : state.dataSize->DataConstantUsedForSizing = ExhaustAirVolFlowDes;
1324 : } else {
1325 107 : state.dataSize->DataConstantUsedForSizing = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirVolFlow;
1326 : }
1327 107 : state.dataSize->DataFractionUsedForSizing = 1.0;
1328 107 : if (TempSize > 0.0) {
1329 107 : std::string SizingString = "Exhaust Air Flow Rate [m3/s]";
1330 107 : SystemAirFlowSizer sizerSystemAirFlow;
1331 107 : sizerSystemAirFlow.overrideSizingString(SizingString);
1332 107 : sizerSystemAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1333 107 : TempSize = sizerSystemAirFlow.size(state, TempSize, ErrorsFound);
1334 107 : }
1335 107 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirVolFlow = TempSize;
1336 107 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignEAFanVolFlowRate =
1337 107 : TempSize * state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).HighRHOAFlowRatio;
1338 : }
1339 :
1340 : // Set Zone equipment sizing data for autosizing the fans and heat exchanger
1341 107 : zoneEqSizing.AirVolFlow = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirVolFlow *
1342 107 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).HighRHOAFlowRatio;
1343 107 : zoneEqSizing.OAVolFlow = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirVolFlow;
1344 107 : zoneEqSizing.SystemAirFlow = true;
1345 107 : zoneEqSizing.DesignSizeFromParent = true;
1346 :
1347 : // Check supply fan flow rate or set flow rate if autosized in fan object
1348 107 : IsAutoSize = false;
1349 107 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignSAFanVolFlowRate == DataSizing::AutoSize) {
1350 102 : IsAutoSize = true;
1351 : }
1352 107 : DesignSAFanVolFlowRateDes = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirVolFlow *
1353 107 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).HighRHOAFlowRatio;
1354 107 : if (IsAutoSize) {
1355 102 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignSAFanVolFlowRate = DesignSAFanVolFlowRateDes;
1356 : } else {
1357 5 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignSAFanVolFlowRate > 0.0 && DesignSAFanVolFlowRateDes > 0.0) {
1358 5 : DesignSAFanVolFlowRateUser = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignSAFanVolFlowRate;
1359 5 : if (state.dataGlobal->DisplayExtraWarnings) {
1360 0 : if ((std::abs(DesignSAFanVolFlowRateDes - DesignSAFanVolFlowRateUser) / DesignSAFanVolFlowRateUser) >
1361 0 : state.dataSize->AutoVsHardSizingThreshold) {
1362 0 : ShowMessage(state,
1363 0 : format("SizeStandAloneERV: Potential issue with equipment sizing for ZoneHVAC:EnergyRecoveryVentilator {} {}",
1364 0 : HVAC::fanTypeNames[(int)state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).supplyAirFanType],
1365 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirFanName));
1366 0 : ShowContinueError(state, format("User-Specified Supply Fan Maximum Flow Rate of {:.5R} [m3/s]", DesignSAFanVolFlowRateUser));
1367 0 : ShowContinueError(state, format("differs from the ERV Supply Air Flow Rate of {:.5R} [m3/s]", DesignSAFanVolFlowRateDes));
1368 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1369 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1370 : }
1371 : }
1372 : }
1373 : }
1374 :
1375 : // simulate the fan to size using the flow rate specified above
1376 : // (i.e., ZoneEqSizing( CurZoneEqNum ).AirVolFlow = StandAloneERV( StandAloneERVNum ).SupplyAirVolFlow * StandAloneERV( StandAloneERVNum
1377 : // ).HighRHOAFlowRatio;)
1378 107 : state.dataFans->fans(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirFanIndex)->simulate(state, true, _, _);
1379 :
1380 107 : state.dataFans->fans(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirFanIndex)->simulate(state, true, _, _);
1381 :
1382 : // now reset the ZoneEqSizing variable to NOT use the multiplier for HighRHOAFlowRatio for sizing HXs
1383 107 : zoneEqSizing.AirVolFlow = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirVolFlow;
1384 107 : }
1385 :
1386 653192 : void CalcStandAloneERV(EnergyPlusData &state,
1387 : int const StandAloneERVNum, // Unit index in ERV data structure
1388 : bool const FirstHVACIteration, // flag for 1st HVAC iteration in the time step
1389 : Real64 &SensLoadMet, // sensible zone load met by unit (W)
1390 : Real64 &LatentMassLoadMet // latent zone load met by unit (kg/s), dehumid = negative
1391 : )
1392 : {
1393 :
1394 : // SUBROUTINE INFORMATION:
1395 : // AUTHOR Richard Raustad, FSEC
1396 : // DATE WRITTEN June 2003
1397 : // MODIFIED Don Shirey, Aug 2009 (LatentMassLoadMet)
1398 : // July 2012, Chandan Sharma - FSEC: Added zone sys avail managers
1399 :
1400 : // PURPOSE OF THIS SUBROUTINE:
1401 : // Simulate the components making up the Stand Alone ERV unit.
1402 :
1403 : // METHODOLOGY EMPLOYED:
1404 : // Simulates the unit components sequentially in the air flow direction.
1405 :
1406 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1407 : Real64 TotLoadMet; // total zone load met by unit (W)
1408 : Real64 LatLoadMet; // latent zone load met by unit (W)
1409 : bool EconomizerFlag; // economizer signal from OA controller
1410 : bool HighHumCtrlFlag; // high humditiy control signal from OA controller
1411 :
1412 653192 : int SupInletNode = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirInletNode;
1413 653192 : int SupOutletNode = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirOutletNode;
1414 653192 : int ExhaustInletNode = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirInletNode;
1415 :
1416 : // Stand alone ERV's HX is ON by default
1417 653192 : bool HXUnitOn = true;
1418 :
1419 : // Get stand alone ERV's controller economizer and high humidity control status
1420 653192 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerNameDefined) {
1421 567323 : EconomizerFlag = state.dataMixedAir->OAController(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerIndex).EconoActive;
1422 567323 : HighHumCtrlFlag =
1423 567323 : state.dataMixedAir->OAController(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerIndex).HighHumCtrlActive;
1424 : } else {
1425 85869 : EconomizerFlag = false;
1426 85869 : HighHumCtrlFlag = false;
1427 : }
1428 :
1429 1306384 : HeatRecovery::SimHeatRecovery(state,
1430 653192 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).HeatExchangerName,
1431 : FirstHVACIteration,
1432 653192 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).HeatExchangerIndex,
1433 : HVAC::FanOp::Continuous,
1434 : _,
1435 : HXUnitOn,
1436 : _,
1437 : _,
1438 : EconomizerFlag,
1439 : HighHumCtrlFlag);
1440 653192 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ElecUseRate = state.dataHVACGlobal->AirToAirHXElecPower;
1441 :
1442 653192 : state.dataFans->fans(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirFanIndex)->simulate(state, FirstHVACIteration, _, _);
1443 653192 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ElecUseRate +=
1444 653192 : state.dataFans->fans(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirFanIndex)->totalPower;
1445 :
1446 653192 : state.dataFans->fans(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirFanIndex)->simulate(state, FirstHVACIteration, _, _);
1447 653192 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ElecUseRate +=
1448 653192 : state.dataFans->fans(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirFanIndex)->totalPower;
1449 :
1450 : // total mass flow through supply side of the ERV (supply air outlet node)
1451 653192 : Real64 AirMassFlow = state.dataLoopNodes->Node(SupOutletNode).MassFlowRate;
1452 2612768 : CalcZoneSensibleLatentOutput(AirMassFlow,
1453 653192 : state.dataLoopNodes->Node(SupOutletNode).Temp,
1454 653192 : state.dataLoopNodes->Node(SupOutletNode).HumRat,
1455 653192 : state.dataLoopNodes->Node(ExhaustInletNode).Temp,
1456 653192 : state.dataLoopNodes->Node(ExhaustInletNode).HumRat,
1457 : SensLoadMet,
1458 : LatLoadMet,
1459 : TotLoadMet);
1460 653192 : LatentMassLoadMet = AirMassFlow * (state.dataLoopNodes->Node(SupOutletNode).HumRat -
1461 653192 : state.dataLoopNodes->Node(ExhaustInletNode).HumRat); // kg/s, dehumidification = negative
1462 :
1463 653192 : if (SensLoadMet < 0.0) {
1464 454606 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SensCoolingRate = std::abs(SensLoadMet);
1465 454606 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SensHeatingRate = 0.0;
1466 : } else {
1467 198586 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SensCoolingRate = 0.0;
1468 198586 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SensHeatingRate = SensLoadMet;
1469 : }
1470 653192 : if (TotLoadMet < 0.0) {
1471 538229 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).TotCoolingRate = std::abs(TotLoadMet);
1472 538229 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).TotHeatingRate = 0.0;
1473 : } else {
1474 114963 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).TotCoolingRate = 0.0;
1475 114963 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).TotHeatingRate = TotLoadMet;
1476 : }
1477 653192 : if (LatLoadMet < 0.0) {
1478 635917 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).LatCoolingRate = std::abs(LatLoadMet);
1479 635917 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).LatHeatingRate = 0.0;
1480 : } else {
1481 17275 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).LatCoolingRate = 0.0;
1482 17275 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).LatHeatingRate = LatLoadMet;
1483 : }
1484 :
1485 : // Provide a one time message when exhaust flow rate is greater than supply flow rate
1486 653192 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).FlowError && !state.dataGlobal->WarmupFlag) {
1487 89697 : Real64 TotalExhaustMassFlow = state.dataLoopNodes->Node(ExhaustInletNode).MassFlowRate;
1488 89697 : Real64 TotalSupplyMassFlow = state.dataLoopNodes->Node(SupInletNode).MassFlowRate;
1489 89697 : if (TotalExhaustMassFlow > TotalSupplyMassFlow && !state.dataHeatBal->ZoneAirMassFlow.EnforceZoneMassBalance) {
1490 0 : ShowWarningError(state,
1491 0 : format("For {} \"{}\" there is unbalanced exhaust air flow.",
1492 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).UnitType,
1493 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).Name));
1494 0 : ShowContinueError(state, format("... The exhaust air mass flow rate = {:.6R}", state.dataLoopNodes->Node(ExhaustInletNode).MassFlowRate));
1495 0 : ShowContinueError(state, format("... The supply air mass flow rate = {:.6R}", state.dataLoopNodes->Node(SupInletNode).MassFlowRate));
1496 0 : ShowContinueErrorTimeStamp(state, "");
1497 0 : ShowContinueError(state, "... Unless there is balancing infiltration / ventilation air flow, this will result in");
1498 0 : ShowContinueError(state, "... load due to induced outside air being neglected in the simulation.");
1499 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).FlowError = false;
1500 : }
1501 : }
1502 653192 : }
1503 :
1504 653192 : void ReportStandAloneERV(EnergyPlusData &state, int const StandAloneERVNum) // number of the current Stand Alone ERV being simulated
1505 : {
1506 :
1507 : // SUBROUTINE INFORMATION:
1508 : // AUTHOR Richard Raustad, FSEC
1509 : // DATE WRITTEN June 2003
1510 :
1511 653192 : Real64 ReportingConstant = state.dataHVACGlobal->TimeStepSysSec;
1512 653192 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ElecUseEnergy =
1513 653192 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ElecUseRate * ReportingConstant;
1514 653192 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SensCoolingEnergy =
1515 653192 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SensCoolingRate * ReportingConstant;
1516 653192 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).LatCoolingEnergy =
1517 653192 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).LatCoolingRate * ReportingConstant;
1518 653192 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).TotCoolingEnergy =
1519 653192 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).TotCoolingRate * ReportingConstant;
1520 653192 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SensHeatingEnergy =
1521 653192 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SensHeatingRate * ReportingConstant;
1522 653192 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).LatHeatingEnergy =
1523 653192 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).LatHeatingRate * ReportingConstant;
1524 653192 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).TotHeatingEnergy =
1525 653192 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).TotHeatingRate * ReportingConstant;
1526 :
1527 653192 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).FirstPass) { // reset sizing flags so other zone equipment can size normally
1528 214 : if (!state.dataGlobal->SysSizingCalc) {
1529 107 : DataSizing::resetHVACSizingGlobals(
1530 107 : state, state.dataSize->CurZoneEqNum, 0, state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).FirstPass);
1531 : }
1532 : }
1533 653192 : }
1534 :
1535 : // Utility subroutines/functions for the HeatingCoil Module
1536 :
1537 0 : Real64 GetSupplyAirFlowRate(EnergyPlusData &state,
1538 : std::string const &ERVType, // must be "ZoneHVAC:EnergyRecoveryVentilator"
1539 : std::string const &ERVCtrlName, // must match a controller name in the ERV data structure
1540 : bool &ErrorsFound // set to true if problem
1541 : )
1542 : {
1543 :
1544 : // FUNCTION INFORMATION:
1545 : // AUTHOR Linda Lawrie
1546 : // DATE WRITTEN October 2006
1547 :
1548 : // PURPOSE OF THIS FUNCTION:
1549 : // This function looks up the ERVCtrlName in the ERV Stand Alone list and returns the
1550 : // Supply Air Flow rate, if found. If incorrect name is given, ErrorsFound is returned as true
1551 : // and supply air flow rate as negative.
1552 :
1553 0 : if (state.dataHVACStandAloneERV->GetERVInputFlag) {
1554 0 : GetStandAloneERV(state);
1555 0 : state.dataHVACStandAloneERV->GetERVInputFlag = false;
1556 : }
1557 :
1558 0 : if (Util::SameString(ERVType, "ZoneHVAC:EnergyRecoveryVentilator")) {
1559 0 : int WhichERV = Util::FindItem(ERVCtrlName, state.dataHVACStandAloneERV->StandAloneERV, &StandAloneERVData::ControllerName);
1560 0 : if (WhichERV != 0) {
1561 0 : return state.dataHVACStandAloneERV->StandAloneERV(WhichERV).SupplyAirVolFlow;
1562 : }
1563 : }
1564 :
1565 0 : ShowSevereError(state, format("Could not find ZoneHVAC:EnergyRecoveryVentilator with Controller Name=\"{}\"", ERVCtrlName));
1566 0 : ErrorsFound = true;
1567 0 : return -1000.0;
1568 : }
1569 :
1570 21418 : int GetStandAloneERVOutAirNode(EnergyPlusData &state, int const StandAloneERVNum)
1571 : {
1572 : // FUNCTION INFORMATION:
1573 : // AUTHOR B Griffith
1574 : // DATE WRITTEN Dec 2006
1575 :
1576 : // PURPOSE OF THIS FUNCTION:
1577 : // lookup function for OA inlet node for ventilation rate reporting
1578 :
1579 21418 : if (state.dataHVACStandAloneERV->GetERVInputFlag) {
1580 0 : GetStandAloneERV(state);
1581 0 : state.dataHVACStandAloneERV->GetERVInputFlag = false;
1582 : }
1583 :
1584 21418 : if (StandAloneERVNum > 0 && StandAloneERVNum <= state.dataHVACStandAloneERV->NumStandAloneERVs) {
1585 21418 : return state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirInletNode;
1586 : }
1587 :
1588 0 : return 0;
1589 : }
1590 :
1591 21418 : int GetStandAloneERVZoneInletAirNode(EnergyPlusData &state, int const StandAloneERVNum)
1592 : {
1593 : // FUNCTION INFORMATION:
1594 : // AUTHOR B Griffith
1595 : // DATE WRITTEN Dec 2006
1596 :
1597 : // PURPOSE OF THIS FUNCTION:
1598 : // lookup function for OA inlet node for ventilation rate reporting
1599 :
1600 21418 : if (state.dataHVACStandAloneERV->GetERVInputFlag) {
1601 0 : GetStandAloneERV(state);
1602 0 : state.dataHVACStandAloneERV->GetERVInputFlag = false;
1603 : }
1604 :
1605 21418 : if (StandAloneERVNum > 0 && StandAloneERVNum <= state.dataHVACStandAloneERV->NumStandAloneERVs) {
1606 21418 : return state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirOutletNode;
1607 : }
1608 :
1609 0 : return 0;
1610 : }
1611 :
1612 21418 : int GetStandAloneERVReturnAirNode(EnergyPlusData &state, int const StandAloneERVNum)
1613 : {
1614 : // FUNCTION INFORMATION:
1615 : // AUTHOR B Griffith
1616 : // DATE WRITTEN Dec 2006
1617 :
1618 : // PURPOSE OF THIS FUNCTION:
1619 : // lookup function for OA inlet node for ventilation rate reporting
1620 :
1621 21418 : if (state.dataHVACStandAloneERV->GetERVInputFlag) {
1622 0 : GetStandAloneERV(state);
1623 0 : state.dataHVACStandAloneERV->GetERVInputFlag = false;
1624 : }
1625 :
1626 21418 : if (StandAloneERVNum > 0 && StandAloneERVNum <= state.dataHVACStandAloneERV->NumStandAloneERVs) {
1627 21418 : return state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirInletNode;
1628 : }
1629 :
1630 0 : return 0;
1631 : }
1632 :
1633 16 : bool GetStandAloneERVNodeNumber(EnergyPlusData &state, int const NodeNumber)
1634 : {
1635 : // PURPOSE OF THIS FUNCTION:
1636 : // Check if a node is used by a stand alone ERV
1637 : // and can be excluded from an airflow network.
1638 :
1639 16 : if (state.dataHVACStandAloneERV->GetERVInputFlag) {
1640 0 : GetStandAloneERV(state);
1641 0 : state.dataHVACStandAloneERV->GetERVInputFlag = false;
1642 : }
1643 :
1644 26 : for (int StandAloneERVIndex = 1; StandAloneERVIndex <= state.dataHVACStandAloneERV->NumStandAloneERVs; ++StandAloneERVIndex) {
1645 :
1646 16 : auto &StandAloneERV = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVIndex);
1647 16 : int SupplyFanInletNodeIndex = 0;
1648 16 : int SupplyFanOutletNodeIndex = 0;
1649 16 : int ExhaustFanInletNodeIndex = 0;
1650 16 : int ExhaustFanOutletNodeIndex = 0;
1651 : Real64 SupplyFanAirFlow;
1652 : Real64 ExhaustFanAirFlow;
1653 :
1654 : // Get supply air fan inlet and outlet node index and air flow
1655 : // ZoneHVAC:EnergyRecoveryVentilator only accepts Fan:SystemModel or Fan:OnOff
1656 16 : SupplyFanInletNodeIndex = state.dataFans->fans(StandAloneERV.SupplyAirFanIndex)->inletNodeNum;
1657 16 : SupplyFanOutletNodeIndex = state.dataFans->fans(StandAloneERV.SupplyAirFanIndex)->outletNodeNum;
1658 16 : SupplyFanAirFlow = state.dataFans->fans(StandAloneERV.SupplyAirFanIndex)->maxAirFlowRate;
1659 :
1660 : // Get exhaust air fan inlet and outlet node index and air flow
1661 16 : ExhaustFanInletNodeIndex = state.dataFans->fans(StandAloneERV.ExhaustAirFanIndex)->inletNodeNum;
1662 16 : ExhaustFanOutletNodeIndex = state.dataFans->fans(StandAloneERV.ExhaustAirFanIndex)->outletNodeNum;
1663 16 : ExhaustFanAirFlow = state.dataFans->fans(StandAloneERV.ExhaustAirFanIndex)->maxAirFlowRate;
1664 :
1665 : // If a standalone ERV's airflow is unbalanced it shouldn't be model along with an AFN
1666 32 : if (std::abs(SupplyFanAirFlow - ExhaustFanAirFlow) >= 1E-20 ||
1667 16 : std::abs(StandAloneERV.DesignSAFanVolFlowRate - StandAloneERV.DesignEAFanVolFlowRate) >= 1E-20) {
1668 0 : break;
1669 : }
1670 :
1671 : // Supply air fan nodes
1672 16 : if (NodeNumber == SupplyFanInletNodeIndex || NodeNumber == SupplyFanOutletNodeIndex || NodeNumber == ExhaustFanInletNodeIndex ||
1673 : NodeNumber == ExhaustFanOutletNodeIndex) {
1674 4 : return true;
1675 : }
1676 :
1677 : // Supply air inlet node
1678 12 : if (NodeNumber == StandAloneERV.SupplyAirInletNode) {
1679 2 : return true;
1680 : }
1681 : }
1682 :
1683 10 : return false;
1684 : }
1685 :
1686 0 : int getEqIndex(EnergyPlusData &state, std::string_view CompName)
1687 : {
1688 0 : if (state.dataHVACStandAloneERV->GetERVInputFlag) {
1689 0 : GetStandAloneERV(state);
1690 0 : state.dataHVACStandAloneERV->GetERVInputFlag = false;
1691 : }
1692 :
1693 0 : for (int StandAloneERVNum = 1; StandAloneERVNum <= state.dataHVACStandAloneERV->NumStandAloneERVs; StandAloneERVNum++) {
1694 0 : if (Util::SameString(CompName, state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).Name)) {
1695 0 : return StandAloneERVNum;
1696 : }
1697 : }
1698 0 : return 0;
1699 : }
1700 :
1701 : } // namespace EnergyPlus::HVACStandAloneERV
|