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