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