Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2024, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // C++ Headers
49 : #include <cassert>
50 : #include <cmath>
51 :
52 : // ObjexxFCL Headers
53 : #include <ObjexxFCL/Array.functions.hh>
54 : #include <ObjexxFCL/Fmath.hh>
55 : #include <ObjexxFCL/string.functions.hh>
56 :
57 : // EnergyPlus Headers
58 : #include <EnergyPlus/Autosizing/Base.hh>
59 : #include <EnergyPlus/BranchNodeConnections.hh>
60 : #include <EnergyPlus/CondenserLoopTowers.hh>
61 : #include <EnergyPlus/CurveManager.hh>
62 : #include <EnergyPlus/Data/EnergyPlusData.hh>
63 : #include <EnergyPlus/DataBranchAirLoopPlant.hh>
64 : #include <EnergyPlus/DataEnvironment.hh>
65 : #include <EnergyPlus/DataHVACGlobals.hh>
66 : #include <EnergyPlus/DataIPShortCuts.hh>
67 : #include <EnergyPlus/DataLoopNode.hh>
68 : #include <EnergyPlus/DataPrecisionGlobals.hh>
69 : #include <EnergyPlus/DataSizing.hh>
70 : #include <EnergyPlus/DataWater.hh>
71 : #include <EnergyPlus/FaultsManager.hh>
72 : #include <EnergyPlus/FluidProperties.hh>
73 : #include <EnergyPlus/General.hh>
74 : #include <EnergyPlus/GeneralRoutines.hh>
75 : #include <EnergyPlus/GlobalNames.hh>
76 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
77 : #include <EnergyPlus/NodeInputManager.hh>
78 : #include <EnergyPlus/OutAirNodeManager.hh>
79 : #include <EnergyPlus/OutputProcessor.hh>
80 : #include <EnergyPlus/OutputReportPredefined.hh>
81 : #include <EnergyPlus/Plant/DataPlant.hh>
82 : #include <EnergyPlus/PlantUtilities.hh>
83 : #include <EnergyPlus/Psychrometrics.hh>
84 : #include <EnergyPlus/ScheduleManager.hh>
85 : #include <EnergyPlus/UtilityRoutines.hh>
86 : #include <EnergyPlus/WaterManager.hh>
87 :
88 : namespace EnergyPlus {
89 :
90 : namespace CondenserLoopTowers {
91 :
92 : // Module containing the routines dealing with the objects COOLING TOWER:SINGLE SPEED,
93 : // COOLING TOWER:TWO SPEED, and COOLING TOWER:VARIABLE SPEED
94 :
95 : // MODULE INFORMATION:
96 : // AUTHOR Dan Fisher
97 : // DATE WRITTEN April 1998
98 : // MODIFIED Shirey, Raustad: Dec 2000; Shirey, Sept 2002, Raustad Mar 2005
99 : // B Griffith Aug 2006, added water consumption and water system interactions
100 : // T Hong, Aug 2008. Added fluid bypass for single speed cooling tower
101 : // Chandan Sharma, FSEC, February 2010, Added basin heater
102 : // A Flament, July 2010, added multi-cell capability for the 3 types of cooling tower
103 : // RE-ENGINEERED na
104 :
105 : // PURPOSE OF THIS MODULE:
106 : // Model the performance of cooling towers
107 :
108 : std::string const cCoolingTower_SingleSpeed("CoolingTower:SingleSpeed");
109 : std::string const cCoolingTower_TwoSpeed("CoolingTower:TwoSpeed");
110 : std::string const cCoolingTower_VariableSpeed("CoolingTower:VariableSpeed");
111 : std::string const cCoolingTower_VariableSpeedMerkel("CoolingTower:VariableSpeed:Merkel");
112 :
113 270 : CoolingTower *CoolingTower::factory(EnergyPlusData &state, std::string_view objectName)
114 : {
115 : // Process the input data for towers if it hasn't been done already
116 270 : if (state.dataCondenserLoopTowers->GetInput) {
117 244 : GetTowerInput(state);
118 244 : state.dataCondenserLoopTowers->GetInput = false;
119 : }
120 : // Now look for this particular tower in the list
121 270 : auto thisObj = std::find_if(state.dataCondenserLoopTowers->towers.begin(),
122 270 : state.dataCondenserLoopTowers->towers.end(),
123 299 : [&objectName](const CoolingTower &myObj) { return myObj.Name == objectName; });
124 270 : if (thisObj != state.dataCondenserLoopTowers->towers.end()) return thisObj;
125 : // If we didn't find it, fatal
126 : ShowFatalError(state, format("CoolingTowerFactory: Error getting inputs for tower named: {}", objectName)); // LCOV_EXCL_LINE
127 : // Shut up the compiler
128 : return nullptr; // LCOV_EXCL_LINE
129 : }
130 :
131 8767027 : void CoolingTower::simulate(EnergyPlusData &state,
132 : [[maybe_unused]] const PlantLocation &calledFromLocation,
133 : [[maybe_unused]] bool const FirstHVACIteration,
134 : Real64 &CurLoad,
135 : bool const RunFlag)
136 : {
137 8767027 : this->initialize(state);
138 8767027 : switch (this->TowerType) {
139 7761854 : case DataPlant::PlantEquipmentType::CoolingTower_SingleSpd:
140 7761854 : this->calculateSingleSpeedTower(state, CurLoad, RunFlag);
141 7761854 : break;
142 298469 : case DataPlant::PlantEquipmentType::CoolingTower_TwoSpd:
143 298469 : this->calculateTwoSpeedTower(state, CurLoad, RunFlag);
144 298469 : break;
145 625884 : case DataPlant::PlantEquipmentType::CoolingTower_VarSpd:
146 625884 : this->calculateVariableSpeedTower(state, CurLoad, RunFlag);
147 625884 : break;
148 80820 : case DataPlant::PlantEquipmentType::CoolingTower_VarSpdMerkel:
149 80820 : this->calculateMerkelVariableSpeedTower(state, CurLoad, RunFlag);
150 80820 : break;
151 0 : default:
152 0 : ShowFatalError(state, format("Plant Equipment Type specified for {} is not a Cooling Tower.", this->Name));
153 : }
154 8767027 : this->calculateWaterUsage(state);
155 8767027 : this->update(state);
156 8767027 : this->report(state, RunFlag);
157 8767027 : }
158 :
159 1372 : void CoolingTower::getDesignCapacities([[maybe_unused]] EnergyPlusData &state,
160 : [[maybe_unused]] const PlantLocation &calledFromLocation,
161 : Real64 &MaxLoad,
162 : Real64 &MinLoad,
163 : Real64 &OptLoad)
164 : {
165 1372 : MinLoad = 0.0;
166 1372 : MaxLoad = this->TowerNominalCapacity * this->HeatRejectCapNomCapSizingRatio;
167 1372 : OptLoad = this->TowerNominalCapacity;
168 1372 : }
169 :
170 270 : void CoolingTower::getSizingFactor(Real64 &SizFactor)
171 : {
172 270 : SizFactor = this->SizFac;
173 270 : }
174 :
175 1372 : void CoolingTower::onInitLoopEquip(EnergyPlusData &state, [[maybe_unused]] const PlantLocation &calledFromLocation)
176 : {
177 1372 : this->initialize(state);
178 1372 : if (this->TowerType == DataPlant::PlantEquipmentType::CoolingTower_VarSpdMerkel) {
179 10 : this->SizeVSMerkelTower(state);
180 : } else {
181 1362 : this->SizeTower(state);
182 : }
183 1372 : }
184 :
185 244 : void GetTowerInput(EnergyPlusData &state)
186 : {
187 :
188 : // SUBROUTINE INFORMATION:
189 : // AUTHOR: Dan Fisher
190 : // DATE WRITTEN: April 1998
191 : // MODIFIED Don Shirey, Jan 2001 and Sept/Oct 2002; Richard Raustad, FSEC, Feb 2005 (added VS tower)
192 : // B. Griffith, Aug. 2006 water consumption modeling and water system connections
193 : // T Hong, Aug. 2008: added fluid bypass for single speed tower
194 : // A Flament, July 2010, added multi-cell capability for the 3 types of cooling tower
195 :
196 : // PURPOSE OF THIS SUBROUTINE:
197 : // Obtains input data for cooling towers and stores it in towers data structure. Additional structure
198 : // (VSTower) stores the coefficients for each VS tower.
199 :
200 : // METHODOLOGY EMPLOYED:
201 : // Uses "Get" routines to read in the data.
202 :
203 : // SUBROUTINE PARAMETER DEFINITIONS:
204 : static constexpr std::string_view OutputFormat("{:5.2F}");
205 :
206 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
207 : int TowerNum; // Tower number, reference counter for towers data array
208 244 : int NumVSCoolToolsModelCoeffs = 0; // Number of CoolTools VS cooling tower coefficient objects
209 244 : int NumVSYorkCalcModelCoeffs = 0; // Number of YorkCalc VS cooling tower coefficient objects
210 : int VSModelCoeffNum; // Specific variable-speed tower coefficient object of interest
211 : int NumAlphas; // Number of elements in the alpha array
212 : int NumNums; // Number of elements in the numeric array
213 : int NumAlphas2; // Number of elements in the alpha2 array
214 : int NumNums2; // Number of elements in the numeric2 array
215 : int IOStat; // IO Status when calling get input subroutine
216 : int CoeffNum; // Index for reading user defined VS tower coefficients
217 244 : bool ErrorsFound(false); // Logical flag set .TRUE. if errors found while getting input data
218 244 : Array1D<Real64> NumArray(33); // Numeric input data array
219 244 : Array1D<Real64> NumArray2(43); // Numeric input data array for VS tower coefficients
220 244 : Array1D_string AlphArray(16); // Character string input data array
221 244 : Array1D_string AlphArray2(1); // Character string input data array for VS tower coefficients
222 :
223 244 : std::unordered_map<std::string, std::string> UniqueSimpleTowerNames;
224 :
225 244 : constexpr std::array<std::string_view, static_cast<int>(EvapLoss::Num)> EvapLossNamesUC{"LOSSFACTOR", "SATURATEDEXIT"};
226 244 : constexpr std::array<std::string_view, static_cast<int>(PIM::Num)> PIMNamesUC{"NOMINALCAPACITY", "UFACTORTIMESAREAANDDESIGNWATERFLOWRATE"};
227 244 : constexpr std::array<std::string_view, static_cast<int>(Blowdown::Num)> BlowDownNamesUC = {"CONCENTRATIONRATIO", "SCHEDULEDRATE"};
228 244 : constexpr std::array<std::string_view, static_cast<int>(CellCtrl::Num)> CellCtrlNamesUC = {"MINIMALCELL", "MAXIMALCELL"};
229 :
230 : // Get number of all cooling towers specified in the input data file (idf)
231 244 : int NumSingleSpeedTowers = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCoolingTower_SingleSpeed);
232 244 : int NumTwoSpeedTowers = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCoolingTower_TwoSpeed);
233 244 : int NumVariableSpeedTowers = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCoolingTower_VariableSpeed);
234 244 : int NumVSMerkelTowers = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCoolingTower_VariableSpeedMerkel);
235 244 : int NumSimpleTowers = NumSingleSpeedTowers + NumTwoSpeedTowers + NumVariableSpeedTowers + NumVSMerkelTowers;
236 :
237 244 : if (NumSimpleTowers <= 0)
238 0 : ShowFatalError(state,
239 : "No Cooling Tower objects found in input, however, a branch object has specified a cooling tower. Search the input for "
240 : "CoolingTower to determine the cause for this error.");
241 :
242 244 : state.dataCondenserLoopTowers->GetInput = false;
243 : // See if load distribution manager has already gotten the input
244 244 : if (allocated(state.dataCondenserLoopTowers->towers)) return;
245 :
246 : // Allocate data structures to hold tower input data, report data and tower inlet conditions
247 244 : state.dataCondenserLoopTowers->towers.allocate(NumSimpleTowers);
248 244 : UniqueSimpleTowerNames.reserve(NumSimpleTowers);
249 : // Allocate variable-speed tower structure with data specific to this type
250 244 : if (NumVariableSpeedTowers > 0) {
251 : // Allow users to input model coefficients other than default
252 16 : NumVSCoolToolsModelCoeffs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "CoolingTowerPerformance:CoolTools");
253 16 : NumVSYorkCalcModelCoeffs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "CoolingTowerPerformance:YorkCalc");
254 : }
255 :
256 244 : std::string &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
257 :
258 : // Load data structures with cooling tower input data
259 244 : cCurrentModuleObject = cCoolingTower_SingleSpeed;
260 475 : for (int SingleSpeedTowerNumber = 1; SingleSpeedTowerNumber <= NumSingleSpeedTowers; ++SingleSpeedTowerNumber) {
261 231 : TowerNum = SingleSpeedTowerNumber;
262 462 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
263 : cCurrentModuleObject,
264 : SingleSpeedTowerNumber,
265 : AlphArray,
266 : NumAlphas,
267 : NumArray,
268 : NumNums,
269 : IOStat,
270 : _,
271 231 : state.dataIPShortCut->lAlphaFieldBlanks,
272 231 : state.dataIPShortCut->cAlphaFieldNames,
273 231 : state.dataIPShortCut->cNumericFieldNames);
274 231 : GlobalNames::VerifyUniqueInterObjectName(
275 462 : state, UniqueSimpleTowerNames, AlphArray(1), cCurrentModuleObject, state.dataIPShortCut->cAlphaFieldNames(1), ErrorsFound);
276 231 : auto &tower = state.dataCondenserLoopTowers->towers(TowerNum);
277 231 : tower.Name = AlphArray(1);
278 231 : tower.TowerType = DataPlant::PlantEquipmentType::CoolingTower_SingleSpd;
279 231 : tower.TowerMassFlowRateMultiplier = 2.5;
280 231 : tower.WaterInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
281 231 : AlphArray(2),
282 : ErrorsFound,
283 : DataLoopNode::ConnectionObjectType::CoolingTowerSingleSpeed,
284 231 : tower.Name,
285 : DataLoopNode::NodeFluidType::Water,
286 : DataLoopNode::ConnectionType::Inlet,
287 : NodeInputManager::CompFluidStream::Primary,
288 : DataLoopNode::ObjectIsNotParent);
289 231 : tower.WaterOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
290 231 : AlphArray(3),
291 : ErrorsFound,
292 : DataLoopNode::ConnectionObjectType::CoolingTowerSingleSpeed,
293 231 : tower.Name,
294 : DataLoopNode::NodeFluidType::Water,
295 : DataLoopNode::ConnectionType::Outlet,
296 : NodeInputManager::CompFluidStream::Primary,
297 : DataLoopNode::ObjectIsNotParent);
298 231 : BranchNodeConnections::TestCompSet(state, cCurrentModuleObject, tower.Name, AlphArray(2), AlphArray(3), "Chilled Water Nodes");
299 231 : tower.DesignWaterFlowRate = NumArray(1);
300 231 : if (tower.DesignWaterFlowRate == DataSizing::AutoSize) {
301 108 : tower.DesignWaterFlowRateWasAutoSized = true;
302 : }
303 231 : tower.HighSpeedAirFlowRate = NumArray(2);
304 231 : if (tower.HighSpeedAirFlowRate == DataSizing::AutoSize) {
305 113 : tower.HighSpeedAirFlowRateWasAutoSized = true;
306 : }
307 231 : tower.HighSpeedFanPower = NumArray(3);
308 231 : if (tower.HighSpeedFanPower == DataSizing::AutoSize) {
309 110 : tower.HighSpeedFanPowerWasAutoSized = true;
310 : }
311 231 : tower.HighSpeedTowerUA = NumArray(4);
312 231 : if (tower.HighSpeedTowerUA == DataSizing::AutoSize) {
313 110 : tower.HighSpeedTowerUAWasAutoSized = true;
314 : }
315 231 : tower.FreeConvAirFlowRate = NumArray(5);
316 231 : if (tower.FreeConvAirFlowRate == DataSizing::AutoSize) {
317 57 : tower.FreeConvAirFlowRateWasAutoSized = true;
318 : }
319 231 : tower.FreeConvAirFlowRateSizingFactor = NumArray(6);
320 231 : tower.FreeConvTowerUA = NumArray(7);
321 231 : if (tower.FreeConvTowerUA == DataSizing::AutoSize) {
322 57 : tower.FreeConvTowerUAWasAutoSized = true;
323 : }
324 231 : tower.FreeConvTowerUASizingFactor = NumArray(8);
325 231 : tower.HeatRejectCapNomCapSizingRatio = NumArray(9);
326 231 : tower.TowerNominalCapacity = NumArray(10);
327 231 : if (tower.TowerNominalCapacity == DataSizing::AutoSize) {
328 0 : tower.TowerNominalCapacityWasAutoSized = true;
329 : }
330 231 : tower.TowerFreeConvNomCap = NumArray(11);
331 231 : if (tower.TowerFreeConvNomCap == DataSizing::AutoSize) {
332 13 : tower.TowerFreeConvNomCapWasAutoSized = true;
333 : }
334 231 : tower.TowerFreeConvNomCapSizingFactor = NumArray(12);
335 231 : if (NumAlphas >= 4) {
336 231 : tower.PerformanceInputMethod_Num = static_cast<PIM>(getEnumValue(PIMNamesUC, Util::makeUPPER(AlphArray(4))));
337 231 : if (tower.PerformanceInputMethod_Num == PIM::Invalid) {
338 0 : ShowSevereError(state, format("{}={}", cCurrentModuleObject, AlphArray(1)));
339 0 : ShowContinueError(state, format("Invalid, {} = {}", state.dataIPShortCut->cAlphaFieldNames(4), AlphArray(4)));
340 0 : ErrorsFound = true;
341 : }
342 : } else {
343 : // Since Performance Input Method has been omitted then assume it to be UA and DESIGN WATER FLOW RATE
344 0 : tower.PerformanceInputMethod_Num = PIM::UFactor;
345 : }
346 : // cooling tower design inlet conditions
347 231 : tower.DesInletAirDBTemp = NumArray(13);
348 231 : if (tower.DesInletAirDBTemp == 0) {
349 0 : tower.DesInletAirDBTemp = 35.0;
350 0 : tower.TowerInletCondsAutoSize = true;
351 : }
352 231 : tower.DesInletAirWBTemp = NumArray(14);
353 231 : if (tower.DesInletAirWBTemp == 0) {
354 0 : tower.DesInletAirWBTemp = 25.6;
355 0 : tower.TowerInletCondsAutoSize = true;
356 : }
357 231 : tower.DesApproach = NumArray(15);
358 231 : if (tower.DesApproach == DataSizing::AutoSize || tower.DesApproach == 0) {
359 231 : tower.DesApproach = 3.9;
360 231 : tower.TowerInletCondsAutoSize = true;
361 : }
362 231 : tower.DesRange = NumArray(16);
363 231 : if (tower.DesRange == DataSizing::AutoSize || tower.DesRange == 0) {
364 231 : tower.DesRange = 5.5;
365 231 : tower.TowerInletCondsAutoSize = true;
366 : }
367 : // set tower design water outlet and inlet temperatures
368 231 : tower.DesOutletWaterTemp = tower.DesInletAirWBTemp + tower.DesApproach;
369 231 : tower.DesInletWaterTemp = tower.DesOutletWaterTemp + tower.DesRange;
370 : // Basin heater power as a function of temperature must be greater than or equal to 0
371 231 : tower.BasinHeaterPowerFTempDiff = NumArray(17);
372 231 : if (NumArray(17) < 0.0) {
373 0 : ShowSevereError(
374 : state,
375 0 : format("{}, \"{}\" basin heater power as a function of temperature difference must be >= 0", cCurrentModuleObject, tower.Name));
376 0 : ErrorsFound = true;
377 : }
378 :
379 231 : tower.BasinHeaterSetPointTemp = NumArray(18);
380 :
381 231 : if (tower.BasinHeaterPowerFTempDiff > 0.0) {
382 0 : if (NumNums < 18) {
383 0 : tower.BasinHeaterSetPointTemp = 2.0;
384 : }
385 0 : if (tower.BasinHeaterSetPointTemp < 2.0) {
386 0 : ShowWarningError(state,
387 0 : format("{}:\"{}\", {} is less than 2 deg C. Freezing could occur.",
388 : cCurrentModuleObject,
389 0 : tower.Name,
390 0 : state.dataIPShortCut->cNumericFieldNames(18)));
391 : }
392 : }
393 :
394 231 : if (!AlphArray(5).empty()) {
395 0 : tower.BasinHeaterSchedulePtr = ScheduleManager::GetScheduleIndex(state, AlphArray(5));
396 0 : if (tower.BasinHeaterSchedulePtr == 0) {
397 0 : ShowWarningError(state,
398 0 : format("{}, \"{}\" basin heater schedule name \"{}\" was not found. Basin heater operation will not be modeled "
399 : "and the simulation continues",
400 : cCurrentModuleObject,
401 0 : tower.Name,
402 : AlphArray(5)));
403 : }
404 : }
405 :
406 : // begin water use and systems get input
407 231 : tower.EvapLossMode = static_cast<EvapLoss>(getEnumValue(EvapLossNamesUC, Util::makeUPPER(AlphArray(6))));
408 :
409 231 : tower.UserEvapLossFactor = NumArray(19); // N11 , \field Evaporation Loss Factor
410 231 : tower.DriftLossFraction = NumArray(20) / 100.0; // N12, \field Drift Loss Percent
411 231 : tower.ConcentrationRatio = NumArray(21); // N13, \field Blowdown Concentration Ratio
412 231 : tower.SizFac = NumArray(25); // N17 \field Sizing Factor
413 231 : if (tower.SizFac <= 0.0) tower.SizFac = 1.0;
414 :
415 231 : tower.BlowdownMode = static_cast<Blowdown>(getEnumValue(BlowDownNamesUC, Util::makeUPPER(AlphArray(7))));
416 231 : tower.SchedIDBlowdown = ScheduleManager::GetScheduleIndex(state, AlphArray(8));
417 231 : if ((tower.SchedIDBlowdown == 0) && (tower.BlowdownMode == Blowdown::Schedule)) {
418 0 : ShowSevereError(state, format("Invalid, {} = \"{}\"", state.dataIPShortCut->cAlphaFieldNames(8), AlphArray(8)));
419 0 : ShowContinueError(state, format("Entered in {} = \"{}\"", cCoolingTower_SingleSpeed, tower.Name));
420 0 : ErrorsFound = true;
421 : }
422 :
423 231 : if (AlphArray(9).empty()) {
424 229 : tower.SuppliedByWaterSystem = false;
425 : } else { // water from storage tank
426 4 : WaterManager::SetupTankDemandComponent(
427 4 : state, AlphArray(1), cCurrentModuleObject, AlphArray(9), ErrorsFound, tower.WaterTankID, tower.WaterTankDemandARRID);
428 2 : tower.SuppliedByWaterSystem = true;
429 : }
430 :
431 : // outdoor air inlet node
432 :
433 231 : if (state.dataIPShortCut->lAlphaFieldBlanks(10)) {
434 195 : tower.OutdoorAirInletNodeNum = 0;
435 : } else {
436 36 : tower.OutdoorAirInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
437 36 : AlphArray(10),
438 : ErrorsFound,
439 : DataLoopNode::ConnectionObjectType::CoolingTowerSingleSpeed,
440 36 : tower.Name,
441 : DataLoopNode::NodeFluidType::Air,
442 : DataLoopNode::ConnectionType::OutsideAirReference,
443 : NodeInputManager::CompFluidStream::Primary,
444 : DataLoopNode::ObjectIsNotParent);
445 36 : if (!OutAirNodeManager::CheckOutAirNodeNumber(state, tower.OutdoorAirInletNodeNum)) {
446 0 : ShowSevereError(state,
447 0 : format("{}, \"{}\" Outdoor Air Inlet Node Name not valid Outdoor Air Node= {}",
448 : cCurrentModuleObject,
449 0 : tower.Name,
450 : AlphArray(10)));
451 0 : ShowContinueError(state, "...does not appear in an OutdoorAir:NodeList or as an OutdoorAir:Node.");
452 0 : ErrorsFound = true;
453 : }
454 : }
455 :
456 : // fluid bypass for single speed tower
457 231 : if (state.dataIPShortCut->lAlphaFieldBlanks(11) || AlphArray(11).empty()) {
458 192 : tower.CapacityControl = CapacityCtrl::FanCycling; // FanCycling
459 : } else {
460 39 : tower.CapacityControl = static_cast<CapacityCtrl>(getEnumValue(CapacityCtrlNamesUC, Util::makeUPPER(AlphArray(11))));
461 39 : if (tower.CapacityControl == CapacityCtrl::Invalid) {
462 0 : tower.CapacityControl = CapacityCtrl::FanCycling;
463 0 : ShowWarningError(state,
464 0 : format("{}, \"{}\" The Capacity Control is not specified correctly. The default Fan Cycling is used.",
465 : cCurrentModuleObject,
466 0 : tower.Name));
467 : }
468 : }
469 :
470 : // added for multi-cell
471 231 : tower.NumCell = NumArray(22);
472 231 : if ((NumNums < 22) && (tower.NumCell == 0)) {
473 : // assume Number of Cells not entered and should be defaulted
474 0 : tower.NumCell = 1;
475 : }
476 231 : tower.MinFracFlowRate = NumArray(23);
477 231 : if ((NumNums < 23) && (tower.MinFracFlowRate == 0.0)) {
478 : // assume Cell Minimum Water Flow Rate Fraction not entered and should be defaulted
479 0 : tower.MinFracFlowRate = 0.33;
480 : }
481 231 : tower.MaxFracFlowRate = NumArray(24);
482 231 : if ((NumNums < 24) && (tower.MaxFracFlowRate == 0.0)) {
483 : // assume Cell Maximum Water Flow Rate Fraction not entered and should be defaulted
484 0 : tower.MaxFracFlowRate = 2.5;
485 : }
486 :
487 : // cell control for single speed tower
488 231 : if (!state.dataIPShortCut->lAlphaFieldBlanks(12)) {
489 2 : tower.cellCtrl = static_cast<CellCtrl>(getEnumValue(CellCtrlNamesUC, Util::makeUPPER(AlphArray(12))));
490 : }
491 :
492 : // High speed air flow rate must be greater than free convection air flow rate.
493 : // Can't tell yet if autosized, check later in initialize.
494 231 : if (tower.HighSpeedAirFlowRate <= tower.FreeConvAirFlowRate && tower.HighSpeedAirFlowRate != DataSizing::AutoSize) {
495 0 : ShowSevereError(
496 : state,
497 0 : format("{} \"{}\". Free convection air flow rate must be less than the design air flow rate.", cCurrentModuleObject, tower.Name));
498 0 : ErrorsFound = true;
499 : }
500 :
501 : // Check various inputs if Performance Input Method = "UA and Design Water Flow Rate"
502 231 : if (tower.PerformanceInputMethod_Num == PIM::UFactor) {
503 228 : if (tower.DesignWaterFlowRate == 0.0) {
504 0 : ShowSevereError(state,
505 0 : format("{} \"{}\". Tower performance input method requires a design water flow rate greater than zero.",
506 : cCurrentModuleObject,
507 0 : tower.Name));
508 0 : ErrorsFound = true;
509 : }
510 228 : if (tower.HighSpeedTowerUA <= tower.FreeConvTowerUA && tower.HighSpeedTowerUA != DataSizing::AutoSize) {
511 0 : ShowSevereError(state,
512 0 : format("{} \"{}\". Free convection UA must be less than the design tower UA.", cCurrentModuleObject, tower.Name));
513 0 : ErrorsFound = true;
514 : }
515 228 : if (tower.FreeConvTowerUA > 0.0 && tower.FreeConvAirFlowRate == 0.0) {
516 0 : ShowSevereError(
517 : state,
518 0 : format("{} \"{}\". Free convection air flow rate must be greater than zero when free convection UA is greater than zero.",
519 : cCurrentModuleObject,
520 0 : tower.Name));
521 0 : ErrorsFound = true;
522 : }
523 3 : } else if (tower.PerformanceInputMethod_Num == PIM::NominalCapacity) {
524 3 : if (tower.TowerNominalCapacity == 0.0) {
525 0 : ShowSevereError(
526 : state,
527 0 : format("{} \"{}\". Tower performance input method requires valid nominal capacity.", cCurrentModuleObject, tower.Name));
528 0 : ErrorsFound = true;
529 : }
530 3 : if (tower.DesignWaterFlowRate != 0.0) {
531 0 : if (tower.DesignWaterFlowRate > 0.0) {
532 0 : ShowWarningError(state,
533 0 : format("{} \"{}\". Nominal capacity input method and design water flow rate have been specified.",
534 : cCurrentModuleObject,
535 0 : tower.Name));
536 : } else {
537 0 : ShowSevereError(
538 : state,
539 0 : format("{} \"{}\". Nominal capacity input method has been specified and design water flow rate is being autosized.",
540 : cCurrentModuleObject,
541 0 : tower.Name));
542 : }
543 0 : ShowContinueError(state, "Design water flow rate will be set according to nominal tower capacity.");
544 : }
545 3 : if (tower.HighSpeedTowerUA != 0.0) {
546 0 : if (tower.HighSpeedTowerUA > 0.0) {
547 0 : ShowWarningError(
548 : state,
549 0 : format("{} \"{}\". Nominal tower capacity and design tower UA have been specified.", cCurrentModuleObject, tower.Name));
550 : } else {
551 0 : ShowSevereError(state,
552 0 : format("{} \"{}\". Nominal tower capacity has been specified and design tower UA is being autosized.",
553 : cCurrentModuleObject,
554 0 : tower.Name));
555 : }
556 0 : ShowContinueError(state, "Design tower UA will be set according to nominal tower capacity.");
557 : }
558 3 : if (tower.FreeConvTowerUA != 0.0) {
559 0 : if (tower.FreeConvTowerUA > 0.0) {
560 0 : ShowWarningError(state,
561 0 : format("{} \"{}\". Nominal capacity input method and free convection UA have been specified.",
562 : cCurrentModuleObject,
563 0 : tower.Name));
564 : } else {
565 0 : ShowSevereError(
566 : state,
567 0 : format("{} \"{}\". Nominal capacity input method has been specified and free convection UA is being autosized.",
568 : cCurrentModuleObject,
569 0 : tower.Name));
570 : }
571 0 : ShowContinueError(state, "Free convection UA will be set according to nominal tower capacity.");
572 : }
573 3 : if (tower.TowerFreeConvNomCap >= tower.TowerNominalCapacity) {
574 0 : ShowSevereError(state,
575 0 : format("{} \"{}\". Free convection nominal capacity must be less than the nominal (design) tower capacity.",
576 : cCurrentModuleObject,
577 0 : tower.Name));
578 0 : ErrorsFound = true;
579 : }
580 3 : if (tower.TowerFreeConvNomCap > 0.0 && tower.FreeConvAirFlowRate == 0.0) {
581 0 : ShowSevereError(
582 : state,
583 0 : format("{} \"{}\". Free convection air flow must be greater than zero when tower free convection capacity is specified.",
584 : cCurrentModuleObject,
585 0 : tower.Name));
586 0 : ErrorsFound = true;
587 : }
588 : } else { // Tower performance input method is not specified as a valid "choice"
589 0 : ShowSevereError(state,
590 0 : format("{} \"{}{}",
591 : cCurrentModuleObject,
592 0 : tower.Name,
593 : ". Tower Performance Input Method must be \"UFactorTimesAreaAndDesignWaterFlowRate\" or \"NominalCapacity\""));
594 0 : ShowContinueError(state, format("Tower Performanace Input Method currently specified as: {}", AlphArray(4)));
595 0 : ErrorsFound = true;
596 : }
597 231 : if (NumAlphas > 12) {
598 1 : tower.EndUseSubcategory = AlphArray(13);
599 : } else {
600 230 : tower.EndUseSubcategory = "General";
601 : }
602 : } // End Single-Speed Tower Loop
603 :
604 244 : cCurrentModuleObject = cCoolingTower_TwoSpeed;
605 257 : for (int TwoSpeedTowerNumber = 1; TwoSpeedTowerNumber <= NumTwoSpeedTowers; ++TwoSpeedTowerNumber) {
606 13 : TowerNum = NumSingleSpeedTowers + TwoSpeedTowerNumber;
607 26 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
608 : cCurrentModuleObject,
609 : TwoSpeedTowerNumber,
610 : AlphArray,
611 : NumAlphas,
612 : NumArray,
613 : NumNums,
614 : IOStat,
615 : _,
616 13 : state.dataIPShortCut->lAlphaFieldBlanks,
617 13 : state.dataIPShortCut->cAlphaFieldNames,
618 13 : state.dataIPShortCut->cNumericFieldNames);
619 13 : GlobalNames::VerifyUniqueInterObjectName(
620 26 : state, UniqueSimpleTowerNames, AlphArray(1), cCurrentModuleObject, state.dataIPShortCut->cAlphaFieldNames(1), ErrorsFound);
621 :
622 13 : auto &tower = state.dataCondenserLoopTowers->towers(TowerNum);
623 13 : tower.Name = AlphArray(1);
624 13 : tower.TowerType = DataPlant::PlantEquipmentType::CoolingTower_TwoSpd;
625 13 : tower.TowerMassFlowRateMultiplier = 2.5;
626 13 : tower.WaterInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
627 13 : AlphArray(2),
628 : ErrorsFound,
629 : DataLoopNode::ConnectionObjectType::CoolingTowerTwoSpeed,
630 13 : tower.Name,
631 : DataLoopNode::NodeFluidType::Water,
632 : DataLoopNode::ConnectionType::Inlet,
633 : NodeInputManager::CompFluidStream::Primary,
634 : DataLoopNode::ObjectIsNotParent);
635 13 : tower.WaterOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
636 13 : AlphArray(3),
637 : ErrorsFound,
638 : DataLoopNode::ConnectionObjectType::CoolingTowerTwoSpeed,
639 13 : tower.Name,
640 : DataLoopNode::NodeFluidType::Water,
641 : DataLoopNode::ConnectionType::Outlet,
642 : NodeInputManager::CompFluidStream::Primary,
643 : DataLoopNode::ObjectIsNotParent);
644 13 : BranchNodeConnections::TestCompSet(state, cCurrentModuleObject, AlphArray(1), AlphArray(2), AlphArray(3), "Chilled Water Nodes");
645 :
646 13 : if (NumAlphas >= 4) {
647 13 : tower.PerformanceInputMethod_Num = static_cast<PIM>(getEnumValue(PIMNamesUC, Util::makeUPPER(AlphArray(4))));
648 : } else {
649 : // Since Performance Input Method has been omitted then assume it to be UA and DESIGN WATER FLOW RATE
650 0 : tower.PerformanceInputMethod_Num = PIM::UFactor;
651 : }
652 13 : tower.DesignWaterFlowRate = NumArray(1);
653 13 : if (tower.DesignWaterFlowRate == DataSizing::AutoSize) {
654 8 : tower.DesignWaterFlowRateWasAutoSized = true;
655 : }
656 13 : tower.HighSpeedAirFlowRate = NumArray(2);
657 13 : if (tower.HighSpeedAirFlowRate == DataSizing::AutoSize) {
658 9 : tower.HighSpeedAirFlowRateWasAutoSized = true;
659 : }
660 13 : tower.HighSpeedFanPower = NumArray(3);
661 13 : if (tower.HighSpeedFanPower == DataSizing::AutoSize) {
662 9 : tower.HighSpeedFanPowerWasAutoSized = true;
663 : }
664 13 : tower.HighSpeedTowerUA = NumArray(4);
665 13 : if (tower.HighSpeedTowerUA == DataSizing::AutoSize) {
666 8 : tower.HighSpeedTowerUAWasAutoSized = true;
667 : }
668 13 : tower.LowSpeedAirFlowRate = NumArray(5);
669 13 : if (tower.LowSpeedAirFlowRate == DataSizing::AutoSize) {
670 9 : tower.LowSpeedAirFlowRateWasAutoSized = true;
671 : }
672 :
673 13 : tower.LowSpeedAirFlowRateSizingFactor = NumArray(6);
674 13 : tower.LowSpeedFanPower = NumArray(7);
675 13 : if (tower.LowSpeedFanPower == DataSizing::AutoSize) {
676 9 : tower.LowSpeedFanPowerWasAutoSized = true;
677 : }
678 13 : tower.LowSpeedFanPowerSizingFactor = NumArray(8);
679 13 : tower.LowSpeedTowerUA = NumArray(9);
680 13 : if (tower.LowSpeedTowerUA == DataSizing::AutoSize) {
681 8 : tower.LowSpeedTowerUAWasAutoSized = true;
682 : }
683 13 : tower.LowSpeedTowerUASizingFactor = NumArray(10);
684 13 : tower.FreeConvAirFlowRate = NumArray(11);
685 13 : if (tower.FreeConvAirFlowRate == DataSizing::AutoSize) {
686 7 : tower.FreeConvAirFlowRateWasAutoSized = true;
687 : }
688 13 : tower.FreeConvAirFlowRateSizingFactor = NumArray(12);
689 13 : tower.FreeConvTowerUA = NumArray(13);
690 13 : if (tower.FreeConvTowerUA == DataSizing::AutoSize) {
691 6 : tower.FreeConvTowerUAWasAutoSized = true;
692 : }
693 13 : tower.FreeConvTowerUASizingFactor = NumArray(14);
694 13 : tower.HeatRejectCapNomCapSizingRatio = NumArray(15);
695 13 : tower.TowerNominalCapacity = NumArray(16);
696 :
697 13 : tower.TowerLowSpeedNomCap = NumArray(17);
698 13 : if (tower.TowerLowSpeedNomCap == DataSizing::AutoSize) {
699 3 : tower.TowerLowSpeedNomCapWasAutoSized = true;
700 : }
701 13 : tower.TowerLowSpeedNomCapSizingFactor = NumArray(18);
702 13 : tower.TowerFreeConvNomCap = NumArray(19);
703 13 : if (tower.TowerFreeConvNomCap == DataSizing::AutoSize) {
704 3 : tower.TowerFreeConvNomCapWasAutoSized = true;
705 : }
706 13 : tower.TowerFreeConvNomCapSizingFactor = NumArray(20);
707 : // cooling tower design inlet conditions
708 13 : tower.DesInletAirDBTemp = NumArray(21);
709 13 : if (tower.DesInletAirDBTemp == 0) {
710 0 : tower.DesInletAirDBTemp = 35.0;
711 0 : tower.TowerInletCondsAutoSize = true;
712 : }
713 13 : tower.DesInletAirWBTemp = NumArray(22);
714 13 : if (tower.DesInletAirWBTemp == 0) {
715 0 : tower.DesInletAirWBTemp = 25.6;
716 0 : tower.TowerInletCondsAutoSize = true;
717 : }
718 13 : tower.DesApproach = NumArray(23);
719 13 : if (tower.DesApproach == DataSizing::AutoSize || tower.DesApproach == 0) {
720 13 : tower.DesApproach = 3.9;
721 13 : tower.TowerInletCondsAutoSize = true;
722 : }
723 13 : tower.DesRange = NumArray(24);
724 13 : if (tower.DesRange == DataSizing::AutoSize || tower.DesRange == 0) {
725 13 : tower.DesRange = 5.5;
726 13 : tower.TowerInletCondsAutoSize = true;
727 : }
728 : // set tower design water outlet and inlet temperatures
729 13 : tower.DesOutletWaterTemp = tower.DesInletAirWBTemp + tower.DesApproach;
730 13 : tower.DesInletWaterTemp = tower.DesOutletWaterTemp + tower.DesRange;
731 : // Basin heater power as a function of temperature must be greater than or equal to 0
732 13 : tower.BasinHeaterPowerFTempDiff = NumArray(25);
733 13 : if (NumArray(25) < 0.0) {
734 0 : ShowSevereError(
735 : state,
736 0 : format("{}, \"{}\" basin heater power as a function of temperature difference must be >= 0", cCurrentModuleObject, tower.Name));
737 0 : ErrorsFound = true;
738 : }
739 :
740 13 : tower.BasinHeaterSetPointTemp = NumArray(26);
741 13 : if (tower.BasinHeaterPowerFTempDiff > 0.0) {
742 0 : if (NumNums < 26) {
743 0 : tower.BasinHeaterSetPointTemp = 2.0;
744 : }
745 0 : if (tower.BasinHeaterSetPointTemp < 2.0) {
746 0 : ShowWarningError(state,
747 0 : format("{}:\"{}\", {} is less than 2 deg C. Freezing could occur.",
748 : cCurrentModuleObject,
749 0 : tower.Name,
750 0 : state.dataIPShortCut->cNumericFieldNames(26)));
751 : }
752 : }
753 :
754 13 : if (!AlphArray(5).empty()) {
755 0 : tower.BasinHeaterSchedulePtr = ScheduleManager::GetScheduleIndex(state, AlphArray(5));
756 0 : if (tower.BasinHeaterSchedulePtr == 0) {
757 0 : ShowWarningError(state,
758 0 : format("{}, \"{}\" basin heater schedule name \"{}\" was not found. Basin heater operation will not be modeled "
759 : "and the simulation continues",
760 : cCurrentModuleObject,
761 0 : tower.Name,
762 : AlphArray(5)));
763 : }
764 : }
765 :
766 : // begin water use and systems get input
767 13 : tower.EvapLossMode = static_cast<EvapLoss>(getEnumValue(EvapLossNamesUC, Util::makeUPPER(AlphArray(6))));
768 13 : tower.UserEvapLossFactor = NumArray(27); // N23 , \field Evaporation Loss Factor
769 13 : tower.DriftLossFraction = NumArray(28) / 100.0; // N24, \field Drift Loss Percent
770 13 : tower.ConcentrationRatio = NumArray(29); // N17, \field Blowdown Concentration Ratio
771 13 : tower.SizFac = NumArray(33); // N21 \field Sizing Factor
772 13 : if (tower.SizFac <= 0.0) tower.SizFac = 1.0;
773 :
774 13 : tower.BlowdownMode = static_cast<Blowdown>(getEnumValue(BlowDownNamesUC, Util::makeUPPER(AlphArray(7))));
775 13 : tower.SchedIDBlowdown = ScheduleManager::GetScheduleIndex(state, AlphArray(8));
776 13 : if ((tower.SchedIDBlowdown == 0) && (tower.BlowdownMode == Blowdown::Schedule)) {
777 0 : ShowSevereError(state, format("Invalid, {} = \"{}\"", state.dataIPShortCut->cAlphaFieldNames(8), AlphArray(8)));
778 0 : ShowContinueError(state, format("Entered in {} = \"{}\"", cCoolingTower_TwoSpeed, tower.Name));
779 0 : ErrorsFound = true;
780 : }
781 :
782 : // added for multi-cell
783 13 : tower.NumCell = NumArray(30);
784 13 : if ((NumNums < 30) && (tower.NumCell == 0)) {
785 : // assume Number of Cells not entered and should be defaulted
786 0 : tower.NumCell = 1;
787 : }
788 13 : tower.MinFracFlowRate = NumArray(31);
789 13 : if ((NumNums < 31) && (tower.MinFracFlowRate == 0.0)) {
790 : // assume Cell Minimum Water Flow Rate Fraction not entered and should be defaulted
791 0 : tower.MinFracFlowRate = 0.33;
792 : }
793 13 : tower.MaxFracFlowRate = NumArray(32);
794 13 : if ((NumNums < 32) && (tower.MaxFracFlowRate == 0.0)) {
795 : // assume Cell Maximum Water Flow Rate Fraction not entered and should be defaulted
796 0 : tower.MaxFracFlowRate = 2.5;
797 : }
798 :
799 : // cell control for two speed tower
800 13 : if (!state.dataIPShortCut->lAlphaFieldBlanks(11)) {
801 3 : tower.cellCtrl = static_cast<CellCtrl>(getEnumValue(CellCtrlNamesUC, Util::makeUPPER(AlphArray(11))));
802 : }
803 :
804 13 : if (state.dataIPShortCut->lAlphaFieldBlanks(9)) {
805 13 : tower.SuppliedByWaterSystem = false;
806 : } else { // water from storage tank
807 0 : WaterManager::SetupTankDemandComponent(
808 0 : state, AlphArray(1), cCurrentModuleObject, AlphArray(9), ErrorsFound, tower.WaterTankID, tower.WaterTankDemandARRID);
809 0 : tower.SuppliedByWaterSystem = true;
810 : }
811 :
812 : // outdoor air inlet node
813 13 : if (state.dataIPShortCut->lAlphaFieldBlanks(10)) {
814 7 : tower.OutdoorAirInletNodeNum = 0;
815 : } else {
816 6 : tower.OutdoorAirInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
817 6 : AlphArray(10),
818 : ErrorsFound,
819 : DataLoopNode::ConnectionObjectType::CoolingTowerTwoSpeed,
820 6 : tower.Name,
821 : DataLoopNode::NodeFluidType::Air,
822 : DataLoopNode::ConnectionType::OutsideAirReference,
823 : NodeInputManager::CompFluidStream::Primary,
824 : DataLoopNode::ObjectIsNotParent);
825 6 : if (!OutAirNodeManager::CheckOutAirNodeNumber(state, tower.OutdoorAirInletNodeNum)) {
826 0 : ShowSevereError(state,
827 0 : format("{}, \"{}\" Outdoor Air Inlet Node Name not valid Outdoor Air Node= {}",
828 : cCurrentModuleObject,
829 0 : tower.Name,
830 : AlphArray(10)));
831 0 : ShowContinueError(state, "...does not appear in an OutdoorAir:NodeList or as an OutdoorAir:Node.");
832 0 : ErrorsFound = true;
833 : }
834 : }
835 :
836 : // High speed air flow rate must be greater than low speed air flow rate.
837 : // Can't tell yet if autosized, check later in initialize.
838 13 : if (tower.HighSpeedAirFlowRate <= tower.LowSpeedAirFlowRate && tower.HighSpeedAirFlowRate != DataSizing::AutoSize) {
839 0 : ShowSevereError(
840 : state,
841 0 : format("{} \"{}\". Low speed air flow rate must be less than the high speed air flow rate.", cCurrentModuleObject, tower.Name));
842 0 : ErrorsFound = true;
843 : }
844 : // Low speed air flow rate must be greater than free convection air flow rate.
845 : // Can't tell yet if autosized, check later in initialize.
846 13 : if (tower.LowSpeedAirFlowRate <= tower.FreeConvAirFlowRate && tower.LowSpeedAirFlowRate != DataSizing::AutoSize) {
847 0 : ShowSevereError(state,
848 0 : format("{} \"{}\". Free convection air flow rate must be less than the low speed air flow rate.",
849 : cCurrentModuleObject,
850 0 : tower.Name));
851 0 : ErrorsFound = true;
852 : }
853 :
854 : // Check various inputs if Performance Input Method = "UA and Design Water Flow Rate"
855 13 : if (tower.PerformanceInputMethod_Num == PIM::UFactor) {
856 8 : if (tower.DesignWaterFlowRate == 0.0) {
857 0 : ShowSevereError(state,
858 0 : format("{} \"{}\". Tower performance input method requires a design water flow rate greater than zero.",
859 : cCurrentModuleObject,
860 0 : tower.Name));
861 0 : ErrorsFound = true;
862 : }
863 8 : if (tower.HighSpeedTowerUA <= tower.LowSpeedTowerUA && tower.HighSpeedTowerUA != DataSizing::AutoSize) {
864 0 : ShowSevereError(state,
865 0 : format("{} \"{}\". Tower UA at low fan speed must be less than the tower UA at high fan speed.",
866 : cCurrentModuleObject,
867 0 : tower.Name));
868 0 : ErrorsFound = true;
869 : }
870 8 : if (tower.LowSpeedTowerUA <= tower.FreeConvTowerUA && tower.LowSpeedTowerUA != DataSizing::AutoSize) {
871 0 : ShowSevereError(state,
872 0 : format("{} \"{}\". Tower UA at free convection air flow rate must be less than the tower UA at low fan speed.",
873 : cCurrentModuleObject,
874 0 : tower.Name));
875 0 : ErrorsFound = true;
876 : }
877 8 : if (tower.FreeConvTowerUA > 0.0 && tower.FreeConvAirFlowRate == 0.0) {
878 0 : ShowSevereError(
879 : state,
880 0 : format("{} \"{}\". Free convection air flow rate must be greater than zero when free convection UA is greater than zero.",
881 : cCurrentModuleObject,
882 0 : tower.Name));
883 0 : ErrorsFound = true;
884 : }
885 5 : } else if (tower.PerformanceInputMethod_Num == PIM::NominalCapacity) {
886 5 : if (tower.TowerNominalCapacity == 0.0) {
887 0 : ShowSevereError(state,
888 0 : format("{} \"{}\". Tower performance input method requires valid high-speed nominal capacity.",
889 : cCurrentModuleObject,
890 0 : tower.Name));
891 0 : ErrorsFound = true;
892 : }
893 5 : if (tower.TowerLowSpeedNomCap == 0.0) {
894 0 : ShowSevereError(state,
895 0 : format("{} \"{}\". Tower performance input method requires valid low-speed nominal capacity.",
896 : cCurrentModuleObject,
897 0 : tower.Name));
898 0 : ErrorsFound = true;
899 : }
900 5 : if (tower.DesignWaterFlowRate != 0.0) {
901 0 : if (tower.DesignWaterFlowRate > 0.0) {
902 0 : ShowWarningError(state,
903 0 : format("{} \"{}\". Nominal capacity input method and design water flow rate have been specified.",
904 : cCurrentModuleObject,
905 0 : tower.Name));
906 : } else {
907 0 : ShowSevereError(
908 : state,
909 0 : format("{} \"{}\". Nominal capacity input method has been specified and design water flow rate is being autosized.",
910 : cCurrentModuleObject,
911 0 : tower.Name));
912 : }
913 0 : ShowContinueError(state, "Design water flow rate will be set according to nominal tower capacity.");
914 : }
915 5 : if (tower.HighSpeedTowerUA != 0.0) {
916 0 : if (tower.HighSpeedTowerUA > 0.0) {
917 0 : ShowWarningError(state,
918 0 : format("{} \"{}\". Nominal capacity input method and tower UA at high fan speed have been specified.",
919 : cCurrentModuleObject,
920 0 : tower.Name));
921 : } else {
922 0 : ShowSevereError(
923 : state,
924 0 : format("{} \"{}\". Nominal capacity input method has been specified and tower UA at high fan speed is being autosized.",
925 : cCurrentModuleObject,
926 0 : tower.Name));
927 : }
928 0 : ShowContinueError(state, "Tower UA at high fan speed will be set according to nominal tower capacity.");
929 : }
930 5 : if (tower.LowSpeedTowerUA != 0.0) {
931 0 : if (tower.LowSpeedTowerUA > 0.0) {
932 0 : ShowWarningError(state,
933 0 : format("{} \"{}\". Nominal capacity input method and tower UA at low fan speed have been specified.",
934 : cCurrentModuleObject,
935 0 : tower.Name));
936 : } else {
937 0 : ShowSevereError(
938 : state,
939 0 : format("{} \"{}\". Nominal capacity input method has been specified and tower UA at low fan speed is being autosized.",
940 : cCurrentModuleObject,
941 0 : tower.Name));
942 : }
943 0 : ShowContinueError(state, "Tower UA at low fan speed will be set according to nominal tower capacity.");
944 : }
945 5 : if (tower.FreeConvTowerUA != 0.0) {
946 0 : if (tower.FreeConvTowerUA > 0.0) {
947 0 : ShowWarningError(state,
948 0 : format("{} \"{}\". Nominal capacity input method and free convection UA have been specified.",
949 : cCurrentModuleObject,
950 0 : tower.Name));
951 : } else {
952 0 : ShowSevereError(
953 : state,
954 0 : format("{} \"{}\". Nominal capacity input method has been specified and free convection UA is being autosized.",
955 : cCurrentModuleObject,
956 0 : tower.Name));
957 : }
958 0 : ShowContinueError(state, "Free convection UA will be set according to nominal tower capacity.");
959 : }
960 5 : if (tower.TowerLowSpeedNomCap >= tower.TowerNominalCapacity) {
961 0 : ShowSevereError(state,
962 0 : format("{} \"{}\". Low-speed nominal capacity must be less than the high-speed nominal capacity.",
963 : cCurrentModuleObject,
964 0 : tower.Name));
965 0 : ErrorsFound = true;
966 : }
967 5 : if (!tower.TowerLowSpeedNomCapWasAutoSized) {
968 5 : if (tower.TowerFreeConvNomCap >= tower.TowerLowSpeedNomCap) {
969 0 : ShowSevereError(state,
970 0 : format("{} \"{}\". Free convection nominal capacity must be less than the low-speed nominal capacity.",
971 : cCurrentModuleObject,
972 0 : tower.Name));
973 0 : ErrorsFound = true;
974 : }
975 : }
976 5 : if (tower.TowerFreeConvNomCap > 0.0 && tower.FreeConvAirFlowRate == 0.0) {
977 0 : ShowSevereError(
978 : state,
979 0 : format("{} \"{}\". Free convection air flow must be greater than zero when tower free convection capacity is specified.",
980 : cCurrentModuleObject,
981 0 : tower.Name));
982 0 : ErrorsFound = true;
983 : }
984 : } else { // Tower performance input method is not specified as a valid "choice"
985 0 : ShowSevereError(
986 : state,
987 0 : format("{} \"{}{}",
988 : cCurrentModuleObject,
989 0 : tower.Name,
990 : R"(". Tower Performance Input Method must be "UFactorTimesAreaAndDesignWaterFlowRate" or "NominalCapacity".)"));
991 0 : ShowContinueError(state, format("Tower Performanace Input Method currently specified as: {}", AlphArray(4)));
992 0 : ErrorsFound = true;
993 : }
994 13 : if (NumAlphas > 11) {
995 2 : tower.EndUseSubcategory = AlphArray(12);
996 : } else {
997 11 : tower.EndUseSubcategory = "General";
998 : }
999 : } // End Two-Speed Tower Loop
1000 :
1001 244 : cCurrentModuleObject = cCoolingTower_VariableSpeed;
1002 268 : for (int VariableSpeedTowerNumber = 1; VariableSpeedTowerNumber <= NumVariableSpeedTowers; ++VariableSpeedTowerNumber) {
1003 24 : TowerNum = NumSingleSpeedTowers + NumTwoSpeedTowers + VariableSpeedTowerNumber;
1004 48 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1005 : cCurrentModuleObject,
1006 : VariableSpeedTowerNumber,
1007 : AlphArray,
1008 : NumAlphas,
1009 : NumArray,
1010 : NumNums,
1011 : IOStat,
1012 : _,
1013 24 : state.dataIPShortCut->lAlphaFieldBlanks,
1014 24 : state.dataIPShortCut->cAlphaFieldNames,
1015 24 : state.dataIPShortCut->cNumericFieldNames);
1016 24 : GlobalNames::VerifyUniqueInterObjectName(
1017 48 : state, UniqueSimpleTowerNames, AlphArray(1), cCurrentModuleObject, state.dataIPShortCut->cAlphaFieldNames(1), ErrorsFound);
1018 :
1019 24 : auto &tower = state.dataCondenserLoopTowers->towers(TowerNum);
1020 24 : tower.VSTower = VariableSpeedTowerNumber;
1021 24 : tower.Name = AlphArray(1);
1022 24 : tower.TowerType = DataPlant::PlantEquipmentType::CoolingTower_VarSpd;
1023 24 : tower.WaterInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
1024 24 : AlphArray(2),
1025 : ErrorsFound,
1026 : DataLoopNode::ConnectionObjectType::CoolingTowerVariableSpeed,
1027 24 : AlphArray(1),
1028 : DataLoopNode::NodeFluidType::Water,
1029 : DataLoopNode::ConnectionType::Inlet,
1030 : NodeInputManager::CompFluidStream::Primary,
1031 : DataLoopNode::ObjectIsNotParent);
1032 24 : tower.WaterOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
1033 24 : AlphArray(3),
1034 : ErrorsFound,
1035 : DataLoopNode::ConnectionObjectType::CoolingTowerVariableSpeed,
1036 24 : AlphArray(1),
1037 : DataLoopNode::NodeFluidType::Water,
1038 : DataLoopNode::ConnectionType::Outlet,
1039 : NodeInputManager::CompFluidStream::Primary,
1040 : DataLoopNode::ObjectIsNotParent);
1041 24 : BranchNodeConnections::TestCompSet(state, cCurrentModuleObject, AlphArray(1), AlphArray(2), AlphArray(3), "Chilled Water Nodes");
1042 :
1043 36 : if ((Util::SameString(AlphArray(4), "CoolToolsUserDefined") || Util::SameString(AlphArray(4), "YorkCalcUserDefined")) &&
1044 12 : state.dataIPShortCut->lAlphaFieldBlanks(5)) {
1045 0 : ShowSevereError(state,
1046 0 : format("{}, \"{}\" a {} must be specified when {} is specified as CoolToolsUserDefined or YorkCalcUserDefined",
1047 : cCurrentModuleObject,
1048 0 : tower.Name,
1049 0 : state.dataIPShortCut->cAlphaFieldNames(5),
1050 0 : state.dataIPShortCut->cAlphaFieldNames(4)));
1051 0 : ErrorsFound = true;
1052 36 : } else if ((Util::SameString(AlphArray(4), "CoolToolsCrossFlow") || Util::SameString(AlphArray(4), "YorkCalc")) &&
1053 12 : !state.dataIPShortCut->lAlphaFieldBlanks(5)) {
1054 0 : ShowWarningError(state,
1055 0 : format("{}, \"{}\" a Tower Model Coefficient Name is specified and the Tower Model Type is not specified as "
1056 : "CoolToolsUserDefined or YorkCalcUserDefined. The CoolingTowerPerformance:CoolTools "
1057 : "(orCoolingTowerPerformance:YorkCalc) data object will not be used.",
1058 : cCurrentModuleObject,
1059 0 : tower.Name));
1060 : } else {
1061 24 : tower.ModelCoeffObjectName = AlphArray(5);
1062 : }
1063 :
1064 24 : if (!state.dataIPShortCut->lAlphaFieldBlanks(6)) {
1065 23 : tower.FanPowerfAirFlowCurve = Curve::GetCurveIndex(state, AlphArray(6));
1066 23 : if (tower.FanPowerfAirFlowCurve == 0) {
1067 0 : ShowWarningError(
1068 : state,
1069 0 : format(
1070 : "{}, \"{}\" the Fan Power Ratio as a function of Air Flow Rate Ratio Curve Name specified as {} was not found. Fan Power "
1071 : "as a function of Air Flow Rate Ratio will default to Fan Power = (Air Flow Rate Ratio)^3 and the simulation continues.",
1072 : cCurrentModuleObject,
1073 0 : tower.Name,
1074 : AlphArray(6)));
1075 : }
1076 : }
1077 :
1078 24 : auto &vstower = state.dataCondenserLoopTowers->towers(tower.VSTower);
1079 :
1080 24 : if (Util::SameString(AlphArray(4), "CoolToolsCrossFlow")) {
1081 10 : tower.TowerModelType = ModelType::CoolToolsXFModel;
1082 : // set cross-flow model coefficients
1083 : // Outputs approach in C
1084 10 : vstower.Coeff[0] = 0.52049709836241;
1085 10 : vstower.Coeff[1] = -10.617046395344;
1086 10 : vstower.Coeff[2] = 10.7292974722538;
1087 10 : vstower.Coeff[3] = -2.74988377158227;
1088 10 : vstower.Coeff[4] = 4.73629943913743;
1089 10 : vstower.Coeff[5] = -8.25759700874711;
1090 10 : vstower.Coeff[6] = 1.57640938114136;
1091 10 : vstower.Coeff[7] = 6.51119643791324;
1092 10 : vstower.Coeff[8] = 1.50433525206692;
1093 10 : vstower.Coeff[9] = -3.2888529287801;
1094 10 : vstower.Coeff[10] = 0.0257786145353773;
1095 10 : vstower.Coeff[11] = 0.182464289315254;
1096 10 : vstower.Coeff[12] = -0.0818947291400898;
1097 10 : vstower.Coeff[13] = -0.215010003996285;
1098 10 : vstower.Coeff[14] = 0.0186741309635284;
1099 10 : vstower.Coeff[15] = 0.0536824177590012;
1100 10 : vstower.Coeff[16] = -0.00270968955115031;
1101 10 : vstower.Coeff[17] = 0.00112277498589279;
1102 10 : vstower.Coeff[18] = -0.00127758497497718;
1103 10 : vstower.Coeff[19] = 0.0000760420796601607;
1104 10 : vstower.Coeff[20] = 1.43600088336017;
1105 10 : vstower.Coeff[21] = -0.5198695909109;
1106 10 : vstower.Coeff[22] = 0.117339576910507;
1107 10 : vstower.Coeff[23] = 1.50492810819924;
1108 10 : vstower.Coeff[24] = -0.135898905926974;
1109 10 : vstower.Coeff[25] = -0.152577581866506;
1110 10 : vstower.Coeff[26] = -0.0533843828114562;
1111 10 : vstower.Coeff[27] = 0.00493294869565511;
1112 10 : vstower.Coeff[28] = -0.00796260394174197;
1113 10 : vstower.Coeff[29] = 0.000222619828621544;
1114 10 : vstower.Coeff[30] = -0.0543952001568055;
1115 10 : vstower.Coeff[31] = 0.00474266879161693;
1116 10 : vstower.Coeff[32] = -0.0185854671815598;
1117 10 : vstower.Coeff[33] = 0.00115667701293848;
1118 10 : vstower.Coeff[34] = 0.000807370664460284;
1119 :
1120 : // set minimum and maximum boundaries for CoolTools crossflow model input variables
1121 10 : vstower.MinInletAirWBTemp = -1.0;
1122 10 : vstower.MaxInletAirWBTemp = 26.6667;
1123 10 : vstower.MinRangeTemp = 1.1111;
1124 10 : vstower.MaxRangeTemp = 11.1111;
1125 10 : vstower.MinApproachTemp = 1.1111;
1126 10 : vstower.MaxApproachTemp = 11.1111;
1127 10 : vstower.MinWaterFlowRatio = 0.75;
1128 10 : vstower.MaxWaterFlowRatio = 1.25;
1129 :
1130 14 : } else if (Util::SameString(AlphArray(4), "YorkCalc")) {
1131 2 : tower.TowerModelType = ModelType::YorkCalcModel;
1132 : // set counter-flow model coefficients
1133 : // Outputs approach in C
1134 2 : vstower.Coeff[0] = -0.359741205;
1135 2 : vstower.Coeff[1] = -0.055053608;
1136 2 : vstower.Coeff[2] = 0.0023850432;
1137 2 : vstower.Coeff[3] = 0.173926877;
1138 2 : vstower.Coeff[4] = -0.0248473764;
1139 2 : vstower.Coeff[5] = 0.00048430224;
1140 2 : vstower.Coeff[6] = -0.005589849456;
1141 2 : vstower.Coeff[7] = 0.0005770079712;
1142 2 : vstower.Coeff[8] = -0.00001342427256;
1143 2 : vstower.Coeff[9] = 2.84765801111111;
1144 2 : vstower.Coeff[10] = -0.121765149;
1145 2 : vstower.Coeff[11] = 0.0014599242;
1146 2 : vstower.Coeff[12] = 1.680428651;
1147 2 : vstower.Coeff[13] = -0.0166920786;
1148 2 : vstower.Coeff[14] = -0.0007190532;
1149 2 : vstower.Coeff[15] = -0.025485194448;
1150 2 : vstower.Coeff[16] = 0.0000487491696;
1151 2 : vstower.Coeff[17] = 0.00002719234152;
1152 2 : vstower.Coeff[18] = -0.0653766255555556;
1153 2 : vstower.Coeff[19] = -0.002278167;
1154 2 : vstower.Coeff[20] = 0.0002500254;
1155 2 : vstower.Coeff[21] = -0.0910565458;
1156 2 : vstower.Coeff[22] = 0.00318176316;
1157 2 : vstower.Coeff[23] = 0.000038621772;
1158 2 : vstower.Coeff[24] = -0.0034285382352;
1159 2 : vstower.Coeff[25] = 0.00000856589904;
1160 2 : vstower.Coeff[26] = -0.000001516821552;
1161 :
1162 : // set minimum and maximum boundaries for YorkCalc model input variables
1163 2 : vstower.MinInletAirWBTemp = -34.4;
1164 2 : vstower.MaxInletAirWBTemp = 29.4444;
1165 2 : vstower.MinRangeTemp = 1.1111;
1166 2 : vstower.MaxRangeTemp = 22.2222;
1167 2 : vstower.MinApproachTemp = 1.1111;
1168 2 : vstower.MaxApproachTemp = 40.0;
1169 2 : vstower.MinWaterFlowRatio = 0.75;
1170 2 : vstower.MaxWaterFlowRatio = 1.25;
1171 2 : vstower.MaxLiquidToGasRatio = 8.0;
1172 :
1173 12 : } else if (Util::SameString(AlphArray(4), "CoolToolsUserDefined")) {
1174 1 : tower.TowerModelType = ModelType::CoolToolsUserDefined;
1175 : // Nested Get-input routines below. Should pull out of here and read in beforehand.
1176 1 : for (VSModelCoeffNum = 1; VSModelCoeffNum <= NumVSCoolToolsModelCoeffs; ++VSModelCoeffNum) {
1177 1 : state.dataInputProcessing->inputProcessor->getObjectItem(
1178 : state, "CoolingTowerPerformance:CoolTools", VSModelCoeffNum, AlphArray2, NumAlphas2, NumArray2, NumNums2, IOStat);
1179 1 : if (!Util::SameString(AlphArray2(1), tower.ModelCoeffObjectName)) continue;
1180 1 : vstower.FoundModelCoeff = true;
1181 : // verify the correct number of coefficients for the CoolTools model
1182 1 : if (NumNums2 != 43) {
1183 0 : ShowSevereError(state,
1184 0 : format("CoolingTower:VariableSpeed \"{}\". The number of numeric inputs for object "
1185 : "CoolingTowerPerformance:CoolTools \"{}\" must equal 43.",
1186 0 : tower.Name,
1187 0 : tower.ModelCoeffObjectName));
1188 0 : ErrorsFound = true;
1189 : } else {
1190 :
1191 1 : vstower.MinInletAirWBTemp = NumArray2(1);
1192 1 : vstower.MaxInletAirWBTemp = NumArray2(2);
1193 1 : vstower.MinRangeTemp = NumArray2(3);
1194 1 : vstower.MaxRangeTemp = NumArray2(4);
1195 1 : vstower.MinApproachTemp = NumArray2(5);
1196 1 : vstower.MaxApproachTemp = NumArray2(6);
1197 1 : vstower.MinWaterFlowRatio = NumArray2(7);
1198 1 : vstower.MaxWaterFlowRatio = NumArray2(8);
1199 :
1200 36 : for (CoeffNum = 9; CoeffNum <= NumNums2; ++CoeffNum) {
1201 35 : vstower.Coeff[CoeffNum - 9] = NumArray2(CoeffNum);
1202 : }
1203 : }
1204 1 : break;
1205 : }
1206 1 : if (!vstower.FoundModelCoeff) {
1207 0 : ShowSevereError(state,
1208 0 : format("CoolingTower:VariableSpeed \"{}\". User defined name for variable speed cooling tower model coefficients "
1209 : "object not found = {}",
1210 0 : tower.Name,
1211 0 : tower.ModelCoeffObjectName));
1212 0 : ErrorsFound = true;
1213 : }
1214 11 : } else if (Util::SameString(AlphArray(4), "YorkCalcUserDefined")) {
1215 11 : tower.TowerModelType = ModelType::YorkCalcUserDefined;
1216 : // Nested Get-input routines below. Should pull out of here and read in beforehand.
1217 11 : for (VSModelCoeffNum = 1; VSModelCoeffNum <= NumVSYorkCalcModelCoeffs; ++VSModelCoeffNum) {
1218 11 : state.dataInputProcessing->inputProcessor->getObjectItem(
1219 : state, "CoolingTowerPerformance:YorkCalc", VSModelCoeffNum, AlphArray2, NumAlphas2, NumArray2, NumNums2, IOStat);
1220 11 : if (!Util::SameString(AlphArray2(1), tower.ModelCoeffObjectName)) continue;
1221 11 : vstower.FoundModelCoeff = true;
1222 : // verify the correct number of coefficients for the YorkCalc model
1223 11 : if (NumNums2 != 36) {
1224 0 : ShowSevereError(state,
1225 0 : format("CoolingTower:VariableSpeed \"{}\". The number of numeric inputs for object "
1226 : "CoolingTowerPerformance:YorkCalc \"{}\" must equal 36.",
1227 0 : tower.Name,
1228 0 : tower.ModelCoeffObjectName));
1229 0 : ErrorsFound = true;
1230 : } else {
1231 :
1232 11 : vstower.MinInletAirWBTemp = NumArray2(1);
1233 11 : vstower.MaxInletAirWBTemp = NumArray2(2);
1234 11 : vstower.MinRangeTemp = NumArray2(3);
1235 11 : vstower.MaxRangeTemp = NumArray2(4);
1236 11 : vstower.MinApproachTemp = NumArray2(5);
1237 11 : vstower.MaxApproachTemp = NumArray2(6);
1238 11 : vstower.MinWaterFlowRatio = NumArray2(7);
1239 11 : vstower.MaxWaterFlowRatio = NumArray2(8);
1240 11 : vstower.MaxLiquidToGasRatio = NumArray2(9);
1241 :
1242 308 : for (CoeffNum = 10; CoeffNum <= NumNums2; ++CoeffNum) {
1243 297 : vstower.Coeff[CoeffNum - 10] = NumArray2(CoeffNum);
1244 : }
1245 : }
1246 11 : break;
1247 : }
1248 :
1249 11 : if (!vstower.FoundModelCoeff) {
1250 0 : ShowSevereError(state,
1251 0 : format("{} \"{}\". User defined name for variable speed cooling tower model coefficients object not found = {}",
1252 : cCurrentModuleObject,
1253 0 : tower.Name,
1254 0 : tower.ModelCoeffObjectName));
1255 0 : ErrorsFound = true;
1256 : }
1257 : } else {
1258 0 : ShowSevereError(state, format("{} \"{}\". Illegal Tower Model Type = {}", cCurrentModuleObject, tower.Name, AlphArray(5)));
1259 0 : ShowContinueError(state,
1260 : R"( Tower Model Type must be "CoolToolsCrossFlow", "YorkCalc", "CoolToolsUserDefined", or "YorkCalcUserDefined.)");
1261 0 : ErrorsFound = true;
1262 : }
1263 :
1264 24 : tower.TowerMassFlowRateMultiplier = vstower.MaxWaterFlowRatio;
1265 :
1266 : // check user defined minimums to be greater than 0
1267 24 : if (vstower.MinApproachTemp < 0.0) {
1268 0 : ShowSevereError(state, format("{} \"{}\". User defined minimum approach temperature must be > 0", cCurrentModuleObject, tower.Name));
1269 0 : ErrorsFound = true;
1270 : }
1271 24 : if (vstower.MinRangeTemp < 0.0) {
1272 0 : ShowSevereError(state, format("{} \"{}\". User defined minimum range temperature must be > 0", cCurrentModuleObject, tower.Name));
1273 0 : ErrorsFound = true;
1274 : }
1275 24 : if (vstower.MinWaterFlowRatio < 0.0) {
1276 0 : ShowSevereError(state, format("{} \"{}\". User defined minimum water flow rate ratio must be > 0", cCurrentModuleObject, tower.Name));
1277 0 : ErrorsFound = true;
1278 : }
1279 :
1280 : // check that the user defined maximums are greater than the minimums
1281 24 : if (vstower.MaxApproachTemp < vstower.MinApproachTemp) {
1282 0 : ShowSevereError(state,
1283 0 : format("{} \"{}\". User defined maximum approach temperature must be > the minimum approach temperature",
1284 : cCurrentModuleObject,
1285 0 : tower.Name));
1286 0 : ErrorsFound = true;
1287 : }
1288 24 : if (vstower.MaxRangeTemp < vstower.MinRangeTemp) {
1289 0 : ShowSevereError(state,
1290 0 : format("{} \"{}\". User defined maximum range temperature must be > the minimum range temperature",
1291 : cCurrentModuleObject,
1292 0 : tower.Name));
1293 0 : ErrorsFound = true;
1294 : }
1295 24 : if (vstower.MaxWaterFlowRatio < vstower.MinWaterFlowRatio) {
1296 0 : ShowSevereError(state,
1297 0 : format("{} \"{}\". User defined maximum water flow rate ratio must be > the minimum water flow rate ratio",
1298 : cCurrentModuleObject,
1299 0 : tower.Name));
1300 0 : ErrorsFound = true;
1301 : }
1302 :
1303 24 : tower.DesignInletWB = NumArray(1);
1304 24 : if (NumArray(1) < vstower.MinInletAirWBTemp || NumArray(1) > vstower.MaxInletAirWBTemp) {
1305 0 : ShowSevereError(state,
1306 0 : cCurrentModuleObject.append(", \"")
1307 0 : .append(tower.Name)
1308 0 : .append("\" the design inlet air wet-bulb temperature of ")
1309 0 : .append(format(OutputFormat, tower.DesignInletWB))
1310 0 : .append(" must be within the model limits of ")
1311 0 : .append(format(OutputFormat, vstower.MinInletAirWBTemp))
1312 0 : .append(" and ")
1313 0 : .append(format(OutputFormat, vstower.MaxInletAirWBTemp))
1314 0 : .append(" degrees C"));
1315 0 : ErrorsFound = true;
1316 : }
1317 :
1318 24 : tower.DesignApproach = NumArray(2);
1319 24 : if (NumArray(2) < vstower.MinApproachTemp || NumArray(2) > vstower.MaxApproachTemp) {
1320 0 : ShowSevereError(state,
1321 0 : cCurrentModuleObject.append(", \"")
1322 0 : .append(tower.Name)
1323 0 : .append("\" the design approach temperature of ")
1324 0 : .append(format(OutputFormat, tower.DesignApproach))
1325 0 : .append(" must be within the model limits of ")
1326 0 : .append(format(OutputFormat, vstower.MinApproachTemp))
1327 0 : .append(" and ")
1328 0 : .append(format(OutputFormat, vstower.MaxApproachTemp))
1329 0 : .append(" degrees C"));
1330 0 : ErrorsFound = true;
1331 : }
1332 :
1333 24 : tower.DesignRange = NumArray(3);
1334 24 : if (NumArray(3) < vstower.MinRangeTemp || NumArray(3) > vstower.MaxRangeTemp) {
1335 0 : ShowSevereError(state,
1336 0 : cCurrentModuleObject.append(", \"")
1337 0 : .append(tower.Name)
1338 0 : .append("\" the design range temperature of ")
1339 0 : .append(format(OutputFormat, tower.DesignRange))
1340 0 : .append(" must be within the model limits of ")
1341 0 : .append(format(OutputFormat, vstower.MinRangeTemp))
1342 0 : .append(" and ")
1343 0 : .append(format(OutputFormat, vstower.MaxRangeTemp))
1344 0 : .append(" degrees C"));
1345 0 : ErrorsFound = true;
1346 : }
1347 :
1348 24 : tower.DesignWaterFlowRate = NumArray(4);
1349 24 : if (tower.DesignWaterFlowRate == DataSizing::AutoSize) {
1350 13 : tower.DesignWaterFlowRateWasAutoSized = true;
1351 : }
1352 24 : if (NumArray(4) <= 0.0 && NumArray(4) != DataSizing::AutoSize) {
1353 0 : ShowSevereError(state, format("{}, \"{}\" design water flow rate must be > 0", cCurrentModuleObject, tower.Name));
1354 0 : ErrorsFound = true;
1355 : }
1356 :
1357 24 : tower.HighSpeedAirFlowRate = NumArray(5);
1358 24 : if (tower.HighSpeedAirFlowRate == DataSizing::AutoSize) {
1359 24 : tower.HighSpeedAirFlowRateWasAutoSized = true;
1360 : }
1361 24 : if (NumArray(5) <= 0.0 && NumArray(5) != DataSizing::AutoSize) {
1362 0 : ShowSevereError(state, format("{}, \"{}\" design air flow rate must be > 0", cCurrentModuleObject, tower.Name));
1363 0 : ErrorsFound = true;
1364 : }
1365 :
1366 24 : tower.HighSpeedFanPower = NumArray(6);
1367 24 : if (tower.HighSpeedFanPower == DataSizing::AutoSize) {
1368 13 : tower.HighSpeedFanPowerWasAutoSized = true;
1369 : }
1370 24 : if (NumArray(6) <= 0.0 && NumArray(6) != DataSizing::AutoSize) {
1371 0 : ShowSevereError(state, format("{}, \"{}\" design fan power must be > 0", cCurrentModuleObject, tower.Name));
1372 0 : ErrorsFound = true;
1373 : }
1374 :
1375 : // minimum air flow rate fraction must be >= 0.2 and <= 0.5, below this value the tower fan cycles to maintain the setpoint
1376 24 : tower.MinimumVSAirFlowFrac = NumArray(7);
1377 24 : tower.MinimumVSAirFlowFrac = NumArray(7);
1378 24 : if (NumArray(7) < 0.2 || NumArray(7) > 0.5) {
1379 0 : ShowSevereError(state,
1380 0 : format("{}, \"{}\" minimum VS air flow rate ratio must be >= 0.2 and <= 0.5", cCurrentModuleObject, tower.Name));
1381 0 : ErrorsFound = true;
1382 : }
1383 :
1384 : // fraction of tower capacity in free convection regime must be >= to 0 and <= 0.2
1385 24 : tower.FreeConvectionCapacityFraction = NumArray(8);
1386 24 : if (NumArray(8) < 0.0 || NumArray(8) > 0.2) {
1387 0 : ShowSevereError(state,
1388 0 : format("{}, \"{}\" fraction of tower capacity in free convection regime must be >= 0 and <= 0.2",
1389 : cCurrentModuleObject,
1390 0 : tower.Name));
1391 0 : ErrorsFound = true;
1392 : }
1393 :
1394 : // Basin heater power as a function of temperature must be greater than or equal to 0
1395 24 : tower.BasinHeaterPowerFTempDiff = NumArray(9);
1396 24 : if (NumArray(9) < 0.0) {
1397 0 : ShowSevereError(
1398 : state,
1399 0 : format("{}, \"{}\" basin heater power as a function of temperature difference must be >= 0", cCurrentModuleObject, tower.Name));
1400 0 : ErrorsFound = true;
1401 : }
1402 :
1403 24 : tower.BasinHeaterSetPointTemp = NumArray(10);
1404 24 : if (tower.BasinHeaterPowerFTempDiff > 0.0) {
1405 12 : if (NumNums < 10) {
1406 0 : tower.BasinHeaterSetPointTemp = 2.0;
1407 : }
1408 12 : if (tower.BasinHeaterSetPointTemp < 2.0) {
1409 0 : ShowWarningError(state,
1410 0 : format("{}:\"{}\", {} is less than 2 deg C. Freezing could occur.",
1411 : cCurrentModuleObject,
1412 0 : tower.Name,
1413 0 : state.dataIPShortCut->cNumericFieldNames(10)));
1414 : }
1415 : }
1416 :
1417 : // Performance Input Method for Variable Speed Towers is assigned to be UA AND DESIGN WATER FLOW RATE
1418 : // for autosizing calculations (see SizeTower)
1419 24 : tower.PerformanceInputMethod_Num = PIM::UFactor;
1420 :
1421 24 : if (!AlphArray(7).empty()) {
1422 0 : tower.BasinHeaterSchedulePtr = ScheduleManager::GetScheduleIndex(state, AlphArray(7));
1423 0 : if (tower.BasinHeaterSchedulePtr == 0) {
1424 0 : ShowWarningError(state,
1425 0 : format("{}, \"{}\" basin heater schedule name \"{}\" was not found. Basin heater operation will not be modeled "
1426 : "and the simulation continues",
1427 : cCurrentModuleObject,
1428 0 : tower.Name,
1429 : AlphArray(7)));
1430 : }
1431 : }
1432 :
1433 : // begin water use and systems get input
1434 24 : tower.EvapLossMode = static_cast<EvapLoss>(getEnumValue(EvapLossNamesUC, Util::makeUPPER(AlphArray(8))));
1435 24 : tower.UserEvapLossFactor = NumArray(11); // N11 , \field Evaporation Loss Factor
1436 24 : tower.DriftLossFraction = NumArray(12) / 100.0; // N12, \field Drift Loss Percent
1437 24 : tower.ConcentrationRatio = NumArray(13); // N13, \field Blowdown Concentration Ratio
1438 24 : tower.SizFac = NumArray(17); // N14 \field Sizing Factor
1439 24 : if (tower.SizFac <= 0.0) tower.SizFac = 1.0;
1440 :
1441 24 : tower.BlowdownMode = static_cast<Blowdown>(getEnumValue(BlowDownNamesUC, Util::makeUPPER(AlphArray(9))));
1442 24 : tower.SchedIDBlowdown = ScheduleManager::GetScheduleIndex(state, AlphArray(10));
1443 24 : if ((tower.SchedIDBlowdown == 0) && (tower.BlowdownMode == Blowdown::Schedule)) {
1444 0 : ShowSevereError(state, format("Invalid, {} = \"{}\"", state.dataIPShortCut->cAlphaFieldNames(10), AlphArray(10)));
1445 0 : ShowContinueError(state, format("Entered in {} = \"{}\"", cCoolingTower_VariableSpeed, tower.Name));
1446 0 : ErrorsFound = true;
1447 : }
1448 :
1449 : // added for multi-cell
1450 24 : tower.NumCell = NumArray(14);
1451 24 : if ((NumNums < 14) && (tower.NumCell == 0)) {
1452 : // assume Number of Cells not entered and should be defaulted
1453 0 : tower.NumCell = 1;
1454 : }
1455 24 : tower.MinFracFlowRate = NumArray(15);
1456 24 : if ((NumNums < 15) && (tower.MinFracFlowRate == 0.0)) {
1457 : // assume Cell Minimum Water Flow Rate Fraction not entered and should be defaulted
1458 0 : tower.MinFracFlowRate = 0.33;
1459 : }
1460 24 : tower.MaxFracFlowRate = NumArray(16);
1461 24 : if ((NumNums < 16) && (tower.MaxFracFlowRate == 0.0)) {
1462 : // assume Cell Maximum Water Flow Rate Fraction not entered and should be defaulted
1463 0 : tower.MaxFracFlowRate = 2.5;
1464 : }
1465 :
1466 : // cell control for variable speed tower
1467 24 : if (!state.dataIPShortCut->lAlphaFieldBlanks(13)) {
1468 12 : tower.cellCtrl = static_cast<CellCtrl>(getEnumValue(CellCtrlNamesUC, Util::makeUPPER(AlphArray(13))));
1469 : }
1470 :
1471 24 : if (state.dataIPShortCut->lAlphaFieldBlanks(11)) {
1472 24 : tower.SuppliedByWaterSystem = false;
1473 : } else { // water from storage tank
1474 0 : WaterManager::SetupTankDemandComponent(
1475 0 : state, AlphArray(1), cCurrentModuleObject, AlphArray(11), ErrorsFound, tower.WaterTankID, tower.WaterTankDemandARRID);
1476 0 : tower.SuppliedByWaterSystem = true;
1477 : }
1478 :
1479 : // outdoor air inlet node
1480 24 : if (state.dataIPShortCut->lAlphaFieldBlanks(12)) {
1481 24 : tower.OutdoorAirInletNodeNum = 0;
1482 : } else {
1483 0 : tower.OutdoorAirInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
1484 0 : AlphArray(12),
1485 : ErrorsFound,
1486 : DataLoopNode::ConnectionObjectType::CoolingTowerVariableSpeed,
1487 0 : tower.Name,
1488 : DataLoopNode::NodeFluidType::Air,
1489 : DataLoopNode::ConnectionType::OutsideAirReference,
1490 : NodeInputManager::CompFluidStream::Primary,
1491 : DataLoopNode::ObjectIsNotParent);
1492 0 : if (!OutAirNodeManager::CheckOutAirNodeNumber(state, tower.OutdoorAirInletNodeNum)) {
1493 0 : ShowSevereError(state,
1494 0 : format("{}, \"{}\" Outdoor Air Inlet Node Name not valid Outdoor Air Node= {}",
1495 : cCurrentModuleObject,
1496 0 : tower.Name,
1497 : AlphArray(12)));
1498 0 : ShowContinueError(state, "...does not appear in an OutdoorAir:NodeList or as an OutdoorAir:Node.");
1499 0 : ErrorsFound = true;
1500 : }
1501 : }
1502 24 : if (NumAlphas > 13) {
1503 1 : tower.EndUseSubcategory = AlphArray(14);
1504 : } else {
1505 23 : tower.EndUseSubcategory = "General";
1506 : }
1507 :
1508 : } // End Variable-Speed Tower Loop
1509 :
1510 244 : cCurrentModuleObject = cCoolingTower_VariableSpeedMerkel;
1511 246 : for (int MerkelVSTowerNum = 1; MerkelVSTowerNum <= NumVSMerkelTowers; ++MerkelVSTowerNum) {
1512 2 : TowerNum = NumSingleSpeedTowers + NumTwoSpeedTowers + NumVariableSpeedTowers + MerkelVSTowerNum;
1513 4 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1514 : cCurrentModuleObject,
1515 : MerkelVSTowerNum,
1516 : AlphArray,
1517 : NumAlphas,
1518 : NumArray,
1519 : NumNums,
1520 : IOStat,
1521 2 : state.dataIPShortCut->lNumericFieldBlanks,
1522 2 : state.dataIPShortCut->lAlphaFieldBlanks,
1523 2 : state.dataIPShortCut->cAlphaFieldNames,
1524 2 : state.dataIPShortCut->cNumericFieldNames);
1525 2 : GlobalNames::VerifyUniqueInterObjectName(
1526 4 : state, UniqueSimpleTowerNames, AlphArray(1), cCurrentModuleObject, state.dataIPShortCut->cAlphaFieldNames(1), ErrorsFound);
1527 2 : auto &tower = state.dataCondenserLoopTowers->towers(TowerNum);
1528 2 : tower.Name = AlphArray(1);
1529 2 : tower.TowerType = DataPlant::PlantEquipmentType::CoolingTower_VarSpdMerkel;
1530 2 : tower.WaterInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
1531 2 : AlphArray(2),
1532 : ErrorsFound,
1533 : DataLoopNode::ConnectionObjectType::CoolingTowerVariableSpeedMerkel,
1534 2 : AlphArray(1),
1535 : DataLoopNode::NodeFluidType::Water,
1536 : DataLoopNode::ConnectionType::Inlet,
1537 : NodeInputManager::CompFluidStream::Primary,
1538 : DataLoopNode::ObjectIsNotParent);
1539 2 : tower.WaterOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
1540 2 : AlphArray(3),
1541 : ErrorsFound,
1542 : DataLoopNode::ConnectionObjectType::CoolingTowerVariableSpeedMerkel,
1543 2 : AlphArray(1),
1544 : DataLoopNode::NodeFluidType::Water,
1545 : DataLoopNode::ConnectionType::Outlet,
1546 : NodeInputManager::CompFluidStream::Primary,
1547 : DataLoopNode::ObjectIsNotParent);
1548 2 : BranchNodeConnections::TestCompSet(state, cCurrentModuleObject, AlphArray(1), AlphArray(2), AlphArray(3), "Chilled Water Nodes");
1549 :
1550 2 : if (Util::SameString(AlphArray(4), "UFactorTimesAreaAndDesignWaterFlowRate")) {
1551 0 : tower.PerformanceInputMethod_Num = PIM::UFactor;
1552 2 : } else if (Util::SameString(AlphArray(4), "NominalCapacity")) {
1553 2 : tower.PerformanceInputMethod_Num = PIM::NominalCapacity;
1554 : } else {
1555 0 : ShowSevereError(state, format("{}={}", cCurrentModuleObject, AlphArray(1)));
1556 0 : ShowContinueError(state, format("Invalid, {} = {}", state.dataIPShortCut->cAlphaFieldNames(4), AlphArray(4)));
1557 0 : ErrorsFound = true;
1558 : }
1559 :
1560 2 : tower.FanPowerfAirFlowCurve = Curve::GetCurveIndex(state, AlphArray(5));
1561 2 : if (tower.FanPowerfAirFlowCurve == 0) {
1562 0 : ShowSevereError(state, format("{}={}", cCurrentModuleObject, AlphArray(1)));
1563 0 : ShowContinueError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(5), AlphArray(5)));
1564 0 : ShowContinueError(state, "Curve name not found.");
1565 0 : ErrorsFound = true;
1566 : }
1567 :
1568 2 : tower.HeatRejectCapNomCapSizingRatio = NumArray(1);
1569 2 : tower.TowerNominalCapacity = NumArray(2);
1570 2 : if (tower.TowerNominalCapacity == DataSizing::AutoSize) {
1571 2 : tower.TowerNominalCapacityWasAutoSized = true;
1572 : }
1573 2 : tower.TowerFreeConvNomCap = NumArray(3);
1574 2 : if (tower.TowerFreeConvNomCap == DataSizing::AutoSize) {
1575 2 : tower.TowerFreeConvNomCapWasAutoSized = true;
1576 : }
1577 2 : tower.TowerFreeConvNomCapSizingFactor = NumArray(4);
1578 2 : tower.DesignWaterFlowRate = NumArray(5);
1579 2 : if (tower.DesignWaterFlowRate == DataSizing::AutoSize) {
1580 2 : tower.DesignWaterFlowRateWasAutoSized = true;
1581 : }
1582 2 : tower.DesignWaterFlowPerUnitNomCap = NumArray(6);
1583 2 : tower.HighSpeedAirFlowRate = NumArray(7);
1584 2 : if (tower.HighSpeedAirFlowRate == DataSizing::AutoSize) {
1585 2 : tower.HighSpeedAirFlowRateWasAutoSized = true;
1586 : }
1587 2 : tower.DefaultedDesignAirFlowScalingFactor = state.dataIPShortCut->lNumericFieldBlanks(8);
1588 2 : tower.DesignAirFlowPerUnitNomCap = NumArray(8);
1589 2 : tower.MinimumVSAirFlowFrac = NumArray(9);
1590 2 : tower.HighSpeedFanPower = NumArray(10);
1591 2 : if (tower.HighSpeedFanPower == DataSizing::AutoSize) {
1592 2 : tower.HighSpeedFanPowerWasAutoSized = true;
1593 : }
1594 2 : tower.DesignFanPowerPerUnitNomCap = NumArray(11);
1595 2 : tower.FreeConvAirFlowRate = NumArray(12);
1596 2 : if (tower.FreeConvAirFlowRate == DataSizing::AutoSize) {
1597 2 : tower.FreeConvAirFlowRateWasAutoSized = true;
1598 : }
1599 2 : tower.FreeConvAirFlowRateSizingFactor = NumArray(13);
1600 2 : tower.HighSpeedTowerUA = NumArray(14);
1601 2 : if (tower.HighSpeedTowerUA == DataSizing::AutoSize) {
1602 0 : tower.HighSpeedTowerUAWasAutoSized = true;
1603 : }
1604 2 : tower.FreeConvTowerUA = NumArray(15);
1605 2 : if (tower.FreeConvTowerUA == DataSizing::AutoSize) {
1606 0 : tower.FreeConvTowerUAWasAutoSized = true;
1607 : }
1608 2 : tower.FreeConvTowerUASizingFactor = NumArray(16);
1609 :
1610 2 : tower.UAModFuncAirFlowRatioCurvePtr = Curve::GetCurveIndex(state, AlphArray(6));
1611 2 : if (tower.UAModFuncAirFlowRatioCurvePtr == 0) {
1612 0 : ShowSevereError(state, format("{}={}", cCurrentModuleObject, AlphArray(1)));
1613 0 : ShowContinueError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(6), AlphArray(6)));
1614 0 : ShowContinueError(state, "Curve name not found.");
1615 0 : ErrorsFound = true;
1616 : }
1617 :
1618 2 : tower.UAModFuncWetBulbDiffCurvePtr = Curve::GetCurveIndex(state, AlphArray(7));
1619 2 : if (tower.UAModFuncWetBulbDiffCurvePtr == 0) {
1620 0 : ShowSevereError(state, format("{}={}", cCurrentModuleObject, AlphArray(1)));
1621 0 : ShowContinueError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(7), AlphArray(7)));
1622 0 : ShowContinueError(state, "Curve name not found.");
1623 0 : ErrorsFound = true;
1624 : }
1625 :
1626 2 : tower.UAModFuncWaterFlowRatioCurvePtr = Curve::GetCurveIndex(state, AlphArray(8));
1627 2 : if (tower.UAModFuncWaterFlowRatioCurvePtr == 0) {
1628 0 : ShowSevereError(state, format("{}={}", cCurrentModuleObject, AlphArray(1)));
1629 0 : ShowContinueError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(8), AlphArray(8)));
1630 0 : ShowContinueError(state, "Curve name not found.");
1631 0 : ErrorsFound = true;
1632 : }
1633 : // cooling tower design inlet conditions
1634 2 : tower.DesInletAirDBTemp = NumArray(17);
1635 2 : if (tower.DesInletAirDBTemp == 0) {
1636 0 : tower.DesInletAirDBTemp = 35.0;
1637 0 : tower.TowerInletCondsAutoSize = true;
1638 : }
1639 2 : tower.DesInletAirWBTemp = NumArray(18);
1640 2 : if (tower.DesInletAirWBTemp == 0) {
1641 0 : tower.DesInletAirWBTemp = 25.6;
1642 0 : tower.TowerInletCondsAutoSize = true;
1643 : }
1644 2 : tower.DesApproach = NumArray(19);
1645 2 : if (tower.DesApproach == DataSizing::AutoSize || tower.DesApproach == 0) {
1646 2 : tower.DesApproach = 3.9;
1647 2 : tower.TowerInletCondsAutoSize = true;
1648 : }
1649 2 : tower.DesRange = NumArray(20);
1650 2 : if (tower.DesRange == DataSizing::AutoSize || tower.DesRange == 0) {
1651 2 : tower.DesRange = 5.5;
1652 2 : tower.TowerInletCondsAutoSize = true;
1653 : }
1654 : // set tower design water outlet and inlet temperatures
1655 2 : tower.DesOutletWaterTemp = tower.DesInletAirWBTemp + tower.DesApproach;
1656 2 : tower.DesInletWaterTemp = tower.DesOutletWaterTemp + tower.DesRange;
1657 : // Basin heater power as a function of temperature must be greater than or equal to 0
1658 2 : tower.BasinHeaterPowerFTempDiff = NumArray(21);
1659 2 : if (NumArray(21) < 0.0) {
1660 0 : ShowSevereError(
1661 : state,
1662 0 : format("{}, \"{}\" basin heater power as a function of temperature difference must be >= 0", cCurrentModuleObject, tower.Name));
1663 0 : ErrorsFound = true;
1664 : }
1665 :
1666 2 : tower.BasinHeaterSetPointTemp = NumArray(22);
1667 2 : if (tower.BasinHeaterPowerFTempDiff > 0.0) {
1668 0 : if (NumNums < 22) {
1669 0 : tower.BasinHeaterSetPointTemp = 2.0;
1670 : }
1671 0 : if (tower.BasinHeaterSetPointTemp < 2.0) {
1672 0 : ShowWarningError(state,
1673 0 : format("{}:\"{}\", {} is less than 2 deg C. Freezing could occur.",
1674 : cCurrentModuleObject,
1675 0 : tower.Name,
1676 0 : state.dataIPShortCut->cNumericFieldNames(22)));
1677 : }
1678 : }
1679 :
1680 2 : if (!AlphArray(9).empty()) {
1681 0 : tower.BasinHeaterSchedulePtr = ScheduleManager::GetScheduleIndex(state, AlphArray(9));
1682 0 : if (tower.BasinHeaterSchedulePtr == 0) {
1683 0 : ShowWarningError(state,
1684 0 : format("{}, \"{}\" basin heater schedule name \"{}\" was not found. Basin heater operation will not be modeled "
1685 : "and the simulation continues",
1686 : cCurrentModuleObject,
1687 0 : tower.Name,
1688 : AlphArray(9)));
1689 : }
1690 : }
1691 :
1692 : // begin water use and systems get input
1693 2 : tower.EvapLossMode = static_cast<EvapLoss>(getEnumValue(EvapLossNamesUC, Util::makeUPPER(AlphArray(10))));
1694 2 : tower.UserEvapLossFactor = NumArray(23); // N23 , \field Evaporation Loss Factor
1695 2 : tower.DriftLossFraction = NumArray(24) / 100.0; // N24, \field Drift Loss Percent
1696 2 : tower.ConcentrationRatio = NumArray(25); // N25, \field Blowdown Concentration Ratio
1697 2 : tower.SizFac = NumArray(29); // N29 \field Sizing Factor
1698 2 : if (tower.SizFac <= 0.0) tower.SizFac = 1.0;
1699 :
1700 2 : tower.BlowdownMode = static_cast<Blowdown>(getEnumValue(BlowDownNamesUC, Util::makeUPPER(AlphArray(11))));
1701 2 : tower.SchedIDBlowdown = ScheduleManager::GetScheduleIndex(state, AlphArray(12));
1702 2 : if ((tower.SchedIDBlowdown == 0) && (tower.BlowdownMode == Blowdown::Schedule)) {
1703 0 : ShowSevereError(state, format("Invalid, {} = \"{}\"", state.dataIPShortCut->cAlphaFieldNames(12), AlphArray(12)));
1704 0 : ShowContinueError(state, format("Entered in {} = \"{}\"", cCoolingTower_VariableSpeedMerkel, tower.Name));
1705 0 : ErrorsFound = true;
1706 : }
1707 :
1708 : // added for multi-cell
1709 2 : tower.NumCell = NumArray(26);
1710 2 : if ((NumNums < 26) && (tower.NumCell == 0)) {
1711 : // assume Number of Cells not entered and should be defaulted
1712 0 : tower.NumCell = 1;
1713 : }
1714 2 : tower.MinFracFlowRate = NumArray(27);
1715 2 : if ((NumNums < 27) && (tower.MinFracFlowRate == 0.0)) {
1716 : // assume Cell Minimum Water Flow Rate Fraction not entered and should be defaulted
1717 0 : tower.MinFracFlowRate = 0.33;
1718 : }
1719 2 : tower.MaxFracFlowRate = NumArray(28);
1720 2 : if ((NumNums < 28) && (tower.MaxFracFlowRate == 0.0)) {
1721 : // assume Cell Maximum Water Flow Rate Fraction not entered and should be defaulted
1722 0 : tower.MaxFracFlowRate = 2.5;
1723 : }
1724 2 : tower.TowerMassFlowRateMultiplier = tower.MaxFracFlowRate;
1725 : // cell control for variable speed Merkel tower
1726 2 : if (!state.dataIPShortCut->lAlphaFieldBlanks(15)) {
1727 0 : tower.cellCtrl = static_cast<CellCtrl>(getEnumValue(CellCtrlNamesUC, Util::makeUPPER(AlphArray(15))));
1728 : }
1729 :
1730 2 : if (state.dataIPShortCut->lAlphaFieldBlanks(13)) {
1731 2 : tower.SuppliedByWaterSystem = false;
1732 : } else { // water from storage tank
1733 0 : WaterManager::SetupTankDemandComponent(
1734 0 : state, AlphArray(1), cCurrentModuleObject, AlphArray(13), ErrorsFound, tower.WaterTankID, tower.WaterTankDemandARRID);
1735 0 : tower.SuppliedByWaterSystem = true;
1736 : }
1737 :
1738 : // outdoor air inlet node
1739 2 : if (state.dataIPShortCut->lAlphaFieldBlanks(14)) {
1740 2 : tower.OutdoorAirInletNodeNum = 0;
1741 : } else {
1742 0 : tower.OutdoorAirInletNodeNum =
1743 0 : NodeInputManager::GetOnlySingleNode(state,
1744 0 : AlphArray(14),
1745 : ErrorsFound,
1746 : DataLoopNode::ConnectionObjectType::CoolingTowerVariableSpeedMerkel,
1747 0 : tower.Name,
1748 : DataLoopNode::NodeFluidType::Air,
1749 : DataLoopNode::ConnectionType::OutsideAirReference,
1750 : NodeInputManager::CompFluidStream::Primary,
1751 : DataLoopNode::ObjectIsNotParent);
1752 0 : if (!OutAirNodeManager::CheckOutAirNodeNumber(state, tower.OutdoorAirInletNodeNum)) {
1753 0 : ShowSevereError(state,
1754 0 : format("{}, \"{}\" Outdoor Air Inlet Node Name not valid Outdoor Air Node= {}",
1755 : cCurrentModuleObject,
1756 0 : tower.Name,
1757 : AlphArray(14)));
1758 0 : ShowContinueError(state, "...does not appear in an OutdoorAir:NodeList or as an OutdoorAir:Node.");
1759 0 : ErrorsFound = true;
1760 : }
1761 : }
1762 2 : if (NumAlphas > 15) {
1763 0 : tower.EndUseSubcategory = AlphArray(16);
1764 : } else {
1765 2 : tower.EndUseSubcategory = "General";
1766 : }
1767 :
1768 : } // end merkel vs tower loop
1769 :
1770 244 : if (ErrorsFound) {
1771 0 : ShowFatalError(state, "Errors found in getting cooling tower input.");
1772 : }
1773 244 : }
1774 :
1775 270 : void CoolingTower::oneTimeInit(EnergyPlusData &state)
1776 : {
1777 : // Locate the tower on the plant loops for later usage
1778 270 : bool ErrorsFound = false;
1779 270 : PlantUtilities::ScanPlantLoopsForObject(state, this->Name, this->TowerType, this->plantLoc, ErrorsFound, _, _, _, _, _);
1780 270 : if (ErrorsFound) {
1781 0 : ShowFatalError(state, "initialize: Program terminated due to previous condition(s).");
1782 : }
1783 :
1784 : // check if setpoint on outlet node
1785 517 : this->SetpointIsOnOutlet = !((state.dataLoopNodes->Node(this->WaterOutletNodeNum).TempSetPoint == DataLoopNode::SensedNodeFlagValue) &&
1786 247 : (state.dataLoopNodes->Node(this->WaterOutletNodeNum).TempSetPointHi == DataLoopNode::SensedNodeFlagValue));
1787 270 : }
1788 :
1789 1749 : void CoolingTower::initEachEnvironment(EnergyPlusData &state)
1790 : {
1791 : static constexpr std::string_view RoutineName("CoolingTower::initEachEnvironment");
1792 1749 : Real64 const rho = FluidProperties::GetDensityGlycol(state,
1793 1749 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
1794 : Constant::InitConvTemp,
1795 1749 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
1796 : RoutineName);
1797 1749 : this->DesWaterMassFlowRate = this->DesignWaterFlowRate * rho;
1798 1749 : this->DesWaterMassFlowRatePerCell = this->DesWaterMassFlowRate / this->NumCell;
1799 1749 : PlantUtilities::InitComponentNodes(state, 0.0, this->DesWaterMassFlowRate, this->WaterInletNodeNum, this->WaterOutletNodeNum);
1800 1749 : }
1801 :
1802 8768399 : void CoolingTower::initialize(EnergyPlusData &state)
1803 : {
1804 :
1805 : // SUBROUTINE INFORMATION:
1806 : // AUTHOR Fred Buhl
1807 : // DATE WRITTEN May 2002
1808 : // MODIFIED Don Shirey Sept/Oct 2002, F Buhl Oct 2002
1809 : // RE-ENGINEERED R. Raustad, Oct 2005, moved Max/MinAvail to Init and allowed more than design
1810 : // water flow rate to pass through towers (up to 2.5 and 1.25 times the design flow
1811 : // for 1 or 2-speed and variable speed towers, respectively). Flow multiplier for
1812 : // VS Tower is defaulted to 1.25 and can be reassigned by user.
1813 :
1814 : // PURPOSE OF THIS SUBROUTINE:
1815 : // This subroutine is for initializations of the Cooling Tower components and for
1816 : // final checking of tower inputs (post autosizing)
1817 :
1818 : // METHODOLOGY EMPLOYED:
1819 : // Uses the status flags to trigger initializations.
1820 :
1821 8768399 : if (this->oneTimeFlag) {
1822 270 : this->setupOutputVariables(state);
1823 270 : this->oneTimeInit(state);
1824 270 : this->oneTimeFlag = false;
1825 : }
1826 :
1827 : // Begin environment initializations
1828 8768399 : if (this->envrnFlag && state.dataGlobal->BeginEnvrnFlag && (state.dataPlnt->PlantFirstSizesOkayToFinalize)) {
1829 1749 : this->initEachEnvironment(state);
1830 1749 : this->envrnFlag = false;
1831 : }
1832 :
1833 8768399 : if (!state.dataGlobal->BeginEnvrnFlag) {
1834 8711886 : this->envrnFlag = true;
1835 : }
1836 :
1837 : // Each time initializations
1838 8768399 : this->WaterTemp = state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp;
1839 :
1840 8768399 : if (this->OutdoorAirInletNodeNum != 0) {
1841 1684628 : this->AirTemp = state.dataLoopNodes->Node(this->OutdoorAirInletNodeNum).Temp;
1842 1684628 : this->AirHumRat = state.dataLoopNodes->Node(this->OutdoorAirInletNodeNum).HumRat;
1843 1684628 : this->AirPress = state.dataLoopNodes->Node(this->OutdoorAirInletNodeNum).Press;
1844 1684628 : this->AirWetBulb = state.dataLoopNodes->Node(this->OutdoorAirInletNodeNum).OutAirWetBulb;
1845 : } else {
1846 7083771 : this->AirTemp = state.dataEnvrn->OutDryBulbTemp;
1847 7083771 : this->AirHumRat = state.dataEnvrn->OutHumRat;
1848 7083771 : this->AirPress = state.dataEnvrn->OutBaroPress;
1849 7083771 : this->AirWetBulb = state.dataEnvrn->OutWetBulbTemp;
1850 : }
1851 :
1852 8768399 : this->WaterMassFlowRate =
1853 8768399 : PlantUtilities::RegulateCondenserCompFlowReqOp(state, this->plantLoc, this->DesWaterMassFlowRate * this->TowerMassFlowRateMultiplier);
1854 :
1855 8768399 : PlantUtilities::SetComponentFlowRate(state, this->WaterMassFlowRate, this->WaterInletNodeNum, this->WaterOutletNodeNum, this->plantLoc);
1856 :
1857 : // Added for fluid bypass. 8/2008
1858 8768399 : this->BypassFraction = 0.0;
1859 8768399 : this->BasinHeaterPower = 0.0;
1860 8768399 : this->airFlowRateRatio = 0.0;
1861 8768399 : }
1862 :
1863 270 : void CoolingTower::setupOutputVariables(EnergyPlusData &state)
1864 : {
1865 : // Set up output variables CurrentModuleObject='CoolingTower:SingleSpeed'
1866 270 : if (this->TowerType == DataPlant::PlantEquipmentType::CoolingTower_SingleSpd) {
1867 462 : SetupOutputVariable(state,
1868 : "Cooling Tower Inlet Temperature",
1869 : Constant::Units::C,
1870 231 : this->InletWaterTemp,
1871 : OutputProcessor::TimeStepType::System,
1872 : OutputProcessor::StoreType::Average,
1873 231 : this->Name);
1874 462 : SetupOutputVariable(state,
1875 : "Cooling Tower Outlet Temperature",
1876 : Constant::Units::C,
1877 231 : this->OutletWaterTemp,
1878 : OutputProcessor::TimeStepType::System,
1879 : OutputProcessor::StoreType::Average,
1880 231 : this->Name);
1881 462 : SetupOutputVariable(state,
1882 : "Cooling Tower Mass Flow Rate",
1883 : Constant::Units::kg_s,
1884 231 : this->WaterMassFlowRate,
1885 : OutputProcessor::TimeStepType::System,
1886 : OutputProcessor::StoreType::Average,
1887 231 : this->Name);
1888 462 : SetupOutputVariable(state,
1889 : "Cooling Tower Heat Transfer Rate",
1890 : Constant::Units::W,
1891 231 : this->Qactual,
1892 : OutputProcessor::TimeStepType::System,
1893 : OutputProcessor::StoreType::Average,
1894 231 : this->Name);
1895 462 : SetupOutputVariable(state,
1896 : "Cooling Tower Fan Electricity Rate",
1897 : Constant::Units::W,
1898 231 : this->FanPower,
1899 : OutputProcessor::TimeStepType::System,
1900 : OutputProcessor::StoreType::Average,
1901 231 : this->Name);
1902 462 : SetupOutputVariable(state,
1903 : "Cooling Tower Fan Electricity Energy",
1904 : Constant::Units::J,
1905 231 : this->FanEnergy,
1906 : OutputProcessor::TimeStepType::System,
1907 : OutputProcessor::StoreType::Sum,
1908 231 : this->Name,
1909 : Constant::eResource::Electricity,
1910 : OutputProcessor::Group::Plant,
1911 : OutputProcessor::EndUseCat::HeatRejection,
1912 : this->EndUseSubcategory);
1913 : // Added for fluid bypass
1914 462 : SetupOutputVariable(state,
1915 : "Cooling Tower Bypass Fraction",
1916 : Constant::Units::None,
1917 231 : this->BypassFraction,
1918 : OutputProcessor::TimeStepType::System,
1919 : OutputProcessor::StoreType::Average,
1920 231 : this->Name);
1921 231 : SetupOutputVariable(state,
1922 : "Cooling Tower Operating Cells Count",
1923 : Constant::Units::None,
1924 231 : this->NumCellOn,
1925 : OutputProcessor::TimeStepType::System,
1926 : OutputProcessor::StoreType::Average,
1927 231 : this->Name);
1928 462 : SetupOutputVariable(state,
1929 : "Cooling Tower Fan Cycling Ratio",
1930 : Constant::Units::None,
1931 231 : this->FanCyclingRatio,
1932 : OutputProcessor::TimeStepType::System,
1933 : OutputProcessor::StoreType::Average,
1934 231 : this->Name);
1935 231 : if (this->BasinHeaterPowerFTempDiff > 0.0) {
1936 0 : SetupOutputVariable(state,
1937 : "Cooling Tower Basin Heater Electricity Rate",
1938 : Constant::Units::W,
1939 0 : this->BasinHeaterPower,
1940 : OutputProcessor::TimeStepType::System,
1941 : OutputProcessor::StoreType::Average,
1942 0 : this->Name);
1943 0 : SetupOutputVariable(state,
1944 : "Cooling Tower Basin Heater Electricity Energy",
1945 : Constant::Units::J,
1946 0 : this->BasinHeaterConsumption,
1947 : OutputProcessor::TimeStepType::System,
1948 : OutputProcessor::StoreType::Sum,
1949 0 : this->Name,
1950 : Constant::eResource::Electricity,
1951 : OutputProcessor::Group::Plant,
1952 : OutputProcessor::EndUseCat::HeatRejection,
1953 : "BasinHeater");
1954 : }
1955 : }
1956 :
1957 : // CurrentModuleObject='CoolingTower:TwoSpeed'
1958 270 : if (this->TowerType == DataPlant::PlantEquipmentType::CoolingTower_TwoSpd) {
1959 26 : SetupOutputVariable(state,
1960 : "Cooling Tower Inlet Temperature",
1961 : Constant::Units::C,
1962 13 : this->InletWaterTemp,
1963 : OutputProcessor::TimeStepType::System,
1964 : OutputProcessor::StoreType::Average,
1965 13 : this->Name);
1966 26 : SetupOutputVariable(state,
1967 : "Cooling Tower Outlet Temperature",
1968 : Constant::Units::C,
1969 13 : this->OutletWaterTemp,
1970 : OutputProcessor::TimeStepType::System,
1971 : OutputProcessor::StoreType::Average,
1972 13 : this->Name);
1973 26 : SetupOutputVariable(state,
1974 : "Cooling Tower Mass Flow Rate",
1975 : Constant::Units::kg_s,
1976 13 : this->WaterMassFlowRate,
1977 : OutputProcessor::TimeStepType::System,
1978 : OutputProcessor::StoreType::Average,
1979 13 : this->Name);
1980 26 : SetupOutputVariable(state,
1981 : "Cooling Tower Heat Transfer Rate",
1982 : Constant::Units::W,
1983 13 : this->Qactual,
1984 : OutputProcessor::TimeStepType::System,
1985 : OutputProcessor::StoreType::Average,
1986 13 : this->Name);
1987 26 : SetupOutputVariable(state,
1988 : "Cooling Tower Fan Electricity Rate",
1989 : Constant::Units::W,
1990 13 : this->FanPower,
1991 : OutputProcessor::TimeStepType::System,
1992 : OutputProcessor::StoreType::Average,
1993 13 : this->Name);
1994 26 : SetupOutputVariable(state,
1995 : "Cooling Tower Fan Electricity Energy",
1996 : Constant::Units::J,
1997 13 : this->FanEnergy,
1998 : OutputProcessor::TimeStepType::System,
1999 : OutputProcessor::StoreType::Sum,
2000 13 : this->Name,
2001 : Constant::eResource::Electricity,
2002 : OutputProcessor::Group::Plant,
2003 : OutputProcessor::EndUseCat::HeatRejection,
2004 : this->EndUseSubcategory);
2005 26 : SetupOutputVariable(state,
2006 : "Cooling Tower Fan Cycling Ratio",
2007 : Constant::Units::None,
2008 13 : this->FanCyclingRatio,
2009 : OutputProcessor::TimeStepType::System,
2010 : OutputProcessor::StoreType::Average,
2011 13 : this->Name);
2012 13 : SetupOutputVariable(state,
2013 : "Cooling Tower Fan Speed Level",
2014 : Constant::Units::None,
2015 13 : this->SpeedSelected,
2016 : OutputProcessor::TimeStepType::System,
2017 : OutputProcessor::StoreType::Average,
2018 13 : this->Name);
2019 13 : SetupOutputVariable(state,
2020 : "Cooling Tower Operating Cells Count",
2021 : Constant::Units::None,
2022 13 : this->NumCellOn,
2023 : OutputProcessor::TimeStepType::System,
2024 : OutputProcessor::StoreType::Average,
2025 13 : this->Name);
2026 13 : if (this->BasinHeaterPowerFTempDiff > 0.0) {
2027 0 : SetupOutputVariable(state,
2028 : "Cooling Tower Basin Heater Electricity Rate",
2029 : Constant::Units::W,
2030 0 : this->BasinHeaterPower,
2031 : OutputProcessor::TimeStepType::System,
2032 : OutputProcessor::StoreType::Average,
2033 0 : this->Name);
2034 0 : SetupOutputVariable(state,
2035 : "Cooling Tower Basin Heater Electricity Energy",
2036 : Constant::Units::J,
2037 0 : this->BasinHeaterConsumption,
2038 : OutputProcessor::TimeStepType::System,
2039 : OutputProcessor::StoreType::Sum,
2040 0 : this->Name,
2041 : Constant::eResource::Electricity,
2042 : OutputProcessor::Group::Plant,
2043 : OutputProcessor::EndUseCat::HeatRejection,
2044 : "BasinHeater");
2045 : }
2046 : }
2047 :
2048 : // CurrentModuleObject='CoolingTower:VariableSpeed'
2049 270 : if (this->TowerType == DataPlant::PlantEquipmentType::CoolingTower_VarSpd) {
2050 48 : SetupOutputVariable(state,
2051 : "Cooling Tower Inlet Temperature",
2052 : Constant::Units::C,
2053 24 : this->InletWaterTemp,
2054 : OutputProcessor::TimeStepType::System,
2055 : OutputProcessor::StoreType::Average,
2056 24 : this->Name);
2057 48 : SetupOutputVariable(state,
2058 : "Cooling Tower Outlet Temperature",
2059 : Constant::Units::C,
2060 24 : this->OutletWaterTemp,
2061 : OutputProcessor::TimeStepType::System,
2062 : OutputProcessor::StoreType::Average,
2063 24 : this->Name);
2064 48 : SetupOutputVariable(state,
2065 : "Cooling Tower Mass Flow Rate",
2066 : Constant::Units::kg_s,
2067 24 : this->WaterMassFlowRate,
2068 : OutputProcessor::TimeStepType::System,
2069 : OutputProcessor::StoreType::Average,
2070 24 : this->Name);
2071 48 : SetupOutputVariable(state,
2072 : "Cooling Tower Heat Transfer Rate",
2073 : Constant::Units::W,
2074 24 : this->Qactual,
2075 : OutputProcessor::TimeStepType::System,
2076 : OutputProcessor::StoreType::Average,
2077 24 : this->Name);
2078 48 : SetupOutputVariable(state,
2079 : "Cooling Tower Fan Electricity Rate",
2080 : Constant::Units::W,
2081 24 : this->FanPower,
2082 : OutputProcessor::TimeStepType::System,
2083 : OutputProcessor::StoreType::Average,
2084 24 : this->Name);
2085 48 : SetupOutputVariable(state,
2086 : "Cooling Tower Fan Electricity Energy",
2087 : Constant::Units::J,
2088 24 : this->FanEnergy,
2089 : OutputProcessor::TimeStepType::System,
2090 : OutputProcessor::StoreType::Sum,
2091 24 : this->Name,
2092 : Constant::eResource::Electricity,
2093 : OutputProcessor::Group::Plant,
2094 : OutputProcessor::EndUseCat::HeatRejection,
2095 : this->EndUseSubcategory);
2096 48 : SetupOutputVariable(state,
2097 : "Cooling Tower Air Flow Rate Ratio",
2098 : Constant::Units::None,
2099 24 : this->AirFlowRatio,
2100 : OutputProcessor::TimeStepType::System,
2101 : OutputProcessor::StoreType::Average,
2102 24 : this->Name);
2103 48 : SetupOutputVariable(state,
2104 : "Cooling Tower Fan Part Load Ratio",
2105 : Constant::Units::None,
2106 24 : this->FanCyclingRatio,
2107 : OutputProcessor::TimeStepType::System,
2108 : OutputProcessor::StoreType::Average,
2109 24 : this->Name);
2110 24 : SetupOutputVariable(state,
2111 : "Cooling Tower Operating Cells Count",
2112 : Constant::Units::None,
2113 24 : this->NumCellOn,
2114 : OutputProcessor::TimeStepType::System,
2115 : OutputProcessor::StoreType::Average,
2116 24 : this->Name);
2117 24 : if (this->BasinHeaterPowerFTempDiff > 0.0) {
2118 24 : SetupOutputVariable(state,
2119 : "Cooling Tower Basin Heater Electricity Rate",
2120 : Constant::Units::W,
2121 12 : this->BasinHeaterPower,
2122 : OutputProcessor::TimeStepType::System,
2123 : OutputProcessor::StoreType::Average,
2124 12 : this->Name);
2125 24 : SetupOutputVariable(state,
2126 : "Cooling Tower Basin Heater Electricity Energy",
2127 : Constant::Units::J,
2128 12 : this->BasinHeaterConsumption,
2129 : OutputProcessor::TimeStepType::System,
2130 : OutputProcessor::StoreType::Sum,
2131 12 : this->Name,
2132 : Constant::eResource::Electricity,
2133 : OutputProcessor::Group::Plant,
2134 : OutputProcessor::EndUseCat::HeatRejection,
2135 : "BasinHeater");
2136 : }
2137 : }
2138 :
2139 : // CurrentModuleObject='CoolingTower:VariableSpeed:Merkel'
2140 270 : if (this->TowerType == DataPlant::PlantEquipmentType::CoolingTower_VarSpdMerkel) {
2141 4 : SetupOutputVariable(state,
2142 : "Cooling Tower Inlet Temperature",
2143 : Constant::Units::C,
2144 2 : this->InletWaterTemp,
2145 : OutputProcessor::TimeStepType::System,
2146 : OutputProcessor::StoreType::Average,
2147 2 : this->Name);
2148 4 : SetupOutputVariable(state,
2149 : "Cooling Tower Outlet Temperature",
2150 : Constant::Units::C,
2151 2 : this->OutletWaterTemp,
2152 : OutputProcessor::TimeStepType::System,
2153 : OutputProcessor::StoreType::Average,
2154 2 : this->Name);
2155 4 : SetupOutputVariable(state,
2156 : "Cooling Tower Mass Flow Rate",
2157 : Constant::Units::kg_s,
2158 2 : this->WaterMassFlowRate,
2159 : OutputProcessor::TimeStepType::System,
2160 : OutputProcessor::StoreType::Average,
2161 2 : this->Name);
2162 4 : SetupOutputVariable(state,
2163 : "Cooling Tower Heat Transfer Rate",
2164 : Constant::Units::W,
2165 2 : this->Qactual,
2166 : OutputProcessor::TimeStepType::System,
2167 : OutputProcessor::StoreType::Average,
2168 2 : this->Name);
2169 4 : SetupOutputVariable(state,
2170 : "Cooling Tower Fan Electricity Rate",
2171 : Constant::Units::W,
2172 2 : this->FanPower,
2173 : OutputProcessor::TimeStepType::System,
2174 : OutputProcessor::StoreType::Average,
2175 2 : this->Name);
2176 4 : SetupOutputVariable(state,
2177 : "Cooling Tower Fan Electricity Energy",
2178 : Constant::Units::J,
2179 2 : this->FanEnergy,
2180 : OutputProcessor::TimeStepType::System,
2181 : OutputProcessor::StoreType::Sum,
2182 2 : this->Name,
2183 : Constant::eResource::Electricity,
2184 : OutputProcessor::Group::Plant,
2185 : OutputProcessor::EndUseCat::HeatRejection,
2186 : this->EndUseSubcategory);
2187 4 : SetupOutputVariable(state,
2188 : "Cooling Tower Fan Speed Ratio",
2189 : Constant::Units::None,
2190 2 : this->AirFlowRatio,
2191 : OutputProcessor::TimeStepType::System,
2192 : OutputProcessor::StoreType::Average,
2193 2 : this->Name);
2194 :
2195 2 : SetupOutputVariable(state,
2196 : "Cooling Tower Operating Cells Count",
2197 : Constant::Units::None,
2198 2 : this->NumCellOn,
2199 : OutputProcessor::TimeStepType::System,
2200 : OutputProcessor::StoreType::Average,
2201 2 : this->Name);
2202 2 : if (this->BasinHeaterPowerFTempDiff > 0.0) {
2203 0 : SetupOutputVariable(state,
2204 : "Cooling Tower Basin Heater Electricity Rate",
2205 : Constant::Units::W,
2206 0 : this->BasinHeaterPower,
2207 : OutputProcessor::TimeStepType::System,
2208 : OutputProcessor::StoreType::Average,
2209 0 : this->Name);
2210 0 : SetupOutputVariable(state,
2211 : "Cooling Tower Basin Heater Electricity Energy",
2212 : Constant::Units::J,
2213 0 : this->BasinHeaterConsumption,
2214 : OutputProcessor::TimeStepType::System,
2215 : OutputProcessor::StoreType::Sum,
2216 0 : this->Name,
2217 : Constant::eResource::Electricity,
2218 : OutputProcessor::Group::Plant,
2219 : OutputProcessor::EndUseCat::HeatRejection,
2220 : "BasinHeater");
2221 : }
2222 : }
2223 : // setup common water reporting for all types of towers.
2224 270 : if (this->SuppliedByWaterSystem) {
2225 4 : SetupOutputVariable(state,
2226 : "Cooling Tower Make Up Water Volume Flow Rate",
2227 : Constant::Units::m3_s,
2228 2 : this->MakeUpVdot,
2229 : OutputProcessor::TimeStepType::System,
2230 : OutputProcessor::StoreType::Average,
2231 2 : this->Name);
2232 4 : SetupOutputVariable(state,
2233 : "Cooling Tower Make Up Water Volume",
2234 : Constant::Units::m3,
2235 2 : this->MakeUpVol,
2236 : OutputProcessor::TimeStepType::System,
2237 : OutputProcessor::StoreType::Sum,
2238 2 : this->Name);
2239 4 : SetupOutputVariable(state,
2240 : "Cooling Tower Storage Tank Water Volume Flow Rate",
2241 : Constant::Units::m3_s,
2242 2 : this->TankSupplyVdot,
2243 : OutputProcessor::TimeStepType::System,
2244 : OutputProcessor::StoreType::Average,
2245 2 : this->Name);
2246 4 : SetupOutputVariable(state,
2247 : "Cooling Tower Storage Tank Water Volume",
2248 : Constant::Units::m3,
2249 2 : this->TankSupplyVol,
2250 : OutputProcessor::TimeStepType::System,
2251 : OutputProcessor::StoreType::Sum,
2252 2 : this->Name,
2253 : Constant::eResource::Water,
2254 : OutputProcessor::Group::Plant,
2255 : OutputProcessor::EndUseCat::HeatRejection);
2256 4 : SetupOutputVariable(state,
2257 : "Cooling Tower Starved Storage Tank Water Volume Flow Rate",
2258 : Constant::Units::m3_s,
2259 2 : this->StarvedMakeUpVdot,
2260 : OutputProcessor::TimeStepType::System,
2261 : OutputProcessor::StoreType::Average,
2262 2 : this->Name);
2263 4 : SetupOutputVariable(state,
2264 : "Cooling Tower Starved Storage Tank Water Volume",
2265 : Constant::Units::m3,
2266 2 : this->StarvedMakeUpVol,
2267 : OutputProcessor::TimeStepType::System,
2268 : OutputProcessor::StoreType::Sum,
2269 2 : this->Name);
2270 4 : SetupOutputVariable(state,
2271 : "Cooling Tower Make Up Mains Water Volume",
2272 : Constant::Units::m3,
2273 2 : this->StarvedMakeUpVol,
2274 : OutputProcessor::TimeStepType::System,
2275 : OutputProcessor::StoreType::Sum,
2276 2 : this->Name,
2277 : Constant::eResource::MainsWater,
2278 : OutputProcessor::Group::Plant,
2279 : OutputProcessor::EndUseCat::HeatRejection);
2280 : } else { // tower water from mains and gets metered
2281 536 : SetupOutputVariable(state,
2282 : "Cooling Tower Make Up Water Volume Flow Rate",
2283 : Constant::Units::m3_s,
2284 268 : this->MakeUpVdot,
2285 : OutputProcessor::TimeStepType::System,
2286 : OutputProcessor::StoreType::Average,
2287 268 : this->Name);
2288 536 : SetupOutputVariable(state,
2289 : "Cooling Tower Make Up Water Volume",
2290 : Constant::Units::m3,
2291 268 : this->MakeUpVol,
2292 : OutputProcessor::TimeStepType::System,
2293 : OutputProcessor::StoreType::Sum,
2294 268 : this->Name,
2295 : Constant::eResource::Water,
2296 : OutputProcessor::Group::Plant,
2297 : OutputProcessor::EndUseCat::HeatRejection);
2298 536 : SetupOutputVariable(state,
2299 : "Cooling Tower Make Up Mains Water Volume",
2300 : Constant::Units::m3,
2301 268 : this->MakeUpVol,
2302 : OutputProcessor::TimeStepType::System,
2303 : OutputProcessor::StoreType::Sum,
2304 268 : this->Name,
2305 : Constant::eResource::MainsWater,
2306 : OutputProcessor::Group::Plant,
2307 : OutputProcessor::EndUseCat::HeatRejection);
2308 : }
2309 :
2310 540 : SetupOutputVariable(state,
2311 : "Cooling Tower Water Evaporation Volume Flow Rate",
2312 : Constant::Units::m3_s,
2313 270 : this->EvaporationVdot,
2314 : OutputProcessor::TimeStepType::System,
2315 : OutputProcessor::StoreType::Average,
2316 270 : this->Name);
2317 540 : SetupOutputVariable(state,
2318 : "Cooling Tower Water Evaporation Volume",
2319 : Constant::Units::m3,
2320 270 : this->EvaporationVol,
2321 : OutputProcessor::TimeStepType::System,
2322 : OutputProcessor::StoreType::Sum,
2323 270 : this->Name);
2324 540 : SetupOutputVariable(state,
2325 : "Cooling Tower Water Drift Volume Flow Rate",
2326 : Constant::Units::m3_s,
2327 270 : this->DriftVdot,
2328 : OutputProcessor::TimeStepType::System,
2329 : OutputProcessor::StoreType::Average,
2330 270 : this->Name);
2331 540 : SetupOutputVariable(state,
2332 : "Cooling Tower Water Drift Volume",
2333 : Constant::Units::m3,
2334 270 : this->DriftVol,
2335 : OutputProcessor::TimeStepType::System,
2336 : OutputProcessor::StoreType::Sum,
2337 270 : this->Name);
2338 540 : SetupOutputVariable(state,
2339 : "Cooling Tower Water Blowdown Volume Flow Rate",
2340 : Constant::Units::m3_s,
2341 270 : this->BlowdownVdot,
2342 : OutputProcessor::TimeStepType::System,
2343 : OutputProcessor::StoreType::Average,
2344 270 : this->Name);
2345 540 : SetupOutputVariable(state,
2346 : "Cooling Tower Water Blowdown Volume",
2347 : Constant::Units::m3,
2348 270 : this->BlowdownVol,
2349 : OutputProcessor::TimeStepType::System,
2350 : OutputProcessor::StoreType::Sum,
2351 270 : this->Name);
2352 540 : SetupOutputVariable(state,
2353 : "Cooling Tower Approach",
2354 : Constant::Units::C,
2355 270 : this->coolingTowerApproach,
2356 : OutputProcessor::TimeStepType::System,
2357 : OutputProcessor::StoreType::Average,
2358 270 : this->Name);
2359 540 : SetupOutputVariable(state,
2360 : "Cooling Tower Range",
2361 : Constant::Units::C,
2362 270 : this->coolingTowerRange,
2363 : OutputProcessor::TimeStepType::System,
2364 : OutputProcessor::StoreType::Average,
2365 270 : this->Name);
2366 270 : }
2367 :
2368 1362 : void CoolingTower::SizeTower(EnergyPlusData &state)
2369 : {
2370 :
2371 : // SUBROUTINE INFORMATION:
2372 : // AUTHOR Fred Buhl
2373 : // DATE WRITTEN May 2002
2374 : // MODIFIED Don Shirey, Sept/Oct 2002; Richard Raustad, Feb 2005
2375 :
2376 : // PURPOSE OF THIS SUBROUTINE:
2377 : // This subroutine is for sizing Cooling Tower Components for which capacities and flow rates
2378 : // have not been specified in the input. This subroutine also calculates tower UA if the user
2379 : // has specified tower performance via the "Nominal Capacity" method.
2380 :
2381 : // METHODOLOGY EMPLOYED:
2382 : // Obtains condenser flow rate from the plant sizing array. If tower performance is specified
2383 : // via the "Nominal Capacity" method, the water flow rate is directly proportional to capacity.
2384 :
2385 : // SUBROUTINE PARAMETER DEFINITIONS:
2386 :
2387 1362 : int constexpr MaxIte(500); // Maximum number of iterations
2388 1362 : Real64 constexpr Acc(0.0001); // Accuracy of result
2389 : static constexpr std::string_view RoutineName("SizeTower");
2390 :
2391 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2392 : int SolFla; // Flag of solver
2393 1362 : Real64 DesTowerLoad(0.0); // Design tower load [W]
2394 : Real64 UA0; // Lower bound for UA [W/C]
2395 : Real64 UA1; // Upper bound for UA [W/C]
2396 : Real64 UA; // Calculated UA value
2397 : Real64 DesTowerInletWaterTemp; // design tower inlet water temperature
2398 : Real64 DesTowerExitWaterTemp; // design tower exit water temperature
2399 : Real64 DesTowerWaterDeltaT; // design tower temperature range
2400 : Real64 DesTowerApproachFromPlant; // design tower approach temperature from plant sizing object
2401 1362 : Real64 TolTemp(0.04); // DeltaT and DesApproach diffs tollerance between plant sizing data and user input in cooling tower
2402 : // for warning message reporting purpose only
2403 :
2404 1362 : Real64 tmpDesignWaterFlowRate = this->DesignWaterFlowRate;
2405 1362 : Real64 tmpHighSpeedFanPower = this->HighSpeedFanPower;
2406 1362 : Real64 tmpHighSpeedAirFlowRate = this->HighSpeedAirFlowRate;
2407 1362 : Real64 tmpLowSpeedAirFlowRate = this->LowSpeedAirFlowRate;
2408 :
2409 1362 : auto &PlantSizData(state.dataSize->PlantSizData);
2410 :
2411 : // Find the appropriate Plant Sizing object
2412 1362 : int PltSizCondNum = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).PlantSizNum;
2413 :
2414 1362 : if (this->TowerType == DataPlant::PlantEquipmentType::CoolingTower_SingleSpd ||
2415 185 : this->TowerType == DataPlant::PlantEquipmentType::CoolingTower_TwoSpd) {
2416 1242 : if (this->TowerInletCondsAutoSize) {
2417 1242 : if (PltSizCondNum > 0) {
2418 : // use plant sizing data
2419 697 : DesTowerExitWaterTemp = PlantSizData(PltSizCondNum).ExitTemp;
2420 697 : DesTowerInletWaterTemp = DesTowerExitWaterTemp + PlantSizData(PltSizCondNum).DeltaT;
2421 697 : DesTowerWaterDeltaT = PlantSizData(PltSizCondNum).DeltaT;
2422 : } else {
2423 : // set hard wired input assumptions
2424 : // AssumedDeltaT = 11.0;
2425 : // AssumedExitTemp = 21.0;
2426 545 : DesTowerWaterDeltaT = 11.0;
2427 545 : DesTowerExitWaterTemp = 21.0;
2428 545 : DesTowerInletWaterTemp = DesTowerExitWaterTemp + DesTowerWaterDeltaT;
2429 : }
2430 : } else {
2431 : // use tower sizing data
2432 0 : DesTowerExitWaterTemp = this->DesOutletWaterTemp;
2433 0 : DesTowerInletWaterTemp = this->DesInletWaterTemp;
2434 0 : DesTowerWaterDeltaT = this->DesRange;
2435 0 : if (PltSizCondNum > 0) {
2436 : // check the tower range against the plant sizing data
2437 0 : if (std::abs(DesTowerWaterDeltaT - PlantSizData(PltSizCondNum).DeltaT) > TolTemp) {
2438 0 : ShowWarningError(state,
2439 0 : format("Error when autosizing the load for cooling tower = {}. Tower Design Range Temperature is different "
2440 : "from the Design Loop Delta Temperature.",
2441 0 : this->Name));
2442 0 : ShowContinueError(state, format("Tower Design Range Temperature specified in tower = {}", this->Name));
2443 0 : ShowContinueError(state,
2444 0 : format("is inconsistent with Design Loop Delta Temperature specified in Sizing:Plant object = {}.",
2445 0 : PlantSizData(PltSizCondNum).PlantLoopName));
2446 0 : ShowContinueError(state, format("..The Design Range Temperature specified in tower is = {:.2T}", this->DesRange));
2447 0 : ShowContinueError(state,
2448 0 : format("..The Design Loop Delta Temperature specified in plant sizing data is = {:.2T}",
2449 0 : PlantSizData(PltSizCondNum).DeltaT));
2450 : }
2451 : // check if the tower approach is different from plant sizing data
2452 0 : DesTowerApproachFromPlant = PlantSizData(PltSizCondNum).ExitTemp - this->DesInletAirWBTemp;
2453 0 : if (std::abs(DesTowerApproachFromPlant - this->DesApproach) > TolTemp) {
2454 0 : ShowWarningError(state,
2455 0 : format("Error when autosizing the UA for cooling tower = {}. Tower Design Approach Temperature is "
2456 : "inconsistent with Approach from Plant Sizing Data.",
2457 0 : this->Name));
2458 0 : ShowContinueError(state,
2459 0 : format("The Design Approach Temperature from inputs specified in Sizing:Plant object = {}",
2460 0 : PlantSizData(PltSizCondNum).PlantLoopName));
2461 0 : ShowContinueError(state, format("is inconsistent with Design Approach Temperature specified in tower = {}.", this->Name));
2462 0 : ShowContinueError(state,
2463 0 : format("..The Design Approach Temperature from inputs specified is = {:.2T}", DesTowerApproachFromPlant));
2464 0 : ShowContinueError(state, format("..The Design Approach Temperature specified in tower is = {:.2T}", this->DesApproach));
2465 : }
2466 : }
2467 : }
2468 : } else { // CoolingTower_VariableSpeed
2469 120 : if (PltSizCondNum > 0) {
2470 : // use plant sizing data
2471 120 : DesTowerExitWaterTemp = PlantSizData(PltSizCondNum).ExitTemp;
2472 120 : DesTowerInletWaterTemp = DesTowerExitWaterTemp + PlantSizData(PltSizCondNum).DeltaT;
2473 120 : DesTowerWaterDeltaT = PlantSizData(PltSizCondNum).DeltaT;
2474 : } else {
2475 : // set hard wired input assumptions
2476 0 : DesTowerWaterDeltaT = 11.0;
2477 0 : DesTowerExitWaterTemp = 21.0;
2478 0 : DesTowerInletWaterTemp = DesTowerExitWaterTemp + DesTowerWaterDeltaT;
2479 : }
2480 : }
2481 :
2482 1362 : if (this->PerformanceInputMethod_Num == PIM::UFactor && (!this->HighSpeedTowerUAWasAutoSized)) {
2483 710 : if (PltSizCondNum > 0) {
2484 205 : Real64 const rho = FluidProperties::GetDensityGlycol(state,
2485 205 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
2486 : DesTowerExitWaterTemp,
2487 205 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
2488 : RoutineName);
2489 205 : Real64 const Cp = FluidProperties::GetSpecificHeatGlycol(state,
2490 205 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
2491 : DesTowerExitWaterTemp,
2492 205 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
2493 : RoutineName);
2494 205 : DesTowerLoad = rho * Cp * this->DesignWaterFlowRate * DesTowerWaterDeltaT;
2495 205 : this->TowerNominalCapacity = DesTowerLoad / this->HeatRejectCapNomCapSizingRatio;
2496 :
2497 : } else {
2498 505 : Real64 AssumedDeltaT = DesTowerWaterDeltaT;
2499 505 : Real64 AssumedExitTemp = DesTowerExitWaterTemp;
2500 :
2501 505 : Real64 const rho = FluidProperties::GetDensityGlycol(state,
2502 505 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
2503 : AssumedExitTemp,
2504 505 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
2505 : RoutineName);
2506 505 : Real64 const Cp = FluidProperties::GetSpecificHeatGlycol(state,
2507 505 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
2508 : AssumedExitTemp,
2509 505 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
2510 : RoutineName);
2511 :
2512 505 : DesTowerLoad = rho * Cp * this->DesignWaterFlowRate * AssumedDeltaT;
2513 505 : this->TowerNominalCapacity = DesTowerLoad / this->HeatRejectCapNomCapSizingRatio;
2514 : }
2515 : }
2516 :
2517 1362 : if (this->DesignWaterFlowRateWasAutoSized) {
2518 667 : if (PltSizCondNum > 0) {
2519 667 : if (PlantSizData(PltSizCondNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
2520 424 : tmpDesignWaterFlowRate = PlantSizData(PltSizCondNum).DesVolFlowRate * this->SizFac;
2521 424 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) this->DesignWaterFlowRate = tmpDesignWaterFlowRate;
2522 : } else {
2523 243 : tmpDesignWaterFlowRate = 0.0;
2524 243 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) this->DesignWaterFlowRate = tmpDesignWaterFlowRate;
2525 : }
2526 667 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
2527 258 : BaseSizer::reportSizerOutput(state,
2528 129 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
2529 : this->Name,
2530 : "Design Water Flow Rate [m3/s]",
2531 : this->DesignWaterFlowRate);
2532 : }
2533 667 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
2534 22 : BaseSizer::reportSizerOutput(state,
2535 11 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
2536 : this->Name,
2537 : "Initial Design Water Flow Rate [m3/s]",
2538 : this->DesignWaterFlowRate);
2539 : }
2540 : } else {
2541 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
2542 0 : ShowSevereError(state, format("Autosizing error for cooling tower object = {}", this->Name));
2543 0 : ShowFatalError(state, "Autosizing of cooling tower condenser flow rate requires a loop Sizing:Plant object.");
2544 : }
2545 : }
2546 : }
2547 :
2548 1362 : if (this->PerformanceInputMethod_Num == PIM::NominalCapacity) {
2549 : // Design water flow rate is assumed to be 3 gpm per ton (SI equivalent 5.382E-8 m3/s per watt)
2550 40 : this->DesignWaterFlowRate = 5.382e-8 * this->TowerNominalCapacity;
2551 40 : tmpDesignWaterFlowRate = this->DesignWaterFlowRate;
2552 40 : if (Util::SameString(DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)], "CoolingTower:SingleSpeed")) {
2553 15 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
2554 6 : BaseSizer::reportSizerOutput(state,
2555 3 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
2556 : this->Name,
2557 : "Design Water Flow Rate based on tower nominal capacity [m3/s]",
2558 : this->DesignWaterFlowRate);
2559 : }
2560 15 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
2561 0 : BaseSizer::reportSizerOutput(state,
2562 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
2563 : this->Name,
2564 : "Initial Design Water Flow Rate based on tower nominal capacity [m3/s]",
2565 : this->DesignWaterFlowRate);
2566 : }
2567 25 : } else if (Util::SameString(DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)], "CoolingTower:TwoSpeed")) {
2568 25 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
2569 10 : BaseSizer::reportSizerOutput(state,
2570 5 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
2571 : this->Name,
2572 : "Design Water Flow Rate based on tower high-speed nominal capacity [m3/s]",
2573 : this->DesignWaterFlowRate);
2574 : }
2575 25 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
2576 0 : BaseSizer::reportSizerOutput(state,
2577 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
2578 : this->Name,
2579 : "Initial Design Water Flow Rate based on tower high-speed nominal capacity [m3/s]",
2580 : this->DesignWaterFlowRate);
2581 : }
2582 : }
2583 : }
2584 :
2585 1362 : PlantUtilities::RegisterPlantCompDesignFlow(state, this->WaterInletNodeNum, tmpDesignWaterFlowRate);
2586 :
2587 1362 : if (this->HighSpeedFanPowerWasAutoSized) {
2588 : // We assume the nominal fan power is 0.0105 times the design load
2589 682 : if (this->PerformanceInputMethod_Num == PIM::NominalCapacity) {
2590 5 : this->HighSpeedFanPower = 0.0105 * this->TowerNominalCapacity;
2591 5 : tmpHighSpeedFanPower = this->HighSpeedFanPower;
2592 : } else {
2593 677 : if (PltSizCondNum > 0) {
2594 677 : if (PlantSizData(PltSizCondNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
2595 431 : Real64 const rho = FluidProperties::GetDensityGlycol(state,
2596 431 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
2597 : Constant::InitConvTemp,
2598 431 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
2599 : RoutineName);
2600 431 : Real64 const Cp = FluidProperties::GetSpecificHeatGlycol(state,
2601 431 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
2602 : DesTowerExitWaterTemp,
2603 431 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
2604 : RoutineName);
2605 431 : DesTowerLoad = rho * Cp * tmpDesignWaterFlowRate * DesTowerWaterDeltaT;
2606 431 : tmpHighSpeedFanPower = 0.0105 * DesTowerLoad;
2607 431 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) this->HighSpeedFanPower = tmpHighSpeedFanPower;
2608 : } else {
2609 246 : tmpHighSpeedFanPower = 0.0;
2610 246 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) this->HighSpeedFanPower = tmpHighSpeedFanPower;
2611 : }
2612 : } else {
2613 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
2614 0 : ShowSevereError(state, "Autosizing of cooling tower fan power requires a loop Sizing:Plant object.");
2615 0 : ShowFatalError(state, format(" Occurs in cooling tower object= {}", this->Name));
2616 : }
2617 : }
2618 : }
2619 682 : if (this->TowerType == DataPlant::PlantEquipmentType::CoolingTower_SingleSpd ||
2620 110 : this->TowerType == DataPlant::PlantEquipmentType::CoolingTower_VarSpd) {
2621 637 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
2622 246 : BaseSizer::reportSizerOutput(state,
2623 123 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
2624 : this->Name,
2625 : "Fan Power at Design Air Flow Rate [W]",
2626 : this->HighSpeedFanPower);
2627 : }
2628 637 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
2629 22 : BaseSizer::reportSizerOutput(state,
2630 11 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
2631 : this->Name,
2632 : "Initial Fan Power at Design Air Flow Rate [W]",
2633 : this->HighSpeedFanPower);
2634 : }
2635 45 : } else if (this->TowerType == DataPlant::PlantEquipmentType::CoolingTower_TwoSpd) {
2636 45 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
2637 18 : BaseSizer::reportSizerOutput(state,
2638 9 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
2639 : this->Name,
2640 : "Fan Power at High Fan Speed [W]",
2641 : this->HighSpeedFanPower);
2642 : }
2643 45 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
2644 0 : BaseSizer::reportSizerOutput(state,
2645 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
2646 : this->Name,
2647 : "Initial Fan Power at High Fan Speed [W]",
2648 : this->HighSpeedFanPower);
2649 : }
2650 : }
2651 : }
2652 :
2653 1362 : if (this->HighSpeedAirFlowRateWasAutoSized) {
2654 : // Plant Sizing Object is not required to AUTOSIZE this field since its simply a multiple of another field.
2655 752 : tmpHighSpeedAirFlowRate = tmpHighSpeedFanPower * 0.5 * (101325.0 / state.dataEnvrn->StdBaroPress) / 190.0;
2656 752 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) this->HighSpeedAirFlowRate = tmpHighSpeedAirFlowRate;
2657 :
2658 752 : if (this->TowerType == DataPlant::PlantEquipmentType::CoolingTower_SingleSpd ||
2659 165 : this->TowerType == DataPlant::PlantEquipmentType::CoolingTower_VarSpd) {
2660 707 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
2661 274 : BaseSizer::reportSizerOutput(state,
2662 137 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
2663 : this->Name,
2664 : "Design Air Flow Rate [m3/s]",
2665 : this->HighSpeedAirFlowRate);
2666 : }
2667 707 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
2668 22 : BaseSizer::reportSizerOutput(state,
2669 11 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
2670 : this->Name,
2671 : "Initial Design Air Flow Rate [m3/s]",
2672 : this->HighSpeedAirFlowRate);
2673 : }
2674 45 : } else if (this->TowerType == DataPlant::PlantEquipmentType::CoolingTower_TwoSpd) {
2675 45 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
2676 18 : BaseSizer::reportSizerOutput(state,
2677 9 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
2678 : this->Name,
2679 : "Air Flow Rate at High Fan Speed [m3/s]",
2680 : this->HighSpeedAirFlowRate);
2681 : }
2682 45 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
2683 0 : BaseSizer::reportSizerOutput(state,
2684 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
2685 : this->Name,
2686 : "Initial Air Flow Rate at High Fan Speed [m3/s]",
2687 : this->HighSpeedAirFlowRate);
2688 : }
2689 : }
2690 : }
2691 :
2692 1362 : if (this->HighSpeedTowerUAWasAutoSized) {
2693 612 : if (PltSizCondNum > 0) {
2694 612 : if (PlantSizData(PltSizCondNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
2695 391 : Real64 const rho = FluidProperties::GetDensityGlycol(state,
2696 391 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
2697 : Constant::InitConvTemp,
2698 391 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
2699 : RoutineName);
2700 391 : Real64 const Cp = FluidProperties::GetSpecificHeatGlycol(state,
2701 391 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
2702 : DesTowerExitWaterTemp,
2703 391 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
2704 : RoutineName);
2705 391 : DesTowerLoad = rho * Cp * tmpDesignWaterFlowRate * DesTowerWaterDeltaT;
2706 : // This conditional statement is to trap when the user specified condenser/tower water design setpoint
2707 : // temperature is less than design inlet air wet bulb temperature
2708 391 : if (PlantSizData(PltSizCondNum).ExitTemp <= this->DesInletAirWBTemp) {
2709 0 : ShowSevereError(state,
2710 0 : format("Error when autosizing the UA value for cooling tower = {}. Design Loop Exit Temperature must be "
2711 : "greater than {:.2T} C when autosizing the tower UA.",
2712 0 : this->Name,
2713 0 : this->DesInletAirWBTemp));
2714 0 : ShowContinueError(state,
2715 0 : format("The Design Loop Exit Temperature specified in Sizing:Plant object = {} ({:.2T} C)",
2716 0 : PlantSizData(PltSizCondNum).PlantLoopName,
2717 0 : PlantSizData(PltSizCondNum).ExitTemp));
2718 0 : ShowContinueError(
2719 : state,
2720 0 : format("is less than or equal to the design inlet air wet-bulb temperature of {:.2T} C.", this->DesInletAirWBTemp));
2721 0 : ShowContinueError(state,
2722 0 : format("If using HVACTemplate:Plant:ChilledWaterLoop, then check that input field Condenser Water Design "
2723 : "Setpoint must be > {:.2T} C if autosizing the cooling tower.",
2724 0 : this->DesInletAirWBTemp));
2725 0 : ShowFatalError(state, format("Autosizing of cooling tower fails for tower = {}.", this->Name));
2726 : }
2727 :
2728 391 : Real64 const solveDesignWaterMassFlow = rho * tmpDesignWaterFlowRate; // design water mass flow rate
2729 391 : UA0 = 0.0001 * DesTowerLoad; // Assume deltaT = 10000K (limit)
2730 391 : UA1 = DesTowerLoad; // Assume deltaT = 1K
2731 391 : this->WaterTemp = DesTowerInletWaterTemp;
2732 391 : this->AirTemp = this->DesInletAirDBTemp; // 35.0;
2733 391 : this->AirWetBulb = this->DesInletAirWBTemp; // 25.6;
2734 391 : this->AirPress = state.dataEnvrn->StdBaroPress;
2735 391 : this->AirHumRat = Psychrometrics::PsyWFnTdbTwbPb(state, this->AirTemp, this->AirWetBulb, this->AirPress);
2736 19360 : auto f1 = [&state, this, DesTowerLoad, solveDesignWaterMassFlow, tmpHighSpeedAirFlowRate, Cp](Real64 UA) {
2737 : Real64 const OutWaterTemp =
2738 9680 : this->calculateSimpleTowerOutletTemp(state, solveDesignWaterMassFlow, tmpHighSpeedAirFlowRate, UA);
2739 9680 : Real64 const CoolingOutput = Cp * solveDesignWaterMassFlow * (this->WaterTemp - OutWaterTemp); // tower cooling output [W]
2740 9680 : return (DesTowerLoad - CoolingOutput) / DesTowerLoad;
2741 391 : };
2742 391 : General::SolveRoot(state, Acc, MaxIte, SolFla, UA, f1, UA0, UA1);
2743 391 : if (SolFla == -1) {
2744 0 : ShowSevereError(state, "Iteration limit exceeded in calculating tower UA");
2745 0 : ShowFatalError(state, format("Autosizing of cooling tower UA failed for tower {}", this->Name));
2746 391 : } else if (SolFla == -2) {
2747 0 : ShowSevereError(state, "Bad starting values for UA");
2748 0 : ShowFatalError(state, format("Autosizing of cooling tower UA failed for tower {}", this->Name));
2749 : }
2750 :
2751 391 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
2752 140 : this->HighSpeedTowerUA = UA;
2753 : }
2754 391 : this->TowerNominalCapacity = DesTowerLoad / this->HeatRejectCapNomCapSizingRatio;
2755 : } else {
2756 221 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
2757 0 : this->HighSpeedTowerUA = 0.0;
2758 : }
2759 : }
2760 612 : if (this->TowerType == DataPlant::PlantEquipmentType::CoolingTower_SingleSpd) {
2761 572 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
2762 220 : BaseSizer::reportSizerOutput(state,
2763 110 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
2764 : this->Name,
2765 : "U-Factor Times Area Value at Design Air Flow Rate [W/C]",
2766 : this->HighSpeedTowerUA);
2767 : }
2768 572 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
2769 22 : BaseSizer::reportSizerOutput(state,
2770 11 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
2771 : this->Name,
2772 : "Initial U-Factor Times Area Value at Design Air Flow Rate [W/C]",
2773 : this->HighSpeedTowerUA);
2774 : }
2775 40 : } else if (this->TowerType == DataPlant::PlantEquipmentType::CoolingTower_TwoSpd) {
2776 40 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
2777 16 : BaseSizer::reportSizerOutput(state,
2778 8 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
2779 : this->Name,
2780 : "U-Factor Times Area Value at High Fan Speed [W/C]",
2781 : this->HighSpeedTowerUA);
2782 : }
2783 40 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
2784 0 : BaseSizer::reportSizerOutput(state,
2785 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
2786 : this->Name,
2787 : "Initial U-Factor Times Area Value at High Fan Speed [W/C]",
2788 : this->HighSpeedTowerUA);
2789 : }
2790 : }
2791 : } else {
2792 0 : if (this->DesignWaterFlowRate >= HVAC::SmallWaterVolFlow) {
2793 :
2794 0 : Real64 const rho = FluidProperties::GetDensityGlycol(state,
2795 0 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
2796 : Constant::InitConvTemp,
2797 0 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
2798 : RoutineName);
2799 0 : Real64 const Cp = FluidProperties::GetSpecificHeatGlycol(state,
2800 0 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
2801 : DesTowerExitWaterTemp,
2802 0 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
2803 : RoutineName);
2804 0 : DesTowerLoad = rho * Cp * tmpDesignWaterFlowRate * DesTowerWaterDeltaT;
2805 : // This conditional statement is to trap when the user specified condenser/tower water design setpoint
2806 : // temperature is less than design inlet air wet bulb temperature
2807 : // Note JM 2018-11-22
2808 : // * If actually user-specified:
2809 : // this->DesOutletWaterTemp = this->DesInletAirWBTemp
2810 : // + this->DesApproach;
2811 : // DesTowerExitWaterTemp = this->DesOutletWaterTemp;
2812 : // => This basically means that approach is negative, which is impossible (must be > 0 per IDD)
2813 : // * If not, hardcoded above to 21C
2814 0 : if (DesTowerExitWaterTemp <= this->DesInletAirWBTemp) {
2815 0 : ShowSevereError(state,
2816 0 : format("Error when autosizing the UA value for cooling tower = {}. Design Tower Exit Temperature must be "
2817 : "greater than {:.2T} C when autosizing the tower UA.",
2818 0 : this->Name,
2819 0 : this->DesInletAirWBTemp));
2820 0 : ShowContinueError(state, format("The User-specified Design Loop Exit Temperature={:.2T}", DesTowerExitWaterTemp));
2821 0 : ShowContinueError(
2822 : state,
2823 0 : format("is less than or equal to the design inlet air wet-bulb temperature of {:.2T} C.", this->DesInletAirWBTemp));
2824 :
2825 0 : if (this->TowerInletCondsAutoSize) {
2826 0 : ShowContinueError(state,
2827 0 : format("Because you did not specify the Design Approach Temperature, and you do not have a "
2828 : "Sizing:Plant object, it was defaulted to {:.2T} C.",
2829 : DesTowerExitWaterTemp));
2830 : } else {
2831 : // Should never get there...
2832 0 : ShowContinueError(state,
2833 0 : format("The Design Loop Exit Temperature is the sum of the design air inlet wet-bulb temperature= "
2834 : "{:.2T} C plus the cooling tower design approach temperature = {:.2T}C.",
2835 0 : this->DesInletAirWBTemp,
2836 0 : this->DesApproach));
2837 : }
2838 0 : ShowContinueError(state,
2839 0 : format("If using HVACTemplate:Plant:ChilledWaterLoop, then check that input field Condenser Water Design "
2840 : "Setpoint must be > {:.2T} C if autosizing the cooling tower.",
2841 0 : this->DesInletAirWBTemp));
2842 0 : ShowFatalError(state, format("Autosizing of cooling tower fails for tower = {}.", this->Name));
2843 : }
2844 :
2845 0 : Real64 const solveWaterMassFlow = rho * tmpDesignWaterFlowRate; // design water mass flow rate
2846 0 : UA0 = 0.0001 * DesTowerLoad; // Assume deltaT = 10000K (limit)
2847 0 : UA1 = DesTowerLoad; // Assume deltaT = 1K
2848 0 : this->WaterTemp = DesTowerInletWaterTemp;
2849 0 : this->AirTemp = this->DesInletAirDBTemp; // 35.0;
2850 0 : this->AirWetBulb = this->DesInletAirWBTemp; // 25.6;
2851 0 : this->AirPress = state.dataEnvrn->StdBaroPress;
2852 0 : this->AirHumRat = Psychrometrics::PsyWFnTdbTwbPb(state, this->AirTemp, this->AirWetBulb, this->AirPress);
2853 0 : auto f = [&state, this, DesTowerLoad, solveWaterMassFlow, tmpHighSpeedAirFlowRate, Cp](Real64 UA) {
2854 0 : Real64 const OutWaterTemp = this->calculateSimpleTowerOutletTemp(state, solveWaterMassFlow, tmpHighSpeedAirFlowRate, UA);
2855 0 : Real64 const CoolingOutput = Cp * solveWaterMassFlow * (this->WaterTemp - OutWaterTemp); // tower cooling output [W]
2856 0 : return (DesTowerLoad - CoolingOutput) / DesTowerLoad;
2857 0 : };
2858 0 : General::SolveRoot(state, Acc, MaxIte, SolFla, UA, f, UA0, UA1);
2859 0 : if (SolFla == -1) {
2860 0 : ShowSevereError(state, "Iteration limit exceeded in calculating tower UA");
2861 0 : ShowFatalError(state, format("Autosizing of cooling tower UA failed for tower {}", this->Name));
2862 0 : } else if (SolFla == -2) {
2863 0 : ShowSevereError(state, "Bad starting values for UA");
2864 0 : ShowFatalError(state, format("Autosizing of cooling tower UA failed for tower {}", this->Name));
2865 : }
2866 :
2867 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
2868 0 : this->HighSpeedTowerUA = UA;
2869 : }
2870 0 : this->TowerNominalCapacity = DesTowerLoad / this->HeatRejectCapNomCapSizingRatio;
2871 : } else {
2872 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
2873 0 : this->HighSpeedTowerUA = 0.0;
2874 : }
2875 : }
2876 0 : if (this->TowerType == DataPlant::PlantEquipmentType::CoolingTower_SingleSpd) {
2877 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
2878 0 : BaseSizer::reportSizerOutput(state,
2879 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
2880 : this->Name,
2881 : "U-Factor Times Area Value at Design Air Flow Rate [W/C]",
2882 : this->HighSpeedTowerUA);
2883 : }
2884 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
2885 0 : BaseSizer::reportSizerOutput(state,
2886 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
2887 : this->Name,
2888 : "Initial U-Factor Times Area Value at Design Air Flow Rate [W/C]",
2889 : this->HighSpeedTowerUA);
2890 : }
2891 0 : } else if (this->TowerType == DataPlant::PlantEquipmentType::CoolingTower_TwoSpd) {
2892 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
2893 0 : BaseSizer::reportSizerOutput(state,
2894 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
2895 : this->Name,
2896 : "U-Factor Times Area Value at High Fan Speed [W/C]",
2897 : this->HighSpeedTowerUA);
2898 : }
2899 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
2900 0 : BaseSizer::reportSizerOutput(state,
2901 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
2902 : this->Name,
2903 : "Initial U-Factor Times Area Value at High Fan Speed [W/C]",
2904 : this->HighSpeedTowerUA);
2905 : }
2906 : }
2907 : }
2908 : }
2909 :
2910 1362 : if (this->PerformanceInputMethod_Num == PIM::NominalCapacity) {
2911 40 : if (this->DesignWaterFlowRate >= HVAC::SmallWaterVolFlow) {
2912 : // nominal capacity doesn't include compressor heat; predefined factor was 1.25 W heat rejection per W of delivered cooling but now is
2913 : // a user input
2914 40 : Real64 const rho = FluidProperties::GetDensityGlycol(state,
2915 40 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
2916 : 29.44,
2917 40 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
2918 : RoutineName); // 85F design exiting water temp
2919 40 : Real64 const Cp = FluidProperties::GetSpecificHeatGlycol(state,
2920 40 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
2921 : 29.44,
2922 40 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
2923 : RoutineName); // 85F design exiting water temp
2924 :
2925 40 : DesTowerLoad = this->TowerNominalCapacity * this->HeatRejectCapNomCapSizingRatio;
2926 40 : Real64 const solveWaterFlowRate = rho * tmpDesignWaterFlowRate; // design water mass flow rate
2927 40 : UA0 = 0.0001 * DesTowerLoad; // Assume deltaT = 10000K (limit)
2928 40 : UA1 = DesTowerLoad; // Assume deltaT = 1K
2929 40 : this->WaterTemp = this->DesInletWaterTemp; // 35.0; // 95F design inlet water temperature
2930 40 : this->AirTemp = this->DesInletAirDBTemp; // 95F design inlet air dry-bulb temp
2931 40 : this->AirWetBulb = this->DesInletAirWBTemp; // 78F design inlet air wet-bulb temp
2932 40 : this->AirPress = state.dataEnvrn->StdBaroPress;
2933 40 : this->AirHumRat = Psychrometrics::PsyWFnTdbTwbPb(state, this->AirTemp, this->AirWetBulb, this->AirPress);
2934 2010 : auto f = [&state, this, DesTowerLoad, solveWaterFlowRate, tmpHighSpeedAirFlowRate, Cp](Real64 UA) {
2935 1005 : Real64 const OutWaterTemp = this->calculateSimpleTowerOutletTemp(state, solveWaterFlowRate, tmpHighSpeedAirFlowRate, UA);
2936 1005 : Real64 const CoolingOutput = Cp * solveWaterFlowRate * (this->WaterTemp - OutWaterTemp); // tower cooling output [W]
2937 1005 : return (DesTowerLoad - CoolingOutput) / DesTowerLoad;
2938 40 : };
2939 40 : General::SolveRoot(state, Acc, MaxIte, SolFla, UA, f, UA0, UA1);
2940 40 : if (SolFla == -1) {
2941 0 : ShowSevereError(state, "Iteration limit exceeded in calculating tower UA");
2942 0 : ShowFatalError(state, format("Autosizing of cooling tower UA failed for tower {}", this->Name));
2943 40 : } else if (SolFla == -2) {
2944 0 : ShowSevereError(state, "Bad starting values for UA");
2945 0 : ShowFatalError(state, format("Autosizing of cooling tower UA failed for tower {}", this->Name));
2946 : }
2947 40 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
2948 8 : this->HighSpeedTowerUA = UA;
2949 : }
2950 : } else {
2951 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
2952 0 : this->HighSpeedTowerUA = 0.0;
2953 : }
2954 : }
2955 40 : if (this->TowerType == DataPlant::PlantEquipmentType::CoolingTower_SingleSpd) {
2956 15 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
2957 6 : BaseSizer::reportSizerOutput(state,
2958 3 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
2959 : this->Name,
2960 : "U-Factor Times Area Value at Design Air Flow Rate [W/C]",
2961 : this->HighSpeedTowerUA);
2962 : }
2963 15 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
2964 0 : BaseSizer::reportSizerOutput(state,
2965 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
2966 : this->Name,
2967 : "Initial U-Factor Times Area Value at Design Air Flow Rate [W/C]",
2968 : this->HighSpeedTowerUA);
2969 : }
2970 25 : } else if (this->TowerType == DataPlant::PlantEquipmentType::CoolingTower_TwoSpd) {
2971 25 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
2972 10 : BaseSizer::reportSizerOutput(state,
2973 5 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
2974 : this->Name,
2975 : "U-Factor Times Area Value at High Fan Speed [W/C]",
2976 : this->HighSpeedTowerUA);
2977 : }
2978 25 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
2979 0 : BaseSizer::reportSizerOutput(state,
2980 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
2981 : this->Name,
2982 : "Initial U-Factor Times Area Value at High Fan Speed [W/C]",
2983 : this->HighSpeedTowerUA);
2984 : }
2985 : }
2986 : }
2987 :
2988 1362 : if (this->LowSpeedAirFlowRateWasAutoSized) {
2989 :
2990 45 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
2991 9 : this->LowSpeedAirFlowRate = this->LowSpeedAirFlowRateSizingFactor * this->HighSpeedAirFlowRate;
2992 9 : tmpLowSpeedAirFlowRate = this->LowSpeedAirFlowRate;
2993 9 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
2994 18 : BaseSizer::reportSizerOutput(state,
2995 9 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
2996 : this->Name,
2997 : "Low Fan Speed Air Flow Rate [m3/s]",
2998 : this->LowSpeedAirFlowRate);
2999 : }
3000 9 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
3001 0 : BaseSizer::reportSizerOutput(state,
3002 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3003 : this->Name,
3004 : "Initial Low Fan Speed Air Flow Rate [m3/s]",
3005 : this->LowSpeedAirFlowRate);
3006 : }
3007 : } else {
3008 36 : tmpLowSpeedAirFlowRate = this->LowSpeedAirFlowRateSizingFactor * tmpHighSpeedAirFlowRate;
3009 : }
3010 : }
3011 :
3012 1362 : if (this->LowSpeedFanPowerWasAutoSized) {
3013 45 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
3014 9 : this->LowSpeedFanPower = this->LowSpeedFanPowerSizingFactor * this->HighSpeedFanPower;
3015 9 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3016 18 : BaseSizer::reportSizerOutput(state,
3017 9 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3018 : this->Name,
3019 : "Fan Power at Low Fan Speed [W]",
3020 : this->LowSpeedFanPower);
3021 : }
3022 9 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
3023 0 : BaseSizer::reportSizerOutput(state,
3024 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3025 : this->Name,
3026 : "Initial Fan Power at Low Fan Speed [W]",
3027 : this->LowSpeedFanPower);
3028 : }
3029 : }
3030 : }
3031 :
3032 1362 : if (this->LowSpeedTowerUAWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
3033 8 : this->LowSpeedTowerUA = this->LowSpeedTowerUASizingFactor * this->HighSpeedTowerUA;
3034 8 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3035 16 : BaseSizer::reportSizerOutput(state,
3036 8 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3037 : this->Name,
3038 : "U-Factor Times Area Value at Low Fan Speed [W/K]",
3039 : this->LowSpeedTowerUA);
3040 : }
3041 8 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
3042 0 : BaseSizer::reportSizerOutput(state,
3043 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3044 : this->Name,
3045 : "Initial U-Factor Times Area Value at Low Fan Speed [W/K]",
3046 : this->LowSpeedTowerUA);
3047 : }
3048 : }
3049 :
3050 1362 : if (this->PerformanceInputMethod_Num == PIM::NominalCapacity) {
3051 40 : if (this->TowerLowSpeedNomCapWasAutoSized) {
3052 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
3053 0 : this->TowerLowSpeedNomCap = this->TowerLowSpeedNomCapSizingFactor * this->TowerNominalCapacity;
3054 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3055 0 : BaseSizer::reportSizerOutput(state,
3056 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3057 : this->Name,
3058 : "Low Speed Nominal Capacity [W]",
3059 : this->TowerLowSpeedNomCap);
3060 : }
3061 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
3062 0 : BaseSizer::reportSizerOutput(state,
3063 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3064 : this->Name,
3065 : "Initial Low Speed Nominal Capacity [W]",
3066 : this->TowerLowSpeedNomCap);
3067 : }
3068 : }
3069 : }
3070 40 : if (this->TowerFreeConvNomCapWasAutoSized) {
3071 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
3072 0 : this->TowerFreeConvNomCap = this->TowerFreeConvNomCapSizingFactor * this->TowerNominalCapacity;
3073 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3074 0 : BaseSizer::reportSizerOutput(state,
3075 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3076 : this->Name,
3077 : "Free Convection Nominal Capacity [W]",
3078 : this->TowerFreeConvNomCap);
3079 : }
3080 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
3081 0 : BaseSizer::reportSizerOutput(state,
3082 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3083 : this->Name,
3084 : "Initial Free Convection Nominal Capacity [W]",
3085 : this->TowerFreeConvNomCap);
3086 : }
3087 : }
3088 : }
3089 : }
3090 :
3091 1402 : if (this->PerformanceInputMethod_Num == PIM::NominalCapacity &&
3092 1402 : Util::SameString(DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)], "CoolingTower:TwoSpeed")) {
3093 25 : if (this->DesignWaterFlowRate >= HVAC::SmallWaterVolFlow && this->TowerLowSpeedNomCap > 0.0) {
3094 :
3095 : // nominal capacity doesn't include compressor heat; predefined factor was 1.25 W heat rejection per W of evap cooling but now is a
3096 : // user input
3097 25 : Real64 const rho = FluidProperties::GetDensityGlycol(state,
3098 25 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
3099 : 29.44,
3100 25 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
3101 : RoutineName); // 85F design exiting water temp
3102 25 : Real64 const Cp = FluidProperties::GetSpecificHeatGlycol(state,
3103 25 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
3104 : 29.44,
3105 25 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
3106 : RoutineName); // 85F design exiting water temp
3107 25 : DesTowerLoad = this->TowerLowSpeedNomCap * this->HeatRejectCapNomCapSizingRatio;
3108 25 : Real64 const solveWaterFlow = rho * tmpDesignWaterFlowRate; // design water mass flow rate
3109 25 : UA0 = 0.0001 * DesTowerLoad; // Assume deltaT = 10000K (limit)
3110 25 : UA1 = DesTowerLoad; // Assume deltaT = 1K
3111 25 : this->WaterTemp = this->DesInletWaterTemp; // 35.0; // 95F design inlet water temperature
3112 25 : this->AirTemp = this->DesInletAirDBTemp; // 35.0; // 95F design inlet air dry-bulb temp
3113 25 : this->AirWetBulb = this->DesInletAirWBTemp; // 25.6; // 78F design inlet air wet-bulb temp
3114 25 : this->AirPress = state.dataEnvrn->StdBaroPress;
3115 25 : this->AirHumRat = Psychrometrics::PsyWFnTdbTwbPb(state, this->AirTemp, this->AirWetBulb, this->AirPress);
3116 700 : auto f = [&state, this, DesTowerLoad, solveWaterFlow, tmpLowSpeedAirFlowRate, Cp](Real64 UA) {
3117 350 : Real64 const OutWaterTemp = this->calculateSimpleTowerOutletTemp(state, solveWaterFlow, tmpLowSpeedAirFlowRate, UA);
3118 350 : Real64 const CoolingOutput = Cp * solveWaterFlow * (this->WaterTemp - OutWaterTemp); // tower cooling output [W]
3119 350 : return (DesTowerLoad - CoolingOutput) / DesTowerLoad;
3120 25 : };
3121 25 : General::SolveRoot(state, Acc, MaxIte, SolFla, UA, f, UA0, UA1);
3122 25 : if (SolFla == -1) {
3123 0 : ShowSevereError(state, "Iteration limit exceeded in calculating tower UA");
3124 0 : ShowFatalError(state, format("Autosizing of cooling tower UA failed for tower {}", this->Name));
3125 25 : } else if (SolFla == -2) {
3126 0 : ShowSevereError(state, "Bad starting values for UA");
3127 0 : ShowFatalError(state, format("Autosizing of cooling tower UA failed for tower {}", this->Name));
3128 : }
3129 25 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
3130 5 : this->LowSpeedTowerUA = UA;
3131 : }
3132 25 : } else {
3133 0 : this->LowSpeedTowerUA = 0.0;
3134 : }
3135 25 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3136 10 : BaseSizer::reportSizerOutput(state,
3137 5 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3138 : this->Name,
3139 : "Low Fan Speed U-Factor Times Area Value [W/K]",
3140 : this->LowSpeedTowerUA);
3141 : }
3142 25 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
3143 0 : BaseSizer::reportSizerOutput(state,
3144 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3145 : this->Name,
3146 : "Initial Low Fan Speed U-Factor Times Area Value [W/K]",
3147 : this->LowSpeedTowerUA);
3148 : }
3149 : }
3150 :
3151 1362 : if (this->FreeConvAirFlowRateWasAutoSized) {
3152 336 : this->FreeConvAirFlowRate = this->FreeConvAirFlowRateSizingFactor * tmpHighSpeedAirFlowRate;
3153 336 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
3154 80 : this->FreeConvAirFlowRate = this->FreeConvAirFlowRateSizingFactor * this->HighSpeedAirFlowRate;
3155 80 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3156 128 : BaseSizer::reportSizerOutput(state,
3157 64 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3158 : this->Name,
3159 : "Free Convection Regime Air Flow Rate [m3/s]",
3160 : this->FreeConvAirFlowRate);
3161 : }
3162 80 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
3163 16 : BaseSizer::reportSizerOutput(state,
3164 8 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3165 : this->Name,
3166 : "Initial Free Convection Regime Air Flow Rate [m3/s]",
3167 : this->FreeConvAirFlowRate);
3168 : }
3169 : }
3170 : }
3171 :
3172 1362 : if (this->FreeConvTowerUAWasAutoSized) {
3173 331 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
3174 79 : this->FreeConvTowerUA = this->FreeConvTowerUASizingFactor * this->HighSpeedTowerUA;
3175 79 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3176 126 : BaseSizer::reportSizerOutput(state,
3177 63 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3178 : this->Name,
3179 : "Free Convection U-Factor Times Area Value [W/K]",
3180 : this->FreeConvTowerUA);
3181 : }
3182 79 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
3183 16 : BaseSizer::reportSizerOutput(state,
3184 8 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3185 : this->Name,
3186 : "Initial Free Convection U-Factor Times Area Value [W/K]",
3187 : this->FreeConvTowerUA);
3188 : }
3189 : }
3190 : }
3191 :
3192 1362 : if (this->PerformanceInputMethod_Num == PIM::NominalCapacity) {
3193 40 : if (this->DesignWaterFlowRate >= HVAC::SmallWaterVolFlow && this->TowerFreeConvNomCap > 0.0) {
3194 : // nominal capacity doesn't include compressor heat; predefined factor was 1.25 W heat rejection per W of evap cooling but now user
3195 : // input
3196 25 : Real64 const rho = FluidProperties::GetDensityGlycol(state,
3197 25 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
3198 : 29.44,
3199 25 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
3200 : RoutineName); // 85F design exiting water temp
3201 25 : Real64 const Cp = FluidProperties::GetSpecificHeatGlycol(state,
3202 25 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
3203 : 29.44,
3204 25 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
3205 : RoutineName); // 85F design exiting water temp
3206 25 : DesTowerLoad = this->TowerFreeConvNomCap * this->HeatRejectCapNomCapSizingRatio;
3207 25 : Real64 const solveWaterFlow = rho * this->DesignWaterFlowRate; // design water mass flow rate
3208 25 : UA0 = 0.0001 * DesTowerLoad; // Assume deltaT = 10000K (limit)
3209 25 : UA1 = DesTowerLoad; // Assume deltaT = 1K
3210 25 : this->WaterTemp = this->DesInletWaterTemp; // 35.0; // 95F design inlet water temperature
3211 25 : this->AirTemp = this->DesInletAirDBTemp; // 35.0; // 95F design inlet air dry-bulb temp
3212 25 : this->AirWetBulb = this->DesInletAirWBTemp; // 25.6; // 78F design inlet air wet-bulb temp
3213 25 : this->AirPress = state.dataEnvrn->StdBaroPress;
3214 25 : this->AirHumRat = Psychrometrics::PsyWFnTdbTwbPb(state, this->AirTemp, this->AirWetBulb, this->AirPress);
3215 560 : auto f = [&state, this, DesTowerLoad, solveWaterFlow, Cp](Real64 UA) {
3216 280 : Real64 const OutWaterTemp = this->calculateSimpleTowerOutletTemp(state, solveWaterFlow, this->FreeConvAirFlowRate, UA);
3217 280 : Real64 const CoolingOutput = Cp * solveWaterFlow * (this->WaterTemp - OutWaterTemp); // tower cooling output [W]
3218 280 : return (DesTowerLoad - CoolingOutput) / DesTowerLoad;
3219 25 : };
3220 25 : General::SolveRoot(state, Acc, MaxIte, SolFla, UA, f, UA0, UA1);
3221 25 : if (SolFla == -1) {
3222 0 : ShowSevereError(state, "Iteration limit exceeded in calculating tower UA");
3223 0 : ShowFatalError(state, format("Autosizing of cooling tower UA failed for tower {}", this->Name));
3224 25 : } else if (SolFla == -2) {
3225 0 : ShowSevereError(state, "Bad starting values for UA calculations");
3226 0 : ShowContinueError(state, "Tower inlet design water temperature assumed to be 35.0 C.");
3227 0 : ShowContinueError(state, "Tower inlet design air dry-bulb temperature assumed to be 35.0 C.");
3228 0 : ShowContinueError(state, "Tower inlet design air wet-bulb temperature assumed to be 25.6 C.");
3229 0 : ShowContinueError(state,
3230 0 : format("Tower load assumed to be {:.3T} times free convection capacity of {:.0T} W.",
3231 0 : this->HeatRejectCapNomCapSizingRatio,
3232 0 : this->TowerFreeConvNomCap));
3233 :
3234 : Real64 OutWaterTemp; // outlet water temperature during sizing [C]
3235 :
3236 0 : OutWaterTemp = this->calculateSimpleTowerOutletTemp(state, solveWaterFlow, this->FreeConvAirFlowRate, UA0);
3237 0 : Real64 CoolingOutput = Cp * solveWaterFlow * (this->WaterTemp - OutWaterTemp); // tower capacity during sizing [W]
3238 0 : ShowContinueError(state, format("Tower capacity at lower UA guess ({:.4T}) = {:.0T} W.", UA0, CoolingOutput));
3239 :
3240 0 : OutWaterTemp = this->calculateSimpleTowerOutletTemp(state, solveWaterFlow, this->FreeConvAirFlowRate, UA1);
3241 0 : CoolingOutput = Cp * solveWaterFlow * (this->WaterTemp - OutWaterTemp);
3242 0 : ShowContinueError(state, format("Tower capacity at upper UA guess ({:.4T}) = {:.0T} W.", UA1, CoolingOutput));
3243 :
3244 0 : if (CoolingOutput < DesTowerLoad) {
3245 0 : ShowContinueError(state, "Free convection capacity should be less than tower capacity at upper UA guess.");
3246 : }
3247 0 : ShowFatalError(state, format("Autosizing of cooling tower UA failed for tower {}", this->Name));
3248 : }
3249 25 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
3250 5 : this->FreeConvTowerUA = UA;
3251 : }
3252 25 : } else {
3253 15 : this->FreeConvTowerUA = 0.0;
3254 : }
3255 40 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3256 16 : BaseSizer::reportSizerOutput(state,
3257 8 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3258 : this->Name,
3259 : "U-Factor Times Area Value at Free Convection Air Flow Rate [W/C]",
3260 : this->FreeConvTowerUA);
3261 : }
3262 40 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
3263 0 : BaseSizer::reportSizerOutput(state,
3264 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3265 : this->Name,
3266 : "Initial U-Factor Times Area Value at Free Convection Air Flow Rate [W/C]",
3267 : this->FreeConvTowerUA);
3268 : }
3269 : }
3270 :
3271 : // calibrate variable speed tower model based on user input by finding calibration water flow rate ratio that
3272 : // yields an approach temperature that matches user input
3273 1362 : if (Util::SameString(DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)], "CoolingTower:VariableSpeed")) {
3274 :
3275 : // check range for water flow rate ratio (make sure RegulaFalsi converges)
3276 120 : Real64 MaxWaterFlowRateRatio = 0.5; // maximum water flow rate ratio which yields desired approach temp
3277 120 : Real64 Tapproach = 0.0; // temporary tower approach temp variable [C]
3278 120 : Real64 const FlowRateRatioStep = (state.dataCondenserLoopTowers->towers(this->VSTower).MaxWaterFlowRatio -
3279 120 : state.dataCondenserLoopTowers->towers(this->VSTower).MinWaterFlowRatio) /
3280 120 : 10.0;
3281 120 : bool ModelCalibrated = true;
3282 120 : Real64 ModelWaterFlowRatioMax = state.dataCondenserLoopTowers->towers(this->VSTower).MaxWaterFlowRatio *
3283 120 : 4.0; // maximum water flow rate ratio used for model calibration
3284 : // find a flow rate large enough to provide an approach temperature > than the user defined approach
3285 120 : Real64 WaterFlowRateRatio(0.0); // tower water flow rate ratio
3286 1285 : while (Tapproach < this->DesignApproach && MaxWaterFlowRateRatio <= ModelWaterFlowRatioMax) {
3287 1165 : WaterFlowRateRatio = MaxWaterFlowRateRatio;
3288 1165 : Tapproach = this->calculateVariableSpeedApproach(state, WaterFlowRateRatio, 1.0, this->DesignInletWB, this->DesignRange);
3289 1165 : if (Tapproach < this->DesignApproach) {
3290 1045 : MaxWaterFlowRateRatio += FlowRateRatioStep;
3291 : }
3292 : // a water flow rate large enough to provide an approach temperature > than the user defined approach does not exist
3293 : // within the tolerances specified by the user
3294 1165 : if ((MaxWaterFlowRateRatio == 0.5 && Tapproach > this->DesignApproach) || MaxWaterFlowRateRatio >= ModelWaterFlowRatioMax) {
3295 0 : ModelCalibrated = false;
3296 0 : break;
3297 : }
3298 : }
3299 :
3300 120 : Real64 WaterFlowRatio(0.0); // tower water flow rate ratio found during model calibration
3301 :
3302 120 : if (ModelCalibrated) {
3303 1020 : auto f = [&state, this](Real64 FlowRatio) {
3304 510 : Real64 Tact = this->calculateVariableSpeedApproach(state, FlowRatio, 1.0, this->DesignInletWB, this->DesignRange);
3305 510 : return this->DesignApproach - Tact;
3306 120 : };
3307 120 : General::SolveRoot(state, Acc, MaxIte, SolFla, WaterFlowRatio, f, DataPrecisionGlobals::constant_pointfive, MaxWaterFlowRateRatio);
3308 :
3309 120 : if (SolFla == -1) {
3310 0 : ShowSevereError(state, "Iteration limit exceeded in calculating tower water flow ratio during calibration");
3311 0 : ShowContinueError(state,
3312 : "Inlet air wet-bulb, range, and/or approach temperature does not allow calibration of water flow rate ratio "
3313 : "for this variable-speed cooling tower.");
3314 0 : ShowFatalError(state, format("Cooling tower calibration failed for tower {}", this->Name));
3315 120 : } else if (SolFla == -2) {
3316 0 : ShowSevereError(state, "Bad starting values for cooling tower water flow rate ratio calibration.");
3317 0 : ShowContinueError(state,
3318 : "Inlet air wet-bulb, range, and/or approach temperature does not allow calibration of water flow rate ratio "
3319 : "for this variable-speed cooling tower.");
3320 0 : ShowFatalError(state, format("Cooling tower calibration failed for tower {}.", this->Name));
3321 : }
3322 : } else {
3323 0 : ShowSevereError(state, "Bad starting values for cooling tower water flow rate ratio calibration.");
3324 0 : ShowContinueError(state, "Design inlet air wet-bulb or range temperature must be modified to achieve the design approach");
3325 0 : ShowContinueError(state,
3326 0 : format("A water flow rate ratio of {:.6F} was calculated to yield an approach temperature of {:.2F}.",
3327 : WaterFlowRateRatio,
3328 : Tapproach));
3329 0 : ShowFatalError(state, format("Cooling tower calibration failed for tower {}.", this->Name));
3330 : }
3331 :
3332 120 : this->CalibratedWaterFlowRate = this->DesignWaterFlowRate / WaterFlowRatio;
3333 :
3334 240 : if (WaterFlowRatio < state.dataCondenserLoopTowers->towers(this->VSTower).MinWaterFlowRatio ||
3335 120 : WaterFlowRatio > state.dataCondenserLoopTowers->towers(this->VSTower).MaxWaterFlowRatio) {
3336 0 : ShowWarningError(state,
3337 0 : format("CoolingTower:VariableSpeed, \"{}\" the calibrated water flow rate ratio is determined to be {:9.6F}. This "
3338 : "is outside the valid range of {:.2F} to {:.2F}.",
3339 0 : this->Name,
3340 : WaterFlowRatio,
3341 0 : state.dataCondenserLoopTowers->towers(this->VSTower).MinWaterFlowRatio,
3342 0 : state.dataCondenserLoopTowers->towers(this->VSTower).MaxWaterFlowRatio));
3343 : }
3344 :
3345 120 : Real64 const rho = FluidProperties::GetDensityGlycol(state,
3346 120 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
3347 120 : (this->DesignInletWB + this->DesignApproach + this->DesignRange),
3348 120 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
3349 : RoutineName);
3350 120 : Real64 const Cp = FluidProperties::GetSpecificHeatGlycol(state,
3351 120 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
3352 120 : (this->DesignInletWB + this->DesignApproach + this->DesignRange),
3353 120 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
3354 : RoutineName);
3355 :
3356 120 : this->TowerNominalCapacity = ((rho * tmpDesignWaterFlowRate) * Cp * this->DesignRange);
3357 120 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3358 48 : BaseSizer::reportSizerOutput(state,
3359 24 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3360 : this->Name,
3361 : "Nominal Capacity [W]",
3362 : this->TowerNominalCapacity);
3363 : }
3364 120 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
3365 0 : BaseSizer::reportSizerOutput(state,
3366 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3367 : this->Name,
3368 : "Initial Nominal Capacity [W]",
3369 : this->TowerNominalCapacity);
3370 : }
3371 120 : this->FreeConvAirFlowRate = this->MinimumVSAirFlowFrac * this->HighSpeedAirFlowRate;
3372 :
3373 120 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3374 48 : BaseSizer::reportSizerOutput(state,
3375 24 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3376 : this->Name,
3377 : "Air Flow Rate in free convection regime [m3/s]",
3378 : this->FreeConvAirFlowRate);
3379 : }
3380 120 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
3381 0 : BaseSizer::reportSizerOutput(state,
3382 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3383 : this->Name,
3384 : "Initial Air Flow Rate in free convection regime [m3/s]",
3385 : this->FreeConvAirFlowRate);
3386 : }
3387 120 : this->TowerFreeConvNomCap = this->TowerNominalCapacity * this->FreeConvectionCapacityFraction;
3388 :
3389 120 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3390 48 : BaseSizer::reportSizerOutput(state,
3391 24 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3392 : this->Name,
3393 : "Tower capacity in free convection regime at design conditions [W]",
3394 : this->TowerFreeConvNomCap);
3395 : }
3396 120 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
3397 0 : BaseSizer::reportSizerOutput(state,
3398 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3399 : this->Name,
3400 : "Initial Tower capacity in free convection regime at design conditions [W]",
3401 : this->TowerFreeConvNomCap);
3402 : }
3403 : }
3404 1362 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3405 : // create predefined report
3406 536 : OutputReportPredefined::PreDefTableEntry(
3407 536 : state, state.dataOutRptPredefined->pdchMechType, this->Name, DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)]);
3408 268 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchMechNomCap, this->Name, this->TowerNominalCapacity);
3409 :
3410 : // create std 229 new table for cooling towers and fluid coolers
3411 536 : OutputReportPredefined::PreDefTableEntry(
3412 536 : state, state.dataOutRptPredefined->pdchCTFCType, this->Name, DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)]);
3413 536 : OutputReportPredefined::PreDefTableEntry(state,
3414 268 : state.dataOutRptPredefined->pdchCTFCCondLoopName,
3415 : this->Name,
3416 536 : this->plantLoc.loopNum > 0 ? state.dataPlnt->PlantLoop(this->plantLoc.loopNum).Name : "N/A");
3417 536 : OutputReportPredefined::PreDefTableEntry(
3418 : state,
3419 268 : state.dataOutRptPredefined->pdchCTFCCondLoopBranchName,
3420 : this->Name,
3421 268 : this->plantLoc.loopNum > 0
3422 536 : ? state.dataPlnt->PlantLoop(plantLoc.loopNum).LoopSide(plantLoc.loopSideNum).Branch(plantLoc.branchNum).Name
3423 : : "N/A");
3424 536 : OutputReportPredefined::PreDefTableEntry(
3425 : state,
3426 268 : state.dataOutRptPredefined->pdchCTFCFluidType,
3427 : this->Name,
3428 268 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName); // Fluid Name more reasonable than FluidType
3429 268 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchCTFCRange, this->Name, this->DesignRange);
3430 268 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchCTFCApproach, this->Name, this->DesignApproach);
3431 536 : OutputReportPredefined::PreDefTableEntry(
3432 268 : state, state.dataOutRptPredefined->pdchCTFCDesFanPwr, this->Name, this->HighSpeedFanPower); // eqival to Design Fan Power?
3433 268 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchCTFCDesInletAirWBT, this->Name, this->DesInletAirWBTemp);
3434 536 : OutputReportPredefined::PreDefTableEntry(
3435 268 : state, state.dataOutRptPredefined->pdchCTFCDesWaterFlowRate, this->Name, this->DesignWaterFlowRate);
3436 268 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchCTFCLevWaterSPTemp, this->Name, this->DesOutletWaterTemp);
3437 : }
3438 :
3439 : // input error checking
3440 1362 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3441 268 : bool ErrorsFound = false;
3442 268 : if (this->TowerType == DataPlant::PlantEquipmentType::CoolingTower_SingleSpd) {
3443 231 : if (this->DesignWaterFlowRate > 0.0) {
3444 231 : if (this->FreeConvAirFlowRate >= this->HighSpeedAirFlowRate) {
3445 0 : ShowSevereError(state,
3446 0 : format("{} \"{}\". Free convection air flow rate must be less than the design air flow rate.",
3447 : cCoolingTower_SingleSpeed,
3448 0 : this->Name));
3449 0 : ErrorsFound = true;
3450 : }
3451 231 : if (this->FreeConvTowerUA >= this->HighSpeedTowerUA) {
3452 0 : ShowSevereError(
3453 : state,
3454 0 : format("{} \"{}\". Free convection UA must be less than the design tower UA.", cCoolingTower_SingleSpeed, this->Name));
3455 0 : ErrorsFound = true;
3456 : }
3457 : }
3458 : }
3459 :
3460 268 : if (this->TowerType == DataPlant::PlantEquipmentType::CoolingTower_TwoSpd) {
3461 13 : if (this->DesignWaterFlowRate > 0.0) {
3462 13 : if (this->HighSpeedAirFlowRate <= this->LowSpeedAirFlowRate) {
3463 0 : ShowSevereError(state,
3464 0 : format("{} \"{}\". Low speed air flow rate must be less than the high speed air flow rate.",
3465 : cCoolingTower_TwoSpeed,
3466 0 : this->Name));
3467 0 : ErrorsFound = true;
3468 : }
3469 13 : if (this->LowSpeedAirFlowRate <= this->FreeConvAirFlowRate) {
3470 0 : ShowSevereError(state,
3471 0 : format("{} \"{}\". Free convection air flow rate must be less than the low speed air flow rate.",
3472 : cCoolingTower_TwoSpeed,
3473 0 : this->Name));
3474 0 : ErrorsFound = true;
3475 : }
3476 13 : if (this->HighSpeedTowerUA <= this->LowSpeedTowerUA) {
3477 0 : ShowSevereError(state,
3478 0 : format("{} \"{}\". Tower UA at low fan speed must be less than the tower UA at high fan speed.",
3479 : cCoolingTower_TwoSpeed,
3480 0 : this->Name));
3481 0 : ErrorsFound = true;
3482 : }
3483 13 : if (this->LowSpeedTowerUA <= this->FreeConvTowerUA) {
3484 0 : ShowSevereError(
3485 : state,
3486 0 : format("{} \"{}\". Tower UA at free convection air flow rate must be less than the tower UA at low fan speed.",
3487 : cCoolingTower_TwoSpeed,
3488 0 : this->Name));
3489 0 : ErrorsFound = true;
3490 : }
3491 : }
3492 : }
3493 268 : if (ErrorsFound) {
3494 0 : ShowFatalError(state, "initialize: Program terminated due to previous condition(s).");
3495 : }
3496 : }
3497 1362 : }
3498 :
3499 10 : void CoolingTower::SizeVSMerkelTower(EnergyPlusData &state)
3500 : {
3501 :
3502 : // SUBROUTINE PARAMETER DEFINITIONS:
3503 10 : int constexpr MaxIte(500); // Maximum number of iterations
3504 10 : Real64 constexpr Acc(0.0001); // Accuracy of result
3505 : static constexpr std::string_view RoutineName("SizeTower");
3506 :
3507 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3508 : int SolFla; // Flag of solver
3509 : Real64 tmpHighSpeedFanPower;
3510 :
3511 : Real64 UA0; // Lower bound for UA [W/C]
3512 : Real64 UA1; // Upper bound for UA [W/C]
3513 : Real64 DesTowerLoad; // Design tower load [W]
3514 10 : Real64 Cp(0); // local specific heat for fluid
3515 10 : Real64 rho(0); // local density for fluid
3516 : Real64 UA; // Calculated UA value
3517 : Real64 DesTowerInletWaterTemp; // design tower inlet water temperature
3518 : Real64 DesTowerExitWaterTemp; // design tower exit water temperature
3519 : Real64 DesTowerWaterDeltaT; // design tower temperature range
3520 : Real64 DesTowerApproachFromPlant; // design tower approach temperature from plant sizing object
3521 10 : Real64 TolTemp(0.04); // DeltaT and DesApproach diffs tollerance between plant sizing data and user input in cooling tower
3522 : // for warning message reporting purpose only
3523 :
3524 : // Find the appropriate Plant Sizing object
3525 10 : int PltSizCondNum = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).PlantSizNum;
3526 :
3527 10 : Real64 tmpNomTowerCap = this->TowerNominalCapacity;
3528 10 : Real64 tmpDesignWaterFlowRate = this->DesignWaterFlowRate;
3529 10 : Real64 tmpTowerFreeConvNomCap = this->TowerFreeConvNomCap;
3530 10 : Real64 tmpDesignAirFlowRate = this->HighSpeedAirFlowRate;
3531 10 : Real64 tmpFreeConvAirFlowRate = this->FreeConvAirFlowRate;
3532 10 : Real64 DesTowerInletAirWBTemp = this->DesInletAirWBTemp;
3533 10 : Real64 DesTowerInletAirDBTemp = this->DesInletAirDBTemp;
3534 :
3535 10 : auto const &PlantSizData(state.dataSize->PlantSizData);
3536 :
3537 10 : if (this->TowerInletCondsAutoSize) {
3538 10 : if (PltSizCondNum > 0) {
3539 : // use plant sizing data
3540 10 : DesTowerExitWaterTemp = PlantSizData(PltSizCondNum).ExitTemp;
3541 10 : DesTowerInletWaterTemp = DesTowerExitWaterTemp + PlantSizData(PltSizCondNum).DeltaT;
3542 10 : DesTowerWaterDeltaT = PlantSizData(PltSizCondNum).DeltaT;
3543 : } else {
3544 : // set default values to replace hard wired input assumptions
3545 0 : DesTowerExitWaterTemp = this->DesOutletWaterTemp;
3546 0 : DesTowerInletWaterTemp = this->DesInletWaterTemp;
3547 0 : DesTowerWaterDeltaT = this->DesRange;
3548 : }
3549 : } else {
3550 : // use tower sizing data
3551 0 : DesTowerExitWaterTemp = this->DesOutletWaterTemp;
3552 0 : DesTowerInletWaterTemp = this->DesInletWaterTemp;
3553 0 : DesTowerWaterDeltaT = this->DesRange;
3554 0 : if (PltSizCondNum > 0) {
3555 : // check the tower range against the plant sizing data
3556 0 : if (std::abs(DesTowerWaterDeltaT - PlantSizData(PltSizCondNum).DeltaT) > TolTemp) {
3557 0 : ShowWarningError(state,
3558 0 : format("Error when autosizing the load for cooling tower = {}. Tower Design Range Temperature is different from "
3559 : "the Design Loop Delta Temperature.",
3560 0 : this->Name));
3561 0 : ShowContinueError(state, format("Tower Design Range Temperature specified in tower = {}", this->Name));
3562 0 : ShowContinueError(state,
3563 0 : format("is inconsistent with Design Loop Delta Temperature specified in Sizing:Plant object = {}.",
3564 0 : PlantSizData(PltSizCondNum).PlantLoopName));
3565 0 : ShowContinueError(state, format("..The Design Range Temperature specified in tower is = {:.2T}", this->DesRange));
3566 0 : ShowContinueError(state,
3567 0 : format("..The Design Loop Delta Temperature specified iin plant sizing data is = {:.2T}",
3568 0 : PlantSizData(PltSizCondNum).DeltaT));
3569 : }
3570 : // check if the tower approach is different from plant sizing data
3571 0 : DesTowerApproachFromPlant = PlantSizData(PltSizCondNum).ExitTemp - this->DesInletAirWBTemp;
3572 0 : if (std::abs(DesTowerApproachFromPlant - this->DesApproach) > TolTemp) {
3573 0 : ShowWarningError(state,
3574 0 : format("Error when autosizing the UA for cooling tower = {}. Tower Design Approach Temperature is inconsistent "
3575 : "with Approach from Plant Sizing Data.",
3576 0 : this->Name));
3577 0 : ShowContinueError(state,
3578 0 : format("The Design Approach Temperature from inputs specified in Sizing:Plant object = {}",
3579 0 : PlantSizData(PltSizCondNum).PlantLoopName));
3580 0 : ShowContinueError(state, format("is inconsistent with Design Approach Temperature specified in tower = {}.", this->Name));
3581 0 : ShowContinueError(state,
3582 0 : format("..The Design Approach Temperature from inputs specified is = {:.2T}", DesTowerApproachFromPlant));
3583 0 : ShowContinueError(state, format("..The Design Approach Temperature specified in tower is = {:.2T}", this->DesApproach));
3584 : }
3585 : }
3586 : }
3587 :
3588 10 : if (this->PerformanceInputMethod_Num == PIM::NominalCapacity) {
3589 :
3590 10 : if (PltSizCondNum > 0) { // get nominal capacity from PlantSizData(PltSizCondNum)%DeltaT and PlantSizData(PltSizCondNum)%DesVolFlowRate
3591 10 : if (PlantSizData(PltSizCondNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
3592 6 : rho = FluidProperties::GetDensityGlycol(state,
3593 6 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
3594 : DesTowerExitWaterTemp,
3595 6 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
3596 : RoutineName);
3597 6 : Cp = FluidProperties::GetSpecificHeatGlycol(state,
3598 6 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
3599 : DesTowerExitWaterTemp,
3600 6 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
3601 : RoutineName);
3602 6 : DesTowerLoad = rho * Cp * PlantSizData(PltSizCondNum).DesVolFlowRate * DesTowerWaterDeltaT * this->SizFac;
3603 6 : tmpNomTowerCap = DesTowerLoad / this->HeatRejectCapNomCapSizingRatio;
3604 : } else {
3605 4 : if (this->TowerNominalCapacityWasAutoSized) tmpNomTowerCap = 0.0;
3606 : }
3607 : } else { // PltSizCondNum = 0
3608 0 : if (!this->TowerInletCondsAutoSize) { // can use design data entered into tower object
3609 0 : if (this->DesignWaterFlowRate >= HVAC::SmallWaterVolFlow) {
3610 0 : rho = FluidProperties::GetDensityGlycol(state,
3611 0 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
3612 : DesTowerExitWaterTemp,
3613 0 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
3614 : RoutineName);
3615 0 : Cp = FluidProperties::GetSpecificHeatGlycol(state,
3616 0 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
3617 : DesTowerExitWaterTemp,
3618 0 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
3619 : RoutineName);
3620 0 : DesTowerLoad = rho * Cp * this->DesignWaterFlowRate * DesTowerWaterDeltaT * this->SizFac;
3621 0 : tmpNomTowerCap = DesTowerLoad / this->HeatRejectCapNomCapSizingRatio;
3622 : } else {
3623 0 : if (this->TowerNominalCapacityWasAutoSized) tmpNomTowerCap = 0.0;
3624 : }
3625 : } else { // do not have enough data to size.
3626 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize && this->TowerNominalCapacityWasAutoSized) {
3627 0 : ShowSevereError(state, format("Autosizing error for cooling tower object = {}", this->Name));
3628 0 : ShowFatalError(state, "Autosizing of cooling tower nominal capacity requires a loop Sizing:Plant object.");
3629 : }
3630 : }
3631 : }
3632 10 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
3633 2 : if (this->TowerNominalCapacityWasAutoSized) {
3634 2 : this->TowerNominalCapacity = tmpNomTowerCap;
3635 2 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3636 4 : BaseSizer::reportSizerOutput(state,
3637 2 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3638 : this->Name,
3639 : "Design Nominal Capacity [W]",
3640 : tmpNomTowerCap);
3641 : }
3642 2 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
3643 0 : BaseSizer::reportSizerOutput(state,
3644 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3645 : this->Name,
3646 : "Initial Design Nominal Capacity [W]",
3647 : this->TowerNominalCapacity);
3648 : }
3649 : } else { // Hard-sized with sizing data
3650 0 : if (this->TowerNominalCapacity > 0.0 && tmpNomTowerCap > 0.0) {
3651 0 : Real64 NomCapUser(0.0);
3652 0 : NomCapUser = this->TowerNominalCapacity;
3653 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3654 0 : BaseSizer::reportSizerOutput(state,
3655 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3656 : this->Name,
3657 : "Design Nominal Capacity [W]",
3658 : tmpNomTowerCap,
3659 : "User-Specified Nominal Capacity [W]",
3660 : NomCapUser);
3661 0 : if (state.dataGlobal->DisplayExtraWarnings) {
3662 0 : if ((std::abs(tmpNomTowerCap - NomCapUser) / NomCapUser) > state.dataSize->AutoVsHardSizingThreshold) {
3663 0 : ShowMessage(state, format("SizeVSMerkelTower: Potential issue with equipment sizing for {}", this->Name));
3664 0 : ShowContinueError(state, format("User-Specified Nominal Capacity of {:.2R} [W]", NomCapUser));
3665 0 : ShowContinueError(state, format("differs from Design Size Nominal Capacity of {:.2R} [W]", tmpNomTowerCap));
3666 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
3667 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
3668 : }
3669 : }
3670 0 : tmpNomTowerCap = NomCapUser;
3671 : }
3672 : }
3673 : }
3674 : }
3675 :
3676 10 : tmpTowerFreeConvNomCap = tmpNomTowerCap * this->TowerFreeConvNomCapSizingFactor;
3677 10 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
3678 2 : if (this->TowerFreeConvNomCapWasAutoSized) {
3679 2 : this->TowerFreeConvNomCap = tmpTowerFreeConvNomCap;
3680 2 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3681 4 : BaseSizer::reportSizerOutput(state,
3682 2 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3683 : this->Name,
3684 : "Design Free Convection Nominal Capacity [W]",
3685 : this->TowerFreeConvNomCap);
3686 : }
3687 2 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
3688 0 : BaseSizer::reportSizerOutput(state,
3689 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3690 : this->Name,
3691 : "Initial Design Free Convection Nominal Capacity [W]",
3692 : this->TowerFreeConvNomCap);
3693 : }
3694 : } else { // Hard-sized with sizing data
3695 0 : if (this->TowerFreeConvNomCap > 0.0 && tmpTowerFreeConvNomCap > 0.0) {
3696 0 : Real64 NomCapUser(0.0);
3697 0 : NomCapUser = this->TowerFreeConvNomCap;
3698 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3699 0 : BaseSizer::reportSizerOutput(state,
3700 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3701 : this->Name,
3702 : "Design Free Convection Nominal Capacity [W]",
3703 : tmpTowerFreeConvNomCap,
3704 : "User-Specified Free Convection Nominal Capacity [W]",
3705 : NomCapUser);
3706 0 : if (state.dataGlobal->DisplayExtraWarnings) {
3707 0 : if ((std::abs(tmpTowerFreeConvNomCap - NomCapUser) / NomCapUser) > state.dataSize->AutoVsHardSizingThreshold) {
3708 0 : ShowMessage(state, format("SizeVSMerkelTower: Potential issue with equipment sizing for {}", this->Name));
3709 0 : ShowContinueError(state, format("User-Specified Free Convection Nominal Capacity of {:.2R} [W]", NomCapUser));
3710 0 : ShowContinueError(
3711 : state,
3712 0 : format("differs from Design Size Free Convection Nominal Capacity of {:.2R} [W]", tmpTowerFreeConvNomCap));
3713 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
3714 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
3715 : }
3716 : }
3717 0 : tmpTowerFreeConvNomCap = NomCapUser;
3718 : }
3719 : }
3720 : }
3721 : }
3722 :
3723 10 : tmpDesignWaterFlowRate = tmpNomTowerCap * this->DesignWaterFlowPerUnitNomCap;
3724 10 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
3725 2 : if (this->DesignWaterFlowRateWasAutoSized) {
3726 : // for nominal cap input method, get design water flow rate from nominal cap and scalable sizing factor
3727 :
3728 2 : this->DesignWaterFlowRate = tmpDesignWaterFlowRate;
3729 2 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3730 4 : BaseSizer::reportSizerOutput(state,
3731 2 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3732 : this->Name,
3733 : "Design Water Flow Rate [m3/s]",
3734 : this->DesignWaterFlowRate);
3735 : }
3736 2 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
3737 0 : BaseSizer::reportSizerOutput(state,
3738 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3739 : this->Name,
3740 : "Initial Design Water Flow Rate [m3/s]",
3741 : this->DesignWaterFlowRate);
3742 : }
3743 :
3744 : } else { // Hard-sized with sizing data
3745 0 : if (this->DesignWaterFlowRate > 0.0 && tmpDesignWaterFlowRate > 0.0) {
3746 0 : Real64 NomDesWaterFlowUser(0.0);
3747 0 : NomDesWaterFlowUser = this->DesignWaterFlowRate;
3748 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3749 0 : BaseSizer::reportSizerOutput(state,
3750 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3751 : this->Name,
3752 : "Design Water Flow Rate [m3/s]",
3753 : this->DesignWaterFlowRate,
3754 : "User-Specified Design Water Flow Rate [m3/s]",
3755 : NomDesWaterFlowUser);
3756 0 : if (state.dataGlobal->DisplayExtraWarnings) {
3757 0 : if ((std::abs(tmpDesignWaterFlowRate - NomDesWaterFlowUser) / NomDesWaterFlowUser) >
3758 0 : state.dataSize->AutoVsHardSizingThreshold) {
3759 0 : ShowMessage(state, format("SizeVSMerkelTower: Potential issue with equipment sizing for {}", this->Name));
3760 0 : ShowContinueError(state, format("User-Specified Design Water Flow Rate of {:.2R} [m3/s]", NomDesWaterFlowUser));
3761 0 : ShowContinueError(state, format("differs from Design Water Flow Rate of {:.2R} [m3/s]", tmpDesignWaterFlowRate));
3762 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
3763 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
3764 : }
3765 : }
3766 0 : tmpDesignWaterFlowRate = NomDesWaterFlowUser;
3767 : }
3768 : }
3769 : }
3770 : }
3771 :
3772 10 : PlantUtilities::RegisterPlantCompDesignFlow(state, this->WaterInletNodeNum, tmpDesignWaterFlowRate);
3773 :
3774 10 : if (this->DefaultedDesignAirFlowScalingFactor) {
3775 0 : tmpDesignAirFlowRate = tmpNomTowerCap * this->DesignAirFlowPerUnitNomCap * (101325.0 / state.dataEnvrn->StdBaroPress);
3776 : } else {
3777 10 : tmpDesignAirFlowRate = tmpNomTowerCap * this->DesignAirFlowPerUnitNomCap;
3778 : }
3779 10 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
3780 2 : if (this->HighSpeedAirFlowRateWasAutoSized) {
3781 2 : this->HighSpeedAirFlowRate = tmpDesignAirFlowRate;
3782 2 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3783 4 : BaseSizer::reportSizerOutput(state,
3784 2 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3785 : this->Name,
3786 : "Design Air Flow Rate [m3/s]",
3787 : this->HighSpeedAirFlowRate);
3788 : }
3789 2 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
3790 0 : BaseSizer::reportSizerOutput(state,
3791 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3792 : this->Name,
3793 : "Initial Design Air Flow Rate [m3/s]",
3794 : this->HighSpeedAirFlowRate);
3795 : }
3796 : } else { // Hard-sized with sizing data
3797 0 : Real64 DesignAirFlowRateUser(0.0);
3798 0 : DesignAirFlowRateUser = this->HighSpeedAirFlowRate;
3799 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3800 0 : BaseSizer::reportSizerOutput(state,
3801 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3802 : this->Name,
3803 : "Design Air Flow Rate [m3/s]",
3804 : tmpDesignAirFlowRate,
3805 : "User-Specified Design Air Flow Rate [m3/s]",
3806 : DesignAirFlowRateUser);
3807 0 : if (state.dataGlobal->DisplayExtraWarnings) {
3808 0 : if ((std::abs(tmpDesignAirFlowRate - DesignAirFlowRateUser) / DesignAirFlowRateUser) >
3809 0 : state.dataSize->AutoVsHardSizingThreshold) {
3810 0 : ShowMessage(state, format("SizeVSMerkelTower: Potential issue with equipment sizing for {}", this->Name));
3811 0 : ShowContinueError(state, format("User-Specified Design Air Flow Rate of {:.2R} [m3/s]", DesignAirFlowRateUser));
3812 0 : ShowContinueError(state, format("differs from Design Air Flow Rate of {:.2R} [m3/s]", tmpDesignAirFlowRate));
3813 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
3814 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
3815 : }
3816 : }
3817 0 : tmpDesignAirFlowRate = DesignAirFlowRateUser;
3818 : }
3819 : }
3820 : }
3821 10 : tmpFreeConvAirFlowRate = tmpDesignAirFlowRate * this->FreeConvAirFlowRateSizingFactor;
3822 :
3823 10 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
3824 2 : if (this->FreeConvAirFlowRateWasAutoSized) {
3825 2 : this->FreeConvAirFlowRate = tmpFreeConvAirFlowRate;
3826 2 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3827 4 : BaseSizer::reportSizerOutput(state,
3828 2 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3829 : this->Name,
3830 : "Design Free Convection Regime Air Flow Rate [m3/s]",
3831 : this->FreeConvAirFlowRate);
3832 : }
3833 2 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
3834 0 : BaseSizer::reportSizerOutput(state,
3835 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3836 : this->Name,
3837 : "Initial Design Free Convection Regime Air Flow Rate [m3/s]",
3838 : this->FreeConvAirFlowRate);
3839 : }
3840 : } else { // Hard-sized with sizing data
3841 0 : Real64 FreeConvAirFlowUser(0.0);
3842 0 : FreeConvAirFlowUser = this->FreeConvAirFlowRate;
3843 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3844 0 : BaseSizer::reportSizerOutput(state,
3845 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3846 : this->Name,
3847 : "Design Free Convection Regime Air Flow Rate [m3/s]",
3848 : tmpFreeConvAirFlowRate,
3849 : "User-Specified Design Free Convection Regime Air Flow Rate [m3/s]",
3850 : FreeConvAirFlowUser);
3851 0 : if (state.dataGlobal->DisplayExtraWarnings) {
3852 0 : if ((std::abs(tmpFreeConvAirFlowRate - FreeConvAirFlowUser) / FreeConvAirFlowUser) >
3853 0 : state.dataSize->AutoVsHardSizingThreshold) {
3854 0 : ShowMessage(state, format("SizeVSMerkelTower: Potential issue with equipment sizing for {}", this->Name));
3855 0 : ShowContinueError(
3856 : state,
3857 0 : format("User-Specified Design Free Convection Regime Air Flow Rate of {:.2R} [m3/s]", FreeConvAirFlowUser));
3858 0 : ShowContinueError(
3859 : state,
3860 0 : format("differs from Design Free Convection Regime Air Flow Rate of {:.2R} [m3/s]", tmpFreeConvAirFlowRate));
3861 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
3862 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
3863 : }
3864 : }
3865 0 : tmpFreeConvAirFlowRate = FreeConvAirFlowUser;
3866 : }
3867 : }
3868 : }
3869 :
3870 : // now calcuate UA values from nominal capacities and flow rates
3871 10 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
3872 2 : if (PltSizCondNum > 0) { // user has a plant sizing object
3873 2 : Cp = FluidProperties::GetSpecificHeatGlycol(state,
3874 2 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
3875 : DesTowerExitWaterTemp,
3876 2 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
3877 : RoutineName);
3878 2 : this->WaterTemp = DesTowerInletWaterTemp;
3879 : } else { // probably no plant sizing object
3880 0 : Cp = FluidProperties::GetSpecificHeatGlycol(state,
3881 0 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
3882 : Constant::InitConvTemp,
3883 0 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
3884 : RoutineName);
3885 0 : this->WaterTemp = DesTowerInletWaterTemp; // 35.0; // design condition
3886 : }
3887 2 : rho = FluidProperties::GetDensityGlycol(state,
3888 2 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
3889 : Constant::InitConvTemp,
3890 2 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
3891 : RoutineName);
3892 :
3893 : // full speed fan tower UA
3894 2 : Real64 const solveLoad = tmpNomTowerCap * this->HeatRejectCapNomCapSizingRatio;
3895 2 : Real64 const solveWaterFlow = rho * tmpDesignWaterFlowRate; // design water mass flow rate
3896 2 : UA0 = 0.0001 * solveLoad; // Assume deltaT = 10000K (limit)
3897 2 : UA1 = solveLoad; // Assume deltaT = 1K
3898 :
3899 2 : this->AirTemp = this->DesInletAirDBTemp; // 35.0;
3900 2 : this->AirWetBulb = this->DesInletAirWBTemp; // 25.6;
3901 2 : this->AirPress = state.dataEnvrn->StdBaroPress;
3902 2 : this->AirHumRat = Psychrometrics::PsyWFnTdbTwbPb(state, this->AirTemp, this->AirWetBulb, this->AirPress);
3903 144 : auto f = [&state, this, solveLoad, solveWaterFlow, tmpDesignAirFlowRate, Cp](Real64 UA) {
3904 72 : Real64 const OutWaterTemp = this->calculateSimpleTowerOutletTemp(state, solveWaterFlow, tmpDesignAirFlowRate, UA);
3905 72 : Real64 const CoolingOutput = Cp * solveWaterFlow * (this->WaterTemp - OutWaterTemp); // tower cooling output [W]
3906 72 : return (solveLoad - CoolingOutput) / solveLoad;
3907 2 : };
3908 2 : General::SolveRoot(state, Acc, MaxIte, SolFla, UA, f, UA0, UA1);
3909 2 : if (SolFla == -1) {
3910 0 : ShowSevereError(state, "Iteration limit exceeded in calculating tower UA");
3911 0 : ShowFatalError(state, format("calculating cooling tower UA failed for tower {}", this->Name));
3912 2 : } else if (SolFla == -2) {
3913 0 : ShowSevereError(state, "Bad starting values for UA");
3914 0 : ShowFatalError(state, format("Autosizing of cooling tower UA failed for tower {}", this->Name));
3915 : }
3916 2 : this->HighSpeedTowerUA = UA;
3917 2 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3918 4 : BaseSizer::reportSizerOutput(state,
3919 2 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3920 : this->Name,
3921 : "U-Factor Times Area Value at Full Speed Air Flow Rate [W/C]",
3922 : this->HighSpeedTowerUA);
3923 : }
3924 2 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
3925 0 : BaseSizer::reportSizerOutput(state,
3926 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3927 : this->Name,
3928 : "Initial U-Factor Times Area Value at Full Speed Air Flow Rate [W/C]",
3929 : this->HighSpeedTowerUA);
3930 : }
3931 : // free convection tower UA
3932 2 : Real64 const solveLoad1 = tmpTowerFreeConvNomCap * this->HeatRejectCapNomCapSizingRatio;
3933 2 : Real64 solveWaterFlow1 = rho * tmpDesignWaterFlowRate; // design water mass flow rate
3934 2 : UA0 = 0.0001 * solveLoad1; // Assume deltaT = 10000K (limit)
3935 2 : UA0 = max(UA0, 1.0); // limit to 1.0
3936 2 : UA1 = solveLoad1; // Assume deltaT = 1K
3937 2 : this->AirTemp = this->DesInletAirDBTemp; // 35.0;
3938 2 : this->AirWetBulb = this->DesInletAirWBTemp; // 25.6;
3939 2 : this->AirPress = state.dataEnvrn->StdBaroPress;
3940 2 : this->AirHumRat = Psychrometrics::PsyWFnTdbTwbPb(state, this->AirTemp, this->AirWetBulb, this->AirPress);
3941 124 : auto f2 = [&state, this, solveLoad1, solveWaterFlow1, tmpFreeConvAirFlowRate, Cp](Real64 UA) {
3942 62 : Real64 const OutWaterTemp = this->calculateSimpleTowerOutletTemp(state, solveWaterFlow1, tmpFreeConvAirFlowRate, UA);
3943 62 : Real64 const CoolingOutput = Cp * solveWaterFlow1 * (this->WaterTemp - OutWaterTemp); // tower cooling output [W]
3944 62 : return (solveLoad1 - CoolingOutput) / solveLoad1;
3945 2 : };
3946 2 : General::SolveRoot(state, Acc, MaxIte, SolFla, UA, f2, UA0, UA1);
3947 2 : if (SolFla == -1) {
3948 0 : ShowSevereError(state, "Iteration limit exceeded in calculating tower free convection UA");
3949 0 : ShowFatalError(state, format("calculating cooling tower UA failed for tower {}", this->Name));
3950 2 : } else if (SolFla == -2) {
3951 0 : ShowSevereError(state, "Bad starting values for UA");
3952 0 : ShowFatalError(state, format("Autosizing of cooling tower UA failed for free convection tower {}", this->Name));
3953 : }
3954 2 : this->FreeConvTowerUA = UA;
3955 2 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3956 4 : BaseSizer::reportSizerOutput(state,
3957 2 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3958 : this->Name,
3959 : "U-Factor Times Area Value at Free Convection Air Flow Rate [W/C]",
3960 : this->FreeConvTowerUA);
3961 : }
3962 2 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
3963 0 : BaseSizer::reportSizerOutput(state,
3964 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3965 : this->Name,
3966 : "Initial U-Factor Times Area Value at Free Convection Air Flow Rate [W/C]",
3967 : this->FreeConvTowerUA);
3968 : }
3969 : }
3970 0 : } else if (this->PerformanceInputMethod_Num == PIM::UFactor) {
3971 : // UA input method
3972 :
3973 0 : if (this->DesignWaterFlowRateWasAutoSized) { // get from plant sizing
3974 : // UA input method using plant sizing for flow rate, whereas Nominal capacity method uses scalable sizing factor per cap
3975 0 : if (PltSizCondNum > 0) {
3976 0 : if (PlantSizData(PltSizCondNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
3977 0 : tmpDesignWaterFlowRate = PlantSizData(PltSizCondNum).DesVolFlowRate * this->SizFac;
3978 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
3979 0 : this->DesignWaterFlowRate = tmpDesignWaterFlowRate;
3980 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
3981 0 : BaseSizer::reportSizerOutput(state,
3982 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3983 : this->Name,
3984 : "Design Water Flow Rate [m3/s]",
3985 : this->DesignWaterFlowRate);
3986 : }
3987 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
3988 0 : BaseSizer::reportSizerOutput(state,
3989 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
3990 : this->Name,
3991 : "Initial Design Water Flow Rate [m3/s]",
3992 : this->DesignWaterFlowRate);
3993 : }
3994 : }
3995 : } else {
3996 0 : tmpDesignWaterFlowRate = 0.0;
3997 : }
3998 :
3999 : } else {
4000 0 : if (!this->TowerInletCondsAutoSize) {
4001 0 : if (this->DesignWaterFlowRate >= HVAC::SmallWaterVolFlow) {
4002 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
4003 0 : this->DesignWaterFlowRate = tmpDesignWaterFlowRate;
4004 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
4005 0 : BaseSizer::reportSizerOutput(state,
4006 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4007 : this->Name,
4008 : "Design Water Flow Rate [m3/s]",
4009 : this->DesignWaterFlowRate);
4010 : }
4011 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
4012 0 : BaseSizer::reportSizerOutput(state,
4013 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4014 : this->Name,
4015 : "Initial Design Water Flow Rate [m3/s]",
4016 : this->DesignWaterFlowRate);
4017 : }
4018 : }
4019 : } else {
4020 0 : tmpDesignWaterFlowRate = 0.0;
4021 : }
4022 : } else {
4023 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
4024 0 : ShowSevereError(state, format("Autosizing error for cooling tower object = {}", this->Name));
4025 0 : ShowFatalError(state, "Autosizing of cooling tower nominal capacity requires a loop Sizing:Plant object.");
4026 : }
4027 : }
4028 : }
4029 : }
4030 0 : PlantUtilities::RegisterPlantCompDesignFlow(state, this->WaterInletNodeNum, tmpDesignWaterFlowRate);
4031 :
4032 0 : if (this->HighSpeedTowerUAWasAutoSized) {
4033 : // get nominal capacity from PlantSizData(PltSizCondNum)%DeltaT and PlantSizData(PltSizCondNum)%DesVolFlowRate
4034 0 : if (PltSizCondNum > 0) {
4035 0 : if (PlantSizData(PltSizCondNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
4036 0 : rho = FluidProperties::GetDensityGlycol(state,
4037 0 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
4038 : DesTowerExitWaterTemp,
4039 0 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
4040 : RoutineName);
4041 0 : Cp = FluidProperties::GetSpecificHeatGlycol(state,
4042 0 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
4043 : DesTowerExitWaterTemp,
4044 0 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
4045 : RoutineName);
4046 0 : DesTowerLoad = rho * Cp * PlantSizData(PltSizCondNum).DesVolFlowRate * DesTowerWaterDeltaT * this->SizFac;
4047 0 : tmpNomTowerCap = DesTowerLoad / this->HeatRejectCapNomCapSizingRatio;
4048 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
4049 0 : this->TowerNominalCapacity = tmpNomTowerCap;
4050 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
4051 0 : BaseSizer::reportSizerOutput(state,
4052 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4053 : this->Name,
4054 : "Nominal Capacity [W]",
4055 : this->TowerNominalCapacity);
4056 : }
4057 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
4058 0 : BaseSizer::reportSizerOutput(state,
4059 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4060 : this->Name,
4061 : "Initial Nominal Capacity [W]",
4062 : this->TowerNominalCapacity);
4063 : }
4064 : }
4065 : } else {
4066 0 : tmpNomTowerCap = 0.0;
4067 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
4068 0 : this->TowerNominalCapacity = tmpNomTowerCap;
4069 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
4070 0 : BaseSizer::reportSizerOutput(state,
4071 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4072 : this->Name,
4073 : "Nominal Capacity [W]",
4074 : this->TowerNominalCapacity);
4075 : }
4076 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
4077 0 : BaseSizer::reportSizerOutput(state,
4078 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4079 : this->Name,
4080 : "Initial Nominal Capacity [W]",
4081 : this->TowerNominalCapacity);
4082 : }
4083 : }
4084 : }
4085 : } else {
4086 0 : if (!this->TowerInletCondsAutoSize) {
4087 0 : if (this->DesignWaterFlowRate >= HVAC::SmallWaterVolFlow) {
4088 0 : rho = FluidProperties::GetDensityGlycol(state,
4089 0 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
4090 : DesTowerExitWaterTemp,
4091 0 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
4092 : RoutineName);
4093 0 : Cp = FluidProperties::GetSpecificHeatGlycol(state,
4094 0 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
4095 : DesTowerExitWaterTemp,
4096 0 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
4097 : RoutineName);
4098 0 : DesTowerLoad = rho * Cp * this->DesignWaterFlowRate * DesTowerWaterDeltaT * this->SizFac;
4099 0 : tmpNomTowerCap = DesTowerLoad / this->HeatRejectCapNomCapSizingRatio;
4100 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
4101 0 : this->TowerNominalCapacity = tmpNomTowerCap;
4102 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
4103 0 : BaseSizer::reportSizerOutput(state,
4104 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4105 : this->Name,
4106 : "Nominal Capacity [W]",
4107 : this->TowerNominalCapacity);
4108 : }
4109 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
4110 0 : BaseSizer::reportSizerOutput(state,
4111 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4112 : this->Name,
4113 : "Initial Nominal Capacity [W]",
4114 : this->TowerNominalCapacity);
4115 : }
4116 : }
4117 : } else {
4118 0 : tmpNomTowerCap = 0.0;
4119 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
4120 0 : this->TowerNominalCapacity = tmpNomTowerCap;
4121 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
4122 0 : BaseSizer::reportSizerOutput(state,
4123 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4124 : this->Name,
4125 : "Nominal Capacity [W]",
4126 : this->TowerNominalCapacity);
4127 : }
4128 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
4129 0 : BaseSizer::reportSizerOutput(state,
4130 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4131 : this->Name,
4132 : "Initial Nominal Capacity [W]",
4133 : this->TowerNominalCapacity);
4134 : }
4135 : }
4136 : }
4137 : } else {
4138 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
4139 0 : ShowSevereError(state, format("Autosizing error for cooling tower object = {}", this->Name));
4140 0 : ShowFatalError(state, "Autosizing of cooling tower nominal capacity requires a loop Sizing:Plant object.");
4141 : }
4142 : }
4143 : }
4144 0 : if (this->TowerFreeConvNomCapWasAutoSized) {
4145 0 : tmpTowerFreeConvNomCap = tmpNomTowerCap * this->TowerFreeConvNomCapSizingFactor;
4146 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
4147 0 : this->TowerFreeConvNomCap = tmpTowerFreeConvNomCap;
4148 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
4149 0 : BaseSizer::reportSizerOutput(state,
4150 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4151 : this->Name,
4152 : "Free Convection Nominal Capacity [W]",
4153 : this->TowerFreeConvNomCap);
4154 : }
4155 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
4156 0 : BaseSizer::reportSizerOutput(state,
4157 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4158 : this->Name,
4159 : "Initial Free Convection Nominal Capacity [W]",
4160 : this->TowerFreeConvNomCap);
4161 : }
4162 : }
4163 : }
4164 0 : if (this->HighSpeedAirFlowRateWasAutoSized) {
4165 0 : if (this->DefaultedDesignAirFlowScalingFactor) {
4166 0 : tmpDesignAirFlowRate = tmpNomTowerCap * this->DesignAirFlowPerUnitNomCap * (101325.0 / state.dataEnvrn->StdBaroPress);
4167 : } else {
4168 0 : tmpDesignAirFlowRate = tmpNomTowerCap * this->DesignAirFlowPerUnitNomCap;
4169 : }
4170 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
4171 0 : this->HighSpeedAirFlowRate = tmpDesignAirFlowRate;
4172 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
4173 0 : BaseSizer::reportSizerOutput(state,
4174 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4175 : this->Name,
4176 : "Design Air Flow Rate [m3/s]",
4177 : this->HighSpeedAirFlowRate);
4178 : }
4179 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
4180 0 : BaseSizer::reportSizerOutput(state,
4181 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4182 : this->Name,
4183 : "Initial Design Air Flow Rate [m3/s]",
4184 : this->HighSpeedAirFlowRate);
4185 : }
4186 : }
4187 : }
4188 0 : if (this->FreeConvAirFlowRateWasAutoSized) {
4189 0 : tmpFreeConvAirFlowRate = tmpDesignAirFlowRate * this->FreeConvAirFlowRateSizingFactor;
4190 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
4191 0 : this->FreeConvAirFlowRate = tmpFreeConvAirFlowRate;
4192 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
4193 0 : BaseSizer::reportSizerOutput(state,
4194 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4195 : this->Name,
4196 : "Free Convection Regime Air Flow Rate [m3/s]",
4197 : this->FreeConvAirFlowRate);
4198 : }
4199 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
4200 0 : BaseSizer::reportSizerOutput(state,
4201 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4202 : this->Name,
4203 : "Initial Free Convection Regime Air Flow Rate [m3/s]",
4204 : this->FreeConvAirFlowRate);
4205 : }
4206 : }
4207 : }
4208 : // now calcuate UA values from nominal capacities and flow rates
4209 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
4210 0 : rho = FluidProperties::GetDensityGlycol(state,
4211 0 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
4212 : Constant::InitConvTemp,
4213 0 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
4214 : RoutineName);
4215 0 : Cp = FluidProperties::GetSpecificHeatGlycol(state,
4216 0 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
4217 : DesTowerExitWaterTemp,
4218 0 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
4219 : RoutineName);
4220 : // full speed fan tower UA
4221 0 : Real64 const solveLoad = tmpNomTowerCap * this->HeatRejectCapNomCapSizingRatio;
4222 0 : Real64 const solveWaterFlow = rho * tmpDesignWaterFlowRate; // design water mass flow rate
4223 0 : UA0 = 0.0001 * solveLoad; // Assume deltaT = 10000K (limit)
4224 0 : UA1 = solveLoad; // Assume deltaT = 1K
4225 0 : this->WaterTemp = DesTowerInletWaterTemp;
4226 0 : this->AirTemp = this->DesInletAirDBTemp; // 35.0;
4227 0 : this->AirWetBulb = this->DesInletAirWBTemp; // 25.6;
4228 0 : this->AirPress = state.dataEnvrn->StdBaroPress;
4229 0 : this->AirHumRat = Psychrometrics::PsyWFnTdbTwbPb(state, this->AirTemp, this->AirWetBulb, this->AirPress);
4230 0 : auto f = [&state, this, solveLoad, solveWaterFlow, tmpDesignAirFlowRate, Cp](Real64 UA) {
4231 0 : Real64 const OutWaterTemp = this->calculateSimpleTowerOutletTemp(state, solveWaterFlow, tmpDesignAirFlowRate, UA);
4232 0 : Real64 const CoolingOutput = Cp * solveWaterFlow * (this->WaterTemp - OutWaterTemp); // tower cooling output [W]
4233 0 : return (solveLoad - CoolingOutput) / solveLoad;
4234 0 : };
4235 0 : General::SolveRoot(state, Acc, MaxIte, SolFla, UA, f, UA0, UA1);
4236 0 : if (SolFla == -1) {
4237 0 : ShowSevereError(state, "Iteration limit exceeded in calculating tower UA");
4238 0 : ShowFatalError(state, format("calculating cooling tower UA failed for tower {}", this->Name));
4239 0 : } else if (SolFla == -2) {
4240 0 : ShowSevereError(state, "Bad starting values for UA");
4241 0 : ShowFatalError(state, format("Autosizing of cooling tower UA failed for tower {}", this->Name));
4242 : }
4243 0 : this->HighSpeedTowerUA = UA;
4244 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
4245 0 : BaseSizer::reportSizerOutput(state,
4246 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4247 : this->Name,
4248 : "U-Factor Times Area Value at Full Speed Air Flow Rate [W/C]",
4249 : this->HighSpeedTowerUA);
4250 : }
4251 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
4252 0 : BaseSizer::reportSizerOutput(state,
4253 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4254 : this->Name,
4255 : "Initial U-Factor Times Area Value at Full Speed Air Flow Rate [W/C]",
4256 : this->HighSpeedTowerUA);
4257 : }
4258 : // free convection tower UA
4259 0 : Real64 const solveLoad2 = tmpTowerFreeConvNomCap * this->HeatRejectCapNomCapSizingRatio;
4260 0 : Real64 const solveWaterFlow2 = rho * tmpDesignWaterFlowRate; // design water mass flow rate
4261 0 : UA0 = 0.0001 * solveLoad2; // Assume deltaT = 10000K (limit)
4262 0 : UA1 = solveLoad2; // Assume deltaT = 1K
4263 0 : this->WaterTemp = DesTowerInletWaterTemp;
4264 0 : this->AirTemp = DesTowerInletAirDBTemp; // 35.0;
4265 0 : this->AirWetBulb = DesTowerInletAirWBTemp; // 25.6;
4266 0 : this->AirPress = state.dataEnvrn->StdBaroPress;
4267 0 : this->AirHumRat = Psychrometrics::PsyWFnTdbTwbPb(state, this->AirTemp, this->AirWetBulb, this->AirPress);
4268 0 : auto f3 = [&state, this, solveLoad2, solveWaterFlow2, tmpFreeConvAirFlowRate, Cp](Real64 UA) {
4269 0 : Real64 const OutWaterTemp = this->calculateSimpleTowerOutletTemp(state, solveWaterFlow2, tmpFreeConvAirFlowRate, UA);
4270 0 : Real64 const CoolingOutput = Cp * solveWaterFlow2 * (this->WaterTemp - OutWaterTemp); // tower cooling output [W]
4271 0 : return (solveLoad2 - CoolingOutput) / solveLoad2;
4272 0 : };
4273 0 : General::SolveRoot(state, Acc, MaxIte, SolFla, UA, f3, UA0, UA1);
4274 0 : if (SolFla == -1) {
4275 0 : ShowSevereError(state, "Iteration limit exceeded in calculating tower free convection UA");
4276 0 : ShowFatalError(state, format("calculating cooling tower UA failed for tower {}", this->Name));
4277 0 : } else if (SolFla == -2) {
4278 0 : ShowSevereError(state, "Bad starting values for UA");
4279 0 : ShowFatalError(state, format("Autosizing of cooling tower UA failed for free convection tower {}", this->Name));
4280 : }
4281 0 : this->LowSpeedTowerUA = UA;
4282 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
4283 0 : BaseSizer::reportSizerOutput(state,
4284 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4285 : this->Name,
4286 : "U-Factor Times Area Value at Free Convection Air Flow Rate [W/C]",
4287 : this->FreeConvTowerUA);
4288 : }
4289 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
4290 0 : BaseSizer::reportSizerOutput(state,
4291 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4292 : this->Name,
4293 : "Initial U-Factor Times Area Value at Free Convection Air Flow Rate [W/C]",
4294 : this->FreeConvTowerUA);
4295 : }
4296 : }
4297 :
4298 : } else { // full speed UA given
4299 :
4300 0 : if (this->FreeConvTowerUAWasAutoSized) { // determine from scalable sizing factor
4301 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
4302 0 : this->FreeConvTowerUA = this->HighSpeedTowerUA * this->FreeConvTowerUASizingFactor;
4303 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
4304 0 : BaseSizer::reportSizerOutput(state,
4305 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4306 : this->Name,
4307 : "U-Factor Times Area Value at Free Convection Air Flow Rate [W/C]",
4308 : this->FreeConvTowerUA);
4309 : }
4310 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
4311 0 : BaseSizer::reportSizerOutput(state,
4312 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4313 : this->Name,
4314 : "Initial U-Factor Times Area Value at Free Convection Air Flow Rate [W/C]",
4315 : this->FreeConvTowerUA);
4316 : }
4317 : }
4318 : }
4319 : Real64 OutWaterTemp;
4320 0 : if (this->HighSpeedAirFlowRateWasAutoSized) { // given UA but not air flow rate
4321 : // need an air flow rate to find capacity from UA but flow rate is scaled off capacity
4322 : // get nominal capacity from PlantSizData(PltSizCondNum)%DeltaT and PlantSizData(PltSizCondNum)%DesVolFlowRate
4323 0 : if (PltSizCondNum > 0) {
4324 0 : if (PlantSizData(PltSizCondNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
4325 0 : rho = FluidProperties::GetDensityGlycol(state,
4326 0 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
4327 : DesTowerExitWaterTemp,
4328 0 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
4329 : RoutineName);
4330 0 : Cp = FluidProperties::GetSpecificHeatGlycol(state,
4331 0 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
4332 : DesTowerExitWaterTemp,
4333 0 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
4334 : RoutineName);
4335 0 : DesTowerLoad = rho * Cp * PlantSizData(PltSizCondNum).DesVolFlowRate * DesTowerWaterDeltaT;
4336 0 : tmpNomTowerCap = DesTowerLoad / this->HeatRejectCapNomCapSizingRatio;
4337 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
4338 0 : this->TowerNominalCapacity = tmpNomTowerCap;
4339 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
4340 0 : BaseSizer::reportSizerOutput(state,
4341 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4342 : this->Name,
4343 : "Nominal Capacity [W]",
4344 : this->TowerNominalCapacity);
4345 : }
4346 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
4347 0 : BaseSizer::reportSizerOutput(state,
4348 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4349 : this->Name,
4350 : "Initial Nominal Capacity [W]",
4351 : this->TowerNominalCapacity);
4352 : }
4353 : }
4354 : } else {
4355 0 : tmpNomTowerCap = rho = Cp = 0.0; // rho and Cp added: Used below
4356 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
4357 0 : this->TowerNominalCapacity = tmpNomTowerCap;
4358 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
4359 0 : BaseSizer::reportSizerOutput(state,
4360 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4361 : this->Name,
4362 : "Nominal Capacity [W]",
4363 : this->TowerNominalCapacity);
4364 : }
4365 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
4366 0 : BaseSizer::reportSizerOutput(state,
4367 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4368 : this->Name,
4369 : "Initial Nominal Capacity [W]",
4370 : this->TowerNominalCapacity);
4371 : }
4372 : }
4373 : }
4374 :
4375 : } else {
4376 0 : tmpNomTowerCap = 0.0; // Suppress uninitialized warnings
4377 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
4378 0 : ShowSevereError(state, format("Autosizing error for cooling tower object = {}", this->Name));
4379 0 : ShowFatalError(state, "Autosizing of cooling tower nominal capacity requires a loop Sizing:Plant object.");
4380 : }
4381 : }
4382 :
4383 0 : if (this->DefaultedDesignAirFlowScalingFactor) {
4384 0 : tmpDesignAirFlowRate = tmpNomTowerCap * this->DesignAirFlowPerUnitNomCap * (101325.0 / state.dataEnvrn->StdBaroPress);
4385 : } else {
4386 0 : tmpDesignAirFlowRate = tmpNomTowerCap * this->DesignAirFlowPerUnitNomCap;
4387 : }
4388 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
4389 0 : this->HighSpeedAirFlowRate = tmpDesignAirFlowRate;
4390 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
4391 0 : BaseSizer::reportSizerOutput(state,
4392 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4393 : this->Name,
4394 : "Design Air Flow Rate [m3/s]",
4395 : this->HighSpeedAirFlowRate);
4396 : }
4397 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
4398 0 : BaseSizer::reportSizerOutput(state,
4399 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4400 : this->Name,
4401 : "Initial Design Air Flow Rate [m3/s]",
4402 : this->HighSpeedAirFlowRate);
4403 : }
4404 : }
4405 :
4406 : } else { // UA and Air flow rate given, so find Nominal Cap from running model
4407 :
4408 0 : rho = FluidProperties::GetDensityGlycol(state,
4409 0 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
4410 : DesTowerExitWaterTemp,
4411 0 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
4412 : RoutineName);
4413 0 : Cp = FluidProperties::GetSpecificHeatGlycol(state,
4414 0 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
4415 : DesTowerExitWaterTemp,
4416 0 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
4417 : RoutineName);
4418 :
4419 0 : this->WaterTemp = DesTowerInletWaterTemp;
4420 0 : this->AirTemp = DesTowerInletAirDBTemp; // 35.0;
4421 0 : this->AirWetBulb = DesTowerInletAirWBTemp; // 25.6;
4422 0 : this->AirPress = state.dataEnvrn->StdBaroPress;
4423 0 : this->AirHumRat = Psychrometrics::PsyWFnTdbTwbPb(state, this->AirTemp, this->AirWetBulb, this->AirPress);
4424 : OutWaterTemp =
4425 0 : this->calculateSimpleTowerOutletTemp(state, rho * tmpDesignWaterFlowRate, this->HighSpeedAirFlowRate, this->HighSpeedTowerUA);
4426 0 : tmpNomTowerCap = Cp * rho * tmpDesignWaterFlowRate * (this->WaterTemp - OutWaterTemp);
4427 0 : tmpNomTowerCap /= this->HeatRejectCapNomCapSizingRatio;
4428 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
4429 0 : this->TowerNominalCapacity = tmpNomTowerCap;
4430 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
4431 0 : BaseSizer::reportSizerOutput(state,
4432 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4433 : this->Name,
4434 : "Nominal Capacity [W]",
4435 : this->TowerNominalCapacity);
4436 : }
4437 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
4438 0 : BaseSizer::reportSizerOutput(state,
4439 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4440 : this->Name,
4441 : "Initial Nominal Capacity [W]",
4442 : this->TowerNominalCapacity);
4443 : }
4444 : }
4445 :
4446 : } // both UA and air flow rate given
4447 :
4448 0 : if (this->FreeConvAirFlowRateWasAutoSized) {
4449 0 : tmpFreeConvAirFlowRate = tmpDesignAirFlowRate * this->FreeConvAirFlowRateSizingFactor;
4450 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
4451 0 : this->FreeConvAirFlowRate = tmpFreeConvAirFlowRate;
4452 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
4453 0 : BaseSizer::reportSizerOutput(state,
4454 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4455 : this->Name,
4456 : "Free Convection Regime Air Flow Rate [m3/s]",
4457 : this->FreeConvAirFlowRate);
4458 : }
4459 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
4460 0 : BaseSizer::reportSizerOutput(state,
4461 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4462 : this->Name,
4463 : "Initial Free Convection Regime Air Flow Rate [m3/s]",
4464 : this->FreeConvAirFlowRate);
4465 : }
4466 : }
4467 : }
4468 :
4469 : OutWaterTemp =
4470 0 : this->calculateSimpleTowerOutletTemp(state, rho * tmpDesignWaterFlowRate, tmpFreeConvAirFlowRate, this->FreeConvTowerUA);
4471 0 : tmpTowerFreeConvNomCap = Cp * rho * tmpDesignWaterFlowRate * (this->WaterTemp - OutWaterTemp);
4472 0 : tmpTowerFreeConvNomCap /= this->HeatRejectCapNomCapSizingRatio;
4473 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
4474 0 : this->TowerFreeConvNomCap = tmpTowerFreeConvNomCap;
4475 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
4476 0 : BaseSizer::reportSizerOutput(state,
4477 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4478 : this->Name,
4479 : "Free Convection Nominal Capacity [W]",
4480 : this->TowerFreeConvNomCap);
4481 : }
4482 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
4483 0 : BaseSizer::reportSizerOutput(state,
4484 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4485 : this->Name,
4486 : "Initial Free Convection Nominal Capacity [W]",
4487 : this->TowerFreeConvNomCap);
4488 : }
4489 : }
4490 : }
4491 : }
4492 :
4493 10 : tmpHighSpeedFanPower = tmpNomTowerCap * this->DesignFanPowerPerUnitNomCap;
4494 10 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
4495 2 : if (this->HighSpeedFanPowerWasAutoSized) {
4496 :
4497 2 : this->HighSpeedFanPower = tmpHighSpeedFanPower;
4498 2 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
4499 4 : BaseSizer::reportSizerOutput(state,
4500 2 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4501 : this->Name,
4502 : "Design Fan Power [W]",
4503 : this->HighSpeedFanPower);
4504 : }
4505 2 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
4506 0 : BaseSizer::reportSizerOutput(state,
4507 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4508 : this->Name,
4509 : "Initial Design Fan Power [W]",
4510 : this->HighSpeedFanPower);
4511 : }
4512 : } else { // Hard-sized with sizing data
4513 0 : Real64 HighSpeedFanPowerUser(0.0);
4514 0 : HighSpeedFanPowerUser = this->HighSpeedAirFlowRate;
4515 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
4516 0 : BaseSizer::reportSizerOutput(state,
4517 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
4518 : this->Name,
4519 : "Design Fan Power [W]",
4520 : tmpHighSpeedFanPower,
4521 : "User-Specified Design Fan Power [W]",
4522 : HighSpeedFanPowerUser);
4523 0 : if (state.dataGlobal->DisplayExtraWarnings) {
4524 0 : if ((std::abs(tmpHighSpeedFanPower - HighSpeedFanPowerUser) / HighSpeedFanPowerUser) >
4525 0 : state.dataSize->AutoVsHardSizingThreshold) {
4526 0 : ShowMessage(state, format("SizeVSMerkelTower: Potential issue with equipment sizing for {}", this->Name));
4527 0 : ShowContinueError(state, format("User-Specified Design Fan Power of {:.2R} [W]", HighSpeedFanPowerUser));
4528 0 : ShowContinueError(state, format("differs from Design Fan Power of {:.2R} [W]", tmpHighSpeedFanPower));
4529 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
4530 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
4531 : }
4532 : }
4533 : }
4534 : }
4535 : }
4536 10 : } // namespace CondenserLoopTowers
4537 :
4538 7761854 : void CoolingTower::calculateSingleSpeedTower(EnergyPlusData &state, Real64 &MyLoad, bool RunFlag)
4539 : {
4540 :
4541 : // SUBROUTINE INFORMATION:
4542 : // AUTHOR Dan Fisher
4543 : // DATE WRITTEN Sept. 1998
4544 : // MODIFIED Aug. 2008, T Hong, Added fluid bypass for single speed cooling tower
4545 : // The OutletWaterTemp from calculateSimpleTowerOutletTemp can be lower than 0 degreeC
4546 : // which may not be allowed in practice if water is the tower fluid.
4547 : // Chandan Sharma, FSEC, February 2010, Added basin heater
4548 : // Jul. 2010, A Flament, added multi-cell capability for the 3 types of cooling tower
4549 : // Jun. 2016, R Zhang, Applied the condenser supply water temperature sensor fault model
4550 : // Jul. 2016, R Zhang, Applied the cooling tower fouling fault model
4551 : // RE-ENGINEERED Jan. 2001, Richard Raustad
4552 :
4553 : // PURPOSE OF THIS SUBROUTINE:
4554 : // To simulate the operation of a single-speed fan cooling tower.
4555 :
4556 : // METHODOLOGY EMPLOYED:
4557 : // The cooling tower is modeled using effectiveness-NTU relationships for
4558 : // counterflow heat exchangers based on Merkel's theory.
4559 : // The subroutine calculates the period of time required to meet a
4560 : // leaving water temperature setpoint. It assumes that part-load
4561 : // operation represents a linear interpolation of two steady-state regimes.
4562 : // Cyclic losses are neglected. The period of time required to meet the
4563 : // leaving water temperature setpoint is used to determine the required
4564 : // fan power and energy. Free convection regime is also modeled. This
4565 : // occurs when the pump is operating and the fan is off. If free convection
4566 : // regime cooling is all that is required for a given time step, the leaving
4567 : // water temperature is allowed to fall below the leaving water temperature
4568 : // setpoint (free cooling). At times when the cooling tower fan is required,
4569 : // the leaving water temperature is at or above the setpoint.
4570 : // A RunFlag is passed by the upper level manager to indicate the ON/OFF status,
4571 : // or schedule, of the cooling tower. If the tower is OFF, outlet water
4572 : // temperature and flow rate are passed through the model from inlet node to
4573 : // outlet node without intervention (with the exception of free convection
4574 : // where water temperature is allowed to float below the outlet water set
4575 : // point). Reports are also updated with fan power and energy being zero.
4576 : // When the RunFlag indicates an ON condition for the cooling tower, the
4577 : // mass flow rate and water temperature are read from the inlet node of the
4578 : // cooling tower (water-side). The outdoor air wet-bulb temperature is used
4579 : // as the entering condition to the cooling tower (air-side). Input deck
4580 : // parameters are read for the free convection regime (pump ON and fan OFF)
4581 : // and a leaving water temperature is calculated. If the leaving water temperature
4582 : // is at or below the setpoint, the calculated leaving water temperature is
4583 : // placed on the outlet node and no fan power is used. If the calculated leaving
4584 : // water temperature is above the setpoint, the cooling tower fan is turned on
4585 : // and design parameters are used to again calculate the leaving water temperature.
4586 : // If the calculated leaving water temperature is below the setpoint, a fan
4587 : // run-time fraction is calculated and used to determine fan power. The leaving
4588 : // water temperature setpoint is placed on the outlet node. If the calculated
4589 : // leaving water temperature is at or above the setpoint, the calculated
4590 : // leaving water temperature is placed on the outlet node and the fan runs at
4591 : // full power. Water mass flow rate is passed from inlet node to outlet node
4592 : // with no intervention.
4593 : // If a tower has multiple cells, the specified inputs of or the autosized capacity
4594 : // and air/water flow rates are for the entire tower. The number of cells to operate
4595 : // is first determined based on the user entered minimal and maximal water flow fractions
4596 : // per cell. If the loads are not met, more cells (if available) will operate to meet
4597 : // the loads. Inside each cell, the capacity controls still apply. Each cell operates
4598 : // in the same way.
4599 :
4600 : // REFERENCES:
4601 : // ASHRAE HVAC1KIT: A Toolkit for Primary HVAC System Energy Calculation. 1999.
4602 :
4603 : // SUBROUTINE PARAMETER DEFINITIONS:
4604 : static constexpr std::string_view RoutineName("calculateSingleSpeedTower");
4605 7761854 : int constexpr MaxIteration(100); // Maximum fluid bypass iteration calculations
4606 : static constexpr std::string_view MaxItChar("100");
4607 7761854 : Real64 constexpr BypassFractionThreshold(0.01); // Threshold to stop bypass iteration
4608 7761854 : Real64 constexpr OWTLowerLimit(0.0); // The limit of tower exit fluid temperature used in the fluid bypass
4609 : // calculation to avoid fluid freezing. For water, it is 0 degreeC,
4610 : // for glycols, it can be much lower. The fluid type is stored at the loop.
4611 : // Current choices are Water and Steam, needs to expand for glycols
4612 :
4613 : // set inlet and outlet nodes
4614 7761854 : this->Qactual = 0.0;
4615 7761854 : this->FanPower = 0.0;
4616 7761854 : this->OutletWaterTemp = state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp;
4617 :
4618 7761854 : Real64 freeConvTowerUA = this->FreeConvTowerUA;
4619 7761854 : Real64 highSpeedTowerUA = this->HighSpeedTowerUA;
4620 :
4621 : // water temperature setpoint
4622 7761854 : Real64 TempSetPoint = 0.0;
4623 7761854 : switch (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopDemandCalcScheme) {
4624 7654001 : case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
4625 7654001 : if (this->SetpointIsOnOutlet) {
4626 329043 : TempSetPoint = state.dataLoopNodes->Node(this->WaterOutletNodeNum).TempSetPoint;
4627 : } else {
4628 7324958 : TempSetPoint = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopSide(this->plantLoc.loopSideNum).TempSetPoint;
4629 : }
4630 7654001 : } break;
4631 107853 : case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
4632 107853 : if (this->SetpointIsOnOutlet) {
4633 29668 : TempSetPoint = state.dataLoopNodes->Node(this->WaterOutletNodeNum).TempSetPointHi;
4634 : } else {
4635 78185 : TempSetPoint = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopSide(this->plantLoc.loopSideNum).TempSetPointHi;
4636 : }
4637 107853 : } break;
4638 0 : default:
4639 0 : break;
4640 : }
4641 :
4642 : // If there is a fault of condenser SWT Sensor
4643 7761854 : if (this->FaultyCondenserSWTFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
4644 0 : (!state.dataGlobal->KickOffSimulation)) {
4645 0 : int FaultIndex = this->FaultyCondenserSWTIndex;
4646 0 : Real64 TowerOutletTemp_ff = TempSetPoint;
4647 :
4648 : // calculate the sensor offset using fault information
4649 0 : this->FaultyCondenserSWTOffset = state.dataFaultsMgr->FaultsCondenserSWTSensor(FaultIndex).CalFaultOffsetAct(state);
4650 : // update the TempSetPoint
4651 0 : TempSetPoint = TowerOutletTemp_ff - this->FaultyCondenserSWTOffset;
4652 : }
4653 :
4654 : // If there is a fault of cooling tower fouling
4655 7765094 : if (this->FaultyTowerFoulingFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
4656 3240 : (!state.dataGlobal->KickOffSimulation)) {
4657 3240 : int FaultIndex = this->FaultyTowerFoulingIndex;
4658 3240 : Real64 FreeConvTowerUA_ff = this->FreeConvTowerUA;
4659 3240 : Real64 HighSpeedTowerUA_ff = this->HighSpeedTowerUA;
4660 :
4661 : // calculate the Faulty Tower Fouling Factor using fault information
4662 3240 : this->FaultyTowerFoulingFactor = state.dataFaultsMgr->FaultsTowerFouling(FaultIndex).CalFaultyTowerFoulingFactor(state);
4663 :
4664 : // update the tower UA values at faulty cases
4665 3240 : freeConvTowerUA = FreeConvTowerUA_ff * this->FaultyTowerFoulingFactor;
4666 3240 : highSpeedTowerUA = HighSpeedTowerUA_ff * this->FaultyTowerFoulingFactor;
4667 : }
4668 :
4669 : // Added for fluid bypass. First assume no fluid bypass
4670 7761854 : int BypassFlag = 0; // Flag indicator for fluid bypass (0 - no bypass, 1 - bypass)
4671 7761854 : Real64 BypassFraction2 = 0.0;
4672 7761854 : this->BypassFraction = 0.0;
4673 :
4674 : // Added for multi-cell. Determine the number of cells operating
4675 7761854 : int NumCellMin(0);
4676 7761854 : int NumCellMax(0);
4677 7761854 : Real64 WaterMassFlowRatePerCellMin = 0.0;
4678 7761854 : if (this->DesWaterMassFlowRate > 0.0) {
4679 7756819 : WaterMassFlowRatePerCellMin = this->DesWaterMassFlowRate * this->MinFracFlowRate / this->NumCell;
4680 7756819 : Real64 WaterMassFlowRatePerCellMax = this->DesWaterMassFlowRate * this->MaxFracFlowRate / this->NumCell;
4681 :
4682 : // round it up to the nearest integer
4683 7756819 : NumCellMin = min(int((this->WaterMassFlowRate / WaterMassFlowRatePerCellMax) + 0.9999), this->NumCell);
4684 7756819 : NumCellMax = min(int((this->WaterMassFlowRate / WaterMassFlowRatePerCellMin) + 0.9999), this->NumCell);
4685 : }
4686 : // cap min at 1
4687 7761854 : if (NumCellMin <= 0) NumCellMin = 1;
4688 7761854 : if (NumCellMax <= 0) NumCellMax = 1;
4689 7761854 : if (this->cellCtrl == CellCtrl::MinCell) {
4690 40284 : this->NumCellOn = NumCellMin;
4691 : } else {
4692 7721570 : this->NumCellOn = NumCellMax;
4693 : }
4694 7761854 : Real64 WaterMassFlowRatePerCell = this->WaterMassFlowRate / this->NumCellOn;
4695 :
4696 : // Do not RETURN here if flow rate is less than SmallMassFlow. Check basin heater and then RETURN.
4697 :
4698 7761854 : bool returnFlagSet = false;
4699 7761854 : this->checkMassFlowAndLoad(state, MyLoad, RunFlag, returnFlagSet);
4700 7761854 : if (returnFlagSet) return;
4701 :
4702 3494827 : bool IncrNumCellFlag = true; // determine if yes or no we increase the number of cells // set value to true to enter in the loop
4703 :
4704 3494827 : Real64 UAdesign = 0.0; // UA value at design conditions (entered by user or calculated)
4705 : Real64 OutletWaterTempOFF;
4706 3494827 : Real64 FanModeFrac = 0.0;
4707 3494827 : Real64 AirFlowRate = 0.0;
4708 7002638 : while (IncrNumCellFlag) {
4709 3507811 : IncrNumCellFlag = false;
4710 :
4711 : // Initialize local variables to the free convection design values
4712 3507811 : UAdesign = freeConvTowerUA / this->NumCell;
4713 3507811 : AirFlowRate = this->FreeConvAirFlowRate / this->NumCell;
4714 3507811 : OutletWaterTempOFF = state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp;
4715 3507811 : this->OutletWaterTemp = OutletWaterTempOFF;
4716 3507811 : FanModeFrac = 0.0;
4717 :
4718 3507811 : OutletWaterTempOFF = this->calculateSimpleTowerOutletTemp(state, WaterMassFlowRatePerCell, AirFlowRate, UAdesign);
4719 :
4720 : // Assume Setpoint was met using free convection regime (pump ON and fan OFF)
4721 3507811 : this->FanPower = 0.0;
4722 3507811 : this->OutletWaterTemp = OutletWaterTempOFF;
4723 :
4724 3507811 : if (OutletWaterTempOFF > TempSetPoint) {
4725 : // Setpoint was not met (or free conv. not used), turn on cooling tower fan
4726 3496809 : UAdesign = highSpeedTowerUA / this->NumCell;
4727 3496809 : AirFlowRate = this->HighSpeedAirFlowRate / this->NumCell;
4728 :
4729 : // The fan power is for all cells operating
4730 3496809 : Real64 const FanPowerOn = this->HighSpeedFanPower * this->NumCellOn / this->NumCell;
4731 :
4732 3496809 : this->OutletWaterTemp = this->calculateSimpleTowerOutletTemp(state, WaterMassFlowRatePerCell, AirFlowRate, UAdesign);
4733 :
4734 3496809 : if (this->OutletWaterTemp <= TempSetPoint) {
4735 725497 : if (this->CapacityControl == CapacityCtrl::FanCycling || this->OutletWaterTemp <= OWTLowerLimit) {
4736 : // Setpoint was met with pump ON and fan ON, calculate run-time fraction
4737 725387 : FanModeFrac = (TempSetPoint - OutletWaterTempOFF) / (this->OutletWaterTemp - OutletWaterTempOFF);
4738 725387 : this->FanPower = FanModeFrac * FanPowerOn;
4739 725387 : this->OutletWaterTemp = TempSetPoint;
4740 : } else {
4741 : // FluidBypass, fan runs at full speed for the entire time step
4742 110 : FanModeFrac = 1.0;
4743 110 : this->FanPower = FanPowerOn;
4744 110 : BypassFlag = 1;
4745 : }
4746 : } else {
4747 : // Setpoint was not met, cooling tower ran at full capacity
4748 2771312 : FanModeFrac = 1.0;
4749 2771312 : this->FanPower = FanPowerOn;
4750 : // if possible increase the number of cells and do the calculations again with the new water mass flow rate per cell
4751 2771312 : if (this->NumCellOn < this->NumCell && (this->WaterMassFlowRate / (this->NumCellOn + 1)) >= WaterMassFlowRatePerCellMin) {
4752 12984 : ++this->NumCellOn;
4753 12984 : WaterMassFlowRatePerCell = this->WaterMassFlowRate / this->NumCellOn;
4754 12984 : IncrNumCellFlag = true;
4755 : }
4756 : }
4757 11002 : } else if (OutletWaterTempOFF < TempSetPoint) {
4758 : // Need to bypass in free convection cooling mode if bypass is allowed
4759 11002 : if (this->CapacityControl == CapacityCtrl::FluidBypass) {
4760 54 : if (OutletWaterTempOFF > OWTLowerLimit) {
4761 54 : BypassFlag = 1;
4762 : }
4763 : }
4764 : }
4765 : }
4766 :
4767 : // Calculate bypass fraction since OWTLowerLimit < OutletWaterTemp < TempSetPoint.
4768 : // The iteraction ends when the numer of iteraction exceeds the limit or the difference
4769 : // between the new and old bypass fractions is less than the threshold.
4770 3494827 : if (BypassFlag == 1) {
4771 : // Inlet water temperature lower than setpoint, assume 100% bypass, tower fan off
4772 164 : if (this->InletWaterTemp <= TempSetPoint) {
4773 0 : this->FanPower = 0.0;
4774 0 : this->BypassFraction = 1.0;
4775 0 : this->OutletWaterTemp = this->InletWaterTemp;
4776 : } else {
4777 164 : if (std::abs(this->InletWaterTemp - this->OutletWaterTemp) <= 0.01) {
4778 : // Outlet temp is close enough to inlet temp, assume 100% bypass, tower fan off
4779 0 : this->BypassFraction = 1.0;
4780 0 : this->FanPower = 0.0;
4781 : } else {
4782 164 : Real64 bypassFraction = (TempSetPoint - this->OutletWaterTemp) / (this->InletWaterTemp - this->OutletWaterTemp);
4783 164 : if (bypassFraction > 1.0 || bypassFraction < 0.0) {
4784 : // Bypass cannot meet setpoint, assume no bypass
4785 0 : this->BypassFraction = 0.0;
4786 : } else {
4787 164 : int NumIteration = 0;
4788 164 : Real64 BypassFractionPrev = bypassFraction;
4789 164 : Real64 OutletWaterTempPrev = this->OutletWaterTemp;
4790 500 : while (NumIteration < MaxIteration) {
4791 500 : ++NumIteration;
4792 : // need to iterate for the new OutletWaterTemp while bypassing tower water
4793 500 : this->OutletWaterTemp =
4794 500 : this->calculateSimpleTowerOutletTemp(state, WaterMassFlowRatePerCell * (1.0 - bypassFraction), AirFlowRate, UAdesign);
4795 : // Calc new BypassFraction based on the new OutletWaterTemp
4796 500 : if (std::abs(this->OutletWaterTemp - OWTLowerLimit) <= 0.01) {
4797 0 : BypassFraction2 = bypassFraction;
4798 0 : break;
4799 500 : } else if (this->OutletWaterTemp < OWTLowerLimit) {
4800 : // Set OutletWaterTemp = OWTLowerLimit, and use linear interpolation to calculate the bypassFraction
4801 40 : BypassFraction2 = BypassFractionPrev - (BypassFractionPrev - bypassFraction) * (OutletWaterTempPrev - OWTLowerLimit) /
4802 40 : (OutletWaterTempPrev - this->OutletWaterTemp);
4803 80 : this->OutletWaterTemp = this->calculateSimpleTowerOutletTemp(
4804 40 : state, WaterMassFlowRatePerCell * (1.0 - BypassFraction2), AirFlowRate, UAdesign);
4805 40 : if (this->OutletWaterTemp < OWTLowerLimit) {
4806 : // Use previous iteraction values
4807 40 : BypassFraction2 = BypassFractionPrev;
4808 40 : this->OutletWaterTemp = OutletWaterTempPrev;
4809 : }
4810 40 : break;
4811 : } else {
4812 460 : BypassFraction2 = (TempSetPoint - this->OutletWaterTemp) / (this->InletWaterTemp - this->OutletWaterTemp);
4813 : }
4814 :
4815 : // Compare two BypassFraction to determine when to stop
4816 460 : if (std::abs(BypassFraction2 - bypassFraction) <= BypassFractionThreshold) break;
4817 336 : BypassFractionPrev = bypassFraction;
4818 336 : OutletWaterTempPrev = this->OutletWaterTemp;
4819 336 : bypassFraction = BypassFraction2;
4820 : }
4821 164 : if (NumIteration > MaxIteration) {
4822 0 : ShowWarningError(
4823 0 : state, format("Cooling tower fluid bypass iteration exceeds maximum limit of {} for {}", MaxItChar, this->Name));
4824 : }
4825 164 : this->BypassFraction = BypassFraction2;
4826 : // may not meet TempSetPoint due to limit of tower outlet temp to OWTLowerLimit
4827 164 : this->OutletWaterTemp = (1.0 - BypassFraction2) * this->OutletWaterTemp + BypassFraction2 * this->InletWaterTemp;
4828 : }
4829 : }
4830 : }
4831 : }
4832 :
4833 : // output the fraction of the time step the fan is ON
4834 3494827 : this->FanCyclingRatio = FanModeFrac;
4835 : // Should this be water inlet node num?????
4836 3494827 : Real64 const CpWater = FluidProperties::GetSpecificHeatGlycol(state,
4837 3494827 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
4838 3494827 : state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp,
4839 3494827 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
4840 : RoutineName);
4841 :
4842 3494827 : this->Qactual = this->WaterMassFlowRate * CpWater * (state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp - this->OutletWaterTemp);
4843 3494827 : this->airFlowRateRatio = (AirFlowRate * this->NumCell) / this->HighSpeedAirFlowRate;
4844 : }
4845 :
4846 298469 : void CoolingTower::calculateTwoSpeedTower(EnergyPlusData &state, Real64 &MyLoad, bool RunFlag)
4847 : {
4848 :
4849 : // SUBROUTINE INFORMATION:
4850 : // AUTHOR Dan Fisher
4851 : // DATE WRITTEN Sept. 1998
4852 : // MODIFIED Feb. 2010, Chandan Sharma, FSEC, Added basin heater
4853 : // Jul. 2010, A Flament, added multi-cell capability for the 3 types of cooling tower
4854 : // Jun. 2016, R Zhang, Applied the condenser supply water temperature sensor fault model
4855 : // Jul. 2016, R Zhang, Applied the cooling tower fouling fault model
4856 :
4857 : // PURPOSE OF THIS SUBROUTINE:
4858 : // To simulate the operation of a cooling tower with a two-speed fan.
4859 :
4860 : // METHODOLOGY EMPLOYED:
4861 : // The cooling tower is modeled using effectiveness-NTU relationships for
4862 : // counterflow heat exchangers based on Merkel's theory.
4863 : // The subroutine calculates the period of time required to meet a
4864 : // leaving water temperature setpoint. It assumes that part-load
4865 : // operation represents a linear interpolation of three steady-state regimes
4866 : // (high-speed fan operation, low-speed fan operation and free convection regime).
4867 : // Cyclic losses are neglected. The period of time required to meet the
4868 : // leaving water temperature setpoint is used to determine the required
4869 : // fan power and energy. Free convection regime is also modeled. This
4870 : // occures when the pump is operating and the fan is off. If free convection
4871 : // regime cooling is all that is required for a given time step, the leaving
4872 : // water temperature is allowed to fall below the leaving water temperature
4873 : // setpoint (free cooling). At times when the cooling tower fan is required,
4874 : // the leaving water temperature is at or above the setpoint.
4875 : // A RunFlag is passed by the upper level manager to indicate the ON/OFF status,
4876 : // or schedule, of the cooling tower. If the tower is OFF, outlet water
4877 : // temperature and flow rate are passed through the model from inlet node to
4878 : // outlet node without intervention (with the exception of free convection
4879 : // where water temperature is allowed to float below the outlet water set
4880 : // point). Reports are also updated with fan power and fan energy being zero.
4881 : // When the RunFlag indicates an ON condition for the cooling tower, the
4882 : // mass flow rate and water temperature are read from the inlet node of the
4883 : // cooling tower (water-side). The outdoor air wet-bulb temperature is used
4884 : // as the entering condition to the cooling tower (air-side). Input deck
4885 : // parameters are read for the free convection regime (pump ON and fan OFF)
4886 : // and a leaving water temperature is calculated. If the leaving water temperature
4887 : // is at or below the setpoint, the calculated leaving water temperature is
4888 : // placed on the outlet node and no fan power is used. If the calculated leaving
4889 : // water temperature is above the setpoint, the cooling tower fan is turned on
4890 : // and parameters for low fan speed are used to again calculate the leaving
4891 : // water temperature. If the calculated leaving water temperature is
4892 : // below the setpoint, a fan run-time fraction (FanModeFrac) is calculated and
4893 : // used to determine fan power. The leaving water temperature setpoint is placed
4894 : // on the outlet node. If the calculated leaving water temperature is at or above
4895 : // the setpoint, the cooling tower fan is turned on 'high speed' and the routine is
4896 : // repeated. If the calculated leaving water temperature is below the setpoint,
4897 : // a fan run-time fraction is calculated for the second stage fan and fan power
4898 : // is calculated as FanModeFrac*HighSpeedFanPower+(1-FanModeFrac)*LowSpeedFanPower.
4899 : // If the calculated leaving water temperature is above the leaving water temp.
4900 : // setpoint, the calculated leaving water temperature is placed on the outlet
4901 : // node and the fan runs at full power (High Speed Fan Power). Water mass flow
4902 : // rate is passed from inlet node to outlet node with no intervention.
4903 : // If a tower has multiple cells, the specified inputs of or the autosized capacity
4904 : // and air/water flow rates are for the entire tower. The number of cells to operate
4905 : // is first determined based on the user entered minimal and maximal water flow fractions
4906 : // per cell. If the loads are not met, more cells (if available) will operate to meet
4907 : // the loads. Each cell operates in same way - same fan speed etc.
4908 : // REFERENCES:
4909 : // ASHRAE HVAC1KIT: A Toolkit for Primary HVAC System Energy Calculation. 1999.
4910 :
4911 : // SUBROUTINE PARAMETER DEFINITIONS:
4912 : static constexpr std::string_view RoutineName("calculateTwoSpeedTower");
4913 :
4914 : // init
4915 298469 : this->Qactual = 0.0;
4916 298469 : this->FanPower = 0.0;
4917 298469 : this->OutletWaterTemp = state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp;
4918 :
4919 298469 : Real64 freeConvTowerUA = this->FreeConvTowerUA;
4920 298469 : Real64 highSpeedTowerUA = this->HighSpeedTowerUA;
4921 :
4922 : // water temperature setpoint
4923 298469 : Real64 TempSetPoint = 0.0;
4924 298469 : switch (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopDemandCalcScheme) {
4925 280831 : case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
4926 280831 : if (this->SetpointIsOnOutlet) {
4927 31852 : TempSetPoint = state.dataLoopNodes->Node(this->WaterOutletNodeNum).TempSetPoint;
4928 : } else {
4929 248979 : TempSetPoint = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopSide(this->plantLoc.loopSideNum).TempSetPoint;
4930 : }
4931 280831 : } break;
4932 17638 : case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
4933 17638 : if (this->SetpointIsOnOutlet) {
4934 17638 : TempSetPoint = state.dataLoopNodes->Node(this->WaterOutletNodeNum).TempSetPointHi;
4935 : } else {
4936 0 : TempSetPoint = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopSide(this->plantLoc.loopSideNum).TempSetPointHi;
4937 : }
4938 17638 : } break;
4939 0 : default:
4940 0 : break;
4941 : }
4942 :
4943 : // If there is a fault of condenser SWT Sensor
4944 301381 : if (this->FaultyCondenserSWTFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
4945 2912 : (!state.dataGlobal->KickOffSimulation)) {
4946 2912 : int FaultIndex = this->FaultyCondenserSWTIndex;
4947 2912 : Real64 TowerOutletTemp_ff = TempSetPoint;
4948 :
4949 : // calculate the sensor offset using fault information
4950 2912 : this->FaultyCondenserSWTOffset = state.dataFaultsMgr->FaultsCondenserSWTSensor(FaultIndex).CalFaultOffsetAct(state);
4951 : // update the TempSetPoint
4952 2912 : TempSetPoint = TowerOutletTemp_ff - this->FaultyCondenserSWTOffset;
4953 : }
4954 :
4955 : // If there is a fault of cooling tower fouling
4956 298469 : if (this->FaultyTowerFoulingFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
4957 0 : (!state.dataGlobal->KickOffSimulation)) {
4958 0 : int FaultIndex = this->FaultyTowerFoulingIndex;
4959 0 : Real64 FreeConvTowerUA_ff = this->FreeConvTowerUA;
4960 0 : Real64 HighSpeedTowerUA_ff = this->HighSpeedTowerUA;
4961 :
4962 : // calculate the Faulty Tower Fouling Factor using fault information
4963 0 : this->FaultyTowerFoulingFactor = state.dataFaultsMgr->FaultsTowerFouling(FaultIndex).CalFaultyTowerFoulingFactor(state);
4964 :
4965 : // update the tower UA values at faulty cases
4966 0 : freeConvTowerUA = FreeConvTowerUA_ff * this->FaultyTowerFoulingFactor;
4967 0 : highSpeedTowerUA = HighSpeedTowerUA_ff * this->FaultyTowerFoulingFactor;
4968 : }
4969 :
4970 : // Do not RETURN here if flow rate is less than SmallMassFlow. Check basin heater and then RETURN.
4971 298469 : if (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopSide(this->plantLoc.loopSideNum).FlowLock == DataPlant::FlowLock::Unlocked)
4972 261298 : return; // TODO: WTF
4973 149198 : bool returnFlagSet = false;
4974 149198 : this->checkMassFlowAndLoad(state, MyLoad, RunFlag, returnFlagSet);
4975 149198 : if (returnFlagSet) return;
4976 :
4977 : // Added for multi-cell. Determine the number of cells operating
4978 37171 : Real64 WaterMassFlowRatePerCellMin = 0.0;
4979 : Real64 WaterMassFlowRatePerCellMax;
4980 37171 : int NumCellMin(0);
4981 37171 : int NumCellMax(0);
4982 : Real64 WaterMassFlowRatePerCell;
4983 37171 : if (this->DesWaterMassFlowRate > 0.0) {
4984 37171 : WaterMassFlowRatePerCellMin = this->DesWaterMassFlowRate * this->MinFracFlowRate / this->NumCell;
4985 37171 : WaterMassFlowRatePerCellMax = this->DesWaterMassFlowRate * this->MaxFracFlowRate / this->NumCell;
4986 :
4987 : // round it up to the nearest integer
4988 37171 : NumCellMin = min(int((this->WaterMassFlowRate / WaterMassFlowRatePerCellMax) + 0.9999), this->NumCell);
4989 37171 : NumCellMax = min(int((this->WaterMassFlowRate / WaterMassFlowRatePerCellMin) + 0.9999), this->NumCell);
4990 : }
4991 :
4992 : // cap min at 1
4993 37171 : if (NumCellMin <= 0) NumCellMin = 1;
4994 37171 : if (NumCellMax <= 0) NumCellMax = 1;
4995 :
4996 37171 : if (this->cellCtrl == CellCtrl::MinCell) {
4997 3428 : this->NumCellOn = NumCellMin;
4998 : } else {
4999 33743 : this->NumCellOn = NumCellMax;
5000 : }
5001 :
5002 37171 : WaterMassFlowRatePerCell = this->WaterMassFlowRate / this->NumCellOn;
5003 :
5004 37171 : bool IncrNumCellFlag = true;
5005 :
5006 37171 : Real64 AirFlowRate = 0.0;
5007 37171 : Real64 FanModeFrac = 0.0;
5008 37171 : int SpeedSel = 0;
5009 80834 : while (IncrNumCellFlag) {
5010 43663 : IncrNumCellFlag = false;
5011 :
5012 : // set local variable for tower
5013 43663 : Real64 UAdesign = freeConvTowerUA / this->NumCell; // where is NumCellOn?
5014 43663 : AirFlowRate = this->FreeConvAirFlowRate / this->NumCell;
5015 43663 : this->WaterMassFlowRate = state.dataLoopNodes->Node(this->WaterInletNodeNum).MassFlowRate;
5016 43663 : Real64 OutletWaterTemp1stStage = this->OutletWaterTemp;
5017 43663 : Real64 OutletWaterTemp2ndStage = this->OutletWaterTemp;
5018 43663 : FanModeFrac = 0.0;
5019 :
5020 43663 : Real64 OutletWaterTempOFF = this->calculateSimpleTowerOutletTemp(state, WaterMassFlowRatePerCell, AirFlowRate, UAdesign);
5021 :
5022 : // Setpoint was met using free convection regime (pump ON and fan OFF)
5023 43663 : this->FanPower = 0.0;
5024 43663 : this->OutletWaterTemp = OutletWaterTempOFF;
5025 :
5026 43663 : if (OutletWaterTempOFF > TempSetPoint) {
5027 : // Setpoint was not met (or free conv. not used),turn on cooling tower 1st stage fan
5028 43276 : UAdesign = this->LowSpeedTowerUA / this->NumCell;
5029 43276 : AirFlowRate = this->LowSpeedAirFlowRate / this->NumCell;
5030 43276 : Real64 const FanPowerLow = this->LowSpeedFanPower * this->NumCellOn / this->NumCell;
5031 :
5032 43276 : OutletWaterTemp1stStage = this->calculateSimpleTowerOutletTemp(state, WaterMassFlowRatePerCell, AirFlowRate, UAdesign);
5033 :
5034 43276 : if (OutletWaterTemp1stStage <= TempSetPoint) {
5035 : // Setpoint was met with pump ON and fan ON 1st stage, calculate fan mode fraction
5036 5307 : FanModeFrac = (TempSetPoint - OutletWaterTempOFF) / (OutletWaterTemp1stStage - OutletWaterTempOFF);
5037 5307 : this->FanPower = FanModeFrac * FanPowerLow;
5038 5307 : this->OutletWaterTemp = TempSetPoint;
5039 5307 : this->Qactual *= FanModeFrac;
5040 5307 : SpeedSel = 1;
5041 : } else {
5042 : // Setpoint was not met, turn on cooling tower 2nd stage fan
5043 37969 : UAdesign = highSpeedTowerUA / this->NumCell;
5044 37969 : AirFlowRate = this->HighSpeedAirFlowRate / this->NumCell;
5045 37969 : Real64 const FanPowerHigh = this->HighSpeedFanPower * this->NumCellOn / this->NumCell;
5046 :
5047 37969 : OutletWaterTemp2ndStage = this->calculateSimpleTowerOutletTemp(state, WaterMassFlowRatePerCell, AirFlowRate, UAdesign);
5048 :
5049 37969 : if ((OutletWaterTemp2ndStage <= TempSetPoint) && UAdesign > 0.0) {
5050 : // Setpoint was met with pump ON and fan ON 2nd stage, calculate fan mode fraction
5051 9034 : FanModeFrac = (TempSetPoint - OutletWaterTemp1stStage) / (OutletWaterTemp2ndStage - OutletWaterTemp1stStage);
5052 9034 : this->FanPower = (FanModeFrac * FanPowerHigh) + (1.0 - FanModeFrac) * FanPowerLow;
5053 9034 : this->OutletWaterTemp = TempSetPoint;
5054 9034 : SpeedSel = 2;
5055 : } else {
5056 : // Setpoint was not met, cooling tower ran at full capacity
5057 28935 : this->OutletWaterTemp = OutletWaterTemp2ndStage;
5058 28935 : this->FanPower = FanPowerHigh;
5059 28935 : SpeedSel = 2;
5060 28935 : FanModeFrac = 1.0;
5061 : // if possible increase the number of cells and do the calculations again with the new water mass flow rate per cell
5062 28935 : if (this->NumCellOn < this->NumCell && (this->WaterMassFlowRate / (this->NumCellOn + 1)) >= WaterMassFlowRatePerCellMin) {
5063 6492 : ++this->NumCellOn;
5064 6492 : WaterMassFlowRatePerCell = this->WaterMassFlowRate / this->NumCellOn;
5065 6492 : IncrNumCellFlag = true;
5066 : }
5067 : }
5068 : }
5069 : }
5070 : }
5071 :
5072 : // output the fraction of the time step the fan is ON
5073 37171 : this->FanCyclingRatio = FanModeFrac;
5074 37171 : this->SpeedSelected = SpeedSel;
5075 :
5076 37171 : Real64 const CpWater = FluidProperties::GetSpecificHeatGlycol(state,
5077 37171 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
5078 37171 : state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp,
5079 37171 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
5080 : RoutineName);
5081 37171 : this->Qactual = this->WaterMassFlowRate * CpWater * (state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp - this->OutletWaterTemp);
5082 37171 : this->airFlowRateRatio = (AirFlowRate * this->NumCell) / this->HighSpeedAirFlowRate;
5083 : }
5084 :
5085 625884 : void CoolingTower::calculateVariableSpeedTower(EnergyPlusData &state, Real64 &MyLoad, bool RunFlag)
5086 : {
5087 :
5088 : // SUBROUTINE INFORMATION:
5089 : // AUTHOR Richard Raustad
5090 : // DATE WRITTEN Feb 2005
5091 : // MODIFIED Jul. 2010, A Flament, added multi-cell capability for the 3 types of cooling tower
5092 : // Jul. 2010, B Griffith, general fluid props
5093 : // Jun. 2016, R Zhang, Applied the condenser supply water temperature sensor fault model
5094 : // Jul. 2016, R Zhang, Applied the cooling tower fouling fault model
5095 :
5096 : // PURPOSE OF THIS SUBROUTINE:
5097 : // To simulate the operation of a variable-speed fan cooling tower.
5098 :
5099 : // METHODOLOGY EMPLOYED:
5100 : // For each simulation time step, a desired range temperature (Twater,inlet-Twater,setpoint) and desired approach
5101 : // temperature (Twater,setpoint-Tair,WB) is calculated which meets the outlet water temperature setpoint. This
5102 : // desired range and approach temperature also provides a balance point for the empirical model where:
5103 : // Tair,WB + Twater,range + Tapproach = Node(WaterInletNode)%Temp
5104 : // Calculation of water outlet temperature uses one of the following equations:
5105 : // Twater,outlet = Tair,WB + Tapproach (1) or
5106 : // Twater,outlet = Twater,inlet - Twater,range (2)
5107 : // If a solution (or balance) is found, these 2 calculation methods are equal. Equation 2 is used to calculate
5108 : // the outlet water temperature in the free convection regime and at the minimum or maximum fan speed so that
5109 : // if a solution is not reached, the outlet water temperature is approximately equal to the inlet water temperature
5110 : // and the tower fan must be varied to meet the setpoint. Equation 1 is used when the fan speed is varied between
5111 : // the minimum and maximum fan speed to meet the outlet water temperature setpoint.
5112 : // The outlet water temperature in the free convection regime is first calculated to see if the setpoint is met.
5113 : // If the setpoint is met, the fan is OFF and the outlet water temperature is allowed to float below the set
5114 : // point temperature. If the setpoint is not met, the outlet water temperature is re-calculated at the minimum
5115 : // fan speed. If the setpoint is met, the fan is cycled to exactly meet the outlet water temperature setpoint.
5116 : // If the setpoint is not met at the minimum fan speed, the outlet water temperature is re-calculated at the
5117 : // maximum fan speed. If the setpoint at the maximum fan speed is not met, the fan runs at maximum speed the
5118 : // entire time step. If the setpoint is met at the maximum fan speed, the fan speed is varied to meet the setpoint.
5119 : // If a tower has multiple cells, the specified inputs of or the autosized capacity
5120 : // and air/water flow rates are for the entire tower. The number of cells to operate
5121 : // is first determined based on the user entered minimal and maximal water flow fractions
5122 : // per cell. If the loads are not met, more cells (if available) will operate to meet
5123 : // the loads. Inside each cell, the fan speed varies in the same way.
5124 : // REFERENCES:
5125 : // Benton, D.J., Bowmand, C.F., Hydeman, M., Miller, P.,
5126 : // "An Improved Cooling Tower Algorithm for the CoolToolsTM Simulation Model".
5127 : // ASHRAE Transactions 2002, V. 108, Pt. 1.
5128 : // York International Corporation, "YORKcalcTM Software, Chiller-Plant Energy-Estimating Program",
5129 : // Form 160.00-SG2 (0502). 2002.
5130 :
5131 : // SUBROUTINE PARAMETER DEFINITIONS:
5132 :
5133 625884 : int constexpr MaxIte(500); // Maximum number of iterations
5134 625884 : Real64 constexpr Acc(0.0001); // Accuracy of result
5135 : static constexpr std::string_view RoutineName("calculateVariableSpeedTower");
5136 :
5137 : // Added for multi-cell. Determine the number of cells operating
5138 625884 : Real64 WaterMassFlowRatePerCellMin = 0.0;
5139 : Real64 WaterMassFlowRatePerCellMax;
5140 625884 : int NumCellMin(0);
5141 625884 : int NumCellMax(0);
5142 : Real64 WaterMassFlowRatePerCell;
5143 625884 : if (this->DesWaterMassFlowRate > 0.0) {
5144 625439 : WaterMassFlowRatePerCellMin = this->DesWaterMassFlowRate * this->MinFracFlowRate / this->NumCell;
5145 625439 : WaterMassFlowRatePerCellMax = this->DesWaterMassFlowRate * this->MaxFracFlowRate / this->NumCell;
5146 :
5147 : // round it up to the nearest integer
5148 625439 : NumCellMin = min(int((this->WaterMassFlowRate / WaterMassFlowRatePerCellMax) + 0.9999), this->NumCell);
5149 625439 : NumCellMax = min(int((this->WaterMassFlowRate / WaterMassFlowRatePerCellMin) + 0.9999), this->NumCell);
5150 : }
5151 :
5152 : // cap min at 1
5153 625884 : if (NumCellMin <= 0) NumCellMin = 1;
5154 625884 : if (NumCellMax <= 0) NumCellMax = 1;
5155 :
5156 625884 : if (this->cellCtrl == CellCtrl::MinCell) {
5157 23390 : this->NumCellOn = NumCellMin;
5158 : } else {
5159 602494 : this->NumCellOn = NumCellMax;
5160 : }
5161 :
5162 625884 : WaterMassFlowRatePerCell = this->WaterMassFlowRate / this->NumCellOn;
5163 :
5164 : // Initialize subroutine variables
5165 625884 : this->Qactual = 0.0;
5166 625884 : this->FanPower = 0.0;
5167 625884 : this->OutletWaterTemp = state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp;
5168 :
5169 625884 : this->WaterUsage = 0.0;
5170 625884 : Real64 Twb = this->AirWetBulb;
5171 625884 : Real64 TwbCapped = this->AirWetBulb;
5172 :
5173 : // water temperature setpoint
5174 625884 : Real64 TempSetPoint(0.0); // Outlet water temperature setpoint (C)
5175 625884 : switch (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopDemandCalcScheme) {
5176 625884 : case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
5177 625884 : TempSetPoint = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopSide(this->plantLoc.loopSideNum).TempSetPoint;
5178 625884 : } break;
5179 0 : case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
5180 0 : TempSetPoint = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopSide(this->plantLoc.loopSideNum).TempSetPointHi;
5181 0 : } break;
5182 0 : default: {
5183 0 : assert(false);
5184 : } break;
5185 : }
5186 :
5187 : // If there is a fault of condenser SWT Sensor
5188 625884 : if (this->FaultyCondenserSWTFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
5189 0 : (!state.dataGlobal->KickOffSimulation)) {
5190 0 : int FaultIndex = this->FaultyCondenserSWTIndex;
5191 0 : Real64 TowerOutletTemp_ff = TempSetPoint;
5192 :
5193 : // calculate the sensor offset using fault information
5194 0 : this->FaultyCondenserSWTOffset = state.dataFaultsMgr->FaultsCondenserSWTSensor(FaultIndex).CalFaultOffsetAct(state);
5195 : // update the TempSetPoint
5196 0 : TempSetPoint = TowerOutletTemp_ff - this->FaultyCondenserSWTOffset;
5197 : }
5198 :
5199 625884 : Real64 Tr = state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp - TempSetPoint;
5200 625884 : Real64 Ta = TempSetPoint - this->AirWetBulb;
5201 :
5202 : // Do not RETURN here if flow rate is less than MassFlowTolerance. Check basin heater and then RETURN.
5203 625884 : if (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopSide(this->plantLoc.loopSideNum).FlowLock == DataPlant::FlowLock::Unlocked)
5204 535706 : return; // TODO: WTF
5205 :
5206 312870 : bool returnFlagSet = false;
5207 312870 : this->checkMassFlowAndLoad(state, MyLoad, RunFlag, returnFlagSet);
5208 312870 : if (returnFlagSet) return;
5209 :
5210 : // loop to increment NumCell if we cannot meet the setpoint with the actual number of cells calculated above
5211 90178 : bool IncrNumCellFlag = true;
5212 : Real64 OutletWaterTempOFF; // Outlet water temperature with fan OFF (C)
5213 90178 : Real64 OutletWaterTempON = 0.0; // Outlet water temperature with fan ON at maximum fan speed (C)
5214 90178 : Real64 FreeConvectionCapFrac = 0.0; // fraction of tower capacity in free convection
5215 90178 : Real64 WaterFlowRateRatioCapped = 0.0; // Water flow rate ratio passed to VS tower model
5216 : Real64 TrCapped; // range temp passed to VS tower model
5217 : Real64 TaCapped; // approach temp passed to VS tower model
5218 186752 : while (IncrNumCellFlag) {
5219 96574 : IncrNumCellFlag = false;
5220 : // Initialize inlet node water properties
5221 96574 : Real64 const WaterDensity = FluidProperties::GetDensityGlycol(state,
5222 96574 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
5223 96574 : state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp,
5224 96574 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
5225 : RoutineName);
5226 96574 : Real64 const WaterFlowRateRatio = WaterMassFlowRatePerCell / (WaterDensity * this->CalibratedWaterFlowRate / this->NumCell);
5227 :
5228 : // check independent inputs with respect to model boundaries
5229 96574 : this->checkModelBounds(state, Twb, Tr, Ta, WaterFlowRateRatio, TwbCapped, TrCapped, TaCapped, WaterFlowRateRatioCapped);
5230 :
5231 : // determine the free convection capacity by finding the outlet temperature at full air flow and multiplying
5232 : // the tower's full capacity temperature difference by the percentage of tower capacity in free convection
5233 : // regime specified by the user
5234 :
5235 96574 : this->airFlowRateRatio = 1.0;
5236 96574 : OutletWaterTempOFF = state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp;
5237 96574 : this->OutletWaterTemp = OutletWaterTempOFF;
5238 96574 : FreeConvectionCapFrac = this->FreeConvectionCapacityFraction;
5239 96574 : OutletWaterTempON = this->calculateVariableTowerOutletTemp(state, WaterFlowRateRatioCapped, this->airFlowRateRatio, TwbCapped);
5240 :
5241 96574 : if (OutletWaterTempON > TempSetPoint) {
5242 47867 : this->FanCyclingRatio = 1.0;
5243 47867 : this->airFlowRateRatio = 1.0;
5244 47867 : this->FanPower = this->HighSpeedFanPower * this->NumCellOn / this->NumCell;
5245 47867 : this->OutletWaterTemp = OutletWaterTempON;
5246 : // if possible increase the number of cells and do the calculations again with the new water mass flow rate per cell
5247 47867 : if (this->NumCellOn < this->NumCell && (this->WaterMassFlowRate / (this->NumCellOn + 1)) > WaterMassFlowRatePerCellMin) {
5248 6396 : ++this->NumCellOn;
5249 6396 : WaterMassFlowRatePerCell = this->WaterMassFlowRate / this->NumCellOn;
5250 6396 : IncrNumCellFlag = true;
5251 : }
5252 : }
5253 : }
5254 :
5255 : // find the correct air ratio only if full flow is too much
5256 90178 : if (OutletWaterTempON < TempSetPoint) {
5257 : // outlet water temperature is calculated in the free convection regime
5258 48707 : OutletWaterTempOFF = state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp -
5259 48707 : FreeConvectionCapFrac * (state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp - OutletWaterTempON);
5260 : // fan is OFF
5261 48707 : this->FanCyclingRatio = 0.0;
5262 : // air flow ratio is assumed to be the fraction of tower capacity in the free convection regime (fan is OFF but air is flowing)
5263 48707 : this->airFlowRateRatio = FreeConvectionCapFrac;
5264 :
5265 : // Assume setpoint was met using free convection regime (pump ON and fan OFF)
5266 48707 : this->FanPower = 0.0;
5267 48707 : this->OutletWaterTemp = OutletWaterTempOFF;
5268 :
5269 48707 : if (OutletWaterTempOFF > TempSetPoint) {
5270 : // Setpoint was not met, turn on cooling tower fan at minimum fan speed
5271 :
5272 47621 : this->airFlowRateRatio = this->MinimumVSAirFlowFrac;
5273 : Real64 OutletWaterTempMIN; // Outlet water temperature with fan at minimum speed (C)
5274 47621 : OutletWaterTempMIN = this->calculateVariableTowerOutletTemp(state, WaterFlowRateRatioCapped, this->airFlowRateRatio, TwbCapped);
5275 :
5276 47621 : if (OutletWaterTempMIN < TempSetPoint) {
5277 : // if setpoint was exceeded, cycle the fan at minimum air flow to meet the setpoint temperature
5278 20074 : if (this->FanPowerfAirFlowCurve == 0) {
5279 0 : this->FanPower = pow_3(this->airFlowRateRatio) * this->HighSpeedFanPower * this->NumCellOn / this->NumCell;
5280 : } else {
5281 20074 : Real64 const FanCurveValue = Curve::CurveValue(state, this->FanPowerfAirFlowCurve, this->airFlowRateRatio);
5282 20074 : this->FanPower = max(0.0, (this->HighSpeedFanPower * FanCurveValue)) * this->NumCellOn / this->NumCell;
5283 : }
5284 : // fan is cycling ON and OFF at the minimum fan speed. Adjust fan power and air flow rate ratio according to cycling rate
5285 20074 : this->FanCyclingRatio = ((OutletWaterTempOFF - TempSetPoint) / (OutletWaterTempOFF - OutletWaterTempMIN));
5286 20074 : this->FanPower *= this->FanCyclingRatio;
5287 20074 : this->OutletWaterTemp = TempSetPoint;
5288 20074 : this->airFlowRateRatio =
5289 20074 : (this->FanCyclingRatio * this->MinimumVSAirFlowFrac) + ((1 - this->FanCyclingRatio) * FreeConvectionCapFrac);
5290 : } else {
5291 : // if setpoint was not met at minimum fan speed, set fan speed to maximum
5292 27547 : this->airFlowRateRatio = 1.0;
5293 : // fan will not cycle and runs the entire time step
5294 27547 : this->FanCyclingRatio = 1.0;
5295 :
5296 27547 : this->OutletWaterTemp =
5297 27547 : this->calculateVariableTowerOutletTemp(state, WaterFlowRateRatioCapped, this->airFlowRateRatio, TwbCapped);
5298 :
5299 : // Setpoint was met with pump ON and fan ON at full flow
5300 : // Calculate the fraction of full air flow to exactly meet the setpoint temperature
5301 579894 : auto f = [&state, this, WaterFlowRateRatioCapped, TwbCapped, Tr, Ta](Real64 FlowRatio) {
5302 289947 : Real64 TapproachActual = this->calculateVariableSpeedApproach(state, WaterFlowRateRatioCapped, FlowRatio, TwbCapped, Tr);
5303 289947 : return Ta - TapproachActual;
5304 27547 : };
5305 27547 : int SolFla = 0;
5306 27547 : General::SolveRoot(state, Acc, MaxIte, SolFla, this->airFlowRateRatio, f, this->MinimumVSAirFlowFrac, 1.0);
5307 27547 : if (SolFla == -1) {
5308 0 : if (!state.dataGlobal->WarmupFlag)
5309 0 : ShowWarningError(
5310 : state,
5311 0 : format("Cooling tower iteration limit exceeded when calculating air flow rate ratio for tower {}", this->Name));
5312 : // IF RegulaFalsi cannot find a solution then provide detailed output for debugging
5313 27547 : } else if (SolFla == -2) {
5314 0 : if (!state.dataGlobal->WarmupFlag) {
5315 :
5316 0 : if (this->CoolingTowerAFRRFailedCount < 1) {
5317 0 : ++this->CoolingTowerAFRRFailedCount;
5318 0 : ShowWarningError(
5319 : state,
5320 0 : format("CoolingTower:VariableSpeed \"{}\" - Cooling tower air flow rate ratio calculation failed ", this->Name));
5321 0 : ShowContinueError(state,
5322 0 : format("...with conditions as Twb = {:5.2F}, Trange = {:5.2F}, Tapproach = {:5.2F}, and water flow "
5323 : "rate ratio = {:5.2F}",
5324 : TwbCapped,
5325 : Tr,
5326 : Ta,
5327 : WaterFlowRateRatioCapped));
5328 0 : ShowContinueError(state, "...a solution could not be found within the valid range of air flow rate ratios");
5329 0 : ShowContinueErrorTimeStamp(
5330 0 : state, format(" ...Valid air flow rate ratio range = {:5.2F} to 1.0.", this->MinimumVSAirFlowFrac));
5331 0 : ShowContinueError(state, "...Consider modifying the design approach or design range temperature for this tower.");
5332 : } else {
5333 0 : ShowRecurringWarningErrorAtEnd(state,
5334 0 : "CoolingTower:VariableSpeed \"" + this->Name +
5335 : "\" - Cooling tower air flow rate ratio calculation failed error continues.",
5336 0 : this->CoolingTowerAFRRFailedIndex);
5337 : }
5338 : }
5339 : }
5340 :
5341 : // Use theoretical cubic for determination of fan power if user has not specified a fan power ratio curve
5342 27547 : if (this->FanPowerfAirFlowCurve == 0) {
5343 0 : this->FanPower = pow_3(this->airFlowRateRatio) * this->HighSpeedFanPower * this->NumCellOn / this->NumCell;
5344 : } else {
5345 27547 : Real64 const FanCurveValue = Curve::CurveValue(state, this->FanPowerfAirFlowCurve, this->airFlowRateRatio);
5346 27547 : this->FanPower = max(0.0, (this->HighSpeedFanPower * FanCurveValue)) * this->NumCellOn / this->NumCell;
5347 : }
5348 : // outlet water temperature is calculated as the inlet air wet-bulb temperature plus tower approach temperature
5349 27547 : this->OutletWaterTemp = Twb + Ta;
5350 : }
5351 : }
5352 : }
5353 :
5354 90178 : Real64 const CpWater = FluidProperties::GetSpecificHeatGlycol(state,
5355 90178 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
5356 90178 : state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp,
5357 90178 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
5358 : RoutineName);
5359 90178 : this->Qactual = this->WaterMassFlowRate * CpWater * (state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp - this->OutletWaterTemp);
5360 :
5361 : // calculate end time of current time step
5362 90178 : Real64 const CurrentEndTime = state.dataGlobal->CurrentTime + state.dataHVACGlobal->SysTimeElapsed;
5363 :
5364 : // Print warning messages only when valid and only for the first occurrence. Let summary provide statistics.
5365 : // Wait for next time step to print warnings. If simulation iterates, print out
5366 : // the warning for the last iteration only. Must wait for next time step to accomplish this.
5367 : // If a warning occurs and the simulation down shifts, the warning is not valid.
5368 90178 : if (CurrentEndTime > this->CurrentEndTimeLast && state.dataHVACGlobal->TimeStepSys >= this->TimeStepSysLast) {
5369 0 : if (state.dataCondenserLoopTowers->towers(this->VSTower).PrintLGMessage) {
5370 0 : ++state.dataCondenserLoopTowers->towers(this->VSTower).VSErrorCountFlowFrac;
5371 : // Show single warning and pass additional info to ShowRecurringWarningErrorAtEnd
5372 0 : if (state.dataCondenserLoopTowers->towers(this->VSTower).VSErrorCountFlowFrac < 2) {
5373 0 : ShowWarningError(state, state.dataCondenserLoopTowers->towers(this->VSTower).LGBuffer1);
5374 0 : ShowContinueError(state, state.dataCondenserLoopTowers->towers(this->VSTower).LGBuffer2);
5375 : } else {
5376 0 : ShowRecurringWarningErrorAtEnd(state,
5377 0 : format("{} \"{}\" - Liquid to gas ratio is out of range error continues...",
5378 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
5379 0 : this->Name),
5380 0 : state.dataCondenserLoopTowers->towers(this->VSTower).ErrIndexLG,
5381 0 : state.dataCondenserLoopTowers->towers(this->VSTower).LGLast,
5382 0 : state.dataCondenserLoopTowers->towers(this->VSTower).LGLast);
5383 : }
5384 : }
5385 : }
5386 :
5387 : // save last system time step and last end time of current time step (used to determine if warning is valid)
5388 90178 : this->TimeStepSysLast = state.dataHVACGlobal->TimeStepSys;
5389 90178 : this->CurrentEndTimeLast = CurrentEndTime;
5390 :
5391 : // warn user on first occurrence if flow fraction is greater than maximum for the YorkCalc model, use recurring warning stats
5392 90178 : if (this->TowerModelType == ModelType::YorkCalcModel || this->TowerModelType == ModelType::YorkCalcUserDefined) {
5393 45298 : state.dataCondenserLoopTowers->towers(this->VSTower).PrintLGMessage = false;
5394 : // Do not report error message in free convection regime
5395 45298 : if (this->airFlowRateRatio > this->MinimumVSAirFlowFrac) {
5396 28778 : Real64 const FlowFraction = WaterFlowRateRatioCapped / this->airFlowRateRatio;
5397 : // Flow fractions greater than a MaxLiquidToGasRatio of 8 are not reliable using the YorkCalc model
5398 28778 : if (FlowFraction > state.dataCondenserLoopTowers->towers(this->VSTower).MaxLiquidToGasRatio) {
5399 : // Report warnings only during actual simulation
5400 0 : if (!state.dataGlobal->WarmupFlag) {
5401 0 : state.dataCondenserLoopTowers->towers(this->VSTower).PrintLGMessage = true;
5402 0 : state.dataCondenserLoopTowers->towers(this->VSTower).LGBuffer1 =
5403 0 : format("{} \"{}\" - Liquid to gas ratio (L/G) is out of range at {:5.2F}.",
5404 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
5405 0 : this->Name,
5406 0 : FlowFraction);
5407 0 : state.dataCondenserLoopTowers->towers(this->VSTower).LGBuffer2 =
5408 0 : format(" ...Valid maximum ratio = {:5.2F}. Occurrence info = {}, {} {}",
5409 0 : state.dataCondenserLoopTowers->towers(this->VSTower).MaxLiquidToGasRatio,
5410 0 : state.dataEnvrn->EnvironmentName,
5411 0 : state.dataEnvrn->CurMnDy,
5412 0 : General::CreateSysTimeIntervalString(state));
5413 :
5414 0 : state.dataCondenserLoopTowers->towers(this->VSTower).LGLast = FlowFraction;
5415 : }
5416 : }
5417 : }
5418 : }
5419 : }
5420 :
5421 80820 : void CoolingTower::calculateMerkelVariableSpeedTower(EnergyPlusData &state, Real64 &MyLoad, bool RunFlag)
5422 : {
5423 :
5424 : // SUBROUTINE INFORMATION:
5425 : // AUTHOR B.Griffith
5426 : // DATE WRITTEN August 2013
5427 : // MODIFIED Jun. 2016, R Zhang, Applied the condenser supply water temperature sensor fault model
5428 : // Jul. 2016, R Zhang, Applied the cooling tower fouling fault model
5429 :
5430 : // PURPOSE OF THIS SUBROUTINE:
5431 : // Calculate variable speed tower model using Merkel's theory with UA adjustments developed by Scheier
5432 :
5433 : // METHODOLOGY EMPLOYED:
5434 : // Find a fan speed that operates the tower to meet MyLoad
5435 :
5436 : // SUBROUTINE PARAMETER DEFINITIONS:
5437 80820 : Real64 constexpr DesignWetBulb(25.56); // tower outdoor air entering wetbulb for design [C]
5438 80820 : int constexpr MaxIte(500); // Maximum number of iterations for solver
5439 80820 : Real64 constexpr Acc(1.e-3); // Accuracy of solver result
5440 : static constexpr std::string_view RoutineName("calculateMerkelVariableSpeedTower");
5441 :
5442 80820 : Real64 const CpWater = FluidProperties::GetSpecificHeatGlycol(state,
5443 80820 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
5444 80820 : state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp,
5445 80820 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
5446 : RoutineName);
5447 80820 : this->Qactual = 0.0;
5448 80820 : this->FanPower = 0.0;
5449 80820 : this->OutletWaterTemp = state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp;
5450 :
5451 80820 : Real64 freeConvTowerUA = this->FreeConvTowerUA;
5452 80820 : Real64 highSpeedTowerUA = this->HighSpeedTowerUA;
5453 :
5454 : // If there is a fault of condenser SWT Sensor
5455 80820 : if (this->FaultyCondenserSWTFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
5456 0 : (!state.dataGlobal->KickOffSimulation)) {
5457 0 : int FaultIndex = this->FaultyCondenserSWTIndex;
5458 : // calculate the sensor offset using fault information
5459 0 : this->FaultyCondenserSWTOffset = state.dataFaultsMgr->FaultsCondenserSWTSensor(FaultIndex).CalFaultOffsetAct(state);
5460 : }
5461 :
5462 : // If there is a fault of cooling tower fouling
5463 80820 : if (this->FaultyTowerFoulingFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
5464 0 : (!state.dataGlobal->KickOffSimulation)) {
5465 0 : int FaultIndex = this->FaultyTowerFoulingIndex;
5466 0 : Real64 FreeConvTowerUA_ff = this->FreeConvTowerUA;
5467 0 : Real64 HighSpeedTowerUA_ff = this->HighSpeedTowerUA;
5468 :
5469 : // calculate the Faulty Tower Fouling Factor using fault information
5470 0 : this->FaultyTowerFoulingFactor = state.dataFaultsMgr->FaultsTowerFouling(FaultIndex).CalFaultyTowerFoulingFactor(state);
5471 :
5472 : // update the tower UA values at faulty cases
5473 0 : freeConvTowerUA = FreeConvTowerUA_ff * this->FaultyTowerFoulingFactor;
5474 0 : highSpeedTowerUA = HighSpeedTowerUA_ff * this->FaultyTowerFoulingFactor;
5475 : }
5476 :
5477 80820 : Real64 WaterMassFlowRatePerCellMin = 0.0;
5478 : Real64 WaterMassFlowRatePerCellMax;
5479 :
5480 : // Added for multi-cell. Determine the number of cells operating
5481 80820 : int NumCellMin = 0;
5482 80820 : int NumCellMax = 0;
5483 : Real64 WaterMassFlowRatePerCell;
5484 : Real64 UAdesignPerCell;
5485 : Real64 AirFlowRatePerCell;
5486 80820 : if (this->DesWaterMassFlowRate > 0.0) {
5487 80760 : WaterMassFlowRatePerCellMin = this->DesWaterMassFlowRate * this->MinFracFlowRate / this->NumCell;
5488 80760 : WaterMassFlowRatePerCellMax = this->DesWaterMassFlowRate * this->MaxFracFlowRate / this->NumCell;
5489 :
5490 : // round it up to the nearest integer
5491 80760 : NumCellMin = min(int((this->WaterMassFlowRate / WaterMassFlowRatePerCellMax) + 0.9999), this->NumCell);
5492 80760 : NumCellMax = min(int((this->WaterMassFlowRate / WaterMassFlowRatePerCellMin) + 0.9999), this->NumCell);
5493 : }
5494 :
5495 : // cap min at 1
5496 80820 : if (NumCellMin <= 0) NumCellMin = 1;
5497 80820 : if (NumCellMax <= 0) NumCellMax = 1;
5498 :
5499 80820 : if (this->cellCtrl == CellCtrl::MinCell) {
5500 0 : this->NumCellOn = NumCellMin;
5501 : } else {
5502 80820 : this->NumCellOn = NumCellMax;
5503 : }
5504 :
5505 80820 : WaterMassFlowRatePerCell = this->WaterMassFlowRate / this->NumCellOn;
5506 :
5507 80820 : if ((std::abs(MyLoad) <= HVAC::SmallLoad) || !RunFlag) {
5508 : // tower doesn't need to do anything
5509 50654 : this->OutletWaterTemp = state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp;
5510 50654 : this->FanPower = 0.0;
5511 50654 : this->airFlowRateRatio = 0.0;
5512 50654 : this->Qactual = 0.0;
5513 50654 : CalcBasinHeaterPower(
5514 50654 : state, this->BasinHeaterPowerFTempDiff, this->BasinHeaterSchedulePtr, this->BasinHeaterSetPointTemp, this->BasinHeaterPower);
5515 50654 : return;
5516 30166 : } else if (this->WaterMassFlowRate <= DataBranchAirLoopPlant::MassFlowTolerance || (MyLoad > HVAC::SmallLoad)) {
5517 : // for multiple cells, we assume that it's a common basin
5518 0 : CalcBasinHeaterPower(
5519 0 : state, this->BasinHeaterPowerFTempDiff, this->BasinHeaterSchedulePtr, this->BasinHeaterSetPointTemp, this->BasinHeaterPower);
5520 0 : return;
5521 : }
5522 :
5523 : // first find free convection cooling rate
5524 30166 : UAdesignPerCell = freeConvTowerUA / this->NumCell;
5525 30166 : AirFlowRatePerCell = this->FreeConvAirFlowRate / this->NumCell;
5526 30166 : this->WaterMassFlowRate = state.dataLoopNodes->Node(this->WaterInletNodeNum).MassFlowRate;
5527 30166 : Real64 OutletWaterTempOFF = this->calculateSimpleTowerOutletTemp(state, WaterMassFlowRatePerCell, AirFlowRatePerCell, UAdesignPerCell);
5528 :
5529 30166 : Real64 FreeConvQdot = this->WaterMassFlowRate * CpWater * (state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp - OutletWaterTempOFF);
5530 30166 : this->FanPower = 0.0;
5531 :
5532 30166 : if (std::abs(MyLoad) <= FreeConvQdot) { // can meet load with free convection and fan off
5533 :
5534 78 : this->OutletWaterTemp = OutletWaterTempOFF;
5535 78 : this->airFlowRateRatio = 0.0;
5536 78 : this->Qactual = FreeConvQdot;
5537 78 : CalcBasinHeaterPower(
5538 78 : state, this->BasinHeaterPowerFTempDiff, this->BasinHeaterSchedulePtr, this->BasinHeaterSetPointTemp, this->BasinHeaterPower);
5539 :
5540 78 : return;
5541 : }
5542 :
5543 : // next find full fan speed cooling rate
5544 30088 : UAdesignPerCell = highSpeedTowerUA / this->NumCell;
5545 30088 : AirFlowRatePerCell = this->HighSpeedAirFlowRate / this->NumCell;
5546 30088 : this->airFlowRateRatio = 1.0;
5547 30088 : Real64 WaterFlowRateRatio = WaterMassFlowRatePerCell / this->DesWaterMassFlowRatePerCell;
5548 30088 : Real64 UAwetbulbAdjFac = Curve::CurveValue(state, this->UAModFuncWetBulbDiffCurvePtr, (DesignWetBulb - this->AirWetBulb));
5549 30088 : Real64 UAairflowAdjFac = Curve::CurveValue(state, this->UAModFuncAirFlowRatioCurvePtr, this->airFlowRateRatio);
5550 30088 : Real64 UAwaterflowAdjFac = Curve::CurveValue(state, this->UAModFuncWaterFlowRatioCurvePtr, WaterFlowRateRatio);
5551 30088 : Real64 UAadjustedPerCell = UAdesignPerCell * UAwetbulbAdjFac * UAairflowAdjFac * UAwaterflowAdjFac;
5552 30088 : this->OutletWaterTemp = this->calculateSimpleTowerOutletTemp(state, WaterMassFlowRatePerCell, AirFlowRatePerCell, UAadjustedPerCell);
5553 : Real64 FullSpeedFanQdot =
5554 30088 : this->WaterMassFlowRate * CpWater * (state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp - this->OutletWaterTemp);
5555 30088 : Real64 FanPowerAdjustFac = 0.0;
5556 30088 : if (FullSpeedFanQdot <= std::abs(MyLoad)) { // full speed is what we want.
5557 :
5558 29130 : if ((FullSpeedFanQdot + HVAC::SmallLoad) < std::abs(MyLoad) && (this->NumCellOn < this->NumCell) &&
5559 0 : ((this->WaterMassFlowRate / (this->NumCellOn + 1)) >= WaterMassFlowRatePerCellMin)) {
5560 : // If full fan and not meeting setpoint, then increase number of cells until all are used or load is satisfied
5561 0 : bool IncrNumCellFlag = true; // set value to true to enter in the loop
5562 0 : while (IncrNumCellFlag) {
5563 0 : ++this->NumCellOn;
5564 0 : WaterMassFlowRatePerCell = this->WaterMassFlowRate / this->NumCellOn;
5565 0 : WaterFlowRateRatio = WaterMassFlowRatePerCell / this->DesWaterMassFlowRatePerCell;
5566 0 : UAwaterflowAdjFac = Curve::CurveValue(state, this->UAModFuncWaterFlowRatioCurvePtr, WaterFlowRateRatio);
5567 0 : UAadjustedPerCell = UAdesignPerCell * UAwetbulbAdjFac * UAairflowAdjFac * UAwaterflowAdjFac;
5568 0 : this->OutletWaterTemp =
5569 0 : this->calculateSimpleTowerOutletTemp(state, WaterMassFlowRatePerCell, AirFlowRatePerCell, UAadjustedPerCell);
5570 0 : IncrNumCellFlag = (FullSpeedFanQdot + HVAC::SmallLoad) < std::abs(MyLoad) && (this->NumCellOn < this->NumCell) &&
5571 0 : ((this->WaterMassFlowRate / (this->NumCellOn + 1)) >= WaterMassFlowRatePerCellMin);
5572 : }
5573 0 : FullSpeedFanQdot =
5574 0 : this->WaterMassFlowRate * CpWater * (state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp - this->OutletWaterTemp);
5575 : }
5576 29130 : this->Qactual = FullSpeedFanQdot;
5577 29130 : CalcBasinHeaterPower(
5578 29130 : state, this->BasinHeaterPowerFTempDiff, this->BasinHeaterSchedulePtr, this->BasinHeaterSetPointTemp, this->BasinHeaterPower);
5579 : // now calculate fan power
5580 29130 : FanPowerAdjustFac = Curve::CurveValue(state, this->FanPowerfAirFlowCurve, this->airFlowRateRatio);
5581 29130 : this->FanPower = this->HighSpeedFanPower * FanPowerAdjustFac * this->NumCellOn / this->NumCell;
5582 :
5583 29130 : return;
5584 : }
5585 :
5586 : // next find minimum air flow ratio cooling rate
5587 958 : this->airFlowRateRatio = this->MinimumVSAirFlowFrac;
5588 958 : AirFlowRatePerCell = this->airFlowRateRatio * this->HighSpeedAirFlowRate / this->NumCell;
5589 958 : UAairflowAdjFac = Curve::CurveValue(state, this->UAModFuncAirFlowRatioCurvePtr, this->airFlowRateRatio);
5590 958 : UAadjustedPerCell = UAdesignPerCell * UAwetbulbAdjFac * UAairflowAdjFac * UAwaterflowAdjFac;
5591 958 : this->OutletWaterTemp = this->calculateSimpleTowerOutletTemp(state, WaterMassFlowRatePerCell, AirFlowRatePerCell, UAadjustedPerCell);
5592 : Real64 MinSpeedFanQdot =
5593 958 : this->WaterMassFlowRate * CpWater * (state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp - this->OutletWaterTemp);
5594 :
5595 958 : if (std::abs(MyLoad) <= MinSpeedFanQdot) { // min fan speed already exceeds load)
5596 164 : this->Qactual = MinSpeedFanQdot;
5597 164 : CalcBasinHeaterPower(
5598 164 : state, this->BasinHeaterPowerFTempDiff, this->BasinHeaterSchedulePtr, this->BasinHeaterSetPointTemp, this->BasinHeaterPower);
5599 : // now calculate fan power
5600 164 : FanPowerAdjustFac = Curve::CurveValue(state, this->FanPowerfAirFlowCurve, this->airFlowRateRatio);
5601 164 : this->FanPower = this->HighSpeedFanPower * FanPowerAdjustFac * this->NumCellOn / this->NumCell;
5602 164 : return;
5603 : }
5604 :
5605 794 : if ((MinSpeedFanQdot < std::abs(MyLoad)) && (std::abs(MyLoad) < FullSpeedFanQdot)) {
5606 : // load can be refined by modulating fan speed, call regula-falsi
5607 8034 : auto f = [&state, this, MyLoad, WaterMassFlowRatePerCell, UAdesignPerCell, UAwetbulbAdjFac, UAwaterflowAdjFac, CpWater](
5608 36200 : Real64 airFlowRateRatioLocal) {
5609 7240 : Real64 const AirFlowRatePerCell = airFlowRateRatioLocal * this->HighSpeedAirFlowRate / this->NumCell;
5610 7240 : Real64 const UAairflowAdjFac = Curve::CurveValue(state, this->UAModFuncAirFlowRatioCurvePtr, airFlowRateRatioLocal);
5611 7240 : Real64 const UAadjustedPerCell = UAdesignPerCell * UAwetbulbAdjFac * UAairflowAdjFac * UAwaterflowAdjFac;
5612 : Real64 OutletWaterTempTrial =
5613 7240 : this->calculateSimpleTowerOutletTemp(state, WaterMassFlowRatePerCell, AirFlowRatePerCell, UAadjustedPerCell);
5614 : Real64 const Qdot =
5615 7240 : this->WaterMassFlowRate * CpWater * (state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp - OutletWaterTempTrial);
5616 7240 : return std::abs(MyLoad) - Qdot;
5617 794 : };
5618 794 : int SolFla = 0;
5619 794 : General::SolveRoot(state, Acc, MaxIte, SolFla, this->airFlowRateRatio, f, this->MinimumVSAirFlowFrac, 1.0);
5620 :
5621 794 : if (SolFla == -1) {
5622 0 : if (!state.dataGlobal->WarmupFlag) {
5623 0 : if (this->VSMerkelAFRErrorIter < 1) {
5624 0 : ++this->VSMerkelAFRErrorIter;
5625 0 : ShowWarningError(state,
5626 0 : format("{} - Iteration limit exceeded calculating variable speed fan ratio for unit = {}",
5627 : cCoolingTower_VariableSpeedMerkel,
5628 0 : this->Name));
5629 0 : ShowContinueError(state,
5630 0 : format("Estimated air flow ratio = {:.4R}",
5631 0 : (std::abs(MyLoad) - MinSpeedFanQdot) / (FullSpeedFanQdot - MinSpeedFanQdot)));
5632 0 : ShowContinueError(state, format("Calculated air flow ratio = {:.4R}", this->airFlowRateRatio));
5633 0 : ShowContinueErrorTimeStamp(state,
5634 : "The calculated air flow ratio will be used and the simulation continues. Occurrence info:");
5635 : }
5636 0 : ShowRecurringWarningErrorAtEnd(
5637 : state,
5638 0 : cCoolingTower_VariableSpeedMerkel + " \"" + this->Name +
5639 : "\" - Iteration limit exceeded calculating air flow ratio error continues. air flow ratio statistics follow.",
5640 0 : this->VSMerkelAFRErrorIterIndex,
5641 0 : this->airFlowRateRatio,
5642 0 : this->airFlowRateRatio);
5643 : }
5644 794 : } else if (SolFla == -2) {
5645 0 : this->airFlowRateRatio = (std::abs(MyLoad) - MinSpeedFanQdot) / (FullSpeedFanQdot - MinSpeedFanQdot);
5646 0 : if (!state.dataGlobal->WarmupFlag) {
5647 0 : if (this->VSMerkelAFRErrorFail < 1) {
5648 0 : ++this->VSMerkelAFRErrorFail;
5649 0 : ShowWarningError(state,
5650 0 : format("{} - solver failed calculating variable speed fan ratio for unit = {}",
5651 : cCoolingTower_VariableSpeedMerkel,
5652 0 : this->Name));
5653 0 : ShowContinueError(state, format("Estimated air flow ratio = {:.4R}", this->airFlowRateRatio));
5654 0 : ShowContinueErrorTimeStamp(state, "The estimated air flow ratio will be used and the simulation continues. Occurrence info:");
5655 : }
5656 0 : ShowRecurringWarningErrorAtEnd(
5657 : state,
5658 0 : cCoolingTower_VariableSpeedMerkel + " \"" + this->Name +
5659 : "\" - solver failed calculating air flow ratio error continues. air flow ratio statistics follow.",
5660 0 : this->VSMerkelAFRErrorFailIndex,
5661 0 : this->airFlowRateRatio,
5662 0 : this->airFlowRateRatio);
5663 : }
5664 : }
5665 :
5666 : // now rerun to get peformance with AirFlowRateRatio
5667 794 : AirFlowRatePerCell = this->airFlowRateRatio * this->HighSpeedAirFlowRate / this->NumCell;
5668 :
5669 794 : UAairflowAdjFac = Curve::CurveValue(state, this->UAModFuncAirFlowRatioCurvePtr, this->airFlowRateRatio);
5670 794 : UAadjustedPerCell = UAdesignPerCell * UAwetbulbAdjFac * UAairflowAdjFac * UAwaterflowAdjFac;
5671 :
5672 794 : this->OutletWaterTemp = this->calculateSimpleTowerOutletTemp(state, WaterMassFlowRatePerCell, AirFlowRatePerCell, UAadjustedPerCell);
5673 794 : this->Qactual = this->WaterMassFlowRate * CpWater * (state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp - this->OutletWaterTemp);
5674 794 : CalcBasinHeaterPower(
5675 794 : state, this->BasinHeaterPowerFTempDiff, this->BasinHeaterSchedulePtr, this->BasinHeaterSetPointTemp, this->BasinHeaterPower);
5676 :
5677 : // now calculate fan power
5678 794 : FanPowerAdjustFac = Curve::CurveValue(state, this->FanPowerfAirFlowCurve, this->airFlowRateRatio);
5679 794 : this->FanPower = this->HighSpeedFanPower * FanPowerAdjustFac * this->NumCellOn / this->NumCell;
5680 : }
5681 : }
5682 :
5683 7210763 : Real64 CoolingTower::calculateSimpleTowerOutletTemp(EnergyPlusData &state,
5684 : Real64 const waterMassFlowRate,
5685 : Real64 const AirFlowRate,
5686 : Real64 const UAdesign)
5687 : {
5688 :
5689 : // SUBROUTINE INFORMATION:
5690 : // AUTHOR Dan Fisher
5691 : // DATE WRITTEN Sept. 1998
5692 : // RE-ENGINEERED Shirey, Raustad, Jan 2001
5693 :
5694 : // PURPOSE OF THIS SUBROUTINE:
5695 : // See purpose for Single Speed or Two Speed tower model
5696 :
5697 : // METHODOLOGY EMPLOYED:
5698 : // See methodology for Single Speed or Two Speed tower model
5699 :
5700 : // REFERENCES:
5701 : // Merkel, F. 1925. Verduftungskuhlung. VDI Forschungsarbeiten, Nr 275, Berlin.
5702 : // ASHRAE 1999. HVAC1KIT: A Toolkit for Primary HVAC System Energy Calculations.
5703 :
5704 : // SUBROUTINE PARAMETER DEFINITIONS:
5705 : static constexpr std::string_view RoutineName("calculateSimpleTowerOutletTemp");
5706 :
5707 : // initialize some local variables
5708 7210763 : Real64 QactualLocal = 0.0; // Actual heat transfer rate between tower water and air [W]
5709 :
5710 : // set local tower inlet and outlet temperature variables
5711 7210763 : this->InletWaterTemp = this->WaterTemp;
5712 7210763 : Real64 OutletWaterTempLocal = this->InletWaterTemp;
5713 7210763 : Real64 InletAirTemp = this->AirTemp; // Dry-bulb temperature of air entering the tower [C]
5714 7210763 : Real64 InletAirWetBulb = this->AirWetBulb; // Wetbulb temp of entering moist air [C]
5715 :
5716 7210763 : if (UAdesign == 0.0) return OutletWaterTempLocal;
5717 :
5718 : // set water and air properties
5719 5125254 : Real64 AirDensity = Psychrometrics::PsyRhoAirFnPbTdbW(state, this->AirPress, InletAirTemp, this->AirHumRat); // Density of air [kg/m3]
5720 5125254 : Real64 AirMassFlowRate = AirFlowRate * AirDensity; // Mass flow rate of air [kg/s]
5721 5125254 : Real64 CpAir = Psychrometrics::PsyCpAirFnW(this->AirHumRat); // Heat capacity of air [J/kg/K]
5722 5125254 : Real64 CpWater = FluidProperties::GetSpecificHeatGlycol(state,
5723 5125254 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
5724 : this->WaterTemp,
5725 5125254 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
5726 : RoutineName); // Heat capacity of water [J/kg/K]
5727 : Real64 InletAirEnthalpy =
5728 5125254 : Psychrometrics::PsyHFnTdbRhPb(state, this->AirWetBulb, 1.0, this->AirPress); // Enthalpy of entering moist air [J/kg]
5729 :
5730 : // initialize exiting wet bulb temperature before iterating on final solution
5731 5125254 : Real64 OutletAirWetBulb = InletAirWetBulb + 6.0; // Wetbulb temp of exiting moist air [C]
5732 :
5733 : // Calculate mass flow rates
5734 5125254 : if (waterMassFlowRate <= 0.0) {
5735 0 : OutletWaterTempLocal = this->InletWaterTemp;
5736 0 : return OutletWaterTempLocal;
5737 : }
5738 :
5739 5125254 : Real64 MdotCpWater = waterMassFlowRate * CpWater; // Water mass flow rate times the heat capacity [W/K]
5740 :
5741 5125254 : int Iter = 0;
5742 : Real64 OutletAirEnthalpy; // Enthalpy of exiting moist air [J/kg]
5743 5125254 : Real64 WetBulbError = 1.0; // Calculated error for exiting wet-bulb temperature between iterations [delta K/K]
5744 5125254 : Real64 DeltaTwb = 1.0; // Absolute value of difference between inlet and outlet air wet-bulb temp [C]
5745 : Real64 OutletAirWetBulbLast; // temporary Wetbulb temp of exiting moist air [C]
5746 5125254 : int constexpr IterMax(50); // Maximum number of iterations allowed
5747 5125254 : Real64 constexpr WetBulbTolerance(0.00001); // Maximum error for exiting wet-bulb temperature between iterations [delta K/K]
5748 5125254 : Real64 constexpr DeltaTwbTolerance(0.001); // Maximum error (tolerance) in DeltaTwb for iteration convergence [C]
5749 20232999 : while ((WetBulbError > WetBulbTolerance) && (Iter <= IterMax) && (DeltaTwb > DeltaTwbTolerance)) {
5750 15107745 : ++Iter;
5751 : // OutletAirEnthalpy = PsyHFnTdbRhPb(OutletAirWetBulb,1.0,OutBaroPress)
5752 15107745 : OutletAirEnthalpy = Psychrometrics::PsyHFnTdbRhPb(state, OutletAirWetBulb, 1.0, this->AirPress);
5753 : // calculate the airside specific heat and capacity
5754 15107745 : Real64 const CpAirside =
5755 15107745 : (OutletAirEnthalpy - InletAirEnthalpy) /
5756 15107745 : (OutletAirWetBulb - InletAirWetBulb); // Delta enthalpy of the tower air divides by delta air wet-bulb temp [J/kg/K]
5757 15107745 : Real64 const AirCapacity = AirMassFlowRate * CpAirside; // MdotCp of air through the tower
5758 : // calculate the minimum to maximum capacity ratios of airside and waterside
5759 15107745 : Real64 const CapacityRatioMin = min(AirCapacity, MdotCpWater); // Minimum capacity of airside and waterside
5760 15107745 : Real64 const CapacityRatioMax = max(AirCapacity, MdotCpWater); // Maximum capacity of airside and waterside
5761 15107745 : Real64 const CapacityRatio = CapacityRatioMin / CapacityRatioMax; // Ratio of minimum to maximum capacity
5762 : // Calculate heat transfer coefficient and number of transfer units (NTU)
5763 15107745 : Real64 const UAactual = UAdesign * CpAirside / CpAir; // UA value at actual conditions [W/C]
5764 15107745 : Real64 const NumTransferUnits = UAactual / CapacityRatioMin; // Number of transfer Units [NTU]
5765 : // calculate heat exchanger effectiveness
5766 : Real64 effectiveness; // Effectiveness of the heat exchanger [-]
5767 15107745 : if (CapacityRatio <= 0.995) {
5768 15097680 : Real64 Exponent = NumTransferUnits * (1.0 - CapacityRatio);
5769 15097680 : if (Exponent >= 700.0) {
5770 0 : effectiveness = NumTransferUnits / (1.0 + NumTransferUnits);
5771 : } else {
5772 15097680 : effectiveness = (1.0 - std::exp(-1.0 * NumTransferUnits * (1.0 - CapacityRatio))) /
5773 15097680 : (1.0 - CapacityRatio * std::exp(-1.0 * NumTransferUnits * (1.0 - CapacityRatio)));
5774 : }
5775 : } else {
5776 10065 : effectiveness = NumTransferUnits / (1.0 + NumTransferUnits);
5777 : }
5778 : // calculate water to air heat transfer and store last exiting WB temp of air
5779 15107745 : QactualLocal = effectiveness * CapacityRatioMin * (this->InletWaterTemp - InletAirWetBulb);
5780 15107745 : OutletAirWetBulbLast = OutletAirWetBulb;
5781 : // calculate new exiting wet bulb temperature of airstream
5782 15107745 : OutletAirWetBulb = InletAirWetBulb + QactualLocal / AirCapacity;
5783 : // Check error tolerance and exit if satisfied
5784 15107745 : DeltaTwb = std::abs(OutletAirWetBulb - InletAirWetBulb);
5785 : // Add KelvinConv to denominator below convert OutletAirWetBulbLast to Kelvin to avoid divide by zero.
5786 : // Wet bulb error units are delta K/K
5787 15107745 : WetBulbError = std::abs((OutletAirWetBulb - OutletAirWetBulbLast) / (OutletAirWetBulbLast + Constant::Kelvin));
5788 : }
5789 :
5790 5125254 : if (QactualLocal >= 0.0) {
5791 5125174 : OutletWaterTempLocal = this->InletWaterTemp - QactualLocal / MdotCpWater;
5792 : } else {
5793 80 : OutletWaterTempLocal = this->InletWaterTemp;
5794 : }
5795 5125254 : return OutletWaterTempLocal;
5796 : }
5797 :
5798 171742 : Real64 CoolingTower::calculateVariableTowerOutletTemp(EnergyPlusData &state,
5799 : Real64 const WaterFlowRateRatio, // current water flow rate ratio (capped if applicable)
5800 : Real64 const airFlowRateRatioLocal, // current air flow rate ratio
5801 : Real64 const Twb // current inlet air wet-bulb temperature (C, capped if applicable)
5802 : )
5803 : {
5804 :
5805 : // SUBROUTINE INFORMATION:
5806 : // AUTHOR Richard Raustad, FSEC
5807 : // DATE WRITTEN Feb. 2005
5808 :
5809 : // PURPOSE OF THIS SUBROUTINE:
5810 : // To calculate the leaving water temperature of the variable speed cooling tower.
5811 :
5812 : // METHODOLOGY EMPLOYED:
5813 : // The range temperature is varied to determine balance point where model output (Tapproach),
5814 : // range temperature and inlet air wet-bulb temperature show a balance as:
5815 : // Twb + Tapproach + Trange = Node(WaterInletNode)%Temp
5816 :
5817 : // REFERENCES:
5818 : // Benton, D.J., Bowmand, C.F., Hydeman, M., Miller, P.,
5819 : // "An Improved Cooling Tower Algorithm for the CoolToolsTM Simulation Model".
5820 : // ASHRAE Transactions 2002, V. 108, Pt. 1.
5821 : // York International Corporation, "YORKcalcTM Software, Chiller-Plant Energy-Estimating Program",
5822 : // Form 160.00-SG2 (0502). 2002.
5823 :
5824 : // SUBROUTINE PARAMETER DEFINITIONS:
5825 171742 : int constexpr MaxIte(500); // Maximum number of iterations
5826 171742 : Real64 constexpr Acc(0.0001); // Accuracy of result
5827 :
5828 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5829 171742 : Real64 constexpr VSTowerMaxRangeTemp(22.2222); // set VS cooling tower range maximum value used for solver
5830 :
5831 : // determine tower outlet water temperature
5832 : Real64 Tr; // range temperature which results in an energy balance
5833 3105424 : auto f = [&state, this, WaterFlowRateRatio, airFlowRateRatioLocal, Twb](Real64 Trange) {
5834 : // call model to determine approach temperature given other independent variables (range temp is being varied to find balance)
5835 1552712 : Real64 Tapproach = this->calculateVariableSpeedApproach(state, WaterFlowRateRatio, airFlowRateRatioLocal, Twb, Trange);
5836 : // calculate residual based on a balance where Twb + Ta + Tr = Inlet Water Temp
5837 1552712 : return (Twb + Tapproach + Trange) - this->WaterTemp;
5838 171742 : };
5839 171742 : int SolFla = 0;
5840 171742 : General::SolveRoot(state, Acc, MaxIte, SolFla, Tr, f, 0.001, max(this->MaxRangeTemp, VSTowerMaxRangeTemp));
5841 :
5842 : // calculate outlet temperature
5843 171742 : Real64 outletWaterTempLocal = this->WaterTemp - min(Tr, this->MaxRangeTemp);
5844 :
5845 171742 : if (SolFla == -1) {
5846 0 : ShowSevereError(state, "Iteration limit exceeded in calculating tower nominal capacity at minimum air flow ratio");
5847 0 : ShowContinueError(
5848 : state,
5849 : "Design inlet air wet-bulb or approach temperature must be modified to achieve an acceptable range at the minimum air flow rate");
5850 0 : ShowContinueError(state, format("Cooling tower simulation failed to converge for tower {}", this->Name));
5851 171742 : } else if (SolFla == -2) {
5852 : // bad starting value means that solution corresponds to a range that is beyond
5853 : // the bounds of the model; The maximum range is used here
5854 403 : outletWaterTempLocal = this->WaterTemp - this->MaxRangeTemp;
5855 403 : ++this->VSErrorCountTRCalc;
5856 403 : if (this->VSErrorCountTRCalc < 2) {
5857 18 : ShowWarningError(
5858 : state,
5859 18 : format("The range for the cooling tower {} likely exceeds the bounds of the model. The maximum range of the model is used {}.",
5860 9 : this->Name,
5861 9 : this->MaxRangeTemp));
5862 18 : ShowContinueError(state,
5863 18 : format(" ... Occurrence info = {}, {} {}",
5864 9 : state.dataEnvrn->EnvironmentName,
5865 9 : state.dataEnvrn->CurMnDy,
5866 18 : General::CreateSysTimeIntervalString(state)));
5867 : } else {
5868 1182 : ShowRecurringWarningErrorAtEnd(
5869 : state,
5870 788 : format("The range for the cooling tower {} likely exceeds the bounds of the model. The maximum range of the model is used {}",
5871 394 : this->Name,
5872 394 : this->MaxRangeTemp),
5873 394 : this->ErrIndexTRCalc);
5874 : }
5875 : }
5876 171742 : return outletWaterTempLocal;
5877 : }
5878 :
5879 1844334 : Real64 CoolingTower::calculateVariableSpeedApproach(EnergyPlusData &state,
5880 : Real64 const PctWaterFlow, // Water flow ratio of cooling tower
5881 : Real64 const airFlowRatioLocal, // Air flow ratio of cooling tower
5882 : Real64 const Twb, // Inlet air wet-bulb temperature [C]
5883 : Real64 const Tr // Cooling tower range (outlet water temp minus inlet air wet-bulb temp) [C]
5884 : )
5885 : {
5886 : // FUNCTION INFORMATION:
5887 : // AUTHOR Richard Raustad, FSEC
5888 : // DATE WRITTEN Feb. 2005
5889 :
5890 : // PURPOSE OF THIS FUNCTION:
5891 : // Calculate tower approach temperature (e.g. outlet water temp minus inlet air wet-bulb temp)
5892 : // given air flow ratio, water flow ratio, inlet air wet-bulb temp, and tower range.
5893 :
5894 : // METHODOLOGY EMPLOYED:
5895 : // Calculation method used empirical models from CoolTools or York to determine performance
5896 : // of variable speed (variable air flow rate) cooling towers.
5897 :
5898 : // REFERENCES:
5899 : // Benton, D.J., Bowmand, C.F., Hydeman, M., Miller, P.,
5900 : // "An Improved Cooling Tower Algorithm for the CoolToolsTM Simulation Model".
5901 : // ASHRAE Transactions 2002, V. 108, Pt. 1.
5902 : // York International Corporation, "YORKcalcTM Software, Chiller-Plant Energy-Estimating Program",
5903 : // Form 160.00-SG2 (0502). 2002.
5904 :
5905 1844334 : auto &tower = state.dataCondenserLoopTowers->towers(this->VSTower);
5906 1844334 : if (this->TowerModelType == ModelType::YorkCalcModel || this->TowerModelType == ModelType::YorkCalcUserDefined) {
5907 958365 : Real64 PctAirFlow = airFlowRatioLocal;
5908 958365 : Real64 FlowFactor = PctWaterFlow / PctAirFlow;
5909 958365 : return tower.Coeff[0] + tower.Coeff[1] * Twb + tower.Coeff[2] * Twb * Twb + tower.Coeff[3] * Tr + tower.Coeff[4] * Twb * Tr +
5910 958365 : tower.Coeff[5] * Twb * Twb * Tr + tower.Coeff[6] * Tr * Tr + tower.Coeff[7] * Twb * Tr * Tr +
5911 958365 : tower.Coeff[8] * Twb * Twb * Tr * Tr + tower.Coeff[9] * FlowFactor + tower.Coeff[10] * Twb * FlowFactor +
5912 958365 : tower.Coeff[11] * Twb * Twb * FlowFactor + tower.Coeff[12] * Tr * FlowFactor + tower.Coeff[13] * Twb * Tr * FlowFactor +
5913 958365 : tower.Coeff[14] * Twb * Twb * Tr * FlowFactor + tower.Coeff[15] * Tr * Tr * FlowFactor +
5914 958365 : tower.Coeff[16] * Twb * Tr * Tr * FlowFactor + tower.Coeff[17] * Twb * Twb * Tr * Tr * FlowFactor +
5915 958365 : tower.Coeff[18] * FlowFactor * FlowFactor + tower.Coeff[19] * Twb * FlowFactor * FlowFactor +
5916 958365 : tower.Coeff[20] * Twb * Twb * FlowFactor * FlowFactor + tower.Coeff[21] * Tr * FlowFactor * FlowFactor +
5917 958365 : tower.Coeff[22] * Twb * Tr * FlowFactor * FlowFactor + tower.Coeff[23] * Twb * Twb * Tr * FlowFactor * FlowFactor +
5918 958365 : tower.Coeff[24] * Tr * Tr * FlowFactor * FlowFactor + tower.Coeff[25] * Twb * Tr * Tr * FlowFactor * FlowFactor +
5919 958365 : tower.Coeff[26] * Twb * Twb * Tr * Tr * FlowFactor * FlowFactor;
5920 :
5921 : } else { // empirical model is CoolTools format
5922 : // the CoolTools model actually uses PctFanPower = AirFlowRatio^3 as an input to the model
5923 885969 : Real64 PctAirFlow = pow_3(airFlowRatioLocal);
5924 885969 : return tower.Coeff[0] + tower.Coeff[1] * PctAirFlow + tower.Coeff[2] * PctAirFlow * PctAirFlow +
5925 885969 : tower.Coeff[3] * PctAirFlow * PctAirFlow * PctAirFlow + tower.Coeff[4] * PctWaterFlow +
5926 885969 : tower.Coeff[5] * PctAirFlow * PctWaterFlow + tower.Coeff[6] * PctAirFlow * PctAirFlow * PctWaterFlow +
5927 885969 : tower.Coeff[7] * PctWaterFlow * PctWaterFlow + tower.Coeff[8] * PctAirFlow * PctWaterFlow * PctWaterFlow +
5928 885969 : tower.Coeff[9] * PctWaterFlow * PctWaterFlow * PctWaterFlow + tower.Coeff[10] * Twb + tower.Coeff[11] * PctAirFlow * Twb +
5929 885969 : tower.Coeff[12] * PctAirFlow * PctAirFlow * Twb + tower.Coeff[13] * PctWaterFlow * Twb +
5930 885969 : tower.Coeff[14] * PctAirFlow * PctWaterFlow * Twb + tower.Coeff[15] * PctWaterFlow * PctWaterFlow * Twb +
5931 885969 : tower.Coeff[16] * Twb * Twb + tower.Coeff[17] * PctAirFlow * Twb * Twb + tower.Coeff[18] * PctWaterFlow * Twb * Twb +
5932 885969 : tower.Coeff[19] * Twb * Twb * Twb + tower.Coeff[20] * Tr + tower.Coeff[21] * PctAirFlow * Tr +
5933 885969 : tower.Coeff[22] * PctAirFlow * PctAirFlow * Tr + tower.Coeff[23] * PctWaterFlow * Tr +
5934 885969 : tower.Coeff[24] * PctAirFlow * PctWaterFlow * Tr + tower.Coeff[25] * PctWaterFlow * PctWaterFlow * Tr +
5935 885969 : tower.Coeff[26] * Twb * Tr + tower.Coeff[27] * PctAirFlow * Twb * Tr + tower.Coeff[28] * PctWaterFlow * Twb * Tr +
5936 885969 : tower.Coeff[29] * Twb * Twb * Tr + tower.Coeff[30] * Tr * Tr + tower.Coeff[31] * PctAirFlow * Tr * Tr +
5937 885969 : tower.Coeff[32] * PctWaterFlow * Tr * Tr + tower.Coeff[33] * Twb * Tr * Tr + tower.Coeff[34] * Tr * Tr * Tr;
5938 : }
5939 : }
5940 :
5941 96574 : void CoolingTower::checkModelBounds(EnergyPlusData &state,
5942 : Real64 Twb, // current inlet air wet-bulb temperature (C)
5943 : Real64 Tr, // requested range temperature for current time step (C)
5944 : Real64 Ta, // requested approach temperature for current time step (C)
5945 : Real64 WaterFlowRateRatio, // current water flow rate ratio at water inlet node
5946 : Real64 &TwbCapped, // bounded value of inlet air wet-bulb temperature (C)
5947 : Real64 &TrCapped, // bounded value of range temperature (C)
5948 : Real64 &TaCapped, // bounded value of approach temperature (C)
5949 : Real64 &WaterFlowRateRatioCapped // bounded value of water flow rate ratio
5950 : )
5951 : {
5952 :
5953 : // SUBROUTINE INFORMATION:
5954 : // AUTHOR Richard Raustad
5955 : // DATE WRITTEN Feb 2005
5956 :
5957 : // PURPOSE OF THIS SUBROUTINE:
5958 : // To verify that the empirical model's independent variables are within the limits used during the
5959 : // development of the empirical model.
5960 :
5961 : // METHODOLOGY EMPLOYED:
5962 : // The empirical models used for simulating a variable speed cooling tower are based on a limited data set.
5963 : // Extrapolation of empirical models can cause instability and the independent variables may need to be limited.
5964 : // The range of each independent variable is provided either by the CoolTools or York model limits, or
5965 : // specified by the user if the model is User Defined (in either the CoolTools or York model format).
5966 : // These limits are tested in this subroutine each time step and returned for use by the calling routine.
5967 : // The independent variables capped here may or may not be passed to the empirical model in the calling
5968 : // routine depending on their use.
5969 :
5970 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5971 96574 : std::string OutputChar; // character string for warning messages
5972 96574 : std::string OutputCharLo; // character string for warning messages
5973 96574 : std::string OutputCharHi; // character string for warning messages
5974 96574 : std::string TrimValue; // character string for warning messages
5975 : // current end time is compared with last to see if time step changed
5976 :
5977 : // initialize capped variables in case independent variables are in bounds
5978 96574 : TwbCapped = Twb;
5979 96574 : TrCapped = Tr;
5980 96574 : TaCapped = Ta;
5981 96574 : WaterFlowRateRatioCapped = WaterFlowRateRatio;
5982 :
5983 : // calculate end time of current time step
5984 96574 : Real64 CurrentEndTime = state.dataGlobal->CurrentTime + state.dataHVACGlobal->SysTimeElapsed;
5985 :
5986 : // Print warning messages only when valid and only for the first ocurrance. Let summary provide statistics.
5987 : // Wait for next time step to print warnings. If simulation iterates, print out
5988 : // the warning for the last iteration only. Must wait for next time step to accomplish this.
5989 : // If a warning occurs and the simulation down shifts, the warning is not valid.
5990 96574 : if (CurrentEndTime > this->CurrentEndTimeLast && state.dataHVACGlobal->TimeStepSys >= this->TimeStepSysLast) {
5991 12555 : if (state.dataCondenserLoopTowers->towers(this->VSTower).PrintTrMessage) {
5992 334 : ++state.dataCondenserLoopTowers->towers(this->VSTower).VSErrorCountTR;
5993 334 : if (state.dataCondenserLoopTowers->towers(this->VSTower).VSErrorCountTR < 2) {
5994 15 : ShowWarningError(state, state.dataCondenserLoopTowers->towers(this->VSTower).TrBuffer1);
5995 15 : ShowContinueError(state, state.dataCondenserLoopTowers->towers(this->VSTower).TrBuffer2);
5996 15 : ShowContinueError(state, state.dataCondenserLoopTowers->towers(this->VSTower).TrBuffer3);
5997 15 : ShowContinueError(state, " ...Range temperatures outside model boundaries may not adversely affect tower performance.");
5998 15 : ShowContinueError(state, " ...This is not an unexpected occurrence when simulating actual conditions.");
5999 : } else {
6000 957 : ShowRecurringWarningErrorAtEnd(state,
6001 638 : format("{} \"{}\" - Tower range temperature is out of range error continues...",
6002 319 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
6003 319 : this->Name),
6004 319 : state.dataCondenserLoopTowers->towers(this->VSTower).ErrIndexTR,
6005 319 : state.dataCondenserLoopTowers->towers(this->VSTower).TrLast,
6006 319 : state.dataCondenserLoopTowers->towers(this->VSTower).TrLast);
6007 : }
6008 : }
6009 12555 : if (state.dataCondenserLoopTowers->towers(this->VSTower).PrintTwbMessage) {
6010 4 : ++state.dataCondenserLoopTowers->towers(this->VSTower).VSErrorCountIAWB;
6011 4 : if (state.dataCondenserLoopTowers->towers(this->VSTower).VSErrorCountIAWB < 6) {
6012 4 : ShowWarningError(state, state.dataCondenserLoopTowers->towers(this->VSTower).TwbBuffer1);
6013 4 : ShowContinueError(state, state.dataCondenserLoopTowers->towers(this->VSTower).TwbBuffer2);
6014 4 : ShowContinueError(state, state.dataCondenserLoopTowers->towers(this->VSTower).TwbBuffer3);
6015 4 : ShowContinueError(state, " ...Wet-bulb temperatures outside model boundaries may not adversely affect tower performance.");
6016 : } else {
6017 0 : ShowRecurringWarningErrorAtEnd(state,
6018 0 : format("{} \"{}\" - Inlet air wet-bulb temperature is out of range error continues...",
6019 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
6020 0 : this->Name),
6021 0 : state.dataCondenserLoopTowers->towers(this->VSTower).ErrIndexIAWB,
6022 0 : state.dataCondenserLoopTowers->towers(this->VSTower).TwbLast,
6023 0 : state.dataCondenserLoopTowers->towers(this->VSTower).TwbLast);
6024 : }
6025 : }
6026 12555 : if (state.dataCondenserLoopTowers->towers(this->VSTower).PrintTaMessage) {
6027 382 : ++state.dataCondenserLoopTowers->towers(this->VSTower).VSErrorCountTA;
6028 382 : if (state.dataCondenserLoopTowers->towers(this->VSTower).VSErrorCountTA < 2) {
6029 11 : ShowWarningError(state, state.dataCondenserLoopTowers->towers(this->VSTower).TaBuffer1);
6030 11 : ShowContinueError(state, state.dataCondenserLoopTowers->towers(this->VSTower).TaBuffer2);
6031 11 : ShowContinueError(state, state.dataCondenserLoopTowers->towers(this->VSTower).TaBuffer3);
6032 11 : ShowContinueError(state, " ...Approach temperatures outside model boundaries may not adversely affect tower performance.");
6033 11 : ShowContinueError(state, " ...This is not an unexpected occurrence when simulating actual conditions.");
6034 : } else {
6035 1113 : ShowRecurringWarningErrorAtEnd(state,
6036 742 : format("{} \"{}\" - Tower approach temperature is out of range error continues...",
6037 371 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
6038 371 : this->Name),
6039 371 : state.dataCondenserLoopTowers->towers(this->VSTower).ErrIndexTA,
6040 371 : state.dataCondenserLoopTowers->towers(this->VSTower).TaLast,
6041 371 : state.dataCondenserLoopTowers->towers(this->VSTower).TaLast);
6042 : }
6043 : }
6044 12555 : if (state.dataCondenserLoopTowers->towers(this->VSTower).PrintWFRRMessage) {
6045 18 : ++state.dataCondenserLoopTowers->towers(this->VSTower).VSErrorCountWFRR;
6046 18 : if (state.dataCondenserLoopTowers->towers(this->VSTower).VSErrorCountWFRR < 6) {
6047 18 : ShowWarningError(state, state.dataCondenserLoopTowers->towers(this->VSTower).WFRRBuffer1);
6048 18 : ShowContinueError(state, state.dataCondenserLoopTowers->towers(this->VSTower).WFRRBuffer2);
6049 18 : ShowContinueError(state, state.dataCondenserLoopTowers->towers(this->VSTower).WFRRBuffer3);
6050 18 : ShowContinueError(state, " ...Water flow rate ratios outside model boundaries may not adversely affect tower performance.");
6051 : } else {
6052 0 : ShowRecurringWarningErrorAtEnd(state,
6053 0 : format("{} \"{}\" - Water flow rate ratio is out of range error continues...",
6054 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
6055 0 : this->Name),
6056 0 : state.dataCondenserLoopTowers->towers(this->VSTower).ErrIndexWFRR,
6057 0 : state.dataCondenserLoopTowers->towers(this->VSTower).WaterFlowRateRatioLast,
6058 0 : state.dataCondenserLoopTowers->towers(this->VSTower).WaterFlowRateRatioLast);
6059 : }
6060 : }
6061 : }
6062 :
6063 : // save last system time step and last end time of current time step (used to determine if warning is valid)
6064 96574 : this->TimeStepSysLast = state.dataHVACGlobal->TimeStepSys;
6065 96574 : this->CurrentEndTimeLast = CurrentEndTime;
6066 :
6067 : // check boundaries of independent variables and post warnings to individual buffers to print at end of time step
6068 192891 : if (Twb < state.dataCondenserLoopTowers->towers(this->VSTower).MinInletAirWBTemp ||
6069 96317 : Twb > state.dataCondenserLoopTowers->towers(this->VSTower).MaxInletAirWBTemp) {
6070 257 : OutputChar = format("{:.2R}", Twb);
6071 257 : OutputCharLo = format("{:.2R}", state.dataCondenserLoopTowers->towers(this->VSTower).MinInletAirWBTemp);
6072 257 : OutputCharHi = format("{:.2R}", state.dataCondenserLoopTowers->towers(this->VSTower).MaxInletAirWBTemp);
6073 257 : if (Twb < state.dataCondenserLoopTowers->towers(this->VSTower).MinInletAirWBTemp) {
6074 257 : TwbCapped = state.dataCondenserLoopTowers->towers(this->VSTower).MinInletAirWBTemp;
6075 : }
6076 257 : if (Twb > state.dataCondenserLoopTowers->towers(this->VSTower).MaxInletAirWBTemp) {
6077 0 : TwbCapped = state.dataCondenserLoopTowers->towers(this->VSTower).MaxInletAirWBTemp;
6078 : }
6079 257 : if (!state.dataGlobal->WarmupFlag) {
6080 10 : state.dataCondenserLoopTowers->towers(this->VSTower).PrintTwbMessage = true;
6081 10 : state.dataCondenserLoopTowers->towers(this->VSTower).TwbBuffer1 =
6082 20 : format("{} \"{}\" - Inlet air wet-bulb temperature is outside model boundaries at {}.",
6083 10 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
6084 10 : this->Name,
6085 10 : OutputChar);
6086 10 : state.dataCondenserLoopTowers->towers(this->VSTower).TwbBuffer2 =
6087 20 : " ...Valid range = " + OutputCharLo + " to " + OutputCharHi + ". Occurrence info = " + state.dataEnvrn->EnvironmentName + ", " +
6088 40 : state.dataEnvrn->CurMnDy + ' ' + General::CreateSysTimeIntervalString(state);
6089 10 : TrimValue = format("{:.6R}", TwbCapped);
6090 10 : state.dataCondenserLoopTowers->towers(this->VSTower).TwbBuffer3 =
6091 20 : " ...Inlet air wet-bulb temperature passed to the model = " + TrimValue;
6092 10 : state.dataCondenserLoopTowers->towers(this->VSTower).TwbLast = Twb;
6093 : } else {
6094 247 : state.dataCondenserLoopTowers->towers(this->VSTower).PrintTwbMessage = false;
6095 : }
6096 : } else {
6097 96317 : state.dataCondenserLoopTowers->towers(this->VSTower).PrintTwbMessage = false;
6098 : }
6099 :
6100 182168 : if (Tr < state.dataCondenserLoopTowers->towers(this->VSTower).MinRangeTemp ||
6101 85594 : Tr > state.dataCondenserLoopTowers->towers(this->VSTower).MaxRangeTemp) {
6102 10980 : OutputChar = format("{:.2R}", Tr);
6103 10980 : OutputCharLo = format("{:.2R}", state.dataCondenserLoopTowers->towers(this->VSTower).MinRangeTemp);
6104 10980 : OutputCharHi = format("{:.2R}", state.dataCondenserLoopTowers->towers(this->VSTower).MaxRangeTemp);
6105 10980 : if (Tr < state.dataCondenserLoopTowers->towers(this->VSTower).MinRangeTemp) {
6106 10980 : TrCapped = state.dataCondenserLoopTowers->towers(this->VSTower).MinRangeTemp;
6107 : }
6108 10980 : if (Tr > state.dataCondenserLoopTowers->towers(this->VSTower).MaxRangeTemp) {
6109 0 : TrCapped = state.dataCondenserLoopTowers->towers(this->VSTower).MaxRangeTemp;
6110 : }
6111 10980 : if (!state.dataGlobal->WarmupFlag) {
6112 2586 : state.dataCondenserLoopTowers->towers(this->VSTower).PrintTrMessage = true;
6113 2586 : state.dataCondenserLoopTowers->towers(this->VSTower).TrBuffer1 =
6114 5172 : format("{} \"{}\" - Tower range temperature is outside model boundaries at {}.",
6115 2586 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
6116 2586 : this->Name,
6117 2586 : OutputChar);
6118 2586 : state.dataCondenserLoopTowers->towers(this->VSTower).TrBuffer2 =
6119 5172 : " ...Valid range = " + OutputCharLo + " to " + OutputCharHi + ". Occurrence info = " + state.dataEnvrn->EnvironmentName + ", " +
6120 10344 : state.dataEnvrn->CurMnDy + ' ' + General::CreateSysTimeIntervalString(state);
6121 2586 : TrimValue = format("{:.5R}", Tr);
6122 2586 : state.dataCondenserLoopTowers->towers(this->VSTower).TrBuffer3 = " ...Tower range temperature passed to the model = " + TrimValue;
6123 2586 : state.dataCondenserLoopTowers->towers(this->VSTower).TrLast = Tr;
6124 : } else {
6125 8394 : state.dataCondenserLoopTowers->towers(this->VSTower).PrintTrMessage = false;
6126 : }
6127 : } else {
6128 85594 : state.dataCondenserLoopTowers->towers(this->VSTower).PrintTrMessage = false;
6129 : }
6130 :
6131 170658 : if (Ta < state.dataCondenserLoopTowers->towers(this->VSTower).MinApproachTemp ||
6132 74084 : Ta > state.dataCondenserLoopTowers->towers(this->VSTower).MaxApproachTemp) {
6133 26326 : OutputChar = format("{:.2R}", Ta);
6134 26326 : OutputCharLo = format("{:.2R}", state.dataCondenserLoopTowers->towers(this->VSTower).MinApproachTemp);
6135 26326 : OutputCharHi = format("{:.2R}", state.dataCondenserLoopTowers->towers(this->VSTower).MaxApproachTemp);
6136 26326 : if (Ta < state.dataCondenserLoopTowers->towers(this->VSTower).MinApproachTemp) {
6137 22490 : TaCapped = state.dataCondenserLoopTowers->towers(this->VSTower).MinApproachTemp;
6138 : }
6139 26326 : if (Ta > state.dataCondenserLoopTowers->towers(this->VSTower).MaxApproachTemp) {
6140 3836 : TaCapped = state.dataCondenserLoopTowers->towers(this->VSTower).MaxApproachTemp;
6141 : }
6142 26326 : if (!state.dataGlobal->WarmupFlag) {
6143 4183 : state.dataCondenserLoopTowers->towers(this->VSTower).PrintTaMessage = true;
6144 4183 : state.dataCondenserLoopTowers->towers(this->VSTower).TaBuffer1 =
6145 8366 : format("{} \"{}\" - Tower approach temperature is outside model boundaries at {}.",
6146 4183 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
6147 4183 : this->Name,
6148 4183 : OutputChar);
6149 4183 : state.dataCondenserLoopTowers->towers(this->VSTower).TaBuffer2 =
6150 8366 : " ...Valid range = " + OutputCharLo + " to " + OutputCharHi + ". Occurrence info = " + state.dataEnvrn->EnvironmentName + ", " +
6151 16732 : state.dataEnvrn->CurMnDy + ' ' + General::CreateSysTimeIntervalString(state);
6152 4183 : TrimValue = format("{:.5R}", Ta);
6153 4183 : state.dataCondenserLoopTowers->towers(this->VSTower).TaBuffer3 = " ...Tower approach temperature passed to the model = " + TrimValue;
6154 4183 : state.dataCondenserLoopTowers->towers(this->VSTower).TaLast = Ta;
6155 : } else {
6156 22143 : state.dataCondenserLoopTowers->towers(this->VSTower).PrintTaMessage = false;
6157 : }
6158 : } else {
6159 70248 : state.dataCondenserLoopTowers->towers(this->VSTower).PrintTaMessage = false;
6160 : }
6161 :
6162 96574 : if (this->TowerModelType == ModelType::YorkCalcModel || this->TowerModelType == ModelType::YorkCalcUserDefined) {
6163 : // Water flow rate ratio warning not valid for YorkCalc model, print liquid to gas ratio
6164 : // warning instead (bottom of Subroutine VariableSpeedTower)
6165 51694 : state.dataCondenserLoopTowers->towers(this->VSTower).PrintWFRRMessage = false;
6166 : } else {
6167 88907 : if (WaterFlowRateRatio < state.dataCondenserLoopTowers->towers(this->VSTower).MinWaterFlowRatio ||
6168 44027 : WaterFlowRateRatio > state.dataCondenserLoopTowers->towers(this->VSTower).MaxWaterFlowRatio) {
6169 853 : OutputChar = format("{:.2R}", WaterFlowRateRatio);
6170 853 : OutputCharLo = format("{:.2R}", state.dataCondenserLoopTowers->towers(this->VSTower).MinWaterFlowRatio);
6171 853 : OutputCharHi = format("{:.2R}", state.dataCondenserLoopTowers->towers(this->VSTower).MaxWaterFlowRatio);
6172 853 : if (WaterFlowRateRatio < state.dataCondenserLoopTowers->towers(this->VSTower).MinWaterFlowRatio) {
6173 853 : WaterFlowRateRatioCapped = state.dataCondenserLoopTowers->towers(this->VSTower).MinWaterFlowRatio;
6174 : }
6175 853 : if (WaterFlowRateRatio > state.dataCondenserLoopTowers->towers(this->VSTower).MaxWaterFlowRatio) {
6176 0 : WaterFlowRateRatioCapped = state.dataCondenserLoopTowers->towers(this->VSTower).MaxWaterFlowRatio;
6177 : }
6178 853 : if (!state.dataGlobal->WarmupFlag) {
6179 66 : state.dataCondenserLoopTowers->towers(this->VSTower).PrintWFRRMessage = true;
6180 66 : state.dataCondenserLoopTowers->towers(this->VSTower).WFRRBuffer1 =
6181 132 : format("{} \"{}\" - Water flow rate ratio is outside model boundaries at {}.",
6182 66 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
6183 66 : this->Name,
6184 66 : OutputChar);
6185 66 : state.dataCondenserLoopTowers->towers(this->VSTower).WFRRBuffer2 =
6186 132 : " ...Valid range = " + OutputCharLo + " to " + OutputCharHi + ". Occurrence info = " + state.dataEnvrn->EnvironmentName +
6187 264 : ", " + state.dataEnvrn->CurMnDy + ' ' + General::CreateSysTimeIntervalString(state);
6188 66 : TrimValue = format("{:.5R}", WaterFlowRateRatioCapped);
6189 66 : state.dataCondenserLoopTowers->towers(this->VSTower).WFRRBuffer3 = " ...Water flow rate ratio passed to the model = " + TrimValue;
6190 66 : state.dataCondenserLoopTowers->towers(this->VSTower).WaterFlowRateRatioLast = WaterFlowRateRatio;
6191 : } else {
6192 787 : state.dataCondenserLoopTowers->towers(this->VSTower).PrintWFRRMessage = false;
6193 : }
6194 : } else {
6195 44027 : state.dataCondenserLoopTowers->towers(this->VSTower).PrintWFRRMessage = false;
6196 : }
6197 : }
6198 96574 : }
6199 :
6200 8767027 : void CoolingTower::calculateWaterUsage(EnergyPlusData &state)
6201 : {
6202 :
6203 : // SUBROUTINE INFORMATION:
6204 : // AUTHOR B. Griffith
6205 : // DATE WRITTEN August 2006
6206 : // MODIFIED T Hong, Aug. 2008. Added fluid bypass for single speed cooling tower
6207 : // A Flament, July 2010. Added multi-cell capability
6208 :
6209 : // PURPOSE OF THIS SUBROUTINE:
6210 : // Collect tower water useage calculations for reuse by all the tower models.
6211 :
6212 : // REFERENCES:
6213 : // Code for this routine started from VariableSpeedTower
6214 :
6215 : // SUBROUTINE PARAMETER DEFINITIONS:
6216 : static constexpr std::string_view RoutineName("calculateWaterUsage");
6217 :
6218 8767027 : Real64 EvapVdot = 0.0;
6219 8767027 : Real64 AverageWaterTemp = (this->InletWaterTemp + this->OutletWaterTemp) / 2.0;
6220 :
6221 : // Set water and air properties
6222 8767027 : if (this->EvapLossMode == EvapLoss::MoistTheory) {
6223 :
6224 8750133 : Real64 const AirDensity = Psychrometrics::PsyRhoAirFnPbTdbW(state, this->AirPress, this->AirTemp, this->AirHumRat);
6225 8750133 : Real64 const AirMassFlowRate = this->airFlowRateRatio * this->HighSpeedAirFlowRate * AirDensity * this->NumCellOn / this->NumCell;
6226 8750133 : Real64 const InletAirEnthalpy = Psychrometrics::PsyHFnTdbRhPb(state, this->AirWetBulb, 1.0, this->AirPress);
6227 :
6228 8750133 : if (AirMassFlowRate > 0.0) {
6229 : // Calculate outlet air conditions for determining water usage
6230 :
6231 3641120 : Real64 const OutletAirEnthalpy = InletAirEnthalpy + this->Qactual / AirMassFlowRate;
6232 3641120 : Real64 const OutletAirTSat = Psychrometrics::PsyTsatFnHPb(state, OutletAirEnthalpy, this->AirPress);
6233 3641120 : Real64 const OutletAirHumRatSat = Psychrometrics::PsyWFnTdbH(state, OutletAirTSat, OutletAirEnthalpy);
6234 :
6235 : // calculate specific humidity ratios (HUMRAT to mass of moist air not dry air)
6236 3641120 : Real64 const InSpecificHumRat = this->AirHumRat / (1 + this->AirHumRat);
6237 3641120 : Real64 const OutSpecificHumRat = OutletAirHumRatSat / (1 + OutletAirHumRatSat);
6238 :
6239 : // calculate average air temp for density call
6240 3641120 : Real64 const TairAvg = (this->AirTemp + OutletAirTSat) / 2.0;
6241 :
6242 : // Amount of water evaporated, get density water at air temp or 4 C if too cold
6243 3641120 : Real64 const rho = FluidProperties::GetDensityGlycol(state,
6244 3641120 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
6245 : max(TairAvg, 4.0),
6246 3641120 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
6247 : RoutineName);
6248 :
6249 3641120 : EvapVdot = (AirMassFlowRate * (OutSpecificHumRat - InSpecificHumRat)) / rho; // [m3/s]
6250 3641120 : if (EvapVdot < 0.0) EvapVdot = 0.0;
6251 : } else {
6252 5109013 : EvapVdot = 0.0;
6253 : }
6254 :
6255 16894 : } else if (this->EvapLossMode == EvapLoss::UserFactor) {
6256 16894 : Real64 const rho = FluidProperties::GetDensityGlycol(state,
6257 16894 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
6258 : AverageWaterTemp,
6259 16894 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
6260 : RoutineName);
6261 :
6262 16894 : EvapVdot = this->UserEvapLossFactor * (this->InletWaterTemp - this->OutletWaterTemp) * (this->WaterMassFlowRate / rho);
6263 16894 : if (EvapVdot < 0.0) EvapVdot = 0.0;
6264 : } else {
6265 : // should never come here
6266 : }
6267 :
6268 : // amount of water lost due to drift
6269 8767027 : Real64 driftVdot = this->DesignWaterFlowRate * this->NumCellOn / this->NumCell * this->DriftLossFraction * this->airFlowRateRatio;
6270 :
6271 8767027 : Real64 BlowDownVdot(0.0);
6272 8767027 : if (this->BlowdownMode == Blowdown::Schedule) {
6273 : // Amount of water lost due to blow down (purging contaminants from tower basin)
6274 0 : if (this->SchedIDBlowdown > 0) {
6275 0 : BlowDownVdot = ScheduleManager::GetCurrentScheduleValue(state, this->SchedIDBlowdown);
6276 : } else {
6277 0 : BlowDownVdot = 0.0;
6278 : }
6279 8767027 : } else if (this->BlowdownMode == Blowdown::Concentration) {
6280 8767027 : if (this->ConcentrationRatio > 2.0) { // protect divide by zero
6281 8767027 : BlowDownVdot = EvapVdot / (this->ConcentrationRatio - 1) - driftVdot;
6282 : } else {
6283 0 : BlowDownVdot = EvapVdot - driftVdot;
6284 : }
6285 8767027 : if (BlowDownVdot < 0.0) BlowDownVdot = 0.0;
6286 : } else {
6287 : // should never come here
6288 : }
6289 :
6290 : // Added for fluid bypass
6291 8767027 : if (this->CapacityControl == CapacityCtrl::FluidBypass) {
6292 359740 : if (this->EvapLossMode == EvapLoss::UserFactor) EvapVdot *= (1 - this->BypassFraction);
6293 359740 : driftVdot *= (1 - this->BypassFraction);
6294 359740 : BlowDownVdot *= (1 - this->BypassFraction);
6295 : }
6296 :
6297 8767027 : Real64 const makeUpVdot = EvapVdot + driftVdot + BlowDownVdot;
6298 :
6299 : // set demand request in Water Storage if needed
6300 8767027 : Real64 StarvedVdot = 0.0;
6301 8767027 : Real64 tankSupplyVdot = 0.0;
6302 8767027 : if (this->SuppliedByWaterSystem) {
6303 :
6304 : // set demand request
6305 35076 : state.dataWaterData->WaterStorage(this->WaterTankID).VdotRequestDemand(this->WaterTankDemandARRID) = makeUpVdot;
6306 :
6307 35076 : Real64 const AvailTankVdot = state.dataWaterData->WaterStorage(this->WaterTankID)
6308 35076 : .VdotAvailDemand(this->WaterTankDemandARRID); // check what tank can currently provide
6309 :
6310 35076 : tankSupplyVdot = makeUpVdot; // init
6311 35076 : if (AvailTankVdot < makeUpVdot) { // calculate starved flow
6312 20214 : StarvedVdot = makeUpVdot - AvailTankVdot;
6313 20214 : tankSupplyVdot = AvailTankVdot;
6314 : }
6315 : } else { // supplied by mains
6316 : }
6317 :
6318 : // total water usage
6319 : // update report variables
6320 8767027 : this->EvaporationVdot = EvapVdot;
6321 8767027 : this->EvaporationVol = EvapVdot * (state.dataHVACGlobal->TimeStepSysSec);
6322 8767027 : this->DriftVdot = driftVdot;
6323 8767027 : this->DriftVol = driftVdot * (state.dataHVACGlobal->TimeStepSysSec);
6324 8767027 : this->BlowdownVdot = BlowDownVdot;
6325 8767027 : this->BlowdownVol = BlowDownVdot * (state.dataHVACGlobal->TimeStepSysSec);
6326 8767027 : this->MakeUpVdot = makeUpVdot;
6327 8767027 : this->MakeUpVol = makeUpVdot * (state.dataHVACGlobal->TimeStepSysSec);
6328 8767027 : this->TankSupplyVdot = tankSupplyVdot;
6329 8767027 : this->TankSupplyVol = tankSupplyVdot * (state.dataHVACGlobal->TimeStepSysSec);
6330 8767027 : this->StarvedMakeUpVdot = StarvedVdot;
6331 8767027 : this->StarvedMakeUpVol = StarvedVdot * (state.dataHVACGlobal->TimeStepSysSec);
6332 8767027 : this->coolingTowerApproach = this->OutletWaterTemp - this->AirWetBulb;
6333 8767027 : this->coolingTowerRange = this->InletWaterTemp - this->OutletWaterTemp;
6334 8767027 : }
6335 :
6336 8767027 : void CoolingTower::update(EnergyPlusData &state)
6337 : {
6338 :
6339 : // SUBROUTINE INFORMATION:
6340 : // AUTHOR: Dan Fisher
6341 : // DATE WRITTEN: October 1998
6342 :
6343 : // PURPOSE OF THIS SUBROUTINE:
6344 : // This subroutine is for passing results to the outlet water node.
6345 :
6346 : // set node information
6347 8767027 : PlantUtilities::SafeCopyPlantNode(state, this->WaterInletNodeNum, this->WaterOutletNodeNum);
6348 8767027 : state.dataLoopNodes->Node(this->WaterOutletNodeNum).Temp = this->OutletWaterTemp;
6349 :
6350 13149774 : if (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopSide(this->plantLoc.loopSideNum).FlowLock == DataPlant::FlowLock::Unlocked ||
6351 4382747 : state.dataGlobal->WarmupFlag)
6352 8144053 : return;
6353 :
6354 : // Check flow rate through tower and compare to design flow rate, show warning if greater than Design * Mulitplier
6355 622974 : if (state.dataLoopNodes->Node(this->WaterOutletNodeNum).MassFlowRate > this->DesWaterMassFlowRate * this->TowerMassFlowRateMultiplier) {
6356 0 : ++this->HighMassFlowErrorCount;
6357 0 : if (this->HighMassFlowErrorCount < 2) {
6358 0 : ShowWarningError(state, format("{} \"{}\"", DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)], this->Name));
6359 0 : ShowContinueError(state, " Condenser Loop Mass Flow Rate is much greater than the towers design mass flow rate.");
6360 0 : ShowContinueError(
6361 0 : state, format(" Condenser Loop Mass Flow Rate = {:.6T}", state.dataLoopNodes->Node(this->WaterOutletNodeNum).MassFlowRate));
6362 0 : ShowContinueError(state, format(" Tower Design Mass Flow Rate = {:.6T}", this->DesWaterMassFlowRate));
6363 0 : ShowContinueErrorTimeStamp(state, "");
6364 : } else {
6365 0 : ShowRecurringWarningErrorAtEnd(
6366 : state,
6367 0 : format("{} \"{}\" Condenser Loop Mass Flow Rate is much greater than the towers design mass flow rate error continues...",
6368 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
6369 0 : this->Name),
6370 0 : this->HighMassFlowErrorIndex,
6371 0 : state.dataLoopNodes->Node(this->WaterOutletNodeNum).MassFlowRate,
6372 0 : state.dataLoopNodes->Node(this->WaterOutletNodeNum).MassFlowRate);
6373 : }
6374 : }
6375 :
6376 : // Check if OutletWaterTemp is below the minimum condenser loop temp and warn user
6377 622974 : Real64 const LoopMinTemp = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).MinTemp;
6378 622974 : bool const outletWaterTempTooLow = this->OutletWaterTemp < LoopMinTemp;
6379 622974 : bool const flowIsOn = this->WaterMassFlowRate > 0.0;
6380 622974 : if (outletWaterTempTooLow && flowIsOn) {
6381 765 : ++this->OutletWaterTempErrorCount;
6382 765 : if (this->OutletWaterTempErrorCount < 2) {
6383 7 : ShowWarningError(state, format("{} \"{}\"", DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)], this->Name));
6384 14 : ShowContinueError(
6385 : state,
6386 14 : format("Cooling tower water outlet temperature ({:.2F} C) is below the specified minimum condenser loop temp of {:.2F} C",
6387 7 : this->OutletWaterTemp,
6388 : LoopMinTemp));
6389 7 : ShowContinueErrorTimeStamp(state, "");
6390 : } else {
6391 2274 : ShowRecurringWarningErrorAtEnd(
6392 : state,
6393 1516 : format("{} \"{}\" Cooling tower water outlet temperature is below the specified minimum condenser loop temp error continues...",
6394 758 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
6395 758 : this->Name),
6396 758 : this->OutletWaterTempErrorIndex,
6397 758 : this->OutletWaterTemp,
6398 758 : this->OutletWaterTemp);
6399 : }
6400 : }
6401 :
6402 : // Check if water mass flow rate is small (e.g. no flow) and warn user
6403 622974 : if (this->WaterMassFlowRate > 0.0 && this->WaterMassFlowRate <= DataBranchAirLoopPlant::MassFlowTolerance) {
6404 0 : ++this->SmallWaterMassFlowErrorCount;
6405 0 : if (this->SmallWaterMassFlowErrorCount < 2) {
6406 0 : ShowWarningError(state, format("{} \"{}\"", DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)], this->Name));
6407 0 : ShowContinueError(state, "Cooling tower water mass flow rate near zero.");
6408 0 : ShowContinueErrorTimeStamp(state, "");
6409 0 : ShowContinueError(state, format("Actual Mass flow = {:.2T}", this->WaterMassFlowRate));
6410 : } else {
6411 0 : ShowRecurringWarningErrorAtEnd(state,
6412 0 : format("{} \"{}\" Cooling tower water mass flow rate near zero error continues...",
6413 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->TowerType)],
6414 0 : this->Name),
6415 0 : this->SmallWaterMassFlowErrorIndex,
6416 0 : this->WaterMassFlowRate,
6417 0 : this->WaterMassFlowRate);
6418 : }
6419 : }
6420 : }
6421 :
6422 8767027 : void CoolingTower::report(EnergyPlusData &state, bool const RunFlag)
6423 : {
6424 :
6425 : // SUBROUTINE INFORMATION:
6426 : // AUTHOR: Dan Fisher
6427 : // DATE WRITTEN: October 1998
6428 :
6429 : // PURPOSE OF THIS SUBROUTINE:
6430 : // This subroutine updates the report variables for the tower.
6431 :
6432 8767027 : Real64 const ReportingConstant = state.dataHVACGlobal->TimeStepSysSec;
6433 :
6434 8767027 : if (!RunFlag) {
6435 4649770 : this->InletWaterTemp = state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp;
6436 4649770 : this->OutletWaterTemp = state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp;
6437 4649770 : this->Qactual = 0.0;
6438 4649770 : this->FanPower = 0.0;
6439 4649770 : this->FanEnergy = 0.0;
6440 4649770 : this->AirFlowRatio = 0.0;
6441 4649770 : this->WaterAmountUsed = 0.0;
6442 4649770 : this->BasinHeaterConsumption = this->BasinHeaterPower * ReportingConstant;
6443 4649770 : this->FanCyclingRatio = 0.0;
6444 4649770 : this->BypassFraction = 0.0; // added for fluid bypass
6445 4649770 : this->NumCellOn = 0;
6446 4649770 : this->SpeedSelected = 0;
6447 : } else {
6448 4117257 : this->InletWaterTemp = state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp;
6449 4117257 : this->FanEnergy = this->FanPower * ReportingConstant;
6450 4117257 : this->AirFlowRatio = this->airFlowRateRatio;
6451 4117257 : this->WaterAmountUsed = this->WaterUsage * ReportingConstant;
6452 4117257 : this->BasinHeaterConsumption = this->BasinHeaterPower * ReportingConstant;
6453 : }
6454 8767027 : }
6455 :
6456 8223922 : void CoolingTower::checkMassFlowAndLoad(EnergyPlusData &state, Real64 const MyLoad, bool RunFlag, bool &returnFlagSet)
6457 : {
6458 8223922 : if ((MyLoad > -HVAC::SmallLoad) || !RunFlag) {
6459 : // tower doesn't need to do anything
6460 4601746 : this->OutletWaterTemp = state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp;
6461 4601746 : this->FanPower = 0.0;
6462 4601746 : this->airFlowRateRatio = 0.0;
6463 4601746 : this->Qactual = 0.0;
6464 4601746 : this->WaterMassFlowRate = 0.0;
6465 4601746 : PlantUtilities::SetComponentFlowRate(state, this->WaterMassFlowRate, this->WaterInletNodeNum, this->WaterOutletNodeNum, this->plantLoc);
6466 4601746 : CalcBasinHeaterPower(
6467 4601746 : state, this->BasinHeaterPowerFTempDiff, this->BasinHeaterSchedulePtr, this->BasinHeaterSetPointTemp, this->BasinHeaterPower);
6468 4601746 : returnFlagSet = true;
6469 3622176 : } else if (this->WaterMassFlowRate <= DataBranchAirLoopPlant::MassFlowTolerance) {
6470 : // for multiple cells, we assume that it's a common basin
6471 0 : CalcBasinHeaterPower(
6472 0 : state, this->BasinHeaterPowerFTempDiff, this->BasinHeaterSchedulePtr, this->BasinHeaterSetPointTemp, this->BasinHeaterPower);
6473 0 : returnFlagSet = true;
6474 : }
6475 8223922 : }
6476 :
6477 : } // namespace CondenserLoopTowers
6478 :
6479 : } // namespace EnergyPlus
|