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 <cassert>
50 : #include <cmath>
51 :
52 : // ObjexxFCL Headers
53 : #include <ObjexxFCL/Array.functions.hh>
54 : #include <ObjexxFCL/Fmath.hh>
55 :
56 : // EnergyPlus Headers
57 : #include <EnergyPlus/Autosizing/CoolingAirFlowSizing.hh>
58 : #include <EnergyPlus/Autosizing/CoolingCapacitySizing.hh>
59 : #include <EnergyPlus/BranchNodeConnections.hh>
60 : #include <EnergyPlus/CurveManager.hh>
61 : #include <EnergyPlus/Data/EnergyPlusData.hh>
62 : #include <EnergyPlus/DataContaminantBalance.hh>
63 : #include <EnergyPlus/DataEnvironment.hh>
64 : #include <EnergyPlus/DataGlobalConstants.hh>
65 : #include <EnergyPlus/DataHVACGlobals.hh>
66 : #include <EnergyPlus/DataHeatBalFanSys.hh>
67 : #include <EnergyPlus/DataHeatBalance.hh>
68 : #include <EnergyPlus/DataIPShortCuts.hh>
69 : #include <EnergyPlus/DataLoopNode.hh>
70 : #include <EnergyPlus/DataSizing.hh>
71 : #include <EnergyPlus/DataWater.hh>
72 : #include <EnergyPlus/DataZoneEnergyDemands.hh>
73 : #include <EnergyPlus/EMSManager.hh>
74 : #include <EnergyPlus/EvaporativeCoolers.hh>
75 : #include <EnergyPlus/Fans.hh>
76 : #include <EnergyPlus/FaultsManager.hh>
77 : #include <EnergyPlus/General.hh>
78 : #include <EnergyPlus/GeneralRoutines.hh>
79 : #include <EnergyPlus/GlobalNames.hh>
80 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
81 : #include <EnergyPlus/NodeInputManager.hh>
82 : #include <EnergyPlus/OutAirNodeManager.hh>
83 : #include <EnergyPlus/OutputProcessor.hh>
84 : #include <EnergyPlus/Psychrometrics.hh>
85 : #include <EnergyPlus/ScheduleManager.hh>
86 : #include <EnergyPlus/UtilityRoutines.hh>
87 : #include <EnergyPlus/WaterManager.hh>
88 :
89 : namespace EnergyPlus::EvaporativeCoolers {
90 : // Module containing the EvaporativeCoolers simulation routines
91 :
92 : // MODULE INFORMATION:
93 : // AUTHOR Richard J. Liesen
94 : // DATE WRITTEN Oct 2000
95 : // MODIFIED BG July 2003 ResearchSpecial Indirect
96 : // BG February 2007 outside air nodes
97 : // BG March 2009 ResearchSpecial Direct
98 : // RE-ENGINEERED na
99 :
100 : // PURPOSE OF THIS MODULE:
101 : // To encapsulate the data and algorithms required for
102 : // Evaporative Coolers Components for use in mechanical air systems
103 :
104 : // provide models for evaporative coolers as zone forced air units.
105 :
106 : // METHODOLOGY EMPLOYED:
107 : // various evaporative component models in this module
108 : // different models share common module level data structure.
109 :
110 : constexpr std::array<std::string_view, static_cast<int>(EvapCoolerType::Num)> evapCoolerTypeNamesUC = {"EVAPORATIVECOOLER:DIRECT:CELDEKPAD",
111 : "EVAPORATIVECOOLER:INDIRECT:CELDEKPAD",
112 : "EVAPORATIVECOOLER:INDIRECT:WETCOIL",
113 : "EVAPORATIVECOOLER:INDIRECT:RESEARCHSPECIAL",
114 : "EVAPORATIVECOOLER:DIRECT:RESEARCHSPECIAL"};
115 : constexpr std::array<std::string_view, static_cast<int>(EvapCoolerType::Num)> evapCoolerTypeNames = {"EvaporativeCooler:Direct:CelDekPad",
116 : "EvaporativeCooler:Indirect:CelDekPad",
117 : "EvaporativeCooler:Indirect:WetCoil",
118 : "EvaporativeCooler:Indirect:ResearchSpecial",
119 : "EvaporativeCooler:Direct:ResearchSpecial"};
120 :
121 2962542 : void SimEvapCooler(EnergyPlusData &state, std::string_view CompName, int &CompIndex, Real64 const ZoneEvapCoolerPLR)
122 : {
123 :
124 : // SUBROUTINE INFORMATION:
125 : // AUTHOR Richard Liesen
126 : // DATE WRITTEN October 2000
127 :
128 : // PURPOSE OF THIS SUBROUTINE:
129 : // This subroutine manages EvapCooler component simulation.
130 : // It is called from the SimAirLoopComponent
131 : // at the system time step.
132 :
133 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
134 : int EvapCoolNum; // The EvapCooler that you are currently loading input into
135 :
136 2962542 : auto &EvapCond(state.dataEvapCoolers->EvapCond);
137 :
138 : // Obtains and Allocates EvapCooler related parameters from input file
139 2962542 : if (state.dataEvapCoolers->GetInputEvapComponentsFlag) { // First time subroutine has been entered
140 13 : GetEvapInput(state);
141 13 : state.dataEvapCoolers->GetInputEvapComponentsFlag = false;
142 : }
143 :
144 : // Find the correct EvapCoolNumber
145 2962542 : if (CompIndex == 0) {
146 51 : EvapCoolNum = Util::FindItemInList(CompName, EvapCond, &EvapConditions::Name);
147 51 : if (EvapCoolNum == 0) {
148 0 : ShowFatalError(state, format("SimEvapCooler: Unit not found={}", CompName));
149 : }
150 51 : CompIndex = EvapCoolNum;
151 : } else {
152 2962491 : EvapCoolNum = CompIndex;
153 2962491 : if (EvapCoolNum > state.dataEvapCoolers->NumEvapCool || EvapCoolNum < 1) {
154 0 : ShowFatalError(state,
155 0 : format("SimEvapCooler: Invalid CompIndex passed={}, Number of Units={}, Entered Unit name={}",
156 : EvapCoolNum,
157 0 : state.dataEvapCoolers->NumEvapCool,
158 : CompName));
159 : }
160 2962491 : if (state.dataEvapCoolers->CheckEquipName(EvapCoolNum)) {
161 103 : if (CompName != EvapCond(EvapCoolNum).Name) {
162 0 : ShowFatalError(state,
163 0 : format("SimEvapCooler: Invalid CompIndex passed={}, Unit name={}, stored Unit Name for that index={}",
164 : EvapCoolNum,
165 : CompName,
166 0 : EvapCond(EvapCoolNum).Name));
167 : }
168 103 : state.dataEvapCoolers->CheckEquipName(EvapCoolNum) = false;
169 : }
170 : }
171 :
172 : // With the correct EvapCoolNum Initialize
173 2962542 : InitEvapCooler(state, EvapCoolNum); // Initialize all related parameters
174 :
175 2962542 : switch (EvapCond(EvapCoolNum).evapCoolerType) {
176 258218 : case EvapCoolerType::DirectCELDEKPAD: {
177 258218 : CalcDirectEvapCooler(state, EvapCoolNum, ZoneEvapCoolerPLR);
178 258218 : } break;
179 38920 : case EvapCoolerType::IndirectCELDEKPAD: {
180 38920 : CalcDryIndirectEvapCooler(state, EvapCoolNum, ZoneEvapCoolerPLR);
181 38920 : } break;
182 92337 : case EvapCoolerType::IndirectWETCOIL: {
183 92337 : CalcWetIndirectEvapCooler(state, EvapCoolNum, ZoneEvapCoolerPLR);
184 92337 : } break;
185 1156449 : case EvapCoolerType::IndirectRDDSpecial: {
186 1156449 : CalcResearchSpecialPartLoad(state, EvapCoolNum);
187 1156449 : CalcIndirectResearchSpecialEvapCooler(state, EvapCoolNum, ZoneEvapCoolerPLR);
188 1156449 : } break;
189 1416618 : case EvapCoolerType::DirectResearchSpecial: {
190 1416618 : CalcResearchSpecialPartLoad(state, EvapCoolNum);
191 1416618 : CalcDirectResearchSpecialEvapCooler(state, EvapCoolNum, ZoneEvapCoolerPLR);
192 1416618 : } break;
193 0 : default:
194 0 : break;
195 : }
196 : // Update the current Evap Cooler to the outlet nodes
197 2962542 : UpdateEvapCooler(state, EvapCoolNum);
198 :
199 : // Report the current Evap Cooler
200 2962542 : ReportEvapCooler(state, EvapCoolNum);
201 2962542 : }
202 :
203 17 : void GetEvapInput(EnergyPlusData &state)
204 : {
205 :
206 : // SUBROUTINE INFORMATION:
207 : // AUTHOR Richard J. Liesen
208 : // DATE WRITTEN Oct 2000
209 : // MODIFIED BTG, adding in EVAPCOOLER:INDIRECT:RDDSPECIAL
210 :
211 : // PURPOSE OF THIS SUBROUTINE:
212 : // This subroutine is the main routine to call other input routines and Get routines
213 :
214 : // METHODOLOGY EMPLOYED:
215 : // Uses the status flags to trigger events.
216 :
217 : static constexpr std::string_view routineName = "GetEvapInput";
218 :
219 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
220 : int NumDirectEvapCool; // The number of Direct CelDek EvapCooler in this simulation
221 : int NumDryInDirectEvapCool; // The number of dry indirect evap coolers
222 : int NumWetInDirectEvapCool; // The number of wet indirect evap coolers
223 : int NumRDDEvapCool; // the number of special research indirect evap coolers
224 : int NumDirectResearchSpecialEvapCool; // the number of special research direct evap coolers
225 :
226 : int NumAlphas;
227 : int NumNums;
228 : int IOStat;
229 17 : bool ErrorsFound(false);
230 :
231 17 : auto &EvapCond(state.dataEvapCoolers->EvapCond);
232 17 : auto &UniqueEvapCondNames(state.dataEvapCoolers->UniqueEvapCondNames);
233 :
234 17 : state.dataEvapCoolers->GetInputEvapComponentsFlag = false;
235 : // Start getting the input data
236 17 : NumDirectEvapCool = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "EvaporativeCooler:Direct:CelDekPad");
237 17 : NumDryInDirectEvapCool = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "EvaporativeCooler:Indirect:CelDekPad");
238 17 : NumWetInDirectEvapCool = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "EvaporativeCooler:Indirect:WetCoil");
239 17 : NumRDDEvapCool = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "EvaporativeCooler:Indirect:ResearchSpecial");
240 : NumDirectResearchSpecialEvapCool =
241 17 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "EvaporativeCooler:Direct:ResearchSpecial");
242 :
243 : // Sum up all of the Evap Cooler Types
244 34 : state.dataEvapCoolers->NumEvapCool =
245 17 : NumDirectEvapCool + NumDryInDirectEvapCool + NumWetInDirectEvapCool + NumRDDEvapCool + NumDirectResearchSpecialEvapCool;
246 :
247 17 : if (state.dataEvapCoolers->NumEvapCool > 0) {
248 17 : EvapCond.allocate(state.dataEvapCoolers->NumEvapCool);
249 17 : UniqueEvapCondNames.reserve(state.dataEvapCoolers->NumEvapCool);
250 : }
251 17 : state.dataEvapCoolers->CheckEquipName.dimension(state.dataEvapCoolers->NumEvapCool, true);
252 17 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
253 17 : cCurrentModuleObject = "EvaporativeCooler:Direct:CelDekPad";
254 :
255 44 : for (int EvapCoolNum = 1; EvapCoolNum <= NumDirectEvapCool; ++EvapCoolNum) {
256 27 : auto &thisEvapCooler = EvapCond(EvapCoolNum);
257 81 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
258 : cCurrentModuleObject,
259 : EvapCoolNum,
260 27 : state.dataIPShortCut->cAlphaArgs,
261 : NumAlphas,
262 27 : state.dataIPShortCut->rNumericArgs,
263 : NumNums,
264 : IOStat,
265 : _,
266 27 : state.dataIPShortCut->lAlphaFieldBlanks,
267 27 : state.dataIPShortCut->cAlphaFieldNames,
268 27 : state.dataIPShortCut->cNumericFieldNames);
269 :
270 27 : ErrorObjectHeader eoh{routineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
271 :
272 27 : GlobalNames::VerifyUniqueInterObjectName(state,
273 : UniqueEvapCondNames,
274 27 : state.dataIPShortCut->cAlphaArgs(1),
275 : cCurrentModuleObject,
276 27 : state.dataIPShortCut->cAlphaFieldNames(1),
277 : ErrorsFound);
278 :
279 27 : thisEvapCooler.Name = state.dataIPShortCut->cAlphaArgs(1);
280 27 : thisEvapCooler.evapCoolerType = EvapCoolerType::DirectCELDEKPAD;
281 :
282 27 : thisEvapCooler.Schedule = state.dataIPShortCut->cAlphaArgs(2);
283 27 : if (state.dataIPShortCut->lAlphaFieldBlanks(2)) {
284 0 : thisEvapCooler.availSched = Sched::GetScheduleAlwaysOn(state);
285 27 : } else if ((thisEvapCooler.availSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(2))) == nullptr) {
286 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(2), state.dataIPShortCut->cAlphaArgs(2));
287 0 : ErrorsFound = true;
288 : }
289 :
290 27 : thisEvapCooler.InletNode = GetOnlySingleNode(state,
291 27 : state.dataIPShortCut->cAlphaArgs(3),
292 : ErrorsFound,
293 : DataLoopNode::ConnectionObjectType::EvaporativeCoolerDirectCelDekPad,
294 27 : state.dataIPShortCut->cAlphaArgs(1),
295 : DataLoopNode::NodeFluidType::Air,
296 : DataLoopNode::ConnectionType::Inlet,
297 : NodeInputManager::CompFluidStream::Primary,
298 : DataLoopNode::ObjectIsNotParent);
299 :
300 54 : thisEvapCooler.OutletNode = GetOnlySingleNode(state,
301 27 : state.dataIPShortCut->cAlphaArgs(4),
302 : ErrorsFound,
303 : DataLoopNode::ConnectionObjectType::EvaporativeCoolerDirectCelDekPad,
304 27 : state.dataIPShortCut->cAlphaArgs(1),
305 : DataLoopNode::NodeFluidType::Air,
306 : DataLoopNode::ConnectionType::Outlet,
307 : NodeInputManager::CompFluidStream::Primary,
308 : DataLoopNode::ObjectIsNotParent);
309 :
310 54 : BranchNodeConnections::TestCompSet(state,
311 : cCurrentModuleObject,
312 27 : state.dataIPShortCut->cAlphaArgs(1),
313 27 : state.dataIPShortCut->cAlphaArgs(3),
314 27 : state.dataIPShortCut->cAlphaArgs(4),
315 : "Evap Air Nodes");
316 :
317 27 : thisEvapCooler.EvapControlType = state.dataIPShortCut->cAlphaArgs(5);
318 :
319 : // input the numerical data
320 27 : thisEvapCooler.PadArea = state.dataIPShortCut->rNumericArgs(1);
321 27 : thisEvapCooler.PadDepth = state.dataIPShortCut->rNumericArgs(2);
322 27 : thisEvapCooler.RecircPumpPower = state.dataIPShortCut->rNumericArgs(3);
323 :
324 54 : SetupOutputVariable(state,
325 : "Evaporative Cooler Wet Bulb Effectiveness",
326 : Constant::Units::None,
327 27 : thisEvapCooler.SatEff,
328 : OutputProcessor::TimeStepType::System,
329 : OutputProcessor::StoreType::Average,
330 27 : thisEvapCooler.Name);
331 :
332 : // A6 ; \Field Name of Water Supply Storage Tank
333 27 : thisEvapCooler.EvapWaterSupplyName = state.dataIPShortCut->cAlphaArgs(6);
334 27 : if (state.dataIPShortCut->lAlphaFieldBlanks(6)) {
335 27 : thisEvapCooler.EvapWaterSupplyMode = WaterSupply::FromMains;
336 : } else {
337 0 : thisEvapCooler.EvapWaterSupplyMode = WaterSupply::FromTank;
338 0 : WaterManager::SetupTankDemandComponent(state,
339 : thisEvapCooler.Name,
340 : cCurrentModuleObject,
341 : thisEvapCooler.EvapWaterSupplyName,
342 : ErrorsFound,
343 0 : thisEvapCooler.EvapWaterSupTankID,
344 0 : thisEvapCooler.EvapWaterTankDemandARRID);
345 : }
346 :
347 : } // end Number of EvapCooler Loop
348 :
349 : //**************************************************************
350 : // This is the start of the Dry Indirect Evap Cooler Loop
351 17 : cCurrentModuleObject = "EvaporativeCooler:Indirect:CelDekPad";
352 :
353 22 : for (int IndEvapCoolNum = 1; IndEvapCoolNum <= NumDryInDirectEvapCool; ++IndEvapCoolNum) {
354 5 : int EvapCoolNum = NumDirectEvapCool + IndEvapCoolNum;
355 5 : auto &thisEvapCooler = EvapCond(EvapCoolNum);
356 15 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
357 : cCurrentModuleObject,
358 : IndEvapCoolNum,
359 5 : state.dataIPShortCut->cAlphaArgs,
360 : NumAlphas,
361 5 : state.dataIPShortCut->rNumericArgs,
362 : NumNums,
363 : IOStat,
364 : _,
365 5 : state.dataIPShortCut->lAlphaFieldBlanks,
366 5 : state.dataIPShortCut->cAlphaFieldNames,
367 5 : state.dataIPShortCut->cNumericFieldNames);
368 :
369 5 : ErrorObjectHeader eoh{routineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
370 :
371 5 : GlobalNames::VerifyUniqueInterObjectName(state,
372 : UniqueEvapCondNames,
373 5 : state.dataIPShortCut->cAlphaArgs(1),
374 : cCurrentModuleObject,
375 5 : state.dataIPShortCut->cAlphaFieldNames(1),
376 : ErrorsFound);
377 5 : thisEvapCooler.Name = state.dataIPShortCut->cAlphaArgs(1);
378 5 : thisEvapCooler.evapCoolerType = EvapCoolerType::IndirectCELDEKPAD; //'EvaporativeCooler:Indirect:CelDekPad'
379 :
380 5 : thisEvapCooler.Schedule = state.dataIPShortCut->cAlphaArgs(2);
381 5 : if (state.dataIPShortCut->lAlphaFieldBlanks(2)) {
382 0 : thisEvapCooler.availSched = Sched::GetScheduleAlwaysOn(state);
383 5 : } else if ((thisEvapCooler.availSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(2))) == nullptr) {
384 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(2), state.dataIPShortCut->cAlphaArgs(2));
385 0 : ErrorsFound = true;
386 : }
387 :
388 5 : thisEvapCooler.InletNode = GetOnlySingleNode(state,
389 5 : state.dataIPShortCut->cAlphaArgs(3),
390 : ErrorsFound,
391 : DataLoopNode::ConnectionObjectType::EvaporativeCoolerIndirectCelDekPad,
392 5 : state.dataIPShortCut->cAlphaArgs(1),
393 : DataLoopNode::NodeFluidType::Air,
394 : DataLoopNode::ConnectionType::Inlet,
395 : NodeInputManager::CompFluidStream::Primary,
396 : DataLoopNode::ObjectIsNotParent);
397 :
398 10 : thisEvapCooler.OutletNode = GetOnlySingleNode(state,
399 5 : state.dataIPShortCut->cAlphaArgs(4),
400 : ErrorsFound,
401 : DataLoopNode::ConnectionObjectType::EvaporativeCoolerIndirectCelDekPad,
402 5 : state.dataIPShortCut->cAlphaArgs(1),
403 : DataLoopNode::NodeFluidType::Air,
404 : DataLoopNode::ConnectionType::Outlet,
405 : NodeInputManager::CompFluidStream::Primary,
406 : DataLoopNode::ObjectIsNotParent);
407 :
408 10 : BranchNodeConnections::TestCompSet(state,
409 : cCurrentModuleObject,
410 5 : state.dataIPShortCut->cAlphaArgs(1),
411 5 : state.dataIPShortCut->cAlphaArgs(3),
412 5 : state.dataIPShortCut->cAlphaArgs(4),
413 : "Evap Air Nodes");
414 :
415 5 : thisEvapCooler.EvapControlType = state.dataIPShortCut->cAlphaArgs(5);
416 :
417 : // input the numerical data
418 5 : thisEvapCooler.IndirectPadArea = state.dataIPShortCut->rNumericArgs(1);
419 5 : thisEvapCooler.IndirectPadDepth = state.dataIPShortCut->rNumericArgs(2);
420 5 : thisEvapCooler.IndirectRecircPumpPower = state.dataIPShortCut->rNumericArgs(3);
421 5 : thisEvapCooler.IndirectVolFlowRate = state.dataIPShortCut->rNumericArgs(4);
422 5 : thisEvapCooler.IndirectFanEff = state.dataIPShortCut->rNumericArgs(5);
423 5 : thisEvapCooler.IndirectFanDeltaPress = state.dataIPShortCut->rNumericArgs(6);
424 5 : thisEvapCooler.IndirectHXEffectiveness = state.dataIPShortCut->rNumericArgs(7);
425 :
426 10 : SetupOutputVariable(state,
427 : "Evaporative Cooler Wetbulb Effectiveness",
428 : Constant::Units::None,
429 5 : thisEvapCooler.SatEff,
430 : OutputProcessor::TimeStepType::System,
431 : OutputProcessor::StoreType::Average,
432 5 : thisEvapCooler.Name);
433 10 : SetupOutputVariable(state,
434 : "Evaporative Cooler Total Stage Effectiveness",
435 : Constant::Units::None,
436 5 : thisEvapCooler.StageEff,
437 : OutputProcessor::TimeStepType::System,
438 : OutputProcessor::StoreType::Average,
439 5 : thisEvapCooler.Name);
440 :
441 : // A6 ; \Field Name of Water Supply Storage Tank
442 5 : thisEvapCooler.EvapWaterSupplyName = state.dataIPShortCut->cAlphaArgs(6);
443 5 : if (state.dataIPShortCut->lAlphaFieldBlanks(6)) {
444 5 : thisEvapCooler.EvapWaterSupplyMode = WaterSupply::FromMains;
445 : } else {
446 0 : thisEvapCooler.EvapWaterSupplyMode = WaterSupply::FromTank;
447 0 : WaterManager::SetupTankDemandComponent(state,
448 : thisEvapCooler.Name,
449 : cCurrentModuleObject,
450 : thisEvapCooler.EvapWaterSupplyName,
451 : ErrorsFound,
452 0 : thisEvapCooler.EvapWaterSupTankID,
453 0 : thisEvapCooler.EvapWaterTankDemandARRID);
454 : }
455 :
456 : // A7 ; \field Secondary Outside Air Inlet node.
457 5 : if (state.dataIPShortCut->lAlphaFieldBlanks(7)) {
458 0 : thisEvapCooler.SecondaryInletNode = 0;
459 : } else {
460 5 : thisEvapCooler.SecondaryInletNode = GetOnlySingleNode(state,
461 5 : state.dataIPShortCut->cAlphaArgs(7),
462 : ErrorsFound,
463 : DataLoopNode::ConnectionObjectType::EvaporativeCoolerIndirectCelDekPad,
464 5 : state.dataIPShortCut->cAlphaArgs(1),
465 : DataLoopNode::NodeFluidType::Air,
466 : DataLoopNode::ConnectionType::OutsideAirReference,
467 : NodeInputManager::CompFluidStream::Primary,
468 : DataLoopNode::ObjectIsNotParent);
469 5 : if (!OutAirNodeManager::CheckOutAirNodeNumber(state, thisEvapCooler.SecondaryInletNode)) {
470 0 : ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(7), state.dataIPShortCut->cAlphaArgs(7)));
471 0 : ShowContinueError(state, format("Entered in {}={}", cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
472 : // TODO rename point
473 0 : ShowContinueError(state, "Node does not appear in an OutdoorAir:NodeList or as an OutdoorAir:Node.");
474 0 : ErrorsFound = true;
475 : }
476 : }
477 :
478 : } // end Number of Dry Indirect EvapCooler Loop
479 :
480 : //**************************************************************
481 : // This is the start of the WetIndirect Evap Cooler Loop
482 17 : cCurrentModuleObject = "EvaporativeCooler:Indirect:WetCoil";
483 26 : for (int IndEvapCoolNum = 1; IndEvapCoolNum <= NumWetInDirectEvapCool; ++IndEvapCoolNum) {
484 9 : int EvapCoolNum = NumDirectEvapCool + NumDryInDirectEvapCool + IndEvapCoolNum;
485 9 : auto &thisEvapCooler = EvapCond(EvapCoolNum);
486 27 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
487 : cCurrentModuleObject,
488 : IndEvapCoolNum,
489 9 : state.dataIPShortCut->cAlphaArgs,
490 : NumAlphas,
491 9 : state.dataIPShortCut->rNumericArgs,
492 : NumNums,
493 : IOStat,
494 : _,
495 9 : state.dataIPShortCut->lAlphaFieldBlanks,
496 9 : state.dataIPShortCut->cAlphaFieldNames,
497 9 : state.dataIPShortCut->cNumericFieldNames);
498 :
499 9 : ErrorObjectHeader eoh{routineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
500 :
501 9 : GlobalNames::VerifyUniqueInterObjectName(state,
502 : UniqueEvapCondNames,
503 9 : state.dataIPShortCut->cAlphaArgs(1),
504 : cCurrentModuleObject,
505 9 : state.dataIPShortCut->cAlphaFieldNames(1),
506 : ErrorsFound);
507 9 : thisEvapCooler.Name = state.dataIPShortCut->cAlphaArgs(1);
508 9 : thisEvapCooler.evapCoolerType = EvapCoolerType::IndirectWETCOIL; //'EvaporativeCooler:Indirect:WetCoil'
509 :
510 9 : thisEvapCooler.Schedule = state.dataIPShortCut->cAlphaArgs(2);
511 9 : if (state.dataIPShortCut->lAlphaFieldBlanks(2)) {
512 0 : thisEvapCooler.availSched = Sched::GetScheduleAlwaysOn(state);
513 9 : } else if ((thisEvapCooler.availSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(2))) == nullptr) {
514 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(2), state.dataIPShortCut->cAlphaArgs(2));
515 0 : ErrorsFound = true;
516 : }
517 :
518 9 : thisEvapCooler.InletNode = GetOnlySingleNode(state,
519 9 : state.dataIPShortCut->cAlphaArgs(3),
520 : ErrorsFound,
521 : DataLoopNode::ConnectionObjectType::EvaporativeCoolerIndirectWetCoil,
522 9 : state.dataIPShortCut->cAlphaArgs(1),
523 : DataLoopNode::NodeFluidType::Air,
524 : DataLoopNode::ConnectionType::Inlet,
525 : NodeInputManager::CompFluidStream::Primary,
526 : DataLoopNode::ObjectIsNotParent);
527 :
528 18 : thisEvapCooler.OutletNode = GetOnlySingleNode(state,
529 9 : state.dataIPShortCut->cAlphaArgs(4),
530 : ErrorsFound,
531 : DataLoopNode::ConnectionObjectType::EvaporativeCoolerIndirectWetCoil,
532 9 : state.dataIPShortCut->cAlphaArgs(1),
533 : DataLoopNode::NodeFluidType::Air,
534 : DataLoopNode::ConnectionType::Outlet,
535 : NodeInputManager::CompFluidStream::Primary,
536 : DataLoopNode::ObjectIsNotParent);
537 :
538 18 : BranchNodeConnections::TestCompSet(state,
539 : cCurrentModuleObject,
540 9 : state.dataIPShortCut->cAlphaArgs(1),
541 9 : state.dataIPShortCut->cAlphaArgs(3),
542 9 : state.dataIPShortCut->cAlphaArgs(4),
543 : "Evap Air Nodes");
544 :
545 9 : thisEvapCooler.EvapControlType = state.dataIPShortCut->cAlphaArgs(5);
546 :
547 : // input the numerical data
548 9 : thisEvapCooler.WetCoilMaxEfficiency = state.dataIPShortCut->rNumericArgs(1);
549 9 : thisEvapCooler.WetCoilFlowRatio = state.dataIPShortCut->rNumericArgs(2);
550 9 : thisEvapCooler.IndirectRecircPumpPower = state.dataIPShortCut->rNumericArgs(3);
551 9 : thisEvapCooler.IndirectVolFlowRate = state.dataIPShortCut->rNumericArgs(4);
552 9 : thisEvapCooler.IndirectFanEff = state.dataIPShortCut->rNumericArgs(5);
553 9 : thisEvapCooler.IndirectFanDeltaPress = state.dataIPShortCut->rNumericArgs(6);
554 :
555 18 : SetupOutputVariable(state,
556 : "Evaporative Cooler Total Stage Effectiveness",
557 : Constant::Units::None,
558 9 : thisEvapCooler.StageEff,
559 : OutputProcessor::TimeStepType::System,
560 : OutputProcessor::StoreType::Average,
561 9 : thisEvapCooler.Name);
562 :
563 : // A6 ; \Field Name of Water Supply Storage Tank
564 9 : thisEvapCooler.EvapWaterSupplyName = state.dataIPShortCut->cAlphaArgs(6);
565 9 : if (state.dataIPShortCut->lAlphaFieldBlanks(6)) {
566 9 : thisEvapCooler.EvapWaterSupplyMode = WaterSupply::FromMains;
567 : } else {
568 0 : thisEvapCooler.EvapWaterSupplyMode = WaterSupply::FromTank;
569 0 : WaterManager::SetupTankDemandComponent(state,
570 : thisEvapCooler.Name,
571 : cCurrentModuleObject,
572 : thisEvapCooler.EvapWaterSupplyName,
573 : ErrorsFound,
574 0 : thisEvapCooler.EvapWaterSupTankID,
575 0 : thisEvapCooler.EvapWaterTankDemandARRID);
576 : }
577 :
578 : // A7 ; \field Secondary Outside Air Inlet node.
579 9 : if (state.dataIPShortCut->lAlphaFieldBlanks(7)) {
580 0 : thisEvapCooler.SecondaryInletNode = 0;
581 : } else {
582 9 : thisEvapCooler.SecondaryInletNode = GetOnlySingleNode(state,
583 9 : state.dataIPShortCut->cAlphaArgs(7),
584 : ErrorsFound,
585 : DataLoopNode::ConnectionObjectType::EvaporativeCoolerIndirectWetCoil,
586 9 : state.dataIPShortCut->cAlphaArgs(1),
587 : DataLoopNode::NodeFluidType::Air,
588 : DataLoopNode::ConnectionType::OutsideAirReference,
589 : NodeInputManager::CompFluidStream::Primary,
590 : DataLoopNode::ObjectIsNotParent);
591 9 : if (!OutAirNodeManager::CheckOutAirNodeNumber(state, thisEvapCooler.SecondaryInletNode)) {
592 0 : ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(7), state.dataIPShortCut->cAlphaArgs(7)));
593 0 : ShowContinueError(state, format("Entered in {}={}", cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
594 : // TODO rename point
595 0 : ShowContinueError(state, "Node does not appear in an OutdoorAir:NodeList or as an OutdoorAir:Node.");
596 0 : ErrorsFound = true;
597 : }
598 : }
599 :
600 : } // end Number of Wet Coil Indirect EvapCooler Loop
601 : //**************************************************************
602 : // This is the start of the Indirect Research Special Evap Cooler
603 17 : cCurrentModuleObject = "EvaporativeCooler:Indirect:ResearchSpecial";
604 55 : for (int IndEvapCoolNum = 1; IndEvapCoolNum <= NumRDDEvapCool; ++IndEvapCoolNum) {
605 38 : int EvapCoolNum = NumDirectEvapCool + NumDryInDirectEvapCool + NumWetInDirectEvapCool + IndEvapCoolNum;
606 38 : auto &thisEvapCooler = EvapCond(EvapCoolNum);
607 76 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
608 : cCurrentModuleObject,
609 : IndEvapCoolNum,
610 38 : state.dataIPShortCut->cAlphaArgs,
611 : NumAlphas,
612 38 : state.dataIPShortCut->rNumericArgs,
613 : NumNums,
614 : IOStat,
615 38 : state.dataIPShortCut->lNumericFieldBlanks,
616 38 : state.dataIPShortCut->lAlphaFieldBlanks,
617 38 : state.dataIPShortCut->cAlphaFieldNames,
618 38 : state.dataIPShortCut->cNumericFieldNames);
619 :
620 38 : ErrorObjectHeader eoh{routineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
621 38 : GlobalNames::VerifyUniqueInterObjectName(state,
622 : UniqueEvapCondNames,
623 38 : state.dataIPShortCut->cAlphaArgs(1),
624 : cCurrentModuleObject,
625 38 : state.dataIPShortCut->cAlphaFieldNames(1),
626 : ErrorsFound);
627 38 : thisEvapCooler.Name = state.dataIPShortCut->cAlphaArgs(1);
628 38 : thisEvapCooler.evapCoolerType = EvapCoolerType::IndirectRDDSpecial; //'EvaporativeCooler:Indirect:ResearchSpecial'
629 :
630 38 : thisEvapCooler.Schedule = state.dataIPShortCut->cAlphaArgs(2);
631 38 : if (state.dataIPShortCut->lAlphaFieldBlanks(2)) {
632 0 : thisEvapCooler.availSched = Sched::GetScheduleAlwaysOn(state);
633 38 : } else if ((thisEvapCooler.availSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(2))) == nullptr) {
634 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(2), state.dataIPShortCut->cAlphaArgs(2));
635 0 : ErrorsFound = true;
636 : }
637 :
638 38 : thisEvapCooler.InletNode = GetOnlySingleNode(state,
639 38 : state.dataIPShortCut->cAlphaArgs(7),
640 : ErrorsFound,
641 : DataLoopNode::ConnectionObjectType::EvaporativeCoolerIndirectResearchSpecial,
642 38 : state.dataIPShortCut->cAlphaArgs(1),
643 : DataLoopNode::NodeFluidType::Air,
644 : DataLoopNode::ConnectionType::Inlet,
645 : NodeInputManager::CompFluidStream::Primary,
646 : DataLoopNode::ObjectIsNotParent);
647 :
648 76 : thisEvapCooler.OutletNode = GetOnlySingleNode(state,
649 38 : state.dataIPShortCut->cAlphaArgs(8),
650 : ErrorsFound,
651 : DataLoopNode::ConnectionObjectType::EvaporativeCoolerIndirectResearchSpecial,
652 38 : state.dataIPShortCut->cAlphaArgs(1),
653 : DataLoopNode::NodeFluidType::Air,
654 : DataLoopNode::ConnectionType::Outlet,
655 : NodeInputManager::CompFluidStream::Primary,
656 : DataLoopNode::ObjectIsNotParent);
657 :
658 76 : BranchNodeConnections::TestCompSet(state,
659 : cCurrentModuleObject,
660 38 : state.dataIPShortCut->cAlphaArgs(1),
661 38 : state.dataIPShortCut->cAlphaArgs(7),
662 38 : state.dataIPShortCut->cAlphaArgs(8),
663 : "Evap Air Nodes");
664 :
665 38 : if (state.dataIPShortCut->lAlphaFieldBlanks(9)) {
666 0 : thisEvapCooler.SecondaryInletNode = 0;
667 : } else {
668 76 : thisEvapCooler.SecondaryInletNode = GetOnlySingleNode(state,
669 38 : state.dataIPShortCut->cAlphaArgs(9),
670 : ErrorsFound,
671 : DataLoopNode::ConnectionObjectType::EvaporativeCoolerIndirectResearchSpecial,
672 38 : state.dataIPShortCut->cAlphaArgs(1),
673 : DataLoopNode::NodeFluidType::Air,
674 : DataLoopNode::ConnectionType::Inlet,
675 : NodeInputManager::CompFluidStream::Secondary,
676 : DataLoopNode::ObjectIsNotParent);
677 : }
678 :
679 38 : if (state.dataIPShortCut->lAlphaFieldBlanks(10)) {
680 0 : thisEvapCooler.SecondaryOutletNode = 0;
681 : } else {
682 76 : thisEvapCooler.SecondaryOutletNode = GetOnlySingleNode(state,
683 38 : state.dataIPShortCut->cAlphaArgs(10),
684 : ErrorsFound,
685 : DataLoopNode::ConnectionObjectType::EvaporativeCoolerIndirectResearchSpecial,
686 38 : state.dataIPShortCut->cAlphaArgs(1),
687 : DataLoopNode::NodeFluidType::Air,
688 : DataLoopNode::ConnectionType::Outlet,
689 : NodeInputManager::CompFluidStream::Secondary,
690 : DataLoopNode::ObjectIsNotParent);
691 : }
692 :
693 38 : thisEvapCooler.EvapControlNodeNum = GetOnlySingleNode(state,
694 38 : state.dataIPShortCut->cAlphaArgs(11),
695 : ErrorsFound,
696 : DataLoopNode::ConnectionObjectType::EvaporativeCoolerIndirectResearchSpecial,
697 38 : state.dataIPShortCut->cAlphaArgs(1),
698 : DataLoopNode::NodeFluidType::Air,
699 : DataLoopNode::ConnectionType::Sensor,
700 : NodeInputManager::CompFluidStream::Primary,
701 : DataLoopNode::ObjectIsNotParent);
702 :
703 38 : thisEvapCooler.TertiaryInletNode = GetOnlySingleNode(state,
704 38 : state.dataIPShortCut->cAlphaArgs(12),
705 : ErrorsFound,
706 : DataLoopNode::ConnectionObjectType::EvaporativeCoolerIndirectResearchSpecial,
707 38 : state.dataIPShortCut->cAlphaArgs(1),
708 : DataLoopNode::NodeFluidType::Air,
709 : DataLoopNode::ConnectionType::Inlet,
710 : NodeInputManager::CompFluidStream::Tertiary,
711 : DataLoopNode::ObjectIsNotParent);
712 :
713 38 : thisEvapCooler.EvapWaterSupplyName = state.dataIPShortCut->cAlphaArgs(13);
714 38 : if (state.dataIPShortCut->lAlphaFieldBlanks(13)) {
715 38 : thisEvapCooler.EvapWaterSupplyMode = WaterSupply::FromMains;
716 : } else {
717 0 : thisEvapCooler.EvapWaterSupplyMode = WaterSupply::FromTank;
718 0 : WaterManager::SetupTankDemandComponent(state,
719 : thisEvapCooler.Name,
720 : cCurrentModuleObject,
721 : thisEvapCooler.EvapWaterSupplyName,
722 : ErrorsFound,
723 0 : thisEvapCooler.EvapWaterSupTankID,
724 0 : thisEvapCooler.EvapWaterTankDemandARRID);
725 : }
726 :
727 : // input the numerical data
728 38 : thisEvapCooler.WetCoilMaxEfficiency = state.dataIPShortCut->rNumericArgs(1);
729 38 : if (state.dataIPShortCut->lNumericFieldBlanks(2)) {
730 34 : thisEvapCooler.DryCoilMaxEfficiency = 0.0;
731 : } else {
732 4 : thisEvapCooler.DryCoilMaxEfficiency = state.dataIPShortCut->rNumericArgs(2);
733 : }
734 38 : thisEvapCooler.IndirectRecircPumpPower = state.dataIPShortCut->rNumericArgs(3);
735 38 : thisEvapCooler.RecircPumpSizingFactor = state.dataIPShortCut->rNumericArgs(4);
736 38 : thisEvapCooler.IndirectVolFlowRate = state.dataIPShortCut->rNumericArgs(5);
737 38 : thisEvapCooler.IndirectVolFlowScalingFactor = state.dataIPShortCut->rNumericArgs(6);
738 38 : thisEvapCooler.IndirectFanPower = state.dataIPShortCut->rNumericArgs(7);
739 38 : thisEvapCooler.FanSizingSpecificPower = state.dataIPShortCut->rNumericArgs(8);
740 38 : thisEvapCooler.DesVolFlowRate = state.dataIPShortCut->rNumericArgs(9);
741 38 : thisEvapCooler.DPBoundFactor = state.dataIPShortCut->rNumericArgs(10);
742 38 : if (state.dataIPShortCut->lNumericFieldBlanks(11)) {
743 24 : thisEvapCooler.DriftFraction = 0.0;
744 : } else {
745 14 : thisEvapCooler.DriftFraction = state.dataIPShortCut->rNumericArgs(11);
746 : }
747 38 : if (state.dataIPShortCut->lNumericFieldBlanks(12)) {
748 28 : thisEvapCooler.BlowDownRatio = 0.0;
749 : } else {
750 10 : thisEvapCooler.BlowDownRatio = state.dataIPShortCut->rNumericArgs(12);
751 : }
752 42 : if (state.dataIPShortCut->lNumericFieldBlanks(2) || state.dataIPShortCut->lNumericFieldBlanks(13) ||
753 42 : state.dataIPShortCut->lNumericFieldBlanks(14) || state.dataIPShortCut->lNumericFieldBlanks(15)) {
754 34 : thisEvapCooler.EvapCoolerOperationControlFlag = false;
755 : } else {
756 8 : if (!state.dataIPShortCut->lNumericFieldBlanks(2) && !state.dataIPShortCut->lNumericFieldBlanks(13) &&
757 8 : !state.dataIPShortCut->lNumericFieldBlanks(14) && !state.dataIPShortCut->lNumericFieldBlanks(15)) {
758 4 : thisEvapCooler.EvapCoolerOperationControlFlag = true;
759 4 : thisEvapCooler.MinOATDBEvapCooler = state.dataIPShortCut->rNumericArgs(13);
760 4 : thisEvapCooler.MaxOATWBEvapCooler = state.dataIPShortCut->rNumericArgs(14);
761 4 : thisEvapCooler.MaxOATDBEvapCooler = state.dataIPShortCut->rNumericArgs(15);
762 : } else {
763 0 : thisEvapCooler.EvapCoolerOperationControlFlag = false;
764 : }
765 : }
766 38 : thisEvapCooler.WetbulbEffecCurve = Curve::GetCurve(state, state.dataIPShortCut->cAlphaArgs(3));
767 38 : thisEvapCooler.DrybulbEffecCurve = Curve::GetCurve(state, state.dataIPShortCut->cAlphaArgs(4));
768 38 : thisEvapCooler.PumpPowerModifierCurve = Curve::GetCurve(state, state.dataIPShortCut->cAlphaArgs(5));
769 38 : thisEvapCooler.FanPowerModifierCurve = Curve::GetCurve(state, state.dataIPShortCut->cAlphaArgs(6));
770 :
771 76 : SetupOutputVariable(state,
772 : "Evaporative Cooler Total Stage Effectiveness",
773 : Constant::Units::None,
774 38 : thisEvapCooler.StageEff,
775 : OutputProcessor::TimeStepType::System,
776 : OutputProcessor::StoreType::Average,
777 38 : thisEvapCooler.Name);
778 76 : SetupOutputVariable(state,
779 : "Evaporative Cooler Part Load Ratio",
780 : Constant::Units::None,
781 38 : thisEvapCooler.PartLoadFract,
782 : OutputProcessor::TimeStepType::System,
783 : OutputProcessor::StoreType::Average,
784 38 : thisEvapCooler.Name);
785 :
786 38 : SetupOutputVariable(state,
787 : "Evaporative Cooler Dewpoint Bound Status",
788 : Constant::Units::None,
789 38 : thisEvapCooler.DewPointBoundFlag,
790 : OutputProcessor::TimeStepType::System,
791 : OutputProcessor::StoreType::Average,
792 38 : thisEvapCooler.Name);
793 38 : SetupOutputVariable(state,
794 : "Evaporative Cooler Operating Mode Status",
795 : Constant::Units::None,
796 38 : thisEvapCooler.IECOperatingStatus,
797 : OutputProcessor::TimeStepType::System,
798 : OutputProcessor::StoreType::Average,
799 38 : thisEvapCooler.Name);
800 :
801 : } // end of Indirect Research Special cooler input loop
802 :
803 17 : cCurrentModuleObject = "EvaporativeCooler:Direct:ResearchSpecial";
804 41 : for (int DirectEvapCoolNum = 1; DirectEvapCoolNum <= NumDirectResearchSpecialEvapCool; ++DirectEvapCoolNum) {
805 24 : int EvapCoolNum = NumDirectEvapCool + NumDryInDirectEvapCool + NumWetInDirectEvapCool + NumRDDEvapCool + DirectEvapCoolNum;
806 24 : auto &thisEvapCooler = EvapCond(EvapCoolNum);
807 48 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
808 : cCurrentModuleObject,
809 : DirectEvapCoolNum,
810 24 : state.dataIPShortCut->cAlphaArgs,
811 : NumAlphas,
812 24 : state.dataIPShortCut->rNumericArgs,
813 : NumNums,
814 : IOStat,
815 24 : state.dataIPShortCut->lNumericFieldBlanks,
816 24 : state.dataIPShortCut->lAlphaFieldBlanks,
817 24 : state.dataIPShortCut->cAlphaFieldNames,
818 24 : state.dataIPShortCut->cNumericFieldNames);
819 :
820 24 : ErrorObjectHeader eoh{routineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
821 24 : GlobalNames::VerifyUniqueInterObjectName(state,
822 : UniqueEvapCondNames,
823 24 : state.dataIPShortCut->cAlphaArgs(1),
824 : cCurrentModuleObject,
825 24 : state.dataIPShortCut->cAlphaFieldNames(1),
826 : ErrorsFound);
827 24 : thisEvapCooler.Name = state.dataIPShortCut->cAlphaArgs(1);
828 24 : thisEvapCooler.evapCoolerType = EvapCoolerType::DirectResearchSpecial;
829 :
830 24 : thisEvapCooler.Schedule = state.dataIPShortCut->cAlphaArgs(2);
831 24 : if (state.dataIPShortCut->lAlphaFieldBlanks(2)) {
832 0 : thisEvapCooler.availSched = Sched::GetScheduleAlwaysOn(state);
833 24 : } else if ((thisEvapCooler.availSched = Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(2))) == nullptr) {
834 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(2), state.dataIPShortCut->cAlphaArgs(2));
835 0 : ErrorsFound = true;
836 : }
837 :
838 24 : thisEvapCooler.InletNode = GetOnlySingleNode(state,
839 24 : state.dataIPShortCut->cAlphaArgs(5),
840 : ErrorsFound,
841 : DataLoopNode::ConnectionObjectType::EvaporativeCoolerDirectResearchSpecial,
842 24 : state.dataIPShortCut->cAlphaArgs(1),
843 : DataLoopNode::NodeFluidType::Air,
844 : DataLoopNode::ConnectionType::Inlet,
845 : NodeInputManager::CompFluidStream::Primary,
846 : DataLoopNode::ObjectIsNotParent);
847 :
848 48 : thisEvapCooler.OutletNode = GetOnlySingleNode(state,
849 24 : state.dataIPShortCut->cAlphaArgs(6),
850 : ErrorsFound,
851 : DataLoopNode::ConnectionObjectType::EvaporativeCoolerDirectResearchSpecial,
852 24 : state.dataIPShortCut->cAlphaArgs(1),
853 : DataLoopNode::NodeFluidType::Air,
854 : DataLoopNode::ConnectionType::Outlet,
855 : NodeInputManager::CompFluidStream::Primary,
856 : DataLoopNode::ObjectIsNotParent);
857 :
858 48 : BranchNodeConnections::TestCompSet(state,
859 : cCurrentModuleObject,
860 24 : state.dataIPShortCut->cAlphaArgs(1),
861 24 : state.dataIPShortCut->cAlphaArgs(5),
862 24 : state.dataIPShortCut->cAlphaArgs(6),
863 : "Evap Air Nodes");
864 :
865 24 : thisEvapCooler.EvapControlNodeNum = GetOnlySingleNode(state,
866 24 : state.dataIPShortCut->cAlphaArgs(7),
867 : ErrorsFound,
868 : DataLoopNode::ConnectionObjectType::EvaporativeCoolerDirectResearchSpecial,
869 24 : state.dataIPShortCut->cAlphaArgs(1),
870 : DataLoopNode::NodeFluidType::Air,
871 : DataLoopNode::ConnectionType::Sensor,
872 : NodeInputManager::CompFluidStream::Primary,
873 : DataLoopNode::ObjectIsNotParent);
874 :
875 24 : thisEvapCooler.EvapWaterSupplyName = state.dataIPShortCut->cAlphaArgs(8);
876 :
877 24 : if (state.dataIPShortCut->lAlphaFieldBlanks(8)) {
878 24 : thisEvapCooler.EvapWaterSupplyMode = WaterSupply::FromMains;
879 : } else {
880 0 : thisEvapCooler.EvapWaterSupplyMode = WaterSupply::FromTank;
881 0 : WaterManager::SetupTankDemandComponent(state,
882 : thisEvapCooler.Name,
883 : cCurrentModuleObject,
884 : thisEvapCooler.EvapWaterSupplyName,
885 : ErrorsFound,
886 0 : thisEvapCooler.EvapWaterSupTankID,
887 0 : thisEvapCooler.EvapWaterTankDemandARRID);
888 : }
889 24 : thisEvapCooler.DirectEffectiveness = state.dataIPShortCut->rNumericArgs(1);
890 :
891 24 : thisEvapCooler.DesVolFlowRate = state.dataIPShortCut->rNumericArgs(2);
892 24 : thisEvapCooler.RecircPumpPower = state.dataIPShortCut->rNumericArgs(3);
893 24 : thisEvapCooler.RecircPumpSizingFactor = state.dataIPShortCut->rNumericArgs(4);
894 24 : if (state.dataIPShortCut->lNumericFieldBlanks(5)) {
895 0 : thisEvapCooler.DriftFraction = 0.0;
896 : } else {
897 24 : thisEvapCooler.DriftFraction = state.dataIPShortCut->rNumericArgs(5);
898 : }
899 24 : if (state.dataIPShortCut->lNumericFieldBlanks(6)) {
900 0 : thisEvapCooler.BlowDownRatio = 0.0;
901 : } else {
902 24 : thisEvapCooler.BlowDownRatio = state.dataIPShortCut->rNumericArgs(6);
903 : }
904 28 : if (state.dataIPShortCut->lNumericFieldBlanks(7) || state.dataIPShortCut->lNumericFieldBlanks(8) ||
905 4 : state.dataIPShortCut->lNumericFieldBlanks(9)) {
906 20 : thisEvapCooler.EvapCoolerOperationControlFlag = false;
907 : } else {
908 8 : if (!state.dataIPShortCut->lNumericFieldBlanks(7) && !state.dataIPShortCut->lNumericFieldBlanks(8) &&
909 4 : !state.dataIPShortCut->lNumericFieldBlanks(9)) {
910 4 : thisEvapCooler.EvapCoolerOperationControlFlag = true;
911 4 : thisEvapCooler.MinOATDBEvapCooler = state.dataIPShortCut->rNumericArgs(7);
912 4 : thisEvapCooler.MaxOATWBEvapCooler = state.dataIPShortCut->rNumericArgs(8);
913 4 : thisEvapCooler.MaxOATDBEvapCooler = state.dataIPShortCut->rNumericArgs(9);
914 : } else {
915 0 : thisEvapCooler.EvapCoolerOperationControlFlag = false;
916 : }
917 : }
918 24 : thisEvapCooler.WetbulbEffecCurve = Curve::GetCurve(state, state.dataIPShortCut->cAlphaArgs(3));
919 24 : thisEvapCooler.PumpPowerModifierCurve = Curve::GetCurve(state, state.dataIPShortCut->cAlphaArgs(4));
920 :
921 48 : SetupOutputVariable(state,
922 : "Evaporative Cooler Stage Effectiveness",
923 : Constant::Units::None,
924 24 : thisEvapCooler.StageEff,
925 : OutputProcessor::TimeStepType::System,
926 : OutputProcessor::StoreType::Average,
927 24 : thisEvapCooler.Name);
928 : }
929 :
930 17 : if (ErrorsFound) {
931 0 : ShowFatalError(state, "Errors found in processing input for evaporative coolers");
932 : }
933 :
934 120 : for (int EvapCoolNum = 1; EvapCoolNum <= state.dataEvapCoolers->NumEvapCool; ++EvapCoolNum) {
935 103 : auto &thisEvapCooler = EvapCond(EvapCoolNum);
936 : // Setup Report variables for the Evap Coolers
937 206 : SetupOutputVariable(state,
938 : "Evaporative Cooler Electricity Energy",
939 : Constant::Units::J,
940 103 : thisEvapCooler.EvapCoolerEnergy,
941 : OutputProcessor::TimeStepType::System,
942 : OutputProcessor::StoreType::Sum,
943 103 : thisEvapCooler.Name,
944 : Constant::eResource::Electricity,
945 : OutputProcessor::Group::HVAC,
946 : OutputProcessor::EndUseCat::Cooling);
947 206 : SetupOutputVariable(state,
948 : "Evaporative Cooler Electricity Rate",
949 : Constant::Units::W,
950 103 : thisEvapCooler.EvapCoolerPower,
951 : OutputProcessor::TimeStepType::System,
952 : OutputProcessor::StoreType::Average,
953 103 : thisEvapCooler.Name);
954 : // this next report variable is setup differently depending on how the water should be metered here.
955 103 : if (thisEvapCooler.EvapWaterSupplyMode == WaterSupply::FromMains) {
956 206 : SetupOutputVariable(state,
957 : "Evaporative Cooler Water Volume",
958 : Constant::Units::m3,
959 103 : thisEvapCooler.EvapWaterConsump,
960 : OutputProcessor::TimeStepType::System,
961 : OutputProcessor::StoreType::Sum,
962 103 : thisEvapCooler.Name,
963 : Constant::eResource::Water,
964 : OutputProcessor::Group::HVAC,
965 : OutputProcessor::EndUseCat::Cooling);
966 206 : SetupOutputVariable(state,
967 : "Evaporative Cooler Mains Water Volume",
968 : Constant::Units::m3,
969 103 : thisEvapCooler.EvapWaterConsump,
970 : OutputProcessor::TimeStepType::System,
971 : OutputProcessor::StoreType::Sum,
972 103 : thisEvapCooler.Name,
973 : Constant::eResource::MainsWater,
974 : OutputProcessor::Group::HVAC,
975 : OutputProcessor::EndUseCat::Cooling);
976 :
977 0 : } else if (thisEvapCooler.EvapWaterSupplyMode == WaterSupply::FromTank) {
978 0 : SetupOutputVariable(state,
979 : "Evaporative Cooler Storage Tank Water Volume",
980 : Constant::Units::m3,
981 0 : thisEvapCooler.EvapWaterConsump,
982 : OutputProcessor::TimeStepType::System,
983 : OutputProcessor::StoreType::Sum,
984 0 : thisEvapCooler.Name,
985 : Constant::eResource::Water,
986 : OutputProcessor::Group::HVAC,
987 : OutputProcessor::EndUseCat::Cooling);
988 0 : SetupOutputVariable(state,
989 : "Evaporative Cooler Starved Water Volume",
990 : Constant::Units::m3,
991 0 : thisEvapCooler.EvapWaterStarvMakup,
992 : OutputProcessor::TimeStepType::System,
993 : OutputProcessor::StoreType::Sum,
994 0 : thisEvapCooler.Name,
995 : Constant::eResource::Water,
996 : OutputProcessor::Group::HVAC,
997 : OutputProcessor::EndUseCat::Cooling);
998 0 : SetupOutputVariable(state,
999 : "Evaporative Cooler Starved Mains Water Volume",
1000 : Constant::Units::m3,
1001 0 : thisEvapCooler.EvapWaterStarvMakup,
1002 : OutputProcessor::TimeStepType::System,
1003 : OutputProcessor::StoreType::Sum,
1004 0 : thisEvapCooler.Name,
1005 : Constant::eResource::MainsWater,
1006 : OutputProcessor::Group::HVAC,
1007 : OutputProcessor::EndUseCat::Cooling);
1008 : }
1009 : }
1010 17 : }
1011 :
1012 5303237 : void InitEvapCooler(EnergyPlusData &state, int const EvapCoolNum)
1013 : {
1014 :
1015 : // SUBROUTINE INFORMATION:
1016 : // AUTHOR Richard J. Liesen
1017 : // DATE WRITTEN October 2000
1018 : // MODIFIED B. Griffith, May 2009, added EMS setpoint check
1019 :
1020 : // PURPOSE OF THIS SUBROUTINE:
1021 : // This subroutine is for initializations of the EvapCooler Components.
1022 :
1023 : // METHODOLOGY EMPLOYED:
1024 : // Uses the status flags to trigger events.
1025 :
1026 : // Using/Aliasing
1027 5303237 : auto &evapCond = state.dataEvapCoolers->EvapCond(EvapCoolNum);
1028 :
1029 : // Check that setpoint is active
1030 5303237 : if (!state.dataGlobal->SysSizingCalc && state.dataEvapCoolers->MySetPointCheckFlag && state.dataHVACGlobal->DoSetPointTest) {
1031 120 : for (int EvapUnitNum = 1; EvapUnitNum <= state.dataEvapCoolers->NumEvapCool; ++EvapUnitNum) {
1032 :
1033 : // only check evap coolers that are supposed to have a control node
1034 103 : if ((evapCond.evapCoolerType != EvapCoolerType::IndirectRDDSpecial) &&
1035 69 : (evapCond.evapCoolerType != EvapCoolerType::DirectResearchSpecial)) {
1036 61 : continue;
1037 : }
1038 :
1039 42 : int ControlNode = state.dataEvapCoolers->EvapCond(EvapUnitNum).EvapControlNodeNum;
1040 42 : if (ControlNode > 0) {
1041 42 : if (state.dataLoopNodes->Node(ControlNode).TempSetPoint == DataLoopNode::SensedNodeFlagValue) {
1042 0 : if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
1043 0 : ShowSevereError(state, format("Missing temperature setpoint for Evap Cooler unit {}", evapCond.Name));
1044 0 : ShowContinueError(state, " use a Setpoint Manager to establish a setpoint at the unit control node.");
1045 : } else {
1046 0 : bool localSetPointCheck = false;
1047 0 : EMSManager::CheckIfNodeSetPointManagedByEMS(state, ControlNode, HVAC::CtrlVarType::Temp, localSetPointCheck);
1048 0 : state.dataLoopNodes->NodeSetpointCheck(ControlNode).needsSetpointChecking = false;
1049 : // Let it slide apparently
1050 0 : if (localSetPointCheck) {
1051 0 : ShowSevereError(state, format("Missing temperature setpoint for Evap Cooler unit {}", evapCond.Name));
1052 0 : ShowContinueError(state, " use a Setpoint Manager to establish a setpoint at the unit control node.");
1053 0 : ShowContinueError(state, " or use an EMS actuator to establish a setpoint at the unit control node.");
1054 : }
1055 : }
1056 : }
1057 : }
1058 : }
1059 17 : state.dataEvapCoolers->MySetPointCheckFlag = false;
1060 : }
1061 :
1062 5303237 : if (!state.dataGlobal->SysSizingCalc && evapCond.MySizeFlag) {
1063 : // for each cooler, do the sizing once.
1064 103 : SizeEvapCooler(state, EvapCoolNum);
1065 103 : evapCond.MySizeFlag = false;
1066 : }
1067 :
1068 : // Do the following initializations (every time step): This should be the info from
1069 : // the previous components outlets or the node data in this section.
1070 :
1071 : // Transfer the node data to EvapCond data structure
1072 5303237 : auto &thisInletNode = state.dataLoopNodes->Node(evapCond.InletNode);
1073 :
1074 5303237 : Real64 const RhoAir = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, thisInletNode.Temp, thisInletNode.HumRat);
1075 :
1076 : // set the volume flow rates from the input mass flow rates
1077 5303237 : evapCond.VolFlowRate = thisInletNode.MassFlowRate / RhoAir;
1078 :
1079 : // Calculate the entering wet bulb temperature for inlet conditions
1080 5303237 : evapCond.InletWetBulbTemp = Psychrometrics::PsyTwbFnTdbWPb(state, thisInletNode.Temp, thisInletNode.HumRat, state.dataEnvrn->OutBaroPress);
1081 :
1082 : // Set all of the inlet mass flow variables from the nodes
1083 5303237 : evapCond.InletMassFlowRate = thisInletNode.MassFlowRate;
1084 5303237 : evapCond.InletMassFlowRateMaxAvail = thisInletNode.MassFlowRateMaxAvail;
1085 5303237 : evapCond.InletMassFlowRateMinAvail = thisInletNode.MassFlowRateMinAvail;
1086 : // Set all of the inlet state variables from the inlet nodes
1087 5303237 : evapCond.InletTemp = thisInletNode.Temp;
1088 5303237 : evapCond.InletHumRat = thisInletNode.HumRat;
1089 5303237 : evapCond.InletEnthalpy = thisInletNode.Enthalpy;
1090 5303237 : evapCond.InletPressure = thisInletNode.Press;
1091 : // Set default outlet state to inlet states(?)
1092 5303237 : evapCond.OutletTemp = evapCond.InletTemp;
1093 5303237 : evapCond.OutletHumRat = evapCond.InletHumRat;
1094 5303237 : evapCond.OutletEnthalpy = evapCond.InletEnthalpy;
1095 5303237 : evapCond.OutletPressure = evapCond.InletPressure;
1096 :
1097 5303237 : evapCond.OutletMassFlowRate = evapCond.InletMassFlowRate;
1098 5303237 : evapCond.OutletMassFlowRateMaxAvail = evapCond.InletMassFlowRateMaxAvail;
1099 5303237 : evapCond.OutletMassFlowRateMinAvail = evapCond.InletMassFlowRateMinAvail;
1100 :
1101 : // Set all of the secondary inlet mass flow variables from the nodes
1102 5303237 : if (evapCond.SecondaryInletNode != 0) {
1103 2322163 : auto const &thisSecInletNode = state.dataLoopNodes->Node(evapCond.SecondaryInletNode);
1104 2322163 : evapCond.SecInletMassFlowRate = thisSecInletNode.MassFlowRate;
1105 2322163 : evapCond.SecInletMassFlowRateMaxAvail = thisSecInletNode.MassFlowRateMaxAvail;
1106 2322163 : evapCond.SecInletMassFlowRateMinAvail = thisSecInletNode.MassFlowRateMinAvail;
1107 2322163 : evapCond.SecInletTemp = thisSecInletNode.Temp;
1108 2322163 : evapCond.SecInletHumRat = thisSecInletNode.HumRat;
1109 2322163 : evapCond.SecInletEnthalpy = thisSecInletNode.Enthalpy;
1110 2322163 : evapCond.SecInletPressure = thisSecInletNode.Press;
1111 : } else {
1112 2981074 : evapCond.SecInletMassFlowRate = evapCond.IndirectVolFlowRate * state.dataEnvrn->OutAirDensity;
1113 2981074 : evapCond.SecInletMassFlowRateMaxAvail = evapCond.IndirectVolFlowRate * state.dataEnvrn->OutAirDensity;
1114 2981074 : evapCond.SecInletMassFlowRateMinAvail = 0.0;
1115 2981074 : evapCond.SecInletTemp = state.dataEnvrn->OutDryBulbTemp;
1116 2981074 : evapCond.SecInletHumRat =
1117 2981074 : Psychrometrics::PsyWFnTdbTwbPb(state, state.dataEnvrn->OutDryBulbTemp, state.dataEnvrn->OutWetBulbTemp, state.dataEnvrn->OutBaroPress);
1118 2981074 : evapCond.SecInletEnthalpy = state.dataEnvrn->OutEnthalpy;
1119 2981074 : evapCond.SecInletPressure = state.dataEnvrn->OutBaroPress;
1120 : }
1121 : // Set the energy consumption to zero each time through for reporting
1122 5303237 : evapCond.EvapCoolerEnergy = 0.0;
1123 5303237 : evapCond.EvapCoolerPower = 0.0;
1124 5303237 : evapCond.DewPointBoundFlag = 0;
1125 : // Set the water consumption to zero each time through for reporting
1126 5303237 : evapCond.EvapWaterConsumpRate = 0.0;
1127 5303237 : evapCond.EvapWaterConsump = 0.0;
1128 5303237 : evapCond.EvapWaterStarvMakup = 0.0;
1129 :
1130 : // Set the Saturation and Stage Efficiency to zero each time through for reporting
1131 5303237 : evapCond.StageEff = 0.0;
1132 5303237 : evapCond.SatEff = 0.0;
1133 :
1134 : // These initializations are done every iteration
1135 5303237 : int OutNode = evapCond.OutletNode;
1136 5303237 : int ControlNode = evapCond.EvapControlNodeNum;
1137 5303237 : evapCond.IECOperatingStatus = 0;
1138 :
1139 5303237 : if (ControlNode == 0) {
1140 389475 : evapCond.DesiredOutletTemp = 0.0;
1141 4913762 : } else if (ControlNode == OutNode) {
1142 2810418 : evapCond.DesiredOutletTemp = state.dataLoopNodes->Node(ControlNode).TempSetPoint;
1143 : } else {
1144 2103344 : evapCond.DesiredOutletTemp = state.dataLoopNodes->Node(ControlNode).TempSetPoint -
1145 2103344 : (state.dataLoopNodes->Node(ControlNode).Temp - state.dataLoopNodes->Node(OutNode).Temp);
1146 : }
1147 5303237 : }
1148 :
1149 103 : void SizeEvapCooler(EnergyPlusData &state, int const EvapCoolNum)
1150 : {
1151 :
1152 : // SUBROUTINE INFORMATION:
1153 : // AUTHOR B. Griffith
1154 : // DATE WRITTEN March 2009
1155 : // MODIFIED March 2014 Daeho Kang, Add sizing additional fields
1156 :
1157 : // PURPOSE OF THIS SUBROUTINE:
1158 : // Size calculations for Evap coolers
1159 : // currently just for secondary side of Research Special Indirect evap cooler
1160 :
1161 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1162 : bool IsAutoSize; // Indicator to autosize
1163 :
1164 : Real64 volFlowRateDes; // Autosized volume flow rate for reporting
1165 103 : std::string CompType; // for ease in getting objects
1166 :
1167 : // inits
1168 103 : bool CoolerOnOApath = false;
1169 103 : bool CoolerOnMainAirLoop = false;
1170 103 : Real64 IndirectVolFlowRateDes = 0.0; // Autosized volume flow rate for reporting
1171 103 : Real64 IndirectVolFlowRateUser = 0.0; // Hardsized volume flow rate for reporting
1172 103 : Real64 PadAreaDes = 0.0; // Autosized celdek pad area for reporting
1173 103 : Real64 PadAreaUser = 0.0; // Hardsized celdek pad area for reporting
1174 103 : Real64 PadDepthDes = 0.0; // Autosized celdek pad depth for reporting
1175 103 : Real64 PadDepthUser = 0.0; // Hardsized celdek pad depth for reporting
1176 :
1177 103 : auto &CurSysNum(state.dataSize->CurSysNum);
1178 103 : auto &CurZoneEqNum(state.dataSize->CurZoneEqNum);
1179 103 : auto &FinalSysSizing(state.dataSize->FinalSysSizing);
1180 103 : auto &EvapCond(state.dataEvapCoolers->EvapCond);
1181 103 : auto &thisEvapCond(EvapCond(EvapCoolNum));
1182 :
1183 103 : bool HardSizeNoDesRun = !((state.dataSize->SysSizingRunDone || state.dataSize->ZoneSizingRunDone));
1184 103 : bool SizingDesRunThisAirSys = false; // true if a particular air system had a Sizing:System object and system sizing done
1185 103 : bool SizingDesRunThisZone = false; // true if a particular zone had a Sizing:Zone object and zone sizing was done
1186 :
1187 103 : if (CurSysNum > 0) {
1188 51 : CheckThisAirSystemForSizing(state, CurSysNum, SizingDesRunThisAirSys);
1189 51 : if (SizingDesRunThisAirSys) {
1190 42 : HardSizeNoDesRun = false; // Check if design information is available
1191 : }
1192 : }
1193 103 : if (CurZoneEqNum > 0) {
1194 52 : CheckThisZoneForSizing(state, CurZoneEqNum, SizingDesRunThisZone);
1195 : // This next check was added during CppCheck corrections. This does not cause diffs
1196 : // because SizingDesRunThisZone is not used below this point.
1197 : // This check was commented to get back to original code and an issue is needed to correct.
1198 : // Why no check for zone equipment?
1199 : // if (SizingDesRunThisZone) {
1200 : // HardSizeNoDesRun = false; // Check if design information is available
1201 : //}
1202 : }
1203 : // I don't think the sizing logic is correct when it comes to autosized vs hard-sized inputs
1204 : // or input files that use Sizing:Zone or Sizing:System with autosized and/or hard-sized inputs
1205 :
1206 103 : CompType = evapCoolerTypeNames[static_cast<int>(thisEvapCond.evapCoolerType)];
1207 :
1208 : // Search once for the object on an air system
1209 103 : if (CurSysNum > 0) { // central system
1210 : // where is this cooler located, is it on OA system or main loop?
1211 : // search for this component in Air loop branches.
1212 102 : for (int AirSysBranchLoop = 1; AirSysBranchLoop <= state.dataAirSystemsData->PrimaryAirSystems(CurSysNum).NumBranches; ++AirSysBranchLoop) {
1213 258 : for (int BranchComp = 1; BranchComp <= state.dataAirSystemsData->PrimaryAirSystems(CurSysNum).Branch(AirSysBranchLoop).TotalComponents;
1214 : ++BranchComp) {
1215 :
1216 207 : if (Util::SameString(state.dataAirSystemsData->PrimaryAirSystems(CurSysNum).Branch(AirSysBranchLoop).Comp(BranchComp).Name,
1217 : thisEvapCond.Name)) {
1218 37 : CoolerOnMainAirLoop = true;
1219 : }
1220 : }
1221 : }
1222 51 : if (!CoolerOnMainAirLoop) {
1223 14 : CoolerOnOApath = true;
1224 : }
1225 : }
1226 :
1227 : // Start with the indirect volume flow rate
1228 103 : IsAutoSize = false;
1229 103 : if (thisEvapCond.IndirectVolFlowRate == DataSizing::AutoSize) {
1230 10 : IsAutoSize = true;
1231 : }
1232 103 : if (CurSysNum > 0 && !IsAutoSize && !SizingDesRunThisAirSys) {
1233 9 : HardSizeNoDesRun = true;
1234 : }
1235 103 : if (CurSysNum > 0) { // central system
1236 51 : if (!IsAutoSize && !SizingDesRunThisAirSys) {
1237 9 : if (thisEvapCond.IndirectVolFlowRate > 0.0) {
1238 2 : if (thisEvapCond.evapCoolerType == EvapCoolerType::IndirectCELDEKPAD ||
1239 1 : thisEvapCond.evapCoolerType == EvapCoolerType::IndirectWETCOIL ||
1240 0 : thisEvapCond.evapCoolerType == EvapCoolerType::IndirectRDDSpecial) {
1241 2 : BaseSizer::reportSizerOutput(
1242 : state, CompType, thisEvapCond.Name, "User-Specified Secondary Fan Flow Rate [m3/s]", thisEvapCond.IndirectVolFlowRate);
1243 : }
1244 : }
1245 : } else { // Autosize or hardsize with design data
1246 42 : CheckSysSizing(state, CompType, thisEvapCond.Name);
1247 42 : if (CoolerOnMainAirLoop) {
1248 28 : IndirectVolFlowRateDes = FinalSysSizing(CurSysNum).DesMainVolFlow;
1249 14 : } else if (CoolerOnOApath) {
1250 14 : IndirectVolFlowRateDes = max(FinalSysSizing(CurSysNum).DesOutAirVolFlow, 0.5 * FinalSysSizing(CurSysNum).DesMainVolFlow);
1251 : }
1252 : // apply scaling factor the secondary air fan flow rate
1253 42 : if (thisEvapCond.evapCoolerType == EvapCoolerType::IndirectRDDSpecial) {
1254 30 : IndirectVolFlowRateDes = IndirectVolFlowRateDes * thisEvapCond.IndirectVolFlowScalingFactor;
1255 : }
1256 : }
1257 52 : } else if (CurZoneEqNum > 0) { // zone equipment
1258 52 : if (!IsAutoSize && !SizingDesRunThisAirSys) { // this should be SizingDesRunThisZone
1259 52 : if (thisEvapCond.IndirectVolFlowRate > 0.0) {
1260 : // report for the indirect evap cooler types only
1261 20 : if (thisEvapCond.evapCoolerType == EvapCoolerType::IndirectCELDEKPAD ||
1262 16 : thisEvapCond.evapCoolerType == EvapCoolerType::IndirectWETCOIL ||
1263 8 : thisEvapCond.evapCoolerType == EvapCoolerType::IndirectRDDSpecial) {
1264 20 : BaseSizer::reportSizerOutput(
1265 : state, CompType, thisEvapCond.Name, "User-Specified Secondary Fan Flow Rate [m3/s]", thisEvapCond.IndirectVolFlowRate);
1266 : }
1267 : }
1268 : } else { // Autosize or hardsize with design data
1269 : // zone equip evap coolers
1270 0 : IndirectVolFlowRateDes = state.dataSize->FinalZoneSizing(CurZoneEqNum).DesCoolVolFlow;
1271 : // apply scaling factor the secondary air fan flow rate
1272 0 : if (thisEvapCond.evapCoolerType == EvapCoolerType::IndirectRDDSpecial) {
1273 0 : IndirectVolFlowRateDes = IndirectVolFlowRateDes * thisEvapCond.IndirectVolFlowScalingFactor;
1274 : }
1275 : }
1276 : }
1277 103 : if (!HardSizeNoDesRun) {
1278 94 : if (IsAutoSize) {
1279 10 : thisEvapCond.IndirectVolFlowRate = IndirectVolFlowRateDes;
1280 10 : if (thisEvapCond.evapCoolerType == EvapCoolerType::IndirectCELDEKPAD || thisEvapCond.evapCoolerType == EvapCoolerType::IndirectWETCOIL ||
1281 10 : thisEvapCond.evapCoolerType == EvapCoolerType::IndirectRDDSpecial) {
1282 10 : BaseSizer::reportSizerOutput(
1283 : state, CompType, thisEvapCond.Name, "Design Size Secondary Fan Flow Rate [m3/s]", thisEvapCond.IndirectVolFlowRate);
1284 : }
1285 : } else {
1286 84 : if (thisEvapCond.IndirectVolFlowRate > 0.0 && IndirectVolFlowRateDes > 0.0) {
1287 20 : IndirectVolFlowRateUser = thisEvapCond.IndirectVolFlowRate;
1288 20 : BaseSizer::reportSizerOutput(state,
1289 : "EvaporativeCooler:Indirect:ResearchSpecial",
1290 : thisEvapCond.Name,
1291 : "Design Size Secondary Fan Flow Rate [m3/s]",
1292 : IndirectVolFlowRateDes,
1293 : "User-Specified Secondary Fan Flow Rate [m3/s]",
1294 : IndirectVolFlowRateUser);
1295 20 : if (state.dataGlobal->DisplayExtraWarnings) {
1296 0 : if ((std::abs(IndirectVolFlowRateDes - IndirectVolFlowRateUser) / IndirectVolFlowRateUser) >
1297 0 : state.dataSize->AutoVsHardSizingThreshold) {
1298 0 : ShowMessage(state,
1299 0 : format("SizeEvaporativeCooler:Indirect:ResearchSpecial: Potential issue with equipment sizing for {}",
1300 0 : thisEvapCond.Name));
1301 0 : ShowContinueError(state, format("User-Specified Secondary Fan Flow Rate of {:.5R} [m3/s]", IndirectVolFlowRateUser));
1302 0 : ShowContinueError(state, format("differs from Design Size Secondary Fan Flow Rate of {:.5R} [m3/s]", IndirectVolFlowRateDes));
1303 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1304 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1305 : }
1306 : }
1307 : }
1308 : }
1309 : }
1310 :
1311 : // Next up the other volume flow rate
1312 103 : IsAutoSize = false;
1313 103 : if (thisEvapCond.DesVolFlowRate == DataSizing::AutoSize) {
1314 62 : IsAutoSize = true;
1315 : }
1316 103 : if (CurSysNum > 0 && !IsAutoSize && !SizingDesRunThisAirSys) {
1317 9 : HardSizeNoDesRun = true;
1318 : }
1319 103 : if (CurSysNum > 0) { // central system
1320 51 : if (!IsAutoSize && !SizingDesRunThisAirSys) {
1321 : // the .VolFlowRate variable wasn't reported to the eio in develop, so not doing it here
1322 : // if ( EvapCond( EvapCoolNum ).VolFlowRate > 0.0 ) {
1323 : // BaseSizer::reportSizerOutput( CompType, EvapCond( EvapCoolNum ).Name,
1324 : //"User-Specified Secondary Fan Flow Rate [m3/s]", EvapCond( EvapCoolNum ).VolFlowRate );
1325 : //}
1326 : } else { // Autosize or hardsize with design data
1327 42 : CheckSysSizing(state, CompType, thisEvapCond.Name);
1328 42 : if (CoolerOnMainAirLoop) {
1329 28 : volFlowRateDes = FinalSysSizing(CurSysNum).DesMainVolFlow;
1330 14 : } else if (CoolerOnOApath) {
1331 14 : volFlowRateDes = max(FinalSysSizing(CurSysNum).DesOutAirVolFlow, 0.5 * FinalSysSizing(CurSysNum).DesMainVolFlow);
1332 : }
1333 : // no scaling factor on the volFlowRate in develop, so not doing it here
1334 : }
1335 52 : } else if (CurZoneEqNum > 0) { // zone equipment
1336 : // zone equip evap coolers
1337 :
1338 : // this should be SizingDesRunThisZone
1339 52 : if (!IsAutoSize && !SizingDesRunThisAirSys) {
1340 : // the .VolFlowRate variable wasn't reported to the eio in develop, so not doing it here
1341 : // if ( EvapCond( EvapCoolNum ).VolFlowRate > 0.0 ) {
1342 : // BaseSizer::reportSizerOutput( "EvaporativeCooler:Indirect:ResearchSpecial", EvapCond( EvapCoolNum ).Name,
1343 : //"User-Specified Secondary Fan Flow Rate [m3/s]", EvapCond( EvapCoolNum ).VolFlowRate );
1344 : //}
1345 : } else { // Autosize or hardsize with design data
1346 20 : volFlowRateDes = state.dataSize->FinalZoneSizing(CurZoneEqNum).DesCoolVolFlow;
1347 : }
1348 :
1349 : } else { // zone equipment
1350 : // can't do zone equip evap coolers yet
1351 : }
1352 103 : if (!HardSizeNoDesRun) {
1353 94 : if (IsAutoSize) {
1354 62 : thisEvapCond.DesVolFlowRate = volFlowRateDes;
1355 : // only these two evap coolers has primary air design flow rate
1356 62 : if (thisEvapCond.evapCoolerType == EvapCoolerType::IndirectRDDSpecial) {
1357 38 : BaseSizer::reportSizerOutput(state,
1358 : "EvaporativeCooler:Indirect:ResearchSpecial",
1359 : thisEvapCond.Name,
1360 : "Primary Air Design Flow Rate [m3/s]",
1361 : thisEvapCond.DesVolFlowRate);
1362 38 : BaseSizer::reportSizerOutput(state,
1363 : "EvaporativeCooler:Indirect:ResearchSpecial",
1364 : thisEvapCond.Name,
1365 : "Secondary Air Design Flow Rate [m3/s]",
1366 : thisEvapCond.IndirectVolFlowRate);
1367 24 : } else if (thisEvapCond.evapCoolerType == EvapCoolerType::DirectResearchSpecial) {
1368 24 : BaseSizer::reportSizerOutput(state,
1369 : "EvaporativeCooler:Direct:ResearchSpecial",
1370 : thisEvapCond.Name,
1371 : "Primary Air Design Flow Rate [m3/s]",
1372 : thisEvapCond.DesVolFlowRate);
1373 : }
1374 : } else {
1375 : // the .VolFlowRate variable wasn't reported to the eio in develop, so not doing it here
1376 : // if ( EvapCond( EvapCoolNum ).IndirectVolFlowRate > 0.0 && IndirectVolFlowRateDes > 0.0 ) {
1377 : // IndirectVolFlowRateUser = EvapCond( EvapCoolNum ).IndirectVolFlowRate;
1378 : // BaseSizer::reportSizerOutput( "EvaporativeCooler:Indirect:ResearchSpecial", EvapCond( EvapCoolNum ).Name,
1379 : //"Design Size Secondary Fan Flow Rate [m3/s]", IndirectVolFlowRateDes,
1380 : //"User-Specified Secondary Fan Flow Rate [m3/s]", IndirectVolFlowRateUser );
1381 : // if ( DisplayExtraWarnings ) {
1382 : // if ( ( std::abs( IndirectVolFlowRateDes - IndirectVolFlowRateUser ) / IndirectVolFlowRateUser ) > AutoVsHardSizingThreshold ) {
1383 : // ShowMessage(state, format("SizeEvaporativeCooler:Indirect:ResearchSpecial: \nPotential issue with equipment sizing for {}", EvapCond(
1384 : // EvapCoolNum
1385 : // ).Name)); ShowContinueError(state, format("User-Specified Secondary Fan Flow Rate of {} [m3/s]", RoundSigDigits(
1386 : // IndirectVolFlowRateUser, 5 ))); ShowContinueError(state, format("differs from Design Size Secondary Fan Flow Rate of
1387 : // {:.5R}", IndirectVolFlowRateDes) + " [m3/s]" ); ShowContinueError(state, "This may, or may not, indicate mismatched component
1388 : // sizes." ); ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components." );
1389 : //}
1390 : //}
1391 : //}
1392 : }
1393 : }
1394 :
1395 103 : if (thisEvapCond.evapCoolerType == EvapCoolerType::DirectCELDEKPAD) {
1396 27 : IsAutoSize = false;
1397 27 : if (thisEvapCond.PadArea == DataSizing::AutoSize) {
1398 1 : IsAutoSize = true;
1399 : }
1400 27 : if (CurSysNum > 0 && !IsAutoSize && !SizingDesRunThisAirSys) {
1401 7 : HardSizeNoDesRun = true;
1402 : }
1403 27 : if (SizingDesRunThisAirSys) {
1404 0 : HardSizeNoDesRun = false; // Check if design information is available
1405 : }
1406 : // Design air flow rate
1407 27 : if (CurSysNum > 0) { // central system
1408 7 : if (!IsAutoSize && !SizingDesRunThisAirSys) {
1409 7 : HardSizeNoDesRun = true;
1410 7 : if (thisEvapCond.PadArea > 0.0) {
1411 7 : BaseSizer::reportSizerOutput(
1412 : state, "EvaporativeCooler:Direct:CelDekPad", thisEvapCond.Name, "User-Specified Celdek Pad Area [m2]", thisEvapCond.PadArea);
1413 : }
1414 : } else { // Autosize or hardsize with design data
1415 0 : CheckSysSizing(state, CompType, thisEvapCond.Name);
1416 0 : if (CoolerOnMainAirLoop) {
1417 0 : IndirectVolFlowRateDes = FinalSysSizing(CurSysNum).DesMainVolFlow;
1418 0 : } else if (CoolerOnOApath) {
1419 0 : IndirectVolFlowRateDes = std::max(FinalSysSizing(CurSysNum).DesOutAirVolFlow, 0.50 * FinalSysSizing(CurSysNum).DesMainVolFlow);
1420 : }
1421 : // Face air velocity of 3m/s is assumed
1422 0 : PadAreaDes = IndirectVolFlowRateDes / 3.0;
1423 : }
1424 20 : } else if (CurZoneEqNum > 0) { // zone equipment
1425 : // zone equip evap coolers
1426 :
1427 : // this should be SizingDesRunThisZone
1428 20 : if (!IsAutoSize && !SizingDesRunThisAirSys) {
1429 19 : HardSizeNoDesRun = true;
1430 19 : if (thisEvapCond.PadArea > 0.0) {
1431 : // report for the indirect evap cooler types only
1432 19 : BaseSizer::reportSizerOutput(
1433 : state, "EvaporativeCooler:Direct:CelDekPad", thisEvapCond.Name, "User-Specified Celdek Pad Area [m2]", thisEvapCond.PadArea);
1434 : }
1435 : } else { // Autosize or hardsize with design data
1436 : // zone equip evap coolers
1437 1 : IndirectVolFlowRateDes = state.dataSize->FinalZoneSizing(CurZoneEqNum).DesCoolVolFlow;
1438 : // Face air velocity of 3m/s is assumed
1439 1 : PadAreaDes = IndirectVolFlowRateDes / 3.0;
1440 : }
1441 : } else {
1442 : }
1443 :
1444 27 : if (!HardSizeNoDesRun) {
1445 1 : if (IsAutoSize) {
1446 1 : thisEvapCond.PadArea = PadAreaDes;
1447 1 : BaseSizer::reportSizerOutput(
1448 : state, "EvaporativeCooler:Direct:CelDekPad", thisEvapCond.Name, "Design Size Celdek Pad Area [m2]", PadAreaDes);
1449 : } else {
1450 0 : if (thisEvapCond.PadArea > 0.0 && PadAreaDes > 0.0) {
1451 0 : PadAreaUser = thisEvapCond.PadArea;
1452 0 : BaseSizer::reportSizerOutput(state,
1453 : "EvaporativeCooler:Direct:CelDekPad",
1454 : thisEvapCond.Name,
1455 : "Design Size Celdek Pad Area [m2]",
1456 : PadAreaDes,
1457 : "User-Specified Celdek Pad Area [m2]",
1458 : PadAreaUser);
1459 0 : if (state.dataGlobal->DisplayExtraWarnings) {
1460 0 : if ((std::abs(PadAreaDes - PadAreaUser) / PadAreaUser) > state.dataSize->AutoVsHardSizingThreshold) {
1461 0 : ShowMessage(
1462 : state,
1463 0 : format("SizeEvaporativeCooler:Direct:CelDekPad: Potential issue with equipment sizing for {}", thisEvapCond.Name));
1464 0 : ShowContinueError(state, format("User-Specified Celdek Pad Area of{:.2R} [m2]", PadAreaUser));
1465 0 : ShowContinueError(state, format("differs from Design Size Celdek Pad Area of {:.2R} [m2]", PadAreaDes));
1466 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1467 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1468 : }
1469 : }
1470 : }
1471 : }
1472 : }
1473 :
1474 27 : IsAutoSize = false;
1475 27 : if (thisEvapCond.PadDepth == DataSizing::AutoSize) {
1476 1 : IsAutoSize = true;
1477 : }
1478 27 : if (CurSysNum > 0 && !IsAutoSize && !SizingDesRunThisAirSys) {
1479 7 : HardSizeNoDesRun = true;
1480 : }
1481 : // The following regression equation is used to determine pad depth,
1482 : // assuming saturation effectiveness of 70% and face air velocity of 3m/s:
1483 : // Effectiveness = 0.792714 + 0.958569D - 0.25193V - 1.03215D^2 + 0.0262659V^2 + 0.914869DV -
1484 : // 1.48241VD^2 - 0.018992V^3D + 1.13137D^3V + 0.0327622V^3D^2 - 0.145384D^3V^2
1485 27 : PadDepthDes = 0.17382;
1486 27 : if (IsAutoSize) {
1487 1 : thisEvapCond.PadDepth = PadDepthDes;
1488 1 : BaseSizer::reportSizerOutput(
1489 : state, "EvaporativeCooler:Direct:CelDekPad", thisEvapCond.Name, "Design Size Celdek Pad Depth [m]", PadDepthDes);
1490 : } else {
1491 26 : if (thisEvapCond.PadDepth > 0.0 && PadDepthDes > 0.0) {
1492 26 : PadDepthUser = thisEvapCond.PadDepth;
1493 26 : BaseSizer::reportSizerOutput(state,
1494 : "EvaporativeCooler:Direct:CelDekPad",
1495 : thisEvapCond.Name,
1496 : "Design Size Celdek Pad Depth [m]",
1497 : PadDepthDes,
1498 : "User-Specified Celdek Pad Depth [m]",
1499 : PadDepthUser);
1500 26 : if (state.dataGlobal->DisplayExtraWarnings) {
1501 0 : if ((std::abs(PadDepthDes - PadDepthUser) / PadDepthUser) > state.dataSize->AutoVsHardSizingThreshold) {
1502 0 : ShowMessage(
1503 0 : state, format("SizeEvaporativeCooler:Direct:CelDekPad: Potential issue with equipment sizing for {}", thisEvapCond.Name));
1504 0 : ShowContinueError(state, format("User-Specified Celdek Pad Depth of {:.2R} [m]", PadDepthUser));
1505 0 : ShowContinueError(state, format("differs from Design Size Celdek Pad Depth of {:.2R} [m]", PadDepthDes));
1506 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1507 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1508 : }
1509 : }
1510 : }
1511 : }
1512 : }
1513 :
1514 103 : if (thisEvapCond.evapCoolerType == EvapCoolerType::IndirectCELDEKPAD) {
1515 5 : IsAutoSize = false;
1516 :
1517 5 : if (thisEvapCond.IndirectPadArea == DataSizing::AutoSize) {
1518 1 : IsAutoSize = true;
1519 : }
1520 5 : if (SizingDesRunThisAirSys) {
1521 0 : HardSizeNoDesRun = false; // Check if design information is available
1522 : }
1523 : // Design air flow rate
1524 5 : if (CurSysNum > 0) { // central system
1525 : // where is this cooler located, is it on OA system or main loop?
1526 : // search for this component in Air loop branches.
1527 2 : for (int AirSysBranchLoop = 1; AirSysBranchLoop <= state.dataAirSystemsData->PrimaryAirSystems(CurSysNum).NumBranches;
1528 : ++AirSysBranchLoop) {
1529 5 : for (int BranchComp = 1;
1530 5 : BranchComp <= state.dataAirSystemsData->PrimaryAirSystems(CurSysNum).Branch(AirSysBranchLoop).TotalComponents;
1531 : ++BranchComp) {
1532 4 : if (Util::SameString(state.dataAirSystemsData->PrimaryAirSystems(CurSysNum).Branch(AirSysBranchLoop).Comp(BranchComp).Name,
1533 : thisEvapCond.Name)) {
1534 1 : CoolerOnMainAirLoop = true;
1535 : }
1536 : }
1537 : }
1538 1 : if (!IsAutoSize && !SizingDesRunThisAirSys) {
1539 1 : HardSizeNoDesRun = true;
1540 1 : if (thisEvapCond.IndirectPadArea > 0.0) {
1541 1 : BaseSizer::reportSizerOutput(state,
1542 : "EvaporativeCooler:Indirect:CelDekPad",
1543 : thisEvapCond.Name,
1544 : "User-Specified Celdek Pad Area [m2]",
1545 : thisEvapCond.IndirectPadArea);
1546 : }
1547 : } else { // Autosize or hardsize with design data
1548 0 : CheckSysSizing(state, CompType, thisEvapCond.Name);
1549 0 : if (!CoolerOnMainAirLoop) {
1550 0 : CoolerOnOApath = true;
1551 : }
1552 0 : if (CoolerOnMainAirLoop) {
1553 0 : IndirectVolFlowRateDes = FinalSysSizing(CurSysNum).DesMainVolFlow;
1554 0 : } else if (CoolerOnOApath) {
1555 0 : IndirectVolFlowRateDes = std::max(FinalSysSizing(CurSysNum).DesOutAirVolFlow, 0.5 * FinalSysSizing(CurSysNum).DesMainVolFlow);
1556 : }
1557 : // Face air velocity of 3m/s is assumed
1558 0 : PadAreaDes = IndirectVolFlowRateDes / 3.0;
1559 : }
1560 4 : } else if (CurZoneEqNum > 0) { // zone equipment
1561 : // zone equip evap coolers
1562 4 : if (!IsAutoSize && !SizingDesRunThisAirSys) { // this should be SizingDesRunThisZone
1563 3 : HardSizeNoDesRun = true;
1564 3 : if (thisEvapCond.IndirectPadArea > 0.0) {
1565 : // report for the indirect evap cooler types only
1566 3 : if (thisEvapCond.PadArea > 0.0) {
1567 0 : BaseSizer::reportSizerOutput(state,
1568 : "EvaporativeCooler:Indirect:CelDekPad",
1569 : thisEvapCond.Name,
1570 : "User-Specified Celdek Pad Area [m2]",
1571 : thisEvapCond.IndirectPadArea);
1572 : }
1573 : }
1574 : } else { // Autosize or hardsize with design data
1575 : // zone equip evap coolers
1576 1 : IndirectVolFlowRateDes = state.dataSize->FinalZoneSizing(CurZoneEqNum).DesCoolVolFlow;
1577 : // Face air velocity of 3m/s is assumed
1578 1 : PadAreaDes = IndirectVolFlowRateDes / 3.0;
1579 : }
1580 : } else {
1581 : }
1582 :
1583 5 : if (!HardSizeNoDesRun) {
1584 1 : if (IsAutoSize) {
1585 1 : thisEvapCond.IndirectPadArea = PadAreaDes;
1586 1 : BaseSizer::reportSizerOutput(
1587 : state, "EvaporativeCooler:Indirect:CelDekPad", thisEvapCond.Name, "Design Size Celdek Pad Area [m2]", PadAreaDes);
1588 : } else {
1589 0 : if (thisEvapCond.IndirectPadArea > 0.0 && PadAreaDes > 0.0) {
1590 0 : PadAreaUser = thisEvapCond.IndirectPadArea;
1591 0 : BaseSizer::reportSizerOutput(state,
1592 : "EvaporativeCooler:Indirect:CelDekPad",
1593 : thisEvapCond.Name,
1594 : "Design Size Celdek Pad Area [m2]",
1595 : PadAreaDes,
1596 : "User-Specified Celdek Pad Area [m2]",
1597 : PadAreaUser);
1598 0 : if (state.dataGlobal->DisplayExtraWarnings) {
1599 0 : if ((std::abs(PadAreaDes - PadAreaUser) / PadAreaUser) > state.dataSize->AutoVsHardSizingThreshold) {
1600 0 : ShowMessage(
1601 : state,
1602 0 : format("SizeEvaporativeCooler:Indirect:CelDekPad: Potential issue with equipment sizing for {}", thisEvapCond.Name));
1603 0 : ShowContinueError(state, format("User-Specified Celdek Pad Area {:.2R} [m2]", PadAreaUser));
1604 0 : ShowContinueError(state, format("differs from Design Size Celdek Pad Area of {:.2R} [m2]", PadAreaDes));
1605 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1606 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1607 : }
1608 : }
1609 : }
1610 : }
1611 : }
1612 :
1613 5 : IsAutoSize = thisEvapCond.IndirectPadDepth == DataSizing::AutoSize;
1614 : // The following regression equation is used to determine pad depth,
1615 : // assuming saturation effectiveness of 70% and face air velocity of 3m/s:
1616 : // Effectiveness = 0.792714 + 0.958569D - 0.25193V - 1.03215D^2 + 0.0262659V^2 + 0.914869DV -
1617 : // 1.48241VD^2 - 0.018992V^3D + 1.13137D^3V + 0.0327622V^3D^2 - 0.145384D^3V^2
1618 :
1619 5 : PadDepthDes = 0.17382;
1620 5 : if (IsAutoSize) {
1621 1 : thisEvapCond.IndirectPadDepth = PadDepthDes;
1622 1 : BaseSizer::reportSizerOutput(
1623 : state, "EvaporativeCooler:Indirect:CelDekPad", thisEvapCond.Name, "Design Size Celdek Pad Depth [m]", PadDepthDes);
1624 : } else {
1625 4 : if (thisEvapCond.IndirectPadDepth > 0.0 && PadDepthDes > 0.0) {
1626 4 : PadDepthUser = thisEvapCond.IndirectPadDepth;
1627 4 : BaseSizer::reportSizerOutput(state,
1628 : "EvaporativeCooler:Indirect:CelDekPad",
1629 : thisEvapCond.Name,
1630 : "Design Size Celdek Pad Depth [m]",
1631 : PadDepthDes,
1632 : "User-Specified Celdek Pad Depth [m]",
1633 : PadDepthUser);
1634 4 : if (state.dataGlobal->DisplayExtraWarnings) {
1635 0 : if ((std::abs(PadDepthDes - PadDepthUser) / PadDepthUser) > state.dataSize->AutoVsHardSizingThreshold) {
1636 0 : ShowMessage(
1637 : state,
1638 0 : format("SizeEvaporativeCooler:Indirect:CelDekPad: Potential issue with equipment sizing for {}", thisEvapCond.Name));
1639 0 : ShowContinueError(state, format("User-Specified Celdek Pad Depth of {:.2R} [m]", PadDepthUser));
1640 0 : ShowContinueError(state, format("differs from Design Size Celdek Pad Depth of {:.2R} [m]", PadDepthDes));
1641 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1642 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1643 : }
1644 : }
1645 : }
1646 : }
1647 : }
1648 :
1649 103 : if (thisEvapCond.evapCoolerType == EvapCoolerType::IndirectRDDSpecial) {
1650 : // secondary air fan sizing: Secondary flow Rate (m3/s) * Fan Flow Sizing Factor (W/(m3/s)
1651 38 : if (thisEvapCond.IndirectFanPower == DataSizing::AutoSize) {
1652 38 : thisEvapCond.IndirectFanPower = thisEvapCond.IndirectVolFlowRate * thisEvapCond.FanSizingSpecificPower;
1653 38 : BaseSizer::reportSizerOutput(
1654 : state, "EvaporativeCooler:Indirect:ResearchSpecial", thisEvapCond.Name, "Secondary Fan Power [W]", thisEvapCond.IndirectFanPower);
1655 : }
1656 : // recirculating water pump sizing: Secondary flow Rate (m3/s) * Pump Sizing Factor (W/(m3/s)
1657 38 : if (thisEvapCond.IndirectRecircPumpPower == DataSizing::AutoSize) {
1658 4 : thisEvapCond.IndirectRecircPumpPower = thisEvapCond.IndirectVolFlowRate * thisEvapCond.RecircPumpSizingFactor;
1659 4 : BaseSizer::reportSizerOutput(state,
1660 : "EvaporativeCooler:Indirect:ResearchSpecial",
1661 : thisEvapCond.Name,
1662 : "Recirculating Pump Power [W]",
1663 : thisEvapCond.IndirectRecircPumpPower);
1664 : }
1665 : }
1666 :
1667 103 : if (thisEvapCond.evapCoolerType == EvapCoolerType::DirectResearchSpecial) {
1668 : // recirculating water pump sizing: Primary Air Design flow Rate (m3/s) * Pump Sizing Factor (W/(m3/s)
1669 24 : if (thisEvapCond.RecircPumpPower == DataSizing::AutoSize) {
1670 0 : thisEvapCond.RecircPumpPower = thisEvapCond.DesVolFlowRate * thisEvapCond.RecircPumpSizingFactor;
1671 0 : BaseSizer::reportSizerOutput(
1672 : state, "EvaporativeCooler:Direct:ResearchSpecial", thisEvapCond.Name, "Recirculating Pump Power [W]", thisEvapCond.RecircPumpPower);
1673 : }
1674 : }
1675 103 : }
1676 :
1677 258218 : void CalcDirectEvapCooler(EnergyPlusData &state, int EvapCoolNum, Real64 const PartLoadRatio)
1678 : {
1679 :
1680 : // SUBROUTINE INFORMATION:
1681 : // AUTHOR Richard J. Liesen
1682 : // DATE WRITTEN October 2000
1683 :
1684 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1685 : Real64 PadDepth; // EvapCooler Pad Depth in Meters as input by the User
1686 : Real64 SatEff; // Saturation Efficiency of the CelDek Pad
1687 : Real64 AirVel; // The Calculated Air Velocity through the Pad
1688 : Real64 TEDB; // Entering Dry Bulb Temperature
1689 : Real64 TEWB; // Entering Wet Bulb Temperature
1690 : Real64 RhoWater;
1691 :
1692 258218 : auto &thisEvapCond(state.dataEvapCoolers->EvapCond(EvapCoolNum));
1693 :
1694 : // If the Evaporative Cooler is operating there should be some mass flow rate
1695 : // Also the evap cooler has to be scheduled to be available
1696 258218 : if ((thisEvapCond.InletMassFlowRate > 0.0) && (thisEvapCond.availSched->getCurrentVal() > 0.0)) {
1697 :
1698 133226 : PadDepth = thisEvapCond.PadDepth;
1699 : //******************************************************************************
1700 : // THIS SUBROUTINE WILL CACULATE THE TEMPERATURE OF THE LEAVING AIR DRY BULB
1701 : // FOR A DIRECT EVAPORATIVE AIR COOLER SUPPLIED WITH CFMAir,DIRPAD,TEWB,TEDB,
1702 : // AND PB (ATM. PRESS.) FOR AIR DENSITY CALCULATIONS.
1703 : //******************************************************************************
1704 :
1705 133226 : AirVel = thisEvapCond.VolFlowRate / thisEvapCond.PadArea;
1706 :
1707 : //******************************************************************************
1708 : // SAT EFF IS FOR DIFFERENT THICKNESS CELDEK PAD (CURVE FIT FROM DATA)
1709 : //******************************************************************************
1710 133226 : SatEff = 0.792714 + 0.958569 * PadDepth - 0.25193 * AirVel - 1.03215 * pow_2(PadDepth) + 2.62659e-2 * pow_2(AirVel) +
1711 133226 : 0.914869 * PadDepth * AirVel - 1.48241 * AirVel * pow_2(PadDepth) - 1.89919e-2 * pow_3(AirVel) * PadDepth +
1712 133226 : 1.13137 * pow_3(PadDepth) * AirVel + 3.27622e-2 * pow_3(AirVel) * pow_2(PadDepth) - 0.145384 * pow_3(PadDepth) * pow_2(AirVel);
1713 :
1714 133226 : if (SatEff >= 1.0) {
1715 0 : SatEff = 1.0;
1716 : }
1717 133226 : if (SatEff < 0.0) { // we have a serious problem. Pad Area and/or depth not suitable for system air flow rates
1718 0 : ShowSevereError(state, format("EVAPCOOLER:DIRECT:CELDEKPAD: {} has a problem", thisEvapCond.Name));
1719 0 : ShowContinueError(state, "Check size of Pad Area and/or Pad Depth in input");
1720 0 : ShowContinueError(state, format("Cooler Effectiveness calculated as: {:.2R}", SatEff));
1721 0 : ShowContinueError(state, format("Air velocity (m/s) through pads calculated as: {:.2R}", AirVel));
1722 0 : ShowFatalError(state, "Program Terminates due to previous error condition");
1723 : }
1724 133226 : thisEvapCond.SatEff = SatEff;
1725 : //***************************************************************************
1726 : // TEMP LEAVING DRY BULB IS CALCULATED FROM SATURATION EFFICIENCY AS THE
1727 : // DRY BULB TEMP APPROACHES THE WET BULB TEMP. WET BULB TEMP IS CONSTANT
1728 : // ACROSS A DIRECT EVAPORATION COOLER.
1729 133226 : TEWB = thisEvapCond.InletWetBulbTemp;
1730 133226 : TEDB = thisEvapCond.InletTemp;
1731 :
1732 133226 : thisEvapCond.OutletTemp = TEDB - ((TEDB - TEWB) * SatEff);
1733 :
1734 133226 : thisEvapCond.OuletWetBulbTemp = thisEvapCond.InletWetBulbTemp;
1735 :
1736 133226 : thisEvapCond.OutletHumRat = Psychrometrics::PsyWFnTdbTwbPb(state, thisEvapCond.OutletTemp, TEWB, state.dataEnvrn->OutBaroPress);
1737 :
1738 133226 : thisEvapCond.OutletEnthalpy = Psychrometrics::PsyHFnTdbW(thisEvapCond.OutletTemp, thisEvapCond.OutletHumRat);
1739 :
1740 : //***************************************************************************
1741 : // ENERGY CONSUMED BY THE RECIRCULATING PUMP
1742 : // Add the pump energy to the total Evap Cooler energy consumption
1743 133226 : thisEvapCond.EvapCoolerPower += PartLoadRatio * thisEvapCond.RecircPumpPower;
1744 : //******************
1745 : // WATER CONSUMPTION IN m3 OF WATER FOR DIRECT
1746 : // H2O [m3/s] = Delta W[kgWater/kDryAir]*Mass Flow Air[kgDryAir/s]
1747 : // /RhoWater [kgWater/m3]
1748 : //******************
1749 133226 : RhoWater = Psychrometrics::RhoH2O(thisEvapCond.OutletTemp);
1750 133226 : thisEvapCond.EvapWaterConsumpRate = (thisEvapCond.OutletHumRat - thisEvapCond.InletHumRat) * thisEvapCond.InletMassFlowRate / RhoWater;
1751 : // A numerical check to keep from having very tiny negative water consumption values being reported
1752 133226 : if (thisEvapCond.EvapWaterConsumpRate < 0.0) {
1753 11914 : thisEvapCond.EvapWaterConsumpRate = 0.0;
1754 : }
1755 :
1756 : } else {
1757 : // The evap cooler is not running and does not change conditions from inlet to outlet
1758 124992 : thisEvapCond.OutletTemp = thisEvapCond.InletTemp;
1759 :
1760 124992 : thisEvapCond.OuletWetBulbTemp = thisEvapCond.InletWetBulbTemp;
1761 :
1762 124992 : thisEvapCond.OutletHumRat = thisEvapCond.InletHumRat;
1763 :
1764 124992 : thisEvapCond.OutletEnthalpy = thisEvapCond.InletEnthalpy;
1765 :
1766 124992 : thisEvapCond.EvapCoolerEnergy = 0.0;
1767 :
1768 124992 : thisEvapCond.EvapWaterConsumpRate = 0.0;
1769 : }
1770 : // all of the mass flowrates are not changed across the evap cooler
1771 258218 : thisEvapCond.OutletMassFlowRate = thisEvapCond.InletMassFlowRate;
1772 258218 : thisEvapCond.OutletMassFlowRateMaxAvail = thisEvapCond.InletMassFlowRateMaxAvail;
1773 258218 : thisEvapCond.OutletMassFlowRateMinAvail = thisEvapCond.InletMassFlowRateMinAvail;
1774 :
1775 : // the pressure is not changed across the evap cooler
1776 258218 : thisEvapCond.OutletPressure = thisEvapCond.InletPressure;
1777 258218 : }
1778 :
1779 38920 : void CalcDryIndirectEvapCooler(EnergyPlusData &state, int EvapCoolNum, Real64 const PartLoadRatio)
1780 : {
1781 :
1782 : // SUBROUTINE INFORMATION:
1783 : // AUTHOR Richard J. Liesen
1784 : // DATE WRITTEN October 2000
1785 : // MODIFIED BG Feb. 2007 secondary air inlet node
1786 :
1787 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1788 : Real64 PadDepth; // EvapCooler Pad Depth in Meters as input by the User
1789 : Real64 SatEff; // Saturation Efficiency of the CelDek Pad
1790 : Real64 AirVel; // The Calculated Air Velocity through the Pad
1791 : Real64 TDBSec; // Secondary leaving dry bulb
1792 : Real64 TWBSec; // Secondary Leaving Wet Bulb
1793 : Real64 HumRatSec; // Secondary leaving Humidity Ratio
1794 : Real64 EffHX; // Effectiveness of Secondary Heat Exchanger
1795 : Real64 QHX; // Q Across Sec HX
1796 : Real64 RhoWater;
1797 : Real64 RhoAir; // Density of the primary side air
1798 : Real64 CpAir; // Cp of the primary side air
1799 : Real64 CFMAir;
1800 : Real64 CFMSec;
1801 :
1802 38920 : auto &thisEvapCond(state.dataEvapCoolers->EvapCond(EvapCoolNum));
1803 :
1804 : // If the Evaporative Cooler is operating there should be some mass flow rate
1805 : // Also the evap cooler has to be scheduled to be available
1806 38920 : if ((thisEvapCond.InletMassFlowRate > 0.0) && (thisEvapCond.availSched->getCurrentVal() > 0.0)) {
1807 :
1808 18464 : PadDepth = thisEvapCond.IndirectPadDepth;
1809 : //******************************************************************************
1810 : // THIS SUBROUTINE WILL CACULATE THE TEMPERATURE OF THE LEAVING AIR DRY BULB
1811 : // FOR A DIRECT EVAPORATIVE AIR COOLER SUPPLIED WITH CFMAir,DIRPAD,TEWB,TEDB,
1812 : // AND PB (ATM. PRESS.) FOR AIR DENSITY CALCULATIONS.
1813 : //******************************************************************************
1814 :
1815 18464 : AirVel = thisEvapCond.IndirectVolFlowRate / thisEvapCond.IndirectPadArea;
1816 :
1817 : //******************************************************************************
1818 : // SAT EFF IS FOR DIFFERENT THICKNESS CELDEK PAD (CURVE FIT FROM DATA)
1819 : //******************************************************************************
1820 18464 : SatEff = 0.792714 + 0.958569 * PadDepth - 0.25193 * AirVel - 1.03215 * pow_2(PadDepth) + 2.62659e-2 * pow_2(AirVel) +
1821 18464 : 0.914869 * PadDepth * AirVel - 1.48241 * AirVel * pow_2(PadDepth) - 1.89919e-2 * pow_3(AirVel) * PadDepth +
1822 18464 : 1.13137 * pow_3(PadDepth) * AirVel + 3.27622e-2 * pow_3(AirVel) * pow_2(PadDepth) - 0.145384 * pow_3(PadDepth) * pow_2(AirVel);
1823 :
1824 18464 : if (SatEff >= 1.0) {
1825 0 : SatEff = 1.0;
1826 : }
1827 18464 : thisEvapCond.SatEff = SatEff;
1828 : //***************************************************************************
1829 : // TEMP LEAVING DRY BULB IS CALCULATED FROM SATURATION EFFICIENCY AS THE
1830 : // DRY BULB TEMP APPROACHES THE WET BULB TEMP ACROSS THE PAD BEFORE THE HX.
1831 : //***************************************************************************
1832 : //***** FIRST CHECK IF THIS TEWB IS A FEASIBLE POINT ON PSYCH CHART**********
1833 :
1834 : // BG Feb 2007 mods for oa node (eg. height-dependent outside air model)
1835 18464 : TWBSec = Psychrometrics::PsyTwbFnTdbWPb(state,
1836 : thisEvapCond.SecInletTemp,
1837 : thisEvapCond.SecInletHumRat,
1838 : thisEvapCond.SecInletPressure); // OutWetBulbTemp
1839 18464 : TDBSec = thisEvapCond.SecInletTemp - ((thisEvapCond.SecInletTemp - TWBSec) * SatEff);
1840 :
1841 18464 : HumRatSec = Psychrometrics::PsyWFnTdbTwbPb(state, TDBSec, TWBSec, thisEvapCond.SecInletPressure);
1842 :
1843 : //***************************************************************************
1844 : // CALCULATE THE TLDB FROM HX EQUATIONS GIVEN AN EFFICIENCY
1845 : //***************************************************************************
1846 18464 : EffHX = thisEvapCond.IndirectHXEffectiveness;
1847 18464 : CpAir = Psychrometrics::PsyCpAirFnW(thisEvapCond.InletHumRat);
1848 18464 : RhoAir = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, thisEvapCond.InletTemp, thisEvapCond.InletHumRat);
1849 18464 : CFMAir = thisEvapCond.VolFlowRate; // Volume Flow Rate Primary Side
1850 18464 : CFMSec = thisEvapCond.IndirectVolFlowRate; // Volume Flow Rate Secondary Side
1851 :
1852 18464 : QHX = EffHX * min(CFMSec, CFMAir) * RhoAir * CpAir * (thisEvapCond.InletTemp - TDBSec);
1853 18464 : thisEvapCond.OutletTemp = thisEvapCond.InletTemp - QHX / (RhoAir * CFMAir * CpAir);
1854 : // This is a rough approximation of the Total Indirect Stage Efficiency for the Dry stage which
1855 : // is a 2 step process the first being the pad efficiency and then the HX Effectiveness. I think that
1856 : // this would mainly be used for evap sizing purposes.
1857 18464 : thisEvapCond.StageEff = SatEff * EffHX;
1858 : //***************************************************************************
1859 : // CALCULATE THE WET BULB TEMP in the primary system air USING PSYCH ROUTINES
1860 : // There is a constant humidity ratio across the primary side but a reduction in the dry bulb temp
1861 18464 : thisEvapCond.OuletWetBulbTemp =
1862 18464 : Psychrometrics::PsyTwbFnTdbWPb(state, thisEvapCond.OutletTemp, thisEvapCond.InletHumRat, state.dataEnvrn->OutBaroPress);
1863 : //***************************************************************************
1864 : // TEMP LEAVING DRY BULB IS CALCULATED FROM SATURATION EFFICIENCY AS THE
1865 : // DRY BULB TEMP APPROACHES THE WET BULB TEMP. WET BULB TEMP IS CONSTANT
1866 : // ACROSS A DIRECT EVAPORATION COOLER.
1867 :
1868 18464 : thisEvapCond.OutletHumRat = thisEvapCond.InletHumRat;
1869 :
1870 18464 : thisEvapCond.OutletEnthalpy = Psychrometrics::PsyHFnTdbW(thisEvapCond.OutletTemp, thisEvapCond.OutletHumRat);
1871 :
1872 : //***************************************************************************
1873 : // POWER OF THE SECONDARY AIR FAN
1874 18464 : if (thisEvapCond.IndirectFanEff > 0.0) {
1875 18464 : thisEvapCond.EvapCoolerPower +=
1876 18464 : PartLoadRatio * thisEvapCond.IndirectFanDeltaPress * thisEvapCond.IndirectVolFlowRate / thisEvapCond.IndirectFanEff;
1877 : }
1878 :
1879 : // ENERGY CONSUMED BY THE RECIRCULATING PUMP
1880 : // ENERGY CONSUMED BY THE RECIRCULATING PUMP
1881 : // Add the pump energy to the total Evap Cooler energy consumption
1882 18464 : thisEvapCond.EvapCoolerPower += PartLoadRatio * thisEvapCond.IndirectRecircPumpPower;
1883 :
1884 : //******************
1885 : // WATER CONSUMPTION IN m3 OF WATER FOR DIRECT
1886 : // H2O [m3/s] = Delta W[kgWater/kgDryAir]*Mass Flow Air[kgDryAir/s]
1887 : // /RhoWater [kgWater/m3]
1888 : //******************
1889 18464 : RhoWater = Psychrometrics::RhoH2O(TDBSec);
1890 18464 : RhoAir = (Psychrometrics::PsyRhoAirFnPbTdbW(state, thisEvapCond.SecInletPressure, thisEvapCond.SecInletTemp, thisEvapCond.SecInletHumRat) +
1891 18464 : Psychrometrics::PsyRhoAirFnPbTdbW(state, thisEvapCond.SecInletPressure, TDBSec, HumRatSec)) /
1892 : 2.0;
1893 18464 : thisEvapCond.EvapWaterConsumpRate =
1894 18464 : PartLoadRatio * (HumRatSec - thisEvapCond.SecInletHumRat) * thisEvapCond.IndirectVolFlowRate * RhoAir / RhoWater;
1895 : // A numerical check to keep from having very tiny negative water consumption values being reported
1896 18464 : if (thisEvapCond.EvapWaterConsumpRate < 0.0) {
1897 2848 : thisEvapCond.EvapWaterConsumpRate = 0.0;
1898 : }
1899 :
1900 : } else {
1901 : // The evap cooler is not running and does not change conditions from inlet to outlet
1902 20456 : thisEvapCond.OutletTemp = thisEvapCond.InletTemp;
1903 :
1904 20456 : thisEvapCond.OuletWetBulbTemp = thisEvapCond.InletWetBulbTemp;
1905 :
1906 20456 : thisEvapCond.OutletHumRat = thisEvapCond.InletHumRat;
1907 :
1908 20456 : thisEvapCond.OutletEnthalpy = thisEvapCond.InletEnthalpy;
1909 :
1910 20456 : thisEvapCond.EvapCoolerEnergy = 0.0;
1911 :
1912 20456 : thisEvapCond.EvapWaterConsumpRate = 0.0;
1913 : }
1914 : // all of the mass flowrates are not changed across the evap cooler
1915 38920 : thisEvapCond.OutletMassFlowRate = thisEvapCond.InletMassFlowRate;
1916 38920 : thisEvapCond.OutletMassFlowRateMaxAvail = thisEvapCond.InletMassFlowRateMaxAvail;
1917 38920 : thisEvapCond.OutletMassFlowRateMinAvail = thisEvapCond.InletMassFlowRateMinAvail;
1918 :
1919 : // the pressure is not changed across the evap cooler
1920 38920 : thisEvapCond.OutletPressure = thisEvapCond.InletPressure;
1921 38920 : }
1922 :
1923 92337 : void CalcWetIndirectEvapCooler(EnergyPlusData &state, int EvapCoolNum, Real64 const PartLoadRatio)
1924 : {
1925 :
1926 : // SUBROUTINE INFORMATION:
1927 : // AUTHOR Richard J. Liesen
1928 : // DATE WRITTEN October 2000
1929 : // RE-ENGINEERED Jan. 2017, Rongpeng Zhang, added fouling fault for evaporative coolers
1930 :
1931 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1932 : Real64 StageEff; // Stage Efficiency of the Heat Exchanger
1933 : Real64 TEDB; // Entering Dry Bulb Temperature
1934 : Real64 TEWB; // Entering Wet Bulb Temperature
1935 : Real64 QHX; // Q Across Sec HX in Watts or J/sec
1936 : Real64 RhoWater;
1937 : Real64 RhoAir; // Density of the primary side air
1938 : Real64 CFMAir;
1939 : Real64 CFMSec;
1940 : Real64 TWBSec; // wet bulb of secondary air
1941 :
1942 92337 : auto &thisEvapCond(state.dataEvapCoolers->EvapCond(EvapCoolNum));
1943 :
1944 : // If the Evaporative Cooler is operating there should be some mass flow rate
1945 : // Also the evap cooler has to be scheduled to be available
1946 92337 : if ((thisEvapCond.InletMassFlowRate > 0.0) && (thisEvapCond.availSched->getCurrentVal() > 0.0)) {
1947 :
1948 : //******************************************************************************
1949 : // THIS SUBROUTINE WILL CACULATE THE TEMPERATURE OF THE LEAVING AIR DRY BULB
1950 : // FOR A WET COIL EVAPORATIVE COOLER
1951 : //******************************************************************************
1952 : // INDIRECT STAGE EFFICIENCY FOR WET COIL INDIRECT EVAP COOLERS
1953 56064 : CFMAir = thisEvapCond.VolFlowRate; // Volume Flow Rate Primary Side
1954 56064 : CFMSec = thisEvapCond.IndirectVolFlowRate; // Volume Flow Rate Secondary Side
1955 :
1956 56064 : StageEff = thisEvapCond.WetCoilMaxEfficiency - min(thisEvapCond.WetCoilFlowRatio * CFMAir / CFMSec, thisEvapCond.WetCoilMaxEfficiency);
1957 :
1958 56064 : if (StageEff >= 1.0) {
1959 0 : StageEff = 1.0;
1960 : }
1961 : // This is a rough approximation of the Total Indirect Stage Efficiency. I think that
1962 : // this would mainly be used for evap sizing purposes.
1963 :
1964 : // If there is a fault of fouling
1965 57586 : if (thisEvapCond.FaultyEvapCoolerFoulingFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
1966 1522 : (!state.dataGlobal->KickOffSimulation)) {
1967 1522 : int FaultIndex = thisEvapCond.FaultyEvapCoolerFoulingIndex;
1968 1522 : Real64 StageEff_ff = StageEff;
1969 :
1970 : // calculate the Faulty Evaporative Cooler Fouling Factor using fault information
1971 1522 : thisEvapCond.FaultyEvapCoolerFoulingFactor = state.dataFaultsMgr->FaultsEvapCoolerFouling(FaultIndex).CalFoulingFactor(state);
1972 :
1973 : // update the StageEff at faulty cases
1974 1522 : StageEff = StageEff_ff * thisEvapCond.FaultyEvapCoolerFoulingFactor;
1975 : }
1976 :
1977 56064 : thisEvapCond.StageEff = StageEff;
1978 : //***************************************************************************
1979 : // TEMP LEAVING DRY BULB IS CALCULATED FROM A SIMPLE WET BULB APPROACH
1980 : // MODEL GIVEN THE INDIRECT STAGE EFFICIENCY.
1981 : // DRY BULB TEMP APPROACHES THE WET BULB TEMP ACROSS THE INDIRECT STAGE.
1982 : //***************************************************************************
1983 : // CALCULATE THE TLDB
1984 56064 : TEWB = thisEvapCond.InletWetBulbTemp;
1985 56064 : TEDB = thisEvapCond.InletTemp;
1986 56064 : TWBSec = Psychrometrics::PsyTwbFnTdbWPb(state, thisEvapCond.SecInletTemp, thisEvapCond.SecInletHumRat, thisEvapCond.SecInletPressure);
1987 56064 : thisEvapCond.OutletTemp = TEDB - StageEff * (TEDB - TWBSec);
1988 :
1989 : //***************************************************************************
1990 : // CALCULATE THE WET BULB TEMP in the primary system air using PSYCH ROUTINES
1991 : // There is a constant humidity ratio across the primary side but a reduction in the dry bulb temp
1992 56064 : thisEvapCond.OuletWetBulbTemp =
1993 56064 : Psychrometrics::PsyTwbFnTdbWPb(state, thisEvapCond.OutletTemp, thisEvapCond.InletHumRat, state.dataEnvrn->OutBaroPress);
1994 : //***************************************************************************
1995 : // CALCULATE other outlet properties using PSYCH ROUTINES
1996 56064 : thisEvapCond.OutletHumRat = thisEvapCond.InletHumRat;
1997 :
1998 56064 : thisEvapCond.OutletEnthalpy = Psychrometrics::PsyHFnTdbW(thisEvapCond.OutletTemp, thisEvapCond.OutletHumRat);
1999 :
2000 : //***************************************************************************
2001 : // Real64 FlowFraction = 1.0;
2002 : // Real64 MassFlowRateMax = Node(thisEvapCond.InletNode).MassFlowRateMax;
2003 : // if (MassFlowRateMax > 0) {
2004 : // FlowFraction = thisEvapCond.InletMassFlowRate / MassFlowRateMax;
2005 : //}
2006 : // POWER OF THE SECONDARY AIR FAN
2007 56064 : if (thisEvapCond.IndirectFanEff > 0.0) {
2008 56064 : thisEvapCond.EvapCoolerPower +=
2009 56064 : PartLoadRatio * thisEvapCond.IndirectFanDeltaPress * thisEvapCond.IndirectVolFlowRate / thisEvapCond.IndirectFanEff;
2010 : }
2011 :
2012 : // ENERGY CONSUMED BY THE RECIRCULATING PUMP
2013 : // ENERGY CONSUMED BY THE RECIRCULATING PUMP
2014 : // Add the pump energy to the total Evap Cooler energy consumption
2015 56064 : thisEvapCond.EvapCoolerPower += PartLoadRatio * thisEvapCond.IndirectRecircPumpPower;
2016 :
2017 : //******************
2018 : // WATER CONSUMPTION IN m3 OF WATER FOR Wet InDIRECT
2019 : // H2O [m3/s] = (QHX [J/s])/(2,500,000 [J/kgWater] * RhoWater [kgWater/m3])
2020 : //******************
2021 : //***** FIRST calculate the heat exchange on the primary air side**********
2022 56064 : RhoAir = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, thisEvapCond.InletTemp, thisEvapCond.InletHumRat);
2023 56064 : QHX = PartLoadRatio * CFMAir * RhoAir * (thisEvapCond.InletEnthalpy - thisEvapCond.OutletEnthalpy);
2024 :
2025 56064 : RhoWater = Psychrometrics::RhoH2O(thisEvapCond.SecInletTemp);
2026 56064 : thisEvapCond.EvapWaterConsumpRate = (QHX / StageEff) / (2500000.0 * RhoWater);
2027 : // A numerical check to keep from having very tiny negative water consumption values being reported
2028 56064 : if (thisEvapCond.EvapWaterConsumpRate < 0.0) {
2029 0 : thisEvapCond.EvapWaterConsumpRate = 0.0;
2030 : }
2031 :
2032 : } else {
2033 : // The evap cooler is not running and does not change conditions from inlet to outlet
2034 36273 : thisEvapCond.OutletTemp = thisEvapCond.InletTemp;
2035 :
2036 36273 : thisEvapCond.OuletWetBulbTemp = thisEvapCond.InletWetBulbTemp;
2037 :
2038 36273 : thisEvapCond.OutletHumRat = thisEvapCond.InletHumRat;
2039 :
2040 36273 : thisEvapCond.OutletEnthalpy = thisEvapCond.InletEnthalpy;
2041 :
2042 36273 : thisEvapCond.EvapCoolerEnergy = 0.0;
2043 :
2044 36273 : thisEvapCond.EvapWaterConsumpRate = 0.0;
2045 : }
2046 : // all of the mass flowrates are not changed across the evap cooler
2047 92337 : thisEvapCond.OutletMassFlowRate = thisEvapCond.InletMassFlowRate;
2048 92337 : thisEvapCond.OutletMassFlowRateMaxAvail = thisEvapCond.InletMassFlowRateMaxAvail;
2049 92337 : thisEvapCond.OutletMassFlowRateMinAvail = thisEvapCond.InletMassFlowRateMinAvail;
2050 :
2051 : // the pressure is not changed across the evap cooler
2052 92337 : thisEvapCond.OutletPressure = thisEvapCond.InletPressure;
2053 92337 : }
2054 :
2055 2573067 : void CalcResearchSpecialPartLoad(EnergyPlusData &state, int EvapCoolNum)
2056 : {
2057 : // SUBROUTINE INFORMATION:
2058 : // AUTHOR B. Griffith
2059 : // DATE WRITTEN July 2003
2060 :
2061 : // REFERENCES:
2062 : // copied CalcWetIndirectEvapCooler as template for new cooler
2063 :
2064 2573067 : Real64 constexpr MinAirMassFlow(0.001);
2065 :
2066 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2067 2573067 : Real64 FullOutput = 0.0;
2068 2573067 : Real64 ReqOutput = 0.0;
2069 : // Set local variables
2070 :
2071 2573067 : auto &thisEvapCond = state.dataEvapCoolers->EvapCond(EvapCoolNum);
2072 :
2073 : // Retrieve the load on the controlled zone
2074 2573067 : int OutletNode = thisEvapCond.OutletNode;
2075 2573067 : int InletNode = thisEvapCond.InletNode;
2076 2573067 : int ControlNode = thisEvapCond.EvapControlNodeNum;
2077 2573067 : Real64 DesOutTemp = thisEvapCond.DesiredOutletTemp;
2078 2573067 : Real64 PartLoadFrac = 0.0;
2079 :
2080 : // If Evap Cooler runs with a cooling load then set PartLoadFrac on Cooling System and the Mass Flow
2081 5128314 : if ((thisEvapCond.availSched->getCurrentVal() > 0.0) && (state.dataLoopNodes->Node(InletNode).MassFlowRate > MinAirMassFlow) &&
2082 7492867 : (state.dataLoopNodes->Node(InletNode).Temp > state.dataLoopNodes->Node(ControlNode).TempSetPoint) &&
2083 2364553 : (std::abs(state.dataLoopNodes->Node(InletNode).Temp - DesOutTemp) > HVAC::TempControlTol)) {
2084 :
2085 : // Get full load result, depending on model
2086 2340695 : thisEvapCond.PartLoadFract = 1.0;
2087 2340695 : switch (thisEvapCond.evapCoolerType) {
2088 1034457 : case EvapCoolerType::IndirectRDDSpecial: {
2089 1034457 : CalcIndirectResearchSpecialEvapCooler(state, EvapCoolNum);
2090 1034457 : UpdateEvapCooler(state, EvapCoolNum);
2091 1034457 : FullOutput = state.dataLoopNodes->Node(InletNode).MassFlowRate *
2092 1034457 : (Psychrometrics::PsyHFnTdbW(state.dataLoopNodes->Node(OutletNode).Temp, state.dataLoopNodes->Node(InletNode).HumRat) -
2093 1034457 : Psychrometrics::PsyHFnTdbW(state.dataLoopNodes->Node(InletNode).Temp, state.dataLoopNodes->Node(InletNode).HumRat));
2094 :
2095 1034457 : ReqOutput = state.dataLoopNodes->Node(InletNode).MassFlowRate *
2096 1034457 : (Psychrometrics::PsyHFnTdbW(thisEvapCond.DesiredOutletTemp, state.dataLoopNodes->Node(InletNode).HumRat) -
2097 1034457 : Psychrometrics::PsyHFnTdbW(state.dataLoopNodes->Node(InletNode).Temp, state.dataLoopNodes->Node(InletNode).HumRat));
2098 :
2099 : // now reinit after test call
2100 1034457 : InitEvapCooler(state, EvapCoolNum);
2101 :
2102 1034457 : } break;
2103 1306238 : case EvapCoolerType::DirectResearchSpecial: {
2104 1306238 : CalcDirectResearchSpecialEvapCooler(state, EvapCoolNum);
2105 1306238 : UpdateEvapCooler(state, EvapCoolNum);
2106 1306238 : FullOutput = state.dataLoopNodes->Node(OutletNode).Temp - state.dataLoopNodes->Node(InletNode).Temp;
2107 1306238 : ReqOutput = thisEvapCond.DesiredOutletTemp - state.dataLoopNodes->Node(InletNode).Temp;
2108 :
2109 : // now reinit after test call
2110 1306238 : InitEvapCooler(state, EvapCoolNum);
2111 :
2112 1306238 : } break;
2113 0 : default: {
2114 0 : assert(false);
2115 : } break;
2116 : }
2117 :
2118 : // Since we are cooling, we expect FullOutput to be < 0 and FullOutput < NoCoolOutput
2119 : // Check that this is the case; if not set PartLoadFrac = 0.0 (off) and return
2120 : // Calculate the part load fraction
2121 2340695 : if (FullOutput == 0.0) {
2122 8982 : FullOutput = 0.00001;
2123 : }
2124 2340695 : PartLoadFrac = ReqOutput / FullOutput;
2125 2340695 : if (PartLoadFrac > 1.0) {
2126 2290790 : PartLoadFrac = 1.0;
2127 49905 : } else if (PartLoadFrac < 0.0) {
2128 8984 : PartLoadFrac = 0.0;
2129 : }
2130 :
2131 : } else { // No cooling
2132 232372 : PartLoadFrac = 0.0;
2133 :
2134 : } // End of the cooler running If block
2135 : // Set the final results
2136 2573067 : thisEvapCond.PartLoadFract = PartLoadFrac;
2137 2573067 : }
2138 :
2139 2190906 : void CalcIndirectResearchSpecialEvapCooler(EnergyPlusData &state, int const EvapCoolNum, Real64 const FanPLR)
2140 : {
2141 :
2142 : // SUBROUTINE INFORMATION:
2143 : // AUTHOR B. Griffith
2144 : // DATE WRITTEN July 2003
2145 : // RE-ENGINEERED October 2014, B Nigusse, added dry and wet operating modes
2146 : // and secondary air flow control
2147 :
2148 : // PURPOSE OF THIS SUBROUTINE:
2149 : // Subroutine models a "special" cooler that allows high effectiveness and controls
2150 :
2151 : // REFERENCES:
2152 : // copied CalcWetIndirectEvapCooler as template for new cooler
2153 :
2154 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2155 : Real64 SecondaryInletDryBulbTemp; // entering drybulb for secondary/purge side
2156 : Real64 SecondaryInletWetBulbTemp; // entering wet bulb for secondary/purge side
2157 : Real64 SecondaryInletDewPointTemp; // entering dewpoint for secondary/purge side
2158 : Real64 SecondaryInletHumRatio; // entering humidity ratio for secondary/purge side
2159 : Real64 StageEff; // Stage Efficiency of the Heat Exchanger
2160 : Real64 TEDB; // Entering Dry Bulb Temperature
2161 : Real64 TEWB; // Entering Wet Bulb Temperature
2162 : Real64 QHX; // Q Across Sec HX in Watts or J/sec
2163 : Real64 RhoWater;
2164 : Real64 RhoAir; // Density of the primary side air
2165 : Real64 CFMAir;
2166 : Real64 BoundTemp; // temperature limit for outlet
2167 : Real64 PartLoad;
2168 : Real64 TotalVolFlow;
2169 : Real64 TertMdot;
2170 : Real64 TertHumRate;
2171 : Real64 TertTemp;
2172 : Real64 TertRho;
2173 : Real64 TertVdot;
2174 : Real64 SecVdot;
2175 : Real64 SecRho;
2176 : Real64 SecMdot;
2177 : Real64 PurgeMdot;
2178 : Real64 PurgeHumRat;
2179 : Real64 PurgeEnthalpy;
2180 : Real64 PurgeTemp;
2181 2190906 : Real64 BlowDownVdot(0.0);
2182 2190906 : Real64 DriftVdot(0.0);
2183 2190906 : Real64 EvapVdot(0.0);
2184 :
2185 2190906 : auto &thisEvapCond(state.dataEvapCoolers->EvapCond(EvapCoolNum));
2186 :
2187 : // If the Evaporative Cooler is operating there should be some mass flow rate
2188 : // Also the evap cooler has to be scheduled to be available
2189 2190906 : if ((thisEvapCond.InletMassFlowRate > 0.0) && (thisEvapCond.availSched->getCurrentVal() > 0.0)) {
2190 :
2191 : //******************************************************************************
2192 : // THIS SUBROUTINE WILL CACULATE THE TEMPERATURE OF THE LEAVING AIR DRY BULB
2193 : // FOR A WET COIL EVAPORATIVE COOLER
2194 : //******************************************************************************
2195 : // INDIRECT STAGE EFFICIENCY FOR WET COIL INDIRECT EVAP COOLERS
2196 2143688 : CFMAir = thisEvapCond.VolFlowRate; // Volume Flow Rate Primary Side
2197 2143688 : StageEff = thisEvapCond.WetCoilMaxEfficiency;
2198 :
2199 : // This is model is for special indirect cooler with efficiency greater than 1.0
2200 2143688 : if (StageEff >= 1.5) {
2201 0 : StageEff = 1.5;
2202 : }
2203 :
2204 2143688 : thisEvapCond.StageEff = StageEff;
2205 :
2206 : //***********************************************
2207 : // Unit is allowed to mix relief air that would otherwise be exhausted outdoors for ventilation
2208 : // If tertiary node is set >0 then it assumed that this node is the exhaust out of the building
2209 : // and the remainder will be made up with outside air from the secondary node
2210 : //*********************************************
2211 :
2212 2143688 : int TertNode = thisEvapCond.TertiaryInletNode;
2213 2143688 : if (TertNode == 0) {
2214 2086461 : SecondaryInletDryBulbTemp = thisEvapCond.SecInletTemp;
2215 : SecondaryInletWetBulbTemp =
2216 2086461 : Psychrometrics::PsyTwbFnTdbWPb(state, thisEvapCond.SecInletTemp, thisEvapCond.SecInletHumRat, state.dataEnvrn->OutBaroPress);
2217 : SecondaryInletDewPointTemp =
2218 2086461 : Psychrometrics::PsyTdpFnTdbTwbPb(state, thisEvapCond.SecInletTemp, SecondaryInletWetBulbTemp, state.dataEnvrn->OutBaroPress);
2219 2086461 : SecondaryInletHumRatio = thisEvapCond.SecInletHumRat;
2220 :
2221 : } else {
2222 :
2223 57227 : TotalVolFlow = thisEvapCond.IndirectVolFlowRate;
2224 57227 : TertMdot = state.dataLoopNodes->Node(TertNode).MassFlowRate;
2225 57227 : TertHumRate = state.dataLoopNodes->Node(TertNode).HumRat;
2226 57227 : TertTemp = state.dataLoopNodes->Node(TertNode).Temp;
2227 : // is Node pressure available or better? using outdoor pressure for now
2228 57227 : TertRho = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, TertTemp, TertHumRate);
2229 57227 : TertVdot = TertMdot / TertRho;
2230 :
2231 57227 : SecVdot = TotalVolFlow - TertVdot;
2232 :
2233 57227 : if (SecVdot < 0.0) { // all tertiary/relief air e.g. economizer wide open
2234 0 : SecVdot = 0.0;
2235 0 : SecondaryInletDryBulbTemp = TertTemp;
2236 0 : SecondaryInletWetBulbTemp = Psychrometrics::PsyTwbFnTdbWPb(state, TertTemp, TertHumRate, state.dataEnvrn->OutBaroPress);
2237 : SecondaryInletDewPointTemp =
2238 0 : Psychrometrics::PsyTdpFnTdbTwbPb(state, TertTemp, SecondaryInletWetBulbTemp, state.dataEnvrn->OutBaroPress);
2239 0 : SecondaryInletHumRatio = TertHumRate;
2240 : } else {
2241 :
2242 : // First determine mass flow of OA, in secondary
2243 : SecRho =
2244 57227 : Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, thisEvapCond.SecInletTemp, thisEvapCond.SecInletHumRat);
2245 57227 : SecMdot = SecRho * SecVdot;
2246 : // Mass balance on moisture to get outlet air humidity ratio
2247 : // this mixing takes place before wet media.
2248 57227 : PurgeMdot = SecMdot + TertMdot;
2249 57227 : PurgeHumRat = (SecMdot * thisEvapCond.SecInletHumRat + TertMdot * TertHumRate) / PurgeMdot;
2250 :
2251 : // Energy balance to get outlet air enthalpy
2252 :
2253 57227 : PurgeEnthalpy = (SecMdot * Psychrometrics::PsyHFnTdbW(thisEvapCond.SecInletTemp, thisEvapCond.SecInletHumRat) +
2254 57227 : TertMdot * Psychrometrics::PsyHFnTdbW(TertTemp, TertHumRate)) /
2255 : PurgeMdot;
2256 :
2257 : // Use Enthalpy and humidity ratio to get outlet temperature from psych chart
2258 :
2259 57227 : PurgeTemp = Psychrometrics::PsyTdbFnHW(PurgeEnthalpy, PurgeHumRat);
2260 57227 : SecondaryInletDryBulbTemp = PurgeTemp;
2261 57227 : SecondaryInletWetBulbTemp = Psychrometrics::PsyTwbFnTdbWPb(state, PurgeTemp, PurgeHumRat, state.dataEnvrn->OutBaroPress);
2262 : SecondaryInletDewPointTemp =
2263 57227 : Psychrometrics::PsyTdpFnTdbTwbPb(state, PurgeTemp, SecondaryInletWetBulbTemp, state.dataEnvrn->OutBaroPress);
2264 57227 : SecondaryInletHumRatio = PurgeHumRat;
2265 : }
2266 : }
2267 2143688 : if (thisEvapCond.EvapCoolerOperationControlFlag) {
2268 : // advanced mode: runs either in dry or wet depending on the entering conditions
2269 34302 : CalcIndirectResearchSpecialEvapCoolerAdvanced(
2270 : state, EvapCoolNum, SecondaryInletDryBulbTemp, SecondaryInletWetBulbTemp, SecondaryInletDewPointTemp, SecondaryInletHumRatio);
2271 :
2272 : } else {
2273 :
2274 2109386 : TEWB = thisEvapCond.InletWetBulbTemp;
2275 2109386 : TEDB = thisEvapCond.InletTemp;
2276 2109386 : PartLoad = thisEvapCond.PartLoadFract;
2277 :
2278 : //***************************************************************************
2279 : // TEMP LEAVING DRY BULB IS CALCULATED FROM A SIMPLE WET BULB APPROACH
2280 : // MODEL GIVEN THE INDIRECT STAGE EFFICIENCY.
2281 : // DRY BULB TEMP APPROACHES THE WET BULB TEMP ACROSS THE INDIRECT STAGE.
2282 : //***************************************************************************
2283 2109386 : if (PartLoad == 1.0) {
2284 : // Tout = Tin - ( 0.7 (Tin - Tpurge,wb,in)
2285 2014804 : thisEvapCond.OutletTemp = TEDB - StageEff * (TEDB - SecondaryInletWetBulbTemp);
2286 : // now bound with secondary dewpoint.
2287 : // unless the resulting Tout<=Tpurge,dp,in ; in which case Tout = Tin - 0.9(Tin-Tpurge,dp,in)
2288 :
2289 2014804 : BoundTemp = TEDB - thisEvapCond.DPBoundFactor * (TEDB - SecondaryInletDewPointTemp);
2290 2014804 : if (thisEvapCond.OutletTemp < BoundTemp) {
2291 1329 : thisEvapCond.OutletTemp = BoundTemp;
2292 1329 : thisEvapCond.DewPointBoundFlag = 1;
2293 : }
2294 94582 : } else if ((PartLoad < 1.0) && (PartLoad > 0.0)) {
2295 : // assume perfect control Use PLF for energy consumption
2296 36240 : if (thisEvapCond.DesiredOutletTemp < TEDB) {
2297 36239 : thisEvapCond.OutletTemp = thisEvapCond.DesiredOutletTemp;
2298 : }
2299 : } else {
2300 : // part load set to zero so no cooling
2301 58342 : thisEvapCond.OutletTemp = thisEvapCond.InletTemp;
2302 : }
2303 :
2304 : //***************************************************************************
2305 : // POWER OF THE SECONDARY AIR FAN with part load factor applied (assumes const efficiency)
2306 2109386 : thisEvapCond.EvapCoolerPower += thisEvapCond.IndirectVolFlowRate * thisEvapCond.FanSizingSpecificPower * PartLoad * FanPLR;
2307 :
2308 : // ENERGY CONSUMED BY THE RECIRCULATING PUMP
2309 : // ENERGY CONSUMED BY THE RECIRCULATING PUMP
2310 : // Add the pump energy to the total Evap Cooler energy consumption
2311 2109386 : thisEvapCond.EvapCoolerPower += thisEvapCond.IndirectRecircPumpPower * PartLoad * FanPLR;
2312 :
2313 : //***************************************************************************
2314 : // CALCULATE THE WET BULB TEMP in the primary system air using PSYCH ROUTINES
2315 : // There is a constant humidity ratio across the primary side but a reduction in the dry bulb temp
2316 2109386 : thisEvapCond.OuletWetBulbTemp =
2317 2109386 : Psychrometrics::PsyTwbFnTdbWPb(state, thisEvapCond.OutletTemp, thisEvapCond.InletHumRat, state.dataEnvrn->OutBaroPress);
2318 : //***************************************************************************
2319 : // CALCULATE other outlet properties using PSYCH ROUTINES
2320 2109386 : thisEvapCond.OutletHumRat = thisEvapCond.InletHumRat;
2321 :
2322 2109386 : thisEvapCond.OutletEnthalpy = Psychrometrics::PsyHFnTdbW(thisEvapCond.OutletTemp, thisEvapCond.OutletHumRat);
2323 : //******************
2324 : // WATER CONSUMPTION IN m3 OF WATER FOR Wet InDIRECT
2325 : // H2O [m3/s] = (QHX [J/s])/(2,500,000 [J/kgWater] * RhoWater [kgWater/m3])
2326 : //******************
2327 : //***** FIRST calculate the heat exchange on the primary air side**********
2328 2109386 : RhoAir = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, thisEvapCond.InletTemp, thisEvapCond.InletHumRat);
2329 2109386 : QHX = CFMAir * RhoAir * (thisEvapCond.InletEnthalpy - thisEvapCond.OutletEnthalpy);
2330 :
2331 2109386 : RhoWater = Psychrometrics::RhoH2O(state.dataEnvrn->OutDryBulbTemp);
2332 2109386 : EvapVdot = (QHX) / (2500000.0 * RhoWater);
2333 2109386 : DriftVdot = EvapVdot * thisEvapCond.DriftFraction;
2334 2109386 : if (thisEvapCond.BlowDownRatio > 0.0) {
2335 723624 : BlowDownVdot = EvapVdot / (thisEvapCond.BlowDownRatio - 1) - DriftVdot;
2336 723624 : if (BlowDownVdot < 0.0) {
2337 0 : BlowDownVdot = 0.0;
2338 : }
2339 : } else {
2340 1385762 : BlowDownVdot = 0.0;
2341 : }
2342 2109386 : thisEvapCond.EvapWaterConsumpRate = EvapVdot + DriftVdot + BlowDownVdot;
2343 : // A numerical check to keep from having very tiny negative water consumption values being reported
2344 2109386 : if (thisEvapCond.EvapWaterConsumpRate < 0.0) {
2345 3780 : thisEvapCond.EvapWaterConsumpRate = 0.0;
2346 : }
2347 : }
2348 :
2349 : } else {
2350 : // The evap cooler is not running and does not change conditions from inlet to outlet
2351 47218 : thisEvapCond.OutletTemp = thisEvapCond.InletTemp;
2352 47218 : thisEvapCond.OuletWetBulbTemp = thisEvapCond.InletWetBulbTemp;
2353 47218 : thisEvapCond.OutletHumRat = thisEvapCond.InletHumRat;
2354 47218 : thisEvapCond.OutletEnthalpy = thisEvapCond.InletEnthalpy;
2355 47218 : thisEvapCond.EvapCoolerEnergy = 0.0;
2356 47218 : thisEvapCond.EvapCoolerPower = 0.0;
2357 47218 : thisEvapCond.EvapWaterConsumpRate = 0.0;
2358 47218 : thisEvapCond.SecInletMassFlowRate = 0.0;
2359 : }
2360 :
2361 : // all of the mass flowrates are not changed across the evap cooler
2362 2190906 : thisEvapCond.OutletMassFlowRate = thisEvapCond.InletMassFlowRate;
2363 2190906 : thisEvapCond.OutletMassFlowRateMaxAvail = thisEvapCond.InletMassFlowRateMaxAvail;
2364 2190906 : thisEvapCond.OutletMassFlowRateMinAvail = thisEvapCond.InletMassFlowRateMinAvail;
2365 : // set secondary air side inlet mass flow rate to the outlet node
2366 2190906 : thisEvapCond.SecOutletMassFlowRate = thisEvapCond.SecInletMassFlowRate;
2367 2190906 : state.dataLoopNodes->Node(thisEvapCond.SecondaryInletNode).MassFlowRate = thisEvapCond.SecInletMassFlowRate;
2368 :
2369 : // the pressure is not changed across the evap cooler
2370 2190906 : thisEvapCond.OutletPressure = thisEvapCond.InletPressure;
2371 2190906 : }
2372 :
2373 34302 : void CalcIndirectResearchSpecialEvapCoolerAdvanced(EnergyPlusData &state,
2374 : int const EvapCoolNum,
2375 : Real64 const InletDryBulbTempSec,
2376 : Real64 const InletWetBulbTempSec,
2377 : Real64 const InletDewPointTempSec,
2378 : Real64 const InletHumRatioSec)
2379 : {
2380 :
2381 : // SUBROUTINE INFORMATION:
2382 : // AUTHOR B. Nigusse
2383 : // DATE WRITTEN October 2014
2384 :
2385 : // PURPOSE OF THIS SUBROUTINE:
2386 : // Subroutine models indirect evaporative cooler with variable effectiveness for wet and dry
2387 : // operating modes depending on entering conditions
2388 :
2389 : // SUBROUTINE PARAMETER DEFINITIONS:
2390 34302 : int constexpr MaxIte(500); // Maximum number of iterations for solver
2391 34302 : Real64 constexpr TempTol(0.01); // convergence tolerance
2392 :
2393 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2394 : Real64 BoundTemp; // temperature limit for outlet
2395 : Real64 PartLoad;
2396 : Real64 TdbOutSysWetMin; // system( primary ) air drybulb outlet temperature minimum based on wet coil
2397 : Real64 TdbOutSysDryMin; // system (primary) air drybulb outlet temperature minimum based on dry coil
2398 : Real64 AirMassFlowSec; // current secondary air mass flow rate
2399 : Real64 AirMassFlowSecDry; // current secondary air mass flow rate in dry mode
2400 : Real64 AirMassFlowSecWet; // current secondary air mass flow rate in wet mode
2401 : Real64 FlowRatioSec; // secondary air flow ratio in dry and wet mode
2402 : Real64 EvapCoolerTotalElectricPowerDry; // evaporative cooler current total electric power drawn
2403 : Real64 EvapCoolerTotalElectricPowerWet; // evaporative cooler current total electric power drawn
2404 : Real64 QHXLatent; // evaporative cooler latent heat transfer rate
2405 : Real64 hfg; // latent heat of vaporization of water at the secondary air inlet condition
2406 :
2407 : Real64 QHX; // Q Across Sec HX in Watts or J/sec
2408 : Real64 RhoWater;
2409 : Real64 RhoAir; // Density of the primary side air
2410 : Real64 MassFlowRateSecMin;
2411 34302 : Real64 BlowDownVdot(0.0);
2412 34302 : Real64 DriftVdot(0.0);
2413 34302 : Real64 EvapVdot(0.0);
2414 :
2415 34302 : auto &thisEvapCond(state.dataEvapCoolers->EvapCond(EvapCoolNum));
2416 :
2417 34302 : Real64 FlowRatioSecDry = 0.0; // current secondary air mass flow ratio in dry mode
2418 34302 : Real64 FlowRatioSecWet = 0.0; // current secondary air mass flow ratio in wet mode
2419 34302 : thisEvapCond.EvapCoolerRDDOperatingMode = OperatingMode::None;
2420 34302 : Real64 TEDB = thisEvapCond.InletTemp; // Entering Dry Bulb Temperature
2421 34302 : Real64 SysTempSetPoint = thisEvapCond.DesiredOutletTemp; // evaporative cooler outlet setpoint temperature, drybulb
2422 34302 : Real64 SecRho = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, InletDryBulbTempSec, InletHumRatioSec);
2423 34302 : Real64 MassFlowRateSecMax = SecRho * thisEvapCond.IndirectVolFlowRate; // Design secondary air mass flow rate
2424 34302 : CalcIndirectRDDEvapCoolerOutletTemp(
2425 : state, EvapCoolNum, OperatingMode::WetFull, MassFlowRateSecMax, InletDryBulbTempSec, InletWetBulbTempSec, InletHumRatioSec);
2426 34302 : TdbOutSysWetMin = thisEvapCond.OutletTemp;
2427 34302 : CalcIndirectRDDEvapCoolerOutletTemp(
2428 : state, EvapCoolNum, OperatingMode::DryFull, MassFlowRateSecMax, InletDryBulbTempSec, InletWetBulbTempSec, InletHumRatioSec);
2429 34302 : TdbOutSysDryMin = thisEvapCond.OutletTemp;
2430 :
2431 : // get current operating modes of indirect evaporative cooler research special
2432 34302 : thisEvapCond.EvapCoolerRDDOperatingMode = IndirectResearchSpecialEvapCoolerOperatingMode(
2433 : state, EvapCoolNum, InletDryBulbTempSec, InletWetBulbTempSec, TdbOutSysWetMin, TdbOutSysDryMin);
2434 :
2435 34302 : MassFlowRateSecMin = 0.0;
2436 34302 : AirMassFlowSec = MassFlowRateSecMax;
2437 34302 : PartLoad = thisEvapCond.PartLoadFract;
2438 : {
2439 34302 : if (thisEvapCond.EvapCoolerRDDOperatingMode == OperatingMode::DryModulated) {
2440 47134 : auto f = [&state, EvapCoolNum, SysTempSetPoint, InletDryBulbTempSec, InletWetBulbTempSec, InletHumRatioSec](Real64 AirMassFlowSec) {
2441 47134 : auto &EvapCond(state.dataEvapCoolers->EvapCond(EvapCoolNum));
2442 47134 : EvapCond.SecInletMassFlowRate = AirMassFlowSec;
2443 47134 : CalcIndirectRDDEvapCoolerOutletTemp(
2444 : state, EvapCoolNum, OperatingMode::DryModulated, AirMassFlowSec, InletDryBulbTempSec, InletWetBulbTempSec, InletHumRatioSec);
2445 47134 : Real64 const OutletAirTemp = EvapCond.OutletTemp; // evap Cooler outlet air temperature
2446 47134 : return SysTempSetPoint - OutletAirTemp;
2447 13226 : };
2448 13226 : int SolFla = 0; // Flag of solver
2449 13226 : General::SolveRoot(state, TempTol, MaxIte, SolFla, AirMassFlowSec, f, MassFlowRateSecMin, MassFlowRateSecMax);
2450 : // if the numerical inversion failed, issue error messages.
2451 13226 : if (SolFla == -1) {
2452 0 : if (!state.dataGlobal->WarmupFlag) {
2453 0 : if (thisEvapCond.IterationLimit == 0) {
2454 0 : ShowSevereError(state,
2455 0 : format("CalcIndirectResearchSpecialEvapCooler: calculate secondary air mass flow failed for Indirect "
2456 : "Evaporative Cooler Research Special = {}",
2457 0 : thisEvapCond.Name));
2458 0 : ShowContinueErrorTimeStamp(state, "");
2459 0 : ShowContinueError(state, format(" Iteration limit [{}] exceeded in calculating secondary air mass flow rate", MaxIte));
2460 0 : ShowContinueError(state, " Simulation continues");
2461 : }
2462 0 : ShowRecurringWarningErrorAtEnd(
2463 : state,
2464 0 : "Secondary air mass flow Iteration limit exceeded in Indirect Evaporative Cooler Research Special = " + thisEvapCond.Name,
2465 0 : thisEvapCond.IterationLimit);
2466 : }
2467 13226 : } else if (SolFla == -2) {
2468 0 : if (!state.dataGlobal->WarmupFlag) {
2469 0 : if (thisEvapCond.IterationFailed == 0) {
2470 0 : ShowSevereError(state,
2471 0 : format("CalcIndirectResearchSpecialEvapCooler: calculate secondary air mass flow failed for Indirect "
2472 : "Evaporative Cooler Research Special = {}",
2473 0 : thisEvapCond.Name));
2474 0 : ShowContinueErrorTimeStamp(state, "");
2475 0 : ShowContinueError(state, "...Bad secondary air mass flow rate limits");
2476 0 : ShowContinueError(state, format("...Given minimum secondary air mass flow rate={:.3R} kg/s", MassFlowRateSecMin));
2477 0 : ShowContinueError(state, format("...Given maximum secondary air mass flow rate={:.3R} kg/s", MassFlowRateSecMax));
2478 0 : ShowContinueError(state, " Simulation continues");
2479 : }
2480 0 : ShowRecurringWarningErrorAtEnd(state,
2481 0 : "Secondary air mass flow control failed in Indirect Evaporative Cooler Research Special = " +
2482 0 : thisEvapCond.Name,
2483 0 : thisEvapCond.IterationFailed);
2484 : }
2485 : }
2486 13226 : thisEvapCond.SecInletMassFlowRate = AirMassFlowSec;
2487 13226 : if (AirMassFlowSec > 0.0) {
2488 13226 : if (MassFlowRateSecMax > 0.0) {
2489 13226 : FlowRatioSec = AirMassFlowSec / MassFlowRateSecMax;
2490 : } else {
2491 0 : FlowRatioSec = 0.0;
2492 : }
2493 : } else {
2494 0 : FlowRatioSec = 0.0;
2495 : }
2496 13226 : thisEvapCond.EvapCoolerPower = IndEvapCoolerPower(state, EvapCoolNum, OperatingMode::DryModulated, FlowRatioSec);
2497 13226 : thisEvapCond.IECOperatingStatus = 1;
2498 21076 : } else if (thisEvapCond.EvapCoolerRDDOperatingMode == OperatingMode::DryFull) {
2499 8 : CalcIndirectRDDEvapCoolerOutletTemp(
2500 : state, EvapCoolNum, OperatingMode::DryFull, MassFlowRateSecMax, InletDryBulbTempSec, InletWetBulbTempSec, InletHumRatioSec);
2501 8 : thisEvapCond.SecInletMassFlowRate = MassFlowRateSecMax;
2502 8 : FlowRatioSec = 1.0;
2503 8 : thisEvapCond.EvapCoolerPower = IndEvapCoolerPower(state, EvapCoolNum, OperatingMode::DryFull, FlowRatioSec);
2504 8 : thisEvapCond.IECOperatingStatus = 1;
2505 21068 : } else if (thisEvapCond.EvapCoolerRDDOperatingMode == OperatingMode::DryWetModulated) {
2506 0 : auto f = [&state, EvapCoolNum, SysTempSetPoint, InletDryBulbTempSec, InletWetBulbTempSec, InletHumRatioSec](Real64 AirMassFlowSec) {
2507 0 : auto &EvapCond(state.dataEvapCoolers->EvapCond(EvapCoolNum));
2508 0 : EvapCond.SecInletMassFlowRate = AirMassFlowSec;
2509 0 : CalcIndirectRDDEvapCoolerOutletTemp(
2510 : state, EvapCoolNum, OperatingMode::DryModulated, AirMassFlowSec, InletDryBulbTempSec, InletWetBulbTempSec, InletHumRatioSec);
2511 0 : Real64 const OutletAirTemp = EvapCond.OutletTemp; // evap Cooler outlet air temperature
2512 0 : return SysTempSetPoint - OutletAirTemp;
2513 0 : };
2514 0 : int SolFla = 0; // Flag of solver
2515 0 : General::SolveRoot(state, TempTol, MaxIte, SolFla, AirMassFlowSec, f, MassFlowRateSecMin, MassFlowRateSecMax);
2516 : // if the numerical inversion failed, issue error messages.
2517 0 : if (SolFla == -1) {
2518 0 : if (!state.dataGlobal->WarmupFlag) {
2519 0 : if (thisEvapCond.IterationLimit == 0) {
2520 0 : ShowSevereError(state,
2521 0 : format("CalcIndirectResearchSpecialEvapCooler: calculate secondary air mass flow failed for Indirect "
2522 : "Evaporative Cooler Research Special = {}",
2523 0 : thisEvapCond.Name));
2524 0 : ShowContinueErrorTimeStamp(state, "");
2525 0 : ShowContinueError(state, format(" Iteration limit [{}] exceeded in calculating secondary air mass flow rate", MaxIte));
2526 0 : ShowContinueError(state, " Simulation continues");
2527 : }
2528 0 : ShowRecurringWarningErrorAtEnd(
2529 : state,
2530 0 : "Secondary air mass flow Iteration limit exceeded in Indirect Evaporative Cooler Research Special = " + thisEvapCond.Name,
2531 0 : thisEvapCond.IterationLimit);
2532 : }
2533 0 : } else if (SolFla == -2) {
2534 0 : if (!state.dataGlobal->WarmupFlag) {
2535 0 : if (thisEvapCond.IterationFailed == 0) {
2536 0 : ShowSevereError(state,
2537 0 : format("CalcIndirectResearchSpecialEvapCooler: calculate secondary air mass flow failed for Indirect "
2538 : "Evaporative Cooler Research Special = {}",
2539 0 : thisEvapCond.Name));
2540 0 : ShowContinueErrorTimeStamp(state, "");
2541 0 : ShowContinueError(state, "...Bad secondary air mass flow rate limits");
2542 0 : ShowContinueError(state, format("...Given minimum secondary air mass flow rate={:.3R} kg/s", MassFlowRateSecMin));
2543 0 : ShowContinueError(state, format("...Given maximum secondary air mass flow rate={:.3R} kg/s", MassFlowRateSecMax));
2544 0 : ShowContinueError(state, " Simulation continues");
2545 : }
2546 0 : ShowRecurringWarningErrorAtEnd(state,
2547 0 : "Secondary air mass flow control failed in Indirect Evaporative Cooler Research Special = " +
2548 0 : thisEvapCond.Name,
2549 0 : thisEvapCond.IterationFailed);
2550 : }
2551 : }
2552 0 : if (AirMassFlowSec > 0.0) {
2553 0 : if (MassFlowRateSecMax > 0.0) {
2554 0 : FlowRatioSec = AirMassFlowSec / MassFlowRateSecMax;
2555 : } else {
2556 0 : FlowRatioSec = 0.0;
2557 : }
2558 : } else {
2559 0 : FlowRatioSec = 0.0;
2560 : }
2561 0 : FlowRatioSecDry = FlowRatioSec;
2562 0 : AirMassFlowSecDry = AirMassFlowSec;
2563 0 : EvapCoolerTotalElectricPowerDry = IndEvapCoolerPower(state, EvapCoolNum, OperatingMode::DryModulated, FlowRatioSecDry);
2564 : // get wet operation performance
2565 0 : auto f2 = [&state, EvapCoolNum, SysTempSetPoint, InletDryBulbTempSec, InletWetBulbTempSec, InletHumRatioSec](Real64 AirMassFlowSec) {
2566 0 : auto &EvapCond(state.dataEvapCoolers->EvapCond(EvapCoolNum));
2567 0 : EvapCond.SecInletMassFlowRate = AirMassFlowSec;
2568 0 : CalcIndirectRDDEvapCoolerOutletTemp(
2569 : state, EvapCoolNum, OperatingMode::WetModulated, AirMassFlowSec, InletDryBulbTempSec, InletWetBulbTempSec, InletHumRatioSec);
2570 0 : Real64 const OutletAirTemp = EvapCond.OutletTemp; // evap Cooler outlet air temperature
2571 0 : return SysTempSetPoint - OutletAirTemp;
2572 0 : };
2573 0 : General::SolveRoot(state, TempTol, MaxIte, SolFla, AirMassFlowSec, f2, MassFlowRateSecMin, MassFlowRateSecMax);
2574 : // if the numerical inversion failed, issue error messages.
2575 0 : if (SolFla == -1) {
2576 0 : if (!state.dataGlobal->WarmupFlag) {
2577 0 : if (thisEvapCond.IterationLimit == 0) {
2578 0 : ShowSevereError(state,
2579 0 : format("CalcIndirectResearchSpecialEvapCooler: calculate secondary air mass flow failed for Indirect "
2580 : "Evaporative Cooler Research Special = {}",
2581 0 : thisEvapCond.Name));
2582 0 : ShowContinueErrorTimeStamp(state, "");
2583 0 : ShowContinueError(state, format(" Iteration limit [{}] exceeded in calculating secondary air mass flow rate", MaxIte));
2584 0 : ShowContinueError(state, " Simulation continues");
2585 : }
2586 0 : ShowRecurringWarningErrorAtEnd(
2587 : state,
2588 0 : "Secondary air mass flow Iteration limit exceeded in Indirect Evaporative Cooler Research Special = " + thisEvapCond.Name,
2589 0 : thisEvapCond.IterationLimit);
2590 : }
2591 0 : } else if (SolFla == -2) {
2592 0 : if (!state.dataGlobal->WarmupFlag) {
2593 0 : if (thisEvapCond.IterationFailed == 0) {
2594 0 : ShowSevereError(state,
2595 0 : format("CalcIndirectResearchSpecialEvapCooler: calculate secondary air mass flow failed for Indirect "
2596 : "Evaporative Cooler Research Special = {}",
2597 0 : thisEvapCond.Name));
2598 0 : ShowContinueErrorTimeStamp(state, "");
2599 0 : ShowContinueError(state, "...Bad secondary air mass flow rate limits");
2600 0 : ShowContinueError(state, format("...Given minimum secondary air mass flow rate={:.3R} kg/s", MassFlowRateSecMin));
2601 0 : ShowContinueError(state, format("...Given maximum secondary air mass flow rate={:.3R} kg/s", MassFlowRateSecMax));
2602 0 : ShowContinueError(state, " Simulation continues");
2603 : }
2604 0 : ShowRecurringWarningErrorAtEnd(state,
2605 0 : "Secondary air mass flow control failed in Indirect Evaporative Cooler Research Special = " +
2606 0 : thisEvapCond.Name,
2607 0 : thisEvapCond.IterationFailed);
2608 : }
2609 : }
2610 0 : if (AirMassFlowSec > 0.0) {
2611 0 : if (MassFlowRateSecMax > 0.0) {
2612 0 : FlowRatioSec = AirMassFlowSec / MassFlowRateSecMax;
2613 : } else {
2614 0 : FlowRatioSec = 0.0;
2615 : }
2616 : } else {
2617 0 : FlowRatioSec = 0.0;
2618 : }
2619 0 : FlowRatioSecWet = FlowRatioSec;
2620 0 : AirMassFlowSecWet = AirMassFlowSec;
2621 0 : EvapCoolerTotalElectricPowerWet = IndEvapCoolerPower(state, EvapCoolNum, OperatingMode::WetModulated, FlowRatioSecWet);
2622 : // compare the dry and wet operation total electric power
2623 0 : if (EvapCoolerTotalElectricPowerDry < EvapCoolerTotalElectricPowerWet) {
2624 0 : thisEvapCond.EvapCoolerRDDOperatingMode = OperatingMode::DryModulated;
2625 0 : FlowRatioSec = FlowRatioSecDry;
2626 0 : thisEvapCond.SecInletMassFlowRate = AirMassFlowSecDry;
2627 0 : CalcIndirectRDDEvapCoolerOutletTemp(
2628 : state, EvapCoolNum, OperatingMode::DryModulated, AirMassFlowSecDry, InletDryBulbTempSec, InletWetBulbTempSec, InletHumRatioSec);
2629 0 : thisEvapCond.EvapCoolerPower = IndEvapCoolerPower(state, EvapCoolNum, OperatingMode::DryModulated, FlowRatioSec);
2630 0 : thisEvapCond.IECOperatingStatus = 1;
2631 : } else {
2632 0 : thisEvapCond.EvapCoolerRDDOperatingMode = OperatingMode::WetModulated;
2633 0 : FlowRatioSec = FlowRatioSecWet;
2634 0 : thisEvapCond.SecInletMassFlowRate = AirMassFlowSecWet;
2635 0 : CalcIndirectRDDEvapCoolerOutletTemp(
2636 : state, EvapCoolNum, OperatingMode::WetModulated, AirMassFlowSecWet, InletDryBulbTempSec, InletWetBulbTempSec, InletHumRatioSec);
2637 0 : thisEvapCond.EvapCoolerPower = IndEvapCoolerPower(state, EvapCoolNum, OperatingMode::WetModulated, FlowRatioSec);
2638 0 : thisEvapCond.IECOperatingStatus = 2;
2639 : }
2640 21068 : } else if (thisEvapCond.EvapCoolerRDDOperatingMode == OperatingMode::WetModulated) {
2641 52764 : auto f = [&state, EvapCoolNum, SysTempSetPoint, InletDryBulbTempSec, InletWetBulbTempSec, InletHumRatioSec](Real64 AirMassFlowSec) {
2642 52764 : auto &EvapCond(state.dataEvapCoolers->EvapCond(EvapCoolNum));
2643 52764 : EvapCond.SecInletMassFlowRate = AirMassFlowSec;
2644 52764 : CalcIndirectRDDEvapCoolerOutletTemp(
2645 : state, EvapCoolNum, OperatingMode::WetModulated, AirMassFlowSec, InletDryBulbTempSec, InletWetBulbTempSec, InletHumRatioSec);
2646 52764 : Real64 const OutletAirTemp = EvapCond.OutletTemp; // evap Cooler outlet air temperature
2647 52764 : return SysTempSetPoint - OutletAirTemp;
2648 4452 : };
2649 4452 : int SolFla = 0; // Flag of solver
2650 4452 : General::SolveRoot(state, TempTol, MaxIte, SolFla, AirMassFlowSec, f, MassFlowRateSecMin, MassFlowRateSecMax);
2651 : // if the numerical inversion failed, issue error messages.
2652 4452 : if (SolFla == -1) {
2653 0 : if (!state.dataGlobal->WarmupFlag) {
2654 0 : if (thisEvapCond.IterationLimit == 0) {
2655 0 : ShowSevereError(state,
2656 0 : format("CalcIndirectResearchSpecialEvapCooler: calculate secondary air mass flow failed for Indirect "
2657 : "Evaporative Cooler Research Special = {}",
2658 0 : thisEvapCond.Name));
2659 0 : ShowContinueErrorTimeStamp(state, "");
2660 0 : ShowContinueError(state, format(" Iteration limit [{}] exceeded in calculating secondary air mass flow rate", MaxIte));
2661 0 : ShowContinueError(state, " Simulation continues");
2662 : }
2663 0 : ShowRecurringWarningErrorAtEnd(
2664 : state,
2665 0 : "Secondary air mass flow Iteration limit exceeded in Indirect Evaporative Cooler Research Special = " + thisEvapCond.Name,
2666 0 : thisEvapCond.IterationLimit);
2667 : }
2668 4452 : } else if (SolFla == -2) {
2669 0 : if (!state.dataGlobal->WarmupFlag) {
2670 0 : if (thisEvapCond.IterationFailed == 0) {
2671 0 : ShowSevereError(state,
2672 0 : format("CalcIndirectResearchSpecialEvapCooler: calculate secondary air mass flow failed for Indirect "
2673 : "Evaporative Cooler Research Special = {}",
2674 0 : thisEvapCond.Name));
2675 0 : ShowContinueErrorTimeStamp(state, "");
2676 0 : ShowContinueError(state, "...Bad secondary air mass flow rate limits");
2677 0 : ShowContinueError(state, format("...Given minimum secondary air mass flow rate={:.3R} kg/s", MassFlowRateSecMin));
2678 0 : ShowContinueError(state, format("...Given maximum secondary air mass flow rate={:.3R} kg/s", MassFlowRateSecMax));
2679 0 : ShowContinueError(state, " Simulation continues");
2680 : }
2681 0 : ShowRecurringWarningErrorAtEnd(state,
2682 0 : "Secondary air mass flow control failed in Indirect Evaporative Cooler Research Special = " +
2683 0 : thisEvapCond.Name,
2684 0 : thisEvapCond.IterationFailed);
2685 : }
2686 : }
2687 4452 : thisEvapCond.SecInletMassFlowRate = AirMassFlowSec;
2688 4452 : if (AirMassFlowSec > 0.0) {
2689 4452 : if (MassFlowRateSecMax > 0.0) {
2690 4452 : FlowRatioSec = AirMassFlowSec / MassFlowRateSecMax;
2691 : } else {
2692 0 : FlowRatioSec = 0.0;
2693 : }
2694 : } else {
2695 0 : FlowRatioSec = 0.0;
2696 : }
2697 4452 : thisEvapCond.EvapCoolerPower = IndEvapCoolerPower(state, EvapCoolNum, OperatingMode::WetModulated, FlowRatioSec);
2698 4452 : thisEvapCond.IECOperatingStatus = 2;
2699 16616 : } else if (thisEvapCond.EvapCoolerRDDOperatingMode == OperatingMode::WetFull) {
2700 236 : CalcIndirectRDDEvapCoolerOutletTemp(
2701 : state, EvapCoolNum, OperatingMode::WetFull, MassFlowRateSecMax, InletDryBulbTempSec, InletWetBulbTempSec, InletHumRatioSec);
2702 236 : thisEvapCond.SecInletMassFlowRate = MassFlowRateSecMax;
2703 236 : FlowRatioSec = 1.0;
2704 236 : thisEvapCond.EvapCoolerPower = IndEvapCoolerPower(state, EvapCoolNum, OperatingMode::WetFull, FlowRatioSec);
2705 236 : thisEvapCond.IECOperatingStatus = 2;
2706 : }
2707 : }
2708 34302 : if (PartLoad == 1.0) {
2709 9148 : if (thisEvapCond.EvapCoolerRDDOperatingMode == OperatingMode::WetModulated ||
2710 6860 : thisEvapCond.EvapCoolerRDDOperatingMode == OperatingMode::WetFull) {
2711 2524 : BoundTemp = TEDB - thisEvapCond.DPBoundFactor * (TEDB - InletDewPointTempSec);
2712 2524 : if (thisEvapCond.OutletTemp < BoundTemp) {
2713 0 : thisEvapCond.OutletTemp = BoundTemp;
2714 0 : thisEvapCond.DewPointBoundFlag = 1;
2715 : }
2716 : }
2717 25154 : } else if ((PartLoad < 1.0) && (PartLoad > 0.0)) {
2718 : // assume perfect control Use PLF for energy consumption
2719 2912 : if (thisEvapCond.DesiredOutletTemp < TEDB) {
2720 2912 : thisEvapCond.OutletTemp = thisEvapCond.DesiredOutletTemp;
2721 : }
2722 : } else {
2723 : // part load set to zero so no cooling
2724 22242 : thisEvapCond.OutletTemp = thisEvapCond.InletTemp;
2725 : }
2726 34302 : if (thisEvapCond.EvapCoolerRDDOperatingMode != OperatingMode::None) {
2727 : // There is a constant humidity ratio across the primary side but a reduction in the dry bulb temp
2728 17922 : thisEvapCond.OuletWetBulbTemp =
2729 17922 : Psychrometrics::PsyTwbFnTdbWPb(state, thisEvapCond.OutletTemp, thisEvapCond.InletHumRat, state.dataEnvrn->OutBaroPress);
2730 17922 : thisEvapCond.OutletHumRat = thisEvapCond.InletHumRat;
2731 17922 : thisEvapCond.OutletEnthalpy = Psychrometrics::PsyHFnTdbW(thisEvapCond.OutletTemp, thisEvapCond.OutletHumRat);
2732 17922 : RhoAir = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, thisEvapCond.InletTemp, thisEvapCond.InletHumRat);
2733 17922 : QHX = thisEvapCond.VolFlowRate * RhoAir * (thisEvapCond.InletEnthalpy - thisEvapCond.OutletEnthalpy);
2734 17922 : if (QHX > HVAC::SmallLoad) {
2735 : // get secondary air outlet condition
2736 6252 : CalcSecondaryAirOutletCondition(state,
2737 : EvapCoolNum,
2738 : thisEvapCond.EvapCoolerRDDOperatingMode,
2739 : thisEvapCond.SecInletMassFlowRate,
2740 : InletDryBulbTempSec,
2741 : InletWetBulbTempSec,
2742 : InletHumRatioSec,
2743 : QHX,
2744 : QHXLatent);
2745 6252 : RhoWater = Psychrometrics::RhoH2O(state.dataEnvrn->OutDryBulbTemp); // this if it is at the outside air inlet node condition
2746 6252 : hfg = Psychrometrics::PsyHfgAirFnWTdb(InletHumRatioSec, InletDryBulbTempSec);
2747 6252 : EvapVdot = (QHXLatent) / (hfg * RhoWater);
2748 6252 : DriftVdot = EvapVdot * thisEvapCond.DriftFraction;
2749 6252 : if (thisEvapCond.BlowDownRatio > 0.0) {
2750 0 : BlowDownVdot = EvapVdot / (thisEvapCond.BlowDownRatio - 1) - DriftVdot;
2751 0 : if (BlowDownVdot < 0.0) {
2752 0 : BlowDownVdot = 0.0;
2753 : }
2754 : } else {
2755 6252 : BlowDownVdot = 0.0;
2756 : }
2757 6252 : thisEvapCond.EvapWaterConsumpRate = EvapVdot + DriftVdot + BlowDownVdot;
2758 : // A numerical check to keep from having very tiny negative water consumption values being reported
2759 6252 : if (thisEvapCond.EvapWaterConsumpRate < 0.0) {
2760 0 : thisEvapCond.EvapWaterConsumpRate = 0.0;
2761 : }
2762 : } else {
2763 11670 : thisEvapCond.OutletTemp = thisEvapCond.InletTemp;
2764 11670 : thisEvapCond.OuletWetBulbTemp = thisEvapCond.InletWetBulbTemp;
2765 11670 : thisEvapCond.OutletEnthalpy = thisEvapCond.InletEnthalpy;
2766 11670 : thisEvapCond.EvapCoolerEnergy = 0.0;
2767 11670 : thisEvapCond.EvapCoolerPower = 0.0;
2768 11670 : thisEvapCond.EvapWaterConsumpRate = 0.0;
2769 11670 : thisEvapCond.SecInletMassFlowRate = 0.0;
2770 11670 : thisEvapCond.IECOperatingStatus = 0;
2771 11670 : thisEvapCond.StageEff = 0.0;
2772 11670 : CalcSecondaryAirOutletCondition(state,
2773 : EvapCoolNum,
2774 : thisEvapCond.EvapCoolerRDDOperatingMode,
2775 : 0.0,
2776 : InletDryBulbTempSec,
2777 : InletWetBulbTempSec,
2778 : InletHumRatioSec,
2779 : QHX,
2780 : QHXLatent);
2781 : }
2782 :
2783 : } else {
2784 : // The evap cooler is not running and does not change conditions from inlet to outlet
2785 16380 : thisEvapCond.OutletTemp = thisEvapCond.InletTemp;
2786 16380 : thisEvapCond.OuletWetBulbTemp = thisEvapCond.InletWetBulbTemp;
2787 16380 : thisEvapCond.OutletHumRat = thisEvapCond.InletHumRat;
2788 16380 : thisEvapCond.OutletEnthalpy = thisEvapCond.InletEnthalpy;
2789 16380 : thisEvapCond.SecOutletTemp = thisEvapCond.SecInletTemp;
2790 16380 : thisEvapCond.SecOutletHumRat = thisEvapCond.SecInletHumRat;
2791 16380 : thisEvapCond.SecOutletEnthalpy = thisEvapCond.SecInletEnthalpy;
2792 16380 : thisEvapCond.SecOutletMassFlowRate = thisEvapCond.SecInletMassFlowRate;
2793 16380 : thisEvapCond.EvapCoolerEnergy = 0.0;
2794 16380 : thisEvapCond.EvapCoolerPower = 0.0;
2795 16380 : thisEvapCond.EvapWaterConsumpRate = 0.0;
2796 16380 : thisEvapCond.SecInletMassFlowRate = 0.0;
2797 16380 : thisEvapCond.IECOperatingStatus = 0;
2798 16380 : thisEvapCond.StageEff = 0.0;
2799 : }
2800 34302 : }
2801 :
2802 34302 : OperatingMode IndirectResearchSpecialEvapCoolerOperatingMode(EnergyPlusData &state,
2803 : int const EvapCoolNum,
2804 : Real64 const InletDryBulbTempSec,
2805 : Real64 const InletWetBulbTempSec,
2806 : Real64 const TdbOutSysWetMin,
2807 : Real64 const TdbOutSysDryMin)
2808 : {
2809 :
2810 : // PURPOSE OF THIS SUBROUTINE:
2811 : // Determines current operating mode of indirect research special evaporative cooler
2812 : // from the five valid operating modes depending the primary and secondary air
2813 : // temperatures, setpoint temperature, and full capacity air outlet temperature.
2814 :
2815 : // METHODOLOGY EMPLOYED:
2816 : // compares various temperatures to determine the operating mode
2817 :
2818 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2819 : Real64 InletDryBulbTempPri; // entering air dry bulb temperature of primary air
2820 : Real64 SysTempSetPoint; // evaporative cooler outlet setpoint temperature, drybulb
2821 : OperatingMode OperatingMode; // current operating mode of indirect evaporative cooler
2822 :
2823 34302 : auto const &thisEvapCond = state.dataEvapCoolers->EvapCond(EvapCoolNum);
2824 :
2825 34302 : InletDryBulbTempPri = thisEvapCond.InletTemp;
2826 34302 : SysTempSetPoint = thisEvapCond.DesiredOutletTemp;
2827 :
2828 : // Now determine the operating modes of indirect evaporative cooler research special. There are five allowed operating modes
2829 34302 : if ((InletDryBulbTempPri <= SysTempSetPoint) ||
2830 29538 : (InletDryBulbTempPri > thisEvapCond.MaxOATDBEvapCooler && InletWetBulbTempSec > thisEvapCond.MaxOATWBEvapCooler) ||
2831 : (InletDryBulbTempPri < InletDryBulbTempSec)) {
2832 16380 : OperatingMode = OperatingMode::None;
2833 17922 : } else if ((InletDryBulbTempSec < thisEvapCond.MinOATDBEvapCooler && TdbOutSysDryMin < SysTempSetPoint)) {
2834 13226 : OperatingMode = OperatingMode::DryModulated; // dry mode capacity modulated
2835 4696 : } else if ((InletDryBulbTempSec < thisEvapCond.MinOATDBEvapCooler && SysTempSetPoint <= TdbOutSysDryMin)) {
2836 8 : OperatingMode = OperatingMode::DryFull; // dry mode in full capacity
2837 4688 : } else if ((InletDryBulbTempSec >= thisEvapCond.MinOATDBEvapCooler && InletWetBulbTempSec < thisEvapCond.MaxOATWBEvapCooler &&
2838 : SysTempSetPoint <= TdbOutSysWetMin)) {
2839 236 : OperatingMode = OperatingMode::WetFull; // wet mode in full capacity
2840 4452 : } else if ((InletDryBulbTempSec >= thisEvapCond.MinOATDBEvapCooler && InletWetBulbTempSec < thisEvapCond.MaxOATWBEvapCooler &&
2841 : TdbOutSysWetMin < SysTempSetPoint)) { // && SysTempSetPoint < TdbOutSysDryMin
2842 4452 : OperatingMode = OperatingMode::WetModulated; // wet mode capacity modulated
2843 0 : } else if ((InletDryBulbTempSec >= thisEvapCond.MinOATDBEvapCooler && InletDryBulbTempSec < thisEvapCond.MaxOATDBEvapCooler &&
2844 0 : InletWetBulbTempSec < thisEvapCond.MaxOATWBEvapCooler && SysTempSetPoint < TdbOutSysDryMin && TdbOutSysWetMin < SysTempSetPoint)) {
2845 0 : OperatingMode = OperatingMode::DryWetModulated; // modulated in dry and wet mode, and the lower total power will be used
2846 : } else {
2847 0 : OperatingMode = OperatingMode::None; // this condition should not happen unless the bounds do not cover all combinations possible
2848 : }
2849 34302 : return OperatingMode;
2850 : }
2851 :
2852 168746 : void CalcIndirectRDDEvapCoolerOutletTemp(EnergyPlusData &state,
2853 : int const EvapCoolNum,
2854 : OperatingMode DryOrWetOperatingMode,
2855 : Real64 const AirMassFlowSec,
2856 : Real64 const EDBTSec,
2857 : Real64 const EWBTSec,
2858 : Real64 const EHumRatSec)
2859 : {
2860 : // SUBROUTINE INFORMATION:
2861 : // AUTHOR B. Nigusse
2862 : // DATE WRITTEN Sep 2014
2863 :
2864 : // PURPOSE OF THIS SUBROUTINE:
2865 : // Indirect research special evaporative cooler performance:
2866 : // determines the IEC primary air outlet temperature
2867 :
2868 : // METHODOLOGY EMPLOYED:
2869 : // Uses effectiveness and energy balance equations to determine
2870 : // primary air outlet temperature. The dry and wet effectiveness
2871 : // values are used depending on operating modes.
2872 :
2873 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2874 : Real64 OutletTemp; // evaporative cooler current outlet air drybulb temperature
2875 : Real64 RhoAirSec; // density of secondary air at inlet condition
2876 : Real64 RhoAirSys; // density of primary air at inlet condition
2877 : Real64 EffectivenessDry; // dry coil effectiveness
2878 : Real64 EffectivenessWet; // wet coil effectiveness
2879 : Real64 FlowRatio; // flow ratio based on current to the design of secondary air flow rate
2880 : Real64 EffModDryMode; // dry mode effectiveness modifier for flow ratio
2881 : Real64 EffModWetMode; // wet mode effectiveness modifier for flow ratio
2882 : Real64 CapFlowSys; // capacity flow (massFlowRate * Specific Heat) of primary air system
2883 : Real64 CapFlowSec; // capacity flow (massFlowRate * Specific Heat) of secondary system
2884 : Real64 CpAirSec; // specific heat of secondary air at inlet condition
2885 : Real64 CpAirSys; // specific heat of primary air at inlet condition
2886 :
2887 : Real64 QHXRate; // total heat transfer rate
2888 : Real64 OutletTempSec; // secondary air outlet temperature
2889 : Real64 SecOutletAirHumRat; // secondary air humidity ratio at constant temperature (Pure mass transfer)
2890 : Real64 SecOutletEnthalpy; // secondary air outlet enthalpy
2891 :
2892 168746 : auto &thisEvapCond(state.dataEvapCoolers->EvapCond(EvapCoolNum));
2893 :
2894 168746 : if (thisEvapCond.InletMassFlowRate > 0.0) {
2895 168746 : FlowRatio = AirMassFlowSec / thisEvapCond.InletMassFlowRate; // ratio of current secondary air flow to current primary air flow
2896 : } else {
2897 0 : FlowRatio = 1.0;
2898 : }
2899 168746 : if (AirMassFlowSec > 0.0) {
2900 151068 : RhoAirSec = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, EDBTSec, EHumRatSec);
2901 151068 : RhoAirSys = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, thisEvapCond.InletTemp, thisEvapCond.InletHumRat);
2902 151068 : if (DryOrWetOperatingMode == OperatingMode::DryModulated || DryOrWetOperatingMode == OperatingMode::DryFull) {
2903 68218 : if (thisEvapCond.DrybulbEffecCurve != nullptr) {
2904 68218 : EffModDryMode = thisEvapCond.DrybulbEffecCurve->value(state, FlowRatio);
2905 : } else {
2906 0 : EffModDryMode = 1.0;
2907 : }
2908 68218 : EffectivenessDry = thisEvapCond.DryCoilMaxEfficiency * EffModDryMode;
2909 68218 : thisEvapCond.StageEff = EffectivenessDry;
2910 68218 : OutletTemp = thisEvapCond.InletTemp - EffectivenessDry * (thisEvapCond.InletTemp - EDBTSec);
2911 68218 : if (OutletTemp > thisEvapCond.InletTemp) {
2912 11646 : OutletTemp = thisEvapCond.InletTemp;
2913 : }
2914 68218 : CpAirSys = Psychrometrics::PsyCpAirFnW(thisEvapCond.InletHumRat);
2915 68218 : CapFlowSys = thisEvapCond.InletMassFlowRate * CpAirSys;
2916 68218 : QHXRate = CapFlowSys * (thisEvapCond.InletTemp - OutletTemp);
2917 68218 : CpAirSec = Psychrometrics::PsyCpAirFnW(EHumRatSec);
2918 68218 : CapFlowSec = AirMassFlowSec * CpAirSec;
2919 68218 : OutletTempSec = EDBTSec + QHXRate / CapFlowSec;
2920 68218 : if (OutletTempSec >= thisEvapCond.InletTemp) {
2921 25588 : OutletTempSec = thisEvapCond.InletTemp - 0.2;
2922 25588 : QHXRate = CapFlowSec * (OutletTempSec - EDBTSec);
2923 25588 : OutletTemp = thisEvapCond.InletTemp - QHXRate / CapFlowSys;
2924 : }
2925 68218 : thisEvapCond.SecOutletTemp = OutletTempSec;
2926 82850 : } else if (DryOrWetOperatingMode == OperatingMode::WetModulated || DryOrWetOperatingMode == OperatingMode::WetFull) {
2927 82850 : if (thisEvapCond.WetbulbEffecCurve != nullptr) {
2928 82850 : EffModWetMode = thisEvapCond.WetbulbEffecCurve->value(state, FlowRatio);
2929 : } else {
2930 0 : EffModWetMode = 1.0;
2931 : }
2932 82850 : EffectivenessWet = thisEvapCond.WetCoilMaxEfficiency * EffModWetMode;
2933 82850 : thisEvapCond.StageEff = EffectivenessWet;
2934 82850 : OutletTemp = thisEvapCond.InletTemp - EffectivenessWet * (thisEvapCond.InletTemp - EWBTSec);
2935 82850 : if (OutletTemp > thisEvapCond.InletTemp) {
2936 11530 : OutletTemp = thisEvapCond.InletTemp;
2937 : }
2938 82850 : CpAirSys = Psychrometrics::PsyCpAirFnW(thisEvapCond.InletHumRat);
2939 82850 : CapFlowSys = thisEvapCond.InletMassFlowRate * CpAirSys;
2940 82850 : QHXRate = CapFlowSys * (thisEvapCond.InletTemp - OutletTemp);
2941 82850 : SecOutletEnthalpy = thisEvapCond.SecInletEnthalpy + QHXRate / AirMassFlowSec;
2942 82850 : SecOutletAirHumRat = Psychrometrics::PsyWFnTdbH(state, EDBTSec,
2943 : SecOutletEnthalpy); // assumes constant temperature moisture addition
2944 : // we may need check based on maximum allowed humidity ratio
2945 82850 : thisEvapCond.SecOutletTemp = EDBTSec;
2946 82850 : thisEvapCond.SecOutletHumRat = SecOutletAirHumRat;
2947 82850 : thisEvapCond.SecOutletEnthalpy = SecOutletEnthalpy;
2948 : } else {
2949 0 : OutletTemp = thisEvapCond.InletTemp;
2950 0 : thisEvapCond.StageEff = 0.0;
2951 : }
2952 : } else {
2953 17678 : OutletTemp = thisEvapCond.InletTemp;
2954 17678 : thisEvapCond.StageEff = 0.0;
2955 : }
2956 : // set results to into output variables
2957 168746 : thisEvapCond.OutletTemp = OutletTemp;
2958 168746 : }
2959 :
2960 17922 : void CalcSecondaryAirOutletCondition(EnergyPlusData &state,
2961 : int const EvapCoolNum,
2962 : OperatingMode OperatingMode,
2963 : Real64 const AirMassFlowSec,
2964 : Real64 const EDBTSec,
2965 : Real64 const EWBTSec,
2966 : Real64 const EHumRatSec,
2967 : Real64 const QHXTotal,
2968 : Real64 &QHXLatent)
2969 : {
2970 : // SUBROUTINE INFORMATION:
2971 : // AUTHOR B. Nigusse
2972 : // DATE WRITTEN Oct 2014
2973 :
2974 : // PURPOSE OF THIS SUBROUTINE:
2975 : // Indirect research special evaporative cooler: determines the secondary air outlet conditions
2976 :
2977 : // METHODOLOGY EMPLOYED:
2978 : // applies energy balance equations to determine the secondary air outlet condition
2979 : // For wt operations assumes the secondary air leaves at at inlet temperature, i.e.,
2980 : // latent heat transfer only. For dry operation the humidity ratio remains constant.
2981 :
2982 : // REFERENCES:
2983 : // CalculateWaterUsage routine of cooling towers for wet operation mode
2984 :
2985 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2986 : Real64 SecOutletAirHumRat; // secondary air humidity ratio at the outlet node
2987 : Real64 SecOutletEnthalpy; // secondary air outlet enthalpy
2988 : Real64 CpAirSec; // specific heat of secondary air at inlet condition
2989 : Real64 hfg; // secondary air side enthalpy of evaporation
2990 :
2991 17922 : auto &thisEvapCond(state.dataEvapCoolers->EvapCond(EvapCoolNum));
2992 :
2993 17922 : QHXLatent = 0.0;
2994 17922 : if (AirMassFlowSec > 0.0) {
2995 6252 : if ((OperatingMode == OperatingMode::DryModulated || OperatingMode == OperatingMode::DryFull)) {
2996 1564 : thisEvapCond.SecOutletHumRat = EHumRatSec;
2997 1564 : CpAirSec = Psychrometrics::PsyCpAirFnW(EHumRatSec);
2998 1564 : thisEvapCond.SecOutletTemp = EDBTSec + QHXTotal / AirMassFlowSec / CpAirSec;
2999 1564 : thisEvapCond.SecOutletEnthalpy = Psychrometrics::PsyHFnTdbW(thisEvapCond.SecOutletTemp, EHumRatSec);
3000 1564 : thisEvapCond.SecOuletWetBulbTemp =
3001 1564 : Psychrometrics::PsyTwbFnTdbWPb(state, thisEvapCond.SecOutletTemp, EHumRatSec, state.dataEnvrn->OutBaroPress);
3002 4688 : } else if ((OperatingMode == OperatingMode::WetModulated || OperatingMode == OperatingMode::WetFull)) {
3003 4688 : SecOutletEnthalpy = thisEvapCond.SecInletEnthalpy + QHXTotal / AirMassFlowSec;
3004 4688 : SecOutletAirHumRat = Psychrometrics::PsyWFnTdbH(state, EDBTSec,
3005 : SecOutletEnthalpy); // assumes a constant temperature moisture addition
3006 4688 : thisEvapCond.SecOutletTemp = EDBTSec;
3007 4688 : thisEvapCond.SecOutletHumRat = SecOutletAirHumRat;
3008 4688 : thisEvapCond.SecOutletEnthalpy = SecOutletEnthalpy;
3009 4688 : thisEvapCond.SecOuletWetBulbTemp =
3010 4688 : Psychrometrics::PsyTwbFnTdbWPb(state, thisEvapCond.SecOutletTemp, SecOutletAirHumRat, state.dataEnvrn->OutBaroPress);
3011 4688 : hfg = Psychrometrics::PsyHfgAirFnWTdb(EHumRatSec, EDBTSec);
3012 4688 : QHXLatent = min(QHXTotal, AirMassFlowSec * (SecOutletAirHumRat - EHumRatSec) * hfg);
3013 : } else {
3014 : // set results to into output variables
3015 0 : thisEvapCond.SecOutletTemp = EDBTSec;
3016 0 : thisEvapCond.SecOuletWetBulbTemp = EWBTSec;
3017 0 : thisEvapCond.SecOutletHumRat = EHumRatSec;
3018 0 : thisEvapCond.SecOutletEnthalpy = thisEvapCond.SecInletEnthalpy;
3019 : }
3020 : } else {
3021 11670 : thisEvapCond.SecOutletTemp = EDBTSec;
3022 11670 : thisEvapCond.SecOuletWetBulbTemp = EWBTSec;
3023 11670 : thisEvapCond.SecOutletHumRat = EHumRatSec;
3024 11670 : thisEvapCond.SecOutletEnthalpy = thisEvapCond.SecInletEnthalpy;
3025 : }
3026 17922 : }
3027 :
3028 17922 : Real64 IndEvapCoolerPower(EnergyPlusData &state,
3029 : int const EvapCoolIndex, // Unit index
3030 : OperatingMode DryWetMode, // dry or wet operating mode of evaporator cooler
3031 : Real64 const FlowRatio // secondary air flow fraction
3032 : )
3033 : {
3034 :
3035 : // SUBROUTINE INFORMATION:
3036 : // AUTHOR B. Nigusse
3037 : // DATE WRITTEN Sep 2014
3038 :
3039 : // PURPOSE OF THIS SUBROUTINE:
3040 : // Calculates the Indirect Evaporative Cooler Total Electric Power
3041 :
3042 : // METHODOLOGY EMPLOYED:
3043 : // Scales the design fan and pump power depending on secondary air flow fraction
3044 : // and sums the two to determine the evaporative cooler total electric power.
3045 :
3046 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3047 : Real64 FanPowerModCurveValue; // fan power modifier curve value
3048 : Real64 PumpPowerModCurveValue; // fan power modifier curve value
3049 : Real64 EvapCoolertotalPower; // current evaporative cooler total electric power
3050 :
3051 17922 : auto &thisEvapCond(state.dataEvapCoolers->EvapCond(EvapCoolIndex));
3052 :
3053 17922 : EvapCoolertotalPower = 0.0;
3054 17922 : if (FlowRatio > 0.0) {
3055 17922 : if (thisEvapCond.FanPowerModifierCurve != nullptr) {
3056 17922 : FanPowerModCurveValue = thisEvapCond.FanPowerModifierCurve->value(state, FlowRatio);
3057 : } else {
3058 0 : FanPowerModCurveValue = thisEvapCond.PartLoadFract * FlowRatio;
3059 : }
3060 17922 : EvapCoolertotalPower += thisEvapCond.IndirectFanPower * FanPowerModCurveValue;
3061 17922 : if (DryWetMode == OperatingMode::WetModulated || DryWetMode == OperatingMode::WetFull) {
3062 : // Add the pump power to the total Evap Cooler power for wet operating mode
3063 4688 : if (thisEvapCond.PumpPowerModifierCurve != nullptr) {
3064 4688 : PumpPowerModCurveValue = thisEvapCond.PumpPowerModifierCurve->value(state, FlowRatio);
3065 : } else {
3066 : // linearly scale pump power using part-load-fraction when pump power modifier curve is not specified
3067 0 : PumpPowerModCurveValue = thisEvapCond.PartLoadFract * FlowRatio;
3068 : }
3069 4688 : EvapCoolertotalPower += thisEvapCond.IndirectRecircPumpPower * PumpPowerModCurveValue;
3070 : }
3071 : } else {
3072 0 : EvapCoolertotalPower = 0.0;
3073 : }
3074 17922 : return EvapCoolertotalPower;
3075 : }
3076 :
3077 2722856 : void CalcDirectResearchSpecialEvapCooler(EnergyPlusData &state, int const EvapCoolNum, Real64 const FanPLR)
3078 : {
3079 :
3080 : // SUBROUTINE INFORMATION:
3081 : // AUTHOR B. Griffith
3082 : // DATE WRITTEN March 2009
3083 :
3084 : // PURPOSE OF THIS SUBROUTINE:
3085 : // calculate model for direct evaporative cooler that is simple and controllable
3086 :
3087 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3088 : Real64 SatEff; // Saturation Efficiency of the CelDek Pad
3089 : Real64 TEDB; // Entering Dry Bulb Temperature
3090 : Real64 TEWB; // Entering Wet Bulb Temperature
3091 : Real64 RhoWater;
3092 : Real64 PartLoad;
3093 : Real64 EffModCurveValue; // effectiveness modifier curve value
3094 : Real64 PumpPowerModCurveValue; // recirculation pump power modifier curve value
3095 2722856 : Real64 FlowRatio(0); // primary air flow frcation (current flow divided by the design flow rate)
3096 : Real64 MassFlowRateSysDesign; // primary air design mass flow rate
3097 : Real64 MassFlowRateSys; // primary air current mass flow rate
3098 2722856 : Real64 BlowDownVdot(0.0);
3099 2722856 : Real64 DriftVdot(0.0);
3100 2722856 : Real64 EvapVdot(0.0);
3101 2722856 : bool EvapCoolerOperatingLimitFlag(false);
3102 :
3103 2722856 : auto &thisEvapCond(state.dataEvapCoolers->EvapCond(EvapCoolNum));
3104 :
3105 2722856 : EvapCoolerOperatingLimitFlag = false;
3106 2722856 : TEDB = thisEvapCond.InletTemp;
3107 2722856 : TEWB = thisEvapCond.InletWetBulbTemp;
3108 2722856 : if (thisEvapCond.EvapCoolerOperationControlFlag) {
3109 34382 : if (TEDB >= thisEvapCond.MinOATDBEvapCooler && (TEWB <= thisEvapCond.MaxOATWBEvapCooler || TEDB <= thisEvapCond.MaxOATDBEvapCooler)) {
3110 24432 : EvapCoolerOperatingLimitFlag = true;
3111 : }
3112 : } else {
3113 2688474 : EvapCoolerOperatingLimitFlag = true;
3114 : }
3115 :
3116 : // If the Evaporative Cooler is operating there should be some mass flow rate
3117 : // Also the evap cooler has to be scheduled to be available
3118 2722856 : if ((thisEvapCond.InletMassFlowRate > 0.0) && (thisEvapCond.availSched->getCurrentVal() > 0.0) && EvapCoolerOperatingLimitFlag) {
3119 :
3120 : //***************************************************************************
3121 : // TEMP LEAVING DRY BULB IS CALCULATED FROM SATURATION EFFICIENCY AS THE
3122 : // DRY BULB TEMP APPROACHES THE WET BULB TEMP. WET BULB TEMP IS CONSTANT
3123 : // ACROSS A DIRECT EVAPORATION COOLER.
3124 2669246 : TEWB = thisEvapCond.InletWetBulbTemp;
3125 2669246 : TEDB = thisEvapCond.InletTemp;
3126 :
3127 2669246 : MassFlowRateSys = thisEvapCond.InletMassFlowRate;
3128 2669246 : MassFlowRateSysDesign = state.dataLoopNodes->Node(thisEvapCond.InletNode).MassFlowRateMax;
3129 2669246 : if (MassFlowRateSysDesign > 0.0) {
3130 691680 : if (MassFlowRateSys > 0.0) {
3131 691680 : FlowRatio = MassFlowRateSys / MassFlowRateSysDesign;
3132 : } else {
3133 0 : FlowRatio = 1.0;
3134 : }
3135 : }
3136 2669246 : if (thisEvapCond.WetbulbEffecCurve != nullptr) {
3137 0 : EffModCurveValue = thisEvapCond.WetbulbEffecCurve->value(state, FlowRatio);
3138 : } else {
3139 : // if no curve specified assume constant effectiveness
3140 2669246 : EffModCurveValue = 1.0;
3141 : }
3142 2669246 : SatEff = thisEvapCond.DirectEffectiveness * EffModCurveValue;
3143 2669246 : thisEvapCond.StageEff = SatEff;
3144 2669246 : PartLoad = thisEvapCond.PartLoadFract;
3145 2669246 : if (PartLoad == 1.0) {
3146 2605152 : thisEvapCond.OutletTemp = TEDB - ((TEDB - TEWB) * SatEff);
3147 2605152 : thisEvapCond.OuletWetBulbTemp = TEWB;
3148 2605152 : thisEvapCond.OutletHumRat = Psychrometrics::PsyWFnTdbTwbPb(state, thisEvapCond.OutletTemp, TEWB, state.dataEnvrn->OutBaroPress);
3149 2605152 : thisEvapCond.OutletEnthalpy = Psychrometrics::PsyHFnTdbW(thisEvapCond.OutletTemp, thisEvapCond.OutletHumRat);
3150 64094 : } else if ((PartLoad < 1.0) && (PartLoad > 0.0)) {
3151 : // assume perfect control Use PLF for energy consumption
3152 976 : if (thisEvapCond.DesiredOutletTemp < TEDB) {
3153 976 : thisEvapCond.OutletTemp = thisEvapCond.DesiredOutletTemp;
3154 976 : thisEvapCond.OuletWetBulbTemp = TEWB;
3155 976 : thisEvapCond.OutletHumRat = Psychrometrics::PsyWFnTdbTwbPb(state, thisEvapCond.OutletTemp, TEWB, state.dataEnvrn->OutBaroPress);
3156 :
3157 976 : thisEvapCond.OutletEnthalpy = Psychrometrics::PsyHFnTdbW(thisEvapCond.OutletTemp, thisEvapCond.OutletHumRat);
3158 : } else { // do no cooling
3159 0 : thisEvapCond.OutletTemp = TEDB;
3160 0 : thisEvapCond.OuletWetBulbTemp = TEWB;
3161 0 : thisEvapCond.OutletHumRat = Psychrometrics::PsyWFnTdbTwbPb(state, thisEvapCond.OutletTemp, TEWB, state.dataEnvrn->OutBaroPress);
3162 0 : thisEvapCond.OutletEnthalpy = Psychrometrics::PsyHFnTdbW(thisEvapCond.OutletTemp, thisEvapCond.OutletHumRat);
3163 : }
3164 : } else {
3165 : // part load set to zero so no cooling
3166 63118 : thisEvapCond.OutletTemp = TEDB;
3167 63118 : thisEvapCond.OuletWetBulbTemp = TEWB;
3168 63118 : thisEvapCond.OutletHumRat = Psychrometrics::PsyWFnTdbTwbPb(state, thisEvapCond.OutletTemp, TEWB, state.dataEnvrn->OutBaroPress);
3169 63118 : thisEvapCond.OutletEnthalpy = Psychrometrics::PsyHFnTdbW(thisEvapCond.OutletTemp, thisEvapCond.OutletHumRat);
3170 : }
3171 :
3172 : //***************************************************************************
3173 : // ENERGY CONSUMED BY THE RECIRCULATING PUMP
3174 : // Add the pump energy to the total Evap Cooler energy comsumption
3175 2669246 : if (thisEvapCond.PumpPowerModifierCurve != nullptr) {
3176 0 : PumpPowerModCurveValue = thisEvapCond.PumpPowerModifierCurve->value(state, FlowRatio);
3177 : } else {
3178 : // if no pump power modifier curve specified, then assume linear variation with part-load and primary fan PLR
3179 2669246 : PumpPowerModCurveValue = PartLoad * FanPLR;
3180 : }
3181 2669246 : thisEvapCond.EvapCoolerPower = thisEvapCond.RecircPumpPower * PumpPowerModCurveValue;
3182 : //******************
3183 : // WATER CONSUMPTION IN m3 OF WATER FOR DIRECT
3184 : // H2O [m3/s] = Delta W[kgWater/kgDryAir]*Mass Flow Air[kgDryAir]
3185 : // /RhoWater [kgWater/m3]
3186 : //******************
3187 2669246 : RhoWater = Psychrometrics::RhoH2O(thisEvapCond.OutletTemp);
3188 2669246 : EvapVdot = (thisEvapCond.OutletHumRat - thisEvapCond.InletHumRat) * thisEvapCond.InletMassFlowRate / RhoWater;
3189 2669246 : DriftVdot = EvapVdot * thisEvapCond.DriftFraction;
3190 :
3191 2669246 : if (thisEvapCond.BlowDownRatio > 0.0) {
3192 2669246 : BlowDownVdot = EvapVdot / (thisEvapCond.BlowDownRatio - 1.0) - DriftVdot;
3193 2669246 : if (BlowDownVdot < 0.0) {
3194 40936 : BlowDownVdot = 0.0;
3195 : }
3196 : } else {
3197 0 : BlowDownVdot = 0.0;
3198 : }
3199 :
3200 2669246 : thisEvapCond.EvapWaterConsumpRate = EvapVdot + DriftVdot + BlowDownVdot;
3201 :
3202 : // A numerical check to keep from having very tiny negative water consumption values being reported
3203 2669246 : if (thisEvapCond.EvapWaterConsumpRate < 0.0) {
3204 40936 : thisEvapCond.EvapWaterConsumpRate = 0.0;
3205 : }
3206 :
3207 : } else {
3208 : // The evap cooler is not running and does not change conditions from inlet to outlet
3209 53610 : thisEvapCond.OutletTemp = thisEvapCond.InletTemp;
3210 :
3211 53610 : thisEvapCond.OuletWetBulbTemp = thisEvapCond.InletWetBulbTemp;
3212 :
3213 53610 : thisEvapCond.OutletHumRat = thisEvapCond.InletHumRat;
3214 :
3215 53610 : thisEvapCond.OutletEnthalpy = thisEvapCond.InletEnthalpy;
3216 53610 : thisEvapCond.EvapCoolerPower = 0.0;
3217 53610 : thisEvapCond.EvapCoolerEnergy = 0.0;
3218 :
3219 53610 : thisEvapCond.EvapWaterConsumpRate = 0.0;
3220 : }
3221 : // all of the mass flowrates are not changed across the evap cooler
3222 2722856 : thisEvapCond.OutletMassFlowRate = thisEvapCond.InletMassFlowRate;
3223 2722856 : thisEvapCond.OutletMassFlowRateMaxAvail = thisEvapCond.InletMassFlowRateMaxAvail;
3224 2722856 : thisEvapCond.OutletMassFlowRateMinAvail = thisEvapCond.InletMassFlowRateMinAvail;
3225 :
3226 : // the pressure is not changed across the evap cooler
3227 2722856 : thisEvapCond.OutletPressure = thisEvapCond.InletPressure;
3228 2722856 : }
3229 :
3230 5303237 : void UpdateEvapCooler(EnergyPlusData &state, int const EvapCoolNum)
3231 : {
3232 :
3233 : // SUBROUTINE INFORMATION:
3234 : // AUTHOR Richard J. Liesen
3235 : // DATE WRITTEN October 2000
3236 :
3237 5303237 : auto &thisEvapCond = state.dataEvapCoolers->EvapCond(EvapCoolNum);
3238 5303237 : auto &thisOutletNode = state.dataLoopNodes->Node(thisEvapCond.OutletNode);
3239 5303237 : auto const &thisInletNode = state.dataLoopNodes->Node(thisEvapCond.InletNode);
3240 :
3241 : // Set the outlet air nodes of the EvapCooler
3242 5303237 : thisOutletNode.MassFlowRate = thisEvapCond.OutletMassFlowRate;
3243 5303237 : thisOutletNode.MassFlowRateMaxAvail = thisEvapCond.OutletMassFlowRateMaxAvail;
3244 5303237 : thisOutletNode.MassFlowRateMinAvail = thisEvapCond.OutletMassFlowRateMinAvail;
3245 5303237 : thisOutletNode.Temp = thisEvapCond.OutletTemp;
3246 5303237 : thisOutletNode.HumRat = thisEvapCond.OutletHumRat;
3247 5303237 : thisOutletNode.Enthalpy = thisEvapCond.OutletEnthalpy;
3248 5303237 : thisOutletNode.Press = thisEvapCond.OutletPressure;
3249 :
3250 5303237 : if (thisEvapCond.SecondaryOutletNode > 0) {
3251 2190906 : auto &thisOutletNodeSec = state.dataLoopNodes->Node(thisEvapCond.SecondaryOutletNode);
3252 : // set outlet nodes of the secondary air side of the EvapCooler (mass Flow Rate Only)
3253 2190906 : if (thisEvapCond.evapCoolerType == EvapCoolerType::IndirectRDDSpecial && thisEvapCond.EvapCoolerOperationControlFlag) {
3254 34302 : thisOutletNodeSec.Temp = thisEvapCond.SecOutletTemp;
3255 34302 : thisOutletNodeSec.HumRat = thisEvapCond.SecOutletHumRat;
3256 34302 : thisOutletNodeSec.Enthalpy = thisEvapCond.SecOutletEnthalpy;
3257 34302 : thisOutletNodeSec.MassFlowRate = thisEvapCond.SecOutletMassFlowRate;
3258 : }
3259 : }
3260 :
3261 : // Set the outlet nodes for properties that just pass through & not used
3262 5303237 : thisOutletNode.Quality = thisInletNode.Quality;
3263 :
3264 : // Set the demand request for supply water from water storage tank (if needed)
3265 5303237 : if (thisEvapCond.EvapWaterSupplyMode == WaterSupply::FromTank) {
3266 0 : state.dataWaterData->WaterStorage(thisEvapCond.EvapWaterSupTankID).VdotRequestDemand(thisEvapCond.EvapWaterTankDemandARRID) =
3267 0 : thisEvapCond.EvapWaterConsumpRate;
3268 : }
3269 :
3270 : // check if should be starved by restricted flow from tank
3271 5303237 : if (thisEvapCond.EvapWaterSupplyMode == WaterSupply::FromTank) {
3272 : Real64 AvailWaterRate =
3273 0 : state.dataWaterData->WaterStorage(thisEvapCond.EvapWaterSupTankID).VdotAvailDemand(thisEvapCond.EvapWaterTankDemandARRID);
3274 0 : if (AvailWaterRate < thisEvapCond.EvapWaterConsumpRate) {
3275 0 : thisEvapCond.EvapWaterStarvMakupRate = thisEvapCond.EvapWaterConsumpRate - AvailWaterRate;
3276 0 : thisEvapCond.EvapWaterConsumpRate = AvailWaterRate;
3277 : } else {
3278 0 : thisEvapCond.EvapWaterStarvMakupRate = 0.0;
3279 : }
3280 : }
3281 :
3282 5303237 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
3283 0 : thisOutletNode.CO2 = thisInletNode.CO2;
3284 : }
3285 :
3286 5303237 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
3287 0 : thisOutletNode.GenContam = thisInletNode.GenContam;
3288 : }
3289 5303237 : }
3290 :
3291 2962542 : void ReportEvapCooler(EnergyPlusData &state, int const EvapCoolNum)
3292 : {
3293 :
3294 : // SUBROUTINE INFORMATION:
3295 : // AUTHOR Richard J. Liesen
3296 : // DATE WRITTEN Oct 2000
3297 :
3298 2962542 : Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
3299 2962542 : auto &thisEvapCond(state.dataEvapCoolers->EvapCond(EvapCoolNum));
3300 :
3301 : // report the Evap Cooler energy from this component
3302 2962542 : thisEvapCond.EvapCoolerPower = thisEvapCond.EvapCoolerPower;
3303 2962542 : thisEvapCond.EvapCoolerEnergy = thisEvapCond.EvapCoolerPower * TimeStepSysSec;
3304 :
3305 : // Report Water comsumption in cubic meters per timestep
3306 2962542 : thisEvapCond.EvapWaterConsump = thisEvapCond.EvapWaterConsumpRate * TimeStepSysSec;
3307 2962542 : thisEvapCond.EvapWaterStarvMakup = thisEvapCond.EvapWaterStarvMakupRate * TimeStepSysSec;
3308 2962542 : }
3309 :
3310 170440 : void SimZoneEvaporativeCoolerUnit(EnergyPlusData &state,
3311 : std::string_view CompName, // name of the packaged terminal heat pump
3312 : int const ZoneNum, // number of zone being served
3313 : Real64 &SensibleOutputProvided, // sensible capacity delivered to zone
3314 : Real64 &LatentOutputProvided, // Latent add/removal (kg/s), dehumid = negative
3315 : int &CompIndex // index to zone hvac unit
3316 : )
3317 : {
3318 :
3319 : // SUBROUTINE INFORMATION:
3320 : // AUTHOR B. Griffith
3321 : // DATE WRITTEN July 2013
3322 : // MODIFIED na
3323 : // RE-ENGINEERED na
3324 :
3325 : // PURPOSE OF THIS SUBROUTINE:
3326 : // public simulation routine for managing zone hvac evaporative cooler unit
3327 :
3328 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3329 : int CompNum;
3330 :
3331 170440 : auto &ZoneEvapUnit(state.dataEvapCoolers->ZoneEvapUnit);
3332 :
3333 170440 : if (state.dataEvapCoolers->GetInputZoneEvapUnit) {
3334 4 : GetInputZoneEvaporativeCoolerUnit(state);
3335 4 : state.dataEvapCoolers->GetInputZoneEvapUnit = false;
3336 : }
3337 :
3338 : // Find the correct Equipment
3339 170440 : if (CompIndex == 0) {
3340 40 : CompNum = Util::FindItemInList(CompName, ZoneEvapUnit);
3341 40 : if (CompNum == 0) {
3342 0 : ShowFatalError(state, "SimZoneEvaporativeCoolerUnit: Zone evaporative cooler unit not found.");
3343 : }
3344 40 : CompIndex = CompNum;
3345 : } else {
3346 170400 : CompNum = CompIndex;
3347 170400 : if (CompNum < 1 || CompNum > state.dataEvapCoolers->NumZoneEvapUnits) {
3348 0 : ShowFatalError(state,
3349 0 : format("SimZoneEvaporativeCoolerUnit: Invalid CompIndex passed={}, Number of units ={}, Entered Unit name = {}",
3350 : CompNum,
3351 0 : state.dataEvapCoolers->NumZoneEvapUnits,
3352 : CompName));
3353 : }
3354 170400 : if (state.dataEvapCoolers->CheckZoneEvapUnitName(CompNum)) {
3355 40 : if (CompName != ZoneEvapUnit(CompNum).Name) {
3356 0 : ShowFatalError(state,
3357 0 : format("SimZoneEvaporativeCoolerUnit: Invalid CompIndex passed={}, Unit name={}, stored unit name for that index={}",
3358 : CompNum,
3359 : CompName,
3360 0 : ZoneEvapUnit(CompNum).Name));
3361 : }
3362 40 : state.dataEvapCoolers->CheckZoneEvapUnitName(CompNum) = false;
3363 : }
3364 : }
3365 :
3366 170440 : InitZoneEvaporativeCoolerUnit(state, CompNum, ZoneNum);
3367 :
3368 170440 : CalcZoneEvaporativeCoolerUnit(state, CompNum, ZoneNum, SensibleOutputProvided, LatentOutputProvided);
3369 :
3370 170440 : ReportZoneEvaporativeCoolerUnit(state, CompNum);
3371 170440 : }
3372 :
3373 4 : void GetInputZoneEvaporativeCoolerUnit(EnergyPlusData &state)
3374 : {
3375 :
3376 : // SUBROUTINE INFORMATION:
3377 : // AUTHOR B. Griffith
3378 : // DATE WRITTEN July 2013
3379 :
3380 : // PURPOSE OF THIS SUBROUTINE:
3381 : // get input for zone evap cooler unit
3382 :
3383 : // SUBROUTINE PARAMETER DEFINITIONS:
3384 : static constexpr std::string_view routineName = "GetInputZoneEvaporativeCoolerUnit";
3385 : static constexpr std::string_view RoutineName("GetInputZoneEvaporativeCoolerUnit: ");
3386 :
3387 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3388 4 : std::string CurrentModuleObject; // Object type for getting and error messages
3389 4 : Array1D_string Alphas; // Alpha items for object
3390 4 : Array1D<Real64> Numbers; // Numeric items for object
3391 4 : Array1D_string cAlphaFields; // Alpha field names
3392 4 : Array1D_string cNumericFields; // Numeric field names
3393 4 : Array1D_bool lAlphaBlanks; // Logical array, alpha field input BLANK = .TRUE.
3394 4 : Array1D_bool lNumericBlanks; // Logical array, numeric field input BLANK = .TRUE.
3395 : int NumAlphas; // Number of Alphas for each GetObjectItem call
3396 : int NumNumbers; // Number of Numbers for each GetObjectItem call
3397 : int NumFields; // Total number of fields in object
3398 4 : bool ErrorsFound(false); // Set to true if errors in input, fatal at end of routine
3399 :
3400 4 : auto &EvapCond(state.dataEvapCoolers->EvapCond);
3401 4 : auto &ZoneEvapUnit(state.dataEvapCoolers->ZoneEvapUnit);
3402 :
3403 4 : if (state.dataEvapCoolers->GetInputEvapComponentsFlag) {
3404 4 : GetEvapInput(state);
3405 4 : state.dataEvapCoolers->GetInputEvapComponentsFlag = false;
3406 : }
3407 :
3408 4 : state.dataEvapCoolers->GetInputZoneEvapUnit = false;
3409 4 : int MaxNumbers = 0;
3410 4 : int MaxAlphas = 0;
3411 :
3412 4 : CurrentModuleObject = "ZoneHVAC:EvaporativeCoolerUnit";
3413 4 : state.dataEvapCoolers->NumZoneEvapUnits = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
3414 4 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, NumFields, NumAlphas, NumNumbers);
3415 4 : MaxNumbers = max(MaxNumbers, NumNumbers);
3416 4 : MaxAlphas = max(MaxAlphas, NumAlphas);
3417 4 : Alphas.allocate(MaxAlphas);
3418 4 : Numbers.dimension(MaxNumbers, 0.0);
3419 4 : cAlphaFields.allocate(MaxAlphas);
3420 4 : cNumericFields.allocate(MaxNumbers);
3421 4 : lAlphaBlanks.dimension(MaxAlphas, true);
3422 4 : lNumericBlanks.dimension(MaxNumbers, true);
3423 :
3424 4 : if (state.dataEvapCoolers->NumZoneEvapUnits > 0) {
3425 : int IOStatus; // Used in GetObjectItem
3426 4 : state.dataEvapCoolers->CheckZoneEvapUnitName.dimension(state.dataEvapCoolers->NumZoneEvapUnits, true);
3427 4 : ZoneEvapUnit.allocate(state.dataEvapCoolers->NumZoneEvapUnits);
3428 :
3429 44 : for (int UnitLoop = 1; UnitLoop <= state.dataEvapCoolers->NumZoneEvapUnits; ++UnitLoop) {
3430 40 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
3431 : CurrentModuleObject,
3432 : UnitLoop,
3433 : Alphas,
3434 : NumAlphas,
3435 : Numbers,
3436 : NumNumbers,
3437 : IOStatus,
3438 : lNumericBlanks,
3439 : lAlphaBlanks,
3440 : cAlphaFields,
3441 : cNumericFields);
3442 :
3443 40 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
3444 :
3445 40 : auto &thisZoneEvapUnit = ZoneEvapUnit(UnitLoop);
3446 40 : thisZoneEvapUnit.Name = Alphas(1);
3447 40 : if (lAlphaBlanks(2)) {
3448 0 : thisZoneEvapUnit.availSched = Sched::GetScheduleAlwaysOn(state);
3449 40 : } else if ((thisZoneEvapUnit.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
3450 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
3451 0 : ErrorsFound = true;
3452 : }
3453 :
3454 40 : if (!lAlphaBlanks(3)) {
3455 0 : thisZoneEvapUnit.AvailManagerListName = Alphas(3);
3456 : }
3457 :
3458 40 : thisZoneEvapUnit.OAInletNodeNum = GetOnlySingleNode(state,
3459 40 : Alphas(4),
3460 : ErrorsFound,
3461 : DataLoopNode::ConnectionObjectType::ZoneHVACEvaporativeCoolerUnit,
3462 40 : Alphas(1),
3463 : DataLoopNode::NodeFluidType::Air,
3464 : DataLoopNode::ConnectionType::OutsideAir,
3465 : NodeInputManager::CompFluidStream::Primary,
3466 : DataLoopNode::ObjectIsParent);
3467 :
3468 40 : thisZoneEvapUnit.UnitOutletNodeNum = GetOnlySingleNode(state,
3469 40 : Alphas(5),
3470 : ErrorsFound,
3471 : DataLoopNode::ConnectionObjectType::ZoneHVACEvaporativeCoolerUnit,
3472 40 : Alphas(1),
3473 : DataLoopNode::NodeFluidType::Air,
3474 : DataLoopNode::ConnectionType::Outlet,
3475 : NodeInputManager::CompFluidStream::Primary,
3476 : DataLoopNode::ObjectIsParent);
3477 :
3478 40 : if (!lAlphaBlanks(6)) {
3479 80 : thisZoneEvapUnit.UnitReliefNodeNum = GetOnlySingleNode(state,
3480 40 : Alphas(6),
3481 : ErrorsFound,
3482 : DataLoopNode::ConnectionObjectType::ZoneHVACEvaporativeCoolerUnit,
3483 40 : Alphas(1),
3484 : DataLoopNode::NodeFluidType::Air,
3485 : DataLoopNode::ConnectionType::Inlet,
3486 : NodeInputManager::CompFluidStream::Primary,
3487 : DataLoopNode::ObjectIsParent);
3488 : }
3489 :
3490 40 : thisZoneEvapUnit.FanName = Alphas(8);
3491 :
3492 40 : thisZoneEvapUnit.fanType = static_cast<HVAC::FanType>(getEnumValue(HVAC::fanTypeNamesUC, Alphas(7)));
3493 40 : assert(thisZoneEvapUnit.fanType != HVAC::FanType::Invalid);
3494 :
3495 40 : thisZoneEvapUnit.FanIndex = Fans::GetFanIndex(state, thisZoneEvapUnit.FanName);
3496 40 : if (thisZoneEvapUnit.FanIndex == 0) {
3497 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(8), thisZoneEvapUnit.FanName);
3498 0 : ErrorsFound = true;
3499 : } else {
3500 40 : auto *fan = state.dataFans->fans(thisZoneEvapUnit.FanIndex);
3501 40 : assert(thisZoneEvapUnit.fanType == fan->type);
3502 40 : thisZoneEvapUnit.FanInletNodeNum = fan->inletNodeNum;
3503 40 : thisZoneEvapUnit.FanOutletNodeNum = fan->outletNodeNum;
3504 40 : thisZoneEvapUnit.ActualFanVolFlowRate = fan->maxAirFlowRate;
3505 40 : thisZoneEvapUnit.fanAvailSched = fan->availSched;
3506 : }
3507 :
3508 : // set evap unit to cycling mode for all fan types. Note OpMode var is not used
3509 : // with used for ZONECOOLINGLOADVARIABLESPEEDFAN Cooler Unit Control Method
3510 40 : thisZoneEvapUnit.fanOp = HVAC::FanOp::Cycling;
3511 :
3512 40 : thisZoneEvapUnit.DesignAirVolumeFlowRate = Numbers(1);
3513 :
3514 40 : thisZoneEvapUnit.fanPlace = static_cast<HVAC::FanPlace>(getEnumValue(HVAC::fanPlaceNamesUC, Alphas(9)));
3515 40 : assert(thisZoneEvapUnit.fanPlace != HVAC::FanPlace::Invalid);
3516 :
3517 : // get the zone numer served by the zoneHVAC evaporative cooler
3518 440 : for (int CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) {
3519 400 : if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) {
3520 0 : continue;
3521 : }
3522 760 : for (int NodeNum = 1; NodeNum <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumInletNodes; ++NodeNum) {
3523 400 : if (thisZoneEvapUnit.UnitOutletNodeNum == state.dataZoneEquip->ZoneEquipConfig(CtrlZone).InletNode(NodeNum)) {
3524 40 : thisZoneEvapUnit.ZonePtr = CtrlZone;
3525 40 : break;
3526 : }
3527 : }
3528 : }
3529 :
3530 40 : constexpr std::array<std::string_view, static_cast<int>(ControlType::Num)> controlTypeNamesUC = {
3531 : "ZONETEMPERATUREDEADBANDONOFFCYCLING", "ZONECOOLINGLOADONOFFCYCLING", "ZONECOOLINGLOADVARIABLESPEEDFAN"};
3532 40 : thisZoneEvapUnit.ControlSchemeType = static_cast<ControlType>(getEnumValue(controlTypeNamesUC, Alphas(10)));
3533 40 : if (thisZoneEvapUnit.ControlSchemeType == ControlType::Invalid) {
3534 0 : ShowSevereError(state, format("{}=\"{}\" invalid data.", CurrentModuleObject, thisZoneEvapUnit.Name));
3535 0 : ShowContinueError(state, format("invalid choice found {}=\"{}\".", cAlphaFields(10), Alphas(10)));
3536 0 : ErrorsFound = true;
3537 : }
3538 :
3539 40 : thisZoneEvapUnit.ThrottlingRange = Numbers(2);
3540 40 : thisZoneEvapUnit.ThresholdCoolingLoad = Numbers(3);
3541 :
3542 40 : thisZoneEvapUnit.EvapCooler_1_Type_Num = static_cast<EvapCoolerType>(getEnumValue(evapCoolerTypeNamesUC, Alphas(11)));
3543 40 : if (thisZoneEvapUnit.EvapCooler_1_Type_Num != EvapCoolerType::Invalid) {
3544 40 : thisZoneEvapUnit.EvapCooler_1_ObjectClassName = evapCoolerTypeNames[static_cast<int>(thisZoneEvapUnit.EvapCooler_1_Type_Num)];
3545 : } else {
3546 0 : ShowSevereError(state, format("{}=\"{}\" invalid data.", CurrentModuleObject, thisZoneEvapUnit.Name));
3547 0 : ShowContinueError(state, format("invalid choice found {}=\"{}\".", cAlphaFields(11), Alphas(11)));
3548 0 : ErrorsFound = true;
3549 : }
3550 :
3551 40 : thisZoneEvapUnit.EvapCooler_1_Name = Alphas(12);
3552 40 : thisZoneEvapUnit.EvapCooler_1_Index = Util::FindItemInList(Alphas(12), state.dataEvapCoolers->EvapCond, &EvapConditions::Name);
3553 40 : if (thisZoneEvapUnit.EvapCooler_1_Index == 0) {
3554 0 : ShowSevereError(state, format("{}=\"{}\" invalid data.", CurrentModuleObject, thisZoneEvapUnit.Name));
3555 0 : ShowContinueError(state, format("invalid, not found {}=\"{}\".", cAlphaFields(12), Alphas(12)));
3556 0 : ErrorsFound = true;
3557 : }
3558 :
3559 40 : if (!lAlphaBlanks(13)) {
3560 12 : thisZoneEvapUnit.EvapCooler_2_Type_Num = static_cast<EvapCoolerType>(getEnumValue(evapCoolerTypeNamesUC, Alphas(13)));
3561 12 : if (thisZoneEvapUnit.EvapCooler_2_Type_Num != EvapCoolerType::Invalid) {
3562 12 : thisZoneEvapUnit.EvapCooler_2_ObjectClassName = evapCoolerTypeNames[static_cast<int>(thisZoneEvapUnit.EvapCooler_2_Type_Num)];
3563 : } else {
3564 0 : ShowSevereError(state, format("{}=\"{}\" invalid data.", CurrentModuleObject, thisZoneEvapUnit.Name));
3565 0 : ShowContinueError(state, format("invalid choice found {}=\"{}\".", cAlphaFields(13), Alphas(13)));
3566 0 : ErrorsFound = true;
3567 : }
3568 :
3569 12 : if (!lAlphaBlanks(14)) {
3570 12 : thisZoneEvapUnit.EvapCooler_2_Name = Alphas(14);
3571 12 : thisZoneEvapUnit.EvapCooler_2_Index = Util::FindItemInList(Alphas(14), state.dataEvapCoolers->EvapCond, &EvapConditions::Name);
3572 12 : if (thisZoneEvapUnit.EvapCooler_2_Index == 0) {
3573 0 : ShowSevereError(state, format("{}=\"{}\" invalid data.", CurrentModuleObject, thisZoneEvapUnit.Name));
3574 0 : ShowContinueError(state, format("invalid, not found {}=\"{}\".", cAlphaFields(14), Alphas(14)));
3575 0 : ErrorsFound = true;
3576 : }
3577 : } else {
3578 0 : ShowSevereError(state, format("{}=\"{}\" invalid data.", CurrentModuleObject, thisZoneEvapUnit.Name));
3579 0 : ShowContinueError(state, format("missing input for {}", cAlphaFields(14)));
3580 0 : ErrorsFound = true;
3581 : }
3582 : }
3583 :
3584 40 : thisZoneEvapUnit.HVACSizingIndex = 0;
3585 40 : if (!lAlphaBlanks(15)) {
3586 0 : thisZoneEvapUnit.HVACSizingIndex = Util::FindItemInList(Alphas(15), state.dataSize->ZoneHVACSizing);
3587 0 : if (thisZoneEvapUnit.HVACSizingIndex == 0) {
3588 0 : ShowSevereError(state, format("{} = {} not found.", cAlphaFields(15), Alphas(15)));
3589 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisZoneEvapUnit.Name));
3590 0 : ErrorsFound = true;
3591 : }
3592 : }
3593 :
3594 40 : if (!lNumericBlanks(4)) {
3595 : // Shut Off Relative Humidity
3596 1 : thisZoneEvapUnit.ShutOffRelativeHumidity = Numbers(4);
3597 : }
3598 :
3599 : // Add fan to component sets array
3600 120 : BranchNodeConnections::SetUpCompSets(state,
3601 : CurrentModuleObject,
3602 : thisZoneEvapUnit.Name,
3603 40 : HVAC::fanTypeNamesUC[(int)thisZoneEvapUnit.fanType],
3604 : thisZoneEvapUnit.FanName,
3605 40 : state.dataLoopNodes->NodeID(thisZoneEvapUnit.FanInletNodeNum),
3606 40 : state.dataLoopNodes->NodeID(thisZoneEvapUnit.FanOutletNodeNum));
3607 :
3608 : // Add first evap cooler to component sets array
3609 80 : BranchNodeConnections::SetUpCompSets(state,
3610 : CurrentModuleObject,
3611 : thisZoneEvapUnit.Name,
3612 : thisZoneEvapUnit.EvapCooler_1_ObjectClassName,
3613 : thisZoneEvapUnit.EvapCooler_1_Name,
3614 40 : state.dataLoopNodes->NodeID(EvapCond(thisZoneEvapUnit.EvapCooler_1_Index).InletNode),
3615 40 : state.dataLoopNodes->NodeID(EvapCond(thisZoneEvapUnit.EvapCooler_1_Index).OutletNode));
3616 :
3617 40 : if (thisZoneEvapUnit.EvapCooler_2_Index > 0) {
3618 : // Add second evap cooler to component sets array
3619 24 : BranchNodeConnections::SetUpCompSets(state,
3620 : CurrentModuleObject,
3621 : thisZoneEvapUnit.Name,
3622 : thisZoneEvapUnit.EvapCooler_2_ObjectClassName,
3623 : thisZoneEvapUnit.EvapCooler_2_Name,
3624 12 : state.dataLoopNodes->NodeID(EvapCond(thisZoneEvapUnit.EvapCooler_2_Index).InletNode),
3625 12 : state.dataLoopNodes->NodeID(EvapCond(thisZoneEvapUnit.EvapCooler_2_Index).OutletNode));
3626 : }
3627 :
3628 : // check that fan type is consistent with control method
3629 40 : if (thisZoneEvapUnit.ControlSchemeType == ControlType::ZoneCoolingLoadVariableSpeedFan) { // must have a VS fan type
3630 20 : if (thisZoneEvapUnit.fanType == HVAC::FanType::Constant) {
3631 0 : ShowSevereError(state, format("{}=\"{}\" invalid data.", CurrentModuleObject, thisZoneEvapUnit.Name));
3632 0 : ShowContinueError(state, "Fan:ConstantVolume is not consistent with control method ZoneCoolingLoadVariableSpeedFan.");
3633 0 : ShowContinueError(state, "Change to a variable speed fan object type");
3634 0 : ErrorsFound = true;
3635 20 : } else if (thisZoneEvapUnit.fanType == HVAC::FanType::OnOff) {
3636 0 : ShowSevereError(state, format("{}=\"{}\" invalid data.", CurrentModuleObject, thisZoneEvapUnit.Name));
3637 0 : ShowContinueError(state, "Fan:OnOff is not consistent with control method ZoneCoolingLoadVariableSpeedFan.");
3638 0 : ShowContinueError(state, "Change to a variable speed fan object type");
3639 0 : ErrorsFound = true;
3640 : }
3641 : }
3642 :
3643 : } // unit loop
3644 : }
3645 :
3646 : //***********************************************************************************
3647 :
3648 4 : Alphas.deallocate();
3649 4 : Numbers.deallocate();
3650 4 : cAlphaFields.deallocate();
3651 4 : cNumericFields.deallocate();
3652 4 : lAlphaBlanks.deallocate();
3653 4 : lNumericBlanks.deallocate();
3654 :
3655 4 : if (ErrorsFound) {
3656 0 : ShowFatalError(state, format("{}Errors found in getting input.", RoutineName));
3657 0 : ShowContinueError(state, "... Preceding condition causes termination.");
3658 : }
3659 :
3660 : // setup output variables
3661 44 : for (int UnitLoop = 1; UnitLoop <= state.dataEvapCoolers->NumZoneEvapUnits; ++UnitLoop) {
3662 40 : auto &thisZoneEvapUnit = ZoneEvapUnit(UnitLoop);
3663 80 : SetupOutputVariable(state,
3664 : "Zone Evaporative Cooler Unit Total Cooling Rate",
3665 : Constant::Units::W,
3666 40 : thisZoneEvapUnit.UnitTotalCoolingRate,
3667 : OutputProcessor::TimeStepType::System,
3668 : OutputProcessor::StoreType::Average,
3669 40 : thisZoneEvapUnit.Name);
3670 80 : SetupOutputVariable(state,
3671 : "Zone Evaporative Cooler Unit Total Cooling Energy",
3672 : Constant::Units::J,
3673 40 : thisZoneEvapUnit.UnitTotalCoolingEnergy,
3674 : OutputProcessor::TimeStepType::System,
3675 : OutputProcessor::StoreType::Sum,
3676 40 : thisZoneEvapUnit.Name,
3677 : Constant::eResource::EnergyTransfer,
3678 : OutputProcessor::Group::HVAC,
3679 : OutputProcessor::EndUseCat::CoolingCoils);
3680 80 : SetupOutputVariable(state,
3681 : "Zone Evaporative Cooler Unit Sensible Cooling Rate",
3682 : Constant::Units::W,
3683 40 : thisZoneEvapUnit.UnitSensibleCoolingRate,
3684 : OutputProcessor::TimeStepType::System,
3685 : OutputProcessor::StoreType::Average,
3686 40 : thisZoneEvapUnit.Name);
3687 80 : SetupOutputVariable(state,
3688 : "Zone Evaporative Cooler Unit Sensible Cooling Energy",
3689 : Constant::Units::J,
3690 40 : thisZoneEvapUnit.UnitSensibleCoolingEnergy,
3691 : OutputProcessor::TimeStepType::System,
3692 : OutputProcessor::StoreType::Sum,
3693 40 : thisZoneEvapUnit.Name);
3694 80 : SetupOutputVariable(state,
3695 : "Zone Evaporative Cooler Unit Latent Heating Rate",
3696 : Constant::Units::W,
3697 40 : thisZoneEvapUnit.UnitLatentHeatingRate,
3698 : OutputProcessor::TimeStepType::System,
3699 : OutputProcessor::StoreType::Average,
3700 40 : thisZoneEvapUnit.Name);
3701 80 : SetupOutputVariable(state,
3702 : "Zone Evaporative Cooler Unit Latent Heating Energy",
3703 : Constant::Units::J,
3704 40 : thisZoneEvapUnit.UnitLatentHeatingEnergy,
3705 : OutputProcessor::TimeStepType::System,
3706 : OutputProcessor::StoreType::Sum,
3707 40 : thisZoneEvapUnit.Name);
3708 80 : SetupOutputVariable(state,
3709 : "Zone Evaporative Cooler Unit Latent Cooling Rate",
3710 : Constant::Units::W,
3711 40 : thisZoneEvapUnit.UnitLatentCoolingRate,
3712 : OutputProcessor::TimeStepType::System,
3713 : OutputProcessor::StoreType::Average,
3714 40 : thisZoneEvapUnit.Name);
3715 80 : SetupOutputVariable(state,
3716 : "Zone Evaporative Cooler Unit Latent Cooling Energy",
3717 : Constant::Units::J,
3718 40 : thisZoneEvapUnit.UnitLatentCoolingEnergy,
3719 : OutputProcessor::TimeStepType::System,
3720 : OutputProcessor::StoreType::Sum,
3721 40 : thisZoneEvapUnit.Name);
3722 80 : SetupOutputVariable(state,
3723 : "Zone Evaporative Cooler Unit Fan Speed Ratio",
3724 : Constant::Units::None,
3725 40 : thisZoneEvapUnit.UnitFanSpeedRatio,
3726 : OutputProcessor::TimeStepType::System,
3727 : OutputProcessor::StoreType::Average,
3728 40 : thisZoneEvapUnit.Name);
3729 40 : SetupOutputVariable(state,
3730 : "Zone Evaporative Cooler Unit Fan Availability Status",
3731 : Constant::Units::None,
3732 40 : (int &)thisZoneEvapUnit.FanAvailStatus,
3733 : OutputProcessor::TimeStepType::System,
3734 : OutputProcessor::StoreType::Average,
3735 40 : thisZoneEvapUnit.Name);
3736 40 : if (thisZoneEvapUnit.ControlSchemeType != ControlType::ZoneCoolingLoadVariableSpeedFan) {
3737 40 : SetupOutputVariable(state,
3738 : "Zone Evaporative Cooler Unit Part Load Ratio",
3739 : Constant::Units::None,
3740 20 : thisZoneEvapUnit.UnitPartLoadRatio,
3741 : OutputProcessor::TimeStepType::System,
3742 : OutputProcessor::StoreType::Average,
3743 20 : thisZoneEvapUnit.Name);
3744 : }
3745 : }
3746 4 : }
3747 :
3748 170440 : void InitZoneEvaporativeCoolerUnit(EnergyPlusData &state,
3749 : int const UnitNum, // unit number
3750 : int const ZoneNum // number of zone being served
3751 : )
3752 : {
3753 :
3754 : // SUBROUTINE INFORMATION:
3755 : // AUTHOR B. Griffith
3756 : // DATE WRITTEN July 2013
3757 :
3758 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3759 170440 : auto &zoneEvapUnit = state.dataEvapCoolers->ZoneEvapUnit(UnitNum);
3760 :
3761 170440 : if (allocated(state.dataAvail->ZoneComp)) {
3762 170400 : if (zoneEvapUnit.MyZoneEq) { // initialize the name of each availability manager list and zone number
3763 40 : state.dataAvail->ZoneComp(DataZoneEquipment::ZoneEquipType::EvaporativeCooler).ZoneCompAvailMgrs(UnitNum).AvailManagerListName =
3764 80 : zoneEvapUnit.AvailManagerListName;
3765 40 : state.dataAvail->ZoneComp(DataZoneEquipment::ZoneEquipType::EvaporativeCooler).ZoneCompAvailMgrs(UnitNum).ZoneNum = ZoneNum;
3766 40 : zoneEvapUnit.MyZoneEq = false;
3767 : }
3768 170400 : zoneEvapUnit.FanAvailStatus =
3769 170400 : state.dataAvail->ZoneComp(DataZoneEquipment::ZoneEquipType::EvaporativeCooler).ZoneCompAvailMgrs(UnitNum).availStatus;
3770 : }
3771 :
3772 170440 : if (!state.dataEvapCoolers->ZoneEquipmentListChecked && state.dataZoneEquip->ZoneEquipInputsFilled) {
3773 4 : state.dataEvapCoolers->ZoneEquipmentListChecked = true;
3774 44 : for (int Loop = 1; Loop <= state.dataEvapCoolers->NumZoneEvapUnits; ++Loop) {
3775 40 : if (DataZoneEquipment::CheckZoneEquipmentList(state, "ZoneHVAC:EvaporativeCoolerUnit", state.dataEvapCoolers->ZoneEvapUnit(Loop).Name)) {
3776 40 : state.dataEvapCoolers->ZoneEvapUnit(Loop).ZoneNodeNum = state.dataZoneEquip->ZoneEquipConfig(ZoneNum).ZoneNode;
3777 : } else {
3778 0 : ShowSevereError(state,
3779 0 : format("InitZoneEvaporativeCoolerUnit: ZoneHVAC:EvaporativeCoolerUnit = {}, is not on any ZoneHVAC:EquipmentList. "
3780 : "It will not be simulated.",
3781 0 : state.dataEvapCoolers->ZoneEvapUnit(Loop).Name));
3782 : }
3783 : }
3784 : }
3785 :
3786 170440 : if (!state.dataGlobal->SysSizingCalc && zoneEvapUnit.MySize) {
3787 40 : SizeZoneEvaporativeCoolerUnit(state, UnitNum);
3788 40 : zoneEvapUnit.MySize = false;
3789 : }
3790 :
3791 170440 : if (zoneEvapUnit.MyFan) {
3792 112 : if (zoneEvapUnit.ActualFanVolFlowRate != DataSizing::AutoSize) {
3793 :
3794 40 : if (zoneEvapUnit.ActualFanVolFlowRate < zoneEvapUnit.DesignAirVolumeFlowRate) {
3795 4 : ShowSevereError(state, format("InitZoneEvaporativeCoolerUnit: ZoneHVAC:EvaporativeCoolerUnit = {}", zoneEvapUnit.Name));
3796 8 : ShowContinueError(state, "...unit fan volumetric flow rate less than evaporative cooler unit design supply air flow rate.");
3797 4 : ShowContinueError(state, format("...fan volumetric flow rate = {:.5T} m3/s.", zoneEvapUnit.ActualFanVolFlowRate));
3798 4 : ShowContinueError(state, format("...evap cooler unit volumetric flow rate = {:.5T} m3/s.", zoneEvapUnit.DesignAirVolumeFlowRate));
3799 4 : zoneEvapUnit.DesignAirVolumeFlowRate = zoneEvapUnit.ActualFanVolFlowRate;
3800 8 : ShowContinueError(state, "...evaporative cooler unit design supply air flow rate will match fan flow rate and simulation continues.");
3801 4 : zoneEvapUnit.MyEnvrn = true; // re-initialize to set mass flow rate and max mass flow rate
3802 : }
3803 :
3804 40 : if (zoneEvapUnit.ActualFanVolFlowRate > 0.0) {
3805 40 : zoneEvapUnit.DesignFanSpeedRatio = zoneEvapUnit.DesignAirVolumeFlowRate / zoneEvapUnit.ActualFanVolFlowRate;
3806 : }
3807 :
3808 40 : zoneEvapUnit.MyFan = false;
3809 : } else {
3810 72 : zoneEvapUnit.ActualFanVolFlowRate = state.dataFans->fans(zoneEvapUnit.FanIndex)->maxAirFlowRate;
3811 : }
3812 : }
3813 :
3814 170440 : if (zoneEvapUnit.fanAvailSched != nullptr) {
3815 : // include fan is not available, then unit is not available
3816 170440 : zoneEvapUnit.UnitIsAvailable = ((zoneEvapUnit.fanAvailSched->getCurrentVal() > 0.0) && (zoneEvapUnit.availSched->getCurrentVal() > 0.0));
3817 : } else {
3818 0 : zoneEvapUnit.UnitIsAvailable = (zoneEvapUnit.availSched->getCurrentVal() > 0.0);
3819 : }
3820 :
3821 170440 : zoneEvapUnit.EvapCooler_1_AvailStatus = (state.dataEvapCoolers->EvapCond(zoneEvapUnit.EvapCooler_1_Index).availSched->getCurrentVal() > 0.0);
3822 :
3823 170440 : if (zoneEvapUnit.EvapCooler_2_Index > 0) {
3824 51132 : zoneEvapUnit.EvapCooler_2_AvailStatus = (state.dataEvapCoolers->EvapCond(zoneEvapUnit.EvapCooler_2_Index).availSched->getCurrentVal() > 0.0);
3825 : }
3826 : // Do the Begin Environment initializations
3827 170440 : if (state.dataGlobal->BeginEnvrnFlag && zoneEvapUnit.MyEnvrn) {
3828 200 : zoneEvapUnit.DesignAirMassFlowRate = state.dataEnvrn->StdRhoAir * zoneEvapUnit.DesignAirVolumeFlowRate;
3829 200 : state.dataLoopNodes->Node(zoneEvapUnit.OAInletNodeNum).MassFlowRateMax = zoneEvapUnit.DesignAirMassFlowRate;
3830 200 : state.dataLoopNodes->Node(zoneEvapUnit.OAInletNodeNum).MassFlowRateMin = 0.0;
3831 200 : state.dataLoopNodes->Node(zoneEvapUnit.OAInletNodeNum).MassFlowRateMinAvail = 0.0;
3832 :
3833 200 : state.dataLoopNodes->Node(zoneEvapUnit.UnitOutletNodeNum).MassFlowRateMax = zoneEvapUnit.DesignAirMassFlowRate;
3834 200 : state.dataLoopNodes->Node(zoneEvapUnit.UnitOutletNodeNum).MassFlowRateMin = 0.0;
3835 200 : state.dataLoopNodes->Node(zoneEvapUnit.UnitOutletNodeNum).MassFlowRateMinAvail = 0.0;
3836 :
3837 200 : if (zoneEvapUnit.UnitReliefNodeNum > 0) {
3838 200 : state.dataLoopNodes->Node(zoneEvapUnit.UnitReliefNodeNum).MassFlowRateMax = zoneEvapUnit.DesignAirMassFlowRate;
3839 200 : state.dataLoopNodes->Node(zoneEvapUnit.UnitReliefNodeNum).MassFlowRateMin = 0.0;
3840 200 : state.dataLoopNodes->Node(zoneEvapUnit.UnitReliefNodeNum).MassFlowRateMinAvail = 0.0;
3841 : }
3842 200 : zoneEvapUnit.WasOnLastTimestep = false;
3843 200 : zoneEvapUnit.IsOnThisTimestep = false;
3844 200 : zoneEvapUnit.FanSpeedRatio = 0.0;
3845 200 : zoneEvapUnit.UnitFanSpeedRatio = 0.0;
3846 200 : zoneEvapUnit.UnitTotalCoolingRate = 0.0;
3847 200 : zoneEvapUnit.UnitTotalCoolingEnergy = 0.0;
3848 200 : zoneEvapUnit.UnitSensibleCoolingRate = 0.0;
3849 200 : zoneEvapUnit.UnitSensibleCoolingEnergy = 0.0;
3850 200 : zoneEvapUnit.UnitLatentHeatingRate = 0.0;
3851 200 : zoneEvapUnit.UnitLatentHeatingEnergy = 0.0;
3852 200 : zoneEvapUnit.UnitLatentCoolingRate = 0.0;
3853 200 : zoneEvapUnit.UnitLatentCoolingEnergy = 0.0;
3854 200 : zoneEvapUnit.FanAvailStatus = Avail::Status::NoAction;
3855 :
3856 : // place default cold setpoints on control nodes of select evap coolers
3857 200 : if ((zoneEvapUnit.EvapCooler_1_Type_Num == EvapCoolerType::DirectResearchSpecial) ||
3858 180 : (zoneEvapUnit.EvapCooler_1_Type_Num == EvapCoolerType::IndirectRDDSpecial)) {
3859 60 : if (state.dataEvapCoolers->EvapCond(zoneEvapUnit.EvapCooler_1_Index).EvapControlNodeNum > 0) {
3860 60 : state.dataLoopNodes->Node(state.dataEvapCoolers->EvapCond(zoneEvapUnit.EvapCooler_1_Index).EvapControlNodeNum).TempSetPoint = -20.0;
3861 : }
3862 : }
3863 200 : if ((zoneEvapUnit.EvapCooler_2_Type_Num == EvapCoolerType::DirectResearchSpecial) ||
3864 160 : (zoneEvapUnit.EvapCooler_2_Type_Num == EvapCoolerType::IndirectRDDSpecial)) {
3865 40 : if (state.dataEvapCoolers->EvapCond(zoneEvapUnit.EvapCooler_2_Index).EvapControlNodeNum > 0) {
3866 40 : state.dataLoopNodes->Node(state.dataEvapCoolers->EvapCond(zoneEvapUnit.EvapCooler_2_Index).EvapControlNodeNum).TempSetPoint = -20.0;
3867 : }
3868 : }
3869 :
3870 200 : zoneEvapUnit.MyEnvrn = false;
3871 : }
3872 170440 : if (!state.dataGlobal->BeginEnvrnFlag) {
3873 169140 : zoneEvapUnit.MyEnvrn = true;
3874 : }
3875 :
3876 : Real64 TimeElapsed =
3877 170440 : state.dataGlobal->HourOfDay + state.dataGlobal->TimeStep * state.dataGlobal->TimeStepZone + state.dataHVACGlobal->SysTimeElapsed;
3878 170440 : if (zoneEvapUnit.TimeElapsed != TimeElapsed) {
3879 83960 : zoneEvapUnit.WasOnLastTimestep = zoneEvapUnit.IsOnThisTimestep;
3880 83960 : zoneEvapUnit.TimeElapsed = TimeElapsed;
3881 : }
3882 170440 : }
3883 :
3884 40 : void SizeZoneEvaporativeCoolerUnit(EnergyPlusData &state, int const UnitNum) // unit number
3885 : {
3886 :
3887 : // SUBROUTINE INFORMATION:
3888 : // AUTHOR B. Griffith
3889 : // DATE WRITTEN July 2013
3890 : // MODIFIED August 2014 Bereket Nigusse, added scalable sizing
3891 : // MODIFIED January 2013 Daeho Kang, add component sizing table entries
3892 :
3893 : // SUBROUTINE PARAMETER DEFINITIONS:
3894 : static constexpr std::string_view RoutineName("SizeZoneEvaporativeCoolerUnit: "); // include trailing blank space
3895 :
3896 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3897 : Real64 TempSize; // autosized value of coil input field
3898 :
3899 40 : auto &zoneEvapUnit = state.dataEvapCoolers->ZoneEvapUnit(UnitNum);
3900 :
3901 40 : state.dataSize->DataScalableSizingON = false;
3902 40 : state.dataSize->ZoneHeatingOnlyFan = false;
3903 40 : state.dataSize->ZoneCoolingOnlyFan = false;
3904 :
3905 40 : state.dataSize->DataZoneNumber = zoneEvapUnit.ZonePtr;
3906 :
3907 40 : if (state.dataSize->CurZoneEqNum > 0) {
3908 40 : std::string CompName = zoneEvapUnit.Name;
3909 40 : std::string CompType = "ZoneHVAC:EvaporativeCoolerUnit";
3910 40 : bool errorsFound = false;
3911 40 : auto &zoneEqSizing = state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum);
3912 40 : bool PrintFlag = true; // TRUE when sizing information is reported in the eio file
3913 :
3914 40 : if (zoneEvapUnit.HVACSizingIndex > 0) {
3915 0 : state.dataSize->ZoneCoolingOnlyFan = true;
3916 : // index of zoneHVAC equipment sizing specification
3917 0 : int zoneHVACIndex = zoneEvapUnit.HVACSizingIndex;
3918 : // Integer representation of sizing method name (e.g., CoolingAirflowSizing, HeatingAirflowSizing,
3919 : // CoolingCapacitySizing, HeatingCapacitySizing, etc.)
3920 0 : int SizingMethod = HVAC::CoolingAirflowSizing;
3921 : // supply air flow rate sizing method (SupplyAirFlowRate, FlowPerFloorArea, FractionOfAutosizedCoolingAirflow,
3922 : // FractionOfAutosizedHeatingAirflow ...)
3923 0 : int SAFMethod = state.dataSize->ZoneHVACSizing(zoneHVACIndex).CoolingSAFMethod;
3924 0 : zoneEqSizing.SizingMethod(SizingMethod) = SAFMethod;
3925 0 : if (SAFMethod == DataSizing::None || SAFMethod == DataSizing::SupplyAirFlowRate || SAFMethod == DataSizing::FlowPerFloorArea ||
3926 : SAFMethod == DataSizing::FractionOfAutosizedCoolingAirflow) {
3927 0 : switch (SAFMethod) {
3928 0 : case DataSizing::SupplyAirFlowRate:
3929 0 : if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow > 0.0) {
3930 0 : zoneEqSizing.AirVolFlow = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow;
3931 0 : zoneEqSizing.SystemAirFlow = true;
3932 : }
3933 0 : TempSize = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow;
3934 0 : if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow > 0.0) {
3935 0 : PrintFlag = false;
3936 : }
3937 0 : break;
3938 0 : case DataSizing::FlowPerFloorArea:
3939 0 : zoneEqSizing.SystemAirFlow = true;
3940 0 : zoneEqSizing.AirVolFlow = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow *
3941 0 : state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
3942 0 : TempSize = zoneEqSizing.AirVolFlow;
3943 0 : state.dataSize->DataScalableSizingON = true;
3944 0 : break;
3945 0 : case DataSizing::FractionOfAutosizedCoolingAirflow:
3946 0 : state.dataSize->DataFracOfAutosizedCoolingAirflow = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow;
3947 0 : TempSize = DataSizing::AutoSize;
3948 0 : state.dataSize->DataScalableSizingON = true;
3949 0 : break;
3950 0 : default:
3951 0 : TempSize = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow;
3952 : }
3953 :
3954 0 : CoolingAirFlowSizer sizingCoolingAirFlow;
3955 0 : std::string stringOverride = "Design Supply Air Flow Rate [m3/s]";
3956 0 : if (state.dataGlobal->isEpJSON) {
3957 0 : stringOverride = "design_supply_air_flow_rate [m3/s]";
3958 : }
3959 0 : sizingCoolingAirFlow.overrideSizingString(stringOverride);
3960 0 : sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
3961 0 : zoneEvapUnit.DesignAirVolumeFlowRate = sizingCoolingAirFlow.size(state, TempSize, errorsFound);
3962 :
3963 0 : } else if (SAFMethod == DataSizing::FlowPerCoolingCapacity) {
3964 0 : SizingMethod = HVAC::CoolingCapacitySizing;
3965 0 : TempSize = DataSizing::AutoSize;
3966 0 : PrintFlag = false;
3967 0 : state.dataSize->DataScalableSizingON = true;
3968 0 : state.dataSize->DataFlowUsedForSizing = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).DesCoolVolFlow;
3969 0 : if (state.dataSize->ZoneHVACSizing(zoneHVACIndex).CoolingCapMethod == DataSizing::FractionOfAutosizedCoolingCapacity) {
3970 0 : state.dataSize->DataFracOfAutosizedCoolingCapacity = state.dataSize->ZoneHVACSizing(zoneHVACIndex).ScaledCoolingCapacity;
3971 : }
3972 0 : CoolingCapacitySizer sizerCoolingCapacity;
3973 0 : sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
3974 0 : state.dataSize->DataCapacityUsedForSizing = sizerCoolingCapacity.size(state, TempSize, errorsFound);
3975 0 : state.dataSize->DataFlowPerCoolingCapacity = state.dataSize->ZoneHVACSizing(zoneHVACIndex).MaxCoolAirVolFlow;
3976 0 : PrintFlag = true;
3977 0 : TempSize = DataSizing::AutoSize;
3978 :
3979 0 : CoolingAirFlowSizer sizingCoolingAirFlow;
3980 0 : std::string stringOverride = "Design Supply Air Flow Rate [m3/s]";
3981 0 : if (state.dataGlobal->isEpJSON) {
3982 0 : stringOverride = "design_supply_air_flow_rate [m3/s]";
3983 : }
3984 0 : sizingCoolingAirFlow.overrideSizingString(stringOverride);
3985 0 : sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
3986 0 : zoneEvapUnit.DesignAirVolumeFlowRate = sizingCoolingAirFlow.size(state, TempSize, errorsFound);
3987 0 : }
3988 0 : state.dataSize->DataScalableSizingON = false;
3989 0 : state.dataSize->ZoneCoolingOnlyFan = false;
3990 : } else {
3991 : // no scalble sizing method has been specified. Sizing proceeds using the method
3992 : // specified in the zoneHVAC object
3993 : // N1 , \field Maximum Supply Air Flow Rate
3994 40 : state.dataSize->ZoneCoolingOnlyFan = true;
3995 40 : if (zoneEvapUnit.DesignAirVolumeFlowRate > 0.0) {
3996 16 : PrintFlag = false;
3997 : }
3998 40 : TempSize = zoneEvapUnit.DesignAirVolumeFlowRate;
3999 40 : CoolingAirFlowSizer sizingCoolingAirFlow;
4000 40 : std::string stringOverride = "Design Supply Air Flow Rate [m3/s]";
4001 40 : if (state.dataGlobal->isEpJSON) {
4002 0 : stringOverride = "design_supply_air_flow_rate [m3/s]";
4003 : }
4004 40 : sizingCoolingAirFlow.overrideSizingString(stringOverride);
4005 40 : sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
4006 40 : zoneEvapUnit.DesignAirVolumeFlowRate = sizingCoolingAirFlow.size(state, TempSize, errorsFound);
4007 40 : state.dataSize->ZoneCoolingOnlyFan = false;
4008 40 : }
4009 40 : }
4010 40 : }
4011 :
4012 170440 : void CalcZoneEvaporativeCoolerUnit(EnergyPlusData &state,
4013 : int const UnitNum, // unit number
4014 : int const ZoneNum, // number of zone being served
4015 : Real64 &SensibleOutputProvided, // sensible capacity delivered to zone
4016 : Real64 &LatentOutputProvided // Latent add/removal (kg/s), dehumid = negative
4017 : )
4018 : {
4019 :
4020 : // SUBROUTINE INFORMATION:
4021 : // AUTHOR B. Griffith
4022 : // DATE WRITTEN July 2013
4023 :
4024 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4025 : Real64 ZoneCoolingLoad;
4026 : Real64 CoolingLoadThreashold;
4027 : Real64 ZoneTemp;
4028 : Real64 CoolSetLowThrottle;
4029 : Real64 CoolSetHiThrottle;
4030 : Real64 PartLoadRatio;
4031 :
4032 : {
4033 170440 : auto &zoneEvapUnit = state.dataEvapCoolers->ZoneEvapUnit(UnitNum);
4034 :
4035 170440 : Real64 relativeHumidity = 100.0 * Psychrometrics::PsyRhFnTdbWPb(state,
4036 170440 : state.dataLoopNodes->Node(zoneEvapUnit.ZoneNodeNum).Temp,
4037 170440 : state.dataLoopNodes->Node(zoneEvapUnit.ZoneNodeNum).HumRat,
4038 170440 : state.dataEnvrn->OutBaroPress,
4039 170440 : "CalcZoneEvaporativeCoolerUnit");
4040 170440 : if (relativeHumidity > zoneEvapUnit.ShutOffRelativeHumidity) {
4041 : // unit is off when humidity is too high
4042 4250 : PartLoadRatio = 0.0;
4043 4250 : zoneEvapUnit.UnitPartLoadRatio = PartLoadRatio;
4044 4250 : CalcZoneEvapUnitOutput(state, UnitNum, PartLoadRatio, SensibleOutputProvided, LatentOutputProvided);
4045 4250 : zoneEvapUnit.IsOnThisTimestep = false;
4046 4250 : return;
4047 : }
4048 :
4049 166190 : if (zoneEvapUnit.ControlSchemeType == ControlType::ZoneTemperatureDeadBandOnOffCycling) {
4050 51132 : ZoneTemp = state.dataLoopNodes->Node(zoneEvapUnit.ZoneNodeNum).Temp;
4051 :
4052 51132 : auto const &zoneTstatSetpt = state.dataHeatBalFanSys->zoneTstatSetpts(ZoneNum);
4053 51132 : CoolSetLowThrottle = zoneTstatSetpt.setptHi - (0.5 * zoneEvapUnit.ThrottlingRange);
4054 51132 : CoolSetHiThrottle = zoneTstatSetpt.setptHi + (0.5 * zoneEvapUnit.ThrottlingRange);
4055 :
4056 51132 : if ((ZoneTemp < CoolSetLowThrottle) || !zoneEvapUnit.UnitIsAvailable) {
4057 35178 : zoneEvapUnit.IsOnThisTimestep = false;
4058 15954 : } else if (ZoneTemp > CoolSetHiThrottle) {
4059 9840 : zoneEvapUnit.IsOnThisTimestep = true;
4060 : } else {
4061 6114 : if (zoneEvapUnit.WasOnLastTimestep) {
4062 6114 : zoneEvapUnit.IsOnThisTimestep = true;
4063 : } else {
4064 0 : zoneEvapUnit.IsOnThisTimestep = false;
4065 : }
4066 : }
4067 :
4068 51132 : if (zoneEvapUnit.IsOnThisTimestep) {
4069 :
4070 15954 : if (zoneEvapUnit.fanOp == HVAC::FanOp::Continuous) {
4071 0 : PartLoadRatio = 1.0;
4072 0 : zoneEvapUnit.UnitPartLoadRatio = PartLoadRatio;
4073 0 : CalcZoneEvapUnitOutput(state, UnitNum, PartLoadRatio, SensibleOutputProvided, LatentOutputProvided);
4074 : } else {
4075 15954 : ZoneCoolingLoad = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputReqToCoolSP;
4076 : // calculate part load ratio for cycling fan/unit first
4077 15954 : ControlZoneEvapUnitOutput(state, UnitNum, ZoneCoolingLoad);
4078 15954 : PartLoadRatio = zoneEvapUnit.UnitPartLoadRatio;
4079 15954 : CalcZoneEvapUnitOutput(state, UnitNum, PartLoadRatio, SensibleOutputProvided, LatentOutputProvided);
4080 : }
4081 :
4082 : } else { // not running
4083 :
4084 35178 : PartLoadRatio = 0.0;
4085 35178 : zoneEvapUnit.UnitPartLoadRatio = PartLoadRatio;
4086 35178 : CalcZoneEvapUnitOutput(state, UnitNum, PartLoadRatio, SensibleOutputProvided, LatentOutputProvided);
4087 : }
4088 :
4089 115058 : } else if (zoneEvapUnit.ControlSchemeType == ControlType::ZoneCoolingLoadOnOffCycling) {
4090 :
4091 : // get zone loads
4092 34088 : ZoneCoolingLoad = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputReqToCoolSP;
4093 34088 : CoolingLoadThreashold = -1.0 * zoneEvapUnit.ThresholdCoolingLoad;
4094 :
4095 34088 : if ((ZoneCoolingLoad < CoolingLoadThreashold) && zoneEvapUnit.UnitIsAvailable) {
4096 :
4097 10636 : if (zoneEvapUnit.fanOp == HVAC::FanOp::Continuous) {
4098 0 : PartLoadRatio = 1.0;
4099 0 : zoneEvapUnit.UnitPartLoadRatio = PartLoadRatio;
4100 0 : CalcZoneEvapUnitOutput(state, UnitNum, PartLoadRatio, SensibleOutputProvided, LatentOutputProvided);
4101 : } else {
4102 : // calculate part load ratio for cycling fan/unit first
4103 10636 : ControlZoneEvapUnitOutput(state, UnitNum, ZoneCoolingLoad);
4104 10636 : PartLoadRatio = zoneEvapUnit.UnitPartLoadRatio;
4105 10636 : CalcZoneEvapUnitOutput(state, UnitNum, PartLoadRatio, SensibleOutputProvided, LatentOutputProvided);
4106 : }
4107 :
4108 : } else {
4109 : // unit is off
4110 23452 : PartLoadRatio = 0.0;
4111 23452 : zoneEvapUnit.UnitPartLoadRatio = PartLoadRatio;
4112 23452 : CalcZoneEvapUnitOutput(state, UnitNum, PartLoadRatio, SensibleOutputProvided, LatentOutputProvided);
4113 : }
4114 :
4115 80970 : } else if (zoneEvapUnit.ControlSchemeType == ControlType::ZoneCoolingLoadVariableSpeedFan) {
4116 : // get zone loads
4117 80970 : ZoneCoolingLoad = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputReqToCoolSP;
4118 80970 : CoolingLoadThreashold = -1.0 * zoneEvapUnit.ThresholdCoolingLoad;
4119 80970 : if ((ZoneCoolingLoad < CoolingLoadThreashold) && zoneEvapUnit.UnitIsAvailable) {
4120 :
4121 : // determine fan speed to meet load
4122 25218 : ControlVSEvapUnitToMeetLoad(state, UnitNum, ZoneCoolingLoad);
4123 : // variable speed fan used fan speed ratio instead of partload ratio
4124 25218 : CalcZoneEvapUnitOutput(state, UnitNum, zoneEvapUnit.FanSpeedRatio, SensibleOutputProvided, LatentOutputProvided);
4125 :
4126 : } else {
4127 : // unit is off
4128 55752 : PartLoadRatio = 0.0;
4129 55752 : CalcZoneEvapUnitOutput(state, UnitNum, PartLoadRatio, SensibleOutputProvided, LatentOutputProvided);
4130 : }
4131 : }
4132 : }
4133 : }
4134 :
4135 271800 : void CalcZoneEvapUnitOutput(EnergyPlusData &state,
4136 : int const UnitNum, // unit number
4137 : Real64 const PartLoadRatio, // zone evap unit part load ratiod
4138 : Real64 &SensibleOutputProvided, // target cooling load
4139 : Real64 &LatentOutputProvided // target cooling load
4140 : )
4141 : {
4142 : // caculates zone evaporative cooler sensible and latent outputs
4143 :
4144 : Real64 MinHumRat; // minimum humidity ratio
4145 :
4146 271800 : auto &zoneEvapUnit = state.dataEvapCoolers->ZoneEvapUnit(UnitNum);
4147 :
4148 271800 : int const ZoneNodeNum = zoneEvapUnit.ZoneNodeNum;
4149 271800 : int const OAInletNodeNum = zoneEvapUnit.OAInletNodeNum;
4150 271800 : int const OutletNodeNum = zoneEvapUnit.UnitOutletNodeNum;
4151 271800 : int const ReliefNodeNum = zoneEvapUnit.UnitReliefNodeNum;
4152 271800 : int const FanInletNodeNum = zoneEvapUnit.FanInletNodeNum;
4153 271800 : int const FanOutletNodeNum = zoneEvapUnit.FanOutletNodeNum;
4154 271800 : int const EvapCooler_1_Index = zoneEvapUnit.EvapCooler_1_Index;
4155 271800 : int const EvapCooler_2_Index = zoneEvapUnit.EvapCooler_2_Index;
4156 :
4157 : // calculate unit sensible cooling output
4158 271800 : if (PartLoadRatio > 0) {
4159 139366 : state.dataLoopNodes->Node(OAInletNodeNum).MassFlowRate = zoneEvapUnit.DesignAirMassFlowRate * PartLoadRatio;
4160 139366 : state.dataLoopNodes->Node(OAInletNodeNum).MassFlowRateMaxAvail = state.dataLoopNodes->Node(OAInletNodeNum).MassFlowRate;
4161 139366 : state.dataLoopNodes->Node(OutletNodeNum).MassFlowRate = state.dataLoopNodes->Node(OAInletNodeNum).MassFlowRate;
4162 139366 : state.dataLoopNodes->Node(OutletNodeNum).MassFlowRateMaxAvail = state.dataLoopNodes->Node(OutletNodeNum).MassFlowRate;
4163 : } else { // not running
4164 132434 : state.dataLoopNodes->Node(OAInletNodeNum).MassFlowRate = 0.0;
4165 132434 : state.dataLoopNodes->Node(OAInletNodeNum).MassFlowRateMaxAvail = 0.0;
4166 132434 : state.dataLoopNodes->Node(FanInletNodeNum).MassFlowRate = 0.0;
4167 132434 : state.dataLoopNodes->Node(FanInletNodeNum).MassFlowRateMaxAvail = 0.0;
4168 132434 : state.dataLoopNodes->Node(FanOutletNodeNum).MassFlowRate = 0.0;
4169 132434 : state.dataLoopNodes->Node(FanOutletNodeNum).MassFlowRateMaxAvail = 0.0;
4170 132434 : state.dataLoopNodes->Node(OutletNodeNum).MassFlowRate = 0.0;
4171 132434 : state.dataLoopNodes->Node(OutletNodeNum).MassFlowRateMaxAvail = 0.0;
4172 :
4173 132434 : state.dataLoopNodes->Node(state.dataEvapCoolers->EvapCond(EvapCooler_1_Index).InletNode).MassFlowRate = 0.0;
4174 132434 : state.dataLoopNodes->Node(state.dataEvapCoolers->EvapCond(EvapCooler_1_Index).InletNode).MassFlowRateMaxAvail = 0.0;
4175 132434 : state.dataLoopNodes->Node(state.dataEvapCoolers->EvapCond(EvapCooler_1_Index).OutletNode).MassFlowRate = 0.0;
4176 132434 : state.dataLoopNodes->Node(state.dataEvapCoolers->EvapCond(EvapCooler_1_Index).OutletNode).MassFlowRateMaxAvail = 0.0;
4177 :
4178 132434 : if (EvapCooler_2_Index > 0) {
4179 41026 : state.dataLoopNodes->Node(state.dataEvapCoolers->EvapCond(EvapCooler_2_Index).InletNode).MassFlowRate = 0.0;
4180 41026 : state.dataLoopNodes->Node(state.dataEvapCoolers->EvapCond(EvapCooler_2_Index).InletNode).MassFlowRateMaxAvail = 0.0;
4181 41026 : state.dataLoopNodes->Node(state.dataEvapCoolers->EvapCond(EvapCooler_2_Index).OutletNode).MassFlowRate = 0.0;
4182 41026 : state.dataLoopNodes->Node(state.dataEvapCoolers->EvapCond(EvapCooler_2_Index).OutletNode).MassFlowRateMaxAvail = 0.0;
4183 : }
4184 : }
4185 271800 : if (ReliefNodeNum > 0) {
4186 271800 : state.dataLoopNodes->Node(ReliefNodeNum).MassFlowRate = state.dataLoopNodes->Node(OAInletNodeNum).MassFlowRate;
4187 271800 : state.dataLoopNodes->Node(ReliefNodeNum).MassFlowRateMaxAvail = state.dataLoopNodes->Node(OAInletNodeNum).MassFlowRate;
4188 : }
4189 271800 : if (zoneEvapUnit.fanPlace == HVAC::FanPlace::BlowThru) {
4190 105062 : state.dataLoopNodes->Node(FanOutletNodeNum).MassFlowRate = state.dataLoopNodes->Node(OAInletNodeNum).MassFlowRate;
4191 105062 : state.dataLoopNodes->Node(FanOutletNodeNum).MassFlowRateMaxAvail = state.dataLoopNodes->Node(OAInletNodeNum).MassFlowRate;
4192 105062 : state.dataFans->fans(zoneEvapUnit.FanIndex)->simulate(state, false, _, _);
4193 : }
4194 :
4195 271800 : if (zoneEvapUnit.EvapCooler_1_AvailStatus) {
4196 271800 : SimEvapCooler(state, zoneEvapUnit.EvapCooler_1_Name, zoneEvapUnit.EvapCooler_1_Index, PartLoadRatio);
4197 : }
4198 :
4199 271800 : if ((zoneEvapUnit.EvapCooler_2_Index > 0) && zoneEvapUnit.EvapCooler_2_AvailStatus) {
4200 82502 : SimEvapCooler(state, zoneEvapUnit.EvapCooler_2_Name, zoneEvapUnit.EvapCooler_2_Index, PartLoadRatio);
4201 : }
4202 271800 : if (zoneEvapUnit.fanPlace == HVAC::FanPlace::DrawThru) {
4203 166738 : state.dataFans->fans(zoneEvapUnit.FanIndex)->simulate(state, false, _, _);
4204 : }
4205 :
4206 : // calculate sensible and latent outputs delivered
4207 271800 : MinHumRat = min(state.dataLoopNodes->Node(ZoneNodeNum).HumRat, state.dataLoopNodes->Node(OutletNodeNum).HumRat);
4208 271800 : SensibleOutputProvided = state.dataLoopNodes->Node(OutletNodeNum).MassFlowRate *
4209 271800 : (Psychrometrics::PsyHFnTdbW(state.dataLoopNodes->Node(OutletNodeNum).Temp, MinHumRat) -
4210 271800 : Psychrometrics::PsyHFnTdbW(state.dataLoopNodes->Node(ZoneNodeNum).Temp, MinHumRat));
4211 271800 : LatentOutputProvided = state.dataLoopNodes->Node(OutletNodeNum).MassFlowRate *
4212 271800 : (state.dataLoopNodes->Node(OutletNodeNum).HumRat - state.dataLoopNodes->Node(ZoneNodeNum).HumRat);
4213 271800 : }
4214 :
4215 26590 : void ControlZoneEvapUnitOutput(EnergyPlusData &state,
4216 : int const UnitNum, // unit number
4217 : Real64 const ZoneCoolingLoad // target cooling load
4218 : )
4219 : {
4220 :
4221 : // calculates unit cooling part load ratio using root solver numerical method
4222 :
4223 : // local variables
4224 26590 : int constexpr MaxIte(50); // maximum number of iterations
4225 26590 : Real64 constexpr Tol(0.01); // error tolerance
4226 : Real64 PartLoadRatio; // cooling part load ratio
4227 : Real64 FullFlowSensibleOutput; // full flow sensible cooling output
4228 : Real64 FullFlowLatentOutput; // full flow sensible cooling output
4229 :
4230 26590 : auto &zoneEvapUnit = state.dataEvapCoolers->ZoneEvapUnit(UnitNum);
4231 :
4232 : // get full flow sensible cooling output
4233 26590 : PartLoadRatio = 1.0;
4234 26590 : CalcZoneEvapUnitOutput(state, UnitNum, PartLoadRatio, FullFlowSensibleOutput, FullFlowLatentOutput);
4235 :
4236 : // calculate part load ratio
4237 26590 : if (FullFlowSensibleOutput < ZoneCoolingLoad) {
4238 74770 : auto f = [&state, UnitNum, ZoneCoolingLoad](Real64 PartLoadRatio) {
4239 : // calculates cooling load residual by varying part load ratio
4240 : Real64 QSensOutputProvided; // sensible output at a given PLR
4241 : Real64 QLatOutputProvided; // latent output at a given PLR
4242 74770 : CalcZoneEvapUnitOutput(state, UnitNum, PartLoadRatio, QSensOutputProvided, QLatOutputProvided);
4243 74770 : return QSensOutputProvided - ZoneCoolingLoad;
4244 13802 : };
4245 : int SolFla; // Flag of root solver
4246 13802 : General::SolveRoot(state, Tol, MaxIte, SolFla, PartLoadRatio, f, 0.0, 1.0);
4247 13802 : if (SolFla == -1) {
4248 0 : if (zoneEvapUnit.UnitLoadControlMaxIterErrorIndex == 0) {
4249 0 : ShowWarningError(state, format("Iteration limit exceeded calculating evap unit part load ratio, for unit={}", zoneEvapUnit.Name));
4250 0 : ShowContinueErrorTimeStamp(state, "");
4251 0 : ShowContinueError(state, format("Unit part load ratio returned={:.2R}", PartLoadRatio));
4252 0 : ShowContinueError(state, "Check input for Fan Placement.");
4253 : }
4254 0 : ShowRecurringWarningErrorAtEnd(
4255 : state,
4256 0 : format("Zone Evaporative Cooler unit part load ratio control failed (iteration limit [{}]) for ZoneHVAC:EvaporativeCoolerUnit =\"{}",
4257 : MaxIte,
4258 0 : zoneEvapUnit.Name),
4259 0 : zoneEvapUnit.UnitLoadControlMaxIterErrorIndex);
4260 :
4261 13802 : } else if (SolFla == -2) {
4262 0 : if (zoneEvapUnit.UnitLoadControlLimitsErrorIndex == 0) {
4263 0 : ShowWarningError(state,
4264 0 : format("Zone Evaporative Cooler unit calculation failed: unit part load ratio limits exceeded, for unit = {}",
4265 0 : zoneEvapUnit.Name));
4266 0 : ShowContinueError(state, "Check input for Fan Placement.");
4267 0 : ShowContinueErrorTimeStamp(state, "");
4268 0 : if (state.dataGlobal->WarmupFlag) {
4269 0 : ShowContinueError(state, "Error occurred during warmup days.");
4270 : }
4271 : }
4272 0 : ShowRecurringWarningErrorAtEnd(
4273 : state,
4274 0 : "Zone Evaporative Cooler unit part load ratio control failed (limits exceeded) for ZoneHVAC:EvaporativeCoolerUnit =\"" +
4275 0 : zoneEvapUnit.Name,
4276 0 : zoneEvapUnit.UnitLoadControlLimitsErrorIndex);
4277 : }
4278 :
4279 : } else {
4280 12788 : PartLoadRatio = 1.0;
4281 : }
4282 26590 : zoneEvapUnit.UnitPartLoadRatio = PartLoadRatio;
4283 26590 : }
4284 :
4285 25218 : void ControlVSEvapUnitToMeetLoad(EnergyPlusData &state,
4286 : int const UnitNum, // unit number
4287 : Real64 const ZoneCoolingLoad // target cooling load
4288 : )
4289 : {
4290 :
4291 : // SUBROUTINE PARAMETER DEFINITIONS:
4292 25218 : int constexpr MaxIte(500); // maximum number of iterations
4293 25218 : auto &zoneEvapUnit = state.dataEvapCoolers->ZoneEvapUnit(UnitNum);
4294 :
4295 : // first get full load result
4296 25218 : zoneEvapUnit.FanSpeedRatio = 1.0;
4297 25218 : state.dataLoopNodes->Node(zoneEvapUnit.OAInletNodeNum).MassFlowRate = zoneEvapUnit.DesignAirMassFlowRate;
4298 25218 : state.dataLoopNodes->Node(zoneEvapUnit.OAInletNodeNum).MassFlowRateMaxAvail = state.dataLoopNodes->Node(zoneEvapUnit.OAInletNodeNum).MassFlowRate;
4299 25218 : state.dataLoopNodes->Node(zoneEvapUnit.UnitOutletNodeNum).MassFlowRate = state.dataLoopNodes->Node(zoneEvapUnit.OAInletNodeNum).MassFlowRate;
4300 25218 : state.dataLoopNodes->Node(zoneEvapUnit.UnitOutletNodeNum).MassFlowRateMaxAvail =
4301 25218 : state.dataLoopNodes->Node(zoneEvapUnit.UnitOutletNodeNum).MassFlowRate;
4302 :
4303 25218 : if (zoneEvapUnit.UnitReliefNodeNum > 0) {
4304 25218 : state.dataLoopNodes->Node(zoneEvapUnit.UnitReliefNodeNum).MassFlowRate = state.dataLoopNodes->Node(zoneEvapUnit.OAInletNodeNum).MassFlowRate;
4305 25218 : state.dataLoopNodes->Node(zoneEvapUnit.UnitReliefNodeNum).MassFlowRateMaxAvail =
4306 25218 : state.dataLoopNodes->Node(zoneEvapUnit.OAInletNodeNum).MassFlowRate;
4307 : }
4308 25218 : if (zoneEvapUnit.fanPlace == HVAC::FanPlace::BlowThru) {
4309 19900 : state.dataLoopNodes->Node(zoneEvapUnit.FanOutletNodeNum).MassFlowRate = state.dataLoopNodes->Node(zoneEvapUnit.OAInletNodeNum).MassFlowRate;
4310 19900 : state.dataLoopNodes->Node(zoneEvapUnit.FanOutletNodeNum).MassFlowRateMaxAvail =
4311 19900 : state.dataLoopNodes->Node(zoneEvapUnit.OAInletNodeNum).MassFlowRate;
4312 19900 : state.dataFans->fans(zoneEvapUnit.FanIndex)->simulate(state, false, _, _);
4313 : }
4314 :
4315 25218 : if (zoneEvapUnit.EvapCooler_1_AvailStatus) {
4316 25218 : SimEvapCooler(state, zoneEvapUnit.EvapCooler_1_Name, zoneEvapUnit.EvapCooler_1_Index);
4317 : }
4318 :
4319 25218 : if ((zoneEvapUnit.EvapCooler_2_Index > 0) && zoneEvapUnit.EvapCooler_2_AvailStatus) {
4320 9264 : SimEvapCooler(state, zoneEvapUnit.EvapCooler_2_Name, zoneEvapUnit.EvapCooler_2_Index);
4321 : }
4322 25218 : if (zoneEvapUnit.fanPlace == HVAC::FanPlace::DrawThru) {
4323 5318 : state.dataFans->fans(zoneEvapUnit.FanIndex)->simulate(state, false, _, _);
4324 : }
4325 :
4326 : // calculate sensible load met using delta enthalpy at a constant (minimum) humidity ratio)
4327 : Real64 MinHumRat =
4328 25218 : min(state.dataLoopNodes->Node(zoneEvapUnit.ZoneNodeNum).HumRat, state.dataLoopNodes->Node(zoneEvapUnit.UnitOutletNodeNum).HumRat);
4329 25218 : Real64 FullFlowSensibleOutputProvided = state.dataLoopNodes->Node(zoneEvapUnit.UnitOutletNodeNum).MassFlowRate *
4330 25218 : (Psychrometrics::PsyHFnTdbW(state.dataLoopNodes->Node(zoneEvapUnit.UnitOutletNodeNum).Temp, MinHumRat) -
4331 25218 : Psychrometrics::PsyHFnTdbW(state.dataLoopNodes->Node(zoneEvapUnit.ZoneNodeNum).Temp, MinHumRat));
4332 :
4333 25218 : if (FullFlowSensibleOutputProvided < ZoneCoolingLoad) { // find speed ratio by regula falsi numerical method
4334 11612 : Real64 FanSpeedRatio = 1.0;
4335 61240 : auto f = [&state, UnitNum, ZoneCoolingLoad](Real64 FanSpeedRatio) {
4336 61240 : auto &unit = state.dataEvapCoolers->ZoneEvapUnit(UnitNum);
4337 61240 : state.dataLoopNodes->Node(unit.OAInletNodeNum).MassFlowRate = unit.DesignAirMassFlowRate * FanSpeedRatio;
4338 61240 : state.dataLoopNodes->Node(unit.OAInletNodeNum).MassFlowRateMaxAvail = state.dataLoopNodes->Node(unit.OAInletNodeNum).MassFlowRate;
4339 61240 : state.dataLoopNodes->Node(unit.UnitOutletNodeNum).MassFlowRate = state.dataLoopNodes->Node(unit.OAInletNodeNum).MassFlowRate;
4340 61240 : state.dataLoopNodes->Node(unit.UnitOutletNodeNum).MassFlowRateMaxAvail = state.dataLoopNodes->Node(unit.UnitOutletNodeNum).MassFlowRate;
4341 :
4342 61240 : if (unit.UnitReliefNodeNum > 0) {
4343 61240 : state.dataLoopNodes->Node(unit.UnitReliefNodeNum).MassFlowRate = state.dataLoopNodes->Node(unit.OAInletNodeNum).MassFlowRate;
4344 61240 : state.dataLoopNodes->Node(unit.UnitReliefNodeNum).MassFlowRateMaxAvail = state.dataLoopNodes->Node(unit.OAInletNodeNum).MassFlowRate;
4345 : }
4346 61240 : if (unit.fanPlace == HVAC::FanPlace::BlowThru) {
4347 47550 : state.dataLoopNodes->Node(unit.FanOutletNodeNum).MassFlowRate = state.dataLoopNodes->Node(unit.OAInletNodeNum).MassFlowRate;
4348 47550 : state.dataLoopNodes->Node(unit.FanOutletNodeNum).MassFlowRateMaxAvail = state.dataLoopNodes->Node(unit.OAInletNodeNum).MassFlowRate;
4349 47550 : state.dataFans->fans(unit.FanIndex)->simulate(state, false, _, _);
4350 : }
4351 :
4352 61240 : if (unit.EvapCooler_1_AvailStatus) {
4353 61240 : SimEvapCooler(state, unit.EvapCooler_1_Name, unit.EvapCooler_1_Index, FanSpeedRatio);
4354 : }
4355 :
4356 61240 : if ((unit.EvapCooler_2_Index > 0) && unit.EvapCooler_2_AvailStatus) {
4357 26282 : SimEvapCooler(state, unit.EvapCooler_2_Name, unit.EvapCooler_2_Index, FanSpeedRatio);
4358 : }
4359 61240 : if (unit.fanPlace == HVAC::FanPlace::DrawThru) {
4360 13690 : state.dataFans->fans(unit.FanIndex)->simulate(state, false, _, _);
4361 : }
4362 :
4363 : Real64 const MinHumRat =
4364 61240 : min(state.dataLoopNodes->Node(unit.ZoneNodeNum).HumRat, state.dataLoopNodes->Node(unit.UnitOutletNodeNum).HumRat);
4365 61240 : Real64 const SensibleOutputProvided = state.dataLoopNodes->Node(unit.UnitOutletNodeNum).MassFlowRate *
4366 61240 : (Psychrometrics::PsyHFnTdbW(state.dataLoopNodes->Node(unit.UnitOutletNodeNum).Temp, MinHumRat) -
4367 61240 : Psychrometrics::PsyHFnTdbW(state.dataLoopNodes->Node(unit.ZoneNodeNum).Temp, MinHumRat));
4368 :
4369 61240 : return SensibleOutputProvided - ZoneCoolingLoad;
4370 11612 : };
4371 11612 : int SolFla = 0; // Flag of RegulaFalsi solver
4372 11612 : Real64 ErrorToler = 0.01;
4373 11612 : General::SolveRoot(state, ErrorToler, MaxIte, SolFla, FanSpeedRatio, f, 0.0, 1.0);
4374 11612 : if (SolFla == -1) {
4375 0 : if (zoneEvapUnit.UnitVSControlMaxIterErrorIndex == 0) {
4376 0 : ShowWarningError(
4377 0 : state, format("Iteration limit exceeded calculating variable speed evap unit fan speed ratio, for unit={}", zoneEvapUnit.Name));
4378 0 : ShowContinueErrorTimeStamp(state, "");
4379 0 : ShowContinueError(state, format("Fan speed ratio returned={:.2R}", FanSpeedRatio));
4380 0 : ShowContinueError(state, "Check input for Fan Placement.");
4381 : }
4382 0 : ShowRecurringWarningErrorAtEnd(
4383 : state,
4384 0 : format("Zone Evaporative Cooler unit control failed (iteration limit [{}]) for ZoneHVAC:EvaporativeCoolerUnit =\"{}",
4385 : MaxIte,
4386 0 : zoneEvapUnit.Name),
4387 0 : zoneEvapUnit.UnitVSControlMaxIterErrorIndex);
4388 :
4389 11612 : } else if (SolFla == -2) {
4390 0 : if (zoneEvapUnit.UnitVSControlLimitsErrorIndex == 0) {
4391 0 : ShowWarningError(state,
4392 0 : format("Variable speed evaporative cooler unit calculation failed: fan speed ratio limits exceeded, for unit = {}",
4393 0 : zoneEvapUnit.Name));
4394 0 : ShowContinueError(state, "Check input for Fan Placement.");
4395 0 : ShowContinueErrorTimeStamp(state, "");
4396 0 : if (state.dataGlobal->WarmupFlag) {
4397 0 : ShowContinueError(state, "Error occurred during warmup days.");
4398 : }
4399 : }
4400 0 : ShowRecurringWarningErrorAtEnd(state,
4401 0 : "Zone Evaporative Cooler unit control failed (limits exceeded) for ZoneHVAC:EvaporativeCoolerUnit =\"" +
4402 0 : zoneEvapUnit.Name,
4403 0 : zoneEvapUnit.UnitVSControlLimitsErrorIndex);
4404 : }
4405 11612 : zoneEvapUnit.FanSpeedRatio = FanSpeedRatio;
4406 : }
4407 25218 : }
4408 :
4409 170440 : void ReportZoneEvaporativeCoolerUnit(EnergyPlusData &state, int const UnitNum) // unit number
4410 : {
4411 :
4412 : // SUBROUTINE INFORMATION:
4413 : // AUTHOR B. Griffith
4414 : // DATE WRITTEN July 2013
4415 :
4416 : // PURPOSE OF THIS SUBROUTINE:
4417 : // update output variables for the zone evap unit
4418 :
4419 : // Using/Aliasing
4420 170440 : Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
4421 :
4422 170440 : auto &zoneEvapUnit = state.dataEvapCoolers->ZoneEvapUnit(UnitNum);
4423 :
4424 170440 : int ZoneNodeNum = zoneEvapUnit.ZoneNodeNum;
4425 170440 : int UnitOutletNodeNum = zoneEvapUnit.UnitOutletNodeNum;
4426 170440 : Real64 AirMassFlow = state.dataLoopNodes->Node(UnitOutletNodeNum).MassFlowRate;
4427 170440 : Real64 QTotUnitOut = AirMassFlow * (state.dataLoopNodes->Node(UnitOutletNodeNum).Enthalpy - state.dataLoopNodes->Node(ZoneNodeNum).Enthalpy);
4428 170440 : Real64 MinHumRat = min(state.dataLoopNodes->Node(ZoneNodeNum).HumRat, state.dataLoopNodes->Node(UnitOutletNodeNum).HumRat);
4429 170440 : Real64 QSensUnitOut = AirMassFlow * (Psychrometrics::PsyHFnTdbW(state.dataLoopNodes->Node(UnitOutletNodeNum).Temp, MinHumRat) -
4430 170440 : Psychrometrics::PsyHFnTdbW(state.dataLoopNodes->Node(ZoneNodeNum).Temp, MinHumRat));
4431 :
4432 170440 : zoneEvapUnit.UnitTotalCoolingRate = std::abs(min(0.0, QTotUnitOut));
4433 170440 : zoneEvapUnit.UnitTotalCoolingEnergy = zoneEvapUnit.UnitTotalCoolingRate * TimeStepSysSec;
4434 170440 : zoneEvapUnit.UnitSensibleCoolingRate = std::abs(min(0.0, QSensUnitOut));
4435 170440 : zoneEvapUnit.UnitSensibleCoolingEnergy = zoneEvapUnit.UnitSensibleCoolingRate * TimeStepSysSec;
4436 170440 : zoneEvapUnit.UnitLatentHeatingRate = std::abs(max(0.0, (QTotUnitOut - QSensUnitOut)));
4437 170440 : zoneEvapUnit.UnitLatentHeatingEnergy = zoneEvapUnit.UnitLatentHeatingRate * TimeStepSysSec;
4438 170440 : zoneEvapUnit.UnitLatentCoolingRate = std::abs(min(0.0, (QTotUnitOut - QSensUnitOut)));
4439 170440 : zoneEvapUnit.UnitLatentCoolingEnergy = zoneEvapUnit.UnitLatentCoolingRate * TimeStepSysSec;
4440 170440 : zoneEvapUnit.UnitFanSpeedRatio = zoneEvapUnit.FanSpeedRatio;
4441 170440 : }
4442 :
4443 0 : int GetInletNodeNum(EnergyPlusData &state, std::string const &EvapCondName, bool &ErrorsFound)
4444 : {
4445 : // FUNCTION INFORMATION:
4446 : // AUTHOR Lixing Gu
4447 : // DATE WRITTEN May 2019
4448 :
4449 : // PURPOSE OF THIS FUNCTION:
4450 : // This function looks up the given EvapCond and returns the air inlet node number.
4451 : // If incorrect EvapCond name is given, ErrorsFound is returned as true and node number as zero.
4452 :
4453 0 : if (state.dataEvapCoolers->GetInputEvapComponentsFlag) { // First time subroutine has been entered
4454 0 : GetEvapInput(state);
4455 0 : state.dataEvapCoolers->GetInputEvapComponentsFlag = false;
4456 : }
4457 :
4458 : int WhichEvapCond =
4459 0 : Util::FindItemInList(EvapCondName, state.dataEvapCoolers->EvapCond, &EvapConditions::Name, state.dataEvapCoolers->NumEvapCool);
4460 0 : if (WhichEvapCond != 0) {
4461 0 : return state.dataEvapCoolers->EvapCond(WhichEvapCond).InletNode;
4462 : } else {
4463 0 : ShowSevereError(state, format("GetInletNodeNum: Could not find EvaporativeCooler = \"{}\"", EvapCondName));
4464 0 : ErrorsFound = true;
4465 0 : return 0;
4466 : }
4467 : }
4468 :
4469 0 : int GetOutletNodeNum(EnergyPlusData &state, std::string const &EvapCondName, bool &ErrorsFound)
4470 : {
4471 : // FUNCTION INFORMATION:
4472 : // AUTHOR Lixing Gu
4473 : // DATE WRITTEN May 2019
4474 :
4475 : // PURPOSE OF THIS FUNCTION:
4476 : // This function looks up the given EvapCond and returns the air outlet node number.
4477 : // If incorrect EvapCond name is given, ErrorsFound is returned as true and node number as zero.
4478 :
4479 0 : if (state.dataEvapCoolers->GetInputEvapComponentsFlag) { // First time subroutine has been entered
4480 0 : GetEvapInput(state);
4481 0 : state.dataEvapCoolers->GetInputEvapComponentsFlag = false;
4482 : }
4483 : int WhichEvapCond =
4484 0 : Util::FindItemInList(EvapCondName, state.dataEvapCoolers->EvapCond, &EvapConditions::Name, state.dataEvapCoolers->NumEvapCool);
4485 0 : if (WhichEvapCond != 0) {
4486 0 : return state.dataEvapCoolers->EvapCond(WhichEvapCond).OutletNode;
4487 : } else {
4488 0 : ShowSevereError(state, format("GetOutletNodeNum: Could not find EvaporativeCooler = \"{}\"", EvapCondName));
4489 0 : ErrorsFound = true;
4490 0 : return 0;
4491 : }
4492 : }
4493 :
4494 : } // namespace EnergyPlus::EvaporativeCoolers
|