Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // C++ Headers
49 : #include <cmath>
50 :
51 : // ObjexxFCL Headers
52 : #include <ObjexxFCL/Array.functions.hh>
53 : #include <ObjexxFCL/Fmath.hh>
54 :
55 : // EnergyPlus Headers
56 : #include <EnergyPlus/Autosizing/Base.hh>
57 : #include <EnergyPlus/BranchNodeConnections.hh>
58 : #include <EnergyPlus/Data/EnergyPlusData.hh>
59 : #include <EnergyPlus/DataBranchAirLoopPlant.hh>
60 : #include <EnergyPlus/DataEnvironment.hh>
61 : #include <EnergyPlus/DataHVACGlobals.hh>
62 : #include <EnergyPlus/DataIPShortCuts.hh>
63 : #include <EnergyPlus/DataLoopNode.hh>
64 : #include <EnergyPlus/DataSizing.hh>
65 : #include <EnergyPlus/FluidCoolers.hh>
66 : #include <EnergyPlus/FluidProperties.hh>
67 : #include <EnergyPlus/General.hh>
68 : #include <EnergyPlus/GlobalNames.hh>
69 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
70 : #include <EnergyPlus/NodeInputManager.hh>
71 : #include <EnergyPlus/OutAirNodeManager.hh>
72 : #include <EnergyPlus/OutputProcessor.hh>
73 : #include <EnergyPlus/OutputReportPredefined.hh>
74 : #include <EnergyPlus/Plant/DataPlant.hh>
75 : #include <EnergyPlus/PlantUtilities.hh>
76 : #include <EnergyPlus/Psychrometrics.hh>
77 : #include <EnergyPlus/UtilityRoutines.hh>
78 :
79 : namespace EnergyPlus::FluidCoolers {
80 :
81 : // Module containing the routines dealing with the objects FluidCooler:SingleSpeed and
82 : // FluidCooler:TwoSpeed
83 :
84 : // MODULE INFORMATION:
85 : // AUTHOR Chandan Sharma
86 : // DATE WRITTEN August 2008
87 : // MODIFIED April 2010, Chandan Sharma, FSEC
88 :
89 : // PURPOSE OF THIS MODULE:
90 : // Model the performance of fluid coolers
91 :
92 : // REFERENCES:
93 : // Based on cooling tower by Shirey, Raustad: Dec 2000; Shirey, Sept 2002
94 :
95 : // MODULE PARAMETER DEFINITIONS:
96 : std::string const cFluidCooler_SingleSpeed("FluidCooler:SingleSpeed");
97 : std::string const cFluidCooler_TwoSpeed("FluidCooler:TwoSpeed");
98 :
99 6 : FluidCoolerspecs *FluidCoolerspecs::factory(EnergyPlusData &state, DataPlant::PlantEquipmentType objectType, std::string const &objectName)
100 : {
101 6 : if (state.dataFluidCoolers->GetFluidCoolerInputFlag) {
102 6 : GetFluidCoolerInput(state);
103 6 : state.dataFluidCoolers->GetFluidCoolerInputFlag = false;
104 : }
105 : // Now look for this particular fluid cooler in the list
106 12 : auto thisObj = std::find_if(
107 6 : state.dataFluidCoolers->SimpleFluidCooler.begin(),
108 6 : state.dataFluidCoolers->SimpleFluidCooler.end(),
109 6 : [objectType, &objectName](const FluidCoolerspecs &myObj) { return myObj.FluidCoolerType == objectType && myObj.Name == objectName; });
110 6 : if (thisObj != state.dataFluidCoolers->SimpleFluidCooler.end()) {
111 6 : return thisObj;
112 : }
113 :
114 : // If we didn't find it, fatal
115 0 : ShowFatalError(state, format("FluidCooler::factory: Error getting inputs for cooler named: {}", objectName));
116 : // Shut up the compiler
117 0 : return nullptr;
118 : }
119 :
120 148307 : void FluidCoolerspecs::simulate(EnergyPlusData &state,
121 : [[maybe_unused]] const PlantLocation &calledFromLocation,
122 : [[maybe_unused]] bool const FirstHVACIteration,
123 : [[maybe_unused]] Real64 &CurLoad,
124 : bool const RunFlag)
125 : {
126 148307 : this->initialize(state);
127 148307 : if (this->FluidCoolerType == DataPlant::PlantEquipmentType::FluidCooler_SingleSpd) {
128 22981 : this->calcSingleSpeed(state);
129 : } else {
130 125326 : this->calcTwoSpeed(state);
131 : }
132 148307 : this->update(state);
133 148307 : this->report(state, RunFlag);
134 148307 : }
135 :
136 30 : void FluidCoolerspecs::onInitLoopEquip(EnergyPlusData &state, [[maybe_unused]] const PlantLocation &calledFromLocation)
137 : {
138 30 : this->initialize(state);
139 30 : this->size(state);
140 30 : }
141 :
142 30 : void FluidCoolerspecs::getDesignCapacities([[maybe_unused]] EnergyPlusData &state,
143 : [[maybe_unused]] const PlantLocation &calledFromLocation,
144 : Real64 &MaxLoad,
145 : Real64 &MinLoad,
146 : Real64 &OptLoad)
147 : {
148 30 : MaxLoad = this->FluidCoolerNominalCapacity;
149 30 : OptLoad = this->FluidCoolerNominalCapacity;
150 30 : MinLoad = 0.0;
151 30 : }
152 :
153 6 : void GetFluidCoolerInput(EnergyPlusData &state)
154 : {
155 :
156 : // SUBROUTINE INFORMATION:
157 : // AUTHOR: Chandan Sharma
158 : // DATE WRITTEN: August 2008
159 : // MODIFIED Chandan Sharma, FSEC, April 2010
160 :
161 : // PURPOSE OF THIS SUBROUTINE:
162 : // Obtains input data for fluid coolers and stores it in SimpleFluidCooler data structure.
163 :
164 : // METHODOLOGY EMPLOYED:
165 : // Uses "Get" routines to read in the data.
166 :
167 : // REFERENCES:
168 : // Based on GetTowerInput subroutine from Don Shirey, Jan 2001 and Sept/Oct 2002;
169 :
170 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
171 6 : int NumAlphas = 0; // Number of elements in the alpha array
172 6 : int NumNums = 0; // Number of elements in the numeric array
173 6 : int IOStat = 0; // IO Status when calling get input subroutine
174 6 : bool ErrorsFound(false); // Logical flag set .TRUE. if errors found while getting input data
175 6 : Array1D<Real64> NumArray(16); // Numeric input data array
176 6 : Array1D_string AlphArray(5); // Character string input data array
177 :
178 : // Get number of all Fluid Coolers specified in the input data file (idf)
179 6 : int const NumSingleSpeedFluidCoolers = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "FluidCooler:SingleSpeed");
180 6 : int const NumTwoSpeedFluidCoolers = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "FluidCooler:TwoSpeed");
181 6 : state.dataFluidCoolers->NumSimpleFluidCoolers = NumSingleSpeedFluidCoolers + NumTwoSpeedFluidCoolers;
182 :
183 6 : if (state.dataFluidCoolers->NumSimpleFluidCoolers <= 0) {
184 0 : ShowFatalError(state,
185 : "No fluid cooler objects found in input, however, a branch object has specified a fluid cooler. Search the input for "
186 : "fluid cooler to determine the cause for this error.");
187 : }
188 :
189 : // See if load distribution manager has already gotten the input
190 6 : if (allocated(state.dataFluidCoolers->SimpleFluidCooler)) {
191 0 : return;
192 : }
193 6 : state.dataFluidCoolers->GetFluidCoolerInputFlag = false;
194 :
195 : // Allocate data structures to hold fluid cooler input data, report data and fluid cooler inlet conditions
196 6 : state.dataFluidCoolers->SimpleFluidCooler.allocate(state.dataFluidCoolers->NumSimpleFluidCoolers);
197 6 : state.dataFluidCoolers->UniqueSimpleFluidCoolerNames.reserve(state.dataFluidCoolers->NumSimpleFluidCoolers);
198 :
199 : // Load data structures with fluid cooler input data
200 6 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
201 6 : cCurrentModuleObject = cFluidCooler_SingleSpeed;
202 7 : for (int SingleSpeedFluidCoolerNumber = 1; SingleSpeedFluidCoolerNumber <= NumSingleSpeedFluidCoolers; ++SingleSpeedFluidCoolerNumber) {
203 1 : int FluidCoolerNum = SingleSpeedFluidCoolerNumber;
204 2 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
205 : cCurrentModuleObject,
206 : SingleSpeedFluidCoolerNumber,
207 : AlphArray,
208 : NumAlphas,
209 : NumArray,
210 : NumNums,
211 : IOStat,
212 1 : state.dataIPShortCut->lNumericFieldBlanks,
213 1 : state.dataIPShortCut->lAlphaFieldBlanks,
214 1 : state.dataIPShortCut->cAlphaFieldNames,
215 1 : state.dataIPShortCut->cNumericFieldNames);
216 1 : GlobalNames::VerifyUniqueInterObjectName(state,
217 1 : state.dataFluidCoolers->UniqueSimpleFluidCoolerNames,
218 1 : AlphArray(1),
219 : cCurrentModuleObject,
220 1 : state.dataIPShortCut->cAlphaFieldNames(1),
221 : ErrorsFound);
222 :
223 1 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).Name = AlphArray(1);
224 1 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).FluidCoolerType = DataPlant::PlantEquipmentType::FluidCooler_SingleSpd;
225 1 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).indexInArray = FluidCoolerNum;
226 1 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).FluidCoolerMassFlowRateMultiplier = 2.5;
227 1 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).WaterInletNodeNum =
228 2 : NodeInputManager::GetOnlySingleNode(state,
229 1 : AlphArray(2),
230 : ErrorsFound,
231 : DataLoopNode::ConnectionObjectType::FluidCoolerSingleSpeed,
232 1 : AlphArray(1),
233 : DataLoopNode::NodeFluidType::Water,
234 : DataLoopNode::ConnectionType::Inlet,
235 : NodeInputManager::CompFluidStream::Primary,
236 : DataLoopNode::ObjectIsNotParent);
237 1 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).WaterOutletNodeNum =
238 3 : NodeInputManager::GetOnlySingleNode(state,
239 1 : AlphArray(3),
240 : ErrorsFound,
241 : DataLoopNode::ConnectionObjectType::FluidCoolerSingleSpeed,
242 1 : AlphArray(1),
243 : DataLoopNode::NodeFluidType::Water,
244 : DataLoopNode::ConnectionType::Outlet,
245 : NodeInputManager::CompFluidStream::Primary,
246 : DataLoopNode::ObjectIsNotParent);
247 1 : BranchNodeConnections::TestCompSet(state, cCurrentModuleObject, AlphArray(1), AlphArray(2), AlphArray(3), "Chilled Water Nodes");
248 1 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).HighSpeedFluidCoolerUA = NumArray(1);
249 1 : if (state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).HighSpeedFluidCoolerUA == DataSizing::AutoSize) {
250 0 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).HighSpeedFluidCoolerUAWasAutoSized = true;
251 : }
252 1 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).FluidCoolerNominalCapacity = NumArray(2);
253 1 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).DesignEnteringWaterTemp = NumArray(3);
254 1 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).DesignEnteringAirTemp = NumArray(4);
255 1 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).DesignEnteringAirWetBulbTemp = NumArray(5);
256 1 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).DesignWaterFlowRate = NumArray(6);
257 1 : if (state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).DesignWaterFlowRate == DataSizing::AutoSize) {
258 0 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).DesignWaterFlowRateWasAutoSized = true;
259 : }
260 1 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).HighSpeedAirFlowRate = NumArray(7);
261 1 : if (state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).HighSpeedAirFlowRate == DataSizing::AutoSize) {
262 0 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).HighSpeedAirFlowRateWasAutoSized = true;
263 : }
264 1 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).HighSpeedFanPower = NumArray(8);
265 1 : if (state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).HighSpeedFanPower == DataSizing::AutoSize) {
266 1 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).HighSpeedFanPowerWasAutoSized = true;
267 : }
268 :
269 : // outdoor air inlet node
270 1 : if (AlphArray(5).empty()) {
271 1 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).OutdoorAirInletNodeNum = 0;
272 : } else {
273 0 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).OutdoorAirInletNodeNum =
274 0 : NodeInputManager::GetOnlySingleNode(state,
275 0 : AlphArray(5),
276 : ErrorsFound,
277 : DataLoopNode::ConnectionObjectType::FluidCoolerSingleSpeed,
278 0 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).Name,
279 : DataLoopNode::NodeFluidType::Air,
280 : DataLoopNode::ConnectionType::OutsideAirReference,
281 : NodeInputManager::CompFluidStream::Primary,
282 : DataLoopNode::ObjectIsNotParent);
283 0 : if (!OutAirNodeManager::CheckOutAirNodeNumber(state, state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).OutdoorAirInletNodeNum)) {
284 0 : ShowSevereError(state,
285 0 : format("{}= \"{}\" {}= \"{}\" not valid.",
286 : cCurrentModuleObject,
287 0 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).Name,
288 0 : state.dataIPShortCut->cAlphaFieldNames(5),
289 : AlphArray(5)));
290 0 : ShowContinueError(state, "...does not appear in an OutdoorAir:NodeList or as an OutdoorAir:Node.");
291 0 : ErrorsFound = true;
292 : }
293 : }
294 :
295 1 : ErrorsFound |=
296 1 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum)
297 1 : .validateSingleSpeedInputs(
298 1 : state, cCurrentModuleObject, AlphArray, state.dataIPShortCut->cNumericFieldNames, state.dataIPShortCut->cAlphaFieldNames);
299 :
300 : } // End Single-Speed fluid cooler Loop
301 :
302 6 : cCurrentModuleObject = cFluidCooler_TwoSpeed;
303 11 : for (int TwoSpeedFluidCoolerNumber = 1; TwoSpeedFluidCoolerNumber <= NumTwoSpeedFluidCoolers; ++TwoSpeedFluidCoolerNumber) {
304 5 : int FluidCoolerNum = NumSingleSpeedFluidCoolers + TwoSpeedFluidCoolerNumber;
305 10 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
306 : cCurrentModuleObject,
307 : TwoSpeedFluidCoolerNumber,
308 : AlphArray,
309 : NumAlphas,
310 : NumArray,
311 : NumNums,
312 : IOStat,
313 5 : state.dataIPShortCut->lNumericFieldBlanks,
314 5 : state.dataIPShortCut->lAlphaFieldBlanks,
315 5 : state.dataIPShortCut->cAlphaFieldNames,
316 5 : state.dataIPShortCut->cNumericFieldNames);
317 5 : GlobalNames::VerifyUniqueInterObjectName(state,
318 5 : state.dataFluidCoolers->UniqueSimpleFluidCoolerNames,
319 5 : AlphArray(1),
320 : cCurrentModuleObject,
321 5 : state.dataIPShortCut->cAlphaFieldNames(1),
322 : ErrorsFound);
323 :
324 5 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).Name = AlphArray(1);
325 5 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).FluidCoolerType = DataPlant::PlantEquipmentType::FluidCooler_TwoSpd;
326 5 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).indexInArray = FluidCoolerNum;
327 5 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).FluidCoolerMassFlowRateMultiplier = 2.5;
328 5 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).WaterInletNodeNum =
329 10 : NodeInputManager::GetOnlySingleNode(state,
330 5 : AlphArray(2),
331 : ErrorsFound,
332 : DataLoopNode::ConnectionObjectType::FluidCoolerTwoSpeed,
333 5 : AlphArray(1),
334 : DataLoopNode::NodeFluidType::Water,
335 : DataLoopNode::ConnectionType::Inlet,
336 : NodeInputManager::CompFluidStream::Primary,
337 : DataLoopNode::ObjectIsNotParent);
338 5 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).WaterOutletNodeNum =
339 15 : NodeInputManager::GetOnlySingleNode(state,
340 5 : AlphArray(3),
341 : ErrorsFound,
342 : DataLoopNode::ConnectionObjectType::FluidCoolerTwoSpeed,
343 5 : AlphArray(1),
344 : DataLoopNode::NodeFluidType::Water,
345 : DataLoopNode::ConnectionType::Outlet,
346 : NodeInputManager::CompFluidStream::Primary,
347 : DataLoopNode::ObjectIsNotParent);
348 5 : BranchNodeConnections::TestCompSet(state, cCurrentModuleObject, AlphArray(1), AlphArray(2), AlphArray(3), "Chilled Water Nodes");
349 :
350 5 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).HighSpeedFluidCoolerUA = NumArray(1);
351 5 : if (state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).HighSpeedFluidCoolerUA == DataSizing::AutoSize) {
352 0 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).HighSpeedFluidCoolerUAWasAutoSized = true;
353 : }
354 5 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).LowSpeedFluidCoolerUA = NumArray(2);
355 5 : if (state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).LowSpeedFluidCoolerUA == DataSizing::AutoSize) {
356 0 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).LowSpeedFluidCoolerUAWasAutoSized = true;
357 : }
358 5 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).LowSpeedFluidCoolerUASizingFactor = NumArray(3);
359 5 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).FluidCoolerNominalCapacity = NumArray(4);
360 5 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).FluidCoolerLowSpeedNomCap = NumArray(5);
361 5 : if (state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).FluidCoolerLowSpeedNomCap == DataSizing::AutoSize) {
362 0 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).FluidCoolerLowSpeedNomCapWasAutoSized = true;
363 : }
364 5 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).FluidCoolerLowSpeedNomCapSizingFactor = NumArray(6);
365 5 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).DesignEnteringWaterTemp = NumArray(7);
366 5 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).DesignEnteringAirTemp = NumArray(8);
367 5 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).DesignEnteringAirWetBulbTemp = NumArray(9);
368 5 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).DesignWaterFlowRate = NumArray(10);
369 5 : if (state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).DesignWaterFlowRate == DataSizing::AutoSize) {
370 5 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).DesignWaterFlowRateWasAutoSized = true;
371 : }
372 5 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).HighSpeedAirFlowRate = NumArray(11);
373 5 : if (state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).HighSpeedAirFlowRate == DataSizing::AutoSize) {
374 5 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).HighSpeedAirFlowRateWasAutoSized = true;
375 : }
376 5 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).HighSpeedFanPower = NumArray(12);
377 5 : if (state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).HighSpeedFanPower == DataSizing::AutoSize) {
378 1 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).HighSpeedFanPowerWasAutoSized = true;
379 : }
380 5 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).LowSpeedAirFlowRate = NumArray(13);
381 5 : if (state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).LowSpeedAirFlowRate == DataSizing::AutoSize) {
382 5 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).LowSpeedAirFlowRateWasAutoSized = true;
383 : }
384 5 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).LowSpeedAirFlowRateSizingFactor = NumArray(14);
385 5 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).LowSpeedFanPower = NumArray(15);
386 5 : if (state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).LowSpeedFanPower == DataSizing::AutoSize) {
387 5 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).LowSpeedFanPowerWasAutoSized = true;
388 : }
389 5 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).LowSpeedFanPowerSizingFactor = NumArray(16);
390 :
391 : // outdoor air inlet node
392 5 : if (AlphArray(5).empty()) {
393 5 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).OutdoorAirInletNodeNum = 0;
394 : } else {
395 0 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).OutdoorAirInletNodeNum =
396 0 : NodeInputManager::GetOnlySingleNode(state,
397 0 : AlphArray(5),
398 : ErrorsFound,
399 : DataLoopNode::ConnectionObjectType::FluidCoolerTwoSpeed,
400 0 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).Name,
401 : DataLoopNode::NodeFluidType::Air,
402 : DataLoopNode::ConnectionType::OutsideAirReference,
403 : NodeInputManager::CompFluidStream::Primary,
404 : DataLoopNode::ObjectIsNotParent);
405 0 : if (!OutAirNodeManager::CheckOutAirNodeNumber(state, state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).OutdoorAirInletNodeNum)) {
406 0 : ShowSevereError(state,
407 0 : format("{}= \"{}\" {}= \"{}\" not valid.",
408 : cCurrentModuleObject,
409 0 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum).Name,
410 0 : state.dataIPShortCut->cAlphaFieldNames(5),
411 : AlphArray(5)));
412 0 : ShowContinueError(state, "...does not appear in an OutdoorAir:NodeList or as an OutdoorAir:Node.");
413 0 : ErrorsFound = true;
414 : }
415 : }
416 :
417 5 : ErrorsFound |=
418 5 : state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum)
419 5 : .validateTwoSpeedInputs(
420 5 : state, cCurrentModuleObject, AlphArray, state.dataIPShortCut->cNumericFieldNames, state.dataIPShortCut->cAlphaFieldNames);
421 : }
422 :
423 6 : if (ErrorsFound) {
424 0 : ShowFatalError(state, "Errors found in getting fluid cooler input.");
425 : }
426 6 : }
427 :
428 6 : void FluidCoolerspecs::setupOutputVars(EnergyPlusData &state)
429 : {
430 :
431 12 : SetupOutputVariable(state,
432 : "Cooling Tower Inlet Temperature",
433 : Constant::Units::C,
434 6 : this->InletWaterTemp,
435 : OutputProcessor::TimeStepType::System,
436 : OutputProcessor::StoreType::Average,
437 6 : this->Name);
438 12 : SetupOutputVariable(state,
439 : "Cooling Tower Outlet Temperature",
440 : Constant::Units::C,
441 6 : this->OutletWaterTemp,
442 : OutputProcessor::TimeStepType::System,
443 : OutputProcessor::StoreType::Average,
444 6 : this->Name);
445 12 : SetupOutputVariable(state,
446 : "Cooling Tower Mass Flow Rate",
447 : Constant::Units::kg_s,
448 6 : this->WaterMassFlowRate,
449 : OutputProcessor::TimeStepType::System,
450 : OutputProcessor::StoreType::Average,
451 6 : this->Name);
452 12 : SetupOutputVariable(state,
453 : "Cooling Tower Heat Transfer Rate",
454 : Constant::Units::W,
455 6 : this->Qactual,
456 : OutputProcessor::TimeStepType::System,
457 : OutputProcessor::StoreType::Average,
458 6 : this->Name);
459 12 : SetupOutputVariable(state,
460 : "Cooling Tower Fan Electricity Rate",
461 : Constant::Units::W,
462 6 : this->FanPower,
463 : OutputProcessor::TimeStepType::System,
464 : OutputProcessor::StoreType::Average,
465 6 : this->Name);
466 12 : SetupOutputVariable(state,
467 : "Cooling Tower Fan Electricity Energy",
468 : Constant::Units::J,
469 6 : this->FanEnergy,
470 : OutputProcessor::TimeStepType::System,
471 : OutputProcessor::StoreType::Sum,
472 6 : this->Name,
473 : Constant::eResource::Electricity,
474 : OutputProcessor::Group::Plant,
475 : OutputProcessor::EndUseCat::HeatRejection);
476 6 : }
477 :
478 1 : bool FluidCoolerspecs::validateSingleSpeedInputs(EnergyPlusData &state,
479 : std::string const &cCurrentModuleObject,
480 : Array1D<std::string> const &AlphArray,
481 : Array1D<std::string> const &cNumericFieldNames,
482 : Array1D<std::string> const &cAlphaFieldNames)
483 : {
484 : // FUNCTION INFORMATION:
485 : // AUTHOR: Chandan Sharma
486 : // DATE WRITTEN: August 2008
487 : // MODIFIED Chandan Sharma, FSEC, April 2010
488 : // RE-ENGINEERED Jason Glazer, GARD Analytics, February 2015, refactor into a separate function
489 :
490 : // PURPOSE OF THIS FUNCTION:
491 : // Separate the testing of inputs related to design so that it could be called from the unit tests
492 :
493 : // REFERENCES:
494 : // Based on GetTowerInput subroutine from Don Shirey, Jan 2001 and Sept/Oct 2002;
495 :
496 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
497 1 : bool ErrorsFound = false;
498 :
499 : // Design entering water temperature, design entering air temperature and design entering air
500 : // wetbulb temperature must be specified for the both the performance input methods
501 1 : if (this->DesignEnteringWaterTemp <= 0.0) {
502 0 : ShowSevereError(state,
503 0 : format("{} = \"{}\", invalid data for \"{}\", entered value <= 0.0, but must be > 0 ",
504 : cCurrentModuleObject,
505 : AlphArray(1),
506 : cNumericFieldNames(3)));
507 0 : ErrorsFound = true;
508 : }
509 1 : if (this->DesignEnteringAirTemp <= 0.0) {
510 0 : ShowSevereError(state,
511 0 : format("{} = \"{}\", invalid data for \"{}\", entered value <= 0.0, but must be > 0 ",
512 : cCurrentModuleObject,
513 : AlphArray(1),
514 : cNumericFieldNames(4)));
515 0 : ErrorsFound = true;
516 : }
517 1 : if (this->DesignEnteringAirWetBulbTemp <= 0.0) {
518 0 : ShowSevereError(state,
519 0 : format("{} = \"{}\", invalid data for \"{}\", entered value <= 0.0, but must be > 0 ",
520 : cCurrentModuleObject,
521 : AlphArray(1),
522 : cNumericFieldNames(5)));
523 0 : ErrorsFound = true;
524 : }
525 1 : if (this->DesignEnteringWaterTemp <= this->DesignEnteringAirTemp) {
526 0 : ShowSevereError(
527 : state,
528 0 : format("{}= \"{}\",{} must be greater than {}.", cCurrentModuleObject, AlphArray(1), cNumericFieldNames(3), cNumericFieldNames(4)));
529 0 : ErrorsFound = true;
530 : }
531 1 : if (this->DesignEnteringAirTemp <= this->DesignEnteringAirWetBulbTemp) {
532 0 : ShowSevereError(
533 : state,
534 0 : format("{}= \"{}\",{} must be greater than {}.", cCurrentModuleObject, AlphArray(1), cNumericFieldNames(4), cNumericFieldNames(5)));
535 0 : ErrorsFound = true;
536 : }
537 1 : if (this->HighSpeedAirFlowRate <= 0.0 && this->HighSpeedAirFlowRate != DataSizing::AutoSize) {
538 0 : ShowSevereError(state,
539 0 : format("{} = \"{}\", invalid data for \"{}\", entered value <= 0.0, but must be > 0 for {} = \"{}\".",
540 : cCurrentModuleObject,
541 : AlphArray(1),
542 : cNumericFieldNames(7),
543 : cAlphaFieldNames(4),
544 : AlphArray(4)));
545 0 : ErrorsFound = true;
546 : }
547 1 : if (this->DesignWaterFlowRate <= 0.0 && !this->DesignWaterFlowRateWasAutoSized) {
548 0 : ShowSevereError(state,
549 0 : format("{} = \"{}\", invalid data for \"{}\", entered value <= 0.0, but must be > 0 for {} = \"{}\".",
550 : cCurrentModuleObject,
551 : AlphArray(1),
552 : cNumericFieldNames(6),
553 : cAlphaFieldNames(4),
554 : AlphArray(4)));
555 0 : ErrorsFound = true;
556 : }
557 1 : if (this->HighSpeedFanPower <= 0.0 && this->HighSpeedFanPower != DataSizing::AutoSize) {
558 0 : ShowSevereError(state,
559 0 : format("{} = \"{}\", invalid data for \"{}\", entered value <= 0.0, but must be > 0 for {} = \"{}\".",
560 : cCurrentModuleObject,
561 : AlphArray(1),
562 : cNumericFieldNames(8),
563 : cAlphaFieldNames(4),
564 : AlphArray(4)));
565 0 : ErrorsFound = true;
566 : }
567 :
568 : // Check various inputs for both the performance input methods
569 1 : if (Util::SameString(AlphArray(4), "UFactorTimesAreaAndDesignWaterFlowRate")) {
570 0 : this->PerformanceInputMethod_Num = PerfInputMethod::U_FACTOR;
571 0 : if (this->HighSpeedFluidCoolerUA <= 0.0 && this->HighSpeedFluidCoolerUA != DataSizing::AutoSize) {
572 0 : ShowSevereError(state,
573 0 : format("{} = \"{}\", invalid data for \"{}\", entered value <= 0.0, but must be > 0 for {} = \"{}\".",
574 : cCurrentModuleObject,
575 : AlphArray(1),
576 : cNumericFieldNames(1),
577 : cAlphaFieldNames(4),
578 : AlphArray(4)));
579 0 : ErrorsFound = true;
580 : }
581 1 : } else if (Util::SameString(AlphArray(4), "NominalCapacity")) {
582 1 : this->PerformanceInputMethod_Num = PerfInputMethod::NOMINAL_CAPACITY;
583 1 : if (this->FluidCoolerNominalCapacity <= 0.0) {
584 0 : ShowSevereError(state,
585 0 : format("{} = \"{}\", invalid data for \"{}\", entered value <= 0.0, but must be > 0 for {} = \"{}\".",
586 : cCurrentModuleObject,
587 : AlphArray(1),
588 : cNumericFieldNames(2),
589 : cAlphaFieldNames(4),
590 : AlphArray(4)));
591 0 : ErrorsFound = true;
592 : }
593 1 : if (this->HighSpeedFluidCoolerUA != 0.0) {
594 0 : if (this->HighSpeedFluidCoolerUA > 0.0) {
595 0 : ShowWarningError(state,
596 0 : format("{}= \"{}\". Nominal fluid cooler capacity and design fluid cooler UA have been specified.",
597 : cCurrentModuleObject,
598 0 : this->Name));
599 : } else {
600 0 : ShowWarningError(state,
601 0 : format("{}= \"{}\". Nominal fluid cooler capacity has been specified and design fluid cooler UA is being autosized.",
602 : cCurrentModuleObject,
603 0 : this->Name));
604 : }
605 0 : ShowContinueError(state,
606 : "Design fluid cooler UA field must be left blank when nominal fluid cooler capacity performance input method is used.");
607 0 : ShowContinueError(state, "Design fluid cooler UA value will be reset to zero and the simulation continuous.");
608 0 : this->HighSpeedFluidCoolerUA = 0.0;
609 : }
610 : } else { // Fluid cooler performance input method is not specified as a valid "choice"
611 0 : ShowSevereError(state, format("{}= \"{}\", invalid {} = \"{}\".", cCurrentModuleObject, AlphArray(1), cAlphaFieldNames(4), AlphArray(4)));
612 0 : ShowContinueError(state, R"(... must be "UFactorTimesAreaAndDesignWaterFlowRate" or "NominalCapacity".)");
613 0 : ErrorsFound = true;
614 : }
615 1 : return ErrorsFound;
616 : }
617 :
618 5 : bool FluidCoolerspecs::validateTwoSpeedInputs(EnergyPlusData &state,
619 : std::string const &cCurrentModuleObject,
620 : Array1D<std::string> const &AlphArray,
621 : Array1D<std::string> const &cNumericFieldNames,
622 : Array1D<std::string> const &cAlphaFieldNames)
623 : {
624 : // FUNCTION INFORMATION:
625 : // AUTHOR: Chandan Sharma
626 : // DATE WRITTEN: August 2008
627 : // MODIFIED Chandan Sharma, FSEC, April 2010
628 : // RE-ENGINEERED Jason Glazer, GARD Analytics, February 2015, refactor into a separate function
629 :
630 : // PURPOSE OF THIS FUNCTION:
631 : // Separate the testing of inputs related to design so that it could be called from the unit tests
632 :
633 : // REFERENCES:
634 : // Based on GetTowerInput subroutine from Don Shirey, Jan 2001 and Sept/Oct 2002;
635 :
636 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
637 5 : bool ErrorsFound = false;
638 :
639 : // Design entering water temperature, design entering air temperature and design entering air
640 : // wetbulb temperature must be specified for the both the performance input methods
641 5 : if (this->DesignEnteringWaterTemp <= 0.0) {
642 0 : ShowSevereError(state,
643 0 : format("{} = \"{}\", invalid data for \"{}\", entered value <= 0.0, but must be > 0 ",
644 : cCurrentModuleObject,
645 : AlphArray(1),
646 : cNumericFieldNames(7)));
647 0 : ErrorsFound = true;
648 : }
649 5 : if (this->DesignEnteringAirTemp <= 0.0) {
650 0 : ShowSevereError(state,
651 0 : format("{} = \"{}\", invalid data for \"{}\", entered value <= 0.0, but must be > 0 ",
652 : cCurrentModuleObject,
653 : AlphArray(1),
654 : cNumericFieldNames(8)));
655 0 : ErrorsFound = true;
656 : }
657 5 : if (this->DesignEnteringAirWetBulbTemp <= 0.0) {
658 0 : ShowSevereError(state,
659 0 : format("{} = \"{}\", invalid data for \"{}\", entered value <= 0.0, but must be > 0 ",
660 : cCurrentModuleObject,
661 : AlphArray(1),
662 : cNumericFieldNames(9)));
663 0 : ErrorsFound = true;
664 : }
665 5 : if (this->DesignEnteringWaterTemp <= this->DesignEnteringAirTemp) {
666 0 : ShowSevereError(
667 : state,
668 0 : format("{} = \"{}\", {} must be greater than {}.", cCurrentModuleObject, AlphArray(1), cNumericFieldNames(7), cNumericFieldNames(8)));
669 0 : ErrorsFound = true;
670 : }
671 5 : if (this->DesignEnteringAirTemp <= this->DesignEnteringAirWetBulbTemp) {
672 0 : ShowSevereError(
673 : state,
674 0 : format("{} = \"{}\", {} must be greater than {}.", cCurrentModuleObject, AlphArray(1), cNumericFieldNames(8), cNumericFieldNames(9)));
675 0 : ErrorsFound = true;
676 : }
677 :
678 : // Check various inputs for both the performance input methods
679 5 : if (this->DesignWaterFlowRate <= 0.0 && !this->DesignWaterFlowRateWasAutoSized) {
680 0 : ShowSevereError(state,
681 0 : format("{}= \"{}\", invalid data for \"{}\", entered value <= 0.0, but must be > 0 for {}= \"{}\".",
682 : cCurrentModuleObject,
683 : AlphArray(1),
684 : cNumericFieldNames(10),
685 : cAlphaFieldNames(4),
686 : AlphArray(4)));
687 0 : ErrorsFound = true;
688 : }
689 5 : if (this->HighSpeedAirFlowRate <= 0.0 && !this->HighSpeedAirFlowRateWasAutoSized) {
690 0 : ShowSevereError(state,
691 0 : format("{}= \"{}\", invalid data for \"{}\", entered value <= 0.0, but must be > 0 for {}= \"{}\".",
692 : cCurrentModuleObject,
693 : AlphArray(1),
694 : cNumericFieldNames(11),
695 : cAlphaFieldNames(4),
696 : AlphArray(4)));
697 0 : ErrorsFound = true;
698 : }
699 5 : if (this->LowSpeedAirFlowRate <= 0.0 && !this->LowSpeedAirFlowRateWasAutoSized) {
700 0 : ShowSevereError(state,
701 0 : format("{}= \"{}\", invalid data for \"{}\", entered value <= 0.0, but must be > 0 for {}= \"{}\".",
702 : cCurrentModuleObject,
703 : AlphArray(1),
704 : cNumericFieldNames(13),
705 : cAlphaFieldNames(4),
706 : AlphArray(4)));
707 0 : ErrorsFound = true;
708 : }
709 : // High speed air flow rate must be greater than low speed air flow rate.
710 : // Can't tell yet if autosized, check later in InitFluidCooler.
711 5 : if (this->HighSpeedAirFlowRate <= this->LowSpeedAirFlowRate && !this->HighSpeedAirFlowRateWasAutoSized) {
712 0 : ShowSevereError(state,
713 0 : format("{}= \"{}\". Fluid cooler air flow rate at low fan speed must be less than the air flow rate at high fan speed.",
714 : cCurrentModuleObject,
715 0 : this->Name));
716 0 : ErrorsFound = true;
717 : }
718 5 : if (this->HighSpeedFanPower <= 0.0 && !this->HighSpeedFanPowerWasAutoSized) {
719 0 : ShowSevereError(state,
720 0 : format("{} = \"{}\", invalid data for \"{}\", entered value <= 0.0, but must be > 0 for {} = \"{}\".",
721 : cCurrentModuleObject,
722 : AlphArray(1),
723 : cNumericFieldNames(12),
724 : cAlphaFieldNames(4),
725 : AlphArray(4)));
726 0 : ErrorsFound = true;
727 : }
728 5 : if (this->LowSpeedFanPower <= 0.0 && !this->LowSpeedFanPowerWasAutoSized) {
729 0 : ShowSevereError(state,
730 0 : format("{} = \"{}\", invalid data for \"{}\", entered value <= 0.0, but must be > 0 for {} = \"{}\".",
731 : cCurrentModuleObject,
732 : AlphArray(1),
733 : cNumericFieldNames(15),
734 : cAlphaFieldNames(4),
735 : AlphArray(4)));
736 0 : ErrorsFound = true;
737 : }
738 5 : if (this->HighSpeedFanPower <= this->LowSpeedFanPower && !this->HighSpeedFanPowerWasAutoSized) {
739 0 : ShowSevereError(
740 0 : state, format("{}= \"{}\". Fluid cooler low speed fan power must be less than high speed fan power.", cCurrentModuleObject, this->Name));
741 0 : ErrorsFound = true;
742 : }
743 :
744 5 : if (Util::SameString(AlphArray(4), "UFactorTimesAreaAndDesignWaterFlowRate")) {
745 0 : this->PerformanceInputMethod_Num = PerfInputMethod::U_FACTOR;
746 0 : if (this->HighSpeedFluidCoolerUA <= 0.0 && !this->HighSpeedFluidCoolerUAWasAutoSized) {
747 0 : ShowSevereError(state,
748 0 : format("{} = \"{}\", invalid data for \"{}\", entered value <= 0.0, but must be > 0 for {} = \"{}\".",
749 : cCurrentModuleObject,
750 : AlphArray(1),
751 : cNumericFieldNames(1),
752 : cAlphaFieldNames(4),
753 : AlphArray(4)));
754 0 : ErrorsFound = true;
755 : }
756 0 : if (this->LowSpeedFluidCoolerUA <= 0.0 && !this->LowSpeedFluidCoolerUAWasAutoSized) {
757 0 : ShowSevereError(state,
758 0 : format("{} = \"{}\", invalid data for \"{}\", entered value <= 0.0, but must be > 0 for {} = \"{}\".",
759 : cCurrentModuleObject,
760 : AlphArray(1),
761 : cNumericFieldNames(2),
762 : cAlphaFieldNames(4),
763 : AlphArray(4)));
764 0 : ErrorsFound = true;
765 : }
766 0 : if (this->HighSpeedFluidCoolerUA <= this->LowSpeedFluidCoolerUA && !this->HighSpeedFluidCoolerUAWasAutoSized) {
767 0 : ShowSevereError(state,
768 0 : format("{}= \"{}\". Fluid cooler UA at low fan speed must be less than the fluid cooler UA at high fan speed.",
769 : cCurrentModuleObject,
770 0 : this->Name));
771 0 : ErrorsFound = true;
772 : }
773 5 : } else if (Util::SameString(AlphArray(4), "NominalCapacity")) {
774 5 : this->PerformanceInputMethod_Num = PerfInputMethod::NOMINAL_CAPACITY;
775 5 : if (this->FluidCoolerNominalCapacity <= 0.0) {
776 0 : ShowSevereError(state,
777 0 : format("{} = \"{}\", invalid data for \"{}\", entered value <= 0.0, but must be > 0 for {}= \"{}\".",
778 : cCurrentModuleObject,
779 : AlphArray(1),
780 : cNumericFieldNames(4),
781 : cAlphaFieldNames(4),
782 : AlphArray(4)));
783 0 : ErrorsFound = true;
784 : }
785 5 : if (this->FluidCoolerLowSpeedNomCap <= 0.0 && !this->FluidCoolerLowSpeedNomCapWasAutoSized) {
786 0 : ShowSevereError(state,
787 0 : format("{} = \"{}\", invalid data for \"{}\", entered value <= 0.0, but must be > 0 for {}= \"{}\".",
788 : cCurrentModuleObject,
789 : AlphArray(1),
790 : cNumericFieldNames(5),
791 : cAlphaFieldNames(4),
792 : AlphArray(4)));
793 0 : ErrorsFound = true;
794 : }
795 5 : if (this->HighSpeedFluidCoolerUA != 0.0) {
796 0 : if (this->HighSpeedFluidCoolerUA > 0.0) {
797 0 : ShowSevereError(state,
798 0 : format("{}= \"{}\". Nominal capacity input method and fluid cooler UA at high fan speed have been specified.",
799 : cCurrentModuleObject,
800 0 : this->Name));
801 : } else {
802 0 : ShowSevereError(
803 : state,
804 0 : format("{}= \"{}\". Nominal capacity input method has been specified and fluid cooler UA at high fan speed is being autosized.",
805 : cCurrentModuleObject,
806 0 : this->Name));
807 : }
808 0 : ShowContinueError(
809 : state, "Fluid cooler UA at high fan speed must be left blank when nominal fluid cooler capacity performance input method is used.");
810 0 : ErrorsFound = true;
811 : }
812 5 : if (this->LowSpeedFluidCoolerUA != 0.0) {
813 0 : if (this->LowSpeedFluidCoolerUA > 0.0) {
814 0 : ShowSevereError(state,
815 0 : format("{}= \"{}\". Nominal capacity input method and fluid cooler UA at low fan speed have been specified.",
816 : cCurrentModuleObject,
817 0 : this->Name));
818 : } else {
819 0 : ShowSevereError(
820 : state,
821 0 : format("{}= \"{}\". Nominal capacity input method has been specified and fluid cooler UA at low fan speed is being autosized.",
822 : cCurrentModuleObject,
823 0 : this->Name));
824 : }
825 0 : ShowContinueError(
826 : state, "Fluid cooler UA at low fan speed must be left blank when nominal fluid cooler capacity performance input method is used.");
827 0 : ErrorsFound = true;
828 : }
829 5 : if (this->FluidCoolerLowSpeedNomCap >= this->FluidCoolerNominalCapacity) {
830 0 : ShowSevereError(state,
831 0 : format("{} = \"{}\". Low-speed nominal capacity must be less than the high-speed nominal capacity.",
832 : cCurrentModuleObject,
833 0 : this->Name));
834 0 : ErrorsFound = true;
835 : }
836 : } else { // Fluid cooler performance input method is not specified as a valid "choice"
837 0 : ShowSevereError(state, format("{}= \"{}\", invalid {}= \"{}\".", cCurrentModuleObject, AlphArray(1), cAlphaFieldNames(4), AlphArray(4)));
838 0 : ShowContinueError(state, R"(... must be "UFactorTimesAreaAndDesignWaterFlowRate" or "NominalCapacity".)");
839 0 : ErrorsFound = true;
840 : }
841 5 : return ErrorsFound;
842 : }
843 :
844 6 : void FluidCoolerspecs::oneTimeInit_new(EnergyPlusData &state)
845 : {
846 6 : this->setupOutputVars(state);
847 6 : bool ErrorsFound = false;
848 : // Locate the tower on the plant loops for later usage
849 6 : PlantUtilities::ScanPlantLoopsForObject(state, this->Name, this->FluidCoolerType, this->plantLoc, ErrorsFound, _, _, _, _, _);
850 :
851 6 : if (ErrorsFound) {
852 0 : ShowFatalError(state, "InitFluidCooler: Program terminated due to previous condition(s).");
853 : }
854 6 : }
855 :
856 40 : void FluidCoolerspecs::initEachEnvironment(EnergyPlusData &state)
857 : {
858 : static constexpr std::string_view RoutineName("FluidCoolerspecs::initEachEnvironment");
859 40 : Real64 const rho = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
860 40 : this->DesWaterMassFlowRate = this->DesignWaterFlowRate * rho;
861 40 : PlantUtilities::InitComponentNodes(state, 0.0, this->DesWaterMassFlowRate, this->WaterInletNodeNum, this->WaterOutletNodeNum);
862 40 : }
863 :
864 148337 : void FluidCoolerspecs::initialize(EnergyPlusData &state)
865 : {
866 :
867 : // SUBROUTINE INFORMATION:
868 : // AUTHOR Chandan Sharma
869 : // DATE WRITTEN August 2008
870 :
871 : // PURPOSE OF THIS SUBROUTINE:
872 : // This subroutine is for initializations of the fluid cooler components and for
873 : // final checking of fluid cooler inputs (post autosizing)
874 :
875 : // METHODOLOGY EMPLOYED:
876 : // Uses the status flags to trigger initializations.
877 :
878 : // REFERENCES:
879 : // Based on InitTower subroutine by Don Shirey Sept/Oct 2002, F Buhl Oct 2002
880 :
881 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
882 :
883 : // Begin environment initializations
884 148337 : if (this->beginEnvrnInit && state.dataGlobal->BeginEnvrnFlag && (state.dataPlnt->PlantFirstSizesOkayToFinalize)) {
885 40 : this->initEachEnvironment(state);
886 40 : this->beginEnvrnInit = false;
887 : }
888 :
889 148337 : if (!state.dataGlobal->BeginEnvrnFlag) {
890 147648 : this->beginEnvrnInit = true;
891 : }
892 :
893 : // Each time initializations
894 148337 : this->WaterTemp = state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp;
895 :
896 148337 : if (this->OutdoorAirInletNodeNum != 0) {
897 0 : this->AirTemp = state.dataLoopNodes->Node(this->OutdoorAirInletNodeNum).Temp;
898 0 : this->AirHumRat = state.dataLoopNodes->Node(this->OutdoorAirInletNodeNum).HumRat;
899 0 : this->AirPress = state.dataLoopNodes->Node(this->OutdoorAirInletNodeNum).Press;
900 0 : this->AirWetBulb = state.dataLoopNodes->Node(this->OutdoorAirInletNodeNum).OutAirWetBulb;
901 : } else {
902 148337 : this->AirTemp = state.dataEnvrn->OutDryBulbTemp;
903 148337 : this->AirHumRat = state.dataEnvrn->OutHumRat;
904 148337 : this->AirPress = state.dataEnvrn->OutBaroPress;
905 148337 : this->AirWetBulb = state.dataEnvrn->OutWetBulbTemp;
906 : }
907 :
908 148337 : this->WaterMassFlowRate =
909 148337 : PlantUtilities::RegulateCondenserCompFlowReqOp(state, this->plantLoc, this->DesWaterMassFlowRate * this->FluidCoolerMassFlowRateMultiplier);
910 :
911 148337 : PlantUtilities::SetComponentFlowRate(state, this->WaterMassFlowRate, this->WaterInletNodeNum, this->WaterOutletNodeNum, this->plantLoc);
912 148337 : }
913 :
914 30 : void FluidCoolerspecs::size(EnergyPlusData &state)
915 : {
916 :
917 : // SUBROUTINE INFORMATION:
918 : // AUTHOR Chandan Sharma
919 : // DATE WRITTEN August 2008
920 : // MODIFIED April 2010, Chandan Sharma, FSEC
921 :
922 : // PURPOSE OF THIS SUBROUTINE:
923 : // This subroutine is for sizing fluid cooler Components for which capacities and flow rates
924 : // have not been specified in the input. This subroutine also calculates fluid cooler UA if the user
925 : // has specified fluid cooler performance via the "Nominal Capacity" method.
926 :
927 : // METHODOLOGY EMPLOYED:
928 : // Obtains condenser flow rate from the plant sizing array. If fluid cooler performance is specified
929 : // via the "Nominal Capacity" method, the water flow rate is directly proportional to capacity.
930 :
931 : // REFERENCES:
932 : // Based on SizeTower by Don Shirey, Sept/Oct 2002; Richard Raustad, Feb 2005
933 :
934 : // SUBROUTINE PARAMETER DEFINITIONS:
935 30 : constexpr int MaxIte(500); // Maximum number of iterations
936 30 : constexpr Real64 Acc(0.0001); // Accuracy of result
937 : static constexpr std::string_view CalledFrom("SizeFluidCooler");
938 :
939 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
940 : int SolFla; // Flag of solver
941 30 : Real64 DesFluidCoolerLoad(0.0); // Design fluid cooler load [W]
942 : Real64 UA0; // Lower bound for UA [W/C]
943 : Real64 UA1; // Upper bound for UA [W/C]
944 : Real64 UA; // Calculated UA value
945 : Real64 OutWaterTempAtUA0; // Water outlet temperature at UA0
946 : Real64 OutWaterTempAtUA1; // Water outlet temperature at UA1
947 : Real64 Cp; // local specific heat for fluid
948 : Real64 rho; // local density for fluid
949 : Real64 tmpHighSpeedFanPower; // local temporary for high speed fan power
950 : Real64 tmpHighSpeedEvapFluidCoolerUA; // local temporary for high speed cooler UA
951 : bool ErrorsFound;
952 :
953 30 : Real64 tmpDesignWaterFlowRate = this->DesignWaterFlowRate;
954 30 : Real64 tmpHighSpeedAirFlowRate = this->HighSpeedAirFlowRate;
955 : // Find the appropriate Plant Sizing object
956 30 : int PltSizCondNum = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).PlantSizNum;
957 :
958 : // This is to trap when the user specified Condenser/Fluid Cooler water design setpoint temperature is less than design inlet air dry bulb
959 : // temperature
960 25 : auto ensureSizingPlantExitTempIsNotLessThanDesignEnteringAirTemp = [this, &state, PltSizCondNum]() {
961 25 : if (state.dataSize->PlantSizData(PltSizCondNum).ExitTemp <= this->DesignEnteringAirTemp && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
962 0 : ShowSevereError(state, format("Error when autosizing the UA value for fluid cooler = {}.", this->Name));
963 0 : ShowContinueError(state,
964 0 : format("Design Loop Exit Temperature ({:.2R} C) must be greater than design entering air dry-bulb temperature "
965 : "({:.2R} C) when autosizing the fluid cooler UA.",
966 0 : state.dataSize->PlantSizData(PltSizCondNum).ExitTemp,
967 0 : this->DesignEnteringAirTemp));
968 0 : ShowContinueError(state,
969 : "It is recommended that the Design Loop Exit Temperature = design inlet air dry-bulb temp plus the Fluid Cooler "
970 : "design approach temperature (e.g., 4 C).");
971 0 : ShowContinueError(state,
972 : "If using HVACTemplate:Plant:ChilledWaterLoop, then check that input field Condenser Water Design Setpoint must be "
973 : "> design inlet air dry-bulb temp if autosizing the Fluid Cooler.");
974 0 : ShowFatalError(state, "Review and revise design input values as appropriate.");
975 : }
976 25 : };
977 :
978 30 : if (this->DesignWaterFlowRateWasAutoSized) {
979 25 : if (PltSizCondNum > 0) {
980 :
981 25 : ensureSizingPlantExitTempIsNotLessThanDesignEnteringAirTemp();
982 :
983 25 : if (state.dataSize->PlantSizData(PltSizCondNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
984 20 : tmpDesignWaterFlowRate = state.dataSize->PlantSizData(PltSizCondNum).DesVolFlowRate;
985 20 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
986 5 : this->DesignWaterFlowRate = tmpDesignWaterFlowRate;
987 : }
988 : } else {
989 5 : tmpDesignWaterFlowRate = 0.0;
990 5 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
991 0 : this->DesignWaterFlowRate = tmpDesignWaterFlowRate;
992 : }
993 : }
994 25 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
995 5 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
996 10 : BaseSizer::reportSizerOutput(state,
997 5 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)],
998 : this->Name,
999 : "Design Water Flow Rate [m3/s]",
1000 : this->DesignWaterFlowRate);
1001 : }
1002 5 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
1003 0 : BaseSizer::reportSizerOutput(state,
1004 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)],
1005 : this->Name,
1006 : "Initial Design Water Flow Rate [m3/s]",
1007 : this->DesignWaterFlowRate);
1008 : }
1009 : }
1010 25 : this->DesignLeavingWaterTemp = state.dataSize->PlantSizData(PltSizCondNum).ExitTemp;
1011 : } else {
1012 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1013 0 : ShowSevereError(state, format("Autosizing error for fluid cooler object = {}", this->Name));
1014 0 : ShowFatalError(state, "Autosizing of fluid cooler condenser flow rate requires a loop Sizing:Plant object.");
1015 : }
1016 : }
1017 : }
1018 :
1019 30 : PlantUtilities::RegisterPlantCompDesignFlow(state, this->WaterInletNodeNum, tmpDesignWaterFlowRate);
1020 :
1021 30 : if (this->PerformanceInputMethod_Num == PerfInputMethod::U_FACTOR && this->HighSpeedFluidCoolerUAWasAutoSized) {
1022 0 : if (PltSizCondNum > 0) {
1023 0 : rho = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, CalledFrom);
1024 0 : Cp = state.dataPlnt->PlantLoop(this->plantLoc.loopNum)
1025 0 : .glycol->getSpecificHeat(state, state.dataSize->PlantSizData(PltSizCondNum).ExitTemp, CalledFrom);
1026 0 : DesFluidCoolerLoad = rho * Cp * tmpDesignWaterFlowRate * state.dataSize->PlantSizData(PltSizCondNum).DeltaT;
1027 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1028 0 : this->FluidCoolerNominalCapacity = DesFluidCoolerLoad;
1029 : }
1030 : } else {
1031 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1032 0 : this->FluidCoolerNominalCapacity = 0.0;
1033 : }
1034 : }
1035 : }
1036 :
1037 30 : if (this->HighSpeedFanPowerWasAutoSized) {
1038 : // We assume the nominal fan power is 0.0105 times the design load
1039 10 : if (this->PerformanceInputMethod_Num == PerfInputMethod::NOMINAL_CAPACITY) {
1040 10 : tmpHighSpeedFanPower = 0.0105 * this->FluidCoolerNominalCapacity;
1041 10 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1042 2 : this->HighSpeedFanPower = tmpHighSpeedFanPower;
1043 : }
1044 : } else {
1045 0 : if (DesFluidCoolerLoad > 0.0) {
1046 0 : tmpHighSpeedFanPower = 0.0105 * DesFluidCoolerLoad;
1047 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1048 0 : this->HighSpeedFanPower = tmpHighSpeedFanPower;
1049 : }
1050 0 : } else if (PltSizCondNum > 0) {
1051 0 : if (state.dataSize->PlantSizData(PltSizCondNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
1052 :
1053 0 : ensureSizingPlantExitTempIsNotLessThanDesignEnteringAirTemp();
1054 :
1055 0 : rho = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, CalledFrom);
1056 0 : Cp = state.dataPlnt->PlantLoop(this->plantLoc.loopNum)
1057 0 : .glycol->getSpecificHeat(state, state.dataSize->PlantSizData(PltSizCondNum).ExitTemp, CalledFrom);
1058 :
1059 0 : DesFluidCoolerLoad = rho * Cp * tmpDesignWaterFlowRate * state.dataSize->PlantSizData(PltSizCondNum).DeltaT;
1060 0 : tmpHighSpeedFanPower = 0.0105 * DesFluidCoolerLoad;
1061 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1062 0 : this->HighSpeedFanPower = tmpHighSpeedFanPower;
1063 : }
1064 : } else {
1065 0 : tmpHighSpeedFanPower = 0.0;
1066 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1067 0 : this->HighSpeedFanPower = tmpHighSpeedFanPower;
1068 : }
1069 : }
1070 : } else {
1071 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1072 0 : ShowSevereError(state, "Autosizing of fluid cooler fan power requires a loop Sizing:Plant object.");
1073 0 : ShowFatalError(state, format(" Occurs in fluid cooler object = {}", this->Name));
1074 : }
1075 : }
1076 : }
1077 10 : if (this->FluidCoolerType == DataPlant::PlantEquipmentType::FluidCooler_SingleSpd) {
1078 5 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1079 1 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1080 2 : BaseSizer::reportSizerOutput(state,
1081 1 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)],
1082 : this->Name,
1083 : "Fan Power at Design Air Flow Rate [W]",
1084 : this->HighSpeedFanPower);
1085 : }
1086 1 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
1087 0 : BaseSizer::reportSizerOutput(state,
1088 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)],
1089 : this->Name,
1090 : "Initial Fan Power at Design Air Flow Rate [W]",
1091 : this->HighSpeedFanPower);
1092 : }
1093 : }
1094 5 : } else if (this->FluidCoolerType == DataPlant::PlantEquipmentType::FluidCooler_TwoSpd) {
1095 5 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1096 1 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1097 2 : BaseSizer::reportSizerOutput(state,
1098 1 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)],
1099 : this->Name,
1100 : "Fan Power at High Fan Speed [W]",
1101 : this->HighSpeedFanPower);
1102 : }
1103 1 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
1104 0 : BaseSizer::reportSizerOutput(state,
1105 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)],
1106 : this->Name,
1107 : "Initial Fan Power at High Fan Speed [W]",
1108 : this->HighSpeedFanPower);
1109 : }
1110 : }
1111 : }
1112 : }
1113 :
1114 30 : if (this->HighSpeedAirFlowRateWasAutoSized) {
1115 25 : if (this->PerformanceInputMethod_Num == PerfInputMethod::NOMINAL_CAPACITY) {
1116 25 : tmpHighSpeedAirFlowRate = this->FluidCoolerNominalCapacity / (this->DesignEnteringWaterTemp - this->DesignEnteringAirTemp) * 4.0;
1117 25 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1118 5 : this->HighSpeedAirFlowRate = tmpHighSpeedAirFlowRate;
1119 : }
1120 : } else {
1121 0 : if (DesFluidCoolerLoad > 0.0) {
1122 0 : tmpHighSpeedAirFlowRate = DesFluidCoolerLoad / (this->DesignEnteringWaterTemp - this->DesignEnteringAirTemp) * 4.0;
1123 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1124 0 : this->HighSpeedAirFlowRate = tmpHighSpeedAirFlowRate;
1125 : }
1126 0 : } else if (PltSizCondNum > 0) {
1127 0 : if (state.dataSize->PlantSizData(PltSizCondNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
1128 :
1129 0 : ensureSizingPlantExitTempIsNotLessThanDesignEnteringAirTemp();
1130 :
1131 0 : rho = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, CalledFrom);
1132 0 : Cp = state.dataPlnt->PlantLoop(this->plantLoc.loopNum)
1133 0 : .glycol->getSpecificHeat(state, state.dataSize->PlantSizData(PltSizCondNum).ExitTemp, CalledFrom);
1134 :
1135 0 : DesFluidCoolerLoad = rho * Cp * tmpDesignWaterFlowRate * state.dataSize->PlantSizData(PltSizCondNum).DeltaT;
1136 0 : tmpHighSpeedAirFlowRate = DesFluidCoolerLoad / (this->DesignEnteringWaterTemp - this->DesignEnteringAirTemp) * 4.0;
1137 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1138 0 : this->HighSpeedAirFlowRate = tmpHighSpeedAirFlowRate;
1139 : }
1140 : } else {
1141 0 : tmpHighSpeedAirFlowRate = 0.0;
1142 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1143 0 : this->HighSpeedAirFlowRate = tmpHighSpeedAirFlowRate;
1144 : }
1145 : }
1146 : } else {
1147 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1148 0 : ShowSevereError(state, "Autosizing of fluid cooler air flow rate requires a loop Sizing:Plant object");
1149 0 : ShowFatalError(state, format(" Occurs in fluid cooler object = {}", this->Name));
1150 : }
1151 : }
1152 : }
1153 25 : if (this->FluidCoolerType == DataPlant::PlantEquipmentType::FluidCooler_SingleSpd) {
1154 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1155 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1156 0 : BaseSizer::reportSizerOutput(state,
1157 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)],
1158 : this->Name,
1159 : "Design Air Flow Rate [m3/s]",
1160 : this->HighSpeedAirFlowRate);
1161 : }
1162 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
1163 0 : BaseSizer::reportSizerOutput(state,
1164 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)],
1165 : this->Name,
1166 : "Initial Design Air Flow Rate [m3/s]",
1167 : this->HighSpeedAirFlowRate);
1168 : }
1169 : }
1170 25 : } else if (DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)] == "FluidCooler:TwoSpeed") {
1171 25 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1172 5 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1173 10 : BaseSizer::reportSizerOutput(state,
1174 5 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)],
1175 : this->Name,
1176 : "Air Flow Rate at High Fan Speed [m3/s]",
1177 : this->HighSpeedAirFlowRate);
1178 : }
1179 5 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
1180 0 : BaseSizer::reportSizerOutput(state,
1181 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)],
1182 : this->Name,
1183 : "Initial Air Flow Rate at High Fan Speed [m3/s]",
1184 : this->HighSpeedAirFlowRate);
1185 : }
1186 : }
1187 : }
1188 : }
1189 :
1190 30 : if (this->HighSpeedFluidCoolerUAWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1191 0 : if (PltSizCondNum > 0) {
1192 0 : if (state.dataSize->PlantSizData(PltSizCondNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
1193 :
1194 0 : ensureSizingPlantExitTempIsNotLessThanDesignEnteringAirTemp();
1195 :
1196 0 : rho = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, CalledFrom);
1197 0 : Cp = state.dataPlnt->PlantLoop(this->plantLoc.loopNum)
1198 0 : .glycol->getSpecificHeat(state, state.dataSize->PlantSizData(PltSizCondNum).ExitTemp, CalledFrom);
1199 :
1200 0 : DesFluidCoolerLoad = rho * Cp * tmpDesignWaterFlowRate * state.dataSize->PlantSizData(PltSizCondNum).DeltaT;
1201 0 : UA0 = 0.0001 * DesFluidCoolerLoad; // Assume deltaT = 10000K (limit)
1202 0 : UA1 = DesFluidCoolerLoad; // Assume deltaT = 1K
1203 0 : this->WaterTemp = state.dataSize->PlantSizData(PltSizCondNum).ExitTemp + state.dataSize->PlantSizData(PltSizCondNum).DeltaT;
1204 0 : this->AirTemp = this->DesignEnteringAirTemp;
1205 0 : this->AirWetBulb = this->DesignEnteringAirWetBulbTemp;
1206 0 : this->AirPress = state.dataEnvrn->StdBaroPress;
1207 0 : this->AirHumRat = Psychrometrics::PsyWFnTdbTwbPb(state, this->AirTemp, this->AirWetBulb, this->AirPress, CalledFrom);
1208 0 : auto f = [&state, this, DesFluidCoolerLoad, rho, tmpDesignWaterFlowRate, tmpHighSpeedAirFlowRate, Cp](Real64 const UA) {
1209 0 : Real64 OutWaterTemp = 0.0; // outlet water temperature [C]
1210 0 : CalcFluidCoolerOutlet(state, this->indexInArray, rho * tmpDesignWaterFlowRate, tmpHighSpeedAirFlowRate, UA, OutWaterTemp);
1211 : Real64 const Output =
1212 0 : Cp * rho * tmpDesignWaterFlowRate * (state.dataFluidCoolers->SimpleFluidCooler(this->indexInArray).WaterTemp - OutWaterTemp);
1213 0 : return (DesFluidCoolerLoad - Output) / DesFluidCoolerLoad;
1214 0 : };
1215 0 : General::SolveRoot(state, Acc, MaxIte, SolFla, UA, f, UA0, UA1);
1216 0 : if (SolFla == -1) {
1217 0 : ShowWarningError(state, "Iteration limit exceeded in calculating fluid cooler UA.");
1218 0 : ShowContinueError(state, format("Autosizing of fluid cooler UA failed for fluid cooler = {}", this->Name));
1219 0 : ShowContinueError(state, format("The final UA value ={:.2R} W/K, and the simulation continues...", UA));
1220 0 : } else if (SolFla == -2) {
1221 0 : CalcFluidCoolerOutlet(state, this->indexInArray, rho * tmpDesignWaterFlowRate, tmpHighSpeedAirFlowRate, UA0, OutWaterTempAtUA0);
1222 0 : CalcFluidCoolerOutlet(state, this->indexInArray, rho * tmpDesignWaterFlowRate, tmpHighSpeedAirFlowRate, UA1, OutWaterTempAtUA1);
1223 0 : ShowSevereError(state, format("{}: The combination of design input values did not allow the calculation of a ", CalledFrom));
1224 0 : ShowContinueError(state, "reasonable UA value. Review and revise design input values as appropriate. Specifying hard");
1225 0 : ShowContinueError(state, R"(sizes for some "autosizable" fields while autosizing other "autosizable" fields may be )");
1226 0 : ShowContinueError(state, "contributing to this problem.");
1227 0 : ShowContinueError(state, "This model iterates on UA to find the heat transfer required to provide the design outlet ");
1228 0 : ShowContinueError(state, "water temperature. Initially, the outlet water temperatures at high and low UA values are ");
1229 0 : ShowContinueError(state, "calculated. The Design Exit Water Temperature should be between the outlet water ");
1230 0 : ShowContinueError(state, "temperatures calculated at high and low UA values. If the Design Exit Water Temperature is ");
1231 0 : ShowContinueError(state, "out of this range, the solution will not converge and UA will not be calculated. ");
1232 0 : ShowContinueError(state, "The possible solutions could be to manually input adjusted water and/or air flow rates based ");
1233 0 : ShowContinueError(state, "on the autosized values shown below or to adjust design fluid cooler air inlet dry-bulb temperature.");
1234 0 : ShowContinueError(state, "Plant:Sizing object inputs also influence these results (e.g. DeltaT and ExitTemp).");
1235 0 : ShowContinueError(state, "Inputs to the fluid cooler object:");
1236 0 : ShowContinueError(state, format("Design Fluid Cooler Load [W] = {:.2R}", DesFluidCoolerLoad));
1237 0 : ShowContinueError(state, format("Design Fluid Cooler Water Volume Flow Rate [m3/s] = {:.6R}", this->DesignWaterFlowRate));
1238 0 : ShowContinueError(state, format("Design Fluid Cooler Air Volume Flow Rate [m3/s] = {:.2R}", tmpHighSpeedAirFlowRate));
1239 0 : ShowContinueError(state, format("Design Fluid Cooler Air Inlet Dry-bulb Temp [C] = {:.2R}", this->AirTemp));
1240 0 : ShowContinueError(state, "Inputs to the plant sizing object:");
1241 0 : ShowContinueError(
1242 : state,
1243 0 : format("Design Exit Water Temp [C] = {:.2R}", state.dataSize->PlantSizData(PltSizCondNum).ExitTemp));
1244 0 : ShowContinueError(
1245 : state,
1246 0 : format("Loop Design Temperature Difference [C] = {:.2R}", state.dataSize->PlantSizData(PltSizCondNum).DeltaT));
1247 0 : ShowContinueError(state, format("Design Fluid Cooler Water Inlet Temp [C] = {:.2R}", this->WaterTemp));
1248 0 : ShowContinueError(state, format("Calculated water outlet temp at low UA [C] (UA = {:.2R} W/K) = {:.2R}", UA0, OutWaterTempAtUA0));
1249 0 : ShowContinueError(state, format("Calculated water outlet temp at high UA [C](UA = {:.2R} W/K) = {:.2R}", UA1, OutWaterTempAtUA1));
1250 0 : ShowFatalError(state, format("Autosizing of Fluid Cooler UA failed for fluid cooler = {}", this->Name));
1251 : }
1252 0 : tmpHighSpeedEvapFluidCoolerUA = UA;
1253 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1254 0 : this->HighSpeedFluidCoolerUA = tmpHighSpeedEvapFluidCoolerUA;
1255 : }
1256 0 : this->FluidCoolerNominalCapacity = DesFluidCoolerLoad;
1257 : } else {
1258 0 : tmpHighSpeedEvapFluidCoolerUA = 0.0;
1259 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1260 0 : this->HighSpeedFluidCoolerUA = tmpHighSpeedEvapFluidCoolerUA;
1261 : }
1262 : }
1263 0 : if (this->FluidCoolerType == DataPlant::PlantEquipmentType::FluidCooler_SingleSpd) {
1264 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1265 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1266 0 : BaseSizer::reportSizerOutput(state,
1267 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)],
1268 : this->Name,
1269 : "U-factor Times Area Value at Design Air Flow Rate [W/K]",
1270 : this->HighSpeedFluidCoolerUA);
1271 : }
1272 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
1273 0 : BaseSizer::reportSizerOutput(state,
1274 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)],
1275 : this->Name,
1276 : "Initial U-factor Times Area Value at Design Air Flow Rate [W/K]",
1277 : this->HighSpeedFluidCoolerUA);
1278 : }
1279 : }
1280 0 : } else if (this->FluidCoolerType == DataPlant::PlantEquipmentType::FluidCooler_TwoSpd) {
1281 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1282 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1283 0 : BaseSizer::reportSizerOutput(state,
1284 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)],
1285 : this->Name,
1286 : "U-factor Times Area Value at High Fan Speed [W/K]",
1287 : this->HighSpeedFluidCoolerUA);
1288 : }
1289 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
1290 0 : BaseSizer::reportSizerOutput(state,
1291 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)],
1292 : this->Name,
1293 : "Initial U-factor Times Area Value at High Fan Speed [W/K]",
1294 : this->HighSpeedFluidCoolerUA);
1295 : }
1296 : }
1297 : }
1298 : } else {
1299 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1300 0 : ShowSevereError(state, format("Autosizing error for fluid cooler object = {}", this->Name));
1301 0 : ShowFatalError(state, "Autosizing of fluid cooler UA requires a loop Sizing:Plant object.");
1302 : }
1303 : }
1304 : }
1305 :
1306 30 : if (this->PerformanceInputMethod_Num == PerfInputMethod::NOMINAL_CAPACITY) {
1307 30 : if (this->DesignWaterFlowRate >= HVAC::SmallWaterVolFlow) {
1308 10 : rho = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, CalledFrom);
1309 10 : Cp = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).glycol->getSpecificHeat(state, this->DesignEnteringWaterTemp, CalledFrom);
1310 10 : DesFluidCoolerLoad = this->FluidCoolerNominalCapacity;
1311 10 : Real64 par2_WaterFlow = rho * tmpDesignWaterFlowRate;
1312 10 : UA0 = 0.0001 * DesFluidCoolerLoad; // Assume deltaT = 10000K (limit)
1313 10 : UA1 = DesFluidCoolerLoad; // Assume deltaT = 1K
1314 10 : this->WaterTemp = this->DesignEnteringWaterTemp; // design inlet water temperature
1315 10 : this->AirTemp = this->DesignEnteringAirTemp; // design inlet air dry-bulb temp
1316 10 : this->AirWetBulb = this->DesignEnteringAirWetBulbTemp; // design inlet air wet-bulb temp
1317 10 : this->AirPress = state.dataEnvrn->StdBaroPress;
1318 10 : this->AirHumRat = Psychrometrics::PsyWFnTdbTwbPb(state, this->AirTemp, this->AirWetBulb, this->AirPress);
1319 192 : auto f = [&state, this, DesFluidCoolerLoad, par2_WaterFlow, tmpHighSpeedAirFlowRate, Cp](Real64 const UA) {
1320 192 : Real64 OutWaterTemp = 0.0; // outlet water temperature [C]
1321 192 : CalcFluidCoolerOutlet(state, this->indexInArray, par2_WaterFlow, tmpHighSpeedAirFlowRate, UA, OutWaterTemp);
1322 192 : Real64 const Output = Cp * par2_WaterFlow * (state.dataFluidCoolers->SimpleFluidCooler(this->indexInArray).WaterTemp - OutWaterTemp);
1323 192 : return (DesFluidCoolerLoad - Output) / DesFluidCoolerLoad;
1324 10 : };
1325 10 : General::SolveRoot(state, Acc, MaxIte, SolFla, UA, f, UA0, UA1);
1326 10 : if (SolFla == -1) {
1327 0 : ShowWarningError(state, "Iteration limit exceeded in calculating fluid cooler UA.");
1328 0 : if (PltSizCondNum > 0) {
1329 0 : ShowContinueError(state, format("Autosizing of fluid cooler UA failed for fluid cooler = {}", this->Name));
1330 : }
1331 0 : ShowContinueError(state, format("The final UA value ={:.2R} W/K, and the simulation continues...", UA));
1332 10 : } else if (SolFla == -2) {
1333 0 : CalcFluidCoolerOutlet(state, this->indexInArray, rho * tmpDesignWaterFlowRate, tmpHighSpeedAirFlowRate, UA0, OutWaterTempAtUA0);
1334 0 : CalcFluidCoolerOutlet(state, this->indexInArray, rho * tmpDesignWaterFlowRate, tmpHighSpeedAirFlowRate, UA1, OutWaterTempAtUA1);
1335 0 : ShowSevereError(state, format("{}: The combination of design input values did not allow the calculation of a ", CalledFrom));
1336 0 : ShowContinueError(state, "reasonable UA value. Review and revise design input values as appropriate. Specifying hard");
1337 0 : ShowContinueError(state, R"(sizes for some "autosizable" fields while autosizing other "autosizable" fields may be )");
1338 0 : ShowContinueError(state, "contributing to this problem.");
1339 0 : ShowContinueError(state, "This model iterates on UA to find the heat transfer required to provide the design outlet ");
1340 0 : ShowContinueError(state, "water temperature. Initially, the outlet water temperatures at high and low UA values are ");
1341 0 : ShowContinueError(state, "calculated. The Design Exit Water Temperature should be between the outlet water ");
1342 0 : ShowContinueError(state, "temperatures calculated at high and low UA values. If the Design Exit Water Temperature is ");
1343 0 : ShowContinueError(state, "out of this range, the solution will not converge and UA will not be calculated. ");
1344 0 : ShowContinueError(state, "The possible solutions could be to manually input adjusted water and/or air flow rates based ");
1345 0 : ShowContinueError(state, "on the autosized values shown below or to adjust design fluid cooler air inlet dry-bulb temperature.");
1346 0 : ShowContinueError(state, "Plant:Sizing object inputs also influence these results (e.g. DeltaT and ExitTemp).");
1347 0 : ShowContinueError(state, "Inputs to the fluid cooler object:");
1348 0 : ShowContinueError(state, format("Design Fluid Cooler Load [W] = {:.2R}", DesFluidCoolerLoad));
1349 0 : ShowContinueError(state, format("Design Fluid Cooler Water Volume Flow Rate [m3/s] = {:.6R}", this->DesignWaterFlowRate));
1350 0 : ShowContinueError(state, format("Design Fluid Cooler Air Volume Flow Rate [m3/s] = {:.2R}", tmpHighSpeedAirFlowRate));
1351 0 : ShowContinueError(state, format("Design Fluid Cooler Air Inlet Dry-bulb Temp [C] = {:.2R}", this->AirTemp));
1352 0 : if (PltSizCondNum > 0) {
1353 0 : ShowContinueError(state, "Inputs to the plant sizing object:");
1354 0 : ShowContinueError(
1355 : state,
1356 0 : format("Design Exit Water Temp [C] = {:.2R}", state.dataSize->PlantSizData(PltSizCondNum).ExitTemp));
1357 0 : ShowContinueError(
1358 : state,
1359 0 : format("Loop Design Temperature Difference [C] = {:.2R}", state.dataSize->PlantSizData(PltSizCondNum).DeltaT));
1360 : }
1361 0 : ShowContinueError(state, format("Design Fluid Cooler Water Inlet Temp [C] = {:.2R}", this->WaterTemp));
1362 0 : ShowContinueError(state, format("Calculated water outlet temp at low UA [C] (UA = {:.2R} W/K) = {:.2R}", UA0, OutWaterTempAtUA0));
1363 0 : ShowContinueError(state, format("Calculated water outlet temp at high UA [C] (UA = {:.2R} W/K) = {:.2R}", UA1, OutWaterTempAtUA1));
1364 0 : if (PltSizCondNum > 0) {
1365 0 : ShowFatalError(state, format("Autosizing of Fluid Cooler UA failed for fluid cooler = {}", this->Name));
1366 : }
1367 : }
1368 10 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1369 6 : this->HighSpeedFluidCoolerUA = UA;
1370 : }
1371 : } else {
1372 20 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1373 0 : this->HighSpeedFluidCoolerUA = 0.0;
1374 : }
1375 : }
1376 30 : if (this->FluidCoolerType == DataPlant::PlantEquipmentType::FluidCooler_SingleSpd) {
1377 5 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1378 1 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1379 2 : BaseSizer::reportSizerOutput(state,
1380 1 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)],
1381 : this->Name,
1382 : "Fluid cooler UA value at design air flow rate based on nominal capacity input [W/K]",
1383 : this->HighSpeedFluidCoolerUA);
1384 : }
1385 1 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
1386 0 : BaseSizer::reportSizerOutput(state,
1387 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)],
1388 : this->Name,
1389 : "Initial Fluid cooler UA value at design air flow rate based on nominal capacity input [W/K]",
1390 : this->HighSpeedFluidCoolerUA);
1391 : }
1392 : }
1393 25 : } else if (this->FluidCoolerType == DataPlant::PlantEquipmentType::FluidCooler_TwoSpd) {
1394 25 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1395 5 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1396 10 : BaseSizer::reportSizerOutput(state,
1397 5 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)],
1398 : this->Name,
1399 : "Fluid cooler UA value at high fan speed based on nominal capacity input [W/K]",
1400 : this->HighSpeedFluidCoolerUA);
1401 : }
1402 5 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
1403 0 : BaseSizer::reportSizerOutput(state,
1404 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)],
1405 : this->Name,
1406 : "Initial Fluid cooler UA value at high fan speed based on nominal capacity input [W/K]",
1407 : this->HighSpeedFluidCoolerUA);
1408 : }
1409 : }
1410 : }
1411 : }
1412 :
1413 30 : if (this->LowSpeedAirFlowRateWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1414 5 : this->LowSpeedAirFlowRate = this->LowSpeedAirFlowRateSizingFactor * this->HighSpeedAirFlowRate;
1415 5 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1416 10 : BaseSizer::reportSizerOutput(state,
1417 5 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)],
1418 : this->Name,
1419 : "Air Flow Rate at Low Fan Speed [m3/s]",
1420 : this->LowSpeedAirFlowRate);
1421 : }
1422 5 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
1423 0 : BaseSizer::reportSizerOutput(state,
1424 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)],
1425 : this->Name,
1426 : "Initial Air Flow Rate at Low Fan Speed [m3/s]",
1427 : this->LowSpeedAirFlowRate);
1428 : }
1429 : }
1430 :
1431 30 : if (this->LowSpeedFanPowerWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1432 5 : this->LowSpeedFanPower = this->LowSpeedFanPowerSizingFactor * this->HighSpeedFanPower;
1433 5 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1434 10 : BaseSizer::reportSizerOutput(state,
1435 5 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)],
1436 : this->Name,
1437 : "Fan Power at Low Fan Speed [W]",
1438 : this->LowSpeedFanPower);
1439 : }
1440 5 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
1441 0 : BaseSizer::reportSizerOutput(state,
1442 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)],
1443 : this->Name,
1444 : "Initial Fan Power at Low Fan Speed [W]",
1445 : this->LowSpeedFanPower);
1446 : }
1447 : }
1448 :
1449 30 : if (this->LowSpeedFluidCoolerUAWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1450 0 : this->LowSpeedFluidCoolerUA = this->LowSpeedFluidCoolerUASizingFactor * this->HighSpeedFluidCoolerUA;
1451 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1452 0 : BaseSizer::reportSizerOutput(state,
1453 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)],
1454 : this->Name,
1455 : "U-factor Times Area Value at Low Fan Speed [W/K]",
1456 : this->LowSpeedFluidCoolerUA);
1457 : }
1458 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
1459 0 : BaseSizer::reportSizerOutput(state,
1460 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)],
1461 : this->Name,
1462 : "Initial U-factor Times Area Value at Low Fan Speed [W/K]",
1463 : this->LowSpeedFluidCoolerUA);
1464 : }
1465 : }
1466 :
1467 30 : if (this->PerformanceInputMethod_Num == PerfInputMethod::NOMINAL_CAPACITY &&
1468 30 : this->FluidCoolerType == DataPlant::PlantEquipmentType::FluidCooler_TwoSpd) {
1469 25 : if (this->FluidCoolerLowSpeedNomCapWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1470 0 : this->FluidCoolerLowSpeedNomCap = this->FluidCoolerLowSpeedNomCapSizingFactor * this->FluidCoolerNominalCapacity;
1471 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1472 0 : BaseSizer::reportSizerOutput(state,
1473 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)],
1474 : this->Name,
1475 : "Low Fan Speed Nominal Capacity [W]",
1476 : this->FluidCoolerLowSpeedNomCap);
1477 : }
1478 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
1479 0 : BaseSizer::reportSizerOutput(state,
1480 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)],
1481 : this->Name,
1482 : "Initial Low Fan Speed Nominal Capacity [W]",
1483 : this->FluidCoolerLowSpeedNomCap);
1484 : }
1485 : }
1486 :
1487 25 : if (this->DesignWaterFlowRate >= HVAC::SmallWaterVolFlow && this->FluidCoolerLowSpeedNomCap > 0.0) {
1488 5 : rho = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, CalledFrom);
1489 5 : Cp = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).glycol->getSpecificHeat(state, this->DesignEnteringWaterTemp, CalledFrom);
1490 5 : DesFluidCoolerLoad = this->FluidCoolerLowSpeedNomCap;
1491 5 : UA0 = 0.0001 * DesFluidCoolerLoad; // Assume deltaT = 10000K (limit)
1492 5 : UA1 = DesFluidCoolerLoad; // Assume deltaT = 1K
1493 5 : this->WaterTemp = this->DesignEnteringWaterTemp; // design inlet water temperature
1494 5 : this->AirTemp = this->DesignEnteringAirTemp; // design inlet air dry-bulb temp
1495 5 : this->AirWetBulb = this->DesignEnteringAirWetBulbTemp; // design inlet air wet-bulb temp
1496 5 : this->AirPress = state.dataEnvrn->StdBaroPress;
1497 5 : this->AirHumRat = Psychrometrics::PsyWFnTdbTwbPb(state, this->AirTemp, this->AirWetBulb, this->AirPress, CalledFrom);
1498 46 : auto f = [&state, this, DesFluidCoolerLoad, rho, tmpDesignWaterFlowRate, Cp](Real64 const UA) {
1499 46 : Real64 OutWaterTemp = 0.0; // outlet water temperature [C]
1500 46 : CalcFluidCoolerOutlet(state, this->indexInArray, rho * tmpDesignWaterFlowRate, this->LowSpeedAirFlowRate, UA, OutWaterTemp);
1501 : Real64 const Output =
1502 46 : Cp * rho * tmpDesignWaterFlowRate * (state.dataFluidCoolers->SimpleFluidCooler(this->indexInArray).WaterTemp - OutWaterTemp);
1503 46 : return (DesFluidCoolerLoad - Output) / DesFluidCoolerLoad;
1504 5 : };
1505 5 : General::SolveRoot(state, Acc, MaxIte, SolFla, UA, f, UA0, UA1);
1506 5 : if (SolFla == -1) {
1507 0 : ShowWarningError(state, "Iteration limit exceeded in calculating fluid cooler UA.");
1508 0 : ShowContinueError(state, format("Autosizing of fluid cooler UA failed for fluid cooler = {}", this->Name));
1509 0 : ShowContinueError(state, format("The final UA value at low fan speed ={:.2R} W/C, and the simulation continues...", UA));
1510 5 : } else if (SolFla == -2) {
1511 0 : CalcFluidCoolerOutlet(state, this->indexInArray, rho * tmpDesignWaterFlowRate, this->LowSpeedAirFlowRate, UA0, OutWaterTempAtUA0);
1512 0 : CalcFluidCoolerOutlet(state, this->indexInArray, rho * tmpDesignWaterFlowRate, this->LowSpeedAirFlowRate, UA1, OutWaterTempAtUA1);
1513 0 : ShowSevereError(state, format("{}: The combination of design input values did not allow the calculation of a ", CalledFrom));
1514 0 : ShowContinueError(state, "reasonable low-speed UA value. Review and revise design input values as appropriate. ");
1515 0 : ShowContinueError(state, R"(Specifying hard sizes for some "autosizable" fields while autosizing other "autosizable" )");
1516 0 : ShowContinueError(state, "fields may be contributing to this problem.");
1517 0 : ShowContinueError(state, "This model iterates on UA to find the heat transfer required to provide the design outlet ");
1518 0 : ShowContinueError(state, "water temperature. Initially, the outlet water temperatures at high and low UA values are ");
1519 0 : ShowContinueError(state, "calculated. The Design Exit Water Temperature should be between the outlet water ");
1520 0 : ShowContinueError(state, "temperatures calculated at high and low UA values. If the Design Exit Water Temperature is ");
1521 0 : ShowContinueError(state, "out of this range, the solution will not converge and UA will not be calculated. ");
1522 0 : ShowContinueError(state, "The possible solutions could be to manually input adjusted water and/or air flow rates based ");
1523 0 : ShowContinueError(state, "on the autosized values shown below or to adjust design fluid cooler air inlet dry-bulb temperature.");
1524 0 : ShowContinueError(state, "Plant:Sizing object inputs also influence these results (e.g. DeltaT and ExitTemp).");
1525 0 : ShowContinueError(state, "Inputs to the fluid cooler object:");
1526 0 : ShowContinueError(state, format("Design Fluid Cooler Load [W] = {:.2R}", DesFluidCoolerLoad));
1527 0 : ShowContinueError(state, format("Design Fluid Cooler Water Volume Flow Rate [m3/s] = {:.6R}", this->DesignWaterFlowRate));
1528 0 : ShowContinueError(state, format("Design Fluid Cooler Air Volume Flow Rate [m3/s] = {:.2R}", this->LowSpeedAirFlowRate));
1529 0 : ShowContinueError(state, format("Design Fluid Cooler Air Inlet Dry-bulb Temp [C] = {:.2R}", this->AirTemp));
1530 0 : ShowContinueError(state, "Inputs to the plant sizing object:");
1531 0 : ShowContinueError(
1532 : state,
1533 0 : format("Design Exit Water Temp [C] = {:.2R}", state.dataSize->PlantSizData(PltSizCondNum).ExitTemp));
1534 0 : ShowContinueError(
1535 : state,
1536 0 : format("Loop Design Temperature Difference [C] = {:.2R}", state.dataSize->PlantSizData(PltSizCondNum).DeltaT));
1537 0 : ShowContinueError(state, format("Design Fluid Cooler Water Inlet Temp [C] = {:.2R}", this->WaterTemp));
1538 0 : ShowContinueError(state, format("Calculated water outlet temp at low UA [C](UA = {:.2R} W/C) = {:.2R}", UA0, OutWaterTempAtUA0));
1539 0 : ShowContinueError(state, format("Calculated water outlet temp at high UA [C](UA = {:.2R} W/C) = {:.2R}", UA1, OutWaterTempAtUA1));
1540 0 : ShowFatalError(state, format("Autosizing of Fluid Cooler UA failed for fluid cooler = {}", this->Name));
1541 : }
1542 5 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1543 5 : this->LowSpeedFluidCoolerUA = UA;
1544 : }
1545 5 : } else {
1546 20 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1547 0 : this->LowSpeedFluidCoolerUA = 0.0;
1548 : }
1549 : }
1550 25 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1551 5 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1552 10 : BaseSizer::reportSizerOutput(state,
1553 5 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)],
1554 : this->Name,
1555 : "U-factor Times Area Value at Low Fan Speed [W/C]",
1556 : this->LowSpeedFluidCoolerUA);
1557 : }
1558 5 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
1559 0 : BaseSizer::reportSizerOutput(state,
1560 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)],
1561 : this->Name,
1562 : "Initial U-factor Times Area Value at Low Fan Speed [W/C]",
1563 : this->LowSpeedFluidCoolerUA);
1564 : }
1565 : }
1566 : }
1567 :
1568 30 : ErrorsFound = false;
1569 :
1570 30 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1571 :
1572 6 : if (this->DesignLeavingWaterTemp <= HVAC::SmallTempDiff) {
1573 1 : this->WaterTemp = this->DesignEnteringWaterTemp; // design inlet water temperature
1574 1 : this->AirTemp = this->DesignEnteringAirTemp; // design inlet air dry-bulb temp
1575 1 : this->AirWetBulb = this->DesignEnteringAirWetBulbTemp; // design inlet air wet-bulb temp
1576 1 : this->AirPress = state.dataEnvrn->StdBaroPress;
1577 1 : this->AirHumRat = Psychrometrics::PsyWFnTdbTwbPb(state, this->AirTemp, this->AirWetBulb, this->AirPress);
1578 1 : Real64 OutletTemp = 0;
1579 1 : rho = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, CalledFrom);
1580 1 : CalcFluidCoolerOutlet(
1581 1 : state, this->indexInArray, rho * this->DesignWaterFlowRate, this->HighSpeedAirFlowRate, this->HighSpeedFluidCoolerUA, OutletTemp);
1582 1 : this->DesignLeavingWaterTemp = OutletTemp;
1583 : }
1584 :
1585 : // create predefined report
1586 12 : OutputReportPredefined::PreDefTableEntry(
1587 12 : state, state.dataOutRptPredefined->pdchMechType, this->Name, DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)]);
1588 6 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchMechNomCap, this->Name, this->FluidCoolerNominalCapacity);
1589 :
1590 : // create std 229 new table for cooling towers and fluid coolers
1591 12 : OutputReportPredefined::PreDefTableEntry(
1592 12 : state, state.dataOutRptPredefined->pdchCTFCType, this->Name, DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)]);
1593 12 : OutputReportPredefined::PreDefTableEntry(state,
1594 6 : state.dataOutRptPredefined->pdchCTFCCondLoopName,
1595 : this->Name,
1596 12 : this->plantLoc.loopNum > 0 ? state.dataPlnt->PlantLoop(this->plantLoc.loopNum).Name : "N/A");
1597 12 : OutputReportPredefined::PreDefTableEntry(
1598 : state,
1599 6 : state.dataOutRptPredefined->pdchCTFCCondLoopBranchName,
1600 : this->Name,
1601 12 : this->plantLoc.loopNum > 0 ? state.dataPlnt->PlantLoop(plantLoc.loopNum).LoopSide(plantLoc.loopSideNum).Branch(plantLoc.branchNum).Name
1602 : : "N/A");
1603 12 : OutputReportPredefined::PreDefTableEntry(
1604 : state,
1605 6 : state.dataOutRptPredefined->pdchCTFCFluidType,
1606 : this->Name,
1607 6 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName); // Fluid Name more reasonable than FluidType
1608 12 : OutputReportPredefined::PreDefTableEntry(
1609 6 : state, state.dataOutRptPredefined->pdchCTFCRange, this->Name, this->DesignEnteringWaterTemp - this->DesignLeavingWaterTemp);
1610 12 : OutputReportPredefined::PreDefTableEntry(
1611 6 : state, state.dataOutRptPredefined->pdchCTFCApproach, this->Name, this->DesignLeavingWaterTemp - this->DesignEnteringAirWetBulbTemp);
1612 12 : OutputReportPredefined::PreDefTableEntry(
1613 6 : state, state.dataOutRptPredefined->pdchCTFCDesFanPwr, this->Name, this->HighSpeedFanPower); // equivalent to Design Fan Power?
1614 12 : OutputReportPredefined::PreDefTableEntry(
1615 6 : state, state.dataOutRptPredefined->pdchCTFCDesInletAirWBT, this->Name, this->DesignEnteringAirWetBulbTemp);
1616 12 : OutputReportPredefined::PreDefTableEntry(
1617 12 : state, state.dataOutRptPredefined->pdchCTFCDesWaterFlowRate, this->Name, this->DesignWaterFlowRate, 6);
1618 6 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchCTFCLevWaterSPTemp, this->Name, this->DesignLeavingWaterTemp);
1619 : }
1620 :
1621 30 : if (this->FluidCoolerType == DataPlant::PlantEquipmentType::FluidCooler_TwoSpd && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1622 5 : if (this->DesignWaterFlowRate > 0.0) {
1623 5 : if (this->HighSpeedAirFlowRate <= this->LowSpeedAirFlowRate) {
1624 0 : ShowSevereError(
1625 0 : state, format("FluidCooler:TwoSpeed \"{}\". Low speed air flow rate must be less than high speed air flow rate.", this->Name));
1626 0 : ErrorsFound = true;
1627 : }
1628 5 : if (this->HighSpeedFluidCoolerUA <= this->LowSpeedFluidCoolerUA) {
1629 0 : ShowSevereError(
1630 : state,
1631 0 : format("FluidCooler:TwoSpeed \"{}\". Fluid cooler UA at low fan speed must be less than the fluid cooler UA at high fan speed.",
1632 0 : this->Name));
1633 0 : ErrorsFound = true;
1634 : }
1635 : }
1636 : }
1637 :
1638 30 : if (ErrorsFound) {
1639 0 : ShowFatalError(state, "SizeFluidCooler: Program terminated due to previous condition(s).");
1640 : }
1641 30 : }
1642 :
1643 22981 : void FluidCoolerspecs::calcSingleSpeed(EnergyPlusData &state)
1644 : {
1645 :
1646 : // SUBROUTINE INFORMATION:
1647 : // AUTHOR Chandan Sharma
1648 : // DATE WRITTEN August 2008
1649 : // MODIFIED Dec. 2008. BG. added RunFlag logic per original methodology
1650 :
1651 : // PURPOSE OF THIS SUBROUTINE:
1652 : // To simulate the operation of a single-speed fan fluid cooler.
1653 :
1654 : // METHODOLOGY EMPLOYED:
1655 : // The fluid cooler is modeled using effectiveness-NTU relationships for
1656 : // cross flow heat exchangers (both stream unmixed)based on cooling tower model.
1657 : // The subroutine calculates the period of time required to meet a
1658 : // leaving water temperature setpoint. It assumes that part-load
1659 : // operation represents a linear interpolation of two steady-state regimes.
1660 : // Cyclic losses are neglected. The period of time required to meet the
1661 : // leaving water temperature setpoint is used to determine the required
1662 : // fan power and energy.
1663 : // A RunFlag is passed by the upper level manager to indicate the ON/OFF status,
1664 : // or schedule, of the fluid cooler. If the fluid cooler is OFF, outlet water
1665 : // temperature and flow rate are passed through the model from inlet node to
1666 : // outlet node without intervention. Reports are also updated with fan power
1667 : // and energy being zero.
1668 : // When the RunFlag indicates an ON condition for thefluid cooler, the
1669 : // mass flow rate and water temperature are read from the inlet node of the
1670 : // fluid cooler (water-side). The outdoor air dry-bulb temperature is used
1671 : // as the entering condition to thefluid cooler (air-side).Thefluid cooler
1672 : // fan is turned on and design parameters are used to calculate the leaving
1673 : // water temperature.If the calculated leaving water temperature is below the setpoint,
1674 : // a fan run-time fraction is calculated and used to determine fan power. The leaving
1675 : // water temperature setpoint is placed on the outlet node. If the calculated
1676 : // leaving water temperature is at or above the setpoint, the calculated
1677 : // leaving water temperature is placed on the outlet node and the fan runs at
1678 : // full power. Water mass flow rate is passed from inlet node to outlet node
1679 : // with no intervention.
1680 :
1681 : // REFERENCES:
1682 : // ASHRAE HVAC1KIT: A Toolkit for Primary HVAC System Energy Calculation. 1999.
1683 : // Based on SingleSpeedTower subroutine by Dan Fisher ,Sept 1998.
1684 :
1685 : // SUBROUTINE PARAMETER DEFINITIONS:
1686 : static constexpr std::string_view RoutineName("SingleSpeedFluidCooler");
1687 :
1688 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1689 22981 : Real64 TempSetPoint = 0.0;
1690 :
1691 : // set inlet and outlet nodes
1692 22981 : this->Qactual = 0.0;
1693 22981 : this->FanPower = 0.0;
1694 22981 : this->OutletWaterTemp = state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp;
1695 22981 : switch (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopDemandCalcScheme) {
1696 22981 : case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
1697 22981 : TempSetPoint = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopSide(this->plantLoc.loopSideNum).TempSetPoint;
1698 22981 : } break;
1699 0 : case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
1700 0 : TempSetPoint = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopSide(this->plantLoc.loopSideNum).TempSetPointHi;
1701 0 : } break;
1702 0 : default:
1703 0 : break;
1704 : }
1705 :
1706 : // MassFlowTol is a parameter to indicate a no flow condition
1707 22981 : if (this->WaterMassFlowRate <= DataBranchAirLoopPlant::MassFlowTolerance) {
1708 18021 : return;
1709 : }
1710 :
1711 4960 : if (this->OutletWaterTemp < TempSetPoint) { // already there don't need to run the cooler
1712 0 : return;
1713 : }
1714 :
1715 : // Initialize local variables
1716 4960 : Real64 OutletWaterTempOFF = state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp;
1717 4960 : this->OutletWaterTemp = OutletWaterTempOFF;
1718 :
1719 4960 : Real64 UAdesign = this->HighSpeedFluidCoolerUA;
1720 4960 : Real64 AirFlowRate = this->HighSpeedAirFlowRate;
1721 4960 : Real64 FanPowerOn = this->HighSpeedFanPower;
1722 :
1723 4960 : CalcFluidCoolerOutlet(state, this->indexInArray, this->WaterMassFlowRate, AirFlowRate, UAdesign, this->OutletWaterTemp);
1724 :
1725 4960 : if (this->OutletWaterTemp <= TempSetPoint) {
1726 : // Setpoint was met with pump ON and fan ON, calculate run-time fraction or just wasn't needed at all
1727 0 : Real64 FanModeFrac = 0.0;
1728 0 : if (this->OutletWaterTemp != OutletWaterTempOFF) { // don't divide by zero
1729 0 : FanModeFrac = (TempSetPoint - OutletWaterTempOFF) / (this->OutletWaterTemp - OutletWaterTempOFF);
1730 : }
1731 0 : this->FanPower = max(FanModeFrac * FanPowerOn, 0.0); // BG change
1732 0 : this->OutletWaterTemp = TempSetPoint;
1733 : } else {
1734 : // Setpoint was not met, fluid cooler ran at full capacity
1735 4960 : this->FanPower = FanPowerOn;
1736 : }
1737 4960 : Real64 CpWater = state.dataPlnt->PlantLoop(this->plantLoc.loopNum)
1738 4960 : .glycol->getSpecificHeat(state, state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp, RoutineName);
1739 4960 : this->Qactual = this->WaterMassFlowRate * CpWater * (state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp - this->OutletWaterTemp);
1740 : }
1741 :
1742 125326 : void FluidCoolerspecs::calcTwoSpeed(EnergyPlusData &state)
1743 : {
1744 :
1745 : // SUBROUTINE INFORMATION:
1746 : // AUTHOR Chandan Sharma
1747 : // DATE WRITTEN August 2008
1748 : // MODIFIED Dec. 2008. BG. added RunFlag logic per original methodology
1749 :
1750 : // PURPOSE OF THIS SUBROUTINE:
1751 : // To simulate the operation of a fluid cooler with a two-speed fan.
1752 :
1753 : // METHODOLOGY EMPLOYED:
1754 : // The fluid cooler is modeled using effectiveness-NTU relationships for
1755 : // cross flow heat exchangers (both stream unmixed)based on cooling tower model.
1756 : // The subroutine calculates the period of time required to meet a
1757 : // leaving water temperature setpoint. It assumes that part-load
1758 : // operation represents a linear interpolation of two steady-state regimes
1759 : // (high-speed fan operation and low-speed fan operation).
1760 : // Cyclic losses are neglected. The period of time required to meet the
1761 : // leaving water temperature setpoint is used to determine the required
1762 : // fan power and energy.
1763 : // A RunFlag is passed by the upper level manager to indicate the ON/OFF status,
1764 : // or schedule, of the fluid cooler. If the fluid cooler is OFF, outlet water
1765 : // temperature and flow rate are passed through the model from inlet node to
1766 : // outlet node without intervention.Reports are also updated with fan power
1767 : // and fan energy being zero.
1768 : // When the RunFlag indicates an ON condition for the fluid cooler, the
1769 : // mass flow rate and water temperature are read from the inlet node of the
1770 : // fluid cooler (water-side). The outdoor air dry-bulb temperature is used
1771 : // as the entering condition to the fluid cooler (air-side). Input deck
1772 : // parameters are read for the low fan speed and a leaving water temperature
1773 : // is calculated.
1774 : // If the calculated leaving water temperature is below the setpoint,
1775 : // a fan run-time fraction (FanModeFrac) is calculated and used to determine fan power.
1776 : // The leaving water temperature setpoint is placed on the outlet node.
1777 : // If the calculated leaving water temperature is at or above
1778 : // the setpoint, the fluid cooler fan is turned on 'high speed' and the routine is
1779 : // repeated. If the calculated leaving water temperature is below the setpoint,
1780 : // a fan run-time fraction is calculated for the second stage fan and fan power
1781 : // is calculated as FanModeFrac*HighSpeedFanPower+(1-FanModeFrac)*LowSpeedFanPower.
1782 : // If the calculated leaving water temperature is above the leaving water temp.
1783 : // setpoint, the calculated leaving water temperature is placed on the outlet
1784 : // node and the fan runs at full power (High Speed Fan Power). Water mass flow
1785 : // rate is passed from inlet node to outlet node with no intervention.
1786 :
1787 : // REFERENCES:
1788 : // ASHRAE HVAC1KIT: A Toolkit for Primary HVAC System Energy Calculation. 1999.
1789 : // Based on TwoSpeedTower by Dan Fisher ,Sept. 1998.
1790 :
1791 : // SUBROUTINE PARAMETER DEFINITIONS:
1792 : static constexpr std::string_view RoutineName("TwoSpeedFluidCooler");
1793 :
1794 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1795 125326 : Real64 TempSetPoint = 0.0;
1796 :
1797 125326 : this->Qactual = 0.0;
1798 125326 : this->FanPower = 0.0;
1799 125326 : this->OutletWaterTemp = state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp;
1800 125326 : switch (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopDemandCalcScheme) {
1801 22982 : case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
1802 22982 : TempSetPoint = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopSide(this->plantLoc.loopSideNum).TempSetPoint;
1803 22982 : } break;
1804 102344 : case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
1805 102344 : TempSetPoint = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopSide(this->plantLoc.loopSideNum).TempSetPointHi;
1806 102344 : } break;
1807 0 : default:
1808 0 : break;
1809 : }
1810 :
1811 : // MassFlowTol is a parameter to indicate a no flow condition
1812 232302 : if (this->WaterMassFlowRate <= DataBranchAirLoopPlant::MassFlowTolerance ||
1813 106976 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopSide(this->plantLoc.loopSideNum).FlowLock == DataPlant::FlowLock::Unlocked) {
1814 71838 : return;
1815 : }
1816 :
1817 : // set local variable for fluid cooler
1818 53488 : this->WaterMassFlowRate = state.dataLoopNodes->Node(this->WaterInletNodeNum).MassFlowRate;
1819 53488 : Real64 OutletWaterTempOFF = state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp;
1820 53488 : Real64 OutletWaterTemp1stStage = OutletWaterTempOFF;
1821 53488 : Real64 OutletWaterTemp2ndStage = OutletWaterTempOFF;
1822 53488 : Real64 FanModeFrac = 0.0;
1823 :
1824 53488 : if (OutletWaterTempOFF < TempSetPoint) { // already there don't need to run the cooler
1825 0 : return;
1826 : }
1827 :
1828 53488 : Real64 UAdesign = this->LowSpeedFluidCoolerUA;
1829 53488 : Real64 AirFlowRate = this->LowSpeedAirFlowRate;
1830 53488 : Real64 FanPowerLow = this->LowSpeedFanPower;
1831 :
1832 53488 : CalcFluidCoolerOutlet(state, this->indexInArray, this->WaterMassFlowRate, AirFlowRate, UAdesign, OutletWaterTemp1stStage);
1833 :
1834 53488 : if (OutletWaterTemp1stStage <= TempSetPoint) {
1835 : // Setpoint was met with pump ON and fan ON 1st stage, calculate fan mode fraction
1836 27760 : if (OutletWaterTemp1stStage != OutletWaterTempOFF) { // don't divide by zero
1837 27760 : FanModeFrac = (TempSetPoint - OutletWaterTempOFF) / (OutletWaterTemp1stStage - OutletWaterTempOFF);
1838 : }
1839 27760 : this->FanPower = FanModeFrac * FanPowerLow;
1840 27760 : this->OutletWaterTemp = TempSetPoint;
1841 27760 : this->Qactual *= FanModeFrac;
1842 : } else {
1843 : // Setpoint was not met, turn on fluid cooler 2nd stage fan
1844 25728 : UAdesign = this->HighSpeedFluidCoolerUA;
1845 25728 : AirFlowRate = this->HighSpeedAirFlowRate;
1846 25728 : Real64 FanPowerHigh = this->HighSpeedFanPower;
1847 :
1848 25728 : CalcFluidCoolerOutlet(state, this->indexInArray, this->WaterMassFlowRate, AirFlowRate, UAdesign, OutletWaterTemp2ndStage);
1849 :
1850 25728 : if ((OutletWaterTemp2ndStage <= TempSetPoint) && UAdesign > 0.0) {
1851 : // Setpoint was met with pump ON and fan ON 2nd stage, calculate fan mode fraction
1852 52 : FanModeFrac = (TempSetPoint - OutletWaterTemp1stStage) / (OutletWaterTemp2ndStage - OutletWaterTemp1stStage);
1853 52 : this->FanPower = max((FanModeFrac * FanPowerHigh) + (1.0 - FanModeFrac) * FanPowerLow, 0.0);
1854 52 : this->OutletWaterTemp = TempSetPoint;
1855 : } else {
1856 : // Setpoint was not met, fluid cooler ran at full capacity
1857 25676 : this->OutletWaterTemp = OutletWaterTemp2ndStage;
1858 25676 : this->FanPower = FanPowerHigh;
1859 : }
1860 : }
1861 53488 : Real64 CpWater = state.dataPlnt->PlantLoop(this->plantLoc.loopNum)
1862 53488 : .glycol->getSpecificHeat(state, state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp, RoutineName);
1863 53488 : this->Qactual = this->WaterMassFlowRate * CpWater * (state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp - this->OutletWaterTemp);
1864 : }
1865 :
1866 84415 : void CalcFluidCoolerOutlet(
1867 : EnergyPlusData &state, int FluidCoolerNum, Real64 _WaterMassFlowRate, Real64 AirFlowRate, Real64 UAdesign, Real64 &_OutletWaterTemp)
1868 : {
1869 :
1870 : // SUBROUTINE INFORMATION:
1871 : // AUTHOR Chandan Sharma
1872 : // DATE WRITTEN August 2008
1873 : // MODIFIED April 2010, Chandan Sharma, FSEC
1874 :
1875 : // PURPOSE OF THIS SUBROUTINE:
1876 : // See purpose for Single Speed or Two Speed Fluid Cooler model
1877 :
1878 : // METHODOLOGY EMPLOYED:
1879 : // See methodology for Single Speed or Two Speed Fluid Cooler model
1880 :
1881 : // Locals
1882 : Real64 _Qactual; // Actual heat transfer rate between fluid cooler water and air [W]
1883 :
1884 : // SUBROUTINE PARAMETER DEFINITIONS:
1885 : static constexpr std::string_view RoutineName("CalcFluidCoolerOutlet");
1886 :
1887 84415 : if (UAdesign == 0.0) {
1888 0 : return;
1889 : }
1890 :
1891 84415 : auto &fluidCooler = state.dataFluidCoolers->SimpleFluidCooler(FluidCoolerNum);
1892 : // set local fluid cooler inlet and outlet temperature variables
1893 84415 : Real64 _InletWaterTemp = fluidCooler.WaterTemp;
1894 84415 : _OutletWaterTemp = _InletWaterTemp;
1895 84415 : Real64 InletAirTemp = fluidCooler.AirTemp;
1896 :
1897 : // set water and air properties
1898 84415 : Real64 AirDensity = Psychrometrics::PsyRhoAirFnPbTdbW(state, fluidCooler.AirPress, InletAirTemp, fluidCooler.AirHumRat);
1899 84415 : Real64 AirMassFlowRate = AirFlowRate * AirDensity;
1900 84415 : Real64 CpAir = Psychrometrics::PsyCpAirFnW(fluidCooler.AirHumRat);
1901 84415 : Real64 CpWater = state.dataPlnt->PlantLoop(fluidCooler.plantLoc.loopNum).glycol->getSpecificHeat(state, _InletWaterTemp, RoutineName);
1902 :
1903 : // Calculate mass flow rates
1904 84415 : Real64 MdotCpWater = _WaterMassFlowRate * CpWater;
1905 84415 : Real64 AirCapacity = AirMassFlowRate * CpAir;
1906 :
1907 : // calculate the minimum to maximum capacity ratios of airside and waterside
1908 84415 : Real64 CapacityRatioMin = min(AirCapacity, MdotCpWater);
1909 84415 : Real64 CapacityRatioMax = max(AirCapacity, MdotCpWater);
1910 84415 : Real64 CapacityRatio = CapacityRatioMin / CapacityRatioMax;
1911 :
1912 : // Calculate number of transfer units (NTU)
1913 84415 : Real64 NumTransferUnits = UAdesign / CapacityRatioMin;
1914 84415 : Real64 ETA = std::pow(NumTransferUnits, 0.22);
1915 84415 : Real64 A = CapacityRatio * NumTransferUnits / ETA;
1916 84415 : Real64 effectiveness = 1.0 - std::exp(std::expm1(-A) / (CapacityRatio / ETA));
1917 :
1918 : // calculate water to air heat transfer
1919 84415 : _Qactual = effectiveness * CapacityRatioMin * (_InletWaterTemp - InletAirTemp);
1920 :
1921 84415 : if (_Qactual >= 0.0) {
1922 84415 : _OutletWaterTemp = _InletWaterTemp - _Qactual / MdotCpWater;
1923 : } else {
1924 0 : _OutletWaterTemp = _InletWaterTemp;
1925 : }
1926 : }
1927 :
1928 148307 : void FluidCoolerspecs::update(EnergyPlusData &state)
1929 : {
1930 :
1931 : // SUBROUTINE INFORMATION:
1932 : // AUTHOR: Chandan Sharma
1933 : // DATE WRITTEN: August 2008
1934 :
1935 : // PURPOSE OF THIS SUBROUTINE:
1936 : // This subroutine is for passing results to the outlet water node.
1937 :
1938 148307 : int waterOutletNode = this->WaterOutletNodeNum;
1939 148307 : state.dataLoopNodes->Node(waterOutletNode).Temp = this->OutletWaterTemp;
1940 :
1941 222443 : if (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopSide(this->plantLoc.loopSideNum).FlowLock == DataPlant::FlowLock::Unlocked ||
1942 74136 : state.dataGlobal->WarmupFlag) {
1943 138915 : return;
1944 : }
1945 :
1946 : // Check flow rate through fluid cooler and compare to design flow rate, show warning if greater than Design * Multiplier
1947 9392 : if (state.dataLoopNodes->Node(waterOutletNode).MassFlowRate > this->DesWaterMassFlowRate * this->FluidCoolerMassFlowRateMultiplier) {
1948 0 : ++this->HighMassFlowErrorCount;
1949 0 : if (this->HighMassFlowErrorCount < 2) {
1950 0 : ShowWarningError(state, format("{} \"{}\"", DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)], this->Name));
1951 0 : ShowContinueError(state, " Condenser Loop Mass Flow Rate is much greater than the fluid coolers design mass flow rate.");
1952 0 : ShowContinueError(state, format(" Condenser Loop Mass Flow Rate = {:.6T}", state.dataLoopNodes->Node(waterOutletNode).MassFlowRate));
1953 0 : ShowContinueError(state, format(" Fluid Cooler Design Mass Flow Rate = {:.6T}", this->DesWaterMassFlowRate));
1954 0 : ShowContinueErrorTimeStamp(state, "");
1955 : } else {
1956 0 : ShowRecurringWarningErrorAtEnd(
1957 : state,
1958 0 : format("{} \"{}\" Condenser Loop Mass Flow Rate is much greater than the fluid coolers design mass flow rate. Error continues...",
1959 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)],
1960 0 : this->Name),
1961 0 : this->HighMassFlowErrorIndex,
1962 0 : state.dataLoopNodes->Node(waterOutletNode).MassFlowRate,
1963 0 : state.dataLoopNodes->Node(waterOutletNode).MassFlowRate);
1964 : }
1965 : }
1966 :
1967 : // Check if OutletWaterTemp is below the minimum condenser loop temp and warn user
1968 9392 : Real64 LoopMinTemp = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).MinTemp;
1969 9392 : if ((this->OutletWaterTemp < LoopMinTemp) && (this->WaterMassFlowRate > 0.0)) {
1970 0 : ++this->OutletWaterTempErrorCount;
1971 :
1972 0 : if (this->OutletWaterTempErrorCount < 2) {
1973 0 : ShowWarningError(state, format("{} \"{}\"", DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)], this->Name));
1974 0 : ShowContinueError(
1975 : state,
1976 0 : format(" Fluid cooler water outlet temperature ({:.2F} C) is below the specified minimum condenser loop temp of {:.2F} C",
1977 0 : this->OutletWaterTemp,
1978 : LoopMinTemp));
1979 0 : ShowContinueErrorTimeStamp(state, "");
1980 : } else {
1981 0 : ShowRecurringWarningErrorAtEnd(
1982 : state,
1983 0 : format("{} \"{}\" Fluid cooler water outlet temperature is below the specified minimum condenser loop temp. Error continues...",
1984 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)],
1985 0 : this->Name),
1986 0 : this->OutletWaterTempErrorIndex,
1987 0 : this->OutletWaterTemp,
1988 0 : this->OutletWaterTemp);
1989 : }
1990 : }
1991 :
1992 : // Check if water mass flow rate is small (e.g. no flow) and warn user
1993 9392 : if (this->WaterMassFlowRate > 0.0 && this->WaterMassFlowRate <= DataBranchAirLoopPlant::MassFlowTolerance) {
1994 0 : ++this->SmallWaterMassFlowErrorCount;
1995 0 : if (this->SmallWaterMassFlowErrorCount < 2) {
1996 0 : ShowWarningError(state, format("{} \"{}\"", DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)], this->Name));
1997 0 : ShowContinueError(state, " Fluid cooler water mass flow rate near zero.");
1998 0 : ShowContinueErrorTimeStamp(state, "");
1999 0 : ShowContinueError(state, format("Actual Mass flow = {:.2T}", this->WaterMassFlowRate));
2000 : } else {
2001 0 : ShowRecurringWarningErrorAtEnd(state,
2002 0 : format("{} \"{}\" Fluid cooler water mass flow rate is near zero. Error continues...",
2003 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(this->FluidCoolerType)],
2004 0 : this->Name),
2005 0 : this->SmallWaterMassFlowErrorIndex,
2006 0 : this->WaterMassFlowRate,
2007 0 : this->WaterMassFlowRate);
2008 : }
2009 : }
2010 : }
2011 :
2012 148307 : void FluidCoolerspecs::report(EnergyPlusData &state, bool const RunFlag)
2013 : {
2014 :
2015 : // SUBROUTINE INFORMATION:
2016 : // AUTHOR: Chandan Sharma
2017 : // DATE WRITTEN: August 2008
2018 :
2019 : // PURPOSE OF THIS SUBROUTINE:
2020 : // This subroutine updates the report variables for the fluid cooler.
2021 :
2022 148307 : Real64 ReportingConstant = state.dataHVACGlobal->TimeStepSysSec;
2023 148307 : if (!RunFlag) {
2024 36371 : this->InletWaterTemp = state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp;
2025 36371 : this->OutletWaterTemp = state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp;
2026 36371 : this->Qactual = 0.0;
2027 36371 : this->FanPower = 0.0;
2028 36371 : this->FanEnergy = 0.0;
2029 : } else {
2030 111936 : this->InletWaterTemp = state.dataLoopNodes->Node(this->WaterInletNodeNum).Temp;
2031 111936 : this->FanEnergy = this->FanPower * ReportingConstant;
2032 : }
2033 148307 : }
2034 0 : void FluidCoolerspecs::oneTimeInit([[maybe_unused]] EnergyPlusData &state)
2035 : {
2036 0 : }
2037 :
2038 : } // namespace EnergyPlus::FluidCoolers
|