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