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 0 : 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 0 : if (state.dataHVACStandAloneERV->GetERVInputFlag) {
122 0 : GetStandAloneERV(state);
123 0 : state.dataHVACStandAloneERV->GetERVInputFlag = false;
124 : }
125 :
126 : // Find the correct Stand Alone ERV unit index
127 0 : if (CompIndex == 0) {
128 0 : StandAloneERVNum = Util::FindItem(CompName, state.dataHVACStandAloneERV->StandAloneERV);
129 0 : if (StandAloneERVNum == 0) {
130 0 : ShowFatalError(state, format("SimStandAloneERV: Unit not found={}", CompName));
131 : }
132 0 : CompIndex = StandAloneERVNum;
133 : } else {
134 0 : StandAloneERVNum = CompIndex;
135 0 : 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 0 : if (state.dataHVACStandAloneERV->CheckEquipName(StandAloneERVNum)) {
143 0 : 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 0 : state.dataHVACStandAloneERV->CheckEquipName(StandAloneERVNum) = false;
151 : }
152 : }
153 :
154 : // Initialize the Stand Alone ERV unit
155 0 : InitStandAloneERV(state, StandAloneERVNum, ZoneNum, FirstHVACIteration);
156 :
157 0 : CalcStandAloneERV(state, StandAloneERVNum, FirstHVACIteration, SensLoadMet, LatLoadMet);
158 :
159 0 : ReportStandAloneERV(state, StandAloneERVNum);
160 0 : }
161 :
162 6 : 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 6 : Array1D_string Alphas; // Alpha items for object
180 6 : Array1D<Real64> Numbers; // Numeric items for object
181 6 : Array1D_string cAlphaFields;
182 6 : Array1D_string cNumericFields;
183 6 : Array1D_bool lAlphaBlanks;
184 6 : 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 6 : 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 6 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "ZoneHVAC:EnergyRecoveryVentilator", NumArg, NumAlphas, NumNumbers);
201 6 : int MaxAlphas = NumAlphas;
202 6 : int MaxNumbers = NumNumbers;
203 6 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
204 : state, "ZoneHVAC:EnergyRecoveryVentilator:Controller", NumArg, NumAlphas, NumNumbers);
205 6 : MaxAlphas = max(MaxAlphas, NumAlphas);
206 6 : MaxNumbers = max(MaxNumbers, NumNumbers);
207 :
208 6 : Alphas.allocate(MaxAlphas);
209 6 : Numbers.dimension(MaxNumbers, 0.0);
210 6 : cAlphaFields.allocate(MaxAlphas);
211 6 : cNumericFields.allocate(MaxNumbers);
212 6 : lNumericBlanks.dimension(MaxNumbers, false);
213 6 : lAlphaBlanks.dimension(MaxAlphas, false);
214 :
215 6 : state.dataHVACStandAloneERV->GetERVInputFlag = false;
216 :
217 : // find the number of each type of Stand Alone ERV unit
218 6 : std::string CurrentModuleObject = "ZoneHVAC:EnergyRecoveryVentilator";
219 :
220 6 : state.dataHVACStandAloneERV->NumStandAloneERVs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
221 :
222 : // allocate the data structures
223 6 : state.dataHVACStandAloneERV->StandAloneERV.allocate(state.dataHVACStandAloneERV->NumStandAloneERVs);
224 6 : state.dataHVACStandAloneERV->HeatExchangerUniqueNames.reserve(static_cast<unsigned>(state.dataHVACStandAloneERV->NumStandAloneERVs));
225 6 : state.dataHVACStandAloneERV->SupplyAirFanUniqueNames.reserve(static_cast<unsigned>(state.dataHVACStandAloneERV->NumStandAloneERVs));
226 6 : state.dataHVACStandAloneERV->ExhaustAirFanUniqueNames.reserve(static_cast<unsigned>(state.dataHVACStandAloneERV->NumStandAloneERVs));
227 6 : state.dataHVACStandAloneERV->ControllerUniqueNames.reserve(static_cast<unsigned>(state.dataHVACStandAloneERV->NumStandAloneERVs));
228 6 : state.dataHVACStandAloneERV->CheckEquipName.dimension(state.dataHVACStandAloneERV->NumStandAloneERVs, true);
229 :
230 : // loop over Stand Alone ERV units; get and load the input data
231 6 : for (int StandAloneERVIndex = 1; StandAloneERVIndex <= state.dataHVACStandAloneERV->NumStandAloneERVs; ++StandAloneERVIndex) {
232 0 : auto &standAloneERV = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVIndex);
233 :
234 0 : 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 0 : standAloneERV.Name = Alphas(1);
248 0 : standAloneERV.UnitType = CurrentModuleObject;
249 :
250 0 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, standAloneERV.Name};
251 :
252 0 : if (lAlphaBlanks(2)) {
253 0 : standAloneERV.availSched = Sched::GetScheduleAlwaysOn(state);
254 0 : } 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 0 : GlobalNames::IntraObjUniquenessCheck(
260 0 : state, Alphas(3), CurrentModuleObject, cAlphaFields(3), state.dataHVACStandAloneERV->HeatExchangerUniqueNames, ErrorsFound);
261 0 : standAloneERV.HeatExchangerName = Alphas(3);
262 0 : bool errFlag = false;
263 0 : standAloneERV.hxType = HeatRecovery::GetHeatExchangerObjectTypeNum(state, standAloneERV.HeatExchangerName, errFlag);
264 0 : if (errFlag) {
265 0 : ShowContinueError(state, format("... occurs in {} \"{}\"", CurrentModuleObject, standAloneERV.Name));
266 0 : ErrorsFound = true;
267 : }
268 :
269 0 : errFlag = false;
270 0 : HXSupAirFlowRate = HeatRecovery::GetSupplyAirFlowRate(state, standAloneERV.HeatExchangerName, errFlag);
271 0 : if (errFlag) {
272 0 : ShowContinueError(state, format("... occurs in {} \"{}\"", CurrentModuleObject, standAloneERV.Name));
273 0 : ErrorsFound = true;
274 : }
275 0 : standAloneERV.DesignHXVolFlowRate = HXSupAirFlowRate;
276 :
277 0 : standAloneERV.SupplyAirFanName = Alphas(4);
278 0 : GlobalNames::IntraObjUniquenessCheck(
279 0 : state, Alphas(4), CurrentModuleObject, cAlphaFields(4), state.dataHVACStandAloneERV->SupplyAirFanUniqueNames, ErrorsFound);
280 :
281 0 : 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 0 : auto *fan = state.dataFans->fans(standAloneERV.SupplyAirFanIndex);
286 0 : standAloneERV.supplyAirFanType = fan->type;
287 0 : standAloneERV.supplyAirFanSched = fan->availSched;
288 0 : standAloneERV.DesignSAFanVolFlowRate = fan->maxAirFlowRate;
289 0 : standAloneERV.SupplyAirOutletNode = fan->outletNodeNum;
290 : }
291 :
292 0 : standAloneERV.ExhaustAirFanName = Alphas(5);
293 0 : GlobalNames::IntraObjUniquenessCheck(
294 0 : state, Alphas(5), CurrentModuleObject, cAlphaFields(5), state.dataHVACStandAloneERV->ExhaustAirFanUniqueNames, ErrorsFound);
295 :
296 0 : 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 0 : auto *fan = state.dataFans->fans(standAloneERV.ExhaustAirFanIndex);
302 0 : standAloneERV.exhaustAirFanType = fan->type;
303 :
304 0 : standAloneERV.exhaustAirFanSched = fan->availSched;
305 0 : standAloneERV.DesignEAFanVolFlowRate = fan->maxAirFlowRate;
306 0 : standAloneERV.ExhaustAirOutletNode = fan->outletNodeNum;
307 : }
308 :
309 0 : errFlag = false;
310 0 : standAloneERV.SupplyAirInletNode = HeatRecovery::GetSupplyInletNode(state, standAloneERV.HeatExchangerName, errFlag);
311 0 : standAloneERV.ExhaustAirInletNode = HeatRecovery::GetSecondaryInletNode(state, standAloneERV.HeatExchangerName, errFlag);
312 0 : if (errFlag) {
313 0 : ShowContinueError(state, format("... occurs in {} ={}", CurrentModuleObject, standAloneERV.Name));
314 0 : ErrorsFound = true;
315 : }
316 0 : standAloneERV.SupplyAirInletNode = GetOnlySingleNode(state,
317 0 : state.dataLoopNodes->NodeID(standAloneERV.SupplyAirInletNode),
318 : ErrorsFound,
319 : DataLoopNode::ConnectionObjectType::ZoneHVACEnergyRecoveryVentilator,
320 0 : Alphas(1),
321 : DataLoopNode::NodeFluidType::Air,
322 : DataLoopNode::ConnectionType::Inlet,
323 : NodeInputManager::CompFluidStream::Primary,
324 : DataLoopNode::ObjectIsParent);
325 0 : standAloneERV.SupplyAirOutletNode = GetOnlySingleNode(state,
326 0 : state.dataLoopNodes->NodeID(standAloneERV.SupplyAirOutletNode),
327 : ErrorsFound,
328 : DataLoopNode::ConnectionObjectType::ZoneHVACEnergyRecoveryVentilator,
329 0 : Alphas(1),
330 : DataLoopNode::NodeFluidType::Air,
331 : DataLoopNode::ConnectionType::Outlet,
332 : NodeInputManager::CompFluidStream::Primary,
333 : DataLoopNode::ObjectIsParent);
334 0 : standAloneERV.ExhaustAirInletNode = GetOnlySingleNode(state,
335 0 : state.dataLoopNodes->NodeID(standAloneERV.ExhaustAirInletNode),
336 : ErrorsFound,
337 : DataLoopNode::ConnectionObjectType::ZoneHVACEnergyRecoveryVentilator,
338 0 : Alphas(1),
339 : DataLoopNode::NodeFluidType::Air,
340 : DataLoopNode::ConnectionType::Inlet,
341 : NodeInputManager::CompFluidStream::Secondary,
342 : DataLoopNode::ObjectIsParent);
343 0 : standAloneERV.ExhaustAirOutletNode = GetOnlySingleNode(state,
344 0 : state.dataLoopNodes->NodeID(standAloneERV.ExhaustAirOutletNode),
345 : ErrorsFound,
346 : DataLoopNode::ConnectionObjectType::ZoneHVACEnergyRecoveryVentilator,
347 0 : 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 0 : 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 0 : bool ZoneInletNodeFound = false;
365 0 : bool ZoneExhaustNodeFound = false;
366 0 : for (int ControlledZoneNum = 1; ControlledZoneNum <= state.dataGlobal->NumOfZones; ++ControlledZoneNum) {
367 0 : if (!ZoneInletNodeFound) {
368 0 : for (NodeNumber = 1; NodeNumber <= state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumInletNodes; ++NodeNumber) {
369 0 : if (state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNode(NodeNumber) == standAloneERV.SupplyAirOutletNode) {
370 0 : ZoneInletNodeFound = true;
371 0 : ZoneInletCZN = ControlledZoneNum;
372 0 : break; // found zone inlet node
373 : }
374 : }
375 : }
376 0 : if (!ZoneExhaustNodeFound) {
377 0 : for (NodeNumber = 1; NodeNumber <= state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumExhaustNodes; ++NodeNumber) {
378 0 : if (state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ExhaustNode(NodeNumber) == standAloneERV.ExhaustAirInletNode) {
379 0 : ZoneExhaustNodeFound = true;
380 0 : ZoneExhaustCZN = ControlledZoneNum;
381 0 : break; // found zone exhaust node
382 : }
383 : }
384 : }
385 : }
386 0 : 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 0 : 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 0 : if (ZoneInletNodeFound && ZoneExhaustNodeFound) {
400 0 : 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 0 : standAloneERV.ControllerName = Alphas(6);
416 : // If controller name is blank the ERV unit will operate with no controller
417 0 : if (lAlphaBlanks(6)) {
418 0 : standAloneERV.ControllerName = "xxxxx";
419 0 : standAloneERV.ControllerNameDefined = false;
420 : } else {
421 : // Verify controller name in Stand Alone ERV object matches name of valid controller object
422 0 : GlobalNames::IntraObjUniquenessCheck(
423 0 : state, Alphas(6), CurrentModuleObject, cAlphaFields(6), state.dataHVACStandAloneERV->ControllerUniqueNames, ErrorsFound);
424 0 : standAloneERV.ControllerNameDefined = true;
425 0 : if (ErrorsFound) {
426 0 : standAloneERV.ControllerNameDefined = false;
427 : }
428 :
429 0 : if (state.dataInputProcessing->inputProcessor->getObjectItemNum(
430 0 : 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 0 : if (!lAlphaBlanks(7)) {
439 0 : standAloneERV.AvailManagerListName = Alphas(7);
440 : }
441 :
442 : // Read supply and exhaust air flow rates
443 0 : standAloneERV.SupplyAirVolFlow = Numbers(1);
444 0 : standAloneERV.ExhaustAirVolFlow = Numbers(2);
445 :
446 : // Read ventilation rate per floor area for autosizing HX and fans
447 0 : standAloneERV.AirVolFlowPerFloorArea = Numbers(3);
448 0 : standAloneERV.AirVolFlowPerOccupant = Numbers(4);
449 :
450 0 : 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 0 : 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 0 : 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 0 : 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 0 : if (standAloneERV.DesignSAFanVolFlowRate != DataSizing::AutoSize && standAloneERV.SupplyAirVolFlow != DataSizing::AutoSize) {
486 0 : 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 0 : if (standAloneERV.SupplyAirVolFlow != DataSizing::AutoSize) {
504 0 : 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 0 : if (standAloneERV.DesignEAFanVolFlowRate != DataSizing::AutoSize && standAloneERV.ExhaustAirVolFlow != DataSizing::AutoSize) {
528 0 : 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 0 : if (standAloneERV.ExhaustAirVolFlow != DataSizing::AutoSize) {
546 0 : 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 0 : std::string CompSetSupplyFanInlet = "UNDEFINED";
569 0 : std::string CompSetSupplyFanOutlet = state.dataLoopNodes->NodeID(standAloneERV.SupplyAirOutletNode);
570 :
571 : // Add exhaust fan to component sets array
572 0 : std::string CompSetExhaustFanInlet = "UNDEFINED";
573 0 : std::string CompSetExhaustFanOutlet = state.dataLoopNodes->NodeID(standAloneERV.ExhaustAirOutletNode);
574 :
575 : // Add HX to component sets array
576 0 : BranchNodeConnections::SetUpCompSets(
577 : state, standAloneERV.UnitType, standAloneERV.Name, "UNDEFINED", standAloneERV.HeatExchangerName, "UNDEFINED", "UNDEFINED");
578 :
579 : // Add supply fan to component sets array
580 0 : 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 0 : 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 0 : if (state.dataInputProcessing->inputProcessor->getObjectItemNum(
599 0 : 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 0 : if (standAloneERV.supplyAirFanType != HVAC::FanType::SystemModel) {
608 0 : 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 0 : 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 0 : if (standAloneERV.exhaustAirFanType != HVAC::FanType::SystemModel) {
622 0 : 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 0 : 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 0 : }
634 :
635 6 : int OutAirNum = 0;
636 6 : CurrentModuleObject = "ZoneHVAC:EnergyRecoveryVentilator:Controller";
637 6 : NumERVCtrlrs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
638 :
639 6 : for (ERVControllerNum = 1; ERVControllerNum <= NumERVCtrlrs; ++ERVControllerNum) {
640 0 : 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 0 : MixedAir::CheckOAControllerName(state, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
653 0 : ++OutAirNum;
654 0 : auto &thisOAController = state.dataMixedAir->OAController(OutAirNum);
655 :
656 0 : thisOAController.Name = Alphas(1);
657 0 : thisOAController.ControllerType = MixedAir::MixedAirControllerType::ControllerStandAloneERV;
658 0 : int WhichERV = Util::FindItemInList(Alphas(1), state.dataHVACStandAloneERV->StandAloneERV, &StandAloneERVData::ControllerName);
659 0 : if (WhichERV != 0) {
660 0 : AirFlowRate = state.dataHVACStandAloneERV->StandAloneERV(WhichERV).SupplyAirVolFlow;
661 0 : 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 0 : thisOAController.MaxOA = AirFlowRate;
669 0 : thisOAController.MinOA = AirFlowRate;
670 : // OAController(OutAirNum)%TempLim = Numbers(1)
671 0 : if (lNumericBlanks(1)) {
672 0 : thisOAController.TempLim = HVAC::BlankNumeric;
673 : } else {
674 0 : thisOAController.TempLim = Numbers(1);
675 : }
676 : // OAController(OutAirNum)%TempLowLim = Numbers(2)
677 0 : if (lNumericBlanks(2)) {
678 0 : thisOAController.TempLowLim = HVAC::BlankNumeric;
679 : } else {
680 0 : thisOAController.TempLowLim = Numbers(2);
681 : }
682 : // OAController(OutAirNum)%EnthLim = Numbers(3)
683 0 : if (lNumericBlanks(3)) {
684 0 : thisOAController.EnthLim = HVAC::BlankNumeric;
685 : } else {
686 0 : thisOAController.EnthLim = Numbers(3);
687 : }
688 : // OAController(OutAirNum)%DPTempLim = Numbers(4)
689 0 : if (lNumericBlanks(4)) {
690 0 : thisOAController.DPTempLim = HVAC::BlankNumeric;
691 : } else {
692 0 : thisOAController.DPTempLim = Numbers(4);
693 : }
694 :
695 0 : if (WhichERV != 0) {
696 0 : NodeNumber = state.dataHVACStandAloneERV->StandAloneERV(WhichERV).SupplyAirInletNode;
697 : } else {
698 0 : NodeNumber = 0;
699 : }
700 0 : 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 0 : thisOAController.InletNode = NodeNumber;
704 :
705 0 : if (WhichERV != 0) {
706 0 : NodeNumber = state.dataHVACStandAloneERV->StandAloneERV(WhichERV).ExhaustAirInletNode;
707 : } else {
708 0 : NodeNumber = 0;
709 : }
710 0 : thisOAController.RetNode = NodeNumber;
711 :
712 0 : if (!lAlphaBlanks(2)) {
713 0 : thisOAController.EnthalpyCurvePtr = Curve::GetCurveIndex(state, Alphas(2));
714 0 : 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 0 : 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 0 : cAlphaFields(2)); // Field Name
727 : }
728 : }
729 :
730 : // Changed by AMIT for new implementation of the controller:outside air
731 0 : if (Alphas(3) == "EXHAUSTAIRTEMPERATURELIMIT" && Alphas(4) == "EXHAUSTAIRENTHALPYLIMIT") {
732 0 : thisOAController.Econo = MixedAir::EconoOp::DifferentialDryBulbAndEnthalpy;
733 0 : } else if (Alphas(3) == "EXHAUSTAIRTEMPERATURELIMIT" && Alphas(4) == "NOEXHAUSTAIRENTHALPYLIMIT") {
734 0 : thisOAController.Econo = MixedAir::EconoOp::DifferentialDryBulb;
735 0 : } else if (Alphas(3) == "NOEXHAUSTAIRTEMPERATURELIMIT" && Alphas(4) == "EXHAUSTAIRENTHALPYLIMIT") {
736 0 : thisOAController.Econo = MixedAir::EconoOp::DifferentialEnthalpy;
737 0 : } else if (Alphas(3) == "NOEXHAUSTAIRTEMPERATURELIMIT" && Alphas(4) == "NOEXHAUSTAIRENTHALPYLIMIT") {
738 0 : 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 0 : 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 0 : thisOAController.FixedMin = false;
781 0 : thisOAController.EconBypass = true;
782 :
783 : // Initialize to one in case high humidity control is NOT used
784 0 : Real64 HighRHOARatio = 1.0;
785 : // READ Modify Air Flow Data
786 : // High humidity control option is YES, read in additional data
787 0 : if (Util::SameString(Alphas(6), "Yes")) {
788 :
789 0 : HStatZoneNum = Util::FindItemInList(Alphas(7), state.dataHeatBal->Zone);
790 0 : thisOAController.HumidistatZoneNum = HStatZoneNum;
791 :
792 : // Get the node number for the zone with the humidistat
793 0 : if (HStatZoneNum > 0) {
794 0 : bool ZoneNodeFound = false;
795 0 : if (state.dataZoneEquip->ZoneEquipConfig(HStatZoneNum).IsControlled) {
796 : // Find the controlled zone number for the specified humidistat location
797 0 : thisOAController.NodeNumofHumidistatZone = state.dataZoneEquip->ZoneEquipConfig(HStatZoneNum).ZoneNode;
798 0 : ZoneNodeFound = true;
799 : }
800 0 : 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 0 : bool HStatFound = false;
808 0 : for (NumHstatZone = 1; NumHstatZone <= state.dataZoneCtrls->NumHumidityControlZones; ++NumHstatZone) {
809 0 : if (state.dataZoneCtrls->HumidityControlZone(NumHstatZone).ActualZoneNum != HStatZoneNum) continue;
810 0 : HStatFound = true;
811 0 : break;
812 : }
813 0 : if (!HStatFound) {
814 0 : ShowSevereError(state, format("{} \"{}\"", CurrentModuleObject, Alphas(1)));
815 0 : ShowContinueError(state, "... Did not find zone humidistat");
816 0 : ShowContinueError(state, "... A ZoneControl:Humidistat object must be specified for this zone.");
817 0 : ErrorsFound = true;
818 : }
819 : }
820 : } else {
821 0 : ShowSevereError(state, format("{} \"{}\"", CurrentModuleObject, Alphas(1)));
822 0 : ShowContinueError(state, "... Did not find Air Node (Zone with Humidistat)");
823 0 : ShowContinueError(state, "... A ZoneHVAC:EquipmentConnections object must be specified for this zone.");
824 0 : ErrorsFound = true;
825 : }
826 :
827 0 : if (Numbers(5) <= 0.0 && NumNumbers > 4) {
828 :
829 0 : ShowWarningError(state, format("{} \"{}\"", CurrentModuleObject, Alphas(1)));
830 0 : ShowContinueError(state, format("... {} must be greater than 0.", cNumericFields(5)));
831 0 : ShowContinueError(state, format("... {} is reset to 1 and the simulation continues.", cNumericFields(5)));
832 :
833 0 : HighRHOARatio = 1.0;
834 :
835 0 : } else if (NumNumbers > 4) {
836 :
837 0 : HighRHOARatio = Numbers(5);
838 :
839 : } else {
840 :
841 0 : HighRHOARatio = 1.0;
842 : }
843 :
844 0 : if (Util::SameString(Alphas(8), "Yes")) {
845 0 : thisOAController.ModifyDuringHighOAMoisture = false;
846 : } else {
847 0 : thisOAController.ModifyDuringHighOAMoisture = true;
848 : }
849 :
850 0 : } else if (!Util::SameString(Alphas(6), "No") && NumAlphas > 4 && (!lAlphaBlanks(5))) {
851 0 : ShowWarningError(state, format("{} \"{}\"", CurrentModuleObject, Alphas(1)));
852 0 : ShowContinueError(state, format("... Invalid {} = {}", cAlphaFields(6), Alphas(6)));
853 0 : ShowContinueError(state, format("... {} is assumed to be \"No\" and the simulation continues.", cAlphaFields(6)));
854 : } // IF(Util::SameString(Alphas(6),'Yes'))THEN
855 :
856 0 : thisOAController.HighRHOAFlowRatio = HighRHOARatio;
857 0 : if (WhichERV != 0) {
858 0 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).HighRHOAFlowRatio = HighRHOARatio;
859 : }
860 :
861 : // Check for a time of day outside air schedule
862 0 : thisOAController.economizerOASched = Sched::GetSchedule(state, Alphas(5));
863 :
864 0 : if (WhichERV != 0) {
865 0 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).economizerOASched = Sched::GetSchedule(state, Alphas(5));
866 :
867 : // Compare the ERV SA fan flow rates to modified air flow rate.
868 0 : if (HighRHOARatio > 1.0 && state.dataHVACStandAloneERV->StandAloneERV(WhichERV).SupplyAirVolFlow != DataSizing::AutoSize &&
869 0 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).DesignSAFanVolFlowRate != DataSizing::AutoSize) {
870 0 : if (state.dataHVACStandAloneERV->StandAloneERV(WhichERV).SupplyAirVolFlow * HighRHOARatio >
871 0 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).DesignSAFanVolFlowRate) {
872 0 : ShowWarningError(state, format("{} \"{}\"", CurrentModuleObject, Alphas(1)));
873 0 : ShowContinueError(state, format("... A {} was entered as {:.4R}", cNumericFields(5), HighRHOARatio));
874 0 : ShowContinueError(state,
875 : "... This flow ratio results in a Supply Air Volume Flow Rate through the ERV which is greater than the "
876 : "Max Volume specified in the supply air fan object.");
877 0 : ShowContinueError(state,
878 0 : format("... Associated fan object = {} \"{}\"",
879 0 : HVAC::fanTypeNames[(int)state.dataHVACStandAloneERV->StandAloneERV(WhichERV).supplyAirFanType],
880 0 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).SupplyAirFanName));
881 0 : ShowContinueError(state,
882 0 : format("... Modified value = {:.2R}",
883 0 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).SupplyAirVolFlow * HighRHOARatio));
884 0 : ShowContinueError(state,
885 0 : format(" ... Supply Fan Max Volume Flow Rate = {:.2R}",
886 0 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).DesignSAFanVolFlowRate));
887 0 : ShowContinueError(state, "... The ERV supply air fan will limit the air flow through the ERV and the simulation continues.");
888 : }
889 : }
890 :
891 : // Compare the ERV EA fan flow rates to modified air flow rate.
892 0 : if (HighRHOARatio > 1.0 && state.dataHVACStandAloneERV->StandAloneERV(WhichERV).ExhaustAirVolFlow != DataSizing::AutoSize &&
893 0 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).DesignEAFanVolFlowRate != DataSizing::AutoSize) {
894 0 : if (state.dataHVACStandAloneERV->StandAloneERV(WhichERV).ExhaustAirVolFlow * HighRHOARatio >
895 0 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).DesignEAFanVolFlowRate) {
896 0 : ShowWarningError(state, format("ZoneHVAC:EnergyRecoveryVentilator:Controller \"{}\"", Alphas(1)));
897 0 : ShowContinueError(state, format("... A {} was entered as {:.4R}", cNumericFields(5), HighRHOARatio));
898 0 : ShowContinueError(state,
899 : "... This flow ratio results in an Exhaust Air Volume Flow Rate through the ERV which is greater than the "
900 : "Max Volume specified in the exhaust air fan object.");
901 0 : ShowContinueError(state,
902 0 : format("... Associated fan object = {} \"{}\"",
903 0 : HVAC::fanTypeNames[(int)state.dataHVACStandAloneERV->StandAloneERV(WhichERV).exhaustAirFanType],
904 0 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).ExhaustAirFanName));
905 0 : ShowContinueError(state,
906 0 : format("... Modified value = {:.2R}",
907 0 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).ExhaustAirVolFlow * HighRHOARatio));
908 0 : ShowContinueError(state,
909 0 : format(" ... Exhaust Fan Max Volume Flow Rate = {:.2R}",
910 0 : state.dataHVACStandAloneERV->StandAloneERV(WhichERV).DesignEAFanVolFlowRate));
911 0 : ShowContinueError(state, "... The ERV exhaust air fan will limit the air flow through the ERV and the simulation continues.");
912 : }
913 : }
914 : } // IF(WhichERV /= 0)THEN
915 : }
916 :
917 6 : if (ErrorsFound) {
918 0 : ShowFatalError(state, "Errors found in getting ZoneHVAC:EnergyRecoveryVentilator input.");
919 : }
920 :
921 : // Setup report variables for the stand alone ERVs
922 6 : for (int StandAloneERVIndex = 1; StandAloneERVIndex <= state.dataHVACStandAloneERV->NumStandAloneERVs; ++StandAloneERVIndex) {
923 0 : auto &standAloneERV = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVIndex);
924 0 : SetupOutputVariable(state,
925 : "Zone Ventilator Sensible Cooling Rate",
926 : Constant::Units::W,
927 0 : standAloneERV.SensCoolingRate,
928 : OutputProcessor::TimeStepType::System,
929 : OutputProcessor::StoreType::Average,
930 0 : standAloneERV.Name);
931 0 : SetupOutputVariable(state,
932 : "Zone Ventilator Sensible Cooling Energy",
933 : Constant::Units::J,
934 0 : standAloneERV.SensCoolingEnergy,
935 : OutputProcessor::TimeStepType::System,
936 : OutputProcessor::StoreType::Sum,
937 0 : standAloneERV.Name);
938 0 : SetupOutputVariable(state,
939 : "Zone Ventilator Latent Cooling Rate",
940 : Constant::Units::W,
941 0 : standAloneERV.LatCoolingRate,
942 : OutputProcessor::TimeStepType::System,
943 : OutputProcessor::StoreType::Average,
944 0 : standAloneERV.Name);
945 0 : SetupOutputVariable(state,
946 : "Zone Ventilator Latent Cooling Energy",
947 : Constant::Units::J,
948 0 : standAloneERV.LatCoolingEnergy,
949 : OutputProcessor::TimeStepType::System,
950 : OutputProcessor::StoreType::Sum,
951 0 : standAloneERV.Name);
952 0 : SetupOutputVariable(state,
953 : "Zone Ventilator Total Cooling Rate",
954 : Constant::Units::W,
955 0 : standAloneERV.TotCoolingRate,
956 : OutputProcessor::TimeStepType::System,
957 : OutputProcessor::StoreType::Average,
958 0 : standAloneERV.Name);
959 0 : SetupOutputVariable(state,
960 : "Zone Ventilator Total Cooling Energy",
961 : Constant::Units::J,
962 0 : standAloneERV.TotCoolingEnergy,
963 : OutputProcessor::TimeStepType::System,
964 : OutputProcessor::StoreType::Sum,
965 0 : standAloneERV.Name);
966 :
967 0 : SetupOutputVariable(state,
968 : "Zone Ventilator Sensible Heating Rate",
969 : Constant::Units::W,
970 0 : standAloneERV.SensHeatingRate,
971 : OutputProcessor::TimeStepType::System,
972 : OutputProcessor::StoreType::Average,
973 0 : standAloneERV.Name);
974 0 : SetupOutputVariable(state,
975 : "Zone Ventilator Sensible Heating Energy",
976 : Constant::Units::J,
977 0 : standAloneERV.SensHeatingEnergy,
978 : OutputProcessor::TimeStepType::System,
979 : OutputProcessor::StoreType::Sum,
980 0 : standAloneERV.Name);
981 0 : SetupOutputVariable(state,
982 : "Zone Ventilator Latent Heating Rate",
983 : Constant::Units::W,
984 0 : standAloneERV.LatHeatingRate,
985 : OutputProcessor::TimeStepType::System,
986 : OutputProcessor::StoreType::Average,
987 0 : standAloneERV.Name);
988 0 : SetupOutputVariable(state,
989 : "Zone Ventilator Latent Heating Energy",
990 : Constant::Units::J,
991 0 : standAloneERV.LatHeatingEnergy,
992 : OutputProcessor::TimeStepType::System,
993 : OutputProcessor::StoreType::Sum,
994 0 : standAloneERV.Name);
995 0 : SetupOutputVariable(state,
996 : "Zone Ventilator Total Heating Rate",
997 : Constant::Units::W,
998 0 : standAloneERV.TotHeatingRate,
999 : OutputProcessor::TimeStepType::System,
1000 : OutputProcessor::StoreType::Average,
1001 0 : standAloneERV.Name);
1002 0 : SetupOutputVariable(state,
1003 : "Zone Ventilator Total Heating Energy",
1004 : Constant::Units::J,
1005 0 : standAloneERV.TotHeatingEnergy,
1006 : OutputProcessor::TimeStepType::System,
1007 : OutputProcessor::StoreType::Sum,
1008 0 : standAloneERV.Name);
1009 :
1010 0 : SetupOutputVariable(state,
1011 : "Zone Ventilator Electricity Rate",
1012 : Constant::Units::W,
1013 0 : standAloneERV.ElecUseRate,
1014 : OutputProcessor::TimeStepType::System,
1015 : OutputProcessor::StoreType::Average,
1016 0 : standAloneERV.Name);
1017 0 : SetupOutputVariable(state,
1018 : "Zone Ventilator Electricity Energy",
1019 : Constant::Units::J,
1020 0 : standAloneERV.ElecUseEnergy,
1021 : OutputProcessor::TimeStepType::System,
1022 : OutputProcessor::StoreType::Sum,
1023 0 : standAloneERV.Name);
1024 0 : SetupOutputVariable(state,
1025 : "Zone Ventilator Supply Fan Availability Status",
1026 : Constant::Units::None,
1027 0 : (int &)standAloneERV.availStatus,
1028 : OutputProcessor::TimeStepType::System,
1029 : OutputProcessor::StoreType::Average,
1030 0 : standAloneERV.Name);
1031 : }
1032 :
1033 6 : Alphas.deallocate();
1034 6 : Numbers.deallocate();
1035 6 : cAlphaFields.deallocate();
1036 6 : cNumericFields.deallocate();
1037 6 : lNumericBlanks.deallocate();
1038 6 : lAlphaBlanks.deallocate();
1039 6 : }
1040 :
1041 0 : void InitStandAloneERV(EnergyPlusData &state,
1042 : int const StandAloneERVNum, // number of the current Stand Alone ERV unit being simulated
1043 : int const ZoneNum, // number of zone being served unused1208
1044 : bool const FirstHVACIteration // TRUE if first HVAC iteration
1045 : )
1046 : {
1047 :
1048 : // SUBROUTINE INFORMATION:
1049 : // AUTHOR Richard Raustad, FSEC
1050 : // DATE WRITTEN June 2003
1051 : // MODIFIED July 2012, Chandan Sharma - FSEC: Added zone sys avail managers
1052 :
1053 : // PURPOSE OF THIS SUBROUTINE:
1054 : // This subroutine is for initializations of the Stand Alone ERV unit information.
1055 :
1056 : // METHODOLOGY EMPLOYED:
1057 : // Uses the status flags to trigger initializations.
1058 :
1059 : // Do the one time initializations
1060 0 : if (state.dataHVACStandAloneERV->MyOneTimeFlag) {
1061 :
1062 0 : state.dataHVACStandAloneERV->MyEnvrnFlag.allocate(state.dataHVACStandAloneERV->NumStandAloneERVs);
1063 0 : state.dataHVACStandAloneERV->MySizeFlag_InitStandAloneERV.allocate(state.dataHVACStandAloneERV->NumStandAloneERVs);
1064 0 : state.dataHVACStandAloneERV->MyZoneEqFlag.allocate(state.dataHVACStandAloneERV->NumStandAloneERVs);
1065 0 : state.dataHVACStandAloneERV->MyEnvrnFlag = true;
1066 0 : state.dataHVACStandAloneERV->MySizeFlag_InitStandAloneERV = true;
1067 0 : state.dataHVACStandAloneERV->MyZoneEqFlag = true;
1068 0 : state.dataHVACStandAloneERV->MyOneTimeFlag = false;
1069 : }
1070 :
1071 0 : if (allocated(state.dataAvail->ZoneComp)) {
1072 0 : auto &availMgr = state.dataAvail->ZoneComp(DataZoneEquipment::ZoneEquipType::EnergyRecoveryVentilator).ZoneCompAvailMgrs(StandAloneERVNum);
1073 0 : if (state.dataHVACStandAloneERV->MyZoneEqFlag(StandAloneERVNum)) { // initialize the name of each availability manager list and zone number
1074 0 : availMgr.AvailManagerListName = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).AvailManagerListName;
1075 0 : availMgr.ZoneNum = ZoneNum;
1076 0 : state.dataHVACStandAloneERV->MyZoneEqFlag(StandAloneERVNum) = false;
1077 : }
1078 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).availStatus = availMgr.availStatus;
1079 : }
1080 :
1081 : // need to check all units to see if they are on Zone Equipment List or issue warning
1082 0 : if (!state.dataHVACStandAloneERV->ZoneEquipmentListChecked && state.dataZoneEquip->ZoneEquipInputsFilled) {
1083 0 : state.dataHVACStandAloneERV->ZoneEquipmentListChecked = true;
1084 0 : for (int Loop = 1; Loop <= state.dataHVACStandAloneERV->NumStandAloneERVs; ++Loop) {
1085 0 : if (DataZoneEquipment::CheckZoneEquipmentList(
1086 0 : state, state.dataHVACStandAloneERV->StandAloneERV(Loop).UnitType, state.dataHVACStandAloneERV->StandAloneERV(Loop).Name))
1087 0 : continue;
1088 0 : ShowSevereError(state,
1089 0 : format("InitStandAloneERV: Unit=[{},{}] is not on any ZoneHVAC:EquipmentList. It will not be simulated.",
1090 0 : state.dataHVACStandAloneERV->StandAloneERV(Loop).UnitType,
1091 0 : state.dataHVACStandAloneERV->StandAloneERV(Loop).Name));
1092 : }
1093 : }
1094 :
1095 0 : if (!state.dataGlobal->SysSizingCalc && state.dataHVACStandAloneERV->MySizeFlag_InitStandAloneERV(StandAloneERVNum)) {
1096 0 : SizeStandAloneERV(state, StandAloneERVNum);
1097 0 : state.dataHVACStandAloneERV->MySizeFlag_InitStandAloneERV(StandAloneERVNum) = false;
1098 : }
1099 :
1100 : // Do the Begin Environment initializations
1101 0 : if (state.dataGlobal->BeginEnvrnFlag && state.dataHVACStandAloneERV->MyEnvrnFlag(StandAloneERVNum)) {
1102 0 : int SupInNode = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirInletNode;
1103 0 : int ExhInNode = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirInletNode;
1104 : // set the mass flow rates from the input volume flow rates
1105 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).MaxSupAirMassFlow =
1106 0 : state.dataEnvrn->StdRhoAir * state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirVolFlow;
1107 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).MaxExhAirMassFlow =
1108 0 : state.dataEnvrn->StdRhoAir * state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirVolFlow;
1109 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignSAFanMassFlowRate =
1110 0 : state.dataEnvrn->StdRhoAir * state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignSAFanVolFlowRate;
1111 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignEAFanMassFlowRate =
1112 0 : state.dataEnvrn->StdRhoAir * state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignEAFanVolFlowRate;
1113 : // set the node max and min mass flow rates
1114 0 : auto &supInNode = state.dataLoopNodes->Node(SupInNode);
1115 0 : auto &exhInNode = state.dataLoopNodes->Node(ExhInNode);
1116 :
1117 0 : supInNode.MassFlowRateMax = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).MaxSupAirMassFlow;
1118 0 : supInNode.MassFlowRateMin = 0.0;
1119 0 : exhInNode.MassFlowRateMax = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).MaxExhAirMassFlow;
1120 0 : exhInNode.MassFlowRateMin = 0.0;
1121 0 : state.dataHVACStandAloneERV->MyEnvrnFlag(StandAloneERVNum) = false;
1122 : // Initialize OA Controller on BeginEnvrnFlag
1123 0 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerNameDefined) {
1124 0 : MixedAir::SimOAController(state,
1125 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerName,
1126 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerIndex,
1127 : FirstHVACIteration,
1128 : 0);
1129 : }
1130 : } // end one time inits
1131 :
1132 0 : if (!state.dataGlobal->BeginEnvrnFlag) {
1133 0 : state.dataHVACStandAloneERV->MyEnvrnFlag(StandAloneERVNum) = true;
1134 : }
1135 :
1136 : // These initializations are done every iteration
1137 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ElecUseRate = 0.0;
1138 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SensCoolingRate = 0.0;
1139 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).LatCoolingRate = 0.0;
1140 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).TotCoolingRate = 0.0;
1141 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SensHeatingRate = 0.0;
1142 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).LatHeatingRate = 0.0;
1143 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).TotHeatingRate = 0.0;
1144 0 : int SupInNode = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirInletNode;
1145 0 : int ExhInNode = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirInletNode;
1146 0 : auto &supInNode = state.dataLoopNodes->Node(SupInNode);
1147 0 : auto &exhInNode = state.dataLoopNodes->Node(ExhInNode);
1148 :
1149 : // Set the inlet node mass flow rate
1150 0 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).availSched->getCurrentVal() > 0.0) {
1151 :
1152 : // IF optional ControllerName is defined SimOAController ONLY to set economizer and Modifyairflow flags
1153 0 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerNameDefined) {
1154 : // Initialize a flow rate for controller
1155 0 : supInNode.MassFlowRate = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).MaxSupAirMassFlow;
1156 0 : MixedAir::SimOAController(state,
1157 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerName,
1158 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerIndex,
1159 : FirstHVACIteration,
1160 : 0);
1161 : }
1162 :
1163 0 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).supplyAirFanSched->getCurrentVal() > 0 ||
1164 0 : (state.dataHVACGlobal->TurnFansOn && !state.dataHVACGlobal->TurnFansOff)) {
1165 0 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerNameDefined) {
1166 0 : if (state.dataMixedAir->OAController(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerIndex)
1167 0 : .HighHumCtrlActive) {
1168 0 : supInNode.MassFlowRate = min(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignSAFanMassFlowRate,
1169 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).MaxSupAirMassFlow *
1170 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).HighRHOAFlowRatio);
1171 : } else {
1172 0 : supInNode.MassFlowRate = min(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignSAFanMassFlowRate,
1173 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).MaxSupAirMassFlow);
1174 : }
1175 : } else {
1176 0 : supInNode.MassFlowRate = min(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignSAFanMassFlowRate,
1177 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).MaxSupAirMassFlow);
1178 : }
1179 : } else {
1180 0 : supInNode.MassFlowRate = 0.0;
1181 : }
1182 0 : supInNode.MassFlowRateMaxAvail = supInNode.MassFlowRate;
1183 0 : supInNode.MassFlowRateMinAvail = supInNode.MassFlowRate;
1184 :
1185 0 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).exhaustAirFanSched->getCurrentVal() > 0) {
1186 0 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerNameDefined) {
1187 0 : if (state.dataMixedAir->OAController(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerIndex)
1188 0 : .HighHumCtrlActive) {
1189 0 : exhInNode.MassFlowRate = min(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignEAFanMassFlowRate,
1190 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).MaxExhAirMassFlow *
1191 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).HighRHOAFlowRatio);
1192 : } else {
1193 0 : exhInNode.MassFlowRate = min(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignEAFanMassFlowRate,
1194 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).MaxExhAirMassFlow);
1195 : }
1196 : } else {
1197 0 : exhInNode.MassFlowRate = min(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignEAFanMassFlowRate,
1198 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).MaxExhAirMassFlow);
1199 : }
1200 : } else {
1201 0 : exhInNode.MassFlowRate = 0.0;
1202 : }
1203 0 : exhInNode.MassFlowRateMaxAvail = exhInNode.MassFlowRate;
1204 0 : exhInNode.MassFlowRateMinAvail = exhInNode.MassFlowRate;
1205 : } else {
1206 0 : supInNode.MassFlowRate = 0.0;
1207 0 : supInNode.MassFlowRateMaxAvail = 0.0;
1208 0 : supInNode.MassFlowRateMinAvail = 0.0;
1209 0 : exhInNode.MassFlowRate = 0.0;
1210 0 : exhInNode.MassFlowRateMaxAvail = 0.0;
1211 0 : exhInNode.MassFlowRateMinAvail = 0.0;
1212 : }
1213 0 : }
1214 :
1215 5 : void SizeStandAloneERV(EnergyPlusData &state, int const StandAloneERVNum)
1216 : {
1217 :
1218 : // SUBROUTINE INFORMATION:
1219 : // AUTHOR Richard Raustad
1220 : // DATE WRITTEN October 2007
1221 : // MODIFIED August 2013 Daeho Kang, add component sizing table entries
1222 :
1223 : // PURPOSE OF THIS SUBROUTINE:
1224 : // This subroutine is for sizing Stand Alone ERV Components for which flow rates have not been
1225 : // specified in the input.
1226 :
1227 : // METHODOLOGY EMPLOYED:
1228 : // Obtains flow rates from the zone or system sizing arrays.
1229 :
1230 : static constexpr std::string_view RoutineName("SizeStandAloneERV: ");
1231 :
1232 5 : bool IsAutoSize = false;
1233 5 : Real64 SupplyAirVolFlowDes = 0.0;
1234 5 : Real64 DesignSAFanVolFlowRateDes = 0.0;
1235 5 : Real64 DesignSAFanVolFlowRateUser = 0.0;
1236 5 : Real64 ExhaustAirVolFlowDes = 0.0;
1237 5 : std::string CompType = "ZoneHVAC:EnergyRecoveryVentilator";
1238 5 : std::string CompName = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).Name;
1239 5 : bool PrintFlag = true;
1240 5 : bool ErrorsFound = false;
1241 :
1242 5 : auto &zoneEqSizing = state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum);
1243 :
1244 5 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirVolFlow == DataSizing::AutoSize) {
1245 5 : IsAutoSize = true;
1246 : }
1247 :
1248 5 : if (state.dataSize->CurZoneEqNum > 0) {
1249 :
1250 : // Sizing objects are not required for stand alone ERV
1251 : // CALL CheckZoneSizing('ZoneHVAC:EnergyRecoveryVentilator',StandAloneERV(StandAloneERVNum)%Name)
1252 5 : int ZoneNum = state.dataSize->CurZoneEqNum;
1253 5 : Real64 ZoneMult = state.dataHeatBal->Zone(ZoneNum).Multiplier * state.dataHeatBal->Zone(ZoneNum).ListMultiplier;
1254 5 : Real64 FloorArea = state.dataHeatBal->Zone(ZoneNum).FloorArea;
1255 5 : Real64 NumberOfPeople = 0.0;
1256 5 : Real64 MaxPeopleSch = 0.0;
1257 15 : for (int PeopleNum = 1; PeopleNum <= state.dataHeatBal->TotPeople; ++PeopleNum) {
1258 10 : if (ZoneNum != state.dataHeatBal->People(PeopleNum).ZonePtr) continue;
1259 10 : MaxPeopleSch = state.dataHeatBal->People(PeopleNum).sched->getMaxVal(state);
1260 10 : NumberOfPeople = NumberOfPeople + (state.dataHeatBal->People(PeopleNum).NumberOfPeople * MaxPeopleSch);
1261 : }
1262 5 : SupplyAirVolFlowDes = FloorArea * state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).AirVolFlowPerFloorArea +
1263 5 : NumberOfPeople * state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).AirVolFlowPerOccupant;
1264 5 : SupplyAirVolFlowDes = ZoneMult * SupplyAirVolFlowDes;
1265 :
1266 5 : if (SupplyAirVolFlowDes < HVAC::SmallAirVolFlow) {
1267 0 : SupplyAirVolFlowDes = 0.0;
1268 : }
1269 :
1270 : // Size ERV supply flow rate
1271 5 : Real64 TempSize = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirVolFlow;
1272 5 : if (IsAutoSize) {
1273 5 : state.dataSize->DataConstantUsedForSizing = SupplyAirVolFlowDes;
1274 5 : state.dataSize->DataFractionUsedForSizing = 1.0;
1275 5 : TempSize = SupplyAirVolFlowDes;
1276 5 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerNameDefined) {
1277 0 : state.dataMixedAir->OAController(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerIndex).MaxOA =
1278 0 : SupplyAirVolFlowDes * state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).HighRHOAFlowRatio;
1279 0 : state.dataMixedAir->OAController(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerIndex).MinOA =
1280 : SupplyAirVolFlowDes;
1281 : }
1282 : } else {
1283 0 : state.dataSize->DataConstantUsedForSizing = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirVolFlow;
1284 0 : state.dataSize->DataFractionUsedForSizing = 1.0;
1285 : }
1286 5 : if (TempSize > 0.0) {
1287 5 : std::string SizingString = "Supply Air Flow Rate [m3/s]";
1288 5 : SystemAirFlowSizer sizerSystemAirFlow;
1289 5 : sizerSystemAirFlow.overrideSizingString(SizingString);
1290 5 : sizerSystemAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1291 5 : TempSize = sizerSystemAirFlow.size(state, TempSize, ErrorsFound);
1292 5 : }
1293 5 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirVolFlow = TempSize;
1294 : }
1295 :
1296 : // Size ERV exhaust flow rate
1297 5 : state.dataSize->DataFractionUsedForSizing = 1.0;
1298 5 : IsAutoSize = false;
1299 5 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirVolFlow == DataSizing::AutoSize) {
1300 5 : IsAutoSize = true;
1301 : }
1302 :
1303 5 : if (state.dataSize->CurZoneEqNum > 0) {
1304 :
1305 5 : ExhaustAirVolFlowDes = SupplyAirVolFlowDes;
1306 :
1307 5 : if (ExhaustAirVolFlowDes < HVAC::SmallAirVolFlow) {
1308 0 : ExhaustAirVolFlowDes = 0.0;
1309 : }
1310 :
1311 5 : if (ExhaustAirVolFlowDes > state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirVolFlow) {
1312 0 : ExhaustAirVolFlowDes = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirVolFlow;
1313 : }
1314 :
1315 5 : Real64 TempSize = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirVolFlow;
1316 5 : if (IsAutoSize) {
1317 5 : TempSize = ExhaustAirVolFlowDes;
1318 5 : state.dataSize->DataConstantUsedForSizing = ExhaustAirVolFlowDes;
1319 : } else {
1320 0 : state.dataSize->DataConstantUsedForSizing = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirVolFlow;
1321 : }
1322 5 : state.dataSize->DataFractionUsedForSizing = 1.0;
1323 5 : if (TempSize > 0.0) {
1324 5 : std::string SizingString = "Exhaust Air Flow Rate [m3/s]";
1325 5 : SystemAirFlowSizer sizerSystemAirFlow;
1326 5 : sizerSystemAirFlow.overrideSizingString(SizingString);
1327 5 : sizerSystemAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
1328 5 : TempSize = sizerSystemAirFlow.size(state, TempSize, ErrorsFound);
1329 5 : }
1330 5 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirVolFlow = TempSize;
1331 5 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignEAFanVolFlowRate =
1332 5 : TempSize * state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).HighRHOAFlowRatio;
1333 : }
1334 :
1335 : // Set Zone equipment sizing data for autosizing the fans and heat exchanger
1336 5 : zoneEqSizing.AirVolFlow = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirVolFlow *
1337 5 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).HighRHOAFlowRatio;
1338 5 : zoneEqSizing.OAVolFlow = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirVolFlow;
1339 5 : zoneEqSizing.SystemAirFlow = true;
1340 5 : zoneEqSizing.DesignSizeFromParent = true;
1341 :
1342 : // Check supply fan flow rate or set flow rate if autosized in fan object
1343 5 : IsAutoSize = false;
1344 5 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignSAFanVolFlowRate == DataSizing::AutoSize) {
1345 1 : IsAutoSize = true;
1346 : }
1347 5 : DesignSAFanVolFlowRateDes = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirVolFlow *
1348 5 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).HighRHOAFlowRatio;
1349 5 : if (IsAutoSize) {
1350 1 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignSAFanVolFlowRate = DesignSAFanVolFlowRateDes;
1351 : } else {
1352 4 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignSAFanVolFlowRate > 0.0 && DesignSAFanVolFlowRateDes > 0.0) {
1353 0 : DesignSAFanVolFlowRateUser = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).DesignSAFanVolFlowRate;
1354 0 : if (state.dataGlobal->DisplayExtraWarnings) {
1355 0 : if ((std::abs(DesignSAFanVolFlowRateDes - DesignSAFanVolFlowRateUser) / DesignSAFanVolFlowRateUser) >
1356 0 : state.dataSize->AutoVsHardSizingThreshold) {
1357 0 : ShowMessage(state,
1358 0 : format("SizeStandAloneERV: Potential issue with equipment sizing for ZoneHVAC:EnergyRecoveryVentilator {} {}",
1359 0 : HVAC::fanTypeNames[(int)state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).supplyAirFanType],
1360 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirFanName));
1361 0 : ShowContinueError(state, format("User-Specified Supply Fan Maximum Flow Rate of {:.5R} [m3/s]", DesignSAFanVolFlowRateUser));
1362 0 : ShowContinueError(state, format("differs from the ERV Supply Air Flow Rate of {:.5R} [m3/s]", DesignSAFanVolFlowRateDes));
1363 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1364 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1365 : }
1366 : }
1367 : }
1368 : }
1369 :
1370 : // simulate the fan to size using the flow rate specified above
1371 : // (i.e., ZoneEqSizing( CurZoneEqNum ).AirVolFlow = StandAloneERV( StandAloneERVNum ).SupplyAirVolFlow * StandAloneERV( StandAloneERVNum
1372 : // ).HighRHOAFlowRatio;)
1373 5 : state.dataFans->fans(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirFanIndex)->simulate(state, true, _, _);
1374 :
1375 5 : state.dataFans->fans(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirFanIndex)->simulate(state, true, _, _);
1376 :
1377 : // now reset the ZoneEqSizing variable to NOT use the multiplier for HighRHOAFlowRatio for sizing HXs
1378 5 : zoneEqSizing.AirVolFlow = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirVolFlow;
1379 5 : }
1380 :
1381 0 : void CalcStandAloneERV(EnergyPlusData &state,
1382 : int const StandAloneERVNum, // Unit index in ERV data structure
1383 : bool const FirstHVACIteration, // flag for 1st HVAC iteration in the time step
1384 : Real64 &SensLoadMet, // sensible zone load met by unit (W)
1385 : Real64 &LatentMassLoadMet // latent zone load met by unit (kg/s), dehumid = negative
1386 : )
1387 : {
1388 :
1389 : // SUBROUTINE INFORMATION:
1390 : // AUTHOR Richard Raustad, FSEC
1391 : // DATE WRITTEN June 2003
1392 : // MODIFIED Don Shirey, Aug 2009 (LatentMassLoadMet)
1393 : // July 2012, Chandan Sharma - FSEC: Added zone sys avail managers
1394 :
1395 : // PURPOSE OF THIS SUBROUTINE:
1396 : // Simulate the components making up the Stand Alone ERV unit.
1397 :
1398 : // METHODOLOGY EMPLOYED:
1399 : // Simulates the unit components sequentially in the air flow direction.
1400 :
1401 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1402 : Real64 TotLoadMet; // total zone load met by unit (W)
1403 : Real64 LatLoadMet; // latent zone load met by unit (W)
1404 : bool EconomizerFlag; // economizer signal from OA controller
1405 : bool HighHumCtrlFlag; // high humditiy control signal from OA controller
1406 :
1407 0 : int SupInletNode = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirInletNode;
1408 0 : int SupOutletNode = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirOutletNode;
1409 0 : int ExhaustInletNode = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirInletNode;
1410 :
1411 : // Stand alone ERV's HX is ON by default
1412 0 : bool HXUnitOn = true;
1413 :
1414 : // Get stand alone ERV's controller economizer and high humidity control status
1415 0 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerNameDefined) {
1416 0 : EconomizerFlag = state.dataMixedAir->OAController(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerIndex).EconoActive;
1417 0 : HighHumCtrlFlag =
1418 0 : state.dataMixedAir->OAController(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ControllerIndex).HighHumCtrlActive;
1419 : } else {
1420 0 : EconomizerFlag = false;
1421 0 : HighHumCtrlFlag = false;
1422 : }
1423 :
1424 0 : HeatRecovery::SimHeatRecovery(state,
1425 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).HeatExchangerName,
1426 : FirstHVACIteration,
1427 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).HeatExchangerIndex,
1428 : HVAC::FanOp::Continuous,
1429 : _,
1430 : HXUnitOn,
1431 : _,
1432 : _,
1433 : EconomizerFlag,
1434 : HighHumCtrlFlag);
1435 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ElecUseRate = state.dataHVACGlobal->AirToAirHXElecPower;
1436 :
1437 0 : state.dataFans->fans(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirFanIndex)->simulate(state, FirstHVACIteration, _, _);
1438 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ElecUseRate +=
1439 0 : state.dataFans->fans(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirFanIndex)->totalPower;
1440 :
1441 0 : state.dataFans->fans(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirFanIndex)->simulate(state, FirstHVACIteration, _, _);
1442 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ElecUseRate +=
1443 0 : state.dataFans->fans(state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirFanIndex)->totalPower;
1444 :
1445 : // total mass flow through supply side of the ERV (supply air outlet node)
1446 0 : Real64 AirMassFlow = state.dataLoopNodes->Node(SupOutletNode).MassFlowRate;
1447 0 : CalcZoneSensibleLatentOutput(AirMassFlow,
1448 0 : state.dataLoopNodes->Node(SupOutletNode).Temp,
1449 0 : state.dataLoopNodes->Node(SupOutletNode).HumRat,
1450 0 : state.dataLoopNodes->Node(ExhaustInletNode).Temp,
1451 0 : state.dataLoopNodes->Node(ExhaustInletNode).HumRat,
1452 : SensLoadMet,
1453 : LatLoadMet,
1454 : TotLoadMet);
1455 0 : LatentMassLoadMet = AirMassFlow * (state.dataLoopNodes->Node(SupOutletNode).HumRat -
1456 0 : state.dataLoopNodes->Node(ExhaustInletNode).HumRat); // kg/s, dehumidification = negative
1457 :
1458 0 : if (SensLoadMet < 0.0) {
1459 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SensCoolingRate = std::abs(SensLoadMet);
1460 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SensHeatingRate = 0.0;
1461 : } else {
1462 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SensCoolingRate = 0.0;
1463 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SensHeatingRate = SensLoadMet;
1464 : }
1465 0 : if (TotLoadMet < 0.0) {
1466 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).TotCoolingRate = std::abs(TotLoadMet);
1467 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).TotHeatingRate = 0.0;
1468 : } else {
1469 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).TotCoolingRate = 0.0;
1470 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).TotHeatingRate = TotLoadMet;
1471 : }
1472 0 : if (LatLoadMet < 0.0) {
1473 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).LatCoolingRate = std::abs(LatLoadMet);
1474 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).LatHeatingRate = 0.0;
1475 : } else {
1476 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).LatCoolingRate = 0.0;
1477 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).LatHeatingRate = LatLoadMet;
1478 : }
1479 :
1480 : // Provide a one time message when exhaust flow rate is greater than supply flow rate
1481 0 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).FlowError && !state.dataGlobal->WarmupFlag) {
1482 0 : Real64 TotalExhaustMassFlow = state.dataLoopNodes->Node(ExhaustInletNode).MassFlowRate;
1483 0 : Real64 TotalSupplyMassFlow = state.dataLoopNodes->Node(SupInletNode).MassFlowRate;
1484 0 : if (TotalExhaustMassFlow > TotalSupplyMassFlow && !state.dataHeatBal->ZoneAirMassFlow.EnforceZoneMassBalance) {
1485 0 : ShowWarningError(state,
1486 0 : format("For {} \"{}\" there is unbalanced exhaust air flow.",
1487 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).UnitType,
1488 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).Name));
1489 0 : ShowContinueError(state, format("... The exhaust air mass flow rate = {:.6R}", state.dataLoopNodes->Node(ExhaustInletNode).MassFlowRate));
1490 0 : ShowContinueError(state, format("... The supply air mass flow rate = {:.6R}", state.dataLoopNodes->Node(SupInletNode).MassFlowRate));
1491 0 : ShowContinueErrorTimeStamp(state, "");
1492 0 : ShowContinueError(state, "... Unless there is balancing infiltration / ventilation air flow, this will result in");
1493 0 : ShowContinueError(state, "... load due to induced outside air being neglected in the simulation.");
1494 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).FlowError = false;
1495 : }
1496 : }
1497 0 : }
1498 :
1499 0 : void ReportStandAloneERV(EnergyPlusData &state, int const StandAloneERVNum) // number of the current Stand Alone ERV being simulated
1500 : {
1501 :
1502 : // SUBROUTINE INFORMATION:
1503 : // AUTHOR Richard Raustad, FSEC
1504 : // DATE WRITTEN June 2003
1505 :
1506 0 : Real64 ReportingConstant = state.dataHVACGlobal->TimeStepSysSec;
1507 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ElecUseEnergy =
1508 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ElecUseRate * ReportingConstant;
1509 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SensCoolingEnergy =
1510 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SensCoolingRate * ReportingConstant;
1511 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).LatCoolingEnergy =
1512 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).LatCoolingRate * ReportingConstant;
1513 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).TotCoolingEnergy =
1514 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).TotCoolingRate * ReportingConstant;
1515 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SensHeatingEnergy =
1516 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SensHeatingRate * ReportingConstant;
1517 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).LatHeatingEnergy =
1518 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).LatHeatingRate * ReportingConstant;
1519 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).TotHeatingEnergy =
1520 0 : state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).TotHeatingRate * ReportingConstant;
1521 :
1522 0 : if (state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).FirstPass) { // reset sizing flags so other zone equipment can size normally
1523 0 : if (!state.dataGlobal->SysSizingCalc) {
1524 0 : DataSizing::resetHVACSizingGlobals(
1525 0 : state, state.dataSize->CurZoneEqNum, 0, state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).FirstPass);
1526 : }
1527 : }
1528 0 : }
1529 :
1530 : // Utility subroutines/functions for the HeatingCoil Module
1531 :
1532 0 : Real64 GetSupplyAirFlowRate(EnergyPlusData &state,
1533 : std::string const &ERVType, // must be "ZoneHVAC:EnergyRecoveryVentilator"
1534 : std::string const &ERVCtrlName, // must match a controller name in the ERV data structure
1535 : bool &ErrorsFound // set to true if problem
1536 : )
1537 : {
1538 :
1539 : // FUNCTION INFORMATION:
1540 : // AUTHOR Linda Lawrie
1541 : // DATE WRITTEN October 2006
1542 :
1543 : // PURPOSE OF THIS FUNCTION:
1544 : // This function looks up the ERVCtrlName in the ERV Stand Alone list and returns the
1545 : // Supply Air Flow rate, if found. If incorrect name is given, ErrorsFound is returned as true
1546 : // and supply air flow rate as negative.
1547 :
1548 0 : if (state.dataHVACStandAloneERV->GetERVInputFlag) {
1549 0 : GetStandAloneERV(state);
1550 0 : state.dataHVACStandAloneERV->GetERVInputFlag = false;
1551 : }
1552 :
1553 0 : if (Util::SameString(ERVType, "ZoneHVAC:EnergyRecoveryVentilator")) {
1554 0 : int WhichERV = Util::FindItem(ERVCtrlName, state.dataHVACStandAloneERV->StandAloneERV, &StandAloneERVData::ControllerName);
1555 0 : if (WhichERV != 0) {
1556 0 : return state.dataHVACStandAloneERV->StandAloneERV(WhichERV).SupplyAirVolFlow;
1557 : }
1558 : }
1559 :
1560 0 : ShowSevereError(state, format("Could not find ZoneHVAC:EnergyRecoveryVentilator with Controller Name=\"{}\"", ERVCtrlName));
1561 0 : ErrorsFound = true;
1562 0 : return -1000.0;
1563 : }
1564 :
1565 1 : int GetStandAloneERVOutAirNode(EnergyPlusData &state, int const StandAloneERVNum)
1566 : {
1567 : // FUNCTION INFORMATION:
1568 : // AUTHOR B Griffith
1569 : // DATE WRITTEN Dec 2006
1570 :
1571 : // PURPOSE OF THIS FUNCTION:
1572 : // lookup function for OA inlet node for ventilation rate reporting
1573 :
1574 1 : if (state.dataHVACStandAloneERV->GetERVInputFlag) {
1575 0 : GetStandAloneERV(state);
1576 0 : state.dataHVACStandAloneERV->GetERVInputFlag = false;
1577 : }
1578 :
1579 1 : if (StandAloneERVNum > 0 && StandAloneERVNum <= state.dataHVACStandAloneERV->NumStandAloneERVs) {
1580 1 : return state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirInletNode;
1581 : }
1582 :
1583 0 : return 0;
1584 : }
1585 :
1586 1 : int GetStandAloneERVZoneInletAirNode(EnergyPlusData &state, int const StandAloneERVNum)
1587 : {
1588 : // FUNCTION INFORMATION:
1589 : // AUTHOR B Griffith
1590 : // DATE WRITTEN Dec 2006
1591 :
1592 : // PURPOSE OF THIS FUNCTION:
1593 : // lookup function for OA inlet node for ventilation rate reporting
1594 :
1595 1 : if (state.dataHVACStandAloneERV->GetERVInputFlag) {
1596 0 : GetStandAloneERV(state);
1597 0 : state.dataHVACStandAloneERV->GetERVInputFlag = false;
1598 : }
1599 :
1600 1 : if (StandAloneERVNum > 0 && StandAloneERVNum <= state.dataHVACStandAloneERV->NumStandAloneERVs) {
1601 1 : return state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).SupplyAirOutletNode;
1602 : }
1603 :
1604 0 : return 0;
1605 : }
1606 :
1607 1 : int GetStandAloneERVReturnAirNode(EnergyPlusData &state, int const StandAloneERVNum)
1608 : {
1609 : // FUNCTION INFORMATION:
1610 : // AUTHOR B Griffith
1611 : // DATE WRITTEN Dec 2006
1612 :
1613 : // PURPOSE OF THIS FUNCTION:
1614 : // lookup function for OA inlet node for ventilation rate reporting
1615 :
1616 1 : if (state.dataHVACStandAloneERV->GetERVInputFlag) {
1617 0 : GetStandAloneERV(state);
1618 0 : state.dataHVACStandAloneERV->GetERVInputFlag = false;
1619 : }
1620 :
1621 1 : if (StandAloneERVNum > 0 && StandAloneERVNum <= state.dataHVACStandAloneERV->NumStandAloneERVs) {
1622 1 : return state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).ExhaustAirInletNode;
1623 : }
1624 :
1625 0 : return 0;
1626 : }
1627 :
1628 42 : bool GetStandAloneERVNodeNumber(EnergyPlusData &state, int const NodeNumber)
1629 : {
1630 : // PURPOSE OF THIS FUNCTION:
1631 : // Check if a node is used by a stand alone ERV
1632 : // and can be excluded from an airflow network.
1633 :
1634 42 : if (state.dataHVACStandAloneERV->GetERVInputFlag) {
1635 6 : GetStandAloneERV(state);
1636 6 : state.dataHVACStandAloneERV->GetERVInputFlag = false;
1637 : }
1638 :
1639 43 : for (int StandAloneERVIndex = 1; StandAloneERVIndex <= state.dataHVACStandAloneERV->NumStandAloneERVs; ++StandAloneERVIndex) {
1640 :
1641 10 : auto &StandAloneERV = state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVIndex);
1642 10 : int SupplyFanInletNodeIndex = 0;
1643 10 : int SupplyFanOutletNodeIndex = 0;
1644 10 : int ExhaustFanInletNodeIndex = 0;
1645 10 : int ExhaustFanOutletNodeIndex = 0;
1646 : Real64 SupplyFanAirFlow;
1647 : Real64 ExhaustFanAirFlow;
1648 :
1649 : // Get supply air fan inlet and outlet node index and air flow
1650 : // ZoneHVAC:EnergyRecoveryVentilator only accepts Fan:SystemModel or Fan:OnOff
1651 10 : SupplyFanInletNodeIndex = state.dataFans->fans(StandAloneERV.SupplyAirFanIndex)->inletNodeNum;
1652 10 : SupplyFanOutletNodeIndex = state.dataFans->fans(StandAloneERV.SupplyAirFanIndex)->outletNodeNum;
1653 10 : SupplyFanAirFlow = state.dataFans->fans(StandAloneERV.SupplyAirFanIndex)->maxAirFlowRate;
1654 :
1655 : // Get exhaust air fan inlet and outlet node index and air flow
1656 10 : ExhaustFanInletNodeIndex = state.dataFans->fans(StandAloneERV.ExhaustAirFanIndex)->inletNodeNum;
1657 10 : ExhaustFanOutletNodeIndex = state.dataFans->fans(StandAloneERV.ExhaustAirFanIndex)->outletNodeNum;
1658 10 : ExhaustFanAirFlow = state.dataFans->fans(StandAloneERV.ExhaustAirFanIndex)->maxAirFlowRate;
1659 :
1660 : // If a standalone ERV's airflow is unbalanced it shouldn't be model along with an AFN
1661 15 : if (std::abs(SupplyFanAirFlow - ExhaustFanAirFlow) >= 1E-20 ||
1662 5 : std::abs(StandAloneERV.DesignSAFanVolFlowRate - StandAloneERV.DesignEAFanVolFlowRate) >= 1E-20) {
1663 5 : break;
1664 : }
1665 :
1666 : // Supply air fan nodes
1667 5 : if (NodeNumber == SupplyFanInletNodeIndex || NodeNumber == SupplyFanOutletNodeIndex || NodeNumber == ExhaustFanInletNodeIndex ||
1668 : NodeNumber == ExhaustFanOutletNodeIndex) {
1669 4 : return true;
1670 : }
1671 :
1672 : // Supply air inlet node
1673 1 : if (NodeNumber == StandAloneERV.SupplyAirInletNode) {
1674 0 : return true;
1675 : }
1676 : }
1677 :
1678 38 : return false;
1679 : }
1680 :
1681 1 : int getEqIndex(EnergyPlusData &state, std::string_view CompName)
1682 : {
1683 1 : if (state.dataHVACStandAloneERV->GetERVInputFlag) {
1684 0 : GetStandAloneERV(state);
1685 0 : state.dataHVACStandAloneERV->GetERVInputFlag = false;
1686 : }
1687 :
1688 1 : for (int StandAloneERVNum = 1; StandAloneERVNum <= state.dataHVACStandAloneERV->NumStandAloneERVs; StandAloneERVNum++) {
1689 1 : if (Util::SameString(CompName, state.dataHVACStandAloneERV->StandAloneERV(StandAloneERVNum).Name)) {
1690 1 : return StandAloneERVNum;
1691 : }
1692 : }
1693 0 : return 0;
1694 : }
1695 :
1696 : } // namespace EnergyPlus::HVACStandAloneERV
|