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