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