Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // C++ Headers
49 : #include <cmath>
50 :
51 : // ObjexxFCL Headers
52 : #include <ObjexxFCL/Array.functions.hh>
53 :
54 : // EnergyPlus Headers
55 : #include <EnergyPlus/Autosizing/All_Simple_Sizing.hh>
56 : #include <EnergyPlus/Autosizing/CoolingAirFlowSizing.hh>
57 : #include <EnergyPlus/Autosizing/CoolingCapacitySizing.hh>
58 : #include <EnergyPlus/Autosizing/CoolingWaterDesAirInletHumRatSizing.hh>
59 : #include <EnergyPlus/Autosizing/CoolingWaterDesAirInletTempSizing.hh>
60 : #include <EnergyPlus/Autosizing/CoolingWaterDesAirOutletHumRatSizing.hh>
61 : #include <EnergyPlus/Autosizing/CoolingWaterDesAirOutletTempSizing.hh>
62 : #include <EnergyPlus/Autosizing/CoolingWaterDesWaterInletTempSizing.hh>
63 : #include <EnergyPlus/Autosizing/CoolingWaterNumofTubesPerRowSizing.hh>
64 : #include <EnergyPlus/Autosizing/CoolingWaterflowSizing.hh>
65 : #include <EnergyPlus/Autosizing/HeatingAirFlowSizing.hh>
66 : #include <EnergyPlus/Autosizing/HeatingAirflowUASizing.hh>
67 : #include <EnergyPlus/Autosizing/HeatingCapacitySizing.hh>
68 : #include <EnergyPlus/Autosizing/HeatingWaterDesAirInletHumRatSizing.hh>
69 : #include <EnergyPlus/Autosizing/HeatingWaterDesAirInletTempSizing.hh>
70 : #include <EnergyPlus/Autosizing/HeatingWaterDesCoilLoadUsedForUASizing.hh>
71 : #include <EnergyPlus/Autosizing/HeatingWaterDesCoilWaterVolFlowUsedForUASizing.hh>
72 : #include <EnergyPlus/Autosizing/HeatingWaterflowSizing.hh>
73 : #include <EnergyPlus/Autosizing/WaterHeatingCapacitySizing.hh>
74 : #include <EnergyPlus/Autosizing/WaterHeatingCoilUASizing.hh>
75 : #include <EnergyPlus/BranchNodeConnections.hh>
76 : #include <EnergyPlus/Data/EnergyPlusData.hh>
77 : #include <EnergyPlus/DataBranchAirLoopPlant.hh>
78 : #include <EnergyPlus/DataContaminantBalance.hh>
79 : #include <EnergyPlus/DataEnvironment.hh>
80 : #include <EnergyPlus/DataHVACGlobals.hh>
81 : #include <EnergyPlus/DataIPShortCuts.hh>
82 : #include <EnergyPlus/DataLoopNode.hh>
83 : #include <EnergyPlus/DataSizing.hh>
84 : #include <EnergyPlus/DataWater.hh>
85 : #include <EnergyPlus/EMSManager.hh>
86 : #include <EnergyPlus/FaultsManager.hh>
87 : #include <EnergyPlus/FluidProperties.hh>
88 : #include <EnergyPlus/General.hh>
89 : #include <EnergyPlus/GeneralRoutines.hh>
90 : #include <EnergyPlus/GlobalNames.hh>
91 : #include <EnergyPlus/HVACControllers.hh>
92 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
93 : #include <EnergyPlus/NodeInputManager.hh>
94 : #include <EnergyPlus/OutputProcessor.hh>
95 : #include <EnergyPlus/OutputReportPredefined.hh>
96 : #include <EnergyPlus/Plant/DataPlant.hh>
97 : #include <EnergyPlus/PlantUtilities.hh>
98 : #include <EnergyPlus/Psychrometrics.hh>
99 : #include <EnergyPlus/ReportCoilSelection.hh>
100 : #include <EnergyPlus/ScheduleManager.hh>
101 : #include <EnergyPlus/SetPointManager.hh>
102 : #include <EnergyPlus/SimAirServingZones.hh>
103 : #include <EnergyPlus/UtilityRoutines.hh>
104 : #include <EnergyPlus/WaterCoils.hh>
105 : #include <EnergyPlus/WaterManager.hh>
106 :
107 : namespace EnergyPlus::WaterCoils {
108 : // Module containing the WaterCoil simulation routines
109 :
110 : // MODULE INFORMATION:
111 : // AUTHOR Richard J. Liesen
112 : // DATE WRITTEN April 1998
113 : // MODIFIED April 2004: Rahul Chillar
114 : // Feb. 2010, Brent Griffith, Plant Demand Side Update, general fluid properties
115 : // RE-ENGINEERED na
116 :
117 : // PURPOSE OF THIS MODULE:
118 : // To encapsulate the data and algorithms required to
119 : // manage the WaterCoil System Component
120 :
121 : using namespace DataLoopNode;
122 :
123 : using Psychrometrics::PsyCpAirFnW;
124 : using Psychrometrics::PsyHFnTdbRhPb;
125 : using Psychrometrics::PsyHFnTdbW;
126 : using Psychrometrics::PsyRhoAirFnPbTdbW;
127 : using Psychrometrics::PsyTdbFnHW;
128 : using Psychrometrics::PsyTdpFnWPb;
129 : using Psychrometrics::PsyTsatFnHPb;
130 : using Psychrometrics::PsyWFnTdbH;
131 : using Psychrometrics::PsyWFnTdbRhPb;
132 : using Psychrometrics::PsyWFnTdbTwbPb;
133 : using Psychrometrics::PsyWFnTdpPb;
134 :
135 149968186 : void SimulateWaterCoilComponents(EnergyPlusData &state,
136 : std::string_view CompName,
137 : bool const FirstHVACIteration,
138 : int &CompIndex,
139 : ObjexxFCL::Optional<Real64> QActual,
140 : ObjexxFCL::Optional<HVAC::FanOp const> fanOpMode,
141 : ObjexxFCL::Optional<Real64 const> PartLoadRatio)
142 : {
143 :
144 : // SUBROUTINE INFORMATION:
145 : // AUTHOR Richard Liesen
146 : // DATE WRITTEN February 1998
147 :
148 : // PURPOSE OF THIS SUBROUTINE:
149 : // This subroutine manages WaterCoil component simulation.
150 :
151 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
152 : int CoilNum; // The WaterCoil that you are currently loading input into
153 : HVAC::FanOp fanOp; // fan operating mode
154 : Real64 PartLoadFrac; // part-load fraction of heating coil
155 :
156 : // Obtains and Allocates WaterCoil related parameters from input file
157 149968186 : if (state.dataWaterCoils->GetWaterCoilsInputFlag) { // First time subroutine has been entered
158 0 : GetWaterCoilInput(state);
159 0 : state.dataWaterCoils->GetWaterCoilsInputFlag = false;
160 : }
161 :
162 : // Find the correct WaterCoilNumber with the Coil Name
163 149968186 : if (CompIndex == 0) {
164 754287 : CoilNum = Util::FindItemInList(CompName, state.dataWaterCoils->WaterCoil);
165 754287 : if (CoilNum == 0) {
166 0 : ShowFatalError(state, format("SimulateWaterCoilComponents: Coil not found={}", CompName));
167 : }
168 754287 : CompIndex = CoilNum;
169 : } else {
170 149213899 : CoilNum = CompIndex;
171 149213899 : if (CoilNum > state.dataWaterCoils->NumWaterCoils || CoilNum < 1) {
172 0 : ShowFatalError(state,
173 0 : format("SimulateWaterCoilComponents: Invalid CompIndex passed={}, Number of Water Coils={}, Coil name={}",
174 : CoilNum,
175 0 : state.dataWaterCoils->NumWaterCoils,
176 : CompName));
177 : }
178 149213899 : if (state.dataWaterCoils->CheckEquipName(CoilNum)) {
179 3343 : auto const &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
180 3343 : if (CompName != waterCoil.Name) {
181 0 : ShowFatalError(state,
182 0 : format("SimulateWaterCoilComponents: Invalid CompIndex passed={}, Coil name={}, stored Coil Name for that index={}",
183 : CoilNum,
184 : CompName,
185 0 : waterCoil.Name));
186 : }
187 3343 : state.dataWaterCoils->CheckEquipName(CoilNum) = false;
188 : }
189 : }
190 :
191 : // With the correct CoilNum Initialize
192 149968186 : InitWaterCoil(state, CoilNum, FirstHVACIteration); // Initialize all WaterCoil related parameters
193 :
194 149968186 : if (present(fanOpMode)) {
195 6216245 : fanOp = fanOpMode;
196 : } else {
197 143751941 : fanOp = HVAC::FanOp::Continuous;
198 : }
199 149968186 : if (present(PartLoadRatio)) {
200 4815531 : PartLoadFrac = PartLoadRatio;
201 : } else {
202 145152655 : PartLoadFrac = 1.0;
203 : }
204 :
205 149968186 : auto const &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
206 :
207 : // Calculate the Correct WaterCoil Model with the current CoilNum
208 149968186 : if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling) {
209 4920098 : CalcDetailFlatFinCoolingCoil(state, CoilNum, state.dataWaterCoils->SimCalc, fanOp, PartLoadFrac);
210 4920098 : if (present(QActual)) {
211 4427826 : QActual = waterCoil.SenWaterCoolingCoilRate;
212 : }
213 145048088 : } else if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterCooling) {
214 23076407 : CoolingCoil(state, CoilNum, FirstHVACIteration, state.dataWaterCoils->SimCalc, fanOp, PartLoadFrac);
215 23076407 : if (present(QActual)) {
216 14324993 : QActual = waterCoil.SenWaterCoolingCoilRate;
217 : }
218 : }
219 :
220 149968186 : if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterSimpleHeating) {
221 121971681 : CalcSimpleHeatingCoil(state, CoilNum, fanOp, PartLoadFrac, state.dataWaterCoils->SimCalc);
222 121971681 : if (present(QActual)) {
223 20779883 : QActual = waterCoil.TotWaterHeatingCoilRate;
224 : }
225 : }
226 :
227 : // Update the current WaterCoil to the outlet nodes
228 149968186 : UpdateWaterCoil(state, CoilNum);
229 :
230 : // Report the current WaterCoil
231 149968186 : ReportWaterCoil(state, CoilNum);
232 149968186 : }
233 :
234 : // Get Input Section of the Module
235 : //******************************************************************************
236 :
237 337 : void GetWaterCoilInput(EnergyPlusData &state)
238 : {
239 :
240 : // SUBROUTINE INFORMATION:
241 : // AUTHOR Richard Liesen
242 : // DATE WRITTEN April 1998
243 : // MODIFIED April 2004: Rahul Chillar
244 : // November 2013: Tianzhen Hong for fouling coils
245 : // RE-ENGINEERED na
246 :
247 : // PURPOSE OF THIS SUBROUTINE:
248 : // Obtains input data for coils and stores it in coil data structures
249 :
250 : // METHODOLOGY EMPLOYED:
251 : // Uses "Get" routines to read in data.
252 :
253 : // SUBROUTINE PARAMETER DEFINITIONS:
254 : static constexpr std::string_view RoutineName("GetWaterCoilInput: "); // include trailing blank space
255 : static constexpr std::string_view routineName = "GetWaterCoilInput";
256 :
257 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
258 : int CoilNum; // The WaterCoil that you are currently loading input into
259 337 : int NumSimpHeat(0);
260 337 : int NumFlatFin(0);
261 337 : int NumCooling(0);
262 : int SimpHeatNum;
263 : int FlatFinNum;
264 : int CoolingNum;
265 : int NumAlphas;
266 : int NumNums;
267 : int IOStat;
268 337 : std::string CurrentModuleObject; // for ease in getting objects
269 337 : Array1D_string AlphArray; // Alpha input items for object
270 337 : Array1D_string cAlphaFields; // Alpha field names
271 337 : Array1D_string cNumericFields; // Numeric field names
272 337 : Array1D<Real64> NumArray; // Numeric input items for object
273 337 : Array1D_bool lAlphaBlanks; // Logical array, alpha field input BLANK = .TRUE.
274 337 : Array1D_bool lNumericBlanks; // Logical array, numeric field input BLANK = .TRUE.
275 337 : int MaxNums(0); // Maximum number of numeric input fields
276 337 : int MaxAlphas(0); // Maximum number of alpha input fields
277 337 : int TotalArgs(0); // Total number of alpha and numeric arguments (max) for a certain object in the input file
278 337 : bool ErrorsFound(false); // If errors detected in input
279 :
280 337 : NumSimpHeat = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Coil:Heating:Water");
281 337 : NumFlatFin = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Coil:Cooling:Water:DetailedGeometry");
282 337 : NumCooling = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Coil:Cooling:Water");
283 337 : state.dataWaterCoils->NumWaterCoils = NumSimpHeat + NumFlatFin + NumCooling;
284 :
285 337 : if (state.dataWaterCoils->NumWaterCoils > 0) {
286 326 : state.dataWaterCoils->WaterCoil.allocate(state.dataWaterCoils->NumWaterCoils);
287 326 : state.dataWaterCoils->WaterCoilNumericFields.allocate(state.dataWaterCoils->NumWaterCoils);
288 326 : state.dataWaterCoils->WaterTempCoolCoilErrs.dimension(state.dataWaterCoils->NumWaterCoils, 0);
289 326 : state.dataWaterCoils->PartWetCoolCoilErrs.dimension(state.dataWaterCoils->NumWaterCoils, 0);
290 326 : state.dataWaterCoils->CheckEquipName.dimension(state.dataWaterCoils->NumWaterCoils, true);
291 : }
292 :
293 337 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "Coil:Heating:Water", TotalArgs, NumAlphas, NumNums);
294 337 : MaxNums = max(MaxNums, NumNums);
295 337 : MaxAlphas = max(MaxAlphas, NumAlphas);
296 337 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "Coil:Cooling:Water:DetailedGeometry", TotalArgs, NumAlphas, NumNums);
297 337 : MaxNums = max(MaxNums, NumNums);
298 337 : MaxAlphas = max(MaxAlphas, NumAlphas);
299 337 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "Coil:Cooling:Water", TotalArgs, NumAlphas, NumNums);
300 337 : MaxNums = max(MaxNums, NumNums);
301 337 : MaxAlphas = max(MaxAlphas, NumAlphas);
302 :
303 337 : AlphArray.allocate(MaxAlphas);
304 337 : cAlphaFields.allocate(MaxAlphas);
305 337 : cNumericFields.allocate(MaxNums);
306 337 : NumArray.dimension(MaxNums, 0.0);
307 337 : lAlphaBlanks.dimension(MaxAlphas, true);
308 337 : lNumericBlanks.dimension(MaxNums, true);
309 337 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
310 337 : CurrentModuleObject = "Coil:Heating:Water";
311 : // Get the data for simple heating coils
312 3092 : for (SimpHeatNum = 1; SimpHeatNum <= NumSimpHeat; ++SimpHeatNum) {
313 :
314 2755 : CoilNum = SimpHeatNum;
315 :
316 2755 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
317 : CurrentModuleObject,
318 : SimpHeatNum,
319 : AlphArray,
320 : NumAlphas,
321 : NumArray,
322 : NumNums,
323 : IOStat,
324 : lNumericBlanks,
325 : lAlphaBlanks,
326 : cAlphaFields,
327 : cNumericFields);
328 :
329 2755 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphArray(1)};
330 :
331 2755 : state.dataWaterCoils->WaterCoilNumericFields(CoilNum).FieldNames.allocate(MaxNums);
332 2755 : state.dataWaterCoils->WaterCoilNumericFields(CoilNum).FieldNames = "";
333 2755 : state.dataWaterCoils->WaterCoilNumericFields(CoilNum).FieldNames = cNumericFields;
334 2755 : Util::IsNameEmpty(state, AlphArray(1), cCurrentModuleObject, ErrorsFound);
335 :
336 : // ErrorsFound will be set to True if problem was found, left untouched otherwise
337 2755 : GlobalNames::VerifyUniqueCoilName(state, CurrentModuleObject, AlphArray(1), ErrorsFound, CurrentModuleObject + " Name");
338 2755 : auto &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
339 :
340 2755 : waterCoil.Name = AlphArray(1);
341 2755 : if (lAlphaBlanks(2)) {
342 49 : waterCoil.availSched = Sched::GetScheduleAlwaysOn(state);
343 2706 : } else if ((waterCoil.availSched = Sched::GetSchedule(state, AlphArray(2))) == nullptr) {
344 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(2), AlphArray(2));
345 0 : ErrorsFound = true;
346 : }
347 :
348 2755 : waterCoil.WaterCoilModelA = "SIMPLE";
349 2755 : waterCoil.WaterCoilModel = CoilModel::HeatingSimple; // 'SIMPLE'
350 2755 : waterCoil.WaterCoilType = DataPlant::PlantEquipmentType::CoilWaterSimpleHeating;
351 :
352 2755 : waterCoil.UACoil = NumArray(1);
353 2755 : waterCoil.UACoilVariable = waterCoil.UACoil;
354 2755 : waterCoil.MaxWaterVolFlowRate = NumArray(2);
355 2755 : waterCoil.WaterInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
356 2755 : AlphArray(3),
357 : ErrorsFound,
358 : DataLoopNode::ConnectionObjectType::CoilHeatingWater,
359 2755 : AlphArray(1),
360 : DataLoopNode::NodeFluidType::Water,
361 : DataLoopNode::ConnectionType::Inlet,
362 : NodeInputManager::CompFluidStream::Secondary,
363 : ObjectIsNotParent);
364 2755 : waterCoil.WaterOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
365 2755 : AlphArray(4),
366 : ErrorsFound,
367 : DataLoopNode::ConnectionObjectType::CoilHeatingWater,
368 2755 : AlphArray(1),
369 : DataLoopNode::NodeFluidType::Water,
370 : DataLoopNode::ConnectionType::Outlet,
371 : NodeInputManager::CompFluidStream::Secondary,
372 : ObjectIsNotParent);
373 2755 : waterCoil.AirInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
374 2755 : AlphArray(5),
375 : ErrorsFound,
376 : DataLoopNode::ConnectionObjectType::CoilHeatingWater,
377 2755 : AlphArray(1),
378 : DataLoopNode::NodeFluidType::Air,
379 : DataLoopNode::ConnectionType::Inlet,
380 : NodeInputManager::CompFluidStream::Primary,
381 : ObjectIsNotParent);
382 2755 : waterCoil.AirOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
383 2755 : AlphArray(6),
384 : ErrorsFound,
385 : DataLoopNode::ConnectionObjectType::CoilHeatingWater,
386 2755 : AlphArray(1),
387 : DataLoopNode::NodeFluidType::Air,
388 : DataLoopNode::ConnectionType::Outlet,
389 : NodeInputManager::CompFluidStream::Primary,
390 : ObjectIsNotParent);
391 :
392 2755 : if (AlphArray(7) == "NOMINALCAPACITY") { // not "UFACTORTIMESAREAANDDESIGNWATERFLOWRATE"
393 52 : waterCoil.CoilPerfInpMeth = state.dataWaterCoils->NomCap;
394 :
395 : } else {
396 : // will be caught by input processor
397 2703 : waterCoil.CoilPerfInpMeth = state.dataWaterCoils->UAandFlow;
398 : }
399 :
400 2755 : waterCoil.DesTotWaterCoilLoad = NumArray(3);
401 :
402 2755 : if (waterCoil.UACoil == DataSizing::AutoSize && waterCoil.CoilPerfInpMeth == state.dataWaterCoils->UAandFlow) {
403 2401 : waterCoil.RequestingAutoSize = true;
404 : }
405 2755 : if (waterCoil.MaxWaterVolFlowRate == DataSizing::AutoSize) {
406 2449 : waterCoil.RequestingAutoSize = true;
407 : }
408 2755 : if (waterCoil.DesTotWaterCoilLoad == DataSizing::AutoSize && waterCoil.CoilPerfInpMeth == state.dataWaterCoils->NomCap) {
409 9 : waterCoil.RequestingAutoSize = true;
410 : }
411 :
412 2755 : waterCoil.DesInletWaterTemp = NumArray(4);
413 2755 : waterCoil.DesInletAirTemp = NumArray(5);
414 2755 : waterCoil.DesOutletWaterTemp = NumArray(6);
415 2755 : waterCoil.DesOutletAirTemp = NumArray(7);
416 2755 : waterCoil.RatioAirSideToWaterSideConvect = NumArray(8);
417 2755 : if (!lNumericBlanks(9)) {
418 114 : waterCoil.DesignWaterDeltaTemp = NumArray(9);
419 114 : waterCoil.UseDesignWaterDeltaTemp = true;
420 : } else {
421 2641 : waterCoil.UseDesignWaterDeltaTemp = false;
422 : }
423 2755 : if (waterCoil.DesInletWaterTemp <= waterCoil.DesOutletWaterTemp) {
424 0 : ShowSevereError(state, format("For {}, {}", CurrentModuleObject, AlphArray(1)));
425 0 : ShowContinueError(state, format(" the {} must be greater than the {}.", cNumericFields(4), cNumericFields(6)));
426 0 : ErrorsFound = true;
427 : }
428 2755 : if (waterCoil.DesInletAirTemp >= waterCoil.DesOutletAirTemp) {
429 0 : ShowSevereError(state, format("For {}, {}", CurrentModuleObject, AlphArray(1)));
430 0 : ShowContinueError(state, format(" the {} must be less than the {}.", cNumericFields(5), cNumericFields(7)));
431 0 : ErrorsFound = true;
432 : }
433 2755 : if (waterCoil.DesInletAirTemp >= waterCoil.DesInletWaterTemp) {
434 0 : ShowSevereError(state, format("For {}, {}", CurrentModuleObject, AlphArray(1)));
435 0 : ShowContinueError(state, format(" the {} must be less than the {}.", cNumericFields(5), cNumericFields(4)));
436 0 : ErrorsFound = true;
437 : }
438 :
439 5510 : BranchNodeConnections::TestCompSet(state, CurrentModuleObject, AlphArray(1), AlphArray(3), AlphArray(4), "Water Nodes");
440 2755 : BranchNodeConnections::TestCompSet(state, CurrentModuleObject, AlphArray(1), AlphArray(5), AlphArray(6), "Air Nodes");
441 :
442 : // Setup the Simple Heating Coil reporting variables
443 : // CurrentModuleObject = "Coil:Heating:Water"
444 5510 : SetupOutputVariable(state,
445 : "Heating Coil Heating Energy",
446 : Constant::Units::J,
447 2755 : waterCoil.TotWaterHeatingCoilEnergy,
448 : OutputProcessor::TimeStepType::System,
449 : OutputProcessor::StoreType::Sum,
450 2755 : waterCoil.Name,
451 : Constant::eResource::EnergyTransfer,
452 : OutputProcessor::Group::HVAC,
453 : OutputProcessor::EndUseCat::HeatingCoils);
454 5510 : SetupOutputVariable(state,
455 : "Heating Coil Source Side Heat Transfer Energy",
456 : Constant::Units::J,
457 2755 : waterCoil.TotWaterHeatingCoilEnergy,
458 : OutputProcessor::TimeStepType::System,
459 : OutputProcessor::StoreType::Sum,
460 2755 : waterCoil.Name,
461 : Constant::eResource::PlantLoopHeatingDemand,
462 : OutputProcessor::Group::HVAC,
463 : OutputProcessor::EndUseCat::HeatingCoils);
464 5510 : SetupOutputVariable(state,
465 : "Heating Coil Heating Rate",
466 : Constant::Units::W,
467 2755 : waterCoil.TotWaterHeatingCoilRate,
468 : OutputProcessor::TimeStepType::System,
469 : OutputProcessor::StoreType::Average,
470 2755 : waterCoil.Name);
471 5510 : SetupOutputVariable(state,
472 : "Heating Coil U Factor Times Area Value",
473 : Constant::Units::W_K,
474 2755 : waterCoil.UACoilVariable,
475 : OutputProcessor::TimeStepType::System,
476 : OutputProcessor::StoreType::Average,
477 2755 : waterCoil.Name);
478 : }
479 :
480 337 : CurrentModuleObject = "Coil:Cooling:Water:DetailedGeometry";
481 : // Get the data for detailed cooling coils.
482 499 : for (FlatFinNum = 1; FlatFinNum <= NumFlatFin; ++FlatFinNum) {
483 :
484 162 : CoilNum = NumSimpHeat + FlatFinNum;
485 :
486 162 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
487 : CurrentModuleObject,
488 : FlatFinNum,
489 : AlphArray,
490 : NumAlphas,
491 : NumArray,
492 : NumNums,
493 : IOStat,
494 : lNumericBlanks,
495 : lAlphaBlanks,
496 : cAlphaFields,
497 : cNumericFields);
498 :
499 162 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphArray(1)};
500 :
501 162 : state.dataWaterCoils->WaterCoilNumericFields(CoilNum).FieldNames.allocate(MaxNums);
502 162 : state.dataWaterCoils->WaterCoilNumericFields(CoilNum).FieldNames = "";
503 162 : state.dataWaterCoils->WaterCoilNumericFields(CoilNum).FieldNames = cNumericFields;
504 162 : Util::IsNameEmpty(state, AlphArray(1), cCurrentModuleObject, ErrorsFound);
505 :
506 : // ErrorsFound will be set to True if problem was found, left untouched otherwise
507 162 : GlobalNames::VerifyUniqueCoilName(state, CurrentModuleObject, AlphArray(1), ErrorsFound, CurrentModuleObject + " Name");
508 :
509 162 : auto &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
510 162 : waterCoil.Name = AlphArray(1);
511 :
512 162 : if (lAlphaBlanks(2)) {
513 0 : waterCoil.availSched = Sched::GetScheduleAlwaysOn(state);
514 162 : } else if ((waterCoil.availSched = Sched::GetSchedule(state, AlphArray(2))) == nullptr) {
515 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(2), AlphArray(2));
516 0 : ErrorsFound = true;
517 : }
518 :
519 162 : waterCoil.WaterCoilModelA = "DETAILED FLAT FIN";
520 162 : waterCoil.WaterCoilModel = CoilModel::CoolingDetailed; // 'DETAILED FLAT FIN'
521 162 : waterCoil.WaterCoilType = DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling;
522 :
523 162 : waterCoil.MaxWaterVolFlowRate = NumArray(1);
524 162 : if (waterCoil.MaxWaterVolFlowRate == DataSizing::AutoSize) {
525 81 : waterCoil.RequestingAutoSize = true;
526 : }
527 162 : waterCoil.TubeOutsideSurfArea = NumArray(2);
528 162 : if (waterCoil.TubeOutsideSurfArea == DataSizing::AutoSize) {
529 81 : waterCoil.RequestingAutoSize = true;
530 : }
531 162 : waterCoil.TotTubeInsideArea = NumArray(3);
532 162 : if (waterCoil.TotTubeInsideArea == DataSizing::AutoSize) {
533 81 : waterCoil.RequestingAutoSize = true;
534 : }
535 162 : waterCoil.FinSurfArea = NumArray(4);
536 162 : if (waterCoil.FinSurfArea == DataSizing::AutoSize) {
537 81 : waterCoil.RequestingAutoSize = true;
538 : }
539 162 : waterCoil.MinAirFlowArea = NumArray(5);
540 162 : if (waterCoil.MinAirFlowArea == DataSizing::AutoSize) {
541 81 : waterCoil.RequestingAutoSize = true;
542 : }
543 162 : waterCoil.CoilDepth = NumArray(6);
544 162 : if (waterCoil.CoilDepth == DataSizing::AutoSize) {
545 81 : waterCoil.RequestingAutoSize = true;
546 : }
547 162 : waterCoil.FinDiam = NumArray(7);
548 162 : if (waterCoil.FinDiam == DataSizing::AutoSize) {
549 81 : waterCoil.RequestingAutoSize = true;
550 : }
551 162 : waterCoil.FinThickness = NumArray(8);
552 162 : if (waterCoil.FinThickness <= 0.0) {
553 0 : ShowSevereError(state,
554 0 : format("{}: {} must be > 0.0, for {} = {}", CurrentModuleObject, cNumericFields(8), cAlphaFields(1), waterCoil.Name));
555 0 : ErrorsFound = true;
556 : }
557 162 : waterCoil.TubeInsideDiam = NumArray(9);
558 162 : waterCoil.TubeOutsideDiam = NumArray(10);
559 162 : waterCoil.TubeThermConductivity = NumArray(11);
560 162 : if (waterCoil.TubeThermConductivity <= 0.0) {
561 0 : ShowSevereError(state,
562 0 : format("{}: {} must be > 0.0, for {} = {}", CurrentModuleObject, cNumericFields(11), cAlphaFields(1), waterCoil.Name));
563 0 : ErrorsFound = true;
564 : }
565 162 : waterCoil.FinThermConductivity = NumArray(12);
566 162 : if (waterCoil.FinThermConductivity <= 0.0) {
567 0 : ShowSevereError(state,
568 0 : format("{}: {} must be > 0.0, for {} = {}", CurrentModuleObject, cNumericFields(12), cAlphaFields(1), waterCoil.Name));
569 0 : ErrorsFound = true;
570 : }
571 162 : waterCoil.FinSpacing = NumArray(13);
572 162 : waterCoil.TubeDepthSpacing = NumArray(14);
573 162 : waterCoil.NumOfTubeRows = NumArray(15);
574 162 : waterCoil.NumOfTubesPerRow = NumArray(16);
575 162 : if (waterCoil.NumOfTubesPerRow == DataSizing::AutoSize) {
576 78 : waterCoil.RequestingAutoSize = true;
577 : }
578 162 : if (!lNumericBlanks(17)) {
579 1 : waterCoil.DesignWaterDeltaTemp = NumArray(17);
580 1 : waterCoil.UseDesignWaterDeltaTemp = true;
581 : } else {
582 161 : waterCoil.UseDesignWaterDeltaTemp = false;
583 : }
584 162 : waterCoil.WaterInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
585 162 : AlphArray(3),
586 : ErrorsFound,
587 : DataLoopNode::ConnectionObjectType::CoilCoolingWaterDetailedGeometry,
588 162 : AlphArray(1),
589 : DataLoopNode::NodeFluidType::Water,
590 : DataLoopNode::ConnectionType::Inlet,
591 : NodeInputManager::CompFluidStream::Secondary,
592 : ObjectIsNotParent);
593 162 : waterCoil.WaterOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
594 162 : AlphArray(4),
595 : ErrorsFound,
596 : DataLoopNode::ConnectionObjectType::CoilCoolingWaterDetailedGeometry,
597 162 : AlphArray(1),
598 : DataLoopNode::NodeFluidType::Water,
599 : DataLoopNode::ConnectionType::Outlet,
600 : NodeInputManager::CompFluidStream::Secondary,
601 : ObjectIsNotParent);
602 162 : waterCoil.AirInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
603 162 : AlphArray(5),
604 : ErrorsFound,
605 : DataLoopNode::ConnectionObjectType::CoilCoolingWaterDetailedGeometry,
606 162 : AlphArray(1),
607 : DataLoopNode::NodeFluidType::Air,
608 : DataLoopNode::ConnectionType::Inlet,
609 : NodeInputManager::CompFluidStream::Primary,
610 : ObjectIsNotParent);
611 162 : waterCoil.AirOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
612 162 : AlphArray(6),
613 : ErrorsFound,
614 : DataLoopNode::ConnectionObjectType::CoilCoolingWaterDetailedGeometry,
615 162 : AlphArray(1),
616 : DataLoopNode::NodeFluidType::Air,
617 : DataLoopNode::ConnectionType::Outlet,
618 : NodeInputManager::CompFluidStream::Primary,
619 : ObjectIsNotParent);
620 :
621 : // A7 ; \field Name of Water Storage Tank for Condensate Collection
622 162 : waterCoil.CondensateCollectName = AlphArray(7);
623 162 : if (lAlphaBlanks(7)) {
624 162 : waterCoil.CondensateCollectMode = state.dataWaterCoils->CondensateDiscarded;
625 : } else {
626 0 : waterCoil.CondensateCollectMode = state.dataWaterCoils->CondensateToTank;
627 0 : WaterManager::SetupTankSupplyComponent(state,
628 : waterCoil.Name,
629 : CurrentModuleObject,
630 : waterCoil.CondensateCollectName,
631 : ErrorsFound,
632 0 : waterCoil.CondensateTankID,
633 0 : waterCoil.CondensateTankSupplyARRID);
634 : }
635 :
636 324 : BranchNodeConnections::TestCompSet(state, CurrentModuleObject, AlphArray(1), AlphArray(3), AlphArray(4), "Water Nodes");
637 162 : BranchNodeConnections::TestCompSet(state, CurrentModuleObject, AlphArray(1), AlphArray(5), AlphArray(6), "Air Nodes");
638 :
639 : // Setup Report variables for the Detailed Flat Fin Cooling Coils
640 : // CurrentModuleObject = "Coil:Cooling:Water:DetailedGeometry"
641 324 : SetupOutputVariable(state,
642 : "Cooling Coil Total Cooling Energy",
643 : Constant::Units::J,
644 162 : waterCoil.TotWaterCoolingCoilEnergy,
645 : OutputProcessor::TimeStepType::System,
646 : OutputProcessor::StoreType::Sum,
647 162 : waterCoil.Name,
648 : Constant::eResource::EnergyTransfer,
649 : OutputProcessor::Group::HVAC,
650 : OutputProcessor::EndUseCat::CoolingCoils);
651 324 : SetupOutputVariable(state,
652 : "Cooling Coil Source Side Heat Transfer Energy",
653 : Constant::Units::J,
654 162 : waterCoil.TotWaterCoolingCoilEnergy,
655 : OutputProcessor::TimeStepType::System,
656 : OutputProcessor::StoreType::Sum,
657 162 : waterCoil.Name,
658 : Constant::eResource::PlantLoopCoolingDemand,
659 : OutputProcessor::Group::HVAC,
660 : OutputProcessor::EndUseCat::CoolingCoils);
661 324 : SetupOutputVariable(state,
662 : "Cooling Coil Sensible Cooling Energy",
663 : Constant::Units::J,
664 162 : waterCoil.SenWaterCoolingCoilEnergy,
665 : OutputProcessor::TimeStepType::System,
666 : OutputProcessor::StoreType::Sum,
667 162 : waterCoil.Name);
668 324 : SetupOutputVariable(state,
669 : "Cooling Coil Total Cooling Rate",
670 : Constant::Units::W,
671 162 : waterCoil.TotWaterCoolingCoilRate,
672 : OutputProcessor::TimeStepType::System,
673 : OutputProcessor::StoreType::Average,
674 162 : waterCoil.Name);
675 324 : SetupOutputVariable(state,
676 : "Cooling Coil Sensible Cooling Rate",
677 : Constant::Units::W,
678 162 : waterCoil.SenWaterCoolingCoilRate,
679 : OutputProcessor::TimeStepType::System,
680 : OutputProcessor::StoreType::Average,
681 162 : waterCoil.Name);
682 :
683 162 : if (waterCoil.CondensateCollectMode == state.dataWaterCoils->CondensateToTank) {
684 :
685 0 : SetupOutputVariable(state,
686 : "Cooling Coil Condensate Volume Flow Rate",
687 : Constant::Units::m3_s,
688 0 : waterCoil.CondensateVdot,
689 : OutputProcessor::TimeStepType::System,
690 : OutputProcessor::StoreType::Average,
691 0 : waterCoil.Name);
692 0 : SetupOutputVariable(state,
693 : "Cooling Coil Condensate Volume",
694 : Constant::Units::m3,
695 0 : waterCoil.CondensateVol,
696 : OutputProcessor::TimeStepType::System,
697 : OutputProcessor::StoreType::Sum,
698 0 : waterCoil.Name,
699 : Constant::eResource::OnSiteWater,
700 : OutputProcessor::Group::HVAC,
701 : OutputProcessor::EndUseCat::Condensate);
702 : }
703 : }
704 :
705 337 : CurrentModuleObject = "Coil:Cooling:Water";
706 : // Get the data for Cooling coils.
707 771 : for (CoolingNum = 1; CoolingNum <= NumCooling; ++CoolingNum) {
708 :
709 434 : CoilNum = NumSimpHeat + NumFlatFin + CoolingNum;
710 :
711 434 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
712 : CurrentModuleObject,
713 : CoolingNum,
714 : AlphArray,
715 : NumAlphas,
716 : NumArray,
717 : NumNums,
718 : IOStat,
719 : lNumericBlanks,
720 : lAlphaBlanks,
721 : cAlphaFields,
722 : cNumericFields);
723 :
724 434 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphArray(1)};
725 434 : state.dataWaterCoils->WaterCoilNumericFields(CoilNum).FieldNames.allocate(MaxNums);
726 434 : state.dataWaterCoils->WaterCoilNumericFields(CoilNum).FieldNames = "";
727 434 : state.dataWaterCoils->WaterCoilNumericFields(CoilNum).FieldNames = cNumericFields;
728 434 : Util::IsNameEmpty(state, AlphArray(1), cCurrentModuleObject, ErrorsFound);
729 :
730 : // ErrorsFound will be set to True if problem was found, left untouched otherwise
731 434 : GlobalNames::VerifyUniqueCoilName(state, CurrentModuleObject, AlphArray(1), ErrorsFound, CurrentModuleObject + " Name");
732 :
733 434 : auto &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
734 434 : waterCoil.Name = AlphArray(1);
735 :
736 434 : if (lAlphaBlanks(2)) {
737 24 : waterCoil.availSched = Sched::GetScheduleAlwaysOn(state);
738 410 : } else if ((waterCoil.availSched = Sched::GetSchedule(state, AlphArray(2))) == nullptr) {
739 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(2), AlphArray(2));
740 0 : ErrorsFound = true;
741 : }
742 :
743 434 : waterCoil.WaterCoilModelA = "Cooling";
744 434 : waterCoil.WaterCoilModel = CoilModel::CoolingSimple; // 'Cooling'
745 434 : waterCoil.WaterCoilType = DataPlant::PlantEquipmentType::CoilWaterCooling;
746 :
747 434 : waterCoil.MaxWaterVolFlowRate = NumArray(1); // Liquid mass flow rate at Design kg/s
748 434 : if (waterCoil.MaxWaterVolFlowRate == DataSizing::AutoSize) {
749 412 : waterCoil.RequestingAutoSize = true;
750 : }
751 434 : waterCoil.DesAirVolFlowRate = NumArray(2); // Dry air mass flow rate at Design (kg/s)
752 434 : if (waterCoil.DesAirVolFlowRate == DataSizing::AutoSize) {
753 412 : waterCoil.RequestingAutoSize = true;
754 : }
755 434 : waterCoil.DesInletWaterTemp = NumArray(3); // Entering water temperature at Design C
756 434 : if (waterCoil.DesInletWaterTemp == DataSizing::AutoSize) {
757 399 : waterCoil.RequestingAutoSize = true;
758 : }
759 434 : waterCoil.DesInletAirTemp = NumArray(4); // Entering air dry bulb temperature at Design(C)
760 434 : if (waterCoil.DesInletAirTemp == DataSizing::AutoSize) {
761 407 : waterCoil.RequestingAutoSize = true;
762 : }
763 434 : waterCoil.DesOutletAirTemp = NumArray(5); // Leaving air dry bulb temperature at Design(C)
764 434 : if (waterCoil.DesOutletAirTemp == DataSizing::AutoSize) {
765 407 : waterCoil.RequestingAutoSize = true;
766 : }
767 434 : waterCoil.DesInletAirHumRat = NumArray(6); // Entering air humidity ratio at Design
768 434 : if (waterCoil.DesInletAirHumRat == DataSizing::AutoSize) {
769 407 : waterCoil.RequestingAutoSize = true;
770 : }
771 434 : waterCoil.DesOutletAirHumRat = NumArray(7); // Leaving air humidity ratio at Design
772 434 : if (waterCoil.DesOutletAirHumRat == DataSizing::AutoSize) {
773 407 : waterCoil.RequestingAutoSize = true;
774 : }
775 434 : if (!lNumericBlanks(8)) {
776 33 : waterCoil.DesignWaterDeltaTemp = NumArray(8);
777 33 : waterCoil.UseDesignWaterDeltaTemp = true;
778 : } else {
779 401 : waterCoil.UseDesignWaterDeltaTemp = false;
780 : }
781 :
782 434 : waterCoil.WaterInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
783 434 : AlphArray(3),
784 : ErrorsFound,
785 : DataLoopNode::ConnectionObjectType::CoilCoolingWater,
786 434 : AlphArray(1),
787 : DataLoopNode::NodeFluidType::Water,
788 : DataLoopNode::ConnectionType::Inlet,
789 : NodeInputManager::CompFluidStream::Secondary,
790 : ObjectIsNotParent);
791 434 : waterCoil.WaterOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
792 434 : AlphArray(4),
793 : ErrorsFound,
794 : DataLoopNode::ConnectionObjectType::CoilCoolingWater,
795 434 : AlphArray(1),
796 : DataLoopNode::NodeFluidType::Water,
797 : DataLoopNode::ConnectionType::Outlet,
798 : NodeInputManager::CompFluidStream::Secondary,
799 : ObjectIsNotParent);
800 434 : waterCoil.AirInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
801 434 : AlphArray(5),
802 : ErrorsFound,
803 : DataLoopNode::ConnectionObjectType::CoilCoolingWater,
804 434 : AlphArray(1),
805 : DataLoopNode::NodeFluidType::Air,
806 : DataLoopNode::ConnectionType::Inlet,
807 : NodeInputManager::CompFluidStream::Primary,
808 : ObjectIsNotParent);
809 434 : waterCoil.AirOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
810 434 : AlphArray(6),
811 : ErrorsFound,
812 : DataLoopNode::ConnectionObjectType::CoilCoolingWater,
813 434 : AlphArray(1),
814 : DataLoopNode::NodeFluidType::Air,
815 : DataLoopNode::ConnectionType::Outlet,
816 : NodeInputManager::CompFluidStream::Primary,
817 : ObjectIsNotParent);
818 :
819 : // The default is SimpleAnalysis = 2. and DetailedAnalysis =1
820 434 : if (AlphArray(7) == "DETAILEDANALYSIS") { // not "SIMPLEANALYSIS"
821 54 : waterCoil.CoolingCoilAnalysisMode = state.dataWaterCoils->DetailedAnalysis;
822 :
823 : } else {
824 380 : waterCoil.CoolingCoilAnalysisMode = state.dataWaterCoils->SimpleAnalysis;
825 : }
826 :
827 : // The default is CrossFlow = 2. and CounterFlow=1
828 434 : if (AlphArray(8) == "COUNTERFLOW") { // not "CROSSFLOW"
829 1 : waterCoil.HeatExchType = state.dataWaterCoils->CounterFlow;
830 :
831 : } else {
832 433 : waterCoil.HeatExchType = state.dataWaterCoils->CrossFlow;
833 : }
834 :
835 : // A9; \field Name of Water Storage Tank for Condensate Collection
836 434 : waterCoil.CondensateCollectName = AlphArray(9);
837 434 : if (lAlphaBlanks(9)) {
838 434 : waterCoil.CondensateCollectMode = state.dataWaterCoils->CondensateDiscarded;
839 : } else {
840 0 : waterCoil.CondensateCollectMode = state.dataWaterCoils->CondensateToTank;
841 0 : WaterManager::SetupTankSupplyComponent(state,
842 : waterCoil.Name,
843 : CurrentModuleObject,
844 : waterCoil.CondensateCollectName,
845 : ErrorsFound,
846 0 : waterCoil.CondensateTankID,
847 0 : waterCoil.CondensateTankSupplyARRID);
848 : }
849 :
850 868 : BranchNodeConnections::TestCompSet(state, CurrentModuleObject, AlphArray(1), AlphArray(3), AlphArray(4), "Water Nodes");
851 434 : BranchNodeConnections::TestCompSet(state, CurrentModuleObject, AlphArray(1), AlphArray(5), AlphArray(6), "Air Nodes");
852 :
853 : // Setup Report variables for the Design input Cooling Coils
854 : // CurrentModuleObject = "Coil:Cooling:Water"
855 868 : SetupOutputVariable(state,
856 : "Cooling Coil Total Cooling Energy",
857 : Constant::Units::J,
858 434 : waterCoil.TotWaterCoolingCoilEnergy,
859 : OutputProcessor::TimeStepType::System,
860 : OutputProcessor::StoreType::Sum,
861 434 : waterCoil.Name,
862 : Constant::eResource::EnergyTransfer,
863 : OutputProcessor::Group::HVAC,
864 : OutputProcessor::EndUseCat::CoolingCoils);
865 868 : SetupOutputVariable(state,
866 : "Cooling Coil Source Side Heat Transfer Energy",
867 : Constant::Units::J,
868 434 : waterCoil.TotWaterCoolingCoilEnergy,
869 : OutputProcessor::TimeStepType::System,
870 : OutputProcessor::StoreType::Sum,
871 434 : waterCoil.Name,
872 : Constant::eResource::PlantLoopCoolingDemand,
873 : OutputProcessor::Group::HVAC,
874 : OutputProcessor::EndUseCat::CoolingCoils);
875 868 : SetupOutputVariable(state,
876 : "Cooling Coil Sensible Cooling Energy",
877 : Constant::Units::J,
878 434 : waterCoil.SenWaterCoolingCoilEnergy,
879 : OutputProcessor::TimeStepType::System,
880 : OutputProcessor::StoreType::Sum,
881 434 : waterCoil.Name);
882 868 : SetupOutputVariable(state,
883 : "Cooling Coil Total Cooling Rate",
884 : Constant::Units::W,
885 434 : waterCoil.TotWaterCoolingCoilRate,
886 : OutputProcessor::TimeStepType::System,
887 : OutputProcessor::StoreType::Average,
888 434 : waterCoil.Name);
889 868 : SetupOutputVariable(state,
890 : "Cooling Coil Sensible Cooling Rate",
891 : Constant::Units::W,
892 434 : waterCoil.SenWaterCoolingCoilRate,
893 : OutputProcessor::TimeStepType::System,
894 : OutputProcessor::StoreType::Average,
895 434 : waterCoil.Name);
896 868 : SetupOutputVariable(state,
897 : "Cooling Coil Wetted Area Fraction",
898 : Constant::Units::None,
899 434 : waterCoil.SurfAreaWetFraction,
900 : OutputProcessor::TimeStepType::System,
901 : OutputProcessor::StoreType::Average,
902 434 : waterCoil.Name);
903 :
904 434 : if (waterCoil.CondensateCollectMode == state.dataWaterCoils->CondensateToTank) {
905 :
906 0 : SetupOutputVariable(state,
907 : "Cooling Coil Condensate Volume Flow Rate",
908 : Constant::Units::m3_s,
909 0 : waterCoil.CondensateVdot,
910 : OutputProcessor::TimeStepType::System,
911 : OutputProcessor::StoreType::Average,
912 0 : waterCoil.Name);
913 0 : SetupOutputVariable(state,
914 : "Cooling Coil Condensate Volume",
915 : Constant::Units::m3,
916 0 : waterCoil.CondensateVol,
917 : OutputProcessor::TimeStepType::System,
918 : OutputProcessor::StoreType::Sum,
919 0 : waterCoil.Name,
920 : Constant::eResource::OnSiteWater,
921 : OutputProcessor::Group::HVAC,
922 : OutputProcessor::EndUseCat::Condensate);
923 : }
924 : }
925 :
926 337 : if (ErrorsFound) {
927 0 : ShowFatalError(state, format("{}Errors found in getting input.", RoutineName));
928 : }
929 :
930 337 : AlphArray.deallocate();
931 337 : cAlphaFields.deallocate();
932 337 : cNumericFields.deallocate();
933 337 : NumArray.deallocate();
934 337 : lAlphaBlanks.deallocate();
935 337 : lNumericBlanks.deallocate();
936 337 : }
937 :
938 149968186 : void InitWaterCoil(EnergyPlusData &state, int const CoilNum, bool const FirstHVACIteration)
939 : {
940 :
941 : // SUBROUTINE INFORMATION:
942 : // AUTHOR Richard J. Liesen
943 : // DATE WRITTEN February 1998
944 : // MODIFIED April 2004: Rahul Chillar
945 : // November 2013: XP, Tianzhen Hong to handle fouling coils
946 : // RE-ENGINEERED na
947 :
948 : // PURPOSE OF THIS SUBROUTINE:
949 : // This subroutine is for initializations of the WaterCoil Components.
950 :
951 : // METHODOLOGY EMPLOYED:
952 : // Uses the status flags to trigger initializations.
953 :
954 : // SUBROUTINE PARAMETER DEFINITIONS:
955 149968186 : constexpr Real64 SmallNo(1.e-9); // SmallNo number in place of zero
956 149968186 : constexpr int itmax(10);
957 149968186 : constexpr int MaxIte(500); // Maximum number of iterations
958 : static constexpr std::string_view RoutineName("InitWaterCoil");
959 :
960 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
961 : int tempCoilNum; // loop variable
962 : Real64 DesInletAirEnth; // Entering air enthalpy at rating (J/kg)
963 : Real64 DesOutletAirEnth; // Leaving air enthalpy at rating(J/kg)
964 : Real64 DesAirApparatusDewPtEnth; // Air enthalpy at apparatus dew point at rating(J/kg)
965 : Real64 DesSatEnthAtWaterInTemp; // Saturated enthalpy at entering liquid temp(J/kg)
966 : Real64 DesHumRatAtWaterInTemp; // Enthalpy at water inlet temp and entering air HumRat (J/kg)
967 : Real64 CapacitanceAir; // Air-side capacity rate(W/C)
968 : Real64 DesAirTempApparatusDewPt; // Temperature apparatus dew point at design capacity
969 : Real64 DesAirHumRatApparatusDewPt; // Humidity Ratio at apparatus dew point at design capacity
970 : Real64 DesBypassFactor; // ByPass Factor at design condition
971 : Real64 SlopeTempVsHumRatio; // Ratio temperature difference to humidity difference
972 : // between entering and leaving air states
973 : Real64 TempApparatusDewPtEstimate; // Estimate of TAdp from SlopeTempVsHumRatio
974 : Real64 Y1; // Previous values of dependent variable in ITERATE
975 : Real64 X1; // Previous values of independent variable in ITERATE
976 : Real64 error; // Deviation of dependent variable in iteration
977 : int iter; // Iteration counter
978 : int icvg; // Iteration convergence flag
979 : Real64 ResultX; // Output variable from ITERATE function.
980 : int Ipass; // loop index for App_Dewpoint_Loop
981 : int AirInletNode;
982 : int WaterInletNode;
983 : int WaterOutletNode;
984 : Real64 FinDiamVar;
985 : Real64 TubeToFinDiamRatio;
986 : Real64 CpAirStd; // specific heat of air at std conditions
987 : int SolFla; // Flag of solver
988 : Real64 UA0; // lower bound for UA
989 : Real64 UA1; // upper bound for UA
990 : Real64 UA;
991 : Real64 DesUACoilExternalEnth; // enthalpy based UAExternal for wet coil surface {kg/s}
992 : Real64 LogMeanEnthDiff; // long mean enthalpy difference {J/kg}
993 : Real64 LogMeanTempDiff; // long mean temperature difference {C}
994 : Real64 DesOutletWaterTemp;
995 : Real64 DesSatEnthAtWaterOutTemp;
996 : Real64 DesEnthAtWaterOutTempAirInHumRat;
997 : Real64 DesEnthWaterOut;
998 : Real64 Cp; // local fluid specific heat
999 : Real64 rho; // local fluid density
1000 : bool errFlag;
1001 149968186 : Real64 EnthCorrFrac(0.0); // enthalpy correction factor
1002 149968186 : Real64 TempCorrFrac(0.0); // temperature correction factor
1003 :
1004 149968186 : if (state.dataWaterCoils->InitWaterCoilOneTimeFlag) {
1005 : // initialize the environment and sizing flags
1006 326 : state.dataWaterCoils->MyEnvrnFlag.allocate(state.dataWaterCoils->NumWaterCoils);
1007 326 : state.dataWaterCoils->MySizeFlag.allocate(state.dataWaterCoils->NumWaterCoils);
1008 326 : state.dataWaterCoils->CoilWarningOnceFlag.allocate(state.dataWaterCoils->NumWaterCoils);
1009 326 : state.dataWaterCoils->DesCpAir.allocate(state.dataWaterCoils->NumWaterCoils);
1010 326 : state.dataWaterCoils->MyUAAndFlowCalcFlag.allocate(state.dataWaterCoils->NumWaterCoils);
1011 326 : state.dataWaterCoils->MyCoilDesignFlag.allocate(state.dataWaterCoils->NumWaterCoils);
1012 326 : state.dataWaterCoils->MyCoilReportFlag.allocate(state.dataWaterCoils->NumWaterCoils);
1013 326 : state.dataWaterCoils->DesUARangeCheck.allocate(state.dataWaterCoils->NumWaterCoils);
1014 326 : state.dataWaterCoils->PlantLoopScanFlag.allocate(state.dataWaterCoils->NumWaterCoils);
1015 :
1016 326 : state.dataWaterCoils->DesCpAir = 0.0;
1017 326 : state.dataWaterCoils->DesUARangeCheck = 0.0;
1018 326 : state.dataWaterCoils->MyEnvrnFlag = true;
1019 326 : state.dataWaterCoils->MySizeFlag = true;
1020 326 : state.dataWaterCoils->CoilWarningOnceFlag = true;
1021 326 : state.dataWaterCoils->MyUAAndFlowCalcFlag = true;
1022 326 : state.dataWaterCoils->MyCoilDesignFlag = true;
1023 326 : state.dataWaterCoils->MyCoilReportFlag = true;
1024 326 : state.dataWaterCoils->InitWaterCoilOneTimeFlag = false;
1025 326 : state.dataWaterCoils->PlantLoopScanFlag = true;
1026 :
1027 3677 : for (tempCoilNum = 1; tempCoilNum <= state.dataWaterCoils->NumWaterCoils; ++tempCoilNum) {
1028 3351 : HVACControllers::GetControllerNameAndIndex(state,
1029 3351 : state.dataWaterCoils->WaterCoil(tempCoilNum).WaterInletNodeNum,
1030 3351 : state.dataWaterCoils->WaterCoil(tempCoilNum).ControllerName,
1031 3351 : state.dataWaterCoils->WaterCoil(tempCoilNum).ControllerIndex,
1032 : errFlag);
1033 : }
1034 : }
1035 :
1036 149968186 : if (state.dataWaterCoils->WaterCoilControllerCheckOneTimeFlag && (state.dataHVACGlobal->GetAirPathDataDone)) {
1037 326 : bool ErrorsFound = false;
1038 326 : bool WaterCoilOnAirLoop = true;
1039 3677 : for (tempCoilNum = 1; tempCoilNum <= state.dataWaterCoils->NumWaterCoils; ++tempCoilNum) {
1040 3351 : if (state.dataWaterCoils->WaterCoil(tempCoilNum).ControllerIndex > 0) {
1041 902 : SimAirServingZones::CompType CoilTypeNum(SimAirServingZones::CompType::Invalid);
1042 902 : std::string CompType;
1043 902 : std::string const &CompName = state.dataWaterCoils->WaterCoil(tempCoilNum).Name;
1044 902 : if (state.dataWaterCoils->WaterCoil(tempCoilNum).WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterCooling) {
1045 309 : CoilTypeNum = SimAirServingZones::CompType::WaterCoil_Cooling;
1046 309 : CompType = HVAC::cAllCoilTypes(HVAC::Coil_CoolingWater);
1047 593 : } else if (state.dataWaterCoils->WaterCoil(tempCoilNum).WaterCoilType ==
1048 : DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling) {
1049 162 : CoilTypeNum = SimAirServingZones::CompType::WaterCoil_DetailedCool;
1050 162 : CompType = HVAC::cAllCoilTypes(HVAC::Coil_CoolingWaterDetailed);
1051 431 : } else if (state.dataWaterCoils->WaterCoil(tempCoilNum).WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterSimpleHeating) {
1052 431 : CoilTypeNum = SimAirServingZones::CompType::WaterCoil_SimpleHeat;
1053 431 : CompType = HVAC::cAllCoilTypes(HVAC::Coil_HeatingWater);
1054 : }
1055 902 : WaterCoilOnAirLoop = true;
1056 902 : SimAirServingZones::CheckWaterCoilIsOnAirLoop(state, CoilTypeNum, CompType, CompName, WaterCoilOnAirLoop);
1057 902 : if (!WaterCoilOnAirLoop) {
1058 0 : ShowContinueError(state,
1059 0 : format("Controller:WaterCoil = {}. Invalid water controller entry.",
1060 0 : state.dataWaterCoils->WaterCoil(tempCoilNum).ControllerName));
1061 0 : ErrorsFound = true;
1062 : }
1063 902 : }
1064 : }
1065 326 : state.dataWaterCoils->WaterCoilControllerCheckOneTimeFlag = false;
1066 326 : if (ErrorsFound) {
1067 0 : ShowFatalError(state, "Program terminated for previous condition.");
1068 : }
1069 : }
1070 :
1071 149968186 : auto &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
1072 149968186 : if (state.dataWaterCoils->PlantLoopScanFlag(CoilNum) && allocated(state.dataPlnt->PlantLoop)) {
1073 3351 : errFlag = false;
1074 3351 : PlantUtilities::ScanPlantLoopsForObject(state, waterCoil.Name, waterCoil.WaterCoilType, waterCoil.WaterPlantLoc, errFlag, _, _, _, _, _);
1075 3351 : if (errFlag) {
1076 0 : ShowFatalError(state, "InitWaterCoil: Program terminated for previous conditions.");
1077 : }
1078 3351 : state.dataWaterCoils->PlantLoopScanFlag(CoilNum) = false;
1079 : }
1080 149968186 : if (!state.dataGlobal->SysSizingCalc && state.dataWaterCoils->MySizeFlag(CoilNum)) {
1081 : // for each coil, do the sizing once.
1082 3351 : SizeWaterCoil(state, CoilNum);
1083 :
1084 3351 : state.dataWaterCoils->MySizeFlag(CoilNum) = false;
1085 : }
1086 :
1087 : // Do the Begin Environment initializations
1088 149968186 : if (state.dataGlobal->BeginEnvrnFlag && state.dataWaterCoils->MyEnvrnFlag(CoilNum)) {
1089 22164 : rho = state.dataPlnt->PlantLoop(waterCoil.WaterPlantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
1090 : // Initialize all report variables to a known state at beginning of simulation
1091 22164 : waterCoil.TotWaterHeatingCoilEnergy = 0.0;
1092 22164 : waterCoil.TotWaterCoolingCoilEnergy = 0.0;
1093 22164 : waterCoil.SenWaterCoolingCoilEnergy = 0.0;
1094 22164 : waterCoil.TotWaterHeatingCoilRate = 0.0;
1095 22164 : waterCoil.TotWaterCoolingCoilRate = 0.0;
1096 22164 : waterCoil.SenWaterCoolingCoilRate = 0.0;
1097 :
1098 : // The rest of the one time initializations
1099 22164 : AirInletNode = waterCoil.AirInletNodeNum;
1100 22164 : WaterInletNode = waterCoil.WaterInletNodeNum;
1101 22164 : WaterOutletNode = waterCoil.WaterOutletNodeNum;
1102 :
1103 22164 : state.dataWaterCoils->DesCpAir(CoilNum) = PsyCpAirFnW(0.0);
1104 22164 : state.dataWaterCoils->DesUARangeCheck(CoilNum) = (-1568.6 * waterCoil.DesInletAirHumRat + 20.157);
1105 :
1106 22164 : if ((waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterCooling) ||
1107 19302 : (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling)) { // 'Cooling'
1108 3867 : auto &waterInletNode = state.dataLoopNodes->Node(WaterInletNode);
1109 3867 : waterInletNode.Temp = 5.0;
1110 :
1111 3867 : Cp = state.dataPlnt->PlantLoop(waterCoil.WaterPlantLoc.loopNum).glycol->getSpecificHeat(state, waterInletNode.Temp, RoutineName);
1112 :
1113 3867 : waterInletNode.Enthalpy = Cp * waterInletNode.Temp;
1114 3867 : waterInletNode.Quality = 0.0;
1115 3867 : waterInletNode.Press = 0.0;
1116 3867 : waterInletNode.HumRat = 0.0;
1117 : }
1118 :
1119 22164 : if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterSimpleHeating) { // 'Heating'
1120 18297 : auto &waterInletNode = state.dataLoopNodes->Node(WaterInletNode);
1121 18297 : waterInletNode.Temp = 60.0;
1122 :
1123 18297 : Cp = state.dataPlnt->PlantLoop(waterCoil.WaterPlantLoc.loopNum).glycol->getSpecificHeat(state, waterInletNode.Temp, RoutineName);
1124 :
1125 18297 : waterInletNode.Enthalpy = Cp * waterInletNode.Temp;
1126 18297 : waterInletNode.Quality = 0.0;
1127 18297 : waterInletNode.Press = 0.0;
1128 18297 : waterInletNode.HumRat = 0.0;
1129 18297 : state.dataWaterCoils->MyUAAndFlowCalcFlag(CoilNum) = false;
1130 : // fill values for variable UA
1131 18297 : CpAirStd = PsyCpAirFnW(0.0);
1132 18297 : waterCoil.DesAirMassFlowRate = state.dataEnvrn->StdRhoAir * waterCoil.DesAirVolFlowRate;
1133 18297 : waterCoil.LiquidSideNominalConvect =
1134 18297 : waterCoil.UACoil * (waterCoil.RatioAirSideToWaterSideConvect + 1) / waterCoil.RatioAirSideToWaterSideConvect;
1135 18297 : waterCoil.AirSideNominalConvect = waterCoil.RatioAirSideToWaterSideConvect * waterCoil.LiquidSideNominalConvect;
1136 : } else {
1137 3867 : state.dataWaterCoils->MyUAAndFlowCalcFlag(CoilNum) = false;
1138 : }
1139 :
1140 22164 : waterCoil.MaxWaterMassFlowRate = rho * waterCoil.MaxWaterVolFlowRate;
1141 :
1142 22164 : PlantUtilities::InitComponentNodes(state, 0.0, waterCoil.MaxWaterMassFlowRate, waterCoil.WaterInletNodeNum, waterCoil.WaterOutletNodeNum);
1143 :
1144 : // effective fin diameter for detailed flat fin coil
1145 22164 : if (waterCoil.WaterCoilModel == CoilModel::CoolingDetailed) { // 'DETAILED FLAT FIN'
1146 1005 : waterCoil.EffectiveFinDiam =
1147 1005 : std::sqrt(4.0 * waterCoil.FinDiam * waterCoil.CoilDepth / (Constant::Pi * waterCoil.NumOfTubeRows * waterCoil.NumOfTubesPerRow));
1148 :
1149 : // calculate fixed geometric parameters of the coil:
1150 : // Total Area
1151 1005 : waterCoil.TotCoilOutsideSurfArea = waterCoil.TubeOutsideSurfArea + waterCoil.FinSurfArea;
1152 : // Effective Tube Inside Diameter - the model assumes that the coil
1153 : // can be simulated as a tube with an equivalent hydraulic diameter.
1154 1005 : waterCoil.CoilEffectiveInsideDiam = 4.0 * waterCoil.MinAirFlowArea * waterCoil.CoilDepth / waterCoil.TotCoilOutsideSurfArea;
1155 : // Ratio of tube outside diameter to effective fin diameter should always
1156 : // be less than 1
1157 1005 : TubeToFinDiamRatio = waterCoil.TubeOutsideDiam / waterCoil.EffectiveFinDiam;
1158 1005 : if (TubeToFinDiamRatio > 1.0) {
1159 0 : ShowWarningError(state, format("InitWaterCoil: Detailed Flat Fin Coil, TubetoFinDiamRatio > 1.0, [{:.4R}]", TubeToFinDiamRatio));
1160 : // reset tube depth spacing and recalc dependent parameters
1161 0 : waterCoil.TubeDepthSpacing *= (pow_2(TubeToFinDiamRatio) + 0.1);
1162 0 : waterCoil.CoilDepth = waterCoil.TubeDepthSpacing * waterCoil.NumOfTubeRows;
1163 0 : waterCoil.EffectiveFinDiam =
1164 0 : std::sqrt(4.0 * waterCoil.FinDiam * waterCoil.CoilDepth / (Constant::Pi * waterCoil.NumOfTubeRows * waterCoil.NumOfTubesPerRow));
1165 0 : waterCoil.CoilEffectiveInsideDiam = 4.0 * waterCoil.MinAirFlowArea * waterCoil.CoilDepth / waterCoil.TotCoilOutsideSurfArea;
1166 0 : TubeToFinDiamRatio = waterCoil.TubeOutsideDiam / waterCoil.EffectiveFinDiam;
1167 0 : ShowContinueError(state, format(" Resetting tube depth spacing to {:.4R} meters", waterCoil.TubeDepthSpacing));
1168 0 : ShowContinueError(state, format(" Resetting coil depth to {:.4R} meters", waterCoil.CoilDepth));
1169 : }
1170 :
1171 1005 : CalcDryFinEffCoef(state, TubeToFinDiamRatio, state.dataWaterCoils->CoefSeries);
1172 :
1173 1005 : waterCoil.DryFinEfficncyCoef = state.dataWaterCoils->CoefSeries;
1174 :
1175 1005 : FinDiamVar = 0.5 * (waterCoil.EffectiveFinDiam - waterCoil.TubeOutsideDiam);
1176 :
1177 1005 : waterCoil.GeometryCoef1 = 0.159 * std::pow(waterCoil.FinThickness / waterCoil.CoilEffectiveInsideDiam, -0.065) *
1178 1005 : std::pow(waterCoil.FinThickness / FinDiamVar, 0.141);
1179 1005 : waterCoil.GeometryCoef2 = -0.323 * std::pow(waterCoil.FinSpacing / FinDiamVar, 0.049) *
1180 1005 : std::pow(waterCoil.EffectiveFinDiam / waterCoil.TubeDepthSpacing, 0.549) *
1181 1005 : std::pow(waterCoil.FinThickness / waterCoil.FinSpacing, -0.028);
1182 :
1183 : // Set some initial values for simulation
1184 1005 : waterCoil.SatEnthlCurveConstCoef = -10.57;
1185 1005 : waterCoil.SatEnthlCurveSlope = 3.3867;
1186 1005 : waterCoil.EnthVsTempCurveAppxSlope = 3.3867;
1187 1005 : waterCoil.EnthVsTempCurveConst = -10.57;
1188 : // Set Saved Values to Zero
1189 1005 : waterCoil.SurfAreaWetSaved = 0.0;
1190 1005 : waterCoil.MeanWaterTempSaved = 0.0;
1191 1005 : waterCoil.InWaterTempSaved = 0.0;
1192 1005 : waterCoil.OutWaterTempSaved = 0.0;
1193 :
1194 : } // End the Detailed Flat Fin Coil Initialization
1195 :
1196 : // Calculation for Cooling Coil, The part between the '@@@' are design condition
1197 : // and are calculated only once to calculate standard values for UAs and other physical parameters of
1198 : // the cooling coil.
1199 : // Basic Idea for UA: Heat Transfer= UAenthalpybased*(Delta enthalpy), this is a necessity since the
1200 : // coil may be Wet or Dry or Partially Wet-Dry, so latent effects are accounted for in this model while
1201 : // calculating the UA. A fictitious specific heat is also defined to calculate the conventional UA.
1202 : // On the air side, enthalpy capacity rate is the air mass flow rate,while on water side it is
1203 : // enthalpy of saturated air at water temperature.
1204 : //@@@ DESIGN CONDITION BEGIN HERE @@@
1205 :
1206 : // Check for zero design cooling capacity as specified by coil design inputs
1207 41908 : if (state.dataWaterCoils->MyCoilDesignFlag(CoilNum) && (waterCoil.WaterCoilModel == CoilModel::CoolingSimple) &&
1208 41908 : (waterCoil.DesAirVolFlowRate > 0.0) && (waterCoil.MaxWaterMassFlowRate > 0.0)) {
1209 :
1210 432 : DesInletAirEnth = PsyHFnTdbW(waterCoil.DesInletAirTemp, waterCoil.DesInletAirHumRat);
1211 432 : DesOutletAirEnth = PsyHFnTdbW(waterCoil.DesOutletAirTemp, waterCoil.DesOutletAirHumRat);
1212 : DesSatEnthAtWaterInTemp =
1213 432 : PsyHFnTdbW(waterCoil.DesInletWaterTemp, PsyWFnTdpPb(state, waterCoil.DesInletWaterTemp, state.dataEnvrn->StdBaroPress));
1214 : // check for dry coil
1215 432 : DesHumRatAtWaterInTemp = PsyWFnTdbH(state, waterCoil.DesInletWaterTemp, DesSatEnthAtWaterInTemp, RoutineName);
1216 432 : if (DesHumRatAtWaterInTemp > waterCoil.DesOutletAirHumRat && waterCoil.DesOutletAirTemp > waterCoil.DesInletWaterTemp) {
1217 : // if the design outlet air humrat is lower than the saturated air humrat at the design inlet water temp
1218 : // and the design outlet air temperature is higher than the design inlet water temp (i.e, cooling possible),
1219 : // move the design outlet air saturated enthalpy down (i.e., to Twaterin, Wair,out) to allow the coil to size.
1220 36 : DesSatEnthAtWaterInTemp = PsyHFnTdbW(waterCoil.DesInletWaterTemp, waterCoil.DesOutletAirHumRat) - 0.0001;
1221 : }
1222 432 : if (DesOutletAirEnth >= DesInletAirEnth || waterCoil.DesInletWaterTemp >= waterCoil.DesInletAirTemp) {
1223 0 : ShowWarningError(state, format("The design cooling capacity is zero for Coil:Cooling:Water {}", waterCoil.Name));
1224 0 : ShowContinueError(state, " The maximum water flow rate for this coil will be set to zero and the coil will do no cooling.");
1225 0 : ShowContinueError(state,
1226 0 : format(" Check the following coil design inputs for problems: Tair,in = {:.4R}", waterCoil.DesInletAirTemp));
1227 0 : ShowContinueError(state,
1228 0 : format(" Wair,in = {:.6R}", waterCoil.DesInletAirHumRat));
1229 0 : ShowContinueError(state,
1230 0 : format(" Twater,in = {:.4R}", waterCoil.DesInletWaterTemp));
1231 0 : ShowContinueError(state,
1232 0 : format(" Tair,out = {:.4R}", waterCoil.DesOutletAirTemp));
1233 0 : ShowContinueError(state,
1234 0 : format(" Wair,out = {:.6R}", waterCoil.DesOutletAirHumRat));
1235 0 : waterCoil.MaxWaterVolFlowRate = 0.0;
1236 0 : waterCoil.MaxWaterMassFlowRate = 0.0;
1237 : }
1238 : }
1239 :
1240 41908 : if (state.dataWaterCoils->MyCoilDesignFlag(CoilNum) && (waterCoil.WaterCoilModel == CoilModel::CoolingSimple) &&
1241 41908 : (waterCoil.DesAirVolFlowRate > 0.0) && (waterCoil.MaxWaterMassFlowRate > 0.0)) { // 'Cooling'
1242 :
1243 432 : state.dataWaterCoils->MyCoilDesignFlag(CoilNum) = false;
1244 432 : state.dataWaterCoils->NoSatCurveIntersect = false;
1245 432 : state.dataWaterCoils->BelowInletWaterTemp = false;
1246 432 : state.dataWaterCoils->CBFTooLarge = false;
1247 432 : state.dataWaterCoils->NoExitCondReset = false;
1248 899 : for (Ipass = 1; Ipass <= 2; ++Ipass) {
1249 819 : if (Ipass == 2) {
1250 753 : if (!state.dataWaterCoils->NoSatCurveIntersect && !state.dataWaterCoils->BelowInletWaterTemp &&
1251 366 : !state.dataWaterCoils->CBFTooLarge) {
1252 307 : goto Inlet_Conditions_Loop_exit; // coil UA calcs OK
1253 : } else {
1254 80 : ShowWarningError(state, format("In calculating the design coil UA for Coil:Cooling:Water {}", waterCoil.Name));
1255 80 : if (state.dataWaterCoils->NoSatCurveIntersect) {
1256 45 : ShowContinueError(state, "no apparatus dew-point can be found for the initial entering and leaving conditions;");
1257 : }
1258 80 : if (state.dataWaterCoils->BelowInletWaterTemp) {
1259 24 : ShowContinueError(state, "the apparatus dew-point is below the coil design inlet water temperature;");
1260 : }
1261 80 : if (state.dataWaterCoils->CBFTooLarge) {
1262 180 : ShowContinueError(state, "the coil bypass factor is unrealistically large;");
1263 : }
1264 80 : if (!state.dataWaterCoils->NoExitCondReset) {
1265 24 : ShowContinueError(state, "the coil outlet design conditions will be changed to correct the problem.");
1266 : }
1267 80 : ShowContinueError(state, format("The initial design conditions are: Tair,in = {:.4R}", waterCoil.DesInletAirTemp));
1268 80 : ShowContinueError(state, format(" Wair,in = {:.6R}", waterCoil.DesInletAirHumRat));
1269 80 : ShowContinueError(state, format(" Twater,in = {:.4R}", waterCoil.DesInletWaterTemp));
1270 80 : ShowContinueError(state, format(" Tair,out = {:.4R}", waterCoil.DesOutletAirTemp));
1271 80 : ShowContinueError(state, format(" Wair,out = {:.6R}", waterCoil.DesOutletAirHumRat));
1272 80 : if (!state.dataWaterCoils->NoExitCondReset) {
1273 8 : ShowContinueError(state, format("The revised design conditions are: Tair,out = {:.4R}", state.dataWaterCoils->TOutNew));
1274 8 : ShowContinueError(state, format(" Wair,out = {:.6R}", state.dataWaterCoils->WOutNew));
1275 8 : waterCoil.DesOutletAirHumRat = state.dataWaterCoils->WOutNew;
1276 8 : waterCoil.DesOutletAirTemp = state.dataWaterCoils->TOutNew;
1277 : // update outlet air conditions used for sizing
1278 8 : std::string CompType;
1279 8 : if (waterCoil.WaterCoilModel == CoilModel::CoolingDetailed) {
1280 0 : CompType = HVAC::cAllCoilTypes(HVAC::Coil_CoolingWaterDetailed);
1281 : } else {
1282 8 : CompType = HVAC::cAllCoilTypes(HVAC::Coil_CoolingWater);
1283 : }
1284 8 : state.dataRptCoilSelection->coilSelectionReportObj->setCoilLvgAirTemp(
1285 8 : state, waterCoil.Name, CompType, state.dataWaterCoils->TOutNew);
1286 8 : state.dataRptCoilSelection->coilSelectionReportObj->setCoilLvgAirHumRat(
1287 8 : state, waterCoil.Name, CompType, state.dataWaterCoils->WOutNew);
1288 : // end update outlet air conditions used for sizing
1289 8 : }
1290 : }
1291 : }
1292 :
1293 : // Volume flow rate being converted to mass flow rate for water
1294 512 : waterCoil.DesAirMassFlowRate = state.dataEnvrn->StdRhoAir * waterCoil.DesAirVolFlowRate;
1295 :
1296 : // Enthalpy of Air at Inlet design conditions
1297 512 : DesInletAirEnth = PsyHFnTdbW(waterCoil.DesInletAirTemp, waterCoil.DesInletAirHumRat);
1298 :
1299 : // Enthalpy of Air at outlet at design conditions
1300 512 : DesOutletAirEnth = PsyHFnTdbW(waterCoil.DesOutletAirTemp, waterCoil.DesOutletAirHumRat);
1301 :
1302 : // already calculated above and possibly reset if dry coil
1303 : // ! Enthalpy of Water at Inlet design conditions
1304 : // DesSatEnthAtWaterInTemp =PsyHFnTdbW(WaterCoil(CoilNum)%DesInletWaterTemp, &
1305 : // PsyWFnTdpPb(state, WaterCoil(CoilNum)%DesInletWaterTemp,StdBaroPress))
1306 :
1307 : // Total Coil Load from Inlet and Outlet Air States (which include fan heat as appropriate).
1308 512 : waterCoil.DesTotWaterCoilLoad = waterCoil.DesAirMassFlowRate * (DesInletAirEnth - DesOutletAirEnth);
1309 :
1310 : // Enthalpy of Water at Inlet design conditions
1311 512 : Cp = state.dataPlnt->PlantLoop(waterCoil.WaterPlantLoc.loopNum)
1312 512 : .glycol->getSpecificHeat(state, waterCoil.DesInletWaterTemp, RoutineName);
1313 :
1314 512 : DesOutletWaterTemp = waterCoil.DesInletWaterTemp + waterCoil.DesTotWaterCoilLoad / (waterCoil.MaxWaterMassFlowRate * Cp);
1315 :
1316 512 : DesSatEnthAtWaterOutTemp = PsyHFnTdbW(DesOutletWaterTemp, PsyWFnTdpPb(state, DesOutletWaterTemp, state.dataEnvrn->StdBaroPress));
1317 512 : DesEnthAtWaterOutTempAirInHumRat = PsyHFnTdbW(DesOutletWaterTemp, waterCoil.DesInletAirHumRat);
1318 512 : DesEnthWaterOut = min(DesSatEnthAtWaterOutTemp, DesEnthAtWaterOutTempAirInHumRat);
1319 :
1320 : // dry coil test
1321 512 : if (waterCoil.DesOutletAirHumRat < waterCoil.DesInletAirHumRat && DesHumRatAtWaterInTemp < waterCoil.DesInletAirHumRat) { // wet coil
1322 :
1323 : // Calculations for BYPASS FACTOR at design conditions
1324 : // Calculate "slope" of temperature vs. humidity ratio between entering and leaving states
1325 934 : SlopeTempVsHumRatio = (waterCoil.DesInletAirTemp - waterCoil.DesOutletAirTemp) /
1326 467 : max((waterCoil.DesInletAirHumRat - waterCoil.DesOutletAirHumRat), SmallNo);
1327 :
1328 : // Initialize iteration parameters
1329 467 : DesAirTempApparatusDewPt = PsyTdpFnWPb(state, waterCoil.DesOutletAirHumRat, state.dataEnvrn->OutBaroPress);
1330 :
1331 : // Iterating to calculate Apparatus Dew Point Temperature at Design Conditions
1332 2410 : for (iter = 1; iter <= itmax; ++iter) {
1333 :
1334 : // Calculate apparatus dewpoint and compare with predicted value
1335 : // using entering conditions and SlopeTempVsHumRatio
1336 2410 : DesAirHumRatApparatusDewPt = PsyWFnTdpPb(state, DesAirTempApparatusDewPt, state.dataEnvrn->OutBaroPress);
1337 :
1338 : // Initial Estimate for apparatus Dew Point Temperature
1339 2410 : TempApparatusDewPtEstimate =
1340 2410 : waterCoil.DesInletAirTemp - SlopeTempVsHumRatio * (waterCoil.DesInletAirHumRat - DesAirHumRatApparatusDewPt);
1341 :
1342 : // Iterating to calculate Apparatus Dew Point Temperature at Design Condition
1343 2410 : error = DesAirTempApparatusDewPt - TempApparatusDewPtEstimate;
1344 2410 : General::Iterate(ResultX, 0.01, DesAirTempApparatusDewPt, error, X1, Y1, iter, icvg);
1345 2410 : DesAirTempApparatusDewPt = ResultX;
1346 :
1347 : // If converged, exit loop
1348 2410 : if (icvg == 1) {
1349 439 : goto App_DewPoint_Loop1_exit;
1350 : }
1351 :
1352 : // If not converged due to low Humidity Ratio approximate value at outlet conditions
1353 1971 : if (iter == itmax) {
1354 28 : state.dataWaterCoils->NoSatCurveIntersect = true;
1355 28 : DesAirTempApparatusDewPt = PsyTdpFnWPb(state, waterCoil.DesOutletAirHumRat, state.dataEnvrn->OutBaroPress);
1356 28 : DesAirHumRatApparatusDewPt = PsyWFnTdpPb(state, DesAirTempApparatusDewPt, state.dataEnvrn->OutBaroPress);
1357 28 : goto App_DewPoint_Loop1_exit;
1358 : }
1359 :
1360 : // End of Loop for Iteration
1361 : }
1362 0 : App_DewPoint_Loop1_exit:;
1363 :
1364 : // Air enthalpy at apparatus dew point at design conditions
1365 467 : DesAirApparatusDewPtEnth = PsyHFnTdbW(DesAirTempApparatusDewPt, DesAirHumRatApparatusDewPt);
1366 :
1367 : // Calculate bypass factor from enthalpies calculated above.
1368 467 : DesBypassFactor = (DesOutletAirEnth - DesAirApparatusDewPtEnth) / (DesInletAirEnth - DesAirApparatusDewPtEnth);
1369 :
1370 : // Check for bypass factor for unsuitable value. Note that bypass factor is never used in the coil calculation
1371 467 : if ((DesBypassFactor > 0.5) || (DesBypassFactor < 0.0)) {
1372 120 : state.dataWaterCoils->CBFTooLarge = true;
1373 120 : DesBypassFactor = 0.37;
1374 : }
1375 :
1376 467 : if (DesEnthWaterOut > DesInletAirEnth) {
1377 0 : ShowWarningError(state, format("In calculating the design coil UA for Coil:Cooling:Water {}", waterCoil.Name));
1378 0 : ShowContinueError(state, "the outlet chilled water design enthalpy is greater than the inlet air design enthalpy.");
1379 0 : ShowContinueError(state,
1380 0 : format("To correct this condition the design chilled water flow rate will be increased from {:.5R}",
1381 0 : waterCoil.MaxWaterVolFlowRate));
1382 0 : EnthCorrFrac = (DesEnthWaterOut - DesInletAirEnth) / (DesEnthWaterOut - DesSatEnthAtWaterInTemp);
1383 0 : waterCoil.MaxWaterVolFlowRate *= (1.0 + 2.0 * EnthCorrFrac);
1384 0 : ShowContinueError(state, format("to {:.5R} m3/s", waterCoil.MaxWaterVolFlowRate));
1385 0 : waterCoil.MaxWaterMassFlowRate = rho * waterCoil.MaxWaterVolFlowRate;
1386 0 : DesOutletWaterTemp = waterCoil.DesInletWaterTemp + waterCoil.DesTotWaterCoilLoad / (waterCoil.MaxWaterMassFlowRate * Cp);
1387 : DesSatEnthAtWaterOutTemp =
1388 0 : PsyHFnTdbW(DesOutletWaterTemp, PsyWFnTdpPb(state, DesOutletWaterTemp, state.dataEnvrn->StdBaroPress));
1389 0 : DesEnthAtWaterOutTempAirInHumRat = PsyHFnTdbW(DesOutletWaterTemp, waterCoil.DesInletAirHumRat);
1390 0 : DesEnthWaterOut = min(DesSatEnthAtWaterOutTemp, DesEnthAtWaterOutTempAirInHumRat);
1391 : }
1392 :
1393 : // Determine air-side coefficient, UACoilExternal, assuming that the
1394 : // surface temperature is at the apparatus dewpoint temperature
1395 467 : if (DesAirApparatusDewPtEnth <= DesSatEnthAtWaterInTemp) {
1396 11 : state.dataWaterCoils->BelowInletWaterTemp = true;
1397 : }
1398 467 : if ((DesInletAirEnth - DesEnthWaterOut) > SmallNo && (DesOutletAirEnth - DesSatEnthAtWaterInTemp) > SmallNo) {
1399 467 : LogMeanEnthDiff = ((DesInletAirEnth - DesEnthWaterOut) - (DesOutletAirEnth - DesSatEnthAtWaterInTemp)) /
1400 467 : std::log((DesInletAirEnth - DesEnthWaterOut) / (DesOutletAirEnth - DesSatEnthAtWaterInTemp));
1401 : } else {
1402 0 : LogMeanEnthDiff = 2000.0; // UA will be 1/2 the design coil load
1403 : }
1404 467 : DesUACoilExternalEnth = waterCoil.DesTotWaterCoilLoad / LogMeanEnthDiff;
1405 467 : waterCoil.UACoilExternal = DesUACoilExternalEnth * PsyCpAirFnW(waterCoil.DesInletAirHumRat);
1406 :
1407 779 : if (Ipass == 1 && (state.dataWaterCoils->NoSatCurveIntersect || state.dataWaterCoils->CBFTooLarge ||
1408 312 : state.dataWaterCoils->BelowInletWaterTemp)) {
1409 : // reset outlet conditions to 90% relative humidity at the same outlet enthalpy
1410 80 : state.dataWaterCoils->TOutNew = TdbFnHRhPb(state, DesOutletAirEnth, 0.9, state.dataEnvrn->StdBaroPress);
1411 80 : state.dataWaterCoils->WOutNew = PsyWFnTdbH(state, state.dataWaterCoils->TOutNew, DesOutletAirEnth);
1412 159 : if (state.dataWaterCoils->WOutNew >= waterCoil.DesInletAirHumRat ||
1413 79 : state.dataWaterCoils->TOutNew > waterCoil.DesOutletAirTemp) {
1414 72 : state.dataWaterCoils->NoExitCondReset = true;
1415 : }
1416 80 : goto Inlet_Conditions_Loop_loop;
1417 : }
1418 :
1419 387 : waterCoil.UACoilInternal = waterCoil.UACoilExternal * 3.30;
1420 : // Overall heat transfer coefficient
1421 387 : waterCoil.UACoilTotal = 1.0 / (1.0 / waterCoil.UACoilExternal + 1.0 / waterCoil.UACoilInternal);
1422 :
1423 : } else { // dry coil
1424 :
1425 45 : if (DesOutletWaterTemp > waterCoil.DesInletAirTemp) {
1426 0 : ShowWarningError(state, format("In calculating the design coil UA for Coil:Cooling:Water {}", waterCoil.Name));
1427 0 : ShowContinueError(state, "the outlet chilled water design temperature is greater than the inlet air design temperature.");
1428 0 : ShowContinueError(state,
1429 0 : format("To correct this condition the design chilled water flow rate will be increased from {:.5R}",
1430 0 : waterCoil.MaxWaterVolFlowRate));
1431 0 : TempCorrFrac = (DesOutletWaterTemp - waterCoil.DesInletAirTemp) / (DesOutletWaterTemp - waterCoil.DesInletWaterTemp);
1432 0 : waterCoil.MaxWaterVolFlowRate *= (1.0 + 2.0 * TempCorrFrac);
1433 0 : ShowContinueError(state, format("to {:.5R} m3/s", waterCoil.MaxWaterVolFlowRate));
1434 0 : waterCoil.MaxWaterMassFlowRate = rho * waterCoil.MaxWaterVolFlowRate;
1435 0 : DesOutletWaterTemp = waterCoil.DesInletWaterTemp + waterCoil.DesTotWaterCoilLoad / (waterCoil.MaxWaterMassFlowRate * Cp);
1436 : }
1437 :
1438 45 : if ((waterCoil.DesInletAirTemp - DesOutletWaterTemp) > SmallNo &&
1439 45 : (waterCoil.DesOutletAirTemp - waterCoil.DesInletWaterTemp) > SmallNo) {
1440 45 : LogMeanTempDiff =
1441 45 : ((waterCoil.DesInletAirTemp - DesOutletWaterTemp) - (waterCoil.DesOutletAirTemp - waterCoil.DesInletWaterTemp)) /
1442 45 : std::log((waterCoil.DesInletAirTemp - DesOutletWaterTemp) / (waterCoil.DesOutletAirTemp - waterCoil.DesInletWaterTemp));
1443 45 : waterCoil.UACoilExternal = waterCoil.DesTotWaterCoilLoad / LogMeanTempDiff;
1444 : } else {
1445 0 : waterCoil.UACoilExternal = waterCoil.DesTotWaterCoilLoad / 2.0; // make the UA large
1446 : }
1447 45 : waterCoil.UACoilInternal = waterCoil.UACoilExternal * 3.30;
1448 : // Overall heat transfer coefficient
1449 45 : waterCoil.UACoilTotal = 1.0 / (1.0 / waterCoil.UACoilExternal + 1.0 / waterCoil.UACoilInternal);
1450 45 : goto Inlet_Conditions_Loop_exit;
1451 : }
1452 :
1453 467 : Inlet_Conditions_Loop_loop:;
1454 : }
1455 80 : Inlet_Conditions_Loop_exit:;
1456 :
1457 : // estimate the heat external transfer surface area using typical design over all U value
1458 432 : waterCoil.TotCoilOutsideSurfArea = EstimateHEXSurfaceArea(state, CoilNum);
1459 : // calculate internal and external "UA per external surface area"
1460 432 : waterCoil.UACoilInternalPerUnitArea = waterCoil.UACoilInternal / waterCoil.TotCoilOutsideSurfArea;
1461 432 : waterCoil.UAWetExtPerUnitArea = waterCoil.UACoilExternal / waterCoil.TotCoilOutsideSurfArea;
1462 : // approximate the dry UA as 1.0 times wet UA
1463 432 : waterCoil.UADryExtPerUnitArea = waterCoil.UAWetExtPerUnitArea;
1464 :
1465 : // Now use SolveRoot to "invert" the cooling coil model to obtain the UA given the specified design inlet and outlet conditions
1466 : // Note that the UAs we have obtained so far are rough estimates that are the starting points for the the following iterative
1467 : // calculation of the actual UAs.
1468 432 : waterCoil.InletAirTemp = waterCoil.DesInletAirTemp;
1469 432 : waterCoil.InletAirHumRat = waterCoil.DesInletAirHumRat;
1470 432 : waterCoil.InletWaterTemp = waterCoil.DesInletWaterTemp;
1471 432 : waterCoil.InletWaterMassFlowRate = rho * waterCoil.MaxWaterVolFlowRate;
1472 432 : waterCoil.InletAirMassFlowRate = waterCoil.DesAirMassFlowRate;
1473 : // set the lower and upper limits on the UA
1474 432 : UA0 = 0.1 * waterCoil.UACoilExternal;
1475 432 : UA1 = 10.0 * waterCoil.UACoilExternal;
1476 : // Invert the simple cooling coil model: given the design inlet conditions and the design load, find the design UA
1477 8641 : auto f = [&state, CoilNum](Real64 const UA) {
1478 8641 : HVAC::FanOp fanOp = HVAC::FanOp::Continuous;
1479 8641 : Real64 PartLoadRatio = 1.0;
1480 8641 : auto &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
1481 8641 : waterCoil.UACoilExternal = UA;
1482 8641 : waterCoil.UACoilInternal = waterCoil.UACoilExternal * 3.3;
1483 8641 : waterCoil.UACoilTotal = 1.0 / (1.0 / waterCoil.UACoilExternal + 1.0 / waterCoil.UACoilInternal);
1484 8641 : waterCoil.TotCoilOutsideSurfArea = EstimateHEXSurfaceArea(state, CoilNum);
1485 8641 : waterCoil.UACoilInternalPerUnitArea = waterCoil.UACoilInternal / waterCoil.TotCoilOutsideSurfArea;
1486 8641 : waterCoil.UAWetExtPerUnitArea = waterCoil.UACoilExternal / waterCoil.TotCoilOutsideSurfArea;
1487 8641 : waterCoil.UADryExtPerUnitArea = waterCoil.UAWetExtPerUnitArea;
1488 :
1489 8641 : CoolingCoil(state, CoilNum, true, state.dataWaterCoils->DesignCalc, fanOp, PartLoadRatio);
1490 :
1491 8641 : return (waterCoil.DesTotWaterCoilLoad - waterCoil.TotWaterCoolingCoilRate) / waterCoil.DesTotWaterCoilLoad;
1492 432 : };
1493 432 : General::SolveRoot(state, 0.001, MaxIte, SolFla, UA, f, UA0, UA1);
1494 : // if the numerical inversion failed, issue error messages.
1495 432 : if (SolFla == -1) {
1496 0 : ShowSevereError(state, format("Calculation of cooling coil design UA failed for coil {}", waterCoil.Name));
1497 0 : ShowContinueError(state, " Iteration limit exceeded in calculating coil UA");
1498 0 : waterCoil.UACoilExternal = UA0 * 10.0;
1499 0 : waterCoil.UACoilInternal = waterCoil.UACoilExternal * 3.3;
1500 0 : waterCoil.UACoilTotal = 1.0 / (1.0 / waterCoil.UACoilExternal + 1.0 / waterCoil.UACoilInternal);
1501 0 : waterCoil.TotCoilOutsideSurfArea = EstimateHEXSurfaceArea(state, CoilNum);
1502 0 : waterCoil.UACoilInternalPerUnitArea = waterCoil.UACoilInternal / waterCoil.TotCoilOutsideSurfArea;
1503 0 : waterCoil.UAWetExtPerUnitArea = waterCoil.UACoilExternal / waterCoil.TotCoilOutsideSurfArea;
1504 0 : waterCoil.UADryExtPerUnitArea = waterCoil.UAWetExtPerUnitArea;
1505 0 : ShowContinueError(state, format(" Coil design UA set to {:.6R} [W/C]", waterCoil.UACoilTotal));
1506 432 : } else if (SolFla == -2) {
1507 12 : ShowSevereError(state, format("Calculation of cooling coil design UA failed for coil {}", waterCoil.Name));
1508 24 : ShowContinueError(state, " Bad starting values for UA");
1509 12 : waterCoil.UACoilExternal = UA0 * 10.0;
1510 12 : waterCoil.UACoilInternal = waterCoil.UACoilExternal * 3.3;
1511 12 : waterCoil.UACoilTotal = 1.0 / (1.0 / waterCoil.UACoilExternal + 1.0 / waterCoil.UACoilInternal);
1512 12 : waterCoil.TotCoilOutsideSurfArea = EstimateHEXSurfaceArea(state, CoilNum);
1513 12 : waterCoil.UACoilInternalPerUnitArea = waterCoil.UACoilInternal / waterCoil.TotCoilOutsideSurfArea;
1514 12 : waterCoil.UAWetExtPerUnitArea = waterCoil.UACoilExternal / waterCoil.TotCoilOutsideSurfArea;
1515 12 : waterCoil.UADryExtPerUnitArea = waterCoil.UAWetExtPerUnitArea;
1516 12 : ShowContinueError(state, format(" Coil design UA set to {:.6R} [W/C]", waterCoil.UACoilTotal));
1517 : }
1518 :
1519 : // cooling coil surface area
1520 432 : state.dataWaterCoils->SurfaceArea = waterCoil.TotCoilOutsideSurfArea;
1521 :
1522 : // cooling coil overall UA value
1523 432 : state.dataWaterCoils->UATotal = waterCoil.UACoilTotal;
1524 :
1525 : // save the design internal and external UAs
1526 432 : waterCoil.UACoilExternalDes = waterCoil.UACoilExternal;
1527 432 : waterCoil.UACoilInternalDes = waterCoil.UACoilInternal;
1528 : }
1529 :
1530 : //@@@@ DESIGN CONDITION END HERE @@@@
1531 :
1532 : // Calculate rated Total, latent, sensible capacity, SHR, effectiveness
1533 22164 : if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterSimpleHeating) {
1534 18297 : waterCoil.InletAirTemp = 16.6;
1535 18297 : waterCoil.InletAirHumRat = PsyWFnTdbRhPb(state, 16.6, 0.5, state.dataEnvrn->StdBaroPress, RoutineName);
1536 18297 : waterCoil.InletWaterTemp = 82.2;
1537 : } else {
1538 3867 : waterCoil.InletAirTemp = 26.67;
1539 3867 : waterCoil.InletAirHumRat = PsyWFnTdbTwbPb(state, 26.67, 19.44, state.dataEnvrn->StdBaroPress, RoutineName);
1540 3867 : waterCoil.InletWaterTemp = 6.67;
1541 : }
1542 22164 : waterCoil.InletAirEnthalpy = PsyHFnTdbW(waterCoil.InletAirTemp, waterCoil.InletAirHumRat);
1543 22164 : waterCoil.InletWaterMassFlowRate = waterCoil.MaxWaterMassFlowRate;
1544 22164 : waterCoil.InletAirMassFlowRate = state.dataEnvrn->StdRhoAir * waterCoil.DesAirVolFlowRate;
1545 22164 : CapacitanceAir = waterCoil.InletAirMassFlowRate * PsyCpAirFnW(waterCoil.InletAirHumRat);
1546 :
1547 22164 : Cp = state.dataPlnt->PlantLoop(waterCoil.WaterPlantLoc.loopNum).glycol->getSpecificHeat(state, waterCoil.InletWaterTemp, RoutineName);
1548 :
1549 22164 : state.dataWaterCoils->CapacitanceWater = waterCoil.InletWaterMassFlowRate * Cp;
1550 22164 : state.dataWaterCoils->CMin = min(CapacitanceAir, state.dataWaterCoils->CapacitanceWater);
1551 22164 : if (state.dataWaterCoils->CMin > 0.0) {
1552 21893 : if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterCooling) {
1553 2852 : CoolingCoil(state, CoilNum, FirstHVACIteration, state.dataWaterCoils->DesignCalc, HVAC::FanOp::Continuous, 1.0);
1554 8556 : state.dataWaterCoils->CoilEffectiveness = (waterCoil.InletAirTemp - waterCoil.OutletAirTemp) /
1555 5704 : (waterCoil.InletAirTemp - waterCoil.InletWaterTemp) *
1556 2852 : (CapacitanceAir / state.dataWaterCoils->CMin);
1557 2852 : state.dataWaterCoils->RatedLatentCapacity = waterCoil.TotWaterCoolingCoilRate - waterCoil.SenWaterCoolingCoilRate;
1558 2852 : state.dataWaterCoils->RatedSHR = waterCoil.SenWaterCoolingCoilRate / waterCoil.TotWaterCoolingCoilRate;
1559 19041 : } else if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling) {
1560 1005 : CalcDetailFlatFinCoolingCoil(state, CoilNum, state.dataWaterCoils->DesignCalc, HVAC::FanOp::Continuous, 1.0);
1561 3015 : state.dataWaterCoils->CoilEffectiveness = (waterCoil.InletAirTemp - waterCoil.OutletAirTemp) /
1562 2010 : (waterCoil.InletAirTemp - waterCoil.InletWaterTemp) *
1563 1005 : (CapacitanceAir / state.dataWaterCoils->CMin);
1564 1005 : state.dataWaterCoils->RatedLatentCapacity = waterCoil.TotWaterCoolingCoilRate - waterCoil.SenWaterCoolingCoilRate;
1565 1005 : state.dataWaterCoils->RatedSHR = waterCoil.SenWaterCoolingCoilRate / waterCoil.TotWaterCoolingCoilRate;
1566 18036 : } else if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterSimpleHeating) {
1567 18036 : CalcSimpleHeatingCoil(state, CoilNum, HVAC::FanOp::Continuous, 1.0, state.dataWaterCoils->DesignCalc);
1568 18036 : state.dataWaterCoils->CoilEffectiveness = (waterCoil.OutletAirTemp - waterCoil.InletAirTemp) /
1569 36072 : (waterCoil.InletWaterTemp - waterCoil.InletAirTemp) *
1570 18036 : (CapacitanceAir / state.dataWaterCoils->CMin);
1571 : }
1572 : } else {
1573 271 : state.dataWaterCoils->CoilEffectiveness = 0.0;
1574 271 : waterCoil.TotWaterHeatingCoilRate = 0.0;
1575 271 : waterCoil.TotWaterCoolingCoilRate = 0.0;
1576 271 : waterCoil.SenWaterCoolingCoilRate = 0.0;
1577 271 : state.dataWaterCoils->RatedLatentCapacity = 0.0;
1578 271 : state.dataWaterCoils->RatedSHR = 0.0;
1579 : }
1580 22164 : state.dataWaterCoils->MyEnvrnFlag(CoilNum) = false;
1581 :
1582 : } // End If for the Begin Environment initializations
1583 :
1584 149968186 : if (!state.dataGlobal->BeginEnvrnFlag) {
1585 149579089 : state.dataWaterCoils->MyEnvrnFlag(CoilNum) = true;
1586 : }
1587 :
1588 149968186 : if (!state.dataGlobal->DoingSizing) {
1589 149965851 : if (state.dataWaterCoils->MyCoilReportFlag(CoilNum)) {
1590 : // create predefined report entries
1591 3351 : state.dataWaterCoils->MyCoilReportFlag(CoilNum) = false;
1592 3351 : switch (waterCoil.WaterCoilType) {
1593 2755 : case DataPlant::PlantEquipmentType::CoilWaterSimpleHeating: {
1594 2755 : if (state.dataWaterCoils->RptCoilHeaderFlag(1)) {
1595 314 : print(state.files.eio, "{}", "! <Water Heating Coil Capacity Information>,Component Type,Name,Nominal Total Capacity {W}\n");
1596 314 : state.dataWaterCoils->RptCoilHeaderFlag(1) = false;
1597 : }
1598 2755 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchHeatCoilType, waterCoil.Name, "Coil:Heating:Water");
1599 5510 : OutputReportPredefined::PreDefTableEntry(
1600 2755 : state, state.dataOutRptPredefined->pdchHeatCoilDesCap, waterCoil.Name, waterCoil.DesWaterHeatingCoilRate);
1601 5510 : OutputReportPredefined::PreDefTableEntry(
1602 2755 : state, state.dataOutRptPredefined->pdchHeatCoilNomCap, waterCoil.Name, waterCoil.TotWaterHeatingCoilRate);
1603 2755 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchHeatCoilNomEff, waterCoil.Name, "-");
1604 5510 : OutputReportPredefined::addFootNoteSubTable(
1605 : state,
1606 2755 : state.dataOutRptPredefined->pdstHeatCoil,
1607 : "Nominal values are gross at rated conditions, i.e., the supply air fan heat and electric power NOT accounted for.");
1608 2755 : print(state.files.eio,
1609 : "{},{},{:.2R}\n",
1610 : "Water Heating Coil Capacity Information,Coil:Heating:Water",
1611 2755 : waterCoil.Name,
1612 2755 : waterCoil.TotWaterHeatingCoilRate);
1613 8265 : state.dataRptCoilSelection->coilSelectionReportObj->setCoilAirFlow(
1614 5510 : state, waterCoil.Name, "Coil:Heating:Water", waterCoil.DesAirVolFlowRate, waterCoil.RequestingAutoSize);
1615 8265 : state.dataRptCoilSelection->coilSelectionReportObj->setCoilWaterHeaterCapacityNodeNums(
1616 : state,
1617 2755 : waterCoil.Name,
1618 : "Coil:Heating:Water",
1619 : waterCoil.DesWaterHeatingCoilRate,
1620 2755 : waterCoil.RequestingAutoSize,
1621 : waterCoil.WaterInletNodeNum,
1622 : waterCoil.WaterOutletNodeNum,
1623 : waterCoil.WaterPlantLoc.loopNum); // coil report
1624 2755 : break;
1625 : }
1626 162 : case DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling: {
1627 162 : if (state.dataWaterCoils->RptCoilHeaderFlag(2)) {
1628 119 : print(state.files.eio,
1629 : "{}\n",
1630 : "! <Water Cooling Coil Capacity Information>,Component Type,Name,Nominal Total "
1631 : "Capacity {W},Nominal Sensible Capacity {W},Nominal Latent Capacity {W},Nominal "
1632 : "Sensible Heat Ratio");
1633 119 : state.dataWaterCoils->RptCoilHeaderFlag(2) = false;
1634 : }
1635 162 : state.dataWaterCoils->RatedLatentCapacity = waterCoil.TotWaterCoolingCoilRate - waterCoil.SenWaterCoolingCoilRate;
1636 162 : state.dataWaterCoils->RatedSHR = General::SafeDivide(waterCoil.SenWaterCoolingCoilRate, waterCoil.TotWaterCoolingCoilRate);
1637 324 : OutputReportPredefined::PreDefTableEntry(
1638 162 : state, state.dataOutRptPredefined->pdchCoolCoilType, waterCoil.Name, "Coil:Cooling:Water:DetailedGeometry");
1639 324 : OutputReportPredefined::PreDefTableEntry(
1640 162 : state, state.dataOutRptPredefined->pdchCoolCoilDesCap, waterCoil.Name, waterCoil.DesWaterCoolingCoilRate);
1641 324 : OutputReportPredefined::PreDefTableEntry(
1642 162 : state, state.dataOutRptPredefined->pdchCoolCoilTotCap, waterCoil.Name, waterCoil.TotWaterCoolingCoilRate);
1643 324 : OutputReportPredefined::PreDefTableEntry(
1644 162 : state, state.dataOutRptPredefined->pdchCoolCoilSensCap, waterCoil.Name, waterCoil.SenWaterCoolingCoilRate);
1645 486 : OutputReportPredefined::PreDefTableEntry(
1646 324 : state, state.dataOutRptPredefined->pdchCoolCoilLatCap, waterCoil.Name, state.dataWaterCoils->RatedLatentCapacity);
1647 486 : OutputReportPredefined::PreDefTableEntry(
1648 324 : state, state.dataOutRptPredefined->pdchCoolCoilSHR, waterCoil.Name, state.dataWaterCoils->RatedSHR);
1649 162 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchCoolCoilNomEff, waterCoil.Name, "-");
1650 324 : OutputReportPredefined::addFootNoteSubTable(
1651 : state,
1652 162 : state.dataOutRptPredefined->pdstCoolCoil,
1653 : "Nominal values are gross at rated conditions, i.e., the supply air fan heat and electric power NOT accounted for.");
1654 162 : print(state.files.eio,
1655 : "{},{},{:.2R},{:.2R},{:.2R},{:.2R}\n",
1656 : "Water Cooling Coil Capacity Information,Coil:Cooling:Water:DetailedGeometry",
1657 162 : waterCoil.Name,
1658 162 : waterCoil.TotWaterCoolingCoilRate,
1659 162 : waterCoil.SenWaterCoolingCoilRate,
1660 162 : state.dataWaterCoils->RatedLatentCapacity,
1661 162 : state.dataWaterCoils->RatedSHR);
1662 486 : state.dataRptCoilSelection->coilSelectionReportObj->setCoilAirFlow(state,
1663 162 : waterCoil.Name,
1664 : "Coil:Cooling:Water:DetailedGeometry",
1665 : waterCoil.DesAirVolFlowRate,
1666 162 : waterCoil.RequestingAutoSize); // Coil Report
1667 486 : state.dataRptCoilSelection->coilSelectionReportObj->setCoilWaterCoolingCapacity(state,
1668 162 : waterCoil.Name,
1669 : "Coil:Cooling:Water:DetailedGeometry",
1670 : waterCoil.DesWaterCoolingCoilRate,
1671 162 : waterCoil.RequestingAutoSize,
1672 : waterCoil.WaterInletNodeNum,
1673 : waterCoil.WaterOutletNodeNum,
1674 : waterCoil.WaterPlantLoc.loopNum); // Coil Report
1675 162 : break;
1676 : }
1677 434 : case DataPlant::PlantEquipmentType::CoilWaterCooling: {
1678 434 : if (state.dataWaterCoils->RptCoilHeaderFlag(2)) {
1679 191 : print(state.files.eio,
1680 : "{}\n",
1681 : "! <Water Cooling Coil Capacity Information>,Component Type,Name,Nominal Total "
1682 : "Capacity {W},Nominal Sensible Capacity {W},Nominal Latent Capacity {W},Nominal "
1683 : "Sensible Heat Ratio, Nominal Coil UA Value {W/C}, Nominal Coil Surface Area {m2}");
1684 191 : state.dataWaterCoils->RptCoilHeaderFlag(2) = false;
1685 : }
1686 434 : state.dataWaterCoils->RatedLatentCapacity = waterCoil.TotWaterCoolingCoilRate - waterCoil.SenWaterCoolingCoilRate;
1687 434 : state.dataWaterCoils->RatedSHR = General::SafeDivide(waterCoil.SenWaterCoolingCoilRate, waterCoil.TotWaterCoolingCoilRate);
1688 434 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchCoolCoilType, waterCoil.Name, "Coil:Cooling:Water");
1689 868 : OutputReportPredefined::PreDefTableEntry(
1690 434 : state, state.dataOutRptPredefined->pdchCoolCoilDesCap, waterCoil.Name, waterCoil.DesWaterCoolingCoilRate);
1691 868 : OutputReportPredefined::PreDefTableEntry(
1692 434 : state, state.dataOutRptPredefined->pdchCoolCoilTotCap, waterCoil.Name, waterCoil.TotWaterCoolingCoilRate);
1693 868 : OutputReportPredefined::PreDefTableEntry(
1694 434 : state, state.dataOutRptPredefined->pdchCoolCoilSensCap, waterCoil.Name, waterCoil.SenWaterCoolingCoilRate);
1695 1302 : OutputReportPredefined::PreDefTableEntry(
1696 868 : state, state.dataOutRptPredefined->pdchCoolCoilLatCap, waterCoil.Name, state.dataWaterCoils->RatedLatentCapacity);
1697 1302 : OutputReportPredefined::PreDefTableEntry(
1698 868 : state, state.dataOutRptPredefined->pdchCoolCoilSHR, waterCoil.Name, state.dataWaterCoils->RatedSHR);
1699 434 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchCoolCoilNomEff, waterCoil.Name, "-");
1700 868 : OutputReportPredefined::PreDefTableEntry(
1701 434 : state, state.dataOutRptPredefined->pdchCoolCoilUATotal, waterCoil.Name, waterCoil.UACoilTotal);
1702 868 : OutputReportPredefined::PreDefTableEntry(
1703 434 : state, state.dataOutRptPredefined->pdchCoolCoilArea, waterCoil.Name, waterCoil.TotCoilOutsideSurfArea);
1704 868 : OutputReportPredefined::addFootNoteSubTable(
1705 : state,
1706 434 : state.dataOutRptPredefined->pdstCoolCoil,
1707 : "Nominal values are gross at rated conditions, i.e., the supply air fan heat and electric power NOT accounted for.");
1708 434 : print(state.files.eio,
1709 : "{},{},{:.2R},{:.2R},{:.2R},{:.2R},{:.2R},{:.2R}\n",
1710 : "Water Cooling Coil Capacity Information,Coil:Cooling:Water",
1711 434 : waterCoil.Name,
1712 434 : waterCoil.TotWaterCoolingCoilRate,
1713 434 : waterCoil.SenWaterCoolingCoilRate,
1714 434 : state.dataWaterCoils->RatedLatentCapacity,
1715 434 : state.dataWaterCoils->RatedSHR,
1716 434 : state.dataWaterCoils->UATotal,
1717 434 : state.dataWaterCoils->SurfaceArea);
1718 1302 : state.dataRptCoilSelection->coilSelectionReportObj->setCoilAirFlow(state,
1719 434 : waterCoil.Name,
1720 : "Coil:Cooling:Water",
1721 : waterCoil.DesAirVolFlowRate,
1722 434 : waterCoil.RequestingAutoSize); // Coil Report
1723 1302 : state.dataRptCoilSelection->coilSelectionReportObj->setCoilWaterCoolingCapacity(state,
1724 434 : waterCoil.Name,
1725 : "Coil:Cooling:Water",
1726 : waterCoil.DesWaterCoolingCoilRate,
1727 434 : waterCoil.RequestingAutoSize,
1728 : waterCoil.WaterInletNodeNum,
1729 : waterCoil.WaterOutletNodeNum,
1730 : waterCoil.WaterPlantLoc.loopNum); // Coil Report
1731 434 : break;
1732 : }
1733 0 : default:
1734 0 : break;
1735 : }
1736 3351 : if (waterCoil.DesWaterCoolingCoilRate <= 0.0) {
1737 2858 : waterCoil.DesWaterCoolingCoilRate = waterCoil.TotWaterCoolingCoilRate;
1738 : }
1739 3351 : if (waterCoil.DesWaterHeatingCoilRate <= 0.0) {
1740 933 : waterCoil.DesWaterHeatingCoilRate = waterCoil.TotWaterHeatingCoilRate;
1741 : }
1742 :
1743 : // call coil model with everything set at rating point
1744 3351 : waterCoil.InletAirMassFlowRate = waterCoil.DesAirMassFlowRate;
1745 3351 : waterCoil.InletAirTemp = waterCoil.DesInletAirTemp;
1746 3351 : waterCoil.InletAirHumRat = waterCoil.DesInletAirHumRat; // fixed in sizing routine
1747 3351 : waterCoil.InletAirEnthalpy = Psychrometrics::PsyHFnTdbW(waterCoil.DesInletAirTemp, waterCoil.DesInletAirHumRat);
1748 3351 : Real64 DesInletWetBulb = Psychrometrics::PsyTwbFnTdbWPb(
1749 : state, waterCoil.DesInletAirTemp, waterCoil.DesInletAirHumRat, DataEnvironment::StdPressureSeaLevel, "InitWaterCoils");
1750 3351 : waterCoil.InletWaterMassFlowRate = waterCoil.MaxWaterMassFlowRate;
1751 3351 : waterCoil.InletWaterTemp = waterCoil.DesInletWaterTemp;
1752 3351 : Real64 cp = state.dataPlnt->PlantLoop(waterCoil.WaterPlantLoc.loopNum)
1753 3351 : .glycol->getSpecificHeat(state, waterCoil.DesInletWaterTemp, "InitWaterCoil");
1754 3351 : waterCoil.InletWaterEnthalpy = cp * waterCoil.InletWaterTemp;
1755 :
1756 3351 : waterCoil.UACoilVariable = waterCoil.UACoil;
1757 3351 : waterCoil.FaultyCoilFoulingFactor = 0.0;
1758 3351 : Real64 holdOutBaroPress = state.dataEnvrn->OutBaroPress;
1759 3351 : state.dataEnvrn->OutBaroPress = DataEnvironment::StdPressureSeaLevel; // assume rating is for sea level.
1760 3351 : CalcAdjustedCoilUA(state, CoilNum);
1761 :
1762 3351 : std::string coilTypeName(" ");
1763 : // calculate coil sim model at rating point, full load, continuous fan
1764 3351 : if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling) {
1765 162 : CalcDetailFlatFinCoolingCoil(state, CoilNum, state.dataWaterCoils->SimCalc, HVAC::FanOp::Continuous, 1.0);
1766 162 : coilTypeName = "Coil:Cooling:Water:DetailedGeometry";
1767 3189 : } else if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterCooling) {
1768 434 : CoolingCoil(state, CoilNum, FirstHVACIteration, state.dataWaterCoils->SimCalc, HVAC::FanOp::Continuous, 1.0);
1769 434 : coilTypeName = "Coil:Cooling:Water";
1770 2755 : } else if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterSimpleHeating) {
1771 2755 : CalcSimpleHeatingCoil(state, CoilNum, HVAC::FanOp::Continuous, 1.0, state.dataWaterCoils->SimCalc);
1772 2755 : coilTypeName = "Coil:Heating:Water";
1773 : }
1774 3351 : state.dataRptCoilSelection->coilSelectionReportObj->setCoilEqNum(
1775 3351 : state, waterCoil.Name, coilTypeName, state.dataSize->CurSysNum, state.dataSize->CurOASysNum, state.dataSize->CurZoneEqNum);
1776 :
1777 : // coil outlets
1778 3351 : Real64 RatedOutletWetBulb(0.0);
1779 3351 : RatedOutletWetBulb = Psychrometrics::PsyTwbFnTdbWPb(
1780 : state, waterCoil.OutletAirTemp, waterCoil.OutletAirHumRat, DataEnvironment::StdPressureSeaLevel, "InitWaterCoil");
1781 :
1782 : // call set routine in coil report
1783 3351 : if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling ||
1784 3189 : waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterCooling) {
1785 596 : state.dataRptCoilSelection->coilSelectionReportObj->setRatedCoilConditions(
1786 : state,
1787 596 : waterCoil.Name,
1788 : coilTypeName,
1789 : waterCoil.TotWaterCoolingCoilRate, // this is the report variable
1790 : waterCoil.SenWaterCoolingCoilRate, // this is the report variable
1791 : waterCoil.InletAirMassFlowRate,
1792 : waterCoil.InletAirTemp,
1793 : waterCoil.InletAirHumRat,
1794 : DesInletWetBulb,
1795 : waterCoil.OutletAirTemp,
1796 : waterCoil.OutletAirHumRat,
1797 : RatedOutletWetBulb,
1798 : -999.0,
1799 : -999.0,
1800 : -999.0,
1801 : -999.0); // coil effectiveness
1802 2755 : } else if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterSimpleHeating) {
1803 2755 : state.dataRptCoilSelection->coilSelectionReportObj->setRatedCoilConditions(
1804 : state,
1805 2755 : waterCoil.Name,
1806 : coilTypeName,
1807 : waterCoil.TotWaterHeatingCoilRate, // this is the report variable
1808 : waterCoil.TotWaterHeatingCoilRate, // this is the report variable
1809 : waterCoil.InletAirMassFlowRate,
1810 : waterCoil.InletAirTemp,
1811 : waterCoil.InletAirHumRat,
1812 : DesInletWetBulb,
1813 : waterCoil.OutletAirTemp,
1814 : waterCoil.OutletAirHumRat,
1815 : RatedOutletWetBulb,
1816 : -999.0,
1817 : -999.0,
1818 : -999.0,
1819 : -999.0); // coil effectiveness
1820 : }
1821 : // now replace the outdoor air conditions set above for one time rating point calc
1822 3351 : state.dataEnvrn->OutBaroPress = holdOutBaroPress;
1823 : }
1824 : }
1825 :
1826 : // Do the Begin Day initializations
1827 : // NONE
1828 :
1829 : // Do the begin HVAC time step initializations
1830 : // NONE
1831 :
1832 : // Do the following initializations (every time step): This should be the info from
1833 : // the previous components outlets or the node data in this section.
1834 : // First set the conditions for the air into the coil model
1835 149968186 : AirInletNode = waterCoil.AirInletNodeNum;
1836 149968186 : WaterInletNode = waterCoil.WaterInletNodeNum;
1837 149968186 : auto const &airInletNode = state.dataLoopNodes->Node(AirInletNode);
1838 149968186 : waterCoil.InletAirMassFlowRate = airInletNode.MassFlowRate;
1839 149968186 : waterCoil.InletAirTemp = airInletNode.Temp;
1840 149968186 : waterCoil.InletAirHumRat = airInletNode.HumRat;
1841 149968186 : waterCoil.InletAirEnthalpy = airInletNode.Enthalpy;
1842 :
1843 149968186 : auto const &waterInletNode = state.dataLoopNodes->Node(WaterInletNode);
1844 149968186 : waterCoil.InletWaterMassFlowRate = waterInletNode.MassFlowRate;
1845 149968186 : waterCoil.InletWaterTemp = waterInletNode.Temp;
1846 149968186 : waterCoil.InletWaterEnthalpy = waterInletNode.Enthalpy;
1847 :
1848 149968186 : waterCoil.UACoilVariable = waterCoil.UACoil;
1849 :
1850 149968186 : CalcAdjustedCoilUA(state, CoilNum);
1851 :
1852 149968186 : waterCoil.TotWaterHeatingCoilRate = 0.0;
1853 149968186 : waterCoil.TotWaterCoolingCoilRate = 0.0;
1854 149968186 : waterCoil.SenWaterCoolingCoilRate = 0.0;
1855 149968186 : }
1856 :
1857 : // refactor coilUA adjustment into separate routine, for use with rating calc
1858 149971537 : void CalcAdjustedCoilUA(EnergyPlusData &state, int const CoilNum)
1859 : {
1860 : // Pull these precalc routines out of big init routine
1861 : // modify the coil UA based on model in Wetter 1999
1862 : Real64 x_a; // result of Eq.70 in Wetter 1999
1863 : Real64 x_w; // result of Eq.72 in Wetter 1999
1864 : Real64 AirConvectTerm; // result of Eq.71 in Wetter 1999
1865 : Real64 WaterConvectTerm; // result of Eq.73 in Wetter 1999
1866 : Real64 WaterConvSensitivity; // "s" in Wetter 1999, temperature sensitivity in water side convection
1867 :
1868 149971537 : auto &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
1869 : // Coil:Heating:Water
1870 271945973 : if ((waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterSimpleHeating) &&
1871 121974436 : (!(state.dataWaterCoils->MyUAAndFlowCalcFlag(CoilNum)))) { // update Coil UA based on inlet mass flows and temps
1872 121972271 : x_a = 1.0 + 4.769E-3 * (waterCoil.InletAirTemp - waterCoil.DesInletAirTemp);
1873 121972271 : if (waterCoil.DesAirMassFlowRate > 0.0) {
1874 121320201 : AirConvectTerm = x_a * std::pow(waterCoil.InletAirMassFlowRate / waterCoil.DesAirMassFlowRate, 0.8) * waterCoil.AirSideNominalConvect;
1875 : } else {
1876 652070 : AirConvectTerm = 0.0;
1877 : }
1878 121972271 : WaterConvSensitivity = 0.014 / (1.0 + 0.014 * waterCoil.DesInletWaterTemp);
1879 121972271 : x_w = 1.0 + WaterConvSensitivity * (waterCoil.InletWaterTemp - waterCoil.DesInletWaterTemp);
1880 121972271 : if (waterCoil.MaxWaterMassFlowRate > 0.0) {
1881 120849286 : WaterConvectTerm =
1882 120849286 : x_w * std::pow(waterCoil.InletWaterMassFlowRate / waterCoil.MaxWaterMassFlowRate, 0.85) * waterCoil.LiquidSideNominalConvect;
1883 : } else {
1884 1122985 : WaterConvectTerm = 0.0;
1885 : }
1886 121972271 : if ((AirConvectTerm > 0.0) && (WaterConvectTerm > 0.0)) {
1887 76796206 : waterCoil.UACoilVariable = 1.0 / ((1.0 / WaterConvectTerm) + (1.0 / AirConvectTerm));
1888 : } else {
1889 : // use nominal UA since variable UA cannot be calculated
1890 45176065 : waterCoil.UACoilVariable = waterCoil.UACoil;
1891 : }
1892 :
1893 : // calculate the Faulty Coil Fouling (thermal insulance) Factor using fault information
1894 243960300 : if (waterCoil.FaultyCoilFoulingFlag &&
1895 : // The fault shouldn't apply during sizing.
1896 121973598 : (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) && (!state.dataGlobal->KickOffSimulation) &&
1897 : // This was preexisting
1898 1327 : !(state.dataWaterCoils->MyUAAndFlowCalcFlag(CoilNum))) {
1899 : // Store original value
1900 1327 : waterCoil.OriginalUACoilVariable = waterCoil.UACoilVariable;
1901 :
1902 1327 : int FaultIndex = waterCoil.FaultyCoilFoulingIndex;
1903 1327 : FaultsManager::FaultPropertiesFoulingCoil &fouling = state.dataFaultsMgr->FouledCoils(FaultIndex);
1904 1327 : Real64 FaultFrac = fouling.FaultFraction(state);
1905 :
1906 1327 : if (fouling.FoulingInputMethod == FaultsManager::FouledCoil::UARated) {
1907 : // 1/UA' = Frac * (1/UAFouled) + (1-Frac) / UA
1908 1327 : waterCoil.UACoilVariable = 1 / (FaultFrac / (fouling.UAFouled) + (1 - FaultFrac) / waterCoil.UACoilVariable);
1909 : } else {
1910 : // R' = R + Rfoul
1911 : // Rfoul = r_air/A_air + r_water/A_water (FoulingFactor = thermal insulance [K/W, A] = Area [m2], r=fouling factor [m2.K/W]
1912 0 : Real64 FoulingFactor = FaultFrac * (fouling.Rfw / (fouling.Aratio * fouling.Aout) + fouling.Rfa / fouling.Aout);
1913 0 : waterCoil.UACoilVariable = 1.0 / ((1.0 / waterCoil.UACoilVariable) + FoulingFactor);
1914 : }
1915 :
1916 : // Do not allow improving coil performance
1917 1327 : waterCoil.UACoilVariable = min(waterCoil.UACoilVariable, waterCoil.OriginalUACoilVariable);
1918 :
1919 : // Only for reporting purposes
1920 1327 : waterCoil.FaultyCoilFoulingFactor = (1.0 / waterCoil.UACoilVariable) - (1.0 / waterCoil.OriginalUACoilVariable);
1921 : } else {
1922 121970944 : waterCoil.FaultyCoilFoulingFactor = 0;
1923 : }
1924 : }
1925 :
1926 : // Coil:Cooling:Water
1927 : // update Coil UA based on inlet mass flows and temps
1928 149971537 : if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterCooling && (!state.dataWaterCoils->MyCoilDesignFlag(CoilNum))) {
1929 23067487 : if (waterCoil.DesAirMassFlowRate > 0.0) {
1930 23067487 : x_a = 1.0 + 4.769E-3 * (waterCoil.InletAirTemp - waterCoil.DesInletAirTemp);
1931 23067487 : waterCoil.UACoilExternal =
1932 23067487 : x_a * std::pow(waterCoil.InletAirMassFlowRate / waterCoil.DesAirMassFlowRate, 0.8) * waterCoil.UACoilExternalDes;
1933 : } else {
1934 0 : waterCoil.UACoilExternal = waterCoil.UACoilExternalDes;
1935 : }
1936 :
1937 23067487 : if (waterCoil.MaxWaterMassFlowRate > 0.0) {
1938 23067487 : WaterConvSensitivity = 0.014 / (1.0 + 0.014 * waterCoil.DesInletWaterTemp);
1939 23067487 : x_w = 1.0 + WaterConvSensitivity * (waterCoil.InletWaterTemp - waterCoil.DesInletWaterTemp);
1940 23067487 : waterCoil.UACoilInternal =
1941 23067487 : x_w * std::pow(waterCoil.InletWaterMassFlowRate / waterCoil.MaxWaterMassFlowRate, 0.85) * waterCoil.UACoilInternalDes;
1942 : } else {
1943 0 : waterCoil.UACoilInternal = waterCoil.UACoilInternalDes;
1944 : }
1945 :
1946 23067487 : if (!(waterCoil.UACoilInternal > 0.0 && waterCoil.UACoilExternal > 0.0)) {
1947 10295719 : waterCoil.UACoilInternal = waterCoil.UACoilInternalDes;
1948 10295719 : waterCoil.UACoilExternal = waterCoil.UACoilExternalDes;
1949 : }
1950 :
1951 : // If Fouling
1952 46150732 : if (waterCoil.FaultyCoilFoulingFlag &&
1953 : // The fault shouldn't apply during sizing.
1954 23068814 : (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) && (!state.dataGlobal->KickOffSimulation) &&
1955 : // This was preexisting
1956 1327 : !(state.dataWaterCoils->MyUAAndFlowCalcFlag(CoilNum))) {
1957 : // Store original value
1958 : // This is really UACoilTotal technically, but I don't see the point of declaring another Real on the struct just for that
1959 1327 : waterCoil.OriginalUACoilVariable = 1.0 / (1.0 / waterCoil.UACoilExternal + 1.0 / waterCoil.UACoilInternal);
1960 :
1961 1327 : waterCoil.OriginalUACoilExternal = waterCoil.UACoilExternal;
1962 1327 : waterCoil.OriginalUACoilInternal = waterCoil.UACoilInternal;
1963 :
1964 1327 : int FaultIndex = waterCoil.FaultyCoilFoulingIndex;
1965 :
1966 1327 : FaultsManager::FaultPropertiesFoulingCoil &fouling = state.dataFaultsMgr->FouledCoils(FaultIndex);
1967 1327 : Real64 FaultFrac = fouling.FaultFraction(state);
1968 :
1969 1327 : if (fouling.FoulingInputMethod == FaultsManager::FouledCoil::FoulingFactor) {
1970 : // Adjust the External (air) UA and Internal (water) UA accordingly
1971 0 : Real64 Rfoul_air = FaultFrac * (fouling.Rfa / fouling.Aout);
1972 0 : Real64 Rfoul_water = FaultFrac * (fouling.Rfw / (fouling.Aratio * fouling.Aout));
1973 :
1974 0 : waterCoil.UACoilInternal = 1.0 / (1.0 / waterCoil.UACoilInternal + Rfoul_water);
1975 0 : waterCoil.UACoilExternal = 1.0 / (1.0 / waterCoil.UACoilExternal + Rfoul_air);
1976 : //
1977 : } else { // iFouledCoil_UARated
1978 : // FouledUARated is supposed to be the overall UA. So we need to split between Internal and External UAs
1979 :
1980 : // How should I split fouling between internal/external?
1981 : // We can actually use the current ratio before fouling...
1982 : // splitRatio = UACoilInternal/UACoilExternal
1983 : // UACoilInternal = UACoilExternal * splitRatio
1984 :
1985 : // UACoilTotal = 1 / (1 / UACoilExternal + 1 / UACoilInternal)
1986 : // UACoilTotal = 1 / (1 / UACoilExternal + 1 / (UACoilExernal * splitRatio))
1987 : // UACoilTotal = UACoilExternal / (1 + 1 / splitRatio) = UACoilExternal * splitRatio / (1 + splitRatio)
1988 : // UACoilExternal = UACoilTotal * (1 + splitRatio) / splitRatio
1989 : // UACoilInternal = UACoilTotal * (1 + splitRatio)
1990 :
1991 : // Adding in FaultFrac:
1992 : // UACoilExternal = FaultFrac * [UAFouled * (1+splitRatio) / splitRatio] + (1-FaultFrac) * UACoilExternal
1993 : // UACoilInternal = FaultFrac * [UAFouled * splitRatio] + (1-FaultFrac) * UACoilInternal
1994 :
1995 1327 : Real64 splitRatio = waterCoil.UACoilInternal / waterCoil.UACoilExternal;
1996 :
1997 1327 : waterCoil.UACoilExternal =
1998 1327 : 1.0 / ((FaultFrac * splitRatio) / ((1 + splitRatio) * fouling.UAFouled) + (1 - FaultFrac) / waterCoil.UACoilExternal);
1999 :
2000 : // WaterCoil(CoilNum).UACoilInternal = 1.0 /
2001 : //( FaultFrac / ((1 + splitRatio) * fouling.UAFouled) +
2002 : //(1-FaultFrac) / WaterCoil(CoilNum).UACoilInternal);
2003 :
2004 1327 : waterCoil.UACoilInternal = splitRatio * waterCoil.UACoilExternal;
2005 : }
2006 :
2007 : // Do not allow improving coil performance
2008 1327 : waterCoil.UACoilExternal = min(waterCoil.UACoilExternal, waterCoil.OriginalUACoilExternal);
2009 1327 : waterCoil.UACoilInternal = min(waterCoil.UACoilInternal, waterCoil.OriginalUACoilInternal);
2010 :
2011 : // Only for reporting purposes
2012 1327 : waterCoil.FaultyCoilFoulingFactor = (1.0 / waterCoil.UACoilExternal) - (1.0 / waterCoil.OriginalUACoilExternal) +
2013 1327 : (1.0 / waterCoil.UACoilInternal) - (1.0 / waterCoil.OriginalUACoilInternal);
2014 : } else {
2015 23066160 : waterCoil.FaultyCoilFoulingFactor = 0;
2016 : }
2017 :
2018 23067487 : waterCoil.UACoilTotal = 1.0 / (1.0 / waterCoil.UACoilExternal + 1.0 / waterCoil.UACoilInternal);
2019 :
2020 23067487 : waterCoil.UACoilInternalPerUnitArea = waterCoil.UACoilInternal / waterCoil.TotCoilOutsideSurfArea;
2021 23067487 : waterCoil.UAWetExtPerUnitArea = waterCoil.UACoilExternal / waterCoil.TotCoilOutsideSurfArea;
2022 23067487 : waterCoil.UADryExtPerUnitArea = waterCoil.UAWetExtPerUnitArea;
2023 : }
2024 149971537 : }
2025 :
2026 3351 : void SizeWaterCoil(EnergyPlusData &state, int const CoilNum)
2027 : {
2028 :
2029 : // SUBROUTINE INFORMATION:
2030 : // AUTHOR Fred Buhl
2031 : // DATE WRITTEN November 2001
2032 : // MODIFIED August 2013 Daeho Kang, add component sizing table entries
2033 : // RE-ENGINEERED na
2034 :
2035 : // PURPOSE OF THIS SUBROUTINE:
2036 : // This subroutine is for sizing Water Coil Components for which flow rates and UAs have not been
2037 : // specified in the input.
2038 :
2039 : // METHODOLOGY EMPLOYED:
2040 : // Obtains flow rates from the zone or system sizing arrays and plant sizing data. UAs are
2041 : // calculated by numerically inverting the individual coil calculation routines.
2042 :
2043 : // SUBROUTINE PARAMETER DEFINITIONS:
2044 : static constexpr std::string_view RoutineName("SizeWaterCoil");
2045 :
2046 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2047 : Real64 rho;
2048 3351 : std::string CompType; // component type
2049 3351 : std::string SizingString; // input field sizing description (e.g., Nominal Capacity)
2050 : Real64 TempSize; // autosized value
2051 : Real64 DesCoilWaterInTempSaved; // coil water inlet temp used for error checking UA sizing
2052 3351 : Real64 DesCoilInletWaterTempUsed(0.0); // coil design inlet water temp for UA sizing only
2053 : Real64 Cp;
2054 :
2055 3351 : bool ErrorsFound = false;
2056 3351 : bool LoopErrorsFound = false;
2057 3351 : int PltSizCoolNum = 0;
2058 3351 : int PltSizHeatNum = 0;
2059 3351 : Real64 DesCoilAirFlow = 0.0;
2060 3351 : Real64 DesCoilExitTemp = 0.0;
2061 3351 : Real64 CpAirStd = PsyCpAirFnW(0.0);
2062 :
2063 3351 : auto &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
2064 : // cooling coils
2065 3351 : if (((waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterCooling) ||
2066 2917 : (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling)) &&
2067 596 : waterCoil.RequestingAutoSize) {
2068 : // find the appropriate Plant Sizing object
2069 493 : PltSizCoolNum = PlantUtilities::MyPlantSizingIndex(
2070 : state, "chilled water coil", waterCoil.Name, waterCoil.WaterInletNodeNum, waterCoil.WaterOutletNodeNum, LoopErrorsFound);
2071 : }
2072 :
2073 3351 : if (((waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterCooling) ||
2074 2917 : (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling))) { // 'Cooling'
2075 :
2076 596 : if (waterCoil.UseDesignWaterDeltaTemp) {
2077 34 : state.dataSize->DataWaterCoilSizCoolDeltaT = waterCoil.DesignWaterDeltaTemp;
2078 : } else {
2079 562 : if (PltSizCoolNum > 0) {
2080 459 : state.dataSize->DataWaterCoilSizCoolDeltaT = state.dataSize->PlantSizData(PltSizCoolNum).DeltaT;
2081 : }
2082 : }
2083 :
2084 596 : if (PltSizCoolNum > 0) {
2085 :
2086 : // int FieldNum = 0;
2087 493 : state.dataSize->DataPltSizCoolNum = PltSizCoolNum;
2088 493 : state.dataSize->DataWaterLoopNum = waterCoil.WaterPlantLoc.loopNum;
2089 :
2090 493 : if (waterCoil.WaterCoilModel == CoilModel::CoolingDetailed) { // 'DETAILED FLAT FIN'
2091 81 : CompType = HVAC::cAllCoilTypes(HVAC::Coil_CoolingWaterDetailed); // Coil:Cooling:Water:DetailedGeometry
2092 : } else {
2093 412 : CompType = HVAC::cAllCoilTypes(HVAC::Coil_CoolingWater); // Coil:Cooling:Water
2094 : }
2095 :
2096 493 : bool bPRINT = false; // do not print this sizing request since the autosized value is needed and this input may not be autosized (we
2097 : // should print this!)
2098 493 : if (waterCoil.DesAirVolFlowRate == state.dataSize->DataFlowUsedForSizing) {
2099 84 : TempSize = waterCoil.DesAirVolFlowRate; // represents parent object has hard-sized airflow
2100 : } else {
2101 409 : TempSize = DataSizing::AutoSize; // get the autosized air volume flow rate for use in other calculations
2102 : }
2103 :
2104 493 : ErrorsFound = false;
2105 493 : CoolingAirFlowSizer sizingCoolingAirFlow;
2106 493 : std::string const &CompName = waterCoil.Name;
2107 493 : sizingCoolingAirFlow.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
2108 493 : Real64 autoSizedValue = sizingCoolingAirFlow.size(state, TempSize, ErrorsFound);
2109 493 : waterCoil.InletAirMassFlowRate = state.dataEnvrn->StdRhoAir * autoSizedValue; // inlet air mass flow rate is the autosized value
2110 :
2111 : // Check if the air volume flow rate is defined in parent HVAC equipment and set water coil design air volume flow rate accordingly
2112 493 : if (state.dataSize->CurZoneEqNum > 0) {
2113 107 : auto const &ZoneEqSizing = state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum);
2114 107 : if (ZoneEqSizing.DesignSizeFromParent && waterCoil.DesAirVolFlowRate == autoSizedValue) {
2115 80 : state.dataSize->DataAirFlowUsedForSizing = ZoneEqSizing.AirVolFlow;
2116 80 : state.dataSize->DataFlowUsedForSizing = ZoneEqSizing.AirVolFlow;
2117 80 : waterCoil.DesAirVolFlowRate = DataSizing::AutoSize; // represents water coil being autosized
2118 : } else {
2119 27 : state.dataSize->DataAirFlowUsedForSizing =
2120 : autoSizedValue; // many autosized inputs use the design (autosized) air volume flow rate, save this value
2121 27 : state.dataSize->DataFlowUsedForSizing = autoSizedValue;
2122 : }
2123 : } else {
2124 386 : state.dataSize->DataAirFlowUsedForSizing =
2125 : autoSizedValue; // many autosized inputs use the design (autosized) air volume flow rate, save this value
2126 386 : state.dataSize->DataFlowUsedForSizing = autoSizedValue;
2127 : }
2128 :
2129 493 : if (state.dataSize->CurSysNum > 0 && state.dataSize->CurOASysNum == 0) {
2130 355 : Real64 DesCoilExitHumRat(0.0); // fix coil sizing inconsistency
2131 355 : DataSizing::GetCoilDesFlowT(state, state.dataSize->CurSysNum, CpAirStd, DesCoilAirFlow, DesCoilExitTemp, DesCoilExitHumRat);
2132 355 : state.dataSize->DataAirFlowUsedForSizing = DesCoilAirFlow;
2133 355 : state.dataSize->DataFlowUsedForSizing = DesCoilAirFlow;
2134 355 : state.dataSize->DataDesOutletAirTemp = DesCoilExitTemp;
2135 355 : state.dataSize->DataDesOutletAirHumRat = DesCoilExitHumRat; // need to test for dry coil but inlet conditions not yet known
2136 : }
2137 :
2138 : // calculate pre-sizing data needed for specific functions (e.g., CoolingWaterDesAirInletTempSizing needs HRin and air flow)
2139 : // these will be calculated again after other parameters are known
2140 493 : if (waterCoil.WaterCoilModel == CoilModel::CoolingDetailed) { // 'DETAILED FLAT FIN'
2141 81 : TempSize = DataSizing::AutoSize; // coil report
2142 : } else {
2143 412 : TempSize = waterCoil.DesInletAirHumRat; // preserve input if entered
2144 : }
2145 493 : CoolingWaterDesAirInletHumRatSizer sizerCWDesInHumRat;
2146 493 : sizerCWDesInHumRat.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
2147 493 : state.dataSize->DataDesInletAirHumRat = sizerCWDesInHumRat.size(state, TempSize, ErrorsFound);
2148 :
2149 493 : TempSize = DataSizing::AutoSize;
2150 493 : CoolingCapacitySizer sizerCoolingCapacity;
2151 493 : sizerCoolingCapacity.overrideSizingString(SizingString);
2152 493 : sizerCoolingCapacity.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
2153 493 : state.dataSize->DataCapacityUsedForSizing = sizerCoolingCapacity.size(state, TempSize, ErrorsFound);
2154 493 : TempSize = waterCoil.MaxWaterVolFlowRate;
2155 493 : CoolingWaterflowSizer sizerCWWaterflow;
2156 493 : sizerCWWaterflow.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
2157 493 : Real64 autoSizedCWFlow = sizerCWWaterflow.size(state, TempSize, ErrorsFound);
2158 : // Check if the water flow rate is defined in parent HVAC equipment and set water coil design water flow rate accordingly
2159 493 : if (state.dataSize->CurZoneEqNum > 0) {
2160 107 : auto const &ZoneEqSizing = state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum);
2161 107 : if (ZoneEqSizing.DesignSizeFromParent) {
2162 81 : state.dataSize->DataWaterFlowUsedForSizing = ZoneEqSizing.MaxCWVolFlow;
2163 : } else {
2164 26 : state.dataSize->DataWaterFlowUsedForSizing = autoSizedCWFlow;
2165 : }
2166 : } else {
2167 386 : state.dataSize->DataWaterFlowUsedForSizing = autoSizedCWFlow;
2168 : }
2169 : // end pre-sizing data calculations
2170 :
2171 493 : if (waterCoil.WaterCoilModel == CoilModel::CoolingDetailed) { // 'DETAILED FLAT FIN'
2172 81 : bPRINT = false; // do not print this sizing request since this coil does not have a design inlet air temp input field (we
2173 : // should print this!)
2174 81 : TempSize = DataSizing::AutoSize; // not an input for this model
2175 : } else {
2176 412 : bPRINT = true;
2177 412 : TempSize = waterCoil.DesInletAirTemp; // preserve input if entered
2178 : }
2179 :
2180 493 : CoolingWaterDesAirInletTempSizer sizerCWDesInletAirTemp;
2181 493 : sizerCWDesInletAirTemp.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
2182 493 : waterCoil.DesInletAirTemp = sizerCWDesInletAirTemp.size(state, TempSize, ErrorsFound);
2183 493 : state.dataSize->DataDesInletAirTemp = waterCoil.DesInletAirTemp;
2184 :
2185 493 : if (waterCoil.WaterCoilModel == CoilModel::CoolingDetailed) { // 'DETAILED FLAT FIN'
2186 81 : bPRINT = false; // no field for detailed water coil, should print to eio anyway
2187 81 : TempSize = DataSizing::AutoSize; // coil report
2188 : } else {
2189 412 : bPRINT = true;
2190 412 : TempSize = waterCoil.DesInletWaterTemp; // preserve input if entered
2191 : }
2192 493 : CoolingWaterDesWaterInletTempSizer sizerCWDesWaterInTemp;
2193 493 : sizerCWDesWaterInTemp.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
2194 493 : waterCoil.DesInletWaterTemp = sizerCWDesWaterInTemp.size(state, TempSize, ErrorsFound);
2195 :
2196 493 : if ((waterCoil.DesInletWaterTemp > state.dataSize->DataDesOutletAirTemp) && state.dataSize->DataDesOutletAirTemp > 0.0) {
2197 0 : ShowWarningError(state, format("Invalid design inlet water temperature for {} = {}", CompType, CompName));
2198 0 : ShowContinueError(state, format("...design inlet water temperature = {:.3R} C", waterCoil.DesInletWaterTemp));
2199 0 : ShowContinueError(state, format("...design outlet air temperature = {:.3R} C", state.dataSize->DataDesOutletAirTemp));
2200 0 : ShowContinueError(state, "...design inlet water temperature should be less than the design outlet air temperature");
2201 0 : ShowContinueError(state, "...design inlet water temperature is set to the design outlet air temperature minus 5.0C");
2202 0 : waterCoil.DesInletWaterTemp = state.dataSize->DataDesOutletAirTemp - 5.0;
2203 : }
2204 :
2205 493 : if (state.dataSize->CurZoneEqNum > 0) { // zone equipment use air inlet humrat to calculate design outlet air temperature
2206 107 : if (waterCoil.WaterCoilModel == CoilModel::CoolingDetailed) { // 'DETAILED FLAT FIN'
2207 0 : bPRINT = false; // no field for detailed water coil, should print to eio anyway
2208 0 : TempSize = DataSizing::AutoSize; // coil report
2209 : } else {
2210 107 : bPRINT = true;
2211 107 : TempSize = waterCoil.DesInletAirHumRat; // preserve input if entered
2212 : }
2213 107 : sizerCWDesInHumRat.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
2214 107 : waterCoil.DesInletAirHumRat = sizerCWDesInHumRat.size(state, TempSize, ErrorsFound);
2215 : }
2216 :
2217 493 : if (waterCoil.WaterCoilModel == CoilModel::CoolingDetailed) { // 'DETAILED FLAT FIN'
2218 81 : bPRINT = false; // no field for detailed water coil, should print to eio anyway
2219 81 : TempSize = DataSizing::AutoSize; // coil report
2220 : } else {
2221 412 : bPRINT = true;
2222 412 : TempSize = waterCoil.DesOutletAirTemp; // preserve input if entered
2223 : }
2224 :
2225 493 : state.dataSize->DataDesInletWaterTemp = waterCoil.DesInletWaterTemp; // used for warning messages
2226 493 : CoolingWaterDesAirOutletTempSizer sizerCWDesAirOutTemp;
2227 493 : sizerCWDesAirOutTemp.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
2228 493 : waterCoil.DesOutletAirTemp = sizerCWDesAirOutTemp.size(state, TempSize, ErrorsFound);
2229 493 : state.dataSize->DataDesOutletAirTemp = waterCoil.DesOutletAirTemp;
2230 :
2231 493 : if (state.dataSize->CurSysNum > 0) { // This call can be deleted at a future time and remove the if ( CurZoneEqNum > 0 ) check above. This
2232 : // will change the order of the eio file.
2233 386 : if (waterCoil.WaterCoilModel == CoilModel::CoolingDetailed) { // 'DETAILED FLAT FIN'
2234 81 : bPRINT = false; // no field for detailed water coil, should print this to eio anyway
2235 81 : TempSize = DataSizing::AutoSize; // coil report
2236 : } else {
2237 305 : bPRINT = true;
2238 305 : TempSize = waterCoil.DesInletAirHumRat;
2239 : }
2240 386 : sizerCWDesInHumRat.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
2241 386 : waterCoil.DesInletAirHumRat = sizerCWDesInHumRat.size(state, TempSize, ErrorsFound);
2242 : }
2243 :
2244 493 : if (waterCoil.WaterCoilModel == CoilModel::CoolingDetailed) { // 'DETAILED FLAT FIN'
2245 81 : bPRINT = false; // no field for detailed water coil, should print this to eio anyway
2246 81 : TempSize = DataSizing::AutoSize; // coil report
2247 : } else {
2248 412 : bPRINT = true;
2249 412 : TempSize = waterCoil.DesOutletAirHumRat; // preserve input if entered
2250 : }
2251 493 : CoolingWaterDesAirOutletHumRatSizer sizerCWDesOutHumRat;
2252 493 : sizerCWDesOutHumRat.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
2253 493 : waterCoil.DesOutletAirHumRat = sizerCWDesOutHumRat.size(state, TempSize, ErrorsFound);
2254 493 : state.dataSize->DataDesOutletAirHumRat = waterCoil.DesOutletAirHumRat;
2255 :
2256 493 : TempSize = DataSizing::AutoSize;
2257 493 : bPRINT = true;
2258 493 : if (waterCoil.MaxWaterVolFlowRate != DataSizing::AutoSize) {
2259 0 : bPRINT = false;
2260 : }
2261 493 : if (state.dataSize->CurSysNum == 0) {
2262 107 : bPRINT = false;
2263 : }
2264 493 : SizingString = "Design Coil Load [W]"; // there is no input field for this value and this is not the rated capacity (we should
2265 : // always print this!)
2266 : // air inlet/outlet conditions should be known. Don't include fan heat in capacity calculation.
2267 493 : state.dataSize->DataDesAccountForFanHeat = false;
2268 493 : CoolingCapacitySizer sizerCoolingCapacity2;
2269 493 : sizerCoolingCapacity2.overrideSizingString(SizingString);
2270 493 : sizerCoolingCapacity2.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
2271 493 : waterCoil.DesWaterCoolingCoilRate = sizerCoolingCapacity2.size(state, TempSize, ErrorsFound);
2272 493 : waterCoil.InletAirMassFlowRate =
2273 493 : state.dataEnvrn->StdRhoAir * state.dataSize->DataFlowUsedForSizing; // inlet air mass flow rate is the autosized value
2274 493 : state.dataSize->DataCapacityUsedForSizing = waterCoil.DesWaterCoolingCoilRate;
2275 :
2276 : // Why isn't the water volume flow rate based on the user inputs for inlet/outlet air/water temps? Water volume flow rate is
2277 : // always based on autosized inputs.
2278 493 : bPRINT = true;
2279 493 : TempSize = waterCoil.MaxWaterVolFlowRate;
2280 493 : sizerCWWaterflow.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
2281 493 : waterCoil.MaxWaterVolFlowRate = sizerCWWaterflow.size(state, TempSize, ErrorsFound);
2282 493 : state.dataSize->DataWaterFlowUsedForSizing = waterCoil.MaxWaterVolFlowRate;
2283 :
2284 493 : if (waterCoil.WaterCoilModel == CoilModel::CoolingDetailed) { // 'DETAILED FLAT FIN'
2285 81 : bPRINT = false; // do not print this sizing request since this coil does not have a design air flow rate input field (we
2286 : // should print this!)
2287 : } else {
2288 412 : bPRINT = true;
2289 : }
2290 493 : TempSize = waterCoil.DesAirVolFlowRate;
2291 493 : CoolingAirFlowSizer sizingCoolingAirFlow2;
2292 493 : std::string stringOverride = "Design Air Flow Rate [m3/s]";
2293 493 : if (state.dataGlobal->isEpJSON) {
2294 0 : stringOverride = "design_air_flow_rate [m3/s]";
2295 : }
2296 493 : sizingCoolingAirFlow2.overrideSizingString(stringOverride);
2297 : // sizingCoolingAirFlow2.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
2298 493 : sizingCoolingAirFlow2.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
2299 493 : waterCoil.DesAirVolFlowRate = sizingCoolingAirFlow2.size(state, TempSize, ErrorsFound);
2300 493 : waterCoil.DesAirMassFlowRate = waterCoil.DesAirVolFlowRate * state.dataEnvrn->StdRhoAir;
2301 :
2302 493 : if (waterCoil.DesAirVolFlowRate <= 0.0) {
2303 0 : waterCoil.DesAirVolFlowRate = 0.0;
2304 0 : ShowWarningError(state, format("The design air flow rate is zero for {} = {}", CompType, CompName));
2305 0 : ShowContinueError(state, "The autosize value for max air volume flow rate is zero");
2306 : }
2307 :
2308 493 : if (waterCoil.WaterCoilModel == CoilModel::CoolingDetailed) {
2309 :
2310 81 : int FieldNum = 16; // N16, \field Number of Tubes per Row
2311 81 : bPRINT = true;
2312 81 : SizingString = state.dataWaterCoils->WaterCoilNumericFields(CoilNum).FieldNames(FieldNum);
2313 : // Auto size detailed cooling coil number of tubes per row = int( 13750.0 * WaterCoil( CoilNum ).MaxWaterVolFlowRate ) + 1
2314 81 : state.dataSize->DataFlowUsedForSizing = waterCoil.MaxWaterVolFlowRate;
2315 81 : TempSize = float(waterCoil.NumOfTubesPerRow);
2316 81 : CoolingWaterNumofTubesPerRowSizer sizerCWNumofTubesPerRow;
2317 81 : sizerCWNumofTubesPerRow.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
2318 81 : waterCoil.NumOfTubesPerRow = sizerCWNumofTubesPerRow.size(state, TempSize, ErrorsFound);
2319 :
2320 : // Auto size water coil fin diameter = 0.335 * WaterCoil( CoilNum ).InletAirMassFlowRate
2321 81 : state.dataSize->DataConstantUsedForSizing = waterCoil.InletAirMassFlowRate;
2322 81 : state.dataSize->DataFractionUsedForSizing = 0.335;
2323 81 : TempSize = waterCoil.FinDiam;
2324 :
2325 81 : AutoCalculateSizer sizerFinDiameter;
2326 81 : stringOverride = "Fin Diameter [m]";
2327 81 : if (state.dataGlobal->isEpJSON) {
2328 0 : stringOverride = "fin_diameter [m]";
2329 : }
2330 81 : sizerFinDiameter.overrideSizingString(stringOverride);
2331 81 : sizerFinDiameter.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
2332 81 : waterCoil.FinDiam = sizerFinDiameter.size(state, TempSize, ErrorsFound);
2333 :
2334 : // Auto size water coil minimum airflow area = 0.44 * WaterCoil( CoilNum ).InletAirMassFlowRate
2335 81 : state.dataSize->DataConstantUsedForSizing = waterCoil.InletAirMassFlowRate;
2336 81 : state.dataSize->DataFractionUsedForSizing = 0.44;
2337 81 : TempSize = waterCoil.MinAirFlowArea;
2338 :
2339 81 : AutoCalculateSizer sizerMinAirFlowArea;
2340 81 : stringOverride = "Minimum Airflow Area [m2]";
2341 81 : if (state.dataGlobal->isEpJSON) {
2342 0 : stringOverride = "minimum_airflow_area [m2]";
2343 : }
2344 81 : sizerMinAirFlowArea.overrideSizingString(stringOverride);
2345 81 : sizerMinAirFlowArea.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
2346 81 : waterCoil.MinAirFlowArea = sizerMinAirFlowArea.size(state, TempSize, ErrorsFound);
2347 :
2348 81 : if (waterCoil.MinAirFlowArea <= 0.0) {
2349 0 : ShowSevereError(state, format("Coil:Cooling:Water:DetailedGeometry: \"{}\"", waterCoil.Name));
2350 0 : ShowContinueError(state,
2351 0 : format("Coil Minimum Airflow Area must be greater than 0. Coil area = {:.6T}", waterCoil.MinAirFlowArea));
2352 0 : ErrorsFound = true;
2353 : }
2354 :
2355 : // Auto size water coil finned surface area = 78.5 * WaterCoil( CoilNum ).InletAirMassFlowRate
2356 162 : state.dataSize->DataConstantUsedForSizing =
2357 81 : waterCoil.InletAirMassFlowRate; // actual autosized air mass flow rate, not calculated from user input
2358 81 : state.dataSize->DataFractionUsedForSizing = 78.5;
2359 81 : TempSize = waterCoil.FinSurfArea;
2360 :
2361 81 : AutoCalculateSizer sizerFinSurfaceArea;
2362 81 : stringOverride = "Fin Surface Area [m2]";
2363 81 : if (state.dataGlobal->isEpJSON) {
2364 0 : stringOverride = "fin_surface_area [m2]";
2365 : }
2366 81 : sizerFinSurfaceArea.overrideSizingString(stringOverride);
2367 81 : sizerFinSurfaceArea.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
2368 81 : waterCoil.FinSurfArea = sizerFinSurfaceArea.size(state, TempSize, ErrorsFound);
2369 :
2370 : // Auto size water coil total tube inside surface area = 4.4 * WaterCoil( CoilNum ).TubeInsideDiam * WaterCoil( CoilNum
2371 : // ).NumOfTubeRows * WaterCoil( CoilNum ).NumOfTubesPerRow
2372 81 : state.dataSize->DataConstantUsedForSizing = waterCoil.TubeInsideDiam * waterCoil.NumOfTubeRows * waterCoil.NumOfTubesPerRow;
2373 81 : state.dataSize->DataFractionUsedForSizing = 4.4;
2374 81 : TempSize = waterCoil.TotTubeInsideArea;
2375 :
2376 81 : AutoCalculateSizer sizerTubeInsideArea;
2377 81 : stringOverride = "Total Tube Inside Area [m2]";
2378 81 : if (state.dataGlobal->isEpJSON) {
2379 0 : stringOverride = "total_tube_inside_area [m2]";
2380 : }
2381 81 : sizerTubeInsideArea.overrideSizingString(stringOverride);
2382 81 : sizerTubeInsideArea.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
2383 81 : waterCoil.TotTubeInsideArea = sizerTubeInsideArea.size(state, TempSize, ErrorsFound);
2384 :
2385 : // Auto size water coil total tube outside surface area = 4.1 * WaterCoil( CoilNum ).TubeOutsideDiam * WaterCoil( CoilNum
2386 : // ).NumOfTubeRows * WaterCoil( CoilNum ).NumOfTubesPerRow
2387 81 : state.dataSize->DataConstantUsedForSizing = waterCoil.TubeOutsideDiam * waterCoil.NumOfTubeRows * waterCoil.NumOfTubesPerRow;
2388 81 : state.dataSize->DataFractionUsedForSizing = 4.1;
2389 81 : TempSize = waterCoil.TubeOutsideSurfArea;
2390 :
2391 81 : AutoCalculateSizer sizerTubeOutsideArea;
2392 81 : stringOverride = "Tube Outside Surface Area [m2]";
2393 81 : if (state.dataGlobal->isEpJSON) {
2394 0 : stringOverride = "tube_outside_surface_area [m2]";
2395 : }
2396 81 : sizerTubeOutsideArea.overrideSizingString(stringOverride);
2397 81 : sizerTubeOutsideArea.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
2398 81 : waterCoil.TubeOutsideSurfArea = sizerTubeOutsideArea.size(state, TempSize, ErrorsFound);
2399 :
2400 81 : if ((waterCoil.FinSurfArea + waterCoil.TubeOutsideSurfArea) <= 0.0) {
2401 0 : ShowSevereError(state, format("Coil:Cooling:Water:DetailedGeometry: \"{}\"", waterCoil.Name));
2402 0 : ShowContinueError(
2403 : state,
2404 0 : format("Coil Fin Surface Area plus Coil Tube Outside Surface Area must be greater than 0. Total surface area = {:.6T}",
2405 0 : (waterCoil.FinSurfArea + waterCoil.TubeOutsideSurfArea)));
2406 0 : ErrorsFound = true;
2407 : }
2408 :
2409 : // Auto size water coil coil depth = WaterCoil( CoilNum ).TubeDepthSpacing * WaterCoil( CoilNum ).NumOfTubeRows
2410 81 : state.dataSize->DataConstantUsedForSizing = waterCoil.TubeDepthSpacing;
2411 81 : state.dataSize->DataFractionUsedForSizing = waterCoil.NumOfTubeRows;
2412 81 : TempSize = waterCoil.CoilDepth;
2413 :
2414 81 : AutoCalculateSizer sizerCoilDepth;
2415 81 : stringOverride = "Coil Depth [m]";
2416 81 : if (state.dataGlobal->isEpJSON) {
2417 0 : stringOverride = "coil_depth [m]";
2418 : }
2419 81 : sizerCoilDepth.overrideSizingString(stringOverride);
2420 81 : sizerCoilDepth.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
2421 81 : waterCoil.CoilDepth = sizerCoilDepth.size(state, TempSize, ErrorsFound);
2422 81 : }
2423 493 : state.dataSize->DataPltSizCoolNum = 0; // reset all globals to 0 to ensure correct sizing for other child components
2424 493 : state.dataSize->DataWaterLoopNum = 0;
2425 493 : state.dataSize->DataConstantUsedForSizing = 0.0;
2426 493 : state.dataSize->DataFractionUsedForSizing = 0.0;
2427 493 : state.dataSize->DataAirFlowUsedForSizing = 0.0;
2428 493 : state.dataSize->DataFlowUsedForSizing = 0.0;
2429 493 : state.dataSize->DataWaterFlowUsedForSizing = 0.0;
2430 493 : state.dataSize->DataCapacityUsedForSizing = 0.0;
2431 493 : state.dataSize->DataDesInletAirTemp = 0.0;
2432 493 : state.dataSize->DataDesOutletAirTemp = 0.0;
2433 493 : state.dataSize->DataDesOutletAirHumRat = 0.0;
2434 493 : state.dataSize->DataDesInletAirHumRat = 0.0;
2435 493 : state.dataSize->DataDesInletWaterTemp = 0.0;
2436 493 : state.dataSize->DataWaterCoilSizCoolDeltaT = 0.0;
2437 493 : state.dataSize->DataDesAccountForFanHeat = true;
2438 493 : } else {
2439 : // If there is no cooling Plant Sizing object and autosizing was requested, issue fatal error message
2440 103 : if (waterCoil.RequestingAutoSize) {
2441 0 : ShowSevereError(state, "Autosizing of water coil requires a cooling loop Sizing:Plant object");
2442 0 : ShowContinueError(state, format("Occurs in water coil object= {}", waterCoil.Name));
2443 0 : ErrorsFound = true;
2444 : }
2445 : }
2446 : //} // end of cooling Plant Sizing existence IF - ELSE
2447 : } // end cooling coil IF
2448 :
2449 : // if this is a heating coil
2450 3351 : if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterSimpleHeating && waterCoil.RequestingAutoSize) {
2451 : // find the appropriate heating Plant Sizing object
2452 2449 : PltSizHeatNum = PlantUtilities::MyPlantSizingIndex(
2453 : state, "hot water coil", waterCoil.Name, waterCoil.WaterInletNodeNum, waterCoil.WaterOutletNodeNum, LoopErrorsFound);
2454 : }
2455 :
2456 3351 : if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterSimpleHeating) {
2457 :
2458 2755 : if (waterCoil.UseDesignWaterDeltaTemp) {
2459 : // use water design deltaT specified in the heating water coils
2460 114 : state.dataSize->DataWaterCoilSizHeatDeltaT = waterCoil.DesignWaterDeltaTemp;
2461 : } else {
2462 2641 : if (PltSizHeatNum > 0) {
2463 2335 : state.dataSize->DataWaterCoilSizHeatDeltaT = state.dataSize->PlantSizData(PltSizHeatNum).DeltaT;
2464 : }
2465 : }
2466 :
2467 2755 : if (PltSizHeatNum > 0) {
2468 :
2469 2449 : int FieldNum = 0;
2470 2449 : bool NomCapUserInp = false; // flag for whether user has onput a nominal heating capacity
2471 :
2472 2449 : state.dataSize->DataPltSizHeatNum = PltSizHeatNum;
2473 2449 : state.dataSize->DataWaterLoopNum = waterCoil.WaterPlantLoc.loopNum;
2474 2449 : rho = state.dataPlnt->PlantLoop(waterCoil.WaterPlantLoc.loopNum).glycol->getDensity(state, Constant::HWInitConvTemp, RoutineName);
2475 2449 : Cp = state.dataPlnt->PlantLoop(state.dataSize->DataWaterLoopNum).glycol->getSpecificHeat(state, Constant::HWInitConvTemp, RoutineName);
2476 2449 : if (waterCoil.DesTotWaterCoilLoad > 0.0) {
2477 35 : NomCapUserInp = true;
2478 2414 : } else if (state.dataSize->CurSysNum > 0 && state.dataSize->CurSysNum <= state.dataHVACGlobal->NumPrimaryAirSys) {
2479 415 : if (state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).HeatingCapMethod == DataSizing::CapacityPerFloorArea) {
2480 0 : NomCapUserInp = true;
2481 829 : } else if (state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).HeatingCapMethod == DataSizing::HeatingDesignCapacity &&
2482 414 : state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).HeatingTotalCapacity > 0.0) {
2483 0 : NomCapUserInp = true;
2484 : }
2485 : } else {
2486 1999 : NomCapUserInp = false;
2487 : }
2488 2449 : bool bPRINT = false; // do not print this sizing request
2489 2449 : TempSize = DataSizing::AutoSize; // get the autosized air volume flow rate for use in other calculations
2490 2449 : SizingString.clear(); // doesn't matter
2491 2449 : CompType = HVAC::cAllCoilTypes(HVAC::Coil_HeatingWater); // "Coil:Heating:Water"
2492 2449 : std::string const &CompName = waterCoil.Name;
2493 2449 : if (waterCoil.DesiccantRegenerationCoil) {
2494 0 : state.dataSize->DataDesicRegCoil = true;
2495 0 : state.dataSize->DataDesicDehumNum = waterCoil.DesiccantDehumNum;
2496 0 : HeatingCoilDesAirInletTempSizer sizerHeatingDesInletTemp;
2497 0 : ErrorsFound = false;
2498 0 : sizerHeatingDesInletTemp.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
2499 0 : state.dataSize->DataDesInletAirTemp = sizerHeatingDesInletTemp.size(state, DataSizing::AutoSize, ErrorsFound);
2500 :
2501 0 : HeatingCoilDesAirOutletTempSizer sizerHeatingDesOutletTemp;
2502 0 : ErrorsFound = false;
2503 0 : sizerHeatingDesOutletTemp.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
2504 0 : state.dataSize->DataDesOutletAirTemp = sizerHeatingDesOutletTemp.size(state, DataSizing::AutoSize, ErrorsFound);
2505 :
2506 0 : if (state.dataSize->CurOASysNum > 0) {
2507 0 : auto &OASysEqSizing = state.dataSize->OASysEqSizing(state.dataSize->CurOASysNum);
2508 0 : OASysEqSizing.AirFlow = true;
2509 0 : OASysEqSizing.AirVolFlow = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesOutAirVolFlow;
2510 : }
2511 0 : TempSize = DataSizing::AutoSize; // reset back
2512 0 : }
2513 2449 : ErrorsFound = false;
2514 2449 : HeatingAirFlowSizer sizingHeatingAirFlow;
2515 2449 : sizingHeatingAirFlow.overrideSizingString(SizingString);
2516 : // sizingHeatingAirFlow.setHVACSizingIndexData(FanCoil(FanCoilNum).HVACSizingIndex);
2517 2449 : sizingHeatingAirFlow.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
2518 2449 : TempSize = sizingHeatingAirFlow.size(state, TempSize, ErrorsFound);
2519 : // reset the design air volume flow rate for air loop coils only
2520 2449 : if (state.dataSize->CurSysNum > 0) {
2521 416 : waterCoil.DesAirVolFlowRate = TempSize;
2522 : }
2523 2449 : waterCoil.InletAirMassFlowRate = state.dataEnvrn->StdRhoAir * TempSize; // inlet air mass flow rate is not the autosized value
2524 2449 : state.dataSize->DataAirFlowUsedForSizing = TempSize;
2525 2449 : state.dataSize->DataFlowUsedForSizing = TempSize; // many autosized inputs use the design (autosized) air flow rate, save this value
2526 :
2527 2449 : bPRINT = true;
2528 2449 : if (waterCoil.CoilPerfInpMeth == state.dataWaterCoils->NomCap && NomCapUserInp) {
2529 35 : TempSize = waterCoil.DesTotWaterCoilLoad;
2530 35 : state.dataSize->DataNomCapInpMeth = true;
2531 : } else {
2532 2414 : TempSize = DataSizing::AutoSize;
2533 : }
2534 2449 : if (state.dataSize->CurSysNum > 0) {
2535 416 : FieldNum = 3; // N3 , \field Rated Capacity
2536 416 : SizingString = state.dataWaterCoils->WaterCoilNumericFields(CoilNum).FieldNames(FieldNum) + " [W]";
2537 416 : ErrorsFound = false;
2538 416 : HeatingCapacitySizer sizerHeatingCapacity;
2539 416 : sizerHeatingCapacity.overrideSizingString(SizingString);
2540 416 : sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
2541 416 : TempSize = sizerHeatingCapacity.size(state, TempSize, ErrorsFound);
2542 416 : waterCoil.DesWaterHeatingCoilRate = TempSize;
2543 416 : waterCoil.DesTotWaterCoilLoad = TempSize;
2544 416 : state.dataSize->DataCapacityUsedForSizing = waterCoil.DesWaterHeatingCoilRate;
2545 416 : } else {
2546 2033 : WaterHeatingCapacitySizer sizerWaterHeatingCapacity;
2547 2033 : ErrorsFound = false;
2548 2033 : sizerWaterHeatingCapacity.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
2549 2033 : waterCoil.DesWaterHeatingCoilRate = sizerWaterHeatingCapacity.size(state, TempSize, ErrorsFound);
2550 2033 : waterCoil.DesTotWaterCoilLoad = waterCoil.DesWaterHeatingCoilRate;
2551 2033 : state.dataSize->DataCapacityUsedForSizing = waterCoil.DesWaterHeatingCoilRate;
2552 2033 : }
2553 :
2554 : // We now have the design load if it was autosized. For the case of CoilPerfInpMeth == NomCap, calculate the air flow rate
2555 : // specified by the NomCap inputs. This overrides all previous values
2556 2449 : if (waterCoil.CoilPerfInpMeth == state.dataWaterCoils->NomCap && NomCapUserInp) {
2557 35 : waterCoil.InletAirMassFlowRate =
2558 35 : waterCoil.DesTotWaterCoilLoad / (CpAirStd * (waterCoil.DesOutletAirTemp - waterCoil.DesInletAirTemp));
2559 35 : waterCoil.DesAirVolFlowRate = waterCoil.InletAirMassFlowRate / state.dataEnvrn->StdRhoAir;
2560 35 : state.dataSize->DataAirFlowUsedForSizing = waterCoil.DesAirVolFlowRate;
2561 35 : state.dataSize->DataFlowUsedForSizing = waterCoil.DesAirVolFlowRate;
2562 : }
2563 :
2564 2449 : TempSize = waterCoil.MaxWaterVolFlowRate;
2565 :
2566 2449 : if (waterCoil.CoilPerfInpMeth == state.dataWaterCoils->NomCap && NomCapUserInp) {
2567 35 : if (waterCoil.DesTotWaterCoilLoad > HVAC::SmallLoad) {
2568 35 : waterCoil.MaxWaterVolFlowRate =
2569 35 : state.dataSize->DataCapacityUsedForSizing / (Cp * rho * (waterCoil.DesInletWaterTemp - waterCoil.DesOutletWaterTemp));
2570 : } else {
2571 0 : waterCoil.MaxWaterVolFlowRate = 0.0;
2572 : }
2573 35 : state.dataSize->DataConstantUsedForSizing = waterCoil.MaxWaterVolFlowRate;
2574 35 : state.dataSize->DataFractionUsedForSizing = 1.0;
2575 : }
2576 2449 : HeatingWaterflowSizer sizerHWWaterflow;
2577 2449 : sizerHWWaterflow.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
2578 2449 : Real64 sizedMaxWaterVolFlowRate = sizerHWWaterflow.size(state, TempSize, ErrorsFound);
2579 : // Check if the water flow rate is defined in parent HVAC equipment and set water coil design water flow rate accordingly
2580 2449 : if (state.dataSize->CurZoneEqNum > 0) {
2581 2033 : auto const &ZoneEqSizing = state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum);
2582 2033 : if (ZoneEqSizing.DesignSizeFromParent) {
2583 80 : state.dataSize->DataWaterFlowUsedForSizing = ZoneEqSizing.MaxHWVolFlow;
2584 80 : waterCoil.MaxWaterVolFlowRate = ZoneEqSizing.MaxHWVolFlow;
2585 : } else {
2586 1953 : state.dataSize->DataWaterFlowUsedForSizing = sizedMaxWaterVolFlowRate;
2587 1953 : waterCoil.MaxWaterVolFlowRate = sizedMaxWaterVolFlowRate;
2588 : }
2589 : } else {
2590 416 : state.dataSize->DataWaterFlowUsedForSizing = sizedMaxWaterVolFlowRate;
2591 416 : waterCoil.MaxWaterVolFlowRate = sizedMaxWaterVolFlowRate;
2592 : }
2593 2449 : state.dataSize->DataConstantUsedForSizing = 0.0; // reset these in case NomCapUserInp was true
2594 2449 : state.dataSize->DataFractionUsedForSizing = 0.0;
2595 2449 : if (waterCoil.MaxWaterVolFlowRate <= 0.0) {
2596 : // MaxWaterVolFlowRateDes = 0.0;
2597 31 : ShowWarningError(state, format("The design coil load is zero for Coil:Heating:Water {}", waterCoil.Name));
2598 62 : ShowContinueError(state, "The autosize value for maximum water flow rate is zero");
2599 62 : ShowContinueError(state, "To change this, input a value for UA, change the heating design day, or raise the");
2600 62 : ShowContinueError(state, " system heating design supply air temperature. Also check to make sure the Preheat");
2601 93 : ShowContinueError(state, " Design Temperature is not the same as the Central Heating Design Supply Air Temperature. ");
2602 : }
2603 :
2604 : // initialize the water coil inlet conditions
2605 2449 : bPRINT = false; // no need to print to eio since we only need the values
2606 2449 : state.dataSize->DataFlowUsedForSizing = state.dataSize->DataAirFlowUsedForSizing;
2607 2449 : if (waterCoil.CoilPerfInpMeth == state.dataWaterCoils->NomCap && NomCapUserInp) {
2608 35 : waterCoil.InletAirTemp = waterCoil.DesInletAirTemp;
2609 35 : waterCoil.InletAirHumRat = PsyWFnTdbRhPb(state, waterCoil.DesInletAirTemp, 0.5, state.dataEnvrn->StdBaroPress, RoutineName);
2610 35 : waterCoil.InletAirMassFlowRate = state.dataSize->DataAirFlowUsedForSizing * state.dataEnvrn->StdRhoAir; // don't need this
2611 35 : state.dataSize->DataDesOutletAirTemp = waterCoil.DesOutletAirTemp; // for error messages
2612 70 : state.dataSize->DataDesOutletAirHumRat =
2613 35 : PsyWFnTdbRhPb(state, state.dataSize->DataDesOutletAirTemp, 0.5, state.dataEnvrn->StdBaroPress, RoutineName); // for error messages
2614 35 : waterCoil.InletWaterMassFlowRate = rho * state.dataSize->DataWaterFlowUsedForSizing;
2615 35 : waterCoil.MaxWaterMassFlowRate = rho * state.dataSize->DataWaterFlowUsedForSizing;
2616 35 : waterCoil.InletWaterTemp = waterCoil.DesInletWaterTemp;
2617 2414 : } else if (waterCoil.DesiccantRegenerationCoil) {
2618 0 : waterCoil.InletAirTemp = state.dataSize->DataDesInletAirTemp;
2619 0 : HeatingCoilDesAirInletHumRatSizer sizerHeatingDesInletHumRat;
2620 0 : ErrorsFound = false;
2621 0 : sizerHeatingDesInletHumRat.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
2622 0 : waterCoil.DesInletAirHumRat = sizerHeatingDesInletHumRat.size(state, DataSizing::AutoSize, ErrorsFound);
2623 0 : waterCoil.InletAirHumRat = waterCoil.DesInletAirHumRat;
2624 :
2625 0 : waterCoil.DesAirVolFlowRate = state.dataSize->DataAirFlowUsedForSizing; // coil report
2626 0 : waterCoil.InletAirMassFlowRate = state.dataSize->DataAirFlowUsedForSizing * state.dataEnvrn->StdRhoAir; // this is stiil volume flow!
2627 0 : } else {
2628 2414 : HeatingWaterDesAirInletTempSizer sizerHWDesInletTemp;
2629 2414 : sizerHWDesInletTemp.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
2630 2414 : waterCoil.InletAirTemp = sizerHWDesInletTemp.size(state, DataSizing::AutoSize, ErrorsFound);
2631 :
2632 2414 : HeatingWaterDesAirInletHumRatSizer sizerHWAirInletHumRat;
2633 2414 : sizerHWAirInletHumRat.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
2634 2414 : waterCoil.DesInletAirHumRat = sizerHWAirInletHumRat.size(state, DataSizing::AutoSize, ErrorsFound);
2635 2414 : waterCoil.InletAirHumRat = waterCoil.DesInletAirHumRat;
2636 :
2637 2414 : HeatingAirflowUASizer sizerHWAirFlowUA;
2638 2414 : sizerHWAirFlowUA.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
2639 2414 : waterCoil.DesAirMassFlowRate = sizerHWAirFlowUA.size(state, DataSizing::AutoSize, ErrorsFound);
2640 2414 : waterCoil.InletAirMassFlowRate = waterCoil.DesAirMassFlowRate;
2641 2414 : }
2642 :
2643 : // zone and air loop coils use different design coil load calculations, air loop coils use air side capacity,
2644 : // zone coils use water side capacity
2645 2449 : state.dataSize->DataDesInletAirTemp = waterCoil.InletAirTemp; // used in error mesages
2646 2449 : state.dataSize->DataDesInletAirHumRat = waterCoil.InletAirHumRat; // used in error mesages
2647 2449 : state.dataSize->DataFlowUsedForSizing = state.dataSize->DataAirFlowUsedForSizing * state.dataEnvrn->StdRhoAir; // used in error mesages
2648 2449 : waterCoil.MaxWaterVolFlowRate = state.dataSize->DataWaterFlowUsedForSizing; // why is this here?
2649 2449 : if (!(waterCoil.CoilPerfInpMeth == state.dataWaterCoils->NomCap && NomCapUserInp)) {
2650 : // get the design coil load used to size UA
2651 2414 : HeatingWaterDesCoilLoadUsedForUASizer sizerHWDesCoilLoadForUA;
2652 2414 : sizerHWDesCoilLoadForUA.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
2653 2414 : state.dataSize->DataCapacityUsedForSizing = sizerHWDesCoilLoadForUA.size(state, DataSizing::AutoSize, ErrorsFound);
2654 : // get the water volume flow rate used to size UA
2655 2414 : HeatingWaterDesCoilWaterVolFlowUsedForUASizer sizerHWWaterVolFlowUA;
2656 2414 : sizerHWWaterVolFlowUA.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
2657 2414 : state.dataSize->DataWaterFlowUsedForSizing = sizerHWWaterVolFlowUA.size(state, DataSizing::AutoSize, ErrorsFound);
2658 2414 : waterCoil.InletWaterTemp = state.dataSize->PlantSizData(PltSizHeatNum).ExitTemp;
2659 2414 : waterCoil.InletWaterMassFlowRate = rho * state.dataSize->DataWaterFlowUsedForSizing;
2660 2414 : waterCoil.MaxWaterMassFlowRate = rho * state.dataSize->DataWaterFlowUsedForSizing;
2661 2414 : waterCoil.DesWaterHeatingCoilRate = state.dataSize->DataCapacityUsedForSizing;
2662 2414 : }
2663 : // calculate UA
2664 2449 : if (state.dataSize->CurSysNum > 0) {
2665 416 : waterCoil.DesTotWaterCoilLoad = state.dataSize->DataCapacityUsedForSizing;
2666 : }
2667 2449 : FieldNum = 1; // N1 , \field U-Factor Times Area Value
2668 2449 : bPRINT = true; // report to eio the UA value
2669 2449 : SizingString = state.dataWaterCoils->WaterCoilNumericFields(CoilNum).FieldNames(FieldNum) + " [W/K]";
2670 2449 : state.dataSize->DataCoilNum = CoilNum;
2671 2449 : state.dataSize->DataFanOp = HVAC::FanOp::Continuous;
2672 2449 : if (waterCoil.CoilPerfInpMeth == state.dataWaterCoils->NomCap && NomCapUserInp) {
2673 35 : TempSize = DataSizing::AutoSize;
2674 : } else {
2675 2414 : TempSize = waterCoil.UACoil;
2676 : }
2677 :
2678 2449 : state.dataSize->DataFlowUsedForSizing = waterCoil.InletAirMassFlowRate;
2679 2449 : DesCoilWaterInTempSaved = state.dataWaterCoils->WaterCoil(state.dataSize->DataCoilNum).InletWaterTemp;
2680 2449 : if (DesCoilWaterInTempSaved < HVAC::DesCoilHWInletTempMin) {
2681 : // at low coil design water inlet temp, sizing has convergence issue hence slightly higher water inlet temperature
2682 : // is estimated in "EstimateCoilInletWaterTemp" and used for UA autosizing only
2683 0 : EstimateCoilInletWaterTemp(state,
2684 0 : state.dataSize->DataCoilNum,
2685 0 : state.dataSize->DataFanOp,
2686 : 1.0,
2687 0 : state.dataSize->DataCapacityUsedForSizing,
2688 : DesCoilInletWaterTempUsed);
2689 0 : state.dataWaterCoils->WaterCoil(state.dataSize->DataCoilNum).InletWaterTemp = DesCoilInletWaterTempUsed;
2690 : }
2691 : // must set DataCapacityUsedForSizing, DataWaterFlowUsedForSizing and DataFlowUsedForSizing to size UA. Any value of 0 will result
2692 : // in UA = 1.
2693 2449 : WaterHeatingCoilUASizer sizerHWCoilUA;
2694 2449 : sizerHWCoilUA.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
2695 2449 : waterCoil.UACoil = sizerHWCoilUA.size(state, TempSize, ErrorsFound);
2696 2449 : if (DesCoilWaterInTempSaved < HVAC::DesCoilHWInletTempMin) {
2697 0 : ShowWarningError(state, format("Autosizing of heating coil UA for Coil:Heating:Water \"{}\"", CompName));
2698 0 : ShowContinueError(state,
2699 0 : format(" Plant design loop exit temperature = {:.2T} C",
2700 0 : state.dataSize->PlantSizData(state.dataSize->DataPltSizHeatNum).ExitTemp));
2701 0 : ShowContinueError(state, " Plant design loop exit temperature is low for design load and leaving air temperature anticipated.");
2702 0 : ShowContinueError(state,
2703 0 : format(" Heating coil UA-value is sized using coil water inlet temperature = {:.2T} C", DesCoilInletWaterTempUsed));
2704 0 : state.dataWaterCoils->WaterCoil(state.dataSize->DataCoilNum).InletWaterTemp =
2705 : DesCoilWaterInTempSaved; // reset the Design Coil Inlet Water Temperature
2706 : }
2707 : // if coil UA did not size due to one of these variables being 0, must set UACoilVariable to avoid crash later on
2708 4867 : if (state.dataSize->DataCapacityUsedForSizing == 0.0 || state.dataSize->DataWaterFlowUsedForSizing == 0.0 ||
2709 2418 : state.dataSize->DataFlowUsedForSizing == 0.0) {
2710 31 : if (waterCoil.UACoilVariable == DataSizing::AutoSize) {
2711 31 : waterCoil.UACoilVariable = waterCoil.UACoil;
2712 : }
2713 : }
2714 : // WaterCoil(CoilNum).UACoilVariable = WaterCoil(CoilNum).UACoil;
2715 2449 : waterCoil.DesWaterHeatingCoilRate = state.dataSize->DataCapacityUsedForSizing;
2716 2449 : state.dataWaterCoils->WaterCoil(state.dataSize->DataCoilNum).InletWaterTemp =
2717 : DesCoilWaterInTempSaved; // reset the Design Coil Inlet Water Temperature
2718 :
2719 2449 : state.dataSize->DataWaterLoopNum = 0; // reset all globals to 0 to ensure correct sizing for other child components
2720 2449 : state.dataSize->DataPltSizHeatNum = 0;
2721 2449 : state.dataSize->DataCoilNum = 0;
2722 2449 : state.dataSize->DataFanOp = HVAC::FanOp::Invalid;
2723 2449 : state.dataSize->DataCapacityUsedForSizing = 0.0;
2724 2449 : state.dataSize->DataWaterFlowUsedForSizing = 0.0;
2725 2449 : state.dataSize->DataDesInletAirTemp = 0.0;
2726 2449 : state.dataSize->DataDesInletAirHumRat = 0.0;
2727 2449 : state.dataSize->DataDesOutletAirTemp = 0.0;
2728 2449 : state.dataSize->DataDesOutletAirHumRat = 0.0;
2729 2449 : state.dataSize->DataAirFlowUsedForSizing = 0.0;
2730 2449 : state.dataSize->DataFlowUsedForSizing = 0.0;
2731 2449 : state.dataSize->DataDesicDehumNum = 0;
2732 2449 : state.dataSize->DataDesicRegCoil = false;
2733 2449 : state.dataSize->DataWaterCoilSizHeatDeltaT = 0.0;
2734 2449 : state.dataSize->DataNomCapInpMeth = false;
2735 :
2736 2449 : } else {
2737 : // if there is no heating Plant Sizing object and autosizng was requested, issue an error message
2738 306 : if (waterCoil.RequestingAutoSize) {
2739 0 : ShowSevereError(state, "Autosizing of water coil requires a heating loop Sizing:Plant object");
2740 0 : ShowContinueError(state, format("Occurs in water coil object= {}", waterCoil.Name));
2741 0 : ErrorsFound = true;
2742 : }
2743 : }
2744 : //} // end of heating Plant Sizing existence IF - ELSE
2745 : } // end heating coil IF
2746 :
2747 : // save the design water volumetric flow rate for use by the water loop sizing algorithms
2748 3351 : if (waterCoil.MaxWaterVolFlowRate > 0.0) {
2749 3318 : PlantUtilities::RegisterPlantCompDesignFlow(state, waterCoil.WaterInletNodeNum, waterCoil.MaxWaterVolFlowRate);
2750 : }
2751 :
2752 3351 : if (ErrorsFound || state.dataSize->DataErrorsFound) {
2753 0 : ShowFatalError(state, "Preceding water coil sizing errors cause program termination");
2754 : }
2755 3351 : }
2756 :
2757 : // End Initialization Section of the Module
2758 : //******************************************************************************
2759 :
2760 : // Begin Algorithm Section of the Module
2761 : //******************************************************************************
2762 :
2763 122023874 : void CalcSimpleHeatingCoil(EnergyPlusData &state,
2764 : int const CoilNum, // index to heating coil
2765 : HVAC::FanOp const fanOp, // fan operating mode
2766 : Real64 const PartLoadRatio, // part-load ratio of heating coil
2767 : int const CalcMode // 1 = design calc; 2 = simulation calculation
2768 : )
2769 : {
2770 : // SUBROUTINE INFORMATION:
2771 : // AUTHOR Rich Liesen
2772 : // DATE WRITTEN
2773 : // MODIFIED Aug. 2007 - R. Raustad, added fan operating mode and part-load ratio to
2774 : // calculate the outlet conditions when fan and coil cycle.
2775 : // Air and water outlet temperature are full output with average
2776 : // air and water mass flow rate when fan and coil cycle.
2777 : // RE-ENGINEERED na
2778 :
2779 : // PURPOSE OF THIS SUBROUTINE:
2780 : // Simulates a simple NTU effectiveness model heating coil
2781 :
2782 : // METHODOLOGY EMPLOYED:
2783 : // (1) outlet conditions are calculated from the effectiveness and the inlet conditions.
2784 : // (2) Effectiveness is calculated from the NTU formula for a cross flow heat exchanger
2785 : // with both streams unmixed.
2786 : // Note: UA is input by user and is fixed.
2787 :
2788 : // REFERENCES:
2789 : // See for instance ASHRAE HVAC 2 Toolkit, page 4-4, formula (4-7)
2790 :
2791 : // Using/Aliasing
2792 :
2793 : // Locals
2794 : // SUBROUTINE ARGUMENT DEFINITIONS:
2795 :
2796 : // SUBROUTINE PARAMETER DEFINITIONS:
2797 : static constexpr std::string_view RoutineName("CalcSimpleHeatingCoil");
2798 :
2799 : // INTERFACE BLOCK SPECIFICATIONS
2800 : // na
2801 :
2802 : // DERIVED TYPE DEFINITIONS
2803 : // na
2804 :
2805 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2806 : Real64 WaterMassFlowRate;
2807 : Real64 AirMassFlow; // [kg/sec]
2808 : Real64 TempAirIn; // [C]
2809 : Real64 TempAirOut; // [C]
2810 : Real64 Win;
2811 : Real64 TempWaterIn;
2812 : Real64 TempWaterOut;
2813 : Real64 UA;
2814 : Real64 CapacitanceAir;
2815 : Real64 CapacitanceWater;
2816 : Real64 CapacitanceMin;
2817 : Real64 CapacitanceMax;
2818 : Real64 HeatingCoilLoad;
2819 : Real64 NTU;
2820 : Real64 ETA;
2821 : Real64 A;
2822 : Real64 CapRatio;
2823 : Real64 E1;
2824 : Real64 E2;
2825 : Real64 Effec;
2826 : Real64 Cp;
2827 :
2828 122023874 : auto &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
2829 122023874 : UA = waterCoil.UACoilVariable;
2830 122023874 : TempAirIn = waterCoil.InletAirTemp;
2831 122023874 : Win = waterCoil.InletAirHumRat;
2832 122023874 : TempWaterIn = waterCoil.InletWaterTemp;
2833 :
2834 : // adjust mass flow rates for cycling fan cycling coil operation
2835 122023874 : if (fanOp == HVAC::FanOp::Cycling) {
2836 2223372 : if (PartLoadRatio > 0.0) {
2837 1637750 : AirMassFlow = waterCoil.InletAirMassFlowRate / PartLoadRatio;
2838 1637750 : WaterMassFlowRate = min(waterCoil.InletWaterMassFlowRate / PartLoadRatio, waterCoil.MaxWaterMassFlowRate);
2839 : } else {
2840 585622 : AirMassFlow = 0.0;
2841 585622 : WaterMassFlowRate = 0.0;
2842 : }
2843 : } else {
2844 119800502 : AirMassFlow = waterCoil.InletAirMassFlowRate;
2845 119800502 : WaterMassFlowRate = waterCoil.InletWaterMassFlowRate;
2846 : }
2847 :
2848 122023874 : if (WaterMassFlowRate > DataBranchAirLoopPlant::MassFlowTolerance) { // If the coil is operating
2849 77360012 : CapacitanceAir = PsyCpAirFnW(Win) * AirMassFlow;
2850 77360012 : Cp = state.dataPlnt->PlantLoop(waterCoil.WaterPlantLoc.loopNum).glycol->getSpecificHeat(state, TempWaterIn, RoutineName);
2851 77360012 : CapacitanceWater = Cp * WaterMassFlowRate;
2852 77360012 : CapacitanceMin = min(CapacitanceAir, CapacitanceWater);
2853 77360012 : CapacitanceMax = max(CapacitanceAir, CapacitanceWater);
2854 : } else {
2855 44663862 : CapacitanceAir = 0.0;
2856 44663862 : CapacitanceWater = 0.0;
2857 : }
2858 :
2859 : // If the coil is operating there should be some heating capacitance
2860 : // across the coil, so do the simulation. If not set outlet to inlet and no load.
2861 : // Also the coil has to be scheduled to be available
2862 199375588 : if (((CapacitanceAir > 0.0) && (CapacitanceWater > 0.0)) &&
2863 77351714 : (CalcMode == state.dataWaterCoils->DesignCalc || state.dataWaterCoils->MySizeFlag(CoilNum) ||
2864 77302276 : state.dataWaterCoils->MyUAAndFlowCalcFlag(CoilNum) || waterCoil.availSched->getCurrentVal() > 0.0)) {
2865 :
2866 77285158 : if (UA <= 0.0) {
2867 0 : ShowFatalError(state, format("UA is zero for COIL:Heating:Water {}", waterCoil.Name));
2868 : }
2869 77285158 : NTU = UA / CapacitanceMin;
2870 77285158 : ETA = std::pow(NTU, 0.22);
2871 77285158 : CapRatio = CapacitanceMin / CapacitanceMax;
2872 77285158 : A = CapRatio * NTU / ETA;
2873 :
2874 77285158 : if (A > 20.0) {
2875 0 : A = ETA * 1.0 / CapRatio;
2876 : } else {
2877 77285158 : E1 = std::exp(-A);
2878 77285158 : A = ETA * (1.0 - E1) / CapRatio;
2879 : }
2880 :
2881 77285158 : if (A > 20.0) {
2882 216670 : Effec = 1.0;
2883 : } else {
2884 77068488 : E2 = std::exp(-A);
2885 77068488 : Effec = 1.0 - E2;
2886 : }
2887 :
2888 77285158 : TempAirOut = TempAirIn + Effec * CapacitanceMin * (TempWaterIn - TempAirIn) / CapacitanceAir;
2889 77285158 : TempWaterOut = TempWaterIn - CapacitanceAir * (TempAirOut - TempAirIn) / CapacitanceWater;
2890 77285158 : HeatingCoilLoad = CapacitanceWater * (TempWaterIn - TempWaterOut);
2891 : // The HeatingCoilLoad is the change in the enthalpy of the water
2892 77285158 : waterCoil.OutletWaterEnthalpy = waterCoil.InletWaterEnthalpy - HeatingCoilLoad / waterCoil.InletWaterMassFlowRate;
2893 77285158 : waterCoil.OutletWaterMassFlowRate = waterCoil.InletWaterMassFlowRate;
2894 :
2895 : } else { // If not running Conditions do not change across coil from inlet to outlet
2896 :
2897 44738716 : TempAirOut = TempAirIn;
2898 44738716 : TempWaterOut = TempWaterIn;
2899 44738716 : HeatingCoilLoad = 0.0;
2900 44738716 : waterCoil.OutletWaterEnthalpy = waterCoil.InletWaterEnthalpy;
2901 44738716 : waterCoil.OutletWaterMassFlowRate = 0.0;
2902 : }
2903 :
2904 122023874 : if (fanOp == HVAC::FanOp::Cycling) {
2905 2223372 : HeatingCoilLoad *= PartLoadRatio;
2906 : }
2907 :
2908 : // Set the outlet conditions
2909 122023874 : waterCoil.TotWaterHeatingCoilRate = HeatingCoilLoad;
2910 122023874 : waterCoil.OutletAirTemp = TempAirOut;
2911 122023874 : waterCoil.OutletWaterTemp = TempWaterOut;
2912 :
2913 : // This WaterCoil does not change the moisture or Mass Flow across the component
2914 122023874 : waterCoil.OutletAirHumRat = waterCoil.InletAirHumRat;
2915 122023874 : waterCoil.OutletAirMassFlowRate = waterCoil.InletAirMassFlowRate;
2916 : // Set the outlet enthalpys for air and water
2917 122023874 : waterCoil.OutletAirEnthalpy = PsyHFnTdbW(waterCoil.OutletAirTemp, waterCoil.OutletAirHumRat);
2918 122023874 : }
2919 :
2920 4921265 : void CalcDetailFlatFinCoolingCoil(EnergyPlusData &state,
2921 : int const CoilNum,
2922 : int const CalcMode,
2923 : HVAC::FanOp const fanOp, // fan operating mode
2924 : Real64 const PartLoadRatio // part-load ratio of heating coil
2925 : )
2926 : {
2927 :
2928 : // SUBROUTINE INFORMATION:
2929 : // AUTHOR(S) Russell Taylor / Richard Liesen
2930 : // DATE WRITTEN Mar 1997
2931 : // MODIFIED Feb 2010, B. Nigusse, FSEC, corrected units inconsistency for tube and fins
2932 : // materials thermal conductivties. Now input values in the idf are in {W/(m.K)}
2933 : // RE-ENGINEERED Sept 1998
2934 :
2935 : // PURPOSE OF THIS SUBROUTINE:
2936 : // This subroutine simulates a chilled water cooling coil. Provided with
2937 : // the coil geometry and the flow (i.e. air and water) inlet conditions,
2938 : // it will calculate the flow outlet conditions and the total and latent
2939 : // heat extraction rates from the air. The coil model has some limitations
2940 : // as noted in the code.
2941 :
2942 : // METHODOLOGY EMPLOYED:
2943 : // successive substitution, solve coil as if all wet, then
2944 : // again if partly or entirely dry
2945 :
2946 : // REFERENCES:
2947 : // First found in Type 12 from MODSIM, but now
2948 : // programmed directly from Elmahdy, A.H. and Mitalas, G.P. "A
2949 : // Simple Model for Cooling and Dehumidifying Coils for Use in
2950 : // Calculating Energy Requirements for Buildings" _ASHRAE
2951 : // Transactions_ Vol. 83, Part 2, pp. 103-117 (1977).
2952 :
2953 : // OTHER NOTES:
2954 : // Routine was originally adapted for use in IBLAST by R.D. Taylor in l993.
2955 : // Subsequently rewritten and improved by J.C. Vanderzee in 1994
2956 : // Revised and further enhanced by R.D. Taylor in Jan 1996
2957 : // Re-engineered for EnergyPlus by Richard Liesen PhD in 1998
2958 :
2959 : // Using/Aliasing
2960 :
2961 : // Locals
2962 : // SUBROUTINE ARGUMENT DEFINITIONS:
2963 :
2964 : // SUBROUTINE PARAMETER DEFINITIONS:
2965 : static Real64 const exp_47(std::exp(-0.41718));
2966 : static Real64 const exp_35(std::exp(-0.3574));
2967 : static constexpr std::string_view RoutineName("CalcDetailFlatFinCoolingCoil");
2968 :
2969 4921265 : constexpr Real64 AirViscosity(1.846e-5); // Dynamic Viscosity of Air in kg/(m.s)
2970 4921265 : constexpr Real64 ConvK(1.0e-3); // Unit conversion factor
2971 4921265 : constexpr Real64 unity(1.0);
2972 4921265 : constexpr Real64 zero(0.0);
2973 4921265 : constexpr Real64 TubeFoulFactor(5.0e-2); // Inside tube fouling factor for water, in m2K/kW
2974 : // Changed from m2K/W to m2K/kW for consistency with the
2975 : // other parameters in "TubeFoulThermResis" calculation
2976 :
2977 : // INTERFACE BLOCK SPECIFICATIONS
2978 : // na
2979 :
2980 : // DERIVED TYPE DEFINITIONS
2981 : // na
2982 :
2983 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2984 : // INTEGER :: CoolCoilErrs = 0
2985 :
2986 : Real64 AirEnthAtRsdInletWaterTemp;
2987 : Real64 AirExitEnthlAtCoilSurfTemp;
2988 : Real64 AirExitCoilSurfTemp;
2989 : Real64 AirReynoldsNo;
2990 : Real64 AirEnthAtWetDryIntrfcSurfTemp;
2991 : Real64 AirSideDrySurfFilmCoef;
2992 : Real64 AirSideWetSurfFilmCoef;
2993 : Real64 AirWetDryInterfcTemp;
2994 : Real64 CoilToAirThermResistDrySurf;
2995 : Real64 CoilToAirThermResistWetSurf;
2996 : Real64 DryAirSpecHeat;
2997 : Real64 DryCoilCoeff1;
2998 : Real64 DryCoilCoeff;
2999 : Real64 DryCoilEfficiency;
3000 : Real64 DryFinEfficncy;
3001 : Real64 DryCoilInThermResist;
3002 : Real64 DrySideEffectiveWaterTemp;
3003 : Real64 EnterAirDewPoint;
3004 : Real64 EnterAirHumRatDiff;
3005 : Real64 WetDryInterSurfTempErrorLast;
3006 : Real64 WetDryInterSurfTempError;
3007 : Real64 expon;
3008 : Real64 FilmCoefEqnFactor;
3009 : Real64 FilmCoefReynldsCorrelatnFact;
3010 : Real64 FinToTotSurfAreaRatio;
3011 : Real64 InCoilSurfTemp;
3012 : Real64 InsdToOutsdThermResistRatio;
3013 : Real64 InSurfTempSatAirEnthl;
3014 : Real64 K1;
3015 : Real64 MeanWaterTemp;
3016 : Real64 MoistAirSpecificHeat;
3017 : Real64 OutCoilSurfTemp;
3018 : Real64 OutSurfTempSatAirEnthl;
3019 : Real64 RaisedInletWaterTemp;
3020 : Real64 RsdInletWaterTempSatAirHumRat;
3021 : Real64 ScaledAirMassFlowRate;
3022 : Real64 ScaledCoilAirThermResistWetSurf;
3023 : Real64 ScaledWaterSpecHeat;
3024 : Real64 ScaledWaterToTubeThermResist;
3025 : Real64 SensToTotEnthDiffRatio;
3026 : Real64 SurfAreaWet;
3027 : Real64 TubeFoulThermResist;
3028 : Real64 TubeWaterVel;
3029 : Real64 UACoilAllWet;
3030 : Real64 UACoilPartWet;
3031 : Real64 UADryCoil;
3032 : Real64 WaterToTubeThermResist;
3033 : Real64 WetAreaChange;
3034 : Real64 WetAreaLast;
3035 : Real64 WetCoilCoeff;
3036 : Real64 WetCoilFinEfficncy;
3037 : Real64 WetDryInterfcAirEnthl;
3038 : Real64 WetDryInterfcSurfTemp;
3039 : Real64 WetDryInterfcWaterTemp;
3040 : Real64 WetFinEfficncy;
3041 : Real64 WetSideEffctvWaterTemp;
3042 : Real64 y;
3043 : Real64 TempAirIn;
3044 : Real64 TempAirOut;
3045 : Real64 InletAirHumRat;
3046 : Real64 OutletAirHumRat;
3047 : Real64 InletAirEnthalpy;
3048 : Real64 OutletAirEnthalpy;
3049 : Real64 WaterMassFlowRate;
3050 : Real64 AirMassFlow;
3051 : Real64 TempWaterIn;
3052 : Real64 TempWaterOut;
3053 : Real64 TotWaterCoilLoad;
3054 : Real64 SenWaterCoilLoad;
3055 : Real64 AirDensity;
3056 : Real64 AirVelocity;
3057 : Real64 denom;
3058 : Real64 rho;
3059 : Real64 Cp;
3060 :
3061 : // Set derived type variables to shorter local variables
3062 4921265 : auto &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
3063 4921265 : TempAirIn = waterCoil.InletAirTemp;
3064 4921265 : InletAirHumRat = waterCoil.InletAirHumRat;
3065 4921265 : TempWaterIn = waterCoil.InletWaterTemp;
3066 :
3067 : // adjust mass flow rates for cycling fan cycling coil operation
3068 4921265 : if (fanOp == HVAC::FanOp::Cycling) {
3069 0 : if (PartLoadRatio > 0.0) {
3070 0 : AirMassFlow = waterCoil.InletAirMassFlowRate / PartLoadRatio;
3071 0 : WaterMassFlowRate = min(waterCoil.InletWaterMassFlowRate / PartLoadRatio, waterCoil.MaxWaterMassFlowRate);
3072 : } else {
3073 0 : AirMassFlow = 0.0;
3074 0 : WaterMassFlowRate = 0.0;
3075 : }
3076 : } else {
3077 4921265 : AirMassFlow = waterCoil.InletAirMassFlowRate;
3078 4921265 : WaterMassFlowRate = waterCoil.InletWaterMassFlowRate;
3079 : }
3080 :
3081 4921265 : if (WaterMassFlowRate < waterCoil.MaxWaterMassFlowRate * WaterCoils::MinWaterMassFlowFrac) {
3082 2605393 : WaterMassFlowRate = 0.0;
3083 : }
3084 4921265 : if (TempAirIn <= TempWaterIn) {
3085 532192 : WaterMassFlowRate = 0.0;
3086 : }
3087 4921265 : WetDryInterfcAirEnthl = 0.0;
3088 4921265 : OutletAirEnthalpy = 0.0;
3089 4921265 : InletAirEnthalpy = 0.0;
3090 :
3091 : // Warning and error messages for large flow rates for the given user input geometry
3092 4921265 : AirDensity = PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, TempAirIn, InletAirHumRat, RoutineName);
3093 4921265 : if (AirMassFlow > (5.0 * waterCoil.MinAirFlowArea / AirDensity) && state.dataWaterCoils->CoilWarningOnceFlag(CoilNum)) {
3094 2 : ShowWarningError(state, format("Coil:Cooling:Water:DetailedGeometry in Coil ={}", waterCoil.Name));
3095 4 : ShowContinueError(state, "Air Flow Rate Velocity has greatly exceeded upper design guidelines of ~2.5 m/s");
3096 2 : ShowContinueError(state, format("Air Mass Flow Rate[kg/s]={:.6T}", AirMassFlow));
3097 : // [m/s] = [kg/s] / ([m2] * [kg/m3])
3098 2 : AirVelocity = AirMassFlow / (waterCoil.MinAirFlowArea * AirDensity);
3099 2 : ShowContinueError(state, format("Air Face Velocity[m/s]={:.6T}", AirVelocity));
3100 2 : ShowContinueError(state, format("Approximate Mass Flow Rate limit for Face Area[kg/s]={:.6T}", 2.5 * waterCoil.MinAirFlowArea * AirDensity));
3101 4 : ShowContinueError(state, "Coil:Cooling:Water:DetailedGeometry could be resized/autosized to handle capacity");
3102 2 : state.dataWaterCoils->CoilWarningOnceFlag(CoilNum) = false;
3103 4921263 : } else if (AirMassFlow > (44.7 * waterCoil.MinAirFlowArea * AirDensity)) {
3104 0 : ShowSevereError(state, format("Coil:Cooling:Water:DetailedGeometry in Coil ={}", waterCoil.Name));
3105 0 : ShowContinueError(state, "Air Flow Rate Velocity is > 100MPH (44.7m/s) and simulation cannot continue");
3106 0 : ShowContinueError(state, format("Air Mass Flow Rate[kg/s]={:.6T}", AirMassFlow));
3107 0 : AirVelocity = AirMassFlow / (waterCoil.MinAirFlowArea * AirDensity);
3108 0 : ShowContinueError(state, format("Air Face Velocity[m/s]={:.6T}", AirVelocity));
3109 0 : ShowContinueError(state, format("Approximate Mass Flow Rate limit for Face Area[kg/s]={:.6T}", 44.7 * waterCoil.MinAirFlowArea * AirDensity));
3110 0 : ShowFatalError(state, "Coil:Cooling:Water:DetailedGeometry needs to be resized/autosized to handle capacity");
3111 : }
3112 :
3113 : // If Coil is Scheduled ON then do the simulation
3114 7630858 : if (((waterCoil.availSched->getCurrentVal() > 0.0) && (WaterMassFlowRate > 0.0) && (AirMassFlow >= WaterCoils::MinAirMassFlow)) ||
3115 2709593 : (CalcMode == state.dataWaterCoils->DesignCalc)) {
3116 : // transfer inputs to simulation variables and calculate
3117 : // known thermodynamic functions
3118 : // All coil calcs are done in KJoules. Convert to KJ here and then convert
3119 : // back to Joules at the end of the Subroutine.
3120 2212179 : DryAirSpecHeat = PsyCpAirFnW(zero) * ConvK;
3121 2212179 : MoistAirSpecificHeat = PsyCpAirFnW(InletAirHumRat) * ConvK;
3122 2212179 : InletAirEnthalpy = waterCoil.InletAirEnthalpy * ConvK;
3123 :
3124 2212179 : EnterAirDewPoint = PsyTdpFnWPb(state, InletAirHumRat, state.dataEnvrn->OutBaroPress, RoutineName);
3125 : // Ratio of secondary (fin) to total (secondary plus primary) surface areas
3126 2212179 : FinToTotSurfAreaRatio = waterCoil.FinSurfArea / waterCoil.TotCoilOutsideSurfArea;
3127 : // known water and air flow parameters:
3128 2212179 : rho = state.dataPlnt->PlantLoop(waterCoil.WaterPlantLoc.loopNum).glycol->getDensity(state, TempWaterIn, RoutineName);
3129 : // water flow velocity - assuming number of water circuits = NumOfTubesPerRow
3130 2212179 : TubeWaterVel =
3131 2212179 : WaterMassFlowRate * 4.0 / (waterCoil.NumOfTubesPerRow * rho * Constant::Pi * waterCoil.TubeInsideDiam * waterCoil.TubeInsideDiam);
3132 : // air mass flow rate per unit area
3133 2212179 : ScaledAirMassFlowRate = (1.0 + InletAirHumRat) * AirMassFlow / waterCoil.MinAirFlowArea;
3134 : // air flow Reynold's Number
3135 2212179 : AirReynoldsNo = waterCoil.CoilEffectiveInsideDiam * ScaledAirMassFlowRate / AirViscosity;
3136 : // heat transfer coefficients and resistance components:
3137 : // inside (water)
3138 2212179 : WaterToTubeThermResist = std::pow(waterCoil.TubeInsideDiam, 0.2) / (waterCoil.TotTubeInsideArea * 1.429 * std::pow(TubeWaterVel, 0.8));
3139 : // metal and fouling
3140 2212179 : TubeFoulThermResist =
3141 2212179 : (0.5 * (waterCoil.TubeOutsideDiam - waterCoil.TubeInsideDiam) / (ConvK * waterCoil.TubeThermConductivity) + TubeFoulFactor) /
3142 2212179 : waterCoil.TotTubeInsideArea;
3143 : // outside (wet and dry coil)
3144 2212179 : FilmCoefEqnFactor = waterCoil.GeometryCoef1 * std::pow(AirReynoldsNo, waterCoil.GeometryCoef2);
3145 : // (1.23 is 1/Prandt(air)**(2/3))
3146 2212179 : AirSideDrySurfFilmCoef = 1.23 * FilmCoefEqnFactor * MoistAirSpecificHeat * ScaledAirMassFlowRate;
3147 2212179 : FilmCoefReynldsCorrelatnFact = 1.425 + AirReynoldsNo * (-0.51e-3 + AirReynoldsNo * 0.263e-6);
3148 : // NOTE: the equation for FilmCoefReynldsCorrelatnFact generates valid results over
3149 : // a limited range of Air Reynolds Numbers as indicated by
3150 : // deleted code below. Reynolds Numbers outside this range
3151 : // may result in inaccurate results or failure of the coil
3152 : // simulation to obtain a solution
3153 : // Deleted code by J.C. Vanderzee
3154 :
3155 2212179 : AirSideWetSurfFilmCoef = FilmCoefReynldsCorrelatnFact * AirSideDrySurfFilmCoef;
3156 : //-- need wet fin efficiency for outside
3157 2212179 : RaisedInletWaterTemp = TempWaterIn + 0.5;
3158 :
3159 : // By this statement the Inlet Air enthalpy will never be equal to AirEnthAtRsdInletWaterTemp
3160 2212179 : if ((RaisedInletWaterTemp - TempAirIn) < 0.000001) {
3161 2212178 : RaisedInletWaterTemp = TempWaterIn + 0.3;
3162 : }
3163 2212179 : if (TempAirIn < RaisedInletWaterTemp) {
3164 1 : RaisedInletWaterTemp = TempAirIn - 0.3;
3165 : }
3166 :
3167 2212179 : RsdInletWaterTempSatAirHumRat = PsyWFnTdbRhPb(state, RaisedInletWaterTemp, unity, state.dataEnvrn->OutBaroPress, RoutineName);
3168 2212179 : AirEnthAtRsdInletWaterTemp = PsyHFnTdbW(RaisedInletWaterTemp, RsdInletWaterTempSatAirHumRat) * ConvK;
3169 :
3170 2212179 : SensToTotEnthDiffRatio = DryAirSpecHeat * (TempAirIn - RaisedInletWaterTemp) / (InletAirEnthalpy - AirEnthAtRsdInletWaterTemp);
3171 :
3172 2212179 : EnterAirHumRatDiff = InletAirHumRat - RsdInletWaterTempSatAirHumRat;
3173 2212179 : DryFinEfficncy = 0.5 * (waterCoil.EffectiveFinDiam - waterCoil.TubeOutsideDiam) *
3174 2212179 : std::sqrt(2.0 * AirSideWetSurfFilmCoef / (ConvK * waterCoil.FinThermConductivity * waterCoil.FinThickness));
3175 2212179 : if (EnterAirHumRatDiff < 0) {
3176 : // note that this condition indicates dry coil
3177 73375 : EnterAirHumRatDiff = -EnterAirHumRatDiff;
3178 73375 : SensToTotEnthDiffRatio = std::abs(SensToTotEnthDiffRatio);
3179 : }
3180 :
3181 2212179 : if (EnterAirHumRatDiff > 1.0) {
3182 0 : EnterAirHumRatDiff = 1.0;
3183 2212179 : } else if (EnterAirHumRatDiff < 0.00001) {
3184 57 : EnterAirHumRatDiff = 0.00001;
3185 : }
3186 :
3187 2212179 : if (DryFinEfficncy > 1.0) {
3188 0 : DryFinEfficncy = 1.0;
3189 2212179 : } else if (DryFinEfficncy < 0.00001) {
3190 0 : DryFinEfficncy = 0.00001;
3191 : }
3192 :
3193 2212179 : if (TempAirIn > 48.0 / 1.8) {
3194 274279 : WetFinEfficncy =
3195 274279 : exp_47 * std::pow(SensToTotEnthDiffRatio, 0.09471) * std::pow(EnterAirHumRatDiff, 0.0108) * std::pow(DryFinEfficncy, -0.50303);
3196 : } else {
3197 1937900 : WetFinEfficncy =
3198 1937900 : exp_35 * std::pow(SensToTotEnthDiffRatio, 0.16081) * std::pow(EnterAirHumRatDiff, 0.01995) * std::pow(DryFinEfficncy, -0.52951);
3199 : }
3200 :
3201 2212179 : if (WetFinEfficncy > 1.0) {
3202 2212059 : WetFinEfficncy = 0.99;
3203 : }
3204 2212179 : if (WetFinEfficncy < 0.0) {
3205 0 : WetFinEfficncy = 0.001;
3206 : }
3207 : // wet coil fin efficiency
3208 :
3209 2212179 : WetCoilFinEfficncy = 1.0 + FinToTotSurfAreaRatio * (WetFinEfficncy - 1.0);
3210 : // wet coil outside thermal resistance = [1/UA] (wet coil)
3211 2212179 : CoilToAirThermResistWetSurf = MoistAirSpecificHeat / (waterCoil.TotCoilOutsideSurfArea * AirSideWetSurfFilmCoef * WetCoilFinEfficncy);
3212 : //-- and dry fin efficiency
3213 2212179 : DryFinEfficncy = 0.5 * (waterCoil.EffectiveFinDiam - waterCoil.TubeOutsideDiam) *
3214 2212179 : std::sqrt(2.0 * AirSideDrySurfFilmCoef / (ConvK * waterCoil.FinThermConductivity * waterCoil.FinThickness));
3215 : // NOTE: The same caveats on the validity of the FilmCoefReynldsCorrelatnFact equation
3216 : // hold for the DryFinEfficncy equation. Values of DryFinEfficncy outside the
3217 : // specified range of validity are not guaranteed to
3218 : // produce results
3219 : // Deleted code by J.C. Vanderzee
3220 : // dry coil fin efficiency
3221 2212179 : DryCoilEfficiency = 0.0;
3222 : // Tuned Replaced by below to eliminate pow calls
3223 : // for ( CoefPointer = 1; CoefPointer <= 5; ++CoefPointer ) {
3224 : // DryCoilEfficiency += WaterCoil( CoilNum ).DryFinEfficncyCoef( CoefPointer ) * std::pow(
3225 : // DryFinEfficncy,
3226 : // CoefPointer
3227 : //-
3228 : // 1
3229 : //); } // CoefPointer
3230 2212179 : auto const &dry_fin_eff_coef = waterCoil.DryFinEfficncyCoef;
3231 2212179 : Real64 DryFinEfficncy_pow = 1.0;
3232 13273074 : for (int CoefPointer = 1; CoefPointer <= 5; ++CoefPointer) {
3233 11060895 : DryCoilEfficiency += dry_fin_eff_coef(CoefPointer) * DryFinEfficncy_pow;
3234 11060895 : DryFinEfficncy_pow *= DryFinEfficncy;
3235 : } // CoefPointer
3236 2212179 : DryCoilEfficiency = 1.0 + FinToTotSurfAreaRatio * (DryCoilEfficiency - 1.0);
3237 : // dry coil outside thermal resistance = [1/UA] (dry coil)
3238 2212179 : CoilToAirThermResistDrySurf = 1.0 / (waterCoil.TotCoilOutsideSurfArea * AirSideDrySurfFilmCoef * DryCoilEfficiency);
3239 : // definitions made to simplify some of the expressions used below
3240 2212179 : Cp = state.dataPlnt->PlantLoop(waterCoil.WaterPlantLoc.loopNum).glycol->getSpecificHeat(state, TempWaterIn, RoutineName);
3241 2212179 : ScaledWaterSpecHeat = WaterMassFlowRate * Cp * ConvK / AirMassFlow;
3242 2212179 : DryCoilCoeff1 = 1.0 / (AirMassFlow * MoistAirSpecificHeat) - 1.0 / (WaterMassFlowRate * Cp * ConvK);
3243 : // perform initialisations for all wet solution
3244 2212179 : WetSideEffctvWaterTemp = waterCoil.MeanWaterTempSaved + (TempWaterIn - waterCoil.InWaterTempSaved);
3245 2212179 : int WaterTempConvgLoop = 0;
3246 2212179 : bool WaterTempConvg = false;
3247 : // Loop to solve coil as if all wet, converges on MeanWaterTemp eq WetSideEffctvWaterTemp
3248 : // if conv=.TRUE. at any time program exits loop and proceeds
3249 : // to part wet / part dry solution
3250 5556579 : while (WaterTempConvgLoop < 8 && !WaterTempConvg) {
3251 3344400 : ++WaterTempConvgLoop;
3252 3344400 : ScaledWaterToTubeThermResist = WaterToTubeThermResist / (1.0 + 0.0146 * WetSideEffctvWaterTemp);
3253 3344400 : ScaledCoilAirThermResistWetSurf = CoilToAirThermResistWetSurf / waterCoil.SatEnthlCurveSlope;
3254 3344400 : UACoilAllWet =
3255 3344400 : 1.0 / (waterCoil.SatEnthlCurveSlope * (TubeFoulThermResist + ScaledWaterToTubeThermResist + ScaledCoilAirThermResistWetSurf));
3256 : // prevents floating point error when taking exponential
3257 : // of a very large number
3258 3344400 : expon = UACoilAllWet * (1.0 / AirMassFlow - waterCoil.SatEnthlCurveSlope / (WaterMassFlowRate * Cp * ConvK));
3259 3344400 : if (expon < 20.0) { // CR7189 changed from ABS(expon) < 20
3260 : // negative expon can happen, but lead to tiny WetCoilCoef that aren't a problem
3261 3344296 : WetCoilCoeff = std::exp(expon);
3262 : // following appears similar to eq. 320 in Eng Ref but neglects K1 term
3263 3344296 : TempWaterOut = ((1.0 - WetCoilCoeff) * (InletAirEnthalpy - waterCoil.SatEnthlCurveConstCoef) +
3264 3344296 : WetCoilCoeff * TempWaterIn * (waterCoil.SatEnthlCurveSlope - ScaledWaterSpecHeat)) /
3265 3344296 : (waterCoil.SatEnthlCurveSlope - WetCoilCoeff * ScaledWaterSpecHeat);
3266 : } else {
3267 : // following appears to be same as above with equation simplified to use only significant terms when WetCoilCoeff very large
3268 104 : TempWaterOut =
3269 104 : ((InletAirEnthalpy - waterCoil.SatEnthlCurveConstCoef) - TempWaterIn * (waterCoil.SatEnthlCurveSlope - ScaledWaterSpecHeat)) /
3270 : ScaledWaterSpecHeat;
3271 : }
3272 : // above is inverted form of WaterMassFlowRate*cpw*(TempWaterOut-TempWaterIn) = UA(LMHD)
3273 : // note simplification that hsat = WaterCoil(CoilNum)%SatEnthlCurveConstCoef + &
3274 : // WaterCoil(CoilNum)%SatEnthlCurveSlope*WetSideEffctvWaterTemp
3275 3344400 : MeanWaterTemp = 0.5 * (TempWaterIn + TempWaterOut);
3276 3344400 : OutletAirEnthalpy = InletAirEnthalpy - (TempWaterOut - TempWaterIn) * ScaledWaterSpecHeat;
3277 :
3278 3344400 : InsdToOutsdThermResistRatio = (TubeFoulThermResist + ScaledWaterToTubeThermResist) / ScaledCoilAirThermResistWetSurf;
3279 3344400 : InCoilSurfTemp =
3280 3344400 : UACoilAllWet * ScaledCoilAirThermResistWetSurf *
3281 3344400 : (waterCoil.SatEnthlCurveSlope * TempWaterIn + (OutletAirEnthalpy - waterCoil.SatEnthlCurveConstCoef) * InsdToOutsdThermResistRatio);
3282 3344400 : OutCoilSurfTemp =
3283 3344400 : UACoilAllWet * ScaledCoilAirThermResistWetSurf *
3284 3344400 : (waterCoil.SatEnthlCurveSlope * TempWaterOut + (InletAirEnthalpy - waterCoil.SatEnthlCurveConstCoef) * InsdToOutsdThermResistRatio);
3285 :
3286 3344400 : if (std::abs(MeanWaterTemp - WetSideEffctvWaterTemp) > 0.01) {
3287 1132221 : WetSideEffctvWaterTemp = MeanWaterTemp;
3288 1132221 : InSurfTempSatAirEnthl = PsyHFnTdbRhPb(state, InCoilSurfTemp, unity, state.dataEnvrn->OutBaroPress, RoutineName) * ConvK;
3289 1132221 : OutSurfTempSatAirEnthl = PsyHFnTdbRhPb(state, OutCoilSurfTemp, unity, state.dataEnvrn->OutBaroPress, RoutineName) * ConvK;
3290 :
3291 1132221 : waterCoil.SatEnthlCurveSlope = (OutSurfTempSatAirEnthl - InSurfTempSatAirEnthl) / (OutCoilSurfTemp - InCoilSurfTemp);
3292 1132221 : waterCoil.SatEnthlCurveConstCoef = InSurfTempSatAirEnthl - waterCoil.SatEnthlCurveSlope * InCoilSurfTemp;
3293 : } else {
3294 2212179 : WaterTempConvg = true;
3295 : }
3296 : } // End of iteration loop to get MeanWaterTemp=WetSideEffctvWaterTemp
3297 : // if 8 CoolCoilErrs are reached without convergence and the
3298 : // predicted coil surface temperature at the outlet is less than
3299 : // the dew point coil is apparently all wet but a solution
3300 : // cannot be obtained
3301 2212179 : if (!WaterTempConvg && !state.dataGlobal->WarmupFlag && (OutCoilSurfTemp < EnterAirDewPoint)) {
3302 0 : ShowRecurringWarningErrorAtEnd(state,
3303 0 : waterCoil.Name + " not converged (8 iterations) due to \"Wet Convergence\" conditions.",
3304 0 : state.dataWaterCoils->WaterTempCoolCoilErrs(CoilNum),
3305 0 : std::abs(MeanWaterTemp - WetSideEffctvWaterTemp),
3306 0 : std::abs(MeanWaterTemp - WetSideEffctvWaterTemp));
3307 : // CoolCoilErrs = CoolCoilErrs + 1
3308 : // IF (CoolCoilErrs .LE. MaxCoolCoilErrs) THEN
3309 : // CALL ShowWarningError(state, 'tp12c0: not converged in 8 CoolCoilErrs')
3310 : // END IF
3311 : }
3312 2212179 : waterCoil.MeanWaterTempSaved = MeanWaterTemp;
3313 : // now simulate wet dry coil - test outlet condition from all
3314 : // wet case to give an idea of the expected solution
3315 2212179 : int PartWetIterations = 0;
3316 2212179 : WetDryInterSurfTempError = 0.0;
3317 2212179 : bool CoilPartWetConvg = false;
3318 : // Surface temp at coil water outlet (air inlet) is less than
3319 : // the dew point - Coil must be completely wet so no need to
3320 : // simulate wet/dry case
3321 2212179 : if (OutCoilSurfTemp < EnterAirDewPoint) {
3322 642155 : CoilPartWetConvg = true;
3323 642155 : waterCoil.SurfAreaWetFraction = 1.0;
3324 642155 : TotWaterCoilLoad = AirMassFlow * (InletAirEnthalpy - OutletAirEnthalpy);
3325 642155 : AirWetDryInterfcTemp = TempAirIn;
3326 642155 : WetDryInterfcAirEnthl = InletAirEnthalpy;
3327 : // Surface temperature at coil water inlet is greater than the
3328 : // dewpoint - coil cannot be all wet but may be all dry -
3329 : // initialise with all dry solution
3330 1570024 : } else if (InCoilSurfTemp > EnterAirDewPoint) {
3331 277867 : SurfAreaWet = 0.0;
3332 277867 : waterCoil.SurfAreaWetFraction = 0.0;
3333 277867 : WetDryInterfcWaterTemp = TempWaterIn;
3334 277867 : TempWaterOut = waterCoil.OutWaterTempSaved + (TempWaterIn - waterCoil.InWaterTempSaved);
3335 277867 : WetAreaLast = 0.05 * waterCoil.TotCoilOutsideSurfArea;
3336 : // General case - must be part-wet/part-dry - initialise
3337 : // accordingly with some non-zero wet area
3338 : } else {
3339 1292157 : if (waterCoil.SurfAreaWetSaved != 0.0) {
3340 1291171 : SurfAreaWet = waterCoil.SurfAreaWetSaved;
3341 : } else {
3342 986 : SurfAreaWet = 0.8 * waterCoil.TotCoilOutsideSurfArea * (EnterAirDewPoint - InCoilSurfTemp) / (OutCoilSurfTemp - InCoilSurfTemp);
3343 : }
3344 1292157 : WetDryInterfcWaterTemp = TempWaterIn + EnterAirDewPoint - InCoilSurfTemp;
3345 1292157 : WetAreaLast = 0.0;
3346 : }
3347 : // Loop to solve partly wet coil, converges on wet area and
3348 : // boundary temperature at dew point
3349 : // Dry coil is special case with zero wet area, converges on
3350 : // mean water temperature
3351 13474777 : while (PartWetIterations < 40 && !CoilPartWetConvg) {
3352 11262598 : ++PartWetIterations;
3353 : // effective water temp on dry side of coil
3354 11262598 : DrySideEffectiveWaterTemp = 0.5 * (TempWaterOut + WetDryInterfcWaterTemp);
3355 : // tube inside thermal resistance
3356 11262598 : DryCoilInThermResist = WaterToTubeThermResist / (1.0 + 0.0146 * DrySideEffectiveWaterTemp);
3357 : // overall UA, from water to air, of dry portion of coil
3358 :
3359 11262598 : UADryCoil = (waterCoil.TotCoilOutsideSurfArea - SurfAreaWet) /
3360 11262598 : (waterCoil.TotCoilOutsideSurfArea * (TubeFoulThermResist + DryCoilInThermResist + CoilToAirThermResistDrySurf));
3361 :
3362 : // This is a numerical trap for a very small number in the EXP function that is approaching zero
3363 11262598 : if (UADryCoil * DryCoilCoeff1 < -60.0) {
3364 0 : DryCoilCoeff = 0.0;
3365 : } else {
3366 11262598 : DryCoilCoeff = std::exp(UADryCoil * DryCoilCoeff1);
3367 : }
3368 :
3369 11262598 : K1 = WaterMassFlowRate * Cp * ConvK * (DryCoilCoeff - 1.0) /
3370 11262598 : (WaterMassFlowRate * Cp * ConvK * DryCoilCoeff - AirMassFlow * MoistAirSpecificHeat);
3371 11262598 : if (SurfAreaWet != 0) {
3372 10695927 : waterCoil.SurfAreaWetFraction = SurfAreaWet / waterCoil.TotCoilOutsideSurfArea;
3373 : // effective water temp on wet side of coil
3374 10695927 : WetSideEffctvWaterTemp = 0.5 * (TempWaterIn + WetDryInterfcWaterTemp);
3375 : // tube inside thermal resistance
3376 10695927 : ScaledWaterToTubeThermResist = WaterToTubeThermResist / (1.0 + 0.0146 * WetSideEffctvWaterTemp);
3377 10695927 : ScaledCoilAirThermResistWetSurf = CoilToAirThermResistWetSurf / waterCoil.EnthVsTempCurveAppxSlope;
3378 : // overall UA, from water to air, of wet portion of coil
3379 10695927 : UACoilAllWet = 1.0 / (waterCoil.EnthVsTempCurveAppxSlope *
3380 10695927 : (TubeFoulThermResist + ScaledWaterToTubeThermResist + ScaledCoilAirThermResistWetSurf));
3381 10695927 : UACoilPartWet = waterCoil.SurfAreaWetFraction * UACoilAllWet;
3382 10695927 : expon = UACoilPartWet * (1.0 / AirMassFlow - waterCoil.EnthVsTempCurveAppxSlope / (WaterMassFlowRate * Cp * ConvK));
3383 : // prevents floating point error when taking exponential
3384 : // of a very large number
3385 10695927 : if (expon < 20.0) {
3386 10695927 : WetCoilCoeff = std::exp(expon);
3387 : // write(outputfiledebug,*) ' wcc=',wetcoilcoeff
3388 10695927 : denom =
3389 10695927 : (waterCoil.EnthVsTempCurveAppxSlope - WetCoilCoeff * ScaledWaterSpecHeat - (1.0 - WetCoilCoeff) * K1 * MoistAirSpecificHeat);
3390 : // write(outputfiledebug,*) ' denom=',denom
3391 : // WetDryInterfcWaterTemp = ((1.0 - WetCoilCoeff) * (InletAirEnthalpy - WaterCoil(CoilNum)%EnthVsTempCurveConst -
3392 : // K1
3393 : // * &
3394 : // MoistAirSpecificHeat * TempAirIn) + WetCoilCoeff * &
3395 : // TempWaterIn * (WaterCoil(CoilNum)%EnthVsTempCurveAppxSlope - &
3396 : // ScaledWaterSpecHeat)) / (WaterCoil(CoilNum)%EnthVsTempCurveAppxSlope - &
3397 : // WetCoilCoeff * ScaledWaterSpecHeat - (1.0 - WetCoilCoeff) * K1 * &
3398 : // MoistAirSpecificHeat)
3399 10695927 : WetDryInterfcWaterTemp =
3400 10695927 : ((1.0 - WetCoilCoeff) * (InletAirEnthalpy - waterCoil.EnthVsTempCurveConst - K1 * MoistAirSpecificHeat * TempAirIn) +
3401 10695927 : WetCoilCoeff * TempWaterIn * (waterCoil.EnthVsTempCurveAppxSlope - ScaledWaterSpecHeat)) /
3402 : denom;
3403 : } else {
3404 : // approximation to equation for WetDryInterfcWaterTemp when WetCoilCoeff-->inf.
3405 0 : WetDryInterfcWaterTemp = (TempWaterIn * (waterCoil.EnthVsTempCurveAppxSlope - ScaledWaterSpecHeat) -
3406 0 : (InletAirEnthalpy - waterCoil.EnthVsTempCurveConst - K1 * MoistAirSpecificHeat * TempAirIn)) /
3407 0 : (K1 * MoistAirSpecificHeat - ScaledWaterSpecHeat);
3408 : }
3409 : }
3410 : // air temperature at wet-dry interface
3411 11262598 : AirWetDryInterfcTemp = TempAirIn - (TempAirIn - WetDryInterfcWaterTemp) * K1;
3412 : // coil surface temperature at wet-dry interface
3413 11262598 : WetDryInterfcSurfTemp = WetDryInterfcWaterTemp + (AirWetDryInterfcTemp - WetDryInterfcWaterTemp) *
3414 11262598 : (TubeFoulThermResist + DryCoilInThermResist) /
3415 11262598 : (TubeFoulThermResist + DryCoilInThermResist + CoilToAirThermResistDrySurf);
3416 11262598 : if (SurfAreaWet != 0) {
3417 10695927 : WetDryInterfcAirEnthl = InletAirEnthalpy - MoistAirSpecificHeat * (TempAirIn - AirWetDryInterfcTemp);
3418 : // conservation of energy - wet portion of coil
3419 10695927 : OutletAirEnthalpy = WetDryInterfcAirEnthl - WaterMassFlowRate * Cp * ConvK * (WetDryInterfcWaterTemp - TempWaterIn) / AirMassFlow;
3420 : // ratio of inside to outside thermal resistance
3421 10695927 : InsdToOutsdThermResistRatio = (TubeFoulThermResist + ScaledWaterToTubeThermResist) / ScaledCoilAirThermResistWetSurf;
3422 : // coil surface temperature at water inlet (air outlet)
3423 10695927 : InCoilSurfTemp = UACoilAllWet * ScaledCoilAirThermResistWetSurf *
3424 10695927 : (waterCoil.EnthVsTempCurveAppxSlope * TempWaterIn +
3425 10695927 : (OutletAirEnthalpy - waterCoil.EnthVsTempCurveConst) * InsdToOutsdThermResistRatio);
3426 10695927 : WetDryInterSurfTempErrorLast = WetDryInterSurfTempError;
3427 : // in part-wet/part-dry solution EnterAirDewPoint=WetDryInterfcSurfTemp drives WetDryInterSurfTempError->0
3428 10695927 : WetDryInterSurfTempError = EnterAirDewPoint - WetDryInterfcSurfTemp;
3429 : } else {
3430 : // dry coil solution
3431 566671 : WetDryInterfcAirEnthl = 0.0;
3432 566671 : OutletAirEnthalpy = InletAirEnthalpy - MoistAirSpecificHeat * (TempAirIn - AirWetDryInterfcTemp);
3433 : }
3434 : // total cooling = change in air enthalpy across coil
3435 11262598 : TotWaterCoilLoad = AirMassFlow * (InletAirEnthalpy - OutletAirEnthalpy);
3436 : // conservation of energy on water stream gives water outlet
3437 : // temperature
3438 11262598 : TempWaterOut = WaterMassFlowRate * Cp * ConvK; // Temp for next calc
3439 11262598 : TempWaterOut = min(TempWaterIn + TotWaterCoilLoad / TempWaterOut, TempAirIn);
3440 : // update estimate of coil wet area
3441 :
3442 11262598 : if (SurfAreaWet == 0) {
3443 566671 : MeanWaterTemp = 0.5 * (TempWaterOut + WetDryInterfcWaterTemp);
3444 566671 : if (EnterAirDewPoint > WetDryInterfcSurfTemp) {
3445 142667 : SurfAreaWet = 0.5 * WetAreaLast;
3446 424004 : } else if (std::abs(MeanWaterTemp - DrySideEffectiveWaterTemp) <= 0.00002) {
3447 141724 : CoilPartWetConvg = true;
3448 : }
3449 12207331 : } else if (std::abs(WetDryInterSurfTempError) > 0.00002 ||
3450 1511404 : std::abs(SurfAreaWet - WetAreaLast) / waterCoil.TotCoilOutsideSurfArea > 0.00001) {
3451 9299148 : if (WetAreaLast == 0) {
3452 1292157 : WetAreaLast = SurfAreaWet;
3453 1292157 : SurfAreaWet += 0.4 * waterCoil.TotCoilOutsideSurfArea * WetDryInterSurfTempError / (OutCoilSurfTemp - InCoilSurfTemp);
3454 8006991 : } else if (WetDryInterSurfTempError != WetDryInterSurfTempErrorLast) {
3455 8006991 : WetAreaChange = SurfAreaWet - WetAreaLast;
3456 8006991 : WetAreaLast = SurfAreaWet;
3457 8006991 : SurfAreaWet -= 0.8 * WetDryInterSurfTempError * WetAreaChange / (WetDryInterSurfTempError - WetDryInterSurfTempErrorLast);
3458 : }
3459 9299148 : if (SurfAreaWet >= waterCoil.TotCoilOutsideSurfArea) {
3460 155960 : SurfAreaWet = waterCoil.TotCoilOutsideSurfArea;
3461 155960 : MeanWaterTemp = 0.5 * (TempWaterIn + WetDryInterfcWaterTemp);
3462 155960 : if (WetAreaLast == waterCoil.TotCoilOutsideSurfArea && std::abs(MeanWaterTemp - WetSideEffctvWaterTemp) <= 0.00002) {
3463 31521 : CoilPartWetConvg = true;
3464 : }
3465 : }
3466 9299148 : if (SurfAreaWet <= 0) {
3467 6524 : SurfAreaWet = 0.0;
3468 6524 : waterCoil.SurfAreaWetFraction = 0.0;
3469 6524 : WetDryInterfcWaterTemp = TempWaterIn;
3470 : }
3471 9299148 : InSurfTempSatAirEnthl = PsyHFnTdbRhPb(state, InCoilSurfTemp, unity, state.dataEnvrn->OutBaroPress, RoutineName) * ConvK;
3472 9299148 : if ((EnterAirDewPoint - InCoilSurfTemp) >= 0.0001) {
3473 9195901 : AirEnthAtWetDryIntrfcSurfTemp = PsyHFnTdbRhPb(state, EnterAirDewPoint, unity, state.dataEnvrn->OutBaroPress, RoutineName) * ConvK;
3474 9195901 : waterCoil.EnthVsTempCurveAppxSlope =
3475 9195901 : (AirEnthAtWetDryIntrfcSurfTemp - InSurfTempSatAirEnthl) / (EnterAirDewPoint - InCoilSurfTemp);
3476 : } else {
3477 103247 : AirEnthAtWetDryIntrfcSurfTemp =
3478 103247 : PsyHFnTdbRhPb(state, InCoilSurfTemp + 0.0001, unity, state.dataEnvrn->OutBaroPress, RoutineName) * ConvK;
3479 103247 : waterCoil.EnthVsTempCurveAppxSlope = (AirEnthAtWetDryIntrfcSurfTemp - InSurfTempSatAirEnthl) / 0.0001;
3480 : }
3481 9299148 : waterCoil.EnthVsTempCurveConst = InSurfTempSatAirEnthl - waterCoil.EnthVsTempCurveAppxSlope * InCoilSurfTemp;
3482 : } else {
3483 1396779 : CoilPartWetConvg = true;
3484 : }
3485 : }
3486 : // error checking to see if convergence has been achieved
3487 2212179 : if (!CoilPartWetConvg && !state.dataGlobal->WarmupFlag) {
3488 0 : ShowRecurringWarningErrorAtEnd(state,
3489 0 : waterCoil.Name + " not converged (40 iterations) due to \"Partial Wet Convergence\" conditions.",
3490 0 : state.dataWaterCoils->PartWetCoolCoilErrs(CoilNum));
3491 : // CoolCoilErrs = CoolCoilErrs + 1
3492 : // IF (CoolCoilErrs .LE. MaxCoolCoilErrs) THEN
3493 : // CALL ShowWarningError(state, 'tp12c0: not converged in 20 CoolCoilErrs')
3494 : // END IF
3495 : }
3496 2212179 : if (waterCoil.SurfAreaWetFraction > 0 && waterCoil.SurfAreaWetFraction < 1) {
3497 1396764 : waterCoil.SurfAreaWetSaved = SurfAreaWet;
3498 : }
3499 : // calculate TempAirOut, OutletAirHumRat, and SensCoolRate based on equations from
3500 : // TYPE12 and the ASHRAE toolkit
3501 2212179 : if (waterCoil.SurfAreaWetFraction == 0) {
3502 : // dry coil
3503 141724 : TempAirOut = TempAirIn - TotWaterCoilLoad / (AirMassFlow * MoistAirSpecificHeat);
3504 141724 : OutletAirHumRat = InletAirHumRat;
3505 141724 : SenWaterCoilLoad = TotWaterCoilLoad;
3506 : } else {
3507 : // coil effectiveness
3508 2070455 : expon = waterCoil.SurfAreaWetFraction / (CoilToAirThermResistWetSurf * AirMassFlow);
3509 2070455 : y = 0.0;
3510 2070455 : if (expon < 20.0) {
3511 2070291 : y = std::exp(-expon);
3512 : }
3513 2070455 : AirExitEnthlAtCoilSurfTemp = WetDryInterfcAirEnthl - (WetDryInterfcAirEnthl - OutletAirEnthalpy) / (1.0 - y);
3514 2070455 : AirExitCoilSurfTemp = AirExitEnthlAtCoilSurfTemp / ConvK; // TEmporary calc
3515 2070455 : AirExitCoilSurfTemp = PsyTsatFnHPb(state, AirExitCoilSurfTemp, state.dataEnvrn->OutBaroPress);
3516 : // Implementation of epsilon*NTU method
3517 2070455 : TempAirOut = AirExitCoilSurfTemp + (AirWetDryInterfcTemp - AirExitCoilSurfTemp) * y;
3518 2070455 : OutletAirHumRat = PsyWFnTdbH(state, TempAirOut, 1000.0 * OutletAirEnthalpy, RoutineName);
3519 2070455 : SenWaterCoilLoad = AirMassFlow * (PsyCpAirFnW(InletAirHumRat) * TempAirIn - PsyCpAirFnW(OutletAirHumRat) * TempAirOut) * ConvK;
3520 : }
3521 :
3522 2212179 : if (fanOp == HVAC::FanOp::Cycling) {
3523 0 : TotWaterCoilLoad *= PartLoadRatio;
3524 0 : SenWaterCoilLoad *= PartLoadRatio;
3525 : }
3526 :
3527 : // Set the outlet conditions
3528 2212179 : waterCoil.TotWaterCoolingCoilRate = TotWaterCoilLoad * 1000.0;
3529 2212179 : waterCoil.SenWaterCoolingCoilRate = SenWaterCoilLoad * 1000.0;
3530 2212179 : waterCoil.OutletAirTemp = TempAirOut;
3531 2212179 : waterCoil.OutletWaterTemp = TempWaterOut;
3532 2212179 : waterCoil.OutletAirEnthalpy = OutletAirEnthalpy * 1000.0;
3533 2212179 : waterCoil.OutletAirHumRat = OutletAirHumRat;
3534 : // The CoolingCoilLoad is the change in the enthalpy of the water
3535 2212179 : waterCoil.OutletWaterEnthalpy = waterCoil.InletWaterEnthalpy + waterCoil.TotWaterCoolingCoilRate / waterCoil.InletWaterMassFlowRate;
3536 :
3537 : // This WaterCoil does not change the Mass Flow across the component
3538 2212179 : waterCoil.OutletAirMassFlowRate = waterCoil.InletAirMassFlowRate;
3539 2212179 : waterCoil.OutletWaterMassFlowRate = waterCoil.InletWaterMassFlowRate;
3540 : } else {
3541 : // If Coil is scheduled OFF then Outlet conditions are set to Inlet Conditions
3542 2709086 : waterCoil.TotWaterCoolingCoilRate = 0.0;
3543 2709086 : waterCoil.SenWaterCoolingCoilRate = 0.0;
3544 2709086 : TempAirOut = TempAirIn;
3545 2709086 : TempWaterOut = TempWaterIn;
3546 : // set the outlet conditions to the coil derived type
3547 2709086 : waterCoil.OutletAirTemp = TempAirOut;
3548 2709086 : waterCoil.OutletWaterTemp = TempWaterOut;
3549 2709086 : waterCoil.OutletAirEnthalpy = waterCoil.InletAirEnthalpy;
3550 2709086 : waterCoil.OutletAirHumRat = waterCoil.InletAirHumRat;
3551 : // The CoolingCoilLoad is the change in the enthalpy of the water
3552 2709086 : waterCoil.OutletWaterEnthalpy = waterCoil.InletWaterEnthalpy;
3553 :
3554 : // This WaterCoil does not change the Mass Flow across the component
3555 2709086 : waterCoil.OutletAirMassFlowRate = waterCoil.InletAirMassFlowRate;
3556 2709086 : waterCoil.OutletWaterMassFlowRate = 0.0;
3557 : }
3558 :
3559 : // Save some of the Values for next Time step
3560 4921265 : waterCoil.InWaterTempSaved = TempWaterIn;
3561 4921265 : waterCoil.OutWaterTempSaved = TempWaterOut;
3562 4921265 : }
3563 :
3564 23088334 : void CoolingCoil(EnergyPlusData &state,
3565 : int const CoilNum,
3566 : bool const FirstHVACIteration,
3567 : int const CalcMode,
3568 : HVAC::FanOp const fanOp, // fan operating mode
3569 : Real64 const PartLoadRatio // part-load ratio of heating coil
3570 : )
3571 : {
3572 :
3573 : // FUNCTION INFORMATION:
3574 : // AUTHOR Rahul Chillar
3575 : // DATE WRITTEN Mar 2004
3576 :
3577 : // PURPOSE OF THIS FUNCTION:
3578 : // The subroutine has the coil logic. Three types of Cooling Coils exist:
3579 : // They are 1.CoilDry , 2.CoilWet, 3. CoilPartDryPartWet. The logic for
3580 : // the three individual cases is in this subroutine.
3581 :
3582 : // METHODOLOGY EMPLOYED:
3583 : // Simulates a Coil Model from Design conditions and subsequently uses
3584 : // configuration values (example: UA)calculated from those design conditions
3585 : // to calculate new performance of coil from operating inputs.The values are
3586 : // calculated in the Subroutine InitWaterCoil
3587 :
3588 : // REFERENCES:
3589 : // ASHRAE Secondary HVAC Toolkit TRNSYS. 1990. A Transient System
3590 : // Simulation Program: Reference Manual. Solar Energy Laboratory, Univ. Wisconsin-
3591 : // Madison, pp. 4.6.8-1 - 4.6.8-12.
3592 : // Threlkeld, J.L. 1970. Thermal Environmental Engineering, 2nd Edition,
3593 : // Englewood Cliffs: Prentice-Hall,Inc. pp. 254-270.
3594 :
3595 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
3596 : Real64 AirInletCoilSurfTemp; // Coil surface temperature at air entrance(C)
3597 : Real64 AirDewPointTemp; // Temperature dew point at operating condition
3598 : Real64 OutletAirTemp; // Outlet air temperature at operating condition
3599 : Real64 OutletAirHumRat; // Outlet air humidity ratio at operating condition
3600 : Real64 OutletWaterTemp; // Outlet water temperature at operating condtitons
3601 : Real64 TotWaterCoilLoad; // Total heat transfer rate(W)
3602 : Real64 SenWaterCoilLoad; // Sensible heat transfer rate
3603 : Real64 SurfAreaWetFraction; // Fraction of surface area wet
3604 : Real64 AirMassFlowRate; // Air mass flow rate for the calculation
3605 :
3606 23088334 : AirInletCoilSurfTemp = 0.0; // Coil surface temperature at air entrance(C)
3607 23088334 : AirDewPointTemp = 0.0; // Temperature dew point at operating condition
3608 23088334 : OutletAirTemp = 0.0; // Outlet air temperature at operating condition
3609 23088334 : OutletAirHumRat = 0.0; // Outlet air humidity ratio at operating condition
3610 23088334 : OutletWaterTemp = 0.0; // Outlet water temperature at operating condtitons
3611 23088334 : TotWaterCoilLoad = 0.0; // Total heat transfer rate(W)
3612 23088334 : SenWaterCoilLoad = 0.0; // Sensible heat transfer rate
3613 23088334 : SurfAreaWetFraction = 0.0; // Fraction of surface area wet
3614 :
3615 23088334 : auto &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
3616 23088334 : if (fanOp == HVAC::FanOp::Cycling && PartLoadRatio > 0.0) { // FB Start
3617 1346418 : AirMassFlowRate = waterCoil.InletAirMassFlowRate / PartLoadRatio;
3618 : } else {
3619 21741916 : AirMassFlowRate = waterCoil.InletAirMassFlowRate;
3620 : }
3621 :
3622 : // If Coil is Scheduled ON then do the simulation
3623 45091781 : if (((waterCoil.availSched->getCurrentVal() > 0.0) && (waterCoil.InletWaterMassFlowRate > 0.0) &&
3624 46176668 : (AirMassFlowRate >= WaterCoils::MinAirMassFlow) && (waterCoil.DesAirVolFlowRate > 0.0) && (waterCoil.MaxWaterMassFlowRate > 0.0)) ||
3625 10546178 : (CalcMode == state.dataWaterCoils->DesignCalc)) {
3626 :
3627 : // Calculate Temperature Dew Point at operating conditions.
3628 12543576 : AirDewPointTemp = PsyTdpFnWPb(state, waterCoil.InletAirHumRat, state.dataEnvrn->OutBaroPress);
3629 :
3630 12543576 : if (waterCoil.CoolingCoilAnalysisMode == state.dataWaterCoils->DetailedAnalysis) {
3631 : // Coil is completely dry if AirDewPointTemp is less than InletWaterTemp,hence Call CoilCompletelyDry
3632 890832 : if (AirDewPointTemp <= waterCoil.InletWaterTemp) {
3633 :
3634 : // Calculate the leaving conditions and performance of dry coil
3635 1483 : CoilCompletelyDry(state,
3636 : CoilNum,
3637 : waterCoil.InletWaterTemp,
3638 : waterCoil.InletAirTemp,
3639 : waterCoil.UACoilTotal,
3640 : OutletWaterTemp,
3641 : OutletAirTemp,
3642 : OutletAirHumRat,
3643 : TotWaterCoilLoad,
3644 : fanOp,
3645 : PartLoadRatio);
3646 :
3647 1483 : SenWaterCoilLoad = TotWaterCoilLoad;
3648 1483 : SurfAreaWetFraction = 0.0;
3649 :
3650 : } else {
3651 : // Else If AirDewPointTemp is greater than InletWaterTemp then assume the
3652 : // external surface of coil is completely wet,hence Call CoilCompletelyWet
3653 : // Calculate the leaving conditions and performance of wet coil
3654 889349 : CoilCompletelyWet(state,
3655 : CoilNum,
3656 : waterCoil.InletWaterTemp,
3657 : waterCoil.InletAirTemp,
3658 : waterCoil.InletAirHumRat,
3659 : waterCoil.UACoilInternal,
3660 : waterCoil.UACoilExternal,
3661 : OutletWaterTemp,
3662 : OutletAirTemp,
3663 : OutletAirHumRat,
3664 : TotWaterCoilLoad,
3665 : SenWaterCoilLoad,
3666 : SurfAreaWetFraction,
3667 : AirInletCoilSurfTemp,
3668 : fanOp,
3669 : PartLoadRatio);
3670 :
3671 : // If AirDewPointTemp is less than temp of coil surface at entry of air
3672 889349 : if (AirDewPointTemp < AirInletCoilSurfTemp) {
3673 :
3674 : // Then coil is partially wet and dry hence call CoilPartWetPartDry
3675 : // Calculate the leaving conditions and performance of dry coil
3676 709695 : CoilPartWetPartDry(state,
3677 : CoilNum,
3678 : FirstHVACIteration,
3679 : waterCoil.InletWaterTemp,
3680 : waterCoil.InletAirTemp,
3681 : AirDewPointTemp,
3682 : OutletWaterTemp,
3683 : OutletAirTemp,
3684 : OutletAirHumRat,
3685 : TotWaterCoilLoad,
3686 : SenWaterCoilLoad,
3687 : SurfAreaWetFraction,
3688 : fanOp,
3689 : PartLoadRatio);
3690 :
3691 : } // End if for part wet part dry coil
3692 : } // End if for dry coil
3693 :
3694 11652744 : } else if (waterCoil.CoolingCoilAnalysisMode == state.dataWaterCoils->SimpleAnalysis) {
3695 : // Coil is completely dry if AirDewPointTemp is less than InletWaterTemp,hence Call CoilCompletelyDry
3696 11652744 : if (AirDewPointTemp <= waterCoil.InletWaterTemp) {
3697 :
3698 : // Calculate the leaving conditions and performance of dry coil
3699 1868939 : CoilCompletelyDry(state,
3700 : CoilNum,
3701 : waterCoil.InletWaterTemp,
3702 : waterCoil.InletAirTemp,
3703 : waterCoil.UACoilTotal,
3704 : OutletWaterTemp,
3705 : OutletAirTemp,
3706 : OutletAirHumRat,
3707 : TotWaterCoilLoad,
3708 : fanOp,
3709 : PartLoadRatio);
3710 :
3711 1868939 : SenWaterCoilLoad = TotWaterCoilLoad;
3712 1868939 : SurfAreaWetFraction = 0.0;
3713 :
3714 : } else {
3715 : // Else If AirDewPointTemp is greater than InletWaterTemp then assume the
3716 : // external surface of coil is completely wet,hence Call CoilCompletelyWet
3717 : // Calculate the leaving conditions and performance of wet coil
3718 9783805 : CoilCompletelyWet(state,
3719 : CoilNum,
3720 : waterCoil.InletWaterTemp,
3721 : waterCoil.InletAirTemp,
3722 : waterCoil.InletAirHumRat,
3723 : waterCoil.UACoilInternal,
3724 : waterCoil.UACoilExternal,
3725 : OutletWaterTemp,
3726 : OutletAirTemp,
3727 : OutletAirHumRat,
3728 : TotWaterCoilLoad,
3729 : SenWaterCoilLoad,
3730 : SurfAreaWetFraction,
3731 : AirInletCoilSurfTemp,
3732 : fanOp,
3733 : PartLoadRatio);
3734 :
3735 : } // End if for dry coil
3736 : }
3737 :
3738 : // Report outlet variables at nodes
3739 12543576 : waterCoil.OutletAirTemp = OutletAirTemp;
3740 12543576 : waterCoil.OutletAirHumRat = OutletAirHumRat;
3741 12543576 : waterCoil.OutletWaterTemp = OutletWaterTemp;
3742 : // Report output results if the coil was operating
3743 :
3744 12543576 : if (fanOp == HVAC::FanOp::Cycling) {
3745 711300 : TotWaterCoilLoad *= PartLoadRatio;
3746 711300 : SenWaterCoilLoad *= PartLoadRatio;
3747 : }
3748 :
3749 12543576 : waterCoil.TotWaterCoolingCoilRate = TotWaterCoilLoad;
3750 12543576 : waterCoil.SenWaterCoolingCoilRate = SenWaterCoilLoad;
3751 12543576 : waterCoil.SurfAreaWetFraction = SurfAreaWetFraction;
3752 : // WaterCoil(CoilNum)%OutletWaterEnthalpy = WaterCoil(CoilNum)%InletWaterEnthalpy+ &
3753 : // WaterCoil(CoilNum)%TotWaterCoolingCoilRate/WaterCoil(CoilNum)%InletWaterMassFlowRate
3754 12543576 : waterCoil.OutletWaterEnthalpy =
3755 12543576 : waterCoil.InletWaterEnthalpy + General::SafeDivide(waterCoil.TotWaterCoolingCoilRate, waterCoil.InletWaterMassFlowRate);
3756 :
3757 : } else {
3758 : // If both mass flow rates are zero, set outputs to inputs and return
3759 10544758 : waterCoil.OutletWaterTemp = waterCoil.InletWaterTemp;
3760 10544758 : waterCoil.OutletAirTemp = waterCoil.InletAirTemp;
3761 10544758 : waterCoil.OutletAirHumRat = waterCoil.InletAirHumRat;
3762 10544758 : waterCoil.OutletWaterEnthalpy = waterCoil.InletWaterEnthalpy;
3763 10544758 : waterCoil.TotWaterCoolingCoilEnergy = 0.0;
3764 10544758 : waterCoil.SenWaterCoolingCoilEnergy = 0.0;
3765 10544758 : waterCoil.SurfAreaWetFraction = 0.0;
3766 :
3767 : } // End of the Flow or No flow If block
3768 23088334 : waterCoil.OutletWaterMassFlowRate = waterCoil.InletWaterMassFlowRate;
3769 23088334 : waterCoil.OutletAirMassFlowRate = waterCoil.InletAirMassFlowRate;
3770 23088334 : waterCoil.OutletAirEnthalpy = PsyHFnTdbW(waterCoil.OutletAirTemp, waterCoil.OutletAirHumRat);
3771 23088334 : }
3772 :
3773 : // End Algorithm Section of the Module
3774 :
3775 : // Coil Completely Dry Subroutine for Cooling Coil
3776 :
3777 18042056 : void CoilCompletelyDry(EnergyPlusData &state,
3778 : int const CoilNum,
3779 : Real64 const WaterTempIn, // Entering water temperature
3780 : Real64 const AirTempIn, // Entering air dry bulb temperature
3781 : Real64 const CoilUA, // Overall heat transfer coefficient
3782 : Real64 &OutletWaterTemp, // Leaving water temperature
3783 : Real64 &OutletAirTemp, // Leaving air dry bulb temperature
3784 : Real64 &OutletAirHumRat, // Leaving air humidity ratio
3785 : Real64 &Q, // Heat transfer rate
3786 : HVAC::FanOp const fanOp, // fan operating mode
3787 : Real64 const PartLoadRatio // part-load ratio of heating coil
3788 : )
3789 : {
3790 :
3791 : // FUNCTION INFORMATION:
3792 : // AUTHOR Rahul Chillar
3793 : // DATE WRITTEN March 2004
3794 :
3795 : // PURPOSE OF THIS FUNCTION:
3796 : // Calculate the performance of a sensible air-liquid heat exchanger. Calculated
3797 : // results include outlet air temperature and humidity, outlet water temperature,
3798 : // and heat transfer rate.
3799 :
3800 : // METHODOLOGY EMPLOYED:
3801 : // Models coil using effectiveness-NTU model.
3802 :
3803 : // REFERENCES:
3804 : // Kays, W.M. and A.L. London. 1964,Compact Heat Exchangers, 2nd Edition,
3805 : // New York: McGraw-Hill.
3806 :
3807 : // FUNCTION PARAMETER DEFINITIONS:
3808 : static constexpr std::string_view RoutineName("CoilCompletelyDry");
3809 :
3810 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
3811 : Real64 CapacitanceAir; // Air-side capacity rate(W/C)
3812 : Real64 CapacitanceWater; // Water-side capacity rate(W/C)
3813 : Real64 AirMassFlow;
3814 : Real64 WaterMassFlowRate;
3815 : Real64 Cp;
3816 :
3817 18042056 : auto const &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
3818 : // adjust mass flow rates for cycling fan cycling coil operation
3819 18042056 : if (fanOp == HVAC::FanOp::Cycling) {
3820 2125206 : if (PartLoadRatio > 0.0) {
3821 2125206 : AirMassFlow = waterCoil.InletAirMassFlowRate / PartLoadRatio;
3822 2125206 : WaterMassFlowRate = min(waterCoil.InletWaterMassFlowRate / PartLoadRatio, waterCoil.MaxWaterMassFlowRate);
3823 : } else {
3824 0 : AirMassFlow = 0.0;
3825 0 : WaterMassFlowRate = 0.0;
3826 : }
3827 : } else {
3828 15916850 : AirMassFlow = waterCoil.InletAirMassFlowRate;
3829 15916850 : WaterMassFlowRate = waterCoil.InletWaterMassFlowRate;
3830 : }
3831 :
3832 : // Calculate air and water capacity rates
3833 18042056 : CapacitanceAir = AirMassFlow * PsyCpAirFnW(waterCoil.InletAirHumRat);
3834 : // Water Capacity Rate
3835 18042056 : Cp = state.dataPlnt->PlantLoop(waterCoil.WaterPlantLoc.loopNum).glycol->getSpecificHeat(state, WaterTempIn, RoutineName);
3836 :
3837 18042056 : CapacitanceWater = WaterMassFlowRate * Cp;
3838 :
3839 : // Determine the air and water outlet conditions
3840 18042056 : CoilOutletStreamCondition(state, CoilNum, CapacitanceWater, WaterTempIn, CapacitanceAir, AirTempIn, CoilUA, OutletWaterTemp, OutletAirTemp);
3841 :
3842 : // Calculate the total and sensible heat transfer rate both are equal in case of Dry Coil
3843 18042056 : Q = CapacitanceAir * (AirTempIn - OutletAirTemp);
3844 :
3845 : // Outlet humidity is equal to Inlet Humidity because its a dry coil
3846 18042056 : OutletAirHumRat = waterCoil.InletAirHumRat;
3847 18042056 : }
3848 :
3849 : // Coil Completely Wet Subroutine for Cooling Coil
3850 :
3851 26844788 : void CoilCompletelyWet(EnergyPlusData &state,
3852 : int const CoilNum, // Number of Coil
3853 : Real64 const WaterTempIn, // Water temperature IN to this function (C)
3854 : Real64 const AirTempIn, // Air dry bulb temperature IN to this function(C)
3855 : Real64 const AirHumRat, // Air Humidity Ratio IN to this funcation (C)
3856 : Real64 const UAInternalTotal, // Internal overall heat transfer coefficient(W/m2 C)
3857 : Real64 const UAExternalTotal, // External overall heat transfer coefficient(W/m2 C)
3858 : Real64 &OutletWaterTemp, // Leaving water temperature (C)
3859 : Real64 &OutletAirTemp, // Leaving air dry bulb temperature(C)
3860 : Real64 &OutletAirHumRat, // Leaving air humidity ratio
3861 : Real64 &TotWaterCoilLoad, // Total heat transfer rate(W)
3862 : Real64 &SenWaterCoilLoad, // Sensible heat transfer rate(W)
3863 : Real64 &SurfAreaWetFraction, // Fraction of surface area wet
3864 : Real64 &AirInletCoilSurfTemp, // Surface temperature at air entrance(C)
3865 : HVAC::FanOp const fanOp, // fan operating mode
3866 : Real64 const PartLoadRatio // part-load ratio of heating coil
3867 : )
3868 : {
3869 :
3870 : // FUNCTION INFORMATION:
3871 : // AUTHOR Rahul Chillar
3872 : // DATE WRITTEN Mar 2004
3873 :
3874 : // PURPOSE OF THIS FUNCTION:
3875 : // Calculate the performance of a cooling coil when the external fin surface is
3876 : // complete wet. Results include outlet air temperature and humidity,
3877 : // outlet water temperature, sensible and total cooling capacities, and the wet
3878 : // fraction of the air-side surface area.
3879 :
3880 : // METHODOLOGY EMPLOYED:
3881 : // Models coil as counterflow heat exchanger. Approximates saturated air enthalpy as
3882 : // a linear function of temperature
3883 : // TRNSYS. 1990. A Transient System Simulation Program: Reference Manual.
3884 : // Solar Energy Laboratory, Univ. Wisconsin Madison, pp. 4.6.8-1 - 4.6.8-12.
3885 : // Threlkeld, J.L. 1970. Thermal Environmental Engineering, 2nd Edition,
3886 : // Englewood Cliffs: Prentice-Hall,Inc. pp. 254-270.
3887 : // Coil Uses Enthalpy Based Heat Transfer Coefficents and converts them to
3888 : // convential UA values. Intermediate value of fictitious Cp is defined. This follow
3889 : // the same procedure followed in the Design Calculation of the Coil. See the node in
3890 : // the one time calculation for design condition.
3891 :
3892 : // REFERENCES:
3893 : // Elmahdy, A.H. and Mitalas, G.P. 1977."A Simple Model for Cooling and
3894 : // Dehumidifying Coils for Use In Calculating Energy Requirements for Buildings,"
3895 : // ASHRAE Transactions,Vol.83 Part 2, pp. 103-117.
3896 :
3897 : // FUNCTION PARAMETER DEFINITIONS:
3898 : static constexpr std::string_view RoutineName("CoilCompletelyWet");
3899 :
3900 : // INTERFACE BLOCK SPECIFICATIONS
3901 : // na
3902 :
3903 : // DERIVED TYPE DEFINITIONS
3904 : // na
3905 :
3906 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
3907 : Real64 AirSideResist; // Air-side resistance to heat transfer(m2 C/W)
3908 : Real64 WaterSideResist; // Liquid-side resistance to heat transfer(m2 C/W)
3909 : Real64 EnteringAirDewPt; // Entering air dew point(C)
3910 : Real64 UACoilTotalEnth; // Overall enthalpy heat transfer coefficient(kg/s)
3911 : Real64 CapacityRateAirWet; // Air-side capacity rate(kg/s)
3912 : Real64 CapacityRateWaterWet; // Liquid-side capacity rate(kg/s)
3913 : Real64 ResistRatio; // Ratio of resistances
3914 : Real64 EnthAirOutlet; // Outlet air enthalpy
3915 : Real64 EnthSatAirInletWaterTemp; // Saturated enthalpy of air at entering water temperature(J/kg)
3916 : Real64 EnthSatAirOutletWaterTemp; // Saturated enthalpy of air at exit water temperature(J/kg)
3917 : Real64 EnthSatAirCoilSurfaceEntryTemp; // Saturated enthalpy of air at entering surface temperature(J/kg)
3918 : Real64 EnthSatAirCoilSurfaceExitTemp; // Saturated enthalpy of air at exit surface temperature(J/kg)
3919 : Real64 EnthAirInlet; // Enthalpy of air at inlet
3920 : Real64 IntermediateCpSat; // Coefficient for equation below(J/kg C)
3921 : // EnthSat1-EnthSat2 = IntermediateCpSat*(TSat1-TSat2)
3922 : // (all water and surface temperatures are
3923 : // related to saturated air enthalpies for
3924 : // wet surface heat transfer calculations)
3925 26844788 : Real64 constexpr SmallNo(1.e-9); // smallNo used in place of 0
3926 : Real64 AirMassFlow;
3927 : Real64 WaterMassFlowRate;
3928 : Real64 Cp;
3929 :
3930 26844788 : SurfAreaWetFraction = 1.0;
3931 26844788 : AirSideResist = 1.0 / max(UAExternalTotal, SmallNo);
3932 26844788 : WaterSideResist = 1.0 / max(UAInternalTotal, SmallNo);
3933 :
3934 26844788 : auto const &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
3935 : // adjust mass flow rates for cycling fan cycling coil operation
3936 26844788 : if (fanOp == HVAC::FanOp::Cycling) {
3937 2515716 : if (PartLoadRatio > 0.0) {
3938 2515716 : AirMassFlow = waterCoil.InletAirMassFlowRate / PartLoadRatio;
3939 2515716 : WaterMassFlowRate = min(waterCoil.InletWaterMassFlowRate / PartLoadRatio, waterCoil.MaxWaterMassFlowRate);
3940 : } else {
3941 0 : AirMassFlow = 0.0;
3942 0 : WaterMassFlowRate = 0.0;
3943 : }
3944 : } else {
3945 24329072 : AirMassFlow = waterCoil.InletAirMassFlowRate;
3946 24329072 : WaterMassFlowRate = waterCoil.InletWaterMassFlowRate;
3947 : }
3948 :
3949 : // Calculate enthalpies of entering air and water
3950 :
3951 : // Enthalpy of air at inlet to the coil
3952 26844788 : EnthAirInlet = PsyHFnTdbW(AirTempIn, AirHumRat);
3953 :
3954 : // Saturation Enthalpy of Air at inlet water temperature
3955 26844788 : EnthSatAirInletWaterTemp = PsyHFnTdbW(WaterTempIn, PsyWFnTdpPb(state, WaterTempIn, state.dataEnvrn->OutBaroPress));
3956 :
3957 : // Estimate IntermediateCpSat using entering air dewpoint and water temperature
3958 26844788 : EnteringAirDewPt = PsyTdpFnWPb(state, AirHumRat, state.dataEnvrn->OutBaroPress);
3959 :
3960 : // An intermediate value of Specific heat . EnthSat1-EnthSat2 = IntermediateCpSat*(TSat1-TSat2)
3961 26844788 : IntermediateCpSat =
3962 26844788 : (PsyHFnTdbW(EnteringAirDewPt, PsyWFnTdpPb(state, EnteringAirDewPt, state.dataEnvrn->OutBaroPress)) - EnthSatAirInletWaterTemp) /
3963 26844788 : (EnteringAirDewPt - WaterTempIn);
3964 :
3965 : // Determine air and water enthalpy outlet conditions by modeling
3966 : // coil as counterflow enthalpy heat exchanger
3967 26844788 : UACoilTotalEnth = 1.0 / (IntermediateCpSat * WaterSideResist + AirSideResist * PsyCpAirFnW(0.0));
3968 26844788 : CapacityRateAirWet = AirMassFlow;
3969 26844788 : Cp = state.dataPlnt->PlantLoop(waterCoil.WaterPlantLoc.loopNum).glycol->getSpecificHeat(state, WaterTempIn, RoutineName);
3970 26844788 : CapacityRateWaterWet = WaterMassFlowRate * (Cp / IntermediateCpSat);
3971 26844788 : CoilOutletStreamCondition(state,
3972 : CoilNum,
3973 : CapacityRateAirWet,
3974 : EnthAirInlet,
3975 : CapacityRateWaterWet,
3976 : EnthSatAirInletWaterTemp,
3977 : UACoilTotalEnth,
3978 : EnthAirOutlet,
3979 : EnthSatAirOutletWaterTemp);
3980 :
3981 : // Calculate entering and leaving external surface conditions from
3982 : // air and water conditions and the ratio of resistances
3983 26844788 : ResistRatio = (WaterSideResist) / (WaterSideResist + PsyCpAirFnW(0.0) / IntermediateCpSat * AirSideResist);
3984 26844788 : EnthSatAirCoilSurfaceEntryTemp = EnthSatAirOutletWaterTemp + ResistRatio * (EnthAirInlet - EnthSatAirOutletWaterTemp);
3985 26844788 : EnthSatAirCoilSurfaceExitTemp = EnthSatAirInletWaterTemp + ResistRatio * (EnthAirOutlet - EnthSatAirInletWaterTemp);
3986 :
3987 : // Calculate Coil Surface Temperature at air entry to the coil
3988 26844788 : AirInletCoilSurfTemp = PsyTsatFnHPb(state, EnthSatAirCoilSurfaceEntryTemp, state.dataEnvrn->OutBaroPress);
3989 :
3990 : // Calculate outlet air temperature and humidity from enthalpies and surface conditions.
3991 26844788 : TotWaterCoilLoad = AirMassFlow * (EnthAirInlet - EnthAirOutlet);
3992 26844788 : OutletWaterTemp = WaterTempIn + TotWaterCoilLoad / max(WaterMassFlowRate, SmallNo) / Cp;
3993 :
3994 : // Calculates out put variable for the completely wet coil
3995 26844788 : WetCoilOutletCondition(state, CoilNum, AirTempIn, EnthAirInlet, EnthAirOutlet, UAExternalTotal, OutletAirTemp, OutletAirHumRat, SenWaterCoilLoad);
3996 26844788 : }
3997 :
3998 : // Coil Part Wet Part Dry Subroutine for Cooling Coil
3999 :
4000 709695 : void CoilPartWetPartDry(EnergyPlusData &state,
4001 : int const CoilNum, // Number of Coil
4002 : bool const FirstHVACIteration, // Saving Old values
4003 : Real64 const InletWaterTemp, // Entering liquid temperature(C)
4004 : Real64 const InletAirTemp, // Entering air dry bulb temperature(C)
4005 : Real64 const AirDewPointTemp, // Entering air dew point(C)
4006 : Real64 &OutletWaterTemp, // Leaving liquid temperature(C)
4007 : Real64 &OutletAirTemp, // Leaving air dry bulb temperature(C)
4008 : Real64 &OutletAirHumRat, // Leaving air humidity ratio
4009 : Real64 &TotWaterCoilLoad, // Total heat transfer rate (W)
4010 : Real64 &SenWaterCoilLoad, // Sensible heat transfer rate (W)
4011 : Real64 &SurfAreaWetFraction, // Fraction of surface area wet
4012 : HVAC::FanOp const fanOp, // fan operating mode
4013 : Real64 const PartLoadRatio // part-load ratio of heating coil
4014 : )
4015 : {
4016 :
4017 : // FUNCTION INFORMATION:
4018 : // AUTHOR Rahul Chillar
4019 : // DATE WRITTEN March 2004
4020 :
4021 : // PURPOSE OF THIS FUNCTION:
4022 : // Calculate the performance of a cooling coil when the external fin surface is
4023 : // part wet and part dry. Results include outlet air temperature and humidity,
4024 : // outlet liquid temperature, sensible and total cooling capacities, and the wet
4025 : // fraction of the air-side surface area.
4026 :
4027 : // METHODOLOGY EMPLOYED:
4028 : // Models coil using effectiveness NTU model
4029 :
4030 : // REFERENCES:
4031 : // Elmahdy, A.H. and Mitalas, G.P. 1977. "A Simple Model for Cooling and
4032 : // Dehumidifying Coils for Use In Calculating Energy Requirements for Buildings,"
4033 : // ASHRAE Transactions,Vol.83 Part 2, pp. 103-117.
4034 : // TRNSYS. 1990. A Transient System Simulation Program: Reference Manual.
4035 : // Solar Energy Laboratory, Univ. Wisconsin- Madison, pp. 4.6.8-1 - 4.6.8-12.
4036 : // Threlkeld, J.L. 1970. Thermal Environmental Engineering, 2nd Edition,
4037 : // Englewood Cliffs: Prentice-Hall,Inc. pp. 254-270.
4038 :
4039 : // FUNCTION PARAMETER DEFINITIONS:
4040 709695 : int constexpr itmax(60);
4041 709695 : Real64 constexpr smalltempdiff(1.0e-9);
4042 :
4043 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
4044 : Real64 DryCoilHeatTranfer; // Heat transfer rate for dry coil(W)
4045 : Real64 WetCoilTotalHeatTransfer; // Total heat transfer rate for wet coil(W)
4046 : Real64 WetCoilSensibleHeatTransfer; // Sensible heat transfer rate for wet coil(W)
4047 : Real64 SurfAreaWet; // Air-side area of wet coil(m2)
4048 : Real64 SurfAreaDry; // Air-side area of dry coil(m2)
4049 : Real64 DryCoilUA; // Overall heat transfer coefficient for dry coil(W/C)
4050 : Real64 WetDryInterfcWaterTemp; // Liquid temperature at wet/dry boundary(C)
4051 : Real64 WetDryInterfcAirTemp; // Air temperature at wet/dry boundary(C)
4052 : Real64 WetDryInterfcSurfTemp; // Surface temperature at wet/dry boundary(C)
4053 : Real64 EstimateWetDryInterfcWaterTemp; // Estimated liquid temperature at wet/dry boundary(C)
4054 : Real64 EstimateSurfAreaWetFraction; // Initial Estimate for Fraction of Surface Wet with condensation
4055 : Real64 WetPartUAInternal; // UA of Wet Coil Internal
4056 : Real64 WetPartUAExternal; // UA of Dry Coil External
4057 : Real64 WetDryInterfcHumRat; // Humidity Ratio at interface of the wet dry transition
4058 : Real64 X1T; // Variables used in the two iteration in this subroutine.
4059 : Real64 NewSurfAreaWetFrac; // Variables used in the two iteration in this subroutine.
4060 : Real64 ResultXT; // Variables used in the two iteration in this subroutine.
4061 : Real64 Y1T; // Variables used in the two iterations in this subroutine.
4062 : Real64 errorT; // Error in interation for First If loop
4063 : Real64 error; // Deviation of dependent variable in iteration
4064 : Real64 SurfAreaFracPrevious;
4065 : Real64 ErrorPrevious;
4066 : Real64 SurfAreaFracLast;
4067 : Real64 ErrorLast;
4068 : int iter; // Iteration counter
4069 : int icvg; // Iteration convergence flag
4070 : int icvgT; // Iteration Convergence Flag for First If loop
4071 : int itT; // Iteration Counter for First If Loop
4072 :
4073 : // Iterates on SurfAreaWetFraction to converge on surface temperature equal to
4074 : // entering air dewpoint at wet/dry boundary.
4075 :
4076 : // Preliminary estimates of coil performance to begin iteration
4077 709695 : OutletWaterTemp = InletAirTemp;
4078 709695 : DryCoilHeatTranfer = 0.0;
4079 709695 : WetCoilTotalHeatTransfer = 0.0;
4080 709695 : WetCoilSensibleHeatTransfer = 0.0;
4081 :
4082 709695 : auto &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
4083 709695 : if (FirstHVACIteration) {
4084 : // Estimate liquid temperature at boundary as entering air dew point
4085 314814 : WetDryInterfcWaterTemp = AirDewPointTemp;
4086 :
4087 : // Estimate fraction wet surface area based on liquid temperatures
4088 314814 : if (std::abs(OutletWaterTemp - InletWaterTemp) > smalltempdiff) {
4089 314814 : SurfAreaWetFraction = (WetDryInterfcWaterTemp - InletWaterTemp) / (OutletWaterTemp - InletWaterTemp);
4090 : } else {
4091 0 : SurfAreaWetFraction = 0.0;
4092 : }
4093 :
4094 : } else {
4095 394881 : SurfAreaWetFraction = waterCoil.SurfAreaWetFractionSaved;
4096 : }
4097 : // BEGIN LOOP to converge on SurfAreaWetFraction
4098 : // The method employed in this loop is as follows: The coil is partially wet and partially dry,
4099 : // we calculate the temperature of the coil at the interface, (the point at which the moisture begins
4100 : // to condense) temperature of the water at interface and air temp is dew point at that location.
4101 : // This is done by Iterating between the Completely Dry and Completely Wet Coil until the outlet
4102 : // water temperature of one coil equals the inlet water temperature of another.
4103 : // Using this value of interface temperature we now iterate to calculate Surface Fraction Wet, Iterate
4104 : // function perturbs the value of Surface Fraction Wet and based on this new value the entire loop is
4105 : // repeated to get a new interface water temperature and then surface fraction wet is again calculated.
4106 : // This process continues till the error between the Wet Dry Interface Temp and Air Dew Point becomes
4107 : // very negligible and in 95% of the cases its is a complete convergence to give the exact surface Wet
4108 : // fraction.
4109 709695 : NewSurfAreaWetFrac = SurfAreaWetFraction;
4110 709695 : error = 0.0;
4111 709695 : SurfAreaFracPrevious = SurfAreaWetFraction;
4112 709695 : ErrorPrevious = 0.0;
4113 709695 : SurfAreaFracLast = SurfAreaWetFraction;
4114 709695 : ErrorLast = 0.0;
4115 :
4116 4052106 : for (iter = 1; iter <= itmax; ++iter) {
4117 :
4118 : // Calculating Surface Area Wet and Surface Area Dry
4119 4052106 : SurfAreaWet = SurfAreaWetFraction * waterCoil.TotCoilOutsideSurfArea;
4120 4052106 : SurfAreaDry = waterCoil.TotCoilOutsideSurfArea - SurfAreaWet;
4121 :
4122 : // Calculating UA values for the Dry Part of the Coil
4123 4052106 : DryCoilUA = SurfAreaDry / (1.0 / waterCoil.UACoilInternalPerUnitArea + 1.0 / waterCoil.UADryExtPerUnitArea);
4124 :
4125 : // Calculating UA Value for the Wet part of the Coil
4126 4052106 : WetPartUAExternal = waterCoil.UAWetExtPerUnitArea * SurfAreaWet;
4127 4052106 : WetPartUAInternal = waterCoil.UACoilInternalPerUnitArea * SurfAreaWet;
4128 :
4129 : // Calculating Water Temperature at Wet Dry Interface of the coil
4130 4052106 : WetDryInterfcWaterTemp = InletWaterTemp + SurfAreaWetFraction * (OutletWaterTemp - InletWaterTemp);
4131 :
4132 : // BEGIN LOOP to converge on liquid temperature at wet/dry boundary
4133 16171634 : for (itT = 1; itT <= itmax; ++itT) {
4134 :
4135 : // Calculate dry coil performance with estimated liquid temperature at the boundary.
4136 16171634 : CoilCompletelyDry(state,
4137 : CoilNum,
4138 : WetDryInterfcWaterTemp,
4139 : InletAirTemp,
4140 : DryCoilUA,
4141 : OutletWaterTemp,
4142 : WetDryInterfcAirTemp,
4143 : WetDryInterfcHumRat,
4144 : DryCoilHeatTranfer,
4145 : fanOp,
4146 : PartLoadRatio);
4147 :
4148 : // Calculate wet coil performance with calculated air temperature at the boundary.
4149 16171634 : CoilCompletelyWet(state,
4150 : CoilNum,
4151 : InletWaterTemp,
4152 : WetDryInterfcAirTemp,
4153 : WetDryInterfcHumRat,
4154 : WetPartUAInternal,
4155 : WetPartUAExternal,
4156 : EstimateWetDryInterfcWaterTemp,
4157 : OutletAirTemp,
4158 : OutletAirHumRat,
4159 : WetCoilTotalHeatTransfer,
4160 : WetCoilSensibleHeatTransfer,
4161 : EstimateSurfAreaWetFraction,
4162 : WetDryInterfcSurfTemp,
4163 : fanOp,
4164 : PartLoadRatio);
4165 :
4166 : // Iterating to calculate the actual wet dry interface water temperature.
4167 16171634 : errorT = EstimateWetDryInterfcWaterTemp - WetDryInterfcWaterTemp;
4168 16171634 : General::Iterate(ResultXT, 0.001, WetDryInterfcWaterTemp, errorT, X1T, Y1T, itT, icvgT);
4169 16171634 : WetDryInterfcWaterTemp = ResultXT;
4170 :
4171 : // IF convergence is achieved then exit the itT to itmax Do loop.
4172 16171634 : if (icvgT == 1) {
4173 4052106 : break;
4174 : }
4175 :
4176 : } // End Do for Liq Boundary temp Convergence
4177 :
4178 : // Wet Dry Interface temperature not converged after maximum specified iterations.
4179 : // Print error message, set return error flag
4180 4052106 : if ((itT > itmax) && (!state.dataGlobal->WarmupFlag)) {
4181 0 : ShowWarningError(state, format("For Coil:Cooling:Water {}", waterCoil.Name));
4182 0 : ShowContinueError(state, "CoilPartWetPartDry: Maximum iterations exceeded for Liq Temp, at Interface");
4183 : }
4184 :
4185 : // If Following condition prevails then surface is dry, calculate dry coil performance and return
4186 4052106 : if (SurfAreaWetFraction <= 0.0 && WetDryInterfcSurfTemp >= AirDewPointTemp) {
4187 :
4188 : // Calculating Value of Dry UA for the coil
4189 0 : DryCoilUA = waterCoil.TotCoilOutsideSurfArea / (1.0 / waterCoil.UACoilInternalPerUnitArea + 1.0 / waterCoil.UADryExtPerUnitArea);
4190 :
4191 : // Calling the Completely Dry Coil for outputs
4192 0 : CoilCompletelyDry(state,
4193 : CoilNum,
4194 : InletWaterTemp,
4195 : InletAirTemp,
4196 : DryCoilUA,
4197 : OutletWaterTemp,
4198 : OutletAirTemp,
4199 : OutletAirHumRat,
4200 : TotWaterCoilLoad,
4201 : fanOp,
4202 : PartLoadRatio);
4203 :
4204 : // Sensible load = Total load in a Completely Dry Coil
4205 0 : SenWaterCoilLoad = TotWaterCoilLoad;
4206 :
4207 : // All coil is Dry so fraction wet is ofcourse =0
4208 0 : SurfAreaWetFraction = 0.0;
4209 0 : return;
4210 : }
4211 :
4212 : // IF the coil is not Dry then iterate to calculate Fraction of surface area that is wet.
4213 4052106 : error = WetDryInterfcSurfTemp - AirDewPointTemp;
4214 4052106 : CoilAreaFracIter(
4215 : NewSurfAreaWetFrac, SurfAreaWetFraction, error, SurfAreaFracPrevious, ErrorPrevious, SurfAreaFracLast, ErrorLast, iter, icvg);
4216 4052106 : SurfAreaWetFraction = NewSurfAreaWetFrac;
4217 :
4218 : // If converged, leave iteration loop
4219 4052106 : if (icvg == 1) {
4220 709695 : break;
4221 : }
4222 :
4223 : // Surface temperature not converged. Repeat calculations with new
4224 : // estimate of fraction wet surface area.
4225 3342411 : if (SurfAreaWetFraction > 1.0) {
4226 50980 : SurfAreaWetFraction = 1.0;
4227 : }
4228 3342411 : if (SurfAreaWetFraction <= 0.0) {
4229 191838 : SurfAreaWetFraction = 0.0098;
4230 : }
4231 :
4232 : } // End do for the overall iteration
4233 :
4234 : // Calculate sum of total and sensible heat transfer from dry and wet parts.
4235 709695 : TotWaterCoilLoad = DryCoilHeatTranfer + WetCoilTotalHeatTransfer;
4236 709695 : SenWaterCoilLoad = DryCoilHeatTranfer + WetCoilSensibleHeatTransfer;
4237 :
4238 : // Save last iterations values for this current time step
4239 709695 : waterCoil.SurfAreaWetFractionSaved = SurfAreaWetFraction;
4240 : }
4241 :
4242 : // Calculating coil UA for Cooling Coil
4243 :
4244 0 : Real64 CalcCoilUAbyEffectNTU(EnergyPlusData &state,
4245 : int const CoilNum,
4246 : Real64 const CapacityStream1, // Capacity rate of stream1.(W/C)
4247 : Real64 const EnergyInStreamOne, // Inlet state of stream1.(C)
4248 : Real64 const CapacityStream2, // Capacity rate of stream2.(W/C)
4249 : Real64 const EnergyInStreamTwo, // Inlet state of stream2.(C)
4250 : Real64 const DesTotalHeatTransfer // Heat transfer rate(W)
4251 : )
4252 : {
4253 :
4254 : // FUNCTION INFORMATION:
4255 : // AUTHOR Rahul Chillar
4256 : // DATE WRITTEN March 2004
4257 :
4258 : // PURPOSE OF THIS FUNCTION:
4259 : // Calculate the UA of a heat exchanger using the effectiveness-NTU relationships
4260 : // given the entering capacity rate and temperature of each flow stream, the
4261 : // heat transfer rate under these conditions and the heat exchanger configuration.
4262 :
4263 : // METHODOLOGY EMPLOYED:
4264 : // Models coil using effectiveness NTU model
4265 :
4266 : // Enforce explicit typing of all variables in this routine
4267 :
4268 : // Return value
4269 : Real64 CalcCoilUAbyEffectNTU; // Overall heat transfer coefficient(W/C)
4270 :
4271 : // FUNCTION PARAMETER DEFINITIONS:
4272 0 : Real64 constexpr SmallNo(1.e-9);
4273 0 : int constexpr itmax(12);
4274 :
4275 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
4276 : Real64 MaxHeatTransfer; // Maximum heat transfer from inlet conditions (W)
4277 : Real64 EstimatedHeatTransfer; // Estimated heat transfer in iteration(W)
4278 : Real64 CoilUA; // Estimated heat transfer coefficient(W/C)
4279 : Real64 error; // Deviation of dependent variable in iteration
4280 : Real64 X1; // Previous values of independent variable in iteration
4281 : Real64 Y1;
4282 : Real64 ResultX;
4283 : Real64 EnergyOutStreamOne; // Intermediate Variable used
4284 : Real64 EnergyOutStreamTwo; // Intermediate variable used
4285 : Real64 DesTotalHeatTransferCheck; // Check value to keep design total heat transfer in range
4286 : int iter; // Iteration index
4287 : int icvg; // Iteration convergence flag
4288 :
4289 : // Check for Q out of range (effectiveness > 1)
4290 0 : MaxHeatTransfer = std::abs(min(CapacityStream1, CapacityStream2) * (EnergyInStreamOne - EnergyInStreamTwo));
4291 :
4292 0 : auto const &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
4293 : // Error Message
4294 0 : if ((std::abs(DesTotalHeatTransfer) - MaxHeatTransfer) / max(MaxHeatTransfer, SmallNo) > SmallNo) {
4295 0 : ShowWarningError(state, format("For Coil:Cooling:Water {}", waterCoil.Name));
4296 0 : ShowContinueError(state, "CalcCoilUAbyEffectNTU:Given Q impossible for given inlet states, proceeding with MaxHeat Transfer");
4297 0 : ShowContinueError(state, "Check the Sizing:System and Sizing:Zone cooling design supply air temperature and ");
4298 0 : ShowContinueError(state,
4299 : "the Sizing:Plant design Loop exit temperature. There must be sufficient difference between these two temperatures.");
4300 : }
4301 :
4302 : // Design Heat Transfer cannot exceed Max heat Transfer , setting it value such that effectiveness<1.0
4303 0 : if ((DesTotalHeatTransfer) > (MaxHeatTransfer)) {
4304 : // Pegging value so that effectiveness is less than 1.
4305 0 : DesTotalHeatTransferCheck = 0.9 * MaxHeatTransfer;
4306 :
4307 : // Estimate CalcCoilUAbyEffectNTU
4308 0 : CoilUA = std::abs(DesTotalHeatTransferCheck / (EnergyInStreamOne - EnergyInStreamTwo));
4309 :
4310 : } else {
4311 :
4312 : // Estimate CalcCoilUAbyEffectNTU
4313 0 : CoilUA = std::abs(DesTotalHeatTransfer / (EnergyInStreamOne - EnergyInStreamTwo));
4314 : }
4315 :
4316 : // BEGIN LOOP to iteratively calculate CalcCoilUAbyEffectNTU
4317 0 : for (iter = 1; iter <= itmax; ++iter) {
4318 :
4319 : // Calculate heat transfer rate for estimated CalcCoilUAbyEffectNTU
4320 0 : CoilOutletStreamCondition(
4321 : state, CoilNum, CapacityStream1, EnergyInStreamOne, CapacityStream2, EnergyInStreamTwo, CoilUA, EnergyOutStreamOne, EnergyOutStreamTwo);
4322 :
4323 : // Initial Guess for a value of heat transfer
4324 0 : EstimatedHeatTransfer = CapacityStream1 * (EnergyInStreamOne - EnergyOutStreamOne);
4325 :
4326 : // Calculate new estimate for CalcCoilUAbyEffectNTU by iteration
4327 0 : if (DesTotalHeatTransfer > MaxHeatTransfer) {
4328 0 : error = std::abs(EstimatedHeatTransfer) - std::abs(DesTotalHeatTransferCheck);
4329 : } else {
4330 0 : error = std::abs(EstimatedHeatTransfer) - std::abs(DesTotalHeatTransfer);
4331 : }
4332 0 : General::Iterate(ResultX, 0.01, CoilUA, error, X1, Y1, iter, icvg);
4333 0 : CoilUA = ResultX;
4334 : // If converged, leave loop
4335 0 : if (icvg == 1) {
4336 0 : break;
4337 : }
4338 : }
4339 :
4340 : // If not converged after itmax iterations, return error code
4341 0 : if ((iter > itmax) && (!state.dataGlobal->WarmupFlag)) {
4342 0 : ShowWarningError(state, format("For Coil:Cooling:Water {}", waterCoil.Name));
4343 0 : ShowContinueError(state, "CalcCoilUAbyEffectNTU: Maximum iterations exceeded:Coil UA calculation");
4344 0 : CalcCoilUAbyEffectNTU = 0.0; // Autodesk:Return Line added to set return value: Using non-converged CoilUA value may be preferred but
4345 : // that was not happening
4346 : } else {
4347 :
4348 : // Assign value to CalcCoilUAbyEffectNTU
4349 0 : CalcCoilUAbyEffectNTU = CoilUA;
4350 : }
4351 :
4352 0 : return CalcCoilUAbyEffectNTU;
4353 : }
4354 :
4355 : // Calculating coil outlet stream conditions and coil UA for Cooling Coil
4356 :
4357 44886844 : void CoilOutletStreamCondition(EnergyPlusData &state,
4358 : int const CoilNum,
4359 : Real64 const CapacityStream1, // Capacity rate of stream1(W/C)
4360 : Real64 const EnergyInStreamOne, // Inlet state of stream1 (C)
4361 : Real64 const CapacityStream2, // Capacity rate of stream2 (W/C)
4362 : Real64 const EnergyInStreamTwo, // Inlet state of stream2 (C)
4363 : Real64 const CoilUA, // Heat transfer rateW)
4364 : Real64 &EnergyOutStreamOne, // Outlet state of stream1 (C)
4365 : Real64 &EnergyOutStreamTwo // Outlet state of stream2 (C)
4366 : )
4367 : {
4368 :
4369 : // FUNCTION INFORMATION:
4370 : // AUTHOR Rahul Chillar
4371 : // DATE WRITTEN March 2004
4372 :
4373 : // PURPOSE OF THIS FUNCTION:
4374 : // Calculate the outlet states of a simple heat exchanger using the effectiveness-Ntu
4375 : // method of analysis.
4376 :
4377 : // REFERENCES:
4378 : // Kays, W.M. and A.L. London. 1964.Compact Heat Exchangers, 2nd Ed.McGraw-Hill:New York.
4379 :
4380 : // FUNCTION PARAMETER DEFINITIONS:
4381 44886844 : Real64 constexpr LargeNo(1.e10); // value used in place of infinity
4382 44886844 : Real64 constexpr SmallNo(1.e-15); // value used in place of zero
4383 :
4384 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
4385 : Real64 MinimumCapacityStream; // Minimum capacity rate of the streams(W/C)
4386 : Real64 MaximumCapacityStream; // Maximum capacity rate of the streams(W/C)
4387 : Real64 RatioStreamCapacity; // Ratio of minimum to maximum capacity rate
4388 : Real64 NTU; // Number of transfer units
4389 44886844 : Real64 effectiveness(0.0); // Heat exchanger effectiveness
4390 : Real64 MaxHeatTransfer; // Maximum heat transfer possible(W)
4391 : Real64 e; // Intermediate variables in effectiveness equation
4392 : Real64 eta;
4393 : Real64 b;
4394 : Real64 d;
4395 :
4396 : // NTU and MinimumCapacityStream/MaximumCapacityStream (RatioStreamCapacity) calculations
4397 44886844 : MinimumCapacityStream = min(CapacityStream1, CapacityStream2);
4398 44886844 : MaximumCapacityStream = max(CapacityStream1, CapacityStream2);
4399 :
4400 44886844 : if (std::abs(MaximumCapacityStream) <= 1.e-6) { // .EQ. 0.0d0) THEN
4401 0 : RatioStreamCapacity = 1.0;
4402 : } else {
4403 44886844 : RatioStreamCapacity = MinimumCapacityStream / MaximumCapacityStream;
4404 : }
4405 :
4406 44886844 : if (std::abs(MinimumCapacityStream) <= 1.e-6) { // .EQ. 0.0d0) THEN
4407 0 : NTU = LargeNo;
4408 : } else {
4409 44886844 : NTU = CoilUA / MinimumCapacityStream;
4410 : }
4411 :
4412 44886844 : auto const &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
4413 : // Calculate effectiveness for special limiting cases
4414 44886844 : if (NTU <= 0.0) {
4415 168829 : effectiveness = 0.0;
4416 :
4417 44718015 : } else if (RatioStreamCapacity < SmallNo) {
4418 : // MinimumCapacityStream/MaximumCapacityStream = 0 and effectiveness is independent of configuration
4419 : // 20 is the Limit Chosen for Exponential Function, beyond which there is float point error.
4420 0 : if (NTU > 20.0) {
4421 0 : effectiveness = 1.0;
4422 : } else {
4423 0 : effectiveness = 1.0 - std::exp(-NTU);
4424 : }
4425 : // Calculate effectiveness depending on heat exchanger configuration
4426 44718015 : } else if (waterCoil.HeatExchType == state.dataWaterCoils->CounterFlow) {
4427 :
4428 : // Counterflow Heat Exchanger Configuration
4429 12198 : if (std::abs(RatioStreamCapacity - 1.0) < SmallNo) {
4430 0 : effectiveness = NTU / (NTU + 1.0);
4431 : } else {
4432 12198 : if (NTU * (1.0 - RatioStreamCapacity) > 20.0) {
4433 0 : e = 0.0;
4434 : } else {
4435 12198 : e = std::exp(-NTU * (1.0 - RatioStreamCapacity));
4436 : }
4437 12198 : effectiveness = (1.0 - e) / (1.0 - RatioStreamCapacity * e);
4438 : }
4439 :
4440 44705817 : } else if (waterCoil.HeatExchType == state.dataWaterCoils->CrossFlow) {
4441 : // Cross flow, both streams unmixed
4442 44705817 : eta = std::pow(NTU, -0.22);
4443 44705817 : if ((NTU * RatioStreamCapacity * eta) > 20.0) {
4444 0 : b = 1.0 / (RatioStreamCapacity * eta);
4445 0 : if (b > 20.0) {
4446 0 : effectiveness = 1.0;
4447 : } else {
4448 0 : effectiveness = 1.0 - std::exp(-b);
4449 0 : if (effectiveness < 0.0) {
4450 0 : effectiveness = 0.0;
4451 : }
4452 : }
4453 : } else {
4454 44705817 : d = ((std::exp(-NTU * RatioStreamCapacity * eta) - 1.0) / (RatioStreamCapacity * eta));
4455 44705817 : if (d < -20.0 || d > 0.0) {
4456 13615 : effectiveness = 1.0;
4457 : } else {
4458 44692202 : effectiveness = 1.0 - std::exp((std::exp(-NTU * RatioStreamCapacity * eta) - 1.0) / (RatioStreamCapacity * eta));
4459 44692202 : if (effectiveness < 0.0) {
4460 0 : effectiveness = 0.0;
4461 : }
4462 : }
4463 : }
4464 : }
4465 :
4466 : // Determine leaving conditions for the two streams
4467 44886844 : MaxHeatTransfer = max(MinimumCapacityStream, SmallNo) * (EnergyInStreamOne - EnergyInStreamTwo);
4468 44886844 : EnergyOutStreamOne = EnergyInStreamOne - effectiveness * MaxHeatTransfer / max(CapacityStream1, SmallNo);
4469 44886844 : EnergyOutStreamTwo = EnergyInStreamTwo + effectiveness * MaxHeatTransfer / max(CapacityStream2, SmallNo);
4470 44886844 : }
4471 :
4472 : // Subroutine for caculating outlet condition if coil is wet , for Cooling Coil
4473 :
4474 26844788 : void WetCoilOutletCondition(EnergyPlusData &state,
4475 : int const CoilNum,
4476 : Real64 const AirTempIn, // Entering air dry bulb temperature(C)
4477 : Real64 const EnthAirInlet, // Entering air enthalpy(J/kg)
4478 : Real64 const EnthAirOutlet, // Leaving air enthalpy(J/kg)
4479 : Real64 const UACoilExternal, // Heat transfer coefficient for external surface (W/C)
4480 : Real64 &OutletAirTemp, // Leaving air dry bulb temperature(C)
4481 : Real64 &OutletAirHumRat, // Leaving air humidity ratio
4482 : Real64 &SenWaterCoilLoad // Sensible heat transfer rate(W)
4483 : )
4484 : {
4485 :
4486 : // FUNCTION INFORMATION:
4487 : // AUTHOR Rahul Chillar
4488 : // DATE WRITTEN Mar 2004
4489 :
4490 : // PURPOSE OF THIS FUNCTION:
4491 : // Calculate the leaving air temperature,the leaving air humidity ratio and the
4492 : // sensible cooling capacity of wet cooling coil.
4493 :
4494 : // METHODOLOGY EMPLOYED:
4495 : // Assumes condensate at uniform temperature.
4496 :
4497 : // REFERENCES:
4498 : // Elmahdy, A.H. and Mitalas, G.P. 1977."A Simple Model for Cooling and
4499 : // Dehumidifying Coils for Use In Calculating Energy Requirements for Buildings,"
4500 : // ASHRAE Transactions,Vol.83 Part 2, pp. 103-117.
4501 :
4502 : // FUNCTION PARAMETER DEFINITIONS:
4503 26844788 : Real64 constexpr SmallNo(1.e-9); // SmallNo value used in place of zero
4504 :
4505 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
4506 : Real64 CapacitanceAir; // Air capacity rate(W/C)
4507 : Real64 NTU; // Number of heat transfer units
4508 : Real64 effectiveness; // Heat exchanger effectiveness
4509 : Real64 EnthAirCondensateTemp; // Saturated air enthalpy at temperature of condensate(J/kg)
4510 : Real64 TempCondensation; // Temperature of condensate(C)
4511 : Real64 TempAirDewPoint; // Temperature air dew point
4512 :
4513 : // Determine the temperature effectiveness, assuming the temperature
4514 : // of the condensate is constant (MinimumCapacityStream/MaximumCapacityStream = 0) and the specific heat
4515 : // of moist air is constant
4516 :
4517 26844788 : auto const &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
4518 26844788 : CapacitanceAir = waterCoil.InletAirMassFlowRate * PsyCpAirFnW(waterCoil.InletAirHumRat);
4519 :
4520 : // Calculating NTU from UA and Capacitance.
4521 : // del NTU = UACoilExternal/MAX(CapacitanceAir,SmallNo)
4522 : // del effectiveness = 1 - EXP(-MAX(0.0d0,NTU))
4523 : // Calculating NTU from UA and Capacitance.
4524 26844788 : if (UACoilExternal > 0.0) {
4525 26844788 : if (CapacitanceAir > 0.0) {
4526 26844788 : NTU = UACoilExternal / CapacitanceAir;
4527 : } else {
4528 0 : NTU = 0.0;
4529 : }
4530 26844788 : effectiveness = 1.0 - std::exp(-NTU);
4531 : } else {
4532 0 : effectiveness = 0.0;
4533 : }
4534 :
4535 : // Calculate coil surface enthalpy and temperature at the exit
4536 : // of the wet part of the coil using the effectiveness relation
4537 26844788 : effectiveness = max(effectiveness, SmallNo);
4538 26844788 : EnthAirCondensateTemp = EnthAirInlet - (EnthAirInlet - EnthAirOutlet) / effectiveness;
4539 :
4540 : // Calculate condensate temperature as the saturation temperature
4541 : // at given saturation enthalpy
4542 26844788 : TempCondensation = PsyTsatFnHPb(state, EnthAirCondensateTemp, state.dataEnvrn->OutBaroPress);
4543 :
4544 26844788 : TempAirDewPoint = PsyTdpFnWPb(state, waterCoil.InletAirHumRat, state.dataEnvrn->OutBaroPress);
4545 :
4546 26844788 : if ((TempAirDewPoint - TempCondensation) > 0.1) {
4547 :
4548 : // Calculate Outlet Air Temperature using effectivness
4549 23470118 : OutletAirTemp = AirTempIn - (AirTempIn - TempCondensation) * effectiveness;
4550 : // Calculate Outlet air humidity ratio from PsyWFnTdbH routine
4551 23470118 : OutletAirHumRat = PsyWFnTdbH(state, OutletAirTemp, EnthAirOutlet);
4552 :
4553 : } else {
4554 3374670 : OutletAirHumRat = waterCoil.InletAirHumRat;
4555 3374670 : OutletAirTemp = PsyTdbFnHW(EnthAirOutlet, OutletAirHumRat);
4556 : }
4557 :
4558 : // Calculate Sensible Coil Load
4559 26844788 : SenWaterCoilLoad = CapacitanceAir * (AirTempIn - OutletAirTemp);
4560 26844788 : }
4561 :
4562 : // Beginning of Update subroutines for the WaterCoil Module
4563 : // *****************************************************************************
4564 :
4565 149968186 : void UpdateWaterCoil(EnergyPlusData &state, int const CoilNum)
4566 : {
4567 : // SUBROUTINE INFORMATION:
4568 : // AUTHOR Richard Liesen
4569 : // DATE WRITTEN 1998
4570 : // MODIFIED April 2004: Rahul Chillar
4571 : // Feb 2010 B. Griffith, plant upgrades
4572 : // RE-ENGINEERED na
4573 :
4574 : // PURPOSE OF THIS SUBROUTINE:
4575 : // This subroutine updates the coil outlet nodes.
4576 :
4577 : // METHODOLOGY EMPLOYED:
4578 : // Data is moved from the coil data structure to the coil outlet nodes.
4579 :
4580 : // Locals
4581 : // SUBROUTINE ARGUMENT DEFINITIONS:
4582 :
4583 : // SUBROUTINE PARAMETER DEFINITIONS:
4584 : // na
4585 :
4586 : // INTERFACE BLOCK SPECIFICATIONS
4587 : // na
4588 :
4589 : // DERIVED TYPE DEFINITIONS
4590 : // na
4591 :
4592 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4593 149968186 : auto const &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
4594 149968186 : int const AirInletNode = waterCoil.AirInletNodeNum;
4595 149968186 : int const AirOutletNode = waterCoil.AirOutletNodeNum;
4596 149968186 : int const WaterOutletNode = waterCoil.WaterOutletNodeNum;
4597 :
4598 : // Set the outlet air nodes of the WaterCoil
4599 149968186 : state.dataLoopNodes->Node(AirOutletNode).MassFlowRate = waterCoil.OutletAirMassFlowRate;
4600 149968186 : state.dataLoopNodes->Node(AirOutletNode).Temp = waterCoil.OutletAirTemp;
4601 149968186 : state.dataLoopNodes->Node(AirOutletNode).HumRat = waterCoil.OutletAirHumRat;
4602 149968186 : state.dataLoopNodes->Node(AirOutletNode).Enthalpy = waterCoil.OutletAirEnthalpy;
4603 :
4604 149968186 : state.dataLoopNodes->Node(WaterOutletNode).Temp = waterCoil.OutletWaterTemp;
4605 149968186 : state.dataLoopNodes->Node(WaterOutletNode).Enthalpy = waterCoil.OutletWaterEnthalpy;
4606 :
4607 : // Set the outlet nodes for properties that just pass through & not used
4608 149968186 : state.dataLoopNodes->Node(AirOutletNode).Quality = state.dataLoopNodes->Node(AirInletNode).Quality;
4609 149968186 : state.dataLoopNodes->Node(AirOutletNode).Press = state.dataLoopNodes->Node(AirInletNode).Press;
4610 149968186 : state.dataLoopNodes->Node(AirOutletNode).MassFlowRateMin = state.dataLoopNodes->Node(AirInletNode).MassFlowRateMin;
4611 149968186 : state.dataLoopNodes->Node(AirOutletNode).MassFlowRateMax = state.dataLoopNodes->Node(AirInletNode).MassFlowRateMax;
4612 149968186 : state.dataLoopNodes->Node(AirOutletNode).MassFlowRateMinAvail = state.dataLoopNodes->Node(AirInletNode).MassFlowRateMinAvail;
4613 149968186 : state.dataLoopNodes->Node(AirOutletNode).MassFlowRateMaxAvail = state.dataLoopNodes->Node(AirInletNode).MassFlowRateMaxAvail;
4614 149968186 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
4615 0 : state.dataLoopNodes->Node(AirOutletNode).CO2 = state.dataLoopNodes->Node(AirInletNode).CO2;
4616 : }
4617 149968186 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
4618 0 : state.dataLoopNodes->Node(AirOutletNode).GenContam = state.dataLoopNodes->Node(AirInletNode).GenContam;
4619 : }
4620 149968186 : }
4621 :
4622 : // End of Update subroutines for the WaterCoil Module
4623 : // *****************************************************************************
4624 :
4625 : // Beginning of Reporting subroutines for the WaterCoil Module
4626 : // *****************************************************************************
4627 :
4628 149968186 : void ReportWaterCoil(EnergyPlusData &state, int const CoilNum)
4629 : {
4630 :
4631 : // SUBROUTINE INFORMATION:
4632 : // AUTHOR Richard Liesen
4633 : // DATE WRITTEN 1998
4634 :
4635 : // PURPOSE OF THIS SUBROUTINE:
4636 : // This subroutine updates the report variable for the coils.
4637 :
4638 149968186 : auto &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
4639 149968186 : if (waterCoil.reportCoilFinalSizes) {
4640 20373029 : if (!state.dataGlobal->WarmupFlag && !state.dataGlobal->DoingHVACSizingSimulations && !state.dataGlobal->DoingSizing) {
4641 3351 : std::string coilObjClassName;
4642 3351 : if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterSimpleHeating) {
4643 2755 : coilObjClassName = "Coil:Heating:Water";
4644 2755 : state.dataRptCoilSelection->coilSelectionReportObj->setCoilFinalSizes(state,
4645 2755 : waterCoil.Name,
4646 : coilObjClassName,
4647 : waterCoil.DesWaterHeatingCoilRate,
4648 : waterCoil.DesWaterHeatingCoilRate,
4649 : waterCoil.DesAirVolFlowRate,
4650 : waterCoil.MaxWaterVolFlowRate);
4651 2755 : waterCoil.reportCoilFinalSizes = false;
4652 596 : } else if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterDetailedFlatCooling) {
4653 162 : coilObjClassName = "Coil:Cooling:Water:DetailedGeometry";
4654 162 : state.dataRptCoilSelection->coilSelectionReportObj->setCoilFinalSizes(state,
4655 162 : waterCoil.Name,
4656 : coilObjClassName,
4657 : waterCoil.DesWaterCoolingCoilRate,
4658 : -999.0,
4659 : waterCoil.DesAirVolFlowRate,
4660 : waterCoil.MaxWaterVolFlowRate);
4661 162 : waterCoil.reportCoilFinalSizes = false;
4662 434 : } else if (waterCoil.WaterCoilType == DataPlant::PlantEquipmentType::CoilWaterCooling) {
4663 434 : coilObjClassName = "Coil:Cooling:Water";
4664 434 : state.dataRptCoilSelection->coilSelectionReportObj->setCoilFinalSizes(state,
4665 434 : waterCoil.Name,
4666 : coilObjClassName,
4667 : waterCoil.DesWaterCoolingCoilRate,
4668 : -999.0,
4669 : waterCoil.DesAirVolFlowRate,
4670 : waterCoil.MaxWaterVolFlowRate);
4671 434 : waterCoil.reportCoilFinalSizes = false;
4672 : }
4673 3351 : }
4674 : }
4675 149968186 : Real64 ReportingConstant = state.dataHVACGlobal->TimeStepSysSec;
4676 : // report the WaterCoil energy from this component
4677 149968186 : waterCoil.TotWaterHeatingCoilEnergy = waterCoil.TotWaterHeatingCoilRate * ReportingConstant;
4678 149968186 : waterCoil.TotWaterCoolingCoilEnergy = waterCoil.TotWaterCoolingCoilRate * ReportingConstant;
4679 149968186 : waterCoil.SenWaterCoolingCoilEnergy = waterCoil.SenWaterCoolingCoilRate * ReportingConstant;
4680 :
4681 : // report the WaterCoil water collection to water storage tank (if needed)
4682 :
4683 149968186 : if (waterCoil.CondensateCollectMode == state.dataWaterCoils->CondensateToTank) {
4684 : // calculate and report condensation rates (how much water extracted from the air stream)
4685 : // water volumetric flow of water in m3/s for water system interactions
4686 : // put here to catch all types of DX coils
4687 0 : Real64 Tavg = (waterCoil.InletAirTemp + waterCoil.OutletAirTemp) / 2.0;
4688 : // CR9155 Remove specific humidity calculations
4689 : // mdot * del HumRat / rho water
4690 0 : waterCoil.CondensateVdot =
4691 0 : max(0.0, (waterCoil.InletAirMassFlowRate * (waterCoil.InletAirHumRat - waterCoil.OutletAirHumRat) / Psychrometrics::RhoH2O(Tavg)));
4692 0 : waterCoil.CondensateVol = waterCoil.CondensateVdot * ReportingConstant;
4693 :
4694 0 : state.dataWaterData->WaterStorage(waterCoil.CondensateTankID).VdotAvailSupply(waterCoil.CondensateTankSupplyARRID) = waterCoil.CondensateVdot;
4695 0 : state.dataWaterData->WaterStorage(waterCoil.CondensateTankID).TwaterSupply(waterCoil.CondensateTankSupplyARRID) = waterCoil.OutletAirTemp;
4696 : }
4697 149968186 : }
4698 :
4699 : // End of Reporting subroutines for the WaterCoil Module
4700 : // *****************************************************************************
4701 :
4702 : // Beginning of Coil Utility subroutines for the Detailed Model
4703 : // *****************************************************************************
4704 :
4705 1005 : void CalcDryFinEffCoef(EnergyPlusData &state, Real64 const OutTubeEffFinDiamRatio, Array1D<Real64> &PolynomCoef)
4706 : {
4707 : // SUBROUTINE INFORMATION:
4708 : // AUTHOR Unknown
4709 : // DATE WRITTEN Unknown
4710 : // DATE REWRITTEN April 1997 by Russell D. Taylor, Ph.D.
4711 : // MODIFIED
4712 : // RE-ENGINEERED
4713 :
4714 : // PURPOSE OF THIS SUBROUTINE:
4715 : // The following subroutines are used once per cooling coil
4716 : // simulation to obtain the coefficients of the dry fin
4717 : // efficiency equation. CalcDryFinEffCoef is the main calling
4718 : // routine which manages calls to the Bessel funtion and polynomial
4719 : // fit routines.
4720 :
4721 : // REFERENCES:
4722 : // First found in MODSIM.
4723 : // USE STATEMENTS:
4724 : // na
4725 :
4726 : // Argument array dimensioning
4727 :
4728 : // Locals
4729 : // SUBROUTINE ARGUMENT DEFINITIONS:
4730 :
4731 : // SUBROUTINE PARAMETER DEFINITIONS:
4732 : // na
4733 :
4734 : // INTERFACE BLOCK SPECIFICATIONS
4735 : // na
4736 :
4737 : // DERIVED TYPE DEFINITIONS
4738 : // na
4739 :
4740 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4741 : Real64 FAI;
4742 : Real64 FED;
4743 : Real64 FEDnumerator;
4744 : int I;
4745 : int IE1;
4746 : int IE2;
4747 : int IE3;
4748 : int IE4;
4749 : int IE5;
4750 : int IE6;
4751 : Real64 R1;
4752 : Real64 R1I1;
4753 : Real64 R1K1;
4754 : Real64 R2;
4755 : Real64 R2I0;
4756 : Real64 R2I1;
4757 : Real64 R2K0;
4758 : Real64 R2K1;
4759 : Real64 RO;
4760 :
4761 1005 : FAI = 0.02;
4762 61305 : for (I = 1; I <= WaterCoils::MaxOrderedPairs; ++I) {
4763 60300 : FAI += 0.035;
4764 60300 : R1 = FAI / (1.0 - OutTubeEffFinDiamRatio);
4765 60300 : R2 = R1 * OutTubeEffFinDiamRatio;
4766 60300 : RO = 2.0 * OutTubeEffFinDiamRatio / (FAI * (1.0 + OutTubeEffFinDiamRatio));
4767 60300 : CalcIBesselFunc(R1, 1, R1I1, IE1);
4768 60300 : CalcKBesselFunc(R2, 1, R2K1, IE2);
4769 60300 : CalcIBesselFunc(R2, 1, R2I1, IE3);
4770 60300 : CalcKBesselFunc(R1, 1, R1K1, IE4);
4771 60300 : CalcIBesselFunc(R2, 0, R2I0, IE5);
4772 60300 : CalcKBesselFunc(R2, 0, R2K0, IE6);
4773 60300 : FEDnumerator = RO * (R1I1 * R2K1 - R2I1 * R1K1);
4774 60300 : if (FEDnumerator != 0.0) {
4775 60300 : FED = FEDnumerator / (R2I0 * R1K1 + R1I1 * R2K0);
4776 : } else {
4777 0 : FED = 0.0;
4778 : }
4779 : // FED = RO * (R1I1 * R2K1 - R2I1 * R1K1) / (R2I0 * R1K1 + R1I1 * R2K0)
4780 60300 : state.dataWaterCoils->OrderedPair(I, 1) = FAI;
4781 60300 : state.dataWaterCoils->OrderedPair(I, 2) = FED;
4782 : }
4783 1005 : CalcPolynomCoef(state, state.dataWaterCoils->OrderedPair, PolynomCoef);
4784 1005 : }
4785 :
4786 180900 : void CalcIBesselFunc(Real64 const BessFuncArg, int const BessFuncOrd, Real64 &IBessFunc, int &ErrorCode)
4787 : {
4788 : // SUBROUTINE INFORMATION:
4789 : // AUTHOR Unknown
4790 : // DATE WRITTEN Unknown
4791 : // DATE REWRITTEN April 1997 by Russell D. Taylor, Ph.D.
4792 : // MODIFIED
4793 : // RE-ENGINEERED
4794 :
4795 : // PURPOSE OF THIS SUBROUTINE:
4796 : // To calculate the modified Bessel Function from order 0 to BessFuncOrd
4797 : // BessFuncArg ARGUMENT OF BESSEL FUNCTION
4798 : // BessFuncOrd ORDER OF BESSEL FUNCTION, GREATER THAN OR EQUAL TO ZERO
4799 : // IBessFunc RESULTANT VALUE OF I BESSEL FUNCTION
4800 : // ErrorCode RESULTANT ERROR CODE:
4801 : // ErrorCode = 0 NO ERROR
4802 : // ErrorCode = 1 BessFuncOrd .LT. 0
4803 : // ErrorCode = 2 BessFuncArg .LT. 0
4804 : // ErrorCode = 3 IBessFunc .LT. 10**(-30), IBessFunc IS SET TO 0
4805 : // ErrorCode = 4 BessFuncArg .GT. BessFuncOrd & BessFuncArg .GT. 90, IBessFunc IS SET TO 10**38
4806 :
4807 : // REFERENCES:
4808 : // First found in MODSIM.
4809 :
4810 : // USE STATEMENTS:
4811 : // na
4812 :
4813 : // Locals
4814 : // SUBROUTINE ARGUMENT DEFINITIONS:
4815 :
4816 : // SUBROUTINE PARAMETER DEFINITIONS:
4817 180900 : Real64 constexpr ErrorTol(1.0e-06);
4818 :
4819 : // INTERFACE BLOCK SPECIFICATIONS
4820 : // na
4821 :
4822 : // DERIVED TYPE DEFINITIONS
4823 : // na
4824 :
4825 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4826 : int LoopCount;
4827 :
4828 : Real64 FI;
4829 : Real64 FK;
4830 : Real64 TERM;
4831 :
4832 180900 : ErrorCode = 0;
4833 180900 : IBessFunc = 1.0;
4834 180900 : if (BessFuncArg == 0.0 && BessFuncOrd == 0) {
4835 0 : return;
4836 : }
4837 :
4838 180900 : if (BessFuncOrd < 0) {
4839 0 : ErrorCode = 1;
4840 0 : return;
4841 180900 : } else if (BessFuncArg < 0.0) {
4842 0 : ErrorCode = 2;
4843 0 : return;
4844 180900 : } else if (BessFuncArg > 12.0 && BessFuncArg > BessFuncOrd) {
4845 0 : if (BessFuncArg > 90.0) {
4846 0 : ErrorCode = 4;
4847 0 : IBessFunc = 1.0e30;
4848 0 : return;
4849 : }
4850 0 : TERM = 1.0;
4851 0 : IBessFunc = 1.0;
4852 0 : for (LoopCount = 1; LoopCount <= 30; ++LoopCount) { // Start of 1st LoopCount Loop
4853 0 : if (std::abs(TERM) <= std::abs(ErrorTol * IBessFunc)) {
4854 0 : IBessFunc *= std::exp(BessFuncArg) / std::sqrt(2.0 * Constant::Pi * BessFuncArg);
4855 0 : return;
4856 : }
4857 0 : TERM *= 0.125 / BessFuncArg * (pow_2(2 * LoopCount - 1) - 4 * BessFuncOrd * BessFuncOrd) / double(LoopCount);
4858 0 : IBessFunc += TERM;
4859 : } // End of 1st LoopCount loop
4860 : }
4861 :
4862 180900 : TERM = 1.0;
4863 180900 : if (BessFuncOrd > 0) {
4864 241200 : for (LoopCount = 1; LoopCount <= BessFuncOrd; ++LoopCount) { // Start of 2nd LoopCount Loop
4865 120600 : FI = LoopCount;
4866 120600 : if (std::abs(TERM) < 1.0e-30 * FI / (BessFuncArg * 2.0)) {
4867 0 : ErrorCode = 3;
4868 0 : IBessFunc = 0.0;
4869 0 : return;
4870 : }
4871 120600 : TERM *= BessFuncArg / (2.0 * FI);
4872 : } // End of 2nd LoopCount loop
4873 : }
4874 :
4875 180900 : IBessFunc = TERM;
4876 1132140 : for (LoopCount = 1; LoopCount <= 1000; ++LoopCount) { // Start of 3rd LoopCount Loop
4877 1132140 : if (std::abs(TERM) <= std::abs(IBessFunc * ErrorTol)) {
4878 180900 : return;
4879 : }
4880 951240 : FK = LoopCount * (BessFuncOrd + LoopCount);
4881 951240 : TERM *= pow_2(BessFuncArg) / (4.0 * FK);
4882 951240 : IBessFunc += TERM;
4883 : } // End of 3rd LoopCount loop
4884 : }
4885 :
4886 180900 : void CalcKBesselFunc(Real64 const BessFuncArg, int const BessFuncOrd, Real64 &KBessFunc, int &ErrorCode)
4887 : {
4888 : // SUBROUTINE INFORMATION:
4889 : // AUTHOR Unknown
4890 : // DATE WRITTEN Unknown
4891 : // DATE REWRITTEN April 1997 by Russell D. Taylor, Ph.D.
4892 : // MODIFIED
4893 : // RE-ENGINEERED
4894 :
4895 : // PURPOSE OF THIS SUBROUTINE:
4896 : // To calculate the K Bessel Function for a given argument and
4897 : // order
4898 : // BessFuncArg THE ARGUMENT OF THE K BESSEL FUNCTION DESIRED
4899 : // BessFuncOrd THE ORDER OF THE K BESSEL FUNCTION DESIRED
4900 : // KBessFunc THE RESULTANT K BESSEL FUNCTION
4901 : // ErrorCode RESULTANT ERROR CODE:
4902 : // ErrorCode=0 NO ERROR
4903 : // ErrorCode=1 BessFuncOrd IS NEGATIVE
4904 : // ErrorCode=2 BessFuncArg IS ZERO OR NEGATIVE
4905 : // ErrorCode=3 BessFuncArg .GT. 85, KBessFunc .LT. 10**-38; KBessFunc SET TO 0.
4906 : // ErrorCode=4 KBessFunc .GT. 10**38; KBessFunc SET TO 10**38
4907 : // NOTE: BessFuncOrd MUST BE GREATER THAN OR EQUAL TO ZERO
4908 : // METHOD:
4909 : // COMPUTES ZERO ORDER AND FIRST ORDER BESSEL FUNCTIONS USING
4910 : // SERIES APPROXIMATIONS AND THEN COMPUTES BessFuncOrd TH ORDER FUNCTION
4911 : // USING RECURRENCE RELATION.
4912 : // RECURRENCE RELATION AND POLYNOMIAL APPROXIMATION TECHNIQUE
4913 : // AS DESCRIBED BY A.J.M. HITCHCOCK, 'POLYNOMIAL APPROXIMATIONS
4914 : // TO BESSEL FUNCTIONS OF ORDER ZERO AND ONE AND TO RELATED
4915 : // FUNCTIONS,' M.T.A.C., V.11, 1957, PP. 86-88, AND G.BessFuncOrd. WATSON,
4916 : // 'A TREATISE ON THE THEORY OF BESSEL FUNCTIONS,' CAMBRIDGE
4917 : // UNIVERSITY PRESS, 1958, P.62
4918 :
4919 : // USE STATEMENTS:
4920 : // na
4921 :
4922 : // Locals
4923 : // SUBROUTINE ARGUMENT DEFINITIONS:
4924 :
4925 : // SUBROUTINE PARAMETER DEFINITIONS:
4926 180900 : Real64 constexpr GJMAX(1.0e+38);
4927 :
4928 : // INTERFACE BLOCK SPECIFICATIONS
4929 : // na
4930 :
4931 : // DERIVED TYPE DEFINITIONS
4932 : // na
4933 :
4934 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4935 : int LoopCount;
4936 : bool StopLoop;
4937 :
4938 : Real64 FACT;
4939 : Real64 G0;
4940 : Real64 G1;
4941 : Real64 GJ;
4942 : Real64 HJ;
4943 180900 : Array1D<Real64> T(12);
4944 : Real64 X2J;
4945 :
4946 180900 : KBessFunc = 0.0;
4947 180900 : G0 = 0.0;
4948 180900 : GJ = 0.0;
4949 :
4950 180900 : if (BessFuncOrd < 0.0) {
4951 0 : ErrorCode = 1;
4952 0 : return;
4953 180900 : } else if (BessFuncArg <= 0.0) {
4954 0 : ErrorCode = 2;
4955 0 : return;
4956 180900 : } else if (BessFuncArg > 85.0) {
4957 0 : ErrorCode = 3;
4958 0 : KBessFunc = 0.0;
4959 0 : return;
4960 : }
4961 :
4962 180900 : ErrorCode = 0;
4963 :
4964 : // Use polynomial approximation if BessFuncArg > 1.
4965 :
4966 180900 : if (BessFuncArg > 1.0) {
4967 112439 : T(1) = 1.0 / BessFuncArg;
4968 1349268 : for (LoopCount = 2; LoopCount <= 12; ++LoopCount) {
4969 1236829 : T(LoopCount) = T(LoopCount - 1) / BessFuncArg;
4970 : } // End of LoopCount Loop
4971 112439 : if (BessFuncOrd != 1) {
4972 :
4973 : // Compute K0 using polynomial approximation
4974 :
4975 65322 : G0 = std::exp(-BessFuncArg) *
4976 32661 : (1.2533141 - 0.1566642 * T(1) + 0.08811128 * T(2) - 0.09139095 * T(3) + 0.1344596 * T(4) - 0.2299850 * T(5) + 0.3792410 * T(6) -
4977 32661 : 0.5247277 * T(7) + 0.5575368 * T(8) - 0.4262633 * T(9) + 0.2184518 * T(10) - 0.06680977 * T(11) + 0.009189383 * T(12)) *
4978 32661 : std::sqrt(1.0 / BessFuncArg);
4979 32661 : if (BessFuncOrd == 0) {
4980 32661 : KBessFunc = G0;
4981 32661 : return;
4982 : }
4983 : }
4984 :
4985 : // Compute K1 using polynomial approximation
4986 :
4987 159556 : G1 = std::exp(-BessFuncArg) *
4988 79778 : (1.2533141 + 0.4699927 * T(1) - 0.1468583 * T(2) + 0.1280427 * T(3) - 0.1736432 * T(4) + 0.2847618 * T(5) - 0.4594342 * T(6) +
4989 79778 : 0.6283381 * T(7) - 0.6632295 * T(8) + 0.5050239 * T(9) - 0.2581304 * T(10) + 0.07880001 * T(11) - 0.01082418 * T(12)) *
4990 79778 : std::sqrt(1.0 / BessFuncArg);
4991 79778 : if (BessFuncOrd == 1) {
4992 79778 : KBessFunc = G1;
4993 79778 : return;
4994 : }
4995 : } else {
4996 :
4997 : // Use series expansion if BessFuncArg <= 1.
4998 :
4999 68461 : if (BessFuncOrd != 1) {
5000 :
5001 : // Compute K0 using series expansion
5002 :
5003 27639 : G0 = -(0.5772157 + std::log(BessFuncArg / 2.0));
5004 27639 : X2J = 1.0;
5005 27639 : FACT = 1.0;
5006 27639 : HJ = 0.0;
5007 193473 : for (LoopCount = 1; LoopCount <= 6; ++LoopCount) {
5008 165834 : X2J *= pow_2(BessFuncArg) / 4.0;
5009 165834 : FACT *= pow_2(1.0 / double(LoopCount));
5010 165834 : HJ += 1.0 / double(LoopCount);
5011 165834 : G0 += X2J * FACT * (HJ - (0.5772157 + std::log(BessFuncArg / 2.0)));
5012 : } // End of LoopCount Loop
5013 27639 : if (BessFuncOrd == 0.0) {
5014 27639 : KBessFunc = G0;
5015 27639 : return;
5016 : }
5017 : }
5018 :
5019 : // Compute K1 using series expansion
5020 :
5021 40822 : X2J = BessFuncArg / 2.0;
5022 40822 : FACT = 1.0;
5023 40822 : HJ = 1.0;
5024 40822 : G1 = 1.0 / BessFuncArg + X2J * (0.5 + (0.5772157 + std::log(BessFuncArg / 2.0)) - HJ);
5025 326576 : for (LoopCount = 2; LoopCount <= 8; ++LoopCount) {
5026 285754 : X2J *= pow_2(BessFuncArg) / 4.0;
5027 285754 : FACT *= pow_2(1.0 / double(LoopCount));
5028 285754 : HJ += 1.0 / double(LoopCount);
5029 285754 : G1 += X2J * FACT * (0.5 + ((0.5772157 + std::log(BessFuncArg / 2.0)) - HJ) * double(LoopCount));
5030 : } // End of LoopCount Loop
5031 40822 : if (BessFuncOrd == 1) {
5032 40822 : KBessFunc = G1;
5033 40822 : return;
5034 : }
5035 : }
5036 :
5037 : // From K0 and K1 compute KN using recurrence relation
5038 :
5039 0 : LoopCount = 2;
5040 0 : StopLoop = false;
5041 0 : while (LoopCount <= BessFuncOrd && !StopLoop) {
5042 0 : GJ = 2.0 * (double(LoopCount) - 1.0) * G1 / BessFuncArg + G0;
5043 0 : if (GJ - GJMAX > 0.0) {
5044 0 : ErrorCode = 4;
5045 0 : GJ = GJMAX;
5046 0 : StopLoop = true;
5047 : } else {
5048 0 : G0 = G1;
5049 0 : G1 = GJ;
5050 0 : ++LoopCount;
5051 : }
5052 : } // End of LoopCount Loop
5053 0 : KBessFunc = GJ;
5054 180900 : }
5055 :
5056 1005 : void CalcPolynomCoef(EnergyPlusData &state, Array2<Real64> const &OrderedPair, Array1D<Real64> &PolynomCoef)
5057 : {
5058 : // SUBROUTINE INFORMATION:
5059 : // AUTHOR Unknown
5060 : // DATE WRITTEN Unknown
5061 : // DATE REWRITTEN April 1997 by Russell D. Taylor, Ph.D.
5062 : // MODIFIED
5063 : // RE-ENGINEERED
5064 :
5065 : // PURPOSE OF THIS SUBROUTINE:
5066 : // Fits polynomial of order from 1 to MaxPolynomOrder to the
5067 : // ordered pairs of data points X,Y
5068 :
5069 : // USE STATEMENTS:
5070 : // na
5071 :
5072 : // Locals
5073 : // SUBROUTINE ARGUMENT DEFINITIONS:
5074 :
5075 : // SUBROUTINE PARAMETER DEFINITIONS:
5076 : // na
5077 :
5078 : // INTERFACE BLOCK SPECIFICATIONS
5079 : // na
5080 :
5081 : // DERIVED TYPE DEFINITIONS
5082 : // na
5083 :
5084 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5085 : bool Converged;
5086 : Real64 B;
5087 : int I;
5088 : int II;
5089 : int J;
5090 : int PolynomOrder;
5091 : int CurrentOrder;
5092 : int CurrentOrdPair;
5093 : Real64 S1;
5094 : Real64 S2;
5095 :
5096 1005 : auto &OrdPairSum = state.dataWaterCoils->OrdPairSum;
5097 :
5098 1005 : OrdPairSum = 0.0;
5099 1005 : OrdPairSum(1, 1) = WaterCoils::MaxOrderedPairs;
5100 1005 : PolynomCoef = 0.0;
5101 61305 : for (CurrentOrdPair = 1; CurrentOrdPair <= WaterCoils::MaxOrderedPairs; ++CurrentOrdPair) {
5102 60300 : OrdPairSum(2, 1) += OrderedPair(CurrentOrdPair, 1);
5103 60300 : OrdPairSum(3, 1) += OrderedPair(CurrentOrdPair, 1) * OrderedPair(CurrentOrdPair, 1);
5104 60300 : OrdPairSum(1, 2) += OrderedPair(CurrentOrdPair, 2);
5105 60300 : OrdPairSum(2, 2) += OrderedPair(CurrentOrdPair, 1) * OrderedPair(CurrentOrdPair, 2);
5106 : }
5107 1005 : PolynomOrder = 1;
5108 1005 : Converged = false;
5109 5025 : while (!Converged) {
5110 18090 : for (CurrentOrder = 1; CurrentOrder <= PolynomOrder + 1; ++CurrentOrder) {
5111 68340 : for (J = 1; J <= PolynomOrder + 1; ++J) {
5112 54270 : state.dataWaterCoils->OrdPairSumMatrix(J, CurrentOrder) = OrdPairSum(J - 1 + CurrentOrder, 1);
5113 : } // End of J loop
5114 14070 : state.dataWaterCoils->OrdPairSumMatrix(PolynomOrder + 2, CurrentOrder) = OrdPairSum(CurrentOrder, 2);
5115 : } // End of CurrentOrder loop
5116 :
5117 18090 : for (CurrentOrder = 1; CurrentOrder <= PolynomOrder + 1; ++CurrentOrder) {
5118 14070 : state.dataWaterCoils->OrdPairSumMatrix(CurrentOrder, PolynomOrder + 2) = -1.0;
5119 48240 : for (J = CurrentOrder + 1; J <= PolynomOrder + 2; ++J) {
5120 34170 : state.dataWaterCoils->OrdPairSumMatrix(J, PolynomOrder + 2) = 0.0;
5121 : } // End of J loop
5122 :
5123 68340 : for (II = 2; II <= PolynomOrder + 2; ++II) {
5124 193965 : for (J = CurrentOrder + 1; J <= PolynomOrder + 2; ++J) {
5125 279390 : state.dataWaterCoils->OrdPairSumMatrix(J, II) -= state.dataWaterCoils->OrdPairSumMatrix(J, 1) *
5126 139695 : state.dataWaterCoils->OrdPairSumMatrix(CurrentOrder, II) /
5127 139695 : state.dataWaterCoils->OrdPairSumMatrix(CurrentOrder, 1);
5128 : } // End of J loop
5129 : } // End of II loop
5130 68340 : for (II = 1; II <= PolynomOrder + 1; ++II) {
5131 193965 : for (J = CurrentOrder + 1; J <= PolynomOrder + 2; ++J) {
5132 139695 : state.dataWaterCoils->OrdPairSumMatrix(J, II) = state.dataWaterCoils->OrdPairSumMatrix(J, II + 1);
5133 : } // End of J loop
5134 : } // End of II loop
5135 : } // End of CurrentOrder loop
5136 :
5137 4020 : S2 = 0.0;
5138 245220 : for (CurrentOrdPair = 1; CurrentOrdPair <= WaterCoils::MaxOrderedPairs; ++CurrentOrdPair) {
5139 241200 : S1 = state.dataWaterCoils->OrdPairSumMatrix(PolynomOrder + 2, 1);
5140 241200 : auto const OrderedPair1C = OrderedPair(CurrentOrdPair, 1); // (AUTO_OK_OBJ)
5141 241200 : Real64 OrderedPair1C_pow = 1.0;
5142 844200 : for (CurrentOrder = 1; CurrentOrder <= PolynomOrder; ++CurrentOrder) {
5143 603000 : OrderedPair1C_pow *= OrderedPair1C;
5144 603000 : S1 += state.dataWaterCoils->OrdPairSumMatrix(PolynomOrder + 2, CurrentOrder + 1) * OrderedPair1C_pow;
5145 : } // End of CurrentOrder loop
5146 241200 : S2 += (S1 - OrderedPair(CurrentOrdPair, 2)) * (S1 - OrderedPair(CurrentOrdPair, 2));
5147 : } // End of CurrentOrdPair loop
5148 4020 : B = WaterCoils::MaxOrderedPairs - (PolynomOrder + 1);
5149 4020 : if (S2 > 0.0001) {
5150 3029 : S2 = std::sqrt(S2 / B);
5151 : }
5152 18090 : for (CurrentOrder = 1; CurrentOrder <= PolynomOrder + 1; ++CurrentOrder) {
5153 14070 : PolynomCoef(CurrentOrder) = state.dataWaterCoils->OrdPairSumMatrix(PolynomOrder + 2, CurrentOrder);
5154 : } // End of CurrentOrder loop
5155 :
5156 4020 : if ((PolynomOrder - WaterCoils::MaxPolynomOrder < 0) && (S2 - WaterCoils::PolyConvgTol > 0.0)) {
5157 3015 : ++PolynomOrder;
5158 3015 : J = 2 * PolynomOrder;
5159 3015 : OrdPairSum(J, 1) = OrdPairSum(J + 1, 1) = 0.0;
5160 3015 : auto OrdPairSum2P = OrdPairSum(PolynomOrder + 1, 2) = 0.0; // (AUTO_OK_OBJ)
5161 183915 : for (I = 1; I <= WaterCoils::MaxOrderedPairs; ++I) {
5162 180900 : auto const OrderedPair1I = OrderedPair(I, 1); // (AUTO_OK_OBJ)
5163 180900 : Real64 OrderedPair_pow = std::pow(OrderedPair1I, J - 1);
5164 180900 : OrdPairSum(J, 1) += OrderedPair_pow;
5165 180900 : OrderedPair_pow *= OrderedPair1I;
5166 180900 : OrdPairSum(J + 1, 1) += OrderedPair_pow;
5167 180900 : OrdPairSum2P += OrderedPair(I, 2) * std::pow(OrderedPair1I, PolynomOrder);
5168 : }
5169 3015 : OrdPairSum(PolynomOrder + 1, 2) = OrdPairSum2P;
5170 3015 : } else {
5171 1005 : Converged = true;
5172 : }
5173 : }
5174 1005 : }
5175 :
5176 : // Iterate Routine for Cooling Coil
5177 :
5178 4052106 : void CoilAreaFracIter(Real64 &NewSurfAreaWetFrac, // Out Value of variable
5179 : Real64 const SurfAreaFracCurrent, // Driver Value
5180 : Real64 const ErrorCurrent, // Objective Function
5181 : Real64 &SurfAreaFracPrevious, // First Previous value of Surf Area Fraction
5182 : Real64 &ErrorPrevious, // First Previous value of error
5183 : Real64 &SurfAreaFracLast, // Second Previous value of Surf Area Fraction
5184 : Real64 &ErrorLast, // Second Previous value of error
5185 : int const IterNum, // Number of Iterations
5186 : int &icvg // Iteration convergence flag
5187 : )
5188 : {
5189 : // FUNCTION INFORMATION:
5190 : // AUTHOR Rahul Chillar
5191 : // DATE WRITTEN June 2004
5192 :
5193 : // PURPOSE OF THIS FUNCTION:
5194 : // Iterately solves for the value of SurfAreaWetFraction for the Cooling Coil.
5195 :
5196 : // METHODOLOGY EMPLOYED:
5197 : // First function generates 2 sets of guess points by perturbation and subsequently
5198 : // by Linear Fit and using the generated points calculates coeffecients for Quadratic
5199 : // fit to predict the next value of surface area wet fraction.
5200 :
5201 : // REFERENCES:
5202 : // ME 423 Design of Thermal Systems Class Notes.UIUC. W.F.Stoecker
5203 :
5204 : // FUNCTION PARAMETER DEFINITIONS:
5205 4052106 : Real64 constexpr Tolerance(1.e-5); // Relative error tolerance
5206 4052106 : Real64 constexpr PerturbSurfAreaFrac(0.1); // Perturbation applied to Surf Fraction to initialize iteration
5207 4052106 : Real64 constexpr SmallNum(1.e-9); // Small Number
5208 :
5209 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
5210 : Real64 check; // Validity Check for moving to Quad Solution
5211 : Real64 QuadCoefThree; // Term under radical in quadratic solution
5212 : Real64 QuadCoefOne; // Term under radical in quadratic solution
5213 : Real64 QuadCoefTwo; // Term under radical in quadratic solution
5214 : Real64 Slope; // Slope for linear fit
5215 : Real64 SurfAreaFracOther; // Intermediate Value of Surf Area
5216 : int mode; // Linear/ perturbation option
5217 :
5218 : // Convergence Check by comparing previous and current value of surf area fraction
5219 4052106 : if ((std::abs(SurfAreaFracCurrent - SurfAreaFracPrevious) < Tolerance * max(std::abs(SurfAreaFracCurrent), SmallNum) && IterNum != 1) ||
5220 : ErrorCurrent == 0.0) {
5221 : // Setting value for surface area fraction for coil
5222 709695 : NewSurfAreaWetFrac = SurfAreaFracCurrent;
5223 709695 : icvg = 1; // Convergance Flag
5224 709695 : return;
5225 : }
5226 :
5227 : // If Icvg = 0 , it has not converged.By perturbation for getting second set of
5228 : // data (mode=1), Getting Third set of data by performing a linear fit(Mode=2).
5229 : // Now using the above 3 points generated by perturbation and Linear Fit to perform
5230 : // a quadratic fit.This will happen after second iteration only.
5231 3342411 : icvg = 0; // Convergance flag = false
5232 : // For First Iteration Start with perturbation, For second iteration start with linear fit
5233 : // from the previous two values
5234 3342411 : mode = IterNum;
5235 :
5236 41988 : Label10:;
5237 3384399 : if (mode == 1) {
5238 :
5239 : // FirstGuess Set of Points provided by perturbation
5240 709695 : if (std::abs(SurfAreaFracCurrent) > SmallNum) {
5241 709695 : NewSurfAreaWetFrac = SurfAreaFracCurrent * (1.0 + PerturbSurfAreaFrac);
5242 : } else {
5243 0 : NewSurfAreaWetFrac = PerturbSurfAreaFrac;
5244 : }
5245 :
5246 : // Second set of values being calculated from the first set of values (incoming & perturb)
5247 2674704 : } else if (mode == 2) {
5248 :
5249 : // Calculating Slope for interpolating to the New Point (Simple Linear Extrapolation)
5250 751683 : Slope = (ErrorPrevious - ErrorCurrent) / (SurfAreaFracPrevious - SurfAreaFracCurrent);
5251 : // Error Check for value or Slope
5252 751683 : if (Slope == 0.0) {
5253 0 : mode = 1; // Go back to Perturbation
5254 0 : goto Label10;
5255 : }
5256 : // Guessing New Value for Surface Area Fraction
5257 751683 : NewSurfAreaWetFrac = SurfAreaFracCurrent - ErrorCurrent / Slope;
5258 : } else {
5259 :
5260 : // Check for Quadratic Fit possible here ,Previous value of surf area fraction
5261 : // equals current value then Try linear fit for another point.
5262 1923021 : if (SurfAreaFracCurrent == SurfAreaFracPrevious) {
5263 : // Assign Value of previous point to Last Variable for storing
5264 : // Go back and calculate new value for Previous.
5265 0 : SurfAreaFracPrevious = SurfAreaFracLast;
5266 0 : ErrorPrevious = ErrorLast;
5267 0 : mode = 2;
5268 0 : goto Label10;
5269 1923021 : } else if (SurfAreaFracCurrent == SurfAreaFracLast) {
5270 : // Calculate another value using Linear Fit.
5271 25727 : mode = 2;
5272 25727 : goto Label10;
5273 : }
5274 :
5275 : // Now We have enough previous points to calculate coefficients and
5276 : // perform a quadratic fit for new guess value of surface area fraction
5277 :
5278 : // Calculating First Coefficients for Quadratic Curve Fit
5279 1897294 : QuadCoefThree = ((ErrorLast - ErrorCurrent) / (SurfAreaFracLast - SurfAreaFracCurrent) -
5280 1897294 : (ErrorPrevious - ErrorCurrent) / (SurfAreaFracPrevious - SurfAreaFracCurrent)) /
5281 1897294 : (SurfAreaFracLast - SurfAreaFracPrevious);
5282 : // Calculating Second Coefficients for Quadratic Curve Fit
5283 1897294 : QuadCoefTwo = (ErrorPrevious - ErrorCurrent) / (SurfAreaFracPrevious - SurfAreaFracCurrent) -
5284 1897294 : (SurfAreaFracPrevious + SurfAreaFracCurrent) * QuadCoefThree;
5285 :
5286 : // Calculating Third Coefficients for Quadratic Curve Fit
5287 1897294 : QuadCoefOne = ErrorCurrent - (QuadCoefTwo + QuadCoefThree * SurfAreaFracCurrent) * SurfAreaFracCurrent;
5288 :
5289 : // Check for validity of coefficients , if not REAL(r64) ,Then fit is linear
5290 1897294 : if (std::abs(QuadCoefThree) < 1.E-10) {
5291 0 : mode = 2; // going to Linear mode, due to colinear points.
5292 0 : goto Label10;
5293 : }
5294 :
5295 : // If value of Quadratic coefficients not suitable enought due to round off errors
5296 : // to predict new point go to linear fit and acertain new values for the coefficients.
5297 1897294 : if (std::abs((QuadCoefOne + (QuadCoefTwo + QuadCoefThree * SurfAreaFracPrevious) * SurfAreaFracPrevious - ErrorPrevious) / ErrorPrevious) >
5298 : 1.E-4) {
5299 3 : mode = 2; // go to linear mode
5300 3 : goto Label10;
5301 : }
5302 :
5303 : // Validity Check for Imaginary roots, In this case go back to linear fit.
5304 1897291 : check = pow_2(QuadCoefTwo) - 4.0 * QuadCoefOne * QuadCoefThree;
5305 : // Imaginary Root Exist
5306 1897291 : if (check < 0) {
5307 16258 : mode = 2;
5308 16258 : goto Label10;
5309 1881033 : } else if (check > 0) {
5310 : // real unequal roots exist, Determine the roots nearest to most recent guess
5311 1881016 : NewSurfAreaWetFrac = (-QuadCoefTwo + std::sqrt(check)) / QuadCoefThree / 2.0;
5312 1881016 : SurfAreaFracOther = -NewSurfAreaWetFrac - QuadCoefTwo / QuadCoefThree;
5313 : // Assigning value to Surface Area Fraction with recent
5314 1881016 : if (std::abs(NewSurfAreaWetFrac - SurfAreaFracCurrent) > std::abs(SurfAreaFracOther - SurfAreaFracCurrent)) {
5315 3279 : NewSurfAreaWetFrac = SurfAreaFracOther;
5316 : }
5317 : } else {
5318 : // The roots are real, one solution exists.
5319 17 : NewSurfAreaWetFrac = -QuadCoefTwo / QuadCoefThree / 2;
5320 : }
5321 : }
5322 :
5323 3342411 : if (mode < 3) {
5324 : // No valid previous points to eliminate, since it just has 2 points.
5325 : // Loading previous values into last
5326 1461378 : SurfAreaFracLast = SurfAreaFracPrevious;
5327 1461378 : ErrorLast = ErrorPrevious;
5328 : // Loading Current Values into previous
5329 1461378 : SurfAreaFracPrevious = SurfAreaFracCurrent;
5330 1461378 : ErrorPrevious = ErrorCurrent;
5331 : } else {
5332 :
5333 : // Elimination the most distance previous point from the answer based on sign and
5334 : // magnitute of the error. Keeping Current Point
5335 1881033 : if (ErrorPrevious * ErrorCurrent > 0 && ErrorLast * ErrorCurrent > 0) {
5336 : // If sign are same , simply eliminate the one with biggest error value.
5337 333858 : if (std::abs(ErrorLast) > std::abs(ErrorPrevious)) {
5338 : // Eliminating Last Value
5339 97898 : SurfAreaFracLast = SurfAreaFracPrevious;
5340 97898 : ErrorLast = ErrorPrevious;
5341 : }
5342 : } else {
5343 : // If signs are different eliminate previous error with same sign as current error
5344 1645073 : if (ErrorLast * ErrorCurrent > 0) {
5345 : // Previous Loaded to Last
5346 516297 : SurfAreaFracLast = SurfAreaFracPrevious;
5347 516297 : ErrorLast = ErrorPrevious;
5348 : }
5349 : }
5350 : // Current Loaded into previous.
5351 1881033 : SurfAreaFracPrevious = SurfAreaFracCurrent;
5352 1881033 : ErrorPrevious = ErrorCurrent;
5353 : }
5354 : }
5355 :
5356 274435 : void CheckWaterCoilSchedule(EnergyPlusData &state, std::string_view CompName, Real64 &Value, int &CompIndex)
5357 : {
5358 :
5359 : // SUBROUTINE INFORMATION:
5360 : // AUTHOR Linda Lawrie
5361 : // DATE WRITTEN October 2005
5362 :
5363 : // Obtains and Allocates WaterCoil related parameters from input file
5364 274435 : if (state.dataWaterCoils->GetWaterCoilsInputFlag) { // First time subroutine has been entered
5365 0 : GetWaterCoilInput(state);
5366 0 : state.dataWaterCoils->GetWaterCoilsInputFlag = false;
5367 : }
5368 :
5369 274435 : int CoilNum = 0;
5370 : // Find the correct Coil number
5371 274435 : if (CompIndex == 0) {
5372 8 : CoilNum = Util::FindItemInList(CompName, state.dataWaterCoils->WaterCoil);
5373 8 : if (CoilNum == 0) {
5374 0 : ShowFatalError(state, format("CheckWaterCoilSchedule: Coil not found={}", CompName));
5375 : }
5376 8 : CompIndex = CoilNum;
5377 8 : Value = state.dataWaterCoils->WaterCoil(CoilNum).availSched->getCurrentVal(); // not scheduled?
5378 : } else {
5379 274427 : CoilNum = CompIndex;
5380 274427 : if (CoilNum > state.dataWaterCoils->NumWaterCoils || CoilNum < 1) {
5381 0 : ShowFatalError(state,
5382 0 : format("CheckWaterCoilSchedule: Invalid CompIndex passed={}, Number of Heating Coils={}, Coil name={}",
5383 : CoilNum,
5384 0 : state.dataWaterCoils->NumWaterCoils,
5385 : CompName));
5386 : }
5387 274427 : auto const &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
5388 274427 : if (CompName != waterCoil.Name) {
5389 0 : ShowFatalError(state,
5390 0 : format("CheckWaterCoilSchedule: Invalid CompIndex passed={}, Coil name={}, stored Coil Name for that index={}",
5391 : CoilNum,
5392 : CompName,
5393 0 : waterCoil.Name));
5394 : }
5395 274427 : Value = waterCoil.availSched->getCurrentVal(); // not scheduled?
5396 : }
5397 274435 : }
5398 :
5399 167 : Real64 GetCoilMaxWaterFlowRate(EnergyPlusData &state,
5400 : std::string_view CoilType, // must match coil types in this module
5401 : std::string const &CoilName, // must match coil names for the coil type
5402 : bool &ErrorsFound // set to true if problem
5403 : )
5404 : {
5405 :
5406 : // FUNCTION INFORMATION:
5407 : // AUTHOR Linda Lawrie
5408 : // DATE WRITTEN November 2006
5409 :
5410 : // PURPOSE OF THIS FUNCTION:
5411 : // This function looks up the max water flow rate for the given coil and returns it. If
5412 : // incorrect coil type or name is given, ErrorsFound is returned as true and capacity is returned
5413 : // as negative.
5414 :
5415 : // Return value
5416 : Real64 MaxWaterFlowRate; // returned max water flow rate of matched coil
5417 :
5418 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
5419 :
5420 : // Obtains and Allocates WaterCoil related parameters from input file
5421 167 : if (state.dataWaterCoils->GetWaterCoilsInputFlag) { // First time subroutine has been entered
5422 2 : GetWaterCoilInput(state);
5423 2 : state.dataWaterCoils->GetWaterCoilsInputFlag = false;
5424 : }
5425 :
5426 167 : int WhichCoil = 0;
5427 253 : if (Util::SameString(CoilType, "Coil:Heating:Water") || Util::SameString(CoilType, "Coil:Cooling:Water:DetailedGeometry") ||
5428 253 : Util::SameString(CoilType, "Coil:Cooling:Water")) {
5429 167 : WhichCoil = Util::FindItem(CoilName, state.dataWaterCoils->WaterCoil);
5430 167 : if (WhichCoil != 0) {
5431 : // coil does not specify MaxWaterFlowRate
5432 167 : MaxWaterFlowRate = state.dataWaterCoils->WaterCoil(WhichCoil).MaxWaterVolFlowRate;
5433 : }
5434 : } else {
5435 0 : WhichCoil = 0;
5436 : }
5437 :
5438 167 : if (WhichCoil == 0) {
5439 0 : ShowSevereError(state, format("GetCoilMaxWaterFlowRate: Could not find Coil, Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
5440 0 : ShowContinueError(state, "... Max Water Flow rate returned as -1000.");
5441 0 : ErrorsFound = true;
5442 0 : MaxWaterFlowRate = -1000.0;
5443 : }
5444 :
5445 167 : return MaxWaterFlowRate;
5446 : }
5447 :
5448 24 : int GetCoilInletNode(EnergyPlusData &state,
5449 : std::string_view CoilType, // must match coil types in this module
5450 : std::string const &CoilName, // must match coil names for the coil type
5451 : bool &ErrorsFound // set to true if problem
5452 : )
5453 : {
5454 :
5455 : // FUNCTION INFORMATION:
5456 : // AUTHOR R. Raustad
5457 : // DATE WRITTEN March 2007
5458 :
5459 : // PURPOSE OF THIS FUNCTION:
5460 : // This function looks up the given coil and returns the inlet node number. If
5461 : // incorrect coil type or name is given, ErrorsFound is returned as true and node number is returned
5462 : // as zero.
5463 :
5464 : // Obtains and Allocates DXCoils
5465 24 : if (state.dataWaterCoils->GetWaterCoilsInputFlag) {
5466 0 : GetWaterCoilInput(state);
5467 0 : state.dataWaterCoils->GetWaterCoilsInputFlag = false;
5468 : }
5469 :
5470 24 : int NodeNumber = 0;
5471 24 : int WhichCoil = 0;
5472 33 : if (Util::SameString(CoilType, "Coil:Heating:Water") || Util::SameString(CoilType, "Coil:Cooling:Water:DetailedGeometry") ||
5473 33 : Util::SameString(CoilType, "Coil:Cooling:Water")) {
5474 24 : WhichCoil = Util::FindItem(CoilName, state.dataWaterCoils->WaterCoil);
5475 24 : if (WhichCoil != 0) {
5476 24 : NodeNumber = state.dataWaterCoils->WaterCoil(WhichCoil).AirInletNodeNum;
5477 : }
5478 : } else {
5479 0 : WhichCoil = 0;
5480 : }
5481 :
5482 24 : if (WhichCoil == 0) {
5483 0 : ShowSevereError(state, format("GetCoilInletNode: Could not find Coil, Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
5484 0 : ErrorsFound = true;
5485 0 : NodeNumber = 0;
5486 : }
5487 :
5488 24 : return NodeNumber;
5489 : }
5490 :
5491 30 : int GetCoilOutletNode(EnergyPlusData &state,
5492 : std::string_view CoilType, // must match coil types in this module
5493 : std::string const &CoilName, // must match coil names for the coil type
5494 : bool &ErrorsFound // set to true if problem
5495 : )
5496 : {
5497 :
5498 : // FUNCTION INFORMATION:
5499 : // AUTHOR R. Raustad
5500 : // DATE WRITTEN March 2007
5501 :
5502 : // PURPOSE OF THIS FUNCTION:
5503 : // This function looks up the given coil and returns the inlet node number. If
5504 : // incorrect coil type or name is given, ErrorsFound is returned as true and node number is returned
5505 : // as zero.
5506 :
5507 : // Obtains and Allocates DXCoils
5508 30 : if (state.dataWaterCoils->GetWaterCoilsInputFlag) {
5509 0 : GetWaterCoilInput(state);
5510 0 : state.dataWaterCoils->GetWaterCoilsInputFlag = false;
5511 : }
5512 :
5513 30 : int WhichCoil = 0;
5514 30 : int NodeNumber = 0; // returned node number of matched coil
5515 37 : if (Util::SameString(CoilType, "Coil:Heating:Water") || Util::SameString(CoilType, "Coil:Cooling:Water:DetailedGeometry") ||
5516 37 : Util::SameString(CoilType, "Coil:Cooling:Water")) {
5517 30 : WhichCoil = Util::FindItem(CoilName, state.dataWaterCoils->WaterCoil);
5518 30 : if (WhichCoil != 0) {
5519 30 : NodeNumber = state.dataWaterCoils->WaterCoil(WhichCoil).AirOutletNodeNum;
5520 : }
5521 : } else {
5522 0 : WhichCoil = 0;
5523 : }
5524 :
5525 30 : if (WhichCoil == 0) {
5526 0 : ShowSevereError(
5527 : state,
5528 0 : format("GetCoilOutletNode: Could not find Coil, Type=\"{}\" Name=\"{}\" when accessing coil outlet node number.", CoilType, CoilName));
5529 0 : ErrorsFound = true;
5530 0 : NodeNumber = 0;
5531 : }
5532 :
5533 30 : return NodeNumber;
5534 : }
5535 :
5536 5402 : int GetCoilWaterInletNode(EnergyPlusData &state,
5537 : std::string_view CoilType, // must match coil types in this module
5538 : std::string const &CoilName, // must match coil names for the coil type
5539 : bool &ErrorsFound // set to true if problem
5540 : )
5541 : {
5542 :
5543 : // FUNCTION INFORMATION:
5544 : // AUTHOR R. Raustad
5545 : // DATE WRITTEN July 2007
5546 :
5547 : // PURPOSE OF THIS FUNCTION:
5548 : // This function looks up the given coil and returns the inlet water control node number. If
5549 : // incorrect coil type or name is given, ErrorsFound is returned as true and node number is returned
5550 : // as zero.
5551 :
5552 : // Obtains and Allocates DXCoils
5553 5402 : if (state.dataWaterCoils->GetWaterCoilsInputFlag) {
5554 39 : GetWaterCoilInput(state);
5555 39 : state.dataWaterCoils->GetWaterCoilsInputFlag = false;
5556 : }
5557 :
5558 5402 : int NodeNumber = 0; // returned node number of matched coil
5559 5402 : int WhichCoil = 0;
5560 5838 : if (Util::SameString(CoilType, "Coil:Heating:Water") || Util::SameString(CoilType, "Coil:Cooling:Water:DetailedGeometry") ||
5561 5838 : Util::SameString(CoilType, "Coil:Cooling:Water")) {
5562 5402 : WhichCoil = Util::FindItem(CoilName, state.dataWaterCoils->WaterCoil);
5563 5402 : if (WhichCoil != 0) {
5564 5402 : NodeNumber = state.dataWaterCoils->WaterCoil(WhichCoil).WaterInletNodeNum;
5565 : }
5566 : } else {
5567 0 : WhichCoil = 0;
5568 : }
5569 :
5570 5402 : if (WhichCoil == 0) {
5571 0 : ShowSevereError(state, format("GetCoilWaterInletNode: Could not find Coil, Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
5572 0 : ErrorsFound = true;
5573 0 : NodeNumber = 0;
5574 : }
5575 :
5576 5402 : return NodeNumber;
5577 : }
5578 :
5579 2182 : int GetCoilWaterOutletNode(EnergyPlusData &state,
5580 : std::string_view CoilType, // must match coil types in this module
5581 : std::string const &CoilName, // must match coil names for the coil type
5582 : bool &ErrorsFound // set to true if problem
5583 : )
5584 : {
5585 :
5586 : // FUNCTION INFORMATION:
5587 : // AUTHOR R. Raustad
5588 : // DATE WRITTEN July 2007
5589 :
5590 : // PURPOSE OF THIS FUNCTION:
5591 : // This function looks up the given coil and returns the outlet water node number. If
5592 : // incorrect coil type or name is given, ErrorsFound is returned as true and node number is returned
5593 : // as zero.
5594 :
5595 : // Obtains and Allocates DXCoils
5596 2182 : if (state.dataWaterCoils->GetWaterCoilsInputFlag) {
5597 0 : GetWaterCoilInput(state);
5598 0 : state.dataWaterCoils->GetWaterCoilsInputFlag = false;
5599 : }
5600 :
5601 2182 : int NodeNumber = 0; // returned node number of matched coil
5602 2182 : int WhichCoil = 0;
5603 2279 : if (Util::SameString(CoilType, "Coil:Heating:Water") || Util::SameString(CoilType, "Coil:Cooling:Water:DetailedGeometry") ||
5604 2279 : Util::SameString(CoilType, "Coil:Cooling:Water")) {
5605 2182 : WhichCoil = Util::FindItem(CoilName, state.dataWaterCoils->WaterCoil);
5606 2182 : if (WhichCoil != 0) {
5607 2182 : NodeNumber = state.dataWaterCoils->WaterCoil(WhichCoil).WaterOutletNodeNum;
5608 : }
5609 : } else {
5610 0 : WhichCoil = 0;
5611 : }
5612 :
5613 2182 : if (WhichCoil == 0) {
5614 0 : ShowSevereError(state, format("GetCoilWaterOutletNode: Could not find Coil, Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
5615 0 : ErrorsFound = true;
5616 0 : NodeNumber = 0;
5617 : }
5618 :
5619 2182 : return NodeNumber;
5620 : }
5621 :
5622 3102 : void SetCoilDesFlow(EnergyPlusData &state,
5623 : std::string_view CoilType, // must match coil types in this module
5624 : std::string const &CoilName, // must match coil names for the coil type
5625 : Real64 const CoilDesFlow, // coil volumetric air flow rate [m3/s]
5626 : bool &ErrorsFound // set to true if problem
5627 : )
5628 : {
5629 :
5630 : // SUBROUTINE INFORMATION:
5631 : // AUTHOR Fred Buhl
5632 : // DATE WRITTEN May 2009
5633 :
5634 : // PURPOSE OF THIS SUBROUTINE:
5635 : // This routine is designed to set the design air volume flow rate in the
5636 : // water coil data structure. Some of the coil types do not have this datum as
5637 : // an input parameter and it is needed for calculating capacity for output reporting.
5638 :
5639 3102 : if (state.dataWaterCoils->GetWaterCoilsInputFlag) { // First time subroutine has been entered
5640 11 : GetWaterCoilInput(state);
5641 11 : state.dataWaterCoils->GetWaterCoilsInputFlag = false;
5642 : }
5643 :
5644 3286 : if (Util::SameString(CoilType, "Coil:Heating:Water") || Util::SameString(CoilType, "Coil:Cooling:Water:DetailedGeometry") ||
5645 3286 : Util::SameString(CoilType, "Coil:Cooling:Water")) {
5646 3012 : int WhichCoil = Util::FindItem(CoilName, state.dataWaterCoils->WaterCoil);
5647 3012 : if (WhichCoil != 0) {
5648 3012 : if (state.dataWaterCoils->WaterCoil(WhichCoil).DesAirVolFlowRate <= 0.0) {
5649 3003 : state.dataWaterCoils->WaterCoil(WhichCoil).DesAirVolFlowRate = CoilDesFlow;
5650 : } else {
5651 : // WaterCoil(WhichCoil).DesAirVolFlowRate = CoilDesFlow;
5652 : }
5653 : } else {
5654 0 : ShowSevereError(state, format("GetCoilMaxWaterFlowRate: Could not find Coil, Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
5655 0 : ErrorsFound = true;
5656 : }
5657 : }
5658 3102 : }
5659 :
5660 0 : Real64 GetWaterCoilDesAirFlow(EnergyPlusData &state,
5661 : std::string const &CoilType, // must match coil types in this module
5662 : std::string const &CoilName, // must match coil names for the coil type
5663 : bool &ErrorsFound // set to true if problem
5664 : )
5665 : {
5666 :
5667 : // SUBROUTINE INFORMATION:
5668 : // AUTHOR Fred Buhl
5669 : // DATE WRITTEN May 2009
5670 :
5671 : // PURPOSE OF THIS SUBROUTINE:
5672 : // This routine is designed to set the design air volume flow rate in the
5673 : // water coil data structure. Some of the coil types do not have this datum as
5674 : // an input parameter and it is needed for calculating capacity for output reporting.
5675 :
5676 0 : Real64 CoilDesAirFlow = 0.0;
5677 :
5678 0 : if (state.dataWaterCoils->GetWaterCoilsInputFlag) { // First time subroutine has been entered
5679 0 : GetWaterCoilInput(state);
5680 0 : state.dataWaterCoils->GetWaterCoilsInputFlag = false;
5681 : }
5682 :
5683 0 : if (Util::SameString(CoilType, "Coil:Cooling:Water")) {
5684 0 : int WhichCoil = Util::FindItem(CoilName, state.dataWaterCoils->WaterCoil);
5685 0 : if (WhichCoil != 0) {
5686 0 : CoilDesAirFlow = state.dataWaterCoils->WaterCoil(WhichCoil).DesAirVolFlowRate;
5687 : } else {
5688 0 : ShowSevereError(state, format("GetWaterCoilDesAirFlowRate: Could not find Coil, Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
5689 0 : ErrorsFound = true;
5690 : }
5691 : } else {
5692 0 : ShowSevereError(state, format("GetWaterCoilDesAirFlowRate: Funciton not valid for Coil, Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
5693 0 : ErrorsFound = true;
5694 : }
5695 :
5696 0 : return CoilDesAirFlow;
5697 : }
5698 :
5699 902 : void CheckActuatorNode(EnergyPlusData &state,
5700 : int const ActuatorNodeNum, // input actuator node number
5701 : DataPlant::PlantEquipmentType &WaterCoilType, // Cooling or Heating or 0
5702 : bool &NodeNotFound // true if matching water inlet node not found
5703 : )
5704 : {
5705 :
5706 : // SUBROUTINE INFORMATION:
5707 : // AUTHOR Fred Buhl
5708 : // DATE WRITTEN January 2009
5709 :
5710 : // PURPOSE OF THIS FUNCTION:
5711 : // This subroutine checks that the input actuator node number is matched by
5712 : // the water inlet node number of some water coil
5713 :
5714 : // Obtains and Allocates DXCoils
5715 902 : if (state.dataWaterCoils->GetWaterCoilsInputFlag) {
5716 0 : GetWaterCoilInput(state);
5717 0 : state.dataWaterCoils->GetWaterCoilsInputFlag = false;
5718 : }
5719 :
5720 902 : WaterCoilType = DataPlant::PlantEquipmentType::Invalid;
5721 902 : NodeNotFound = true;
5722 22548 : for (int CoilNum = 1; CoilNum <= state.dataWaterCoils->NumWaterCoils; ++CoilNum) {
5723 22548 : auto const &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
5724 22548 : if (waterCoil.WaterInletNodeNum == ActuatorNodeNum) {
5725 902 : WaterCoilType = waterCoil.WaterCoilType;
5726 902 : NodeNotFound = false;
5727 902 : break;
5728 : }
5729 : }
5730 902 : }
5731 :
5732 902 : void CheckForSensorAndSetPointNode(EnergyPlusData &state,
5733 : int const SensorNodeNum, // controller sensor node number
5734 : HVACControllers::CtrlVarType const ControlledVar, // controlled variable type
5735 : bool &NodeNotFound // true if matching air outlet node not found
5736 : )
5737 : {
5738 :
5739 : // SUBROUTINE INFORMATION:
5740 : // AUTHOR Bereket Nigusse
5741 : // DATE WRITTEN March 2013
5742 :
5743 : // PURPOSE OF THIS SUBROUTINE:
5744 : // This subroutine checks that the sensor node number matches the air outlet node number
5745 : // of some water coils
5746 :
5747 : // SUBROUTINE PARAMETER DEFINITIONS:
5748 : static constexpr std::string_view RoutineName("CheckForSensorAndSetpointNode: ");
5749 :
5750 : // Obtains and Allocates DXCoils
5751 902 : if (state.dataWaterCoils->GetWaterCoilsInputFlag) {
5752 2 : GetWaterCoilInput(state);
5753 2 : state.dataWaterCoils->GetWaterCoilsInputFlag = false;
5754 : }
5755 :
5756 902 : int WhichCoil = 0;
5757 902 : NodeNotFound = true;
5758 :
5759 22548 : for (int CoilNum = 1; CoilNum <= state.dataWaterCoils->NumWaterCoils; ++CoilNum) {
5760 22548 : auto const &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
5761 22548 : if (SensorNodeNum != waterCoil.AirOutletNodeNum) {
5762 21646 : continue;
5763 : }
5764 902 : NodeNotFound = false;
5765 902 : WhichCoil = CoilNum;
5766 902 : break;
5767 : }
5768 : // now if the sensor node is on the water coil air outlet node then check that
5769 : // a setpoint is also specified on the water coil outlet node
5770 902 : if (!NodeNotFound) {
5771 902 : if (WhichCoil > 0) {
5772 902 : bool EMSSetPointErrorFlag = false;
5773 902 : switch (ControlledVar) {
5774 847 : case HVACControllers::CtrlVarType::Temperature: {
5775 847 : EMSManager::CheckIfNodeSetPointManagedByEMS(state, SensorNodeNum, HVAC::CtrlVarType::Temp, EMSSetPointErrorFlag);
5776 847 : state.dataLoopNodes->NodeSetpointCheck(SensorNodeNum).needsSetpointChecking = false;
5777 847 : if (EMSSetPointErrorFlag) {
5778 638 : if (!SetPointManager::NodeHasSPMCtrlVarType(state, SensorNodeNum, HVAC::CtrlVarType::Temp)) {
5779 : std::string_view WaterCoilType =
5780 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(state.dataWaterCoils->WaterCoil(WhichCoil).WaterCoilType)];
5781 0 : ShowWarningError(state, format("{}{}=\"{}\". ", RoutineName, WaterCoilType, state.dataWaterCoils->WaterCoil(WhichCoil).Name));
5782 0 : ShowContinueError(state, " ..Temperature setpoint not found on coil air outlet node.");
5783 0 : ShowContinueError(state,
5784 : " ..The setpoint may have been placed on a node downstream of the coil or on an airloop outlet node.");
5785 0 : ShowContinueError(state, " ..Specify the setpoint and the sensor on the coil air outlet node when possible.");
5786 : }
5787 : }
5788 847 : break;
5789 : }
5790 0 : case HVACControllers::CtrlVarType::HumidityRatio: {
5791 0 : EMSManager::CheckIfNodeSetPointManagedByEMS(state, SensorNodeNum, HVAC::CtrlVarType::MaxHumRat, EMSSetPointErrorFlag);
5792 0 : state.dataLoopNodes->NodeSetpointCheck(SensorNodeNum).needsSetpointChecking = false;
5793 0 : if (EMSSetPointErrorFlag) {
5794 0 : if (!SetPointManager::NodeHasSPMCtrlVarType(state, SensorNodeNum, HVAC::CtrlVarType::MaxHumRat)) {
5795 : std::string_view WaterCoilType =
5796 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(state.dataWaterCoils->WaterCoil(WhichCoil).WaterCoilType)];
5797 0 : ShowWarningError(state, format("{}{}=\"{}\". ", RoutineName, WaterCoilType, state.dataWaterCoils->WaterCoil(WhichCoil).Name));
5798 0 : ShowContinueError(state, " ..Humidity ratio setpoint not found on coil air outlet node.");
5799 0 : ShowContinueError(state,
5800 : " ..The setpoint may have been placed on a node downstream of the coil or on an airloop outlet node.");
5801 0 : ShowContinueError(state, " ..Specify the setpoint and the sensor on the coil air outlet node when possible.");
5802 : }
5803 : }
5804 0 : break;
5805 : }
5806 55 : case HVACControllers::CtrlVarType::TemperatureAndHumidityRatio: {
5807 55 : EMSManager::CheckIfNodeSetPointManagedByEMS(state, SensorNodeNum, HVAC::CtrlVarType::Temp, EMSSetPointErrorFlag);
5808 55 : state.dataLoopNodes->NodeSetpointCheck(SensorNodeNum).needsSetpointChecking = false;
5809 55 : if (EMSSetPointErrorFlag) {
5810 30 : if (!SetPointManager::NodeHasSPMCtrlVarType(state, SensorNodeNum, HVAC::CtrlVarType::Temp)) {
5811 : std::string_view WaterCoilType =
5812 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(state.dataWaterCoils->WaterCoil(WhichCoil).WaterCoilType)];
5813 0 : ShowWarningError(state, format("{}{}=\"{}\". ", RoutineName, WaterCoilType, state.dataWaterCoils->WaterCoil(WhichCoil).Name));
5814 0 : ShowContinueError(state, " ..Temperature setpoint not found on coil air outlet node.");
5815 0 : ShowContinueError(state,
5816 : " ..The setpoint may have been placed on a node downstream of the coil or on an airloop outlet node.");
5817 0 : ShowContinueError(state, " ..Specify the setpoint and the sensor on the coil air outlet node when possible.");
5818 : }
5819 : }
5820 55 : EMSSetPointErrorFlag = false;
5821 55 : EMSManager::CheckIfNodeSetPointManagedByEMS(state, SensorNodeNum, HVAC::CtrlVarType::MaxHumRat, EMSSetPointErrorFlag);
5822 55 : state.dataLoopNodes->NodeSetpointCheck(SensorNodeNum).needsSetpointChecking = false;
5823 55 : if (EMSSetPointErrorFlag) {
5824 30 : if (!SetPointManager::NodeHasSPMCtrlVarType(state, SensorNodeNum, HVAC::CtrlVarType::MaxHumRat)) {
5825 : std::string_view WaterCoilType =
5826 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(state.dataWaterCoils->WaterCoil(WhichCoil).WaterCoilType)];
5827 0 : ShowWarningError(state, format("{}{}=\"{}\". ", RoutineName, WaterCoilType, state.dataWaterCoils->WaterCoil(WhichCoil).Name));
5828 0 : ShowContinueError(state, " ..Humidity ratio setpoint not found on coil air outlet node.");
5829 0 : ShowContinueError(state,
5830 : " ..The setpoint may have been placed on a node downstream of the coil or on an airloop outlet node.");
5831 0 : ShowContinueError(state, " ..Specify the setpoint and the sensor on the coil air outlet node when possible.");
5832 : }
5833 : }
5834 55 : break;
5835 : }
5836 0 : default:
5837 0 : break;
5838 : }
5839 : }
5840 : }
5841 902 : }
5842 :
5843 80 : Real64 TdbFnHRhPb(EnergyPlusData &state,
5844 : Real64 const H, // specific enthalpy {J/kg}
5845 : Real64 const RH, // relative humidity value (0.0-1.0)
5846 : Real64 const PB // barometric pressure {Pascals}
5847 : )
5848 : {
5849 :
5850 : // FUNCTION INFORMATION:
5851 : // AUTHOR Fred Buhl
5852 : // DATE WRITTEN April 1, 2009
5853 :
5854 : // PURPOSE OF THIS FUNCTION:
5855 : // Given the specific enthalpy, relative humidity, and the
5856 : // barometric pressure, the function returns the dry bulb temperature.
5857 :
5858 : // Return value
5859 : Real64 T; // result=> humidity ratio
5860 :
5861 : // Locals
5862 : // FUNCTION ARGUMENT DEFINITIONS:
5863 :
5864 : // FUNCTION PARAMETER DEFINITIONS:
5865 80 : int constexpr MaxIte(500); // Maximum number of iterations
5866 80 : Real64 constexpr Acc(1.0); // Accuracy of result
5867 :
5868 : // INTERFACE BLOCK SPECIFICATIONS
5869 : // na
5870 :
5871 : // DERIVED TYPE DEFINITIONS
5872 : // na
5873 :
5874 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
5875 : int SolFla; // Flag of solver
5876 : Real64 T0; // lower bound for Tprov [C]
5877 : Real64 T1; // upper bound for Tprov [C]
5878 80 : Real64 Tprov(0.0); // provisional value of drybulb temperature [C]
5879 :
5880 80 : T0 = 1.0;
5881 80 : T1 = 50.0;
5882 :
5883 1765 : auto f = [&state, H, RH, PB](Real64 const Tprov) { return H - Psychrometrics::PsyHFnTdbRhPb(state, Tprov, RH, PB); };
5884 :
5885 80 : General::SolveRoot(state, Acc, MaxIte, SolFla, Tprov, f, T0, T1);
5886 : // if the numerical inversion failed, issue error messages.
5887 80 : if (SolFla == -1) {
5888 0 : ShowSevereError(state, "Calculation of drybulb temperature failed in TdbFnHRhPb(H,RH,PB)");
5889 0 : ShowContinueError(state, " Iteration limit exceeded");
5890 0 : ShowContinueError(state, format(" H=[{:.6R}], RH=[{:.4R}], PB=[{:.5R}].", H, RH, PB));
5891 80 : } else if (SolFla == -2) {
5892 0 : ShowSevereError(state, "Calculation of drybulb temperature failed in TdbFnHRhPb(H,RH,PB)");
5893 0 : ShowContinueError(state, " Bad starting values for Tdb");
5894 0 : ShowContinueError(state, format(" H=[{:.6R}], RH=[{:.4R}], PB=[{:.5R}].", H, RH, PB));
5895 : }
5896 80 : if (SolFla < 0) {
5897 0 : T = 0.0;
5898 : } else {
5899 80 : T = Tprov;
5900 : }
5901 :
5902 80 : return T;
5903 : }
5904 :
5905 9085 : Real64 EstimateHEXSurfaceArea(EnergyPlusData &state, int const CoilNum) // coil number, [-]
5906 : {
5907 :
5908 : // FUNCTION INFORMATION:
5909 : // AUTHOR Bereket A Nigusse, FSEC
5910 : // DATE WRITTEN July 2010
5911 :
5912 : // PURPOSE OF THIS FUNCTION:
5913 : // Splits the UA value of a simple coil:cooling:water heat exchanger model into
5914 : // "A" and U" values.
5915 :
5916 : // METHODOLOGY EMPLOYED:
5917 : // A typical design U overall heat transfer coefficient is used to split the "UA" into "A"
5918 : // and "U" values. Currently a constant U value calculated for a typical cooling coil is
5919 : // used. The assumptions used to calculate a typical U value are:
5920 : // (1) tube side water velocity of 2.0 [m/s]
5921 : // (2) inside to outside total surface area ratio (Ai/Ao) = 0.07 [-]
5922 : // (3) fins overall efficiency = 0.92 based on aluminum fin, 12 fins per inch, and
5923 : // fins area to total outside surafce area ratio of about 90%.
5924 : // (4) air side convection coefficient of 140.0 [W/m2C]. Assumes sensible convection
5925 : // of 58.0 [W/m2C] and 82.0 [W/m2C] sensible convection equivalent of the mass
5926 : // transfer coefficient converted using the approximate relation:
5927 : // hequivalent = hmasstransfer/CpAir.
5928 :
5929 : // FUNCTION PARAMETER DEFINITIONS:
5930 9085 : constexpr Real64 OverallFinEfficiency(0.92); // Assumes aluminum fins, 12 fins per inch, fins
5931 : // area of about 90% of external surface area Ao.
5932 :
5933 9085 : constexpr Real64 AreaRatio(0.07); // Heat exchanger Inside to Outside surface area ratio
5934 : // design values range from (Ai/Ao) = 0.06 to 0.08
5935 :
5936 : // Constant value air side heat transfer coefficient is assumed. This coefficient has sensible
5937 : // (58.d0 [W/m2C]) and latent (82.d0 [W/m2C]) heat transfer coefficient components.
5938 9085 : constexpr Real64 hAirTubeOutside(58.0 + 82.0); // Air side heat transfer coefficient [W/m2C]
5939 :
5940 : // Tube side water convection heat transfer coefficient of the cooling coil is calculated for
5941 : // inside tube diameter of 0.0122m (~0.5 inch nominal diameter) and water velocity 2.0 m/s:
5942 : static Real64 const hWaterTubeInside(1429.0 * std::pow(2.0, 0.8) * std::pow(0.0122, -0.2)); // water (tube) side heat transfer coefficient [W/m2C]
5943 :
5944 : // Estimate the overall heat transfer coefficient, UOverallHeatTransferCoef in [W/(m2C)].
5945 : // Neglecting tube wall and fouling resistance, the overall U value can be estimated as:
5946 : // 1/UOverallHeatTransferCoef = 1/(hi*AreaRatio) + 1/(ho*OverallFinEfficiency)
5947 : static Real64 const UOverallHeatTransferCoef_inv(
5948 : 1.0 / (hWaterTubeInside * AreaRatio) +
5949 : 1.0 / (hAirTubeOutside * OverallFinEfficiency)); // Inverse of overall heat transfer coefficient for coil [W/m2C]
5950 :
5951 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
5952 9085 : auto &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
5953 9085 : waterCoil.UACoilTotal = 1.0 / (1.0 / waterCoil.UACoilExternal + 1.0 / waterCoil.UACoilInternal);
5954 :
5955 : // the heat exchanger surface area is calculated as follows:
5956 9085 : return waterCoil.UACoilTotal * UOverallHeatTransferCoef_inv; // Heat exchanger surface area [m2]
5957 : }
5958 :
5959 2509 : int GetWaterCoilIndex(EnergyPlusData &state,
5960 : std::string_view CoilType, // must match coil types in this module
5961 : std::string const &CoilName, // must match coil names for the coil type
5962 : bool &ErrorsFound // set to true if problem
5963 : )
5964 : {
5965 :
5966 : // FUNCTION INFORMATION:
5967 : // AUTHOR B. Nigusse, FSEC
5968 : // DATE WRITTEN Feb 2012
5969 :
5970 : // PURPOSE OF THIS FUNCTION:
5971 : // This function looks up the index for the given coil and returns it. If incorrect coil
5972 : // type or name is given, ErrorsFound is returned as true and node number is returned
5973 : // as zero.
5974 :
5975 : // Return value
5976 : int IndexNum; // returned coil index if matched coil
5977 :
5978 : // Obtains and allocates WaterCoil related parameters from input file
5979 2509 : if (state.dataWaterCoils->GetWaterCoilsInputFlag) {
5980 278 : GetWaterCoilInput(state);
5981 278 : state.dataWaterCoils->GetWaterCoilsInputFlag = false;
5982 : }
5983 :
5984 2509 : IndexNum = 0;
5985 2509 : if (CoilType == "COIL:HEATING:WATER") {
5986 2319 : IndexNum = Util::FindItemInList(CoilName, state.dataWaterCoils->WaterCoil);
5987 190 : } else if (CoilType == "COIL:COOLING:WATER") {
5988 190 : IndexNum = Util::FindItemInList(CoilName, state.dataWaterCoils->WaterCoil);
5989 0 : } else if (CoilType == "COIL:COOLING:WATER:DETAILEDGEOMETRY") {
5990 0 : IndexNum = Util::FindItemInList(CoilName, state.dataWaterCoils->WaterCoil);
5991 : } else {
5992 0 : IndexNum = 0;
5993 : }
5994 :
5995 2509 : if (IndexNum == 0) {
5996 0 : ShowSevereError(state, format("GetWaterCoilIndex: Could not find CoilType=\"{}\" with Name=\"{}\"", CoilType, CoilName));
5997 0 : ErrorsFound = true;
5998 : }
5999 :
6000 2509 : return IndexNum;
6001 : }
6002 24 : int GetCompIndex(EnergyPlusData &state, CoilModel compType, std::string_view const coilName)
6003 : {
6004 : static constexpr std::array<std::string_view, (int)WaterCoils::CoilModel::Num> CoilModelNamesUC = {
6005 : "COIL:HEATING:WATER", "COIL:COOLING:WATER", "COIL:COOLING:WATER:DETAILED"};
6006 :
6007 24 : if (state.dataWaterCoils->GetWaterCoilsInputFlag) {
6008 5 : GetWaterCoilInput(state);
6009 5 : state.dataWaterCoils->GetWaterCoilsInputFlag = false;
6010 : }
6011 :
6012 24 : int index = Util::FindItemInList(coilName, state.dataWaterCoils->WaterCoil);
6013 :
6014 24 : if (index == 0) { // may not find coil name
6015 0 : ShowSevereError(state,
6016 0 : format("GetWaterCoilIndex: Could not find CoilType = \"{}\" with Name = \"{}\"", CoilModelNamesUC[(int)compType], coilName));
6017 : }
6018 24 : return index;
6019 : }
6020 :
6021 29 : Real64 GetWaterCoilCapacity(EnergyPlusData &state,
6022 : std::string const &CoilType, // must match coil types in this module
6023 : std::string const &CoilName, // must match coil names for the coil type
6024 : bool &ErrorsFound // set to true if problem
6025 : )
6026 : {
6027 :
6028 : // FUNCTION INFORMATION:
6029 : // AUTHOR R. Raustad, FSEC
6030 : // DATE WRITTEN Sep 2013
6031 :
6032 : // PURPOSE OF THIS FUNCTION:
6033 : // This function looks up the capacity for the given coil and returns it. If incorrect coil
6034 : // type or name is given, ErrorsFound is returned as true and capacity is returned
6035 : // as zero.
6036 :
6037 : // Obtains and allocates WaterCoil related parameters from input file
6038 29 : if (state.dataWaterCoils->GetWaterCoilsInputFlag) {
6039 0 : GetWaterCoilInput(state);
6040 0 : state.dataWaterCoils->GetWaterCoilsInputFlag = false;
6041 : }
6042 :
6043 : int IndexNum; // index to water coil
6044 29 : Real64 Capacity = -1.0; // returned coil capacity if matched coil
6045 :
6046 29 : if (CoilType == "COIL:HEATING:WATER") {
6047 9 : IndexNum = Util::FindItemInList(CoilName, state.dataWaterCoils->WaterCoil);
6048 9 : Capacity = state.dataWaterCoils->WaterCoil(IndexNum).DesWaterHeatingCoilRate;
6049 20 : } else if (CoilType == "COIL:COOLING:WATER") {
6050 20 : IndexNum = Util::FindItemInList(CoilName, state.dataWaterCoils->WaterCoil);
6051 20 : Capacity = state.dataWaterCoils->WaterCoil(IndexNum).DesWaterCoolingCoilRate;
6052 0 : } else if (CoilType == "COIL:COOLING:WATER:DETAILEDGEOMETRY") {
6053 0 : IndexNum = Util::FindItemInList(CoilName, state.dataWaterCoils->WaterCoil);
6054 0 : Capacity = state.dataWaterCoils->WaterCoil(IndexNum).DesWaterCoolingCoilRate;
6055 : } else {
6056 0 : IndexNum = 0;
6057 : }
6058 :
6059 29 : if (IndexNum == 0) {
6060 0 : ShowSevereError(state, format("GetWaterCoilCapacity: Could not find CoilType=\"{}\" with Name=\"{}\"", CoilType, CoilName));
6061 0 : ErrorsFound = true;
6062 : }
6063 :
6064 29 : return Capacity;
6065 : }
6066 :
6067 0 : void UpdateWaterToAirCoilPlantConnection(EnergyPlusData &state,
6068 : DataPlant::PlantEquipmentType const CoilType,
6069 : std::string const &CoilName,
6070 : [[maybe_unused]] int const EquipFlowCtrl, // Flow control mode for the equipment
6071 : int const LoopNum, // Plant loop index for where called from
6072 : const DataPlant::LoopSideLocation LoopSide, // Plant loop side index for where called from
6073 : int &CompIndex, // Chiller number pointer
6074 : [[maybe_unused]] bool const FirstHVACIteration,
6075 : bool &InitLoopEquip // If not zero, calculate the max load for operating conditions
6076 : )
6077 : {
6078 :
6079 : // SUBROUTINE INFORMATION:
6080 : // AUTHOR B. Griffith
6081 : // DATE WRITTEN February 2010
6082 :
6083 : // PURPOSE OF THIS SUBROUTINE:
6084 : // update sim routine called from plant
6085 :
6086 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
6087 :
6088 : int CoilNum;
6089 0 : bool DidAnythingChange(false); // set to true if conditions changed
6090 : int InletNodeNum;
6091 : int OutletNodeNum;
6092 :
6093 : // Find the correct water coil
6094 0 : if (CompIndex == 0) {
6095 0 : CoilNum = Util::FindItemInList(CoilName, state.dataWaterCoils->WaterCoil);
6096 0 : if (CoilNum == 0) {
6097 0 : ShowFatalError(state, format("UpdateWaterToAirCoilPlantConnection: Specified Coil not one of Valid water coils={}", CoilName));
6098 : }
6099 0 : CompIndex = CoilNum;
6100 : } else {
6101 0 : CoilNum = CompIndex;
6102 0 : if (CoilNum > state.dataWaterCoils->NumWaterCoils || CoilNum < 1) {
6103 0 : ShowFatalError(state,
6104 0 : format("UpdateWaterToAirCoilPlantConnection: Invalid CompIndex passed={}, Number of Coils={}, Entered Coil name={}",
6105 : CoilNum,
6106 0 : state.dataWaterCoils->NumWaterCoils,
6107 : CoilName));
6108 : }
6109 0 : auto const &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
6110 0 : if (state.dataGlobal->KickOffSimulation) {
6111 0 : if (CoilName != waterCoil.Name) {
6112 0 : ShowFatalError(
6113 : state,
6114 0 : format("UpdateWaterToAirCoilPlantConnection: Invalid CompIndex passed={}, Coil name={}, stored Coil Name for that index={}",
6115 : CoilNum,
6116 : CoilName,
6117 0 : waterCoil.Name));
6118 : }
6119 0 : if (CoilType != waterCoil.WaterCoilType) {
6120 0 : ShowFatalError(
6121 : state,
6122 0 : format("UpdateWaterToAirCoilPlantConnection: Invalid CompIndex passed={}, Coil name={}, stored Coil Name for that index={}",
6123 : CoilNum,
6124 : CoilName,
6125 0 : DataPlant::PlantEquipTypeNames[static_cast<int>(CoilType)]));
6126 : }
6127 : }
6128 : }
6129 :
6130 0 : if (InitLoopEquip) {
6131 0 : return;
6132 : }
6133 :
6134 0 : DidAnythingChange = false;
6135 :
6136 0 : auto const &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
6137 0 : InletNodeNum = waterCoil.WaterInletNodeNum;
6138 0 : OutletNodeNum = waterCoil.WaterOutletNodeNum;
6139 :
6140 0 : if (state.dataLoopNodes->Node(InletNodeNum).Temp != waterCoil.InletWaterTemp) {
6141 0 : DidAnythingChange = true;
6142 : }
6143 :
6144 0 : if (state.dataLoopNodes->Node(OutletNodeNum).Temp != waterCoil.OutletWaterTemp) {
6145 0 : DidAnythingChange = true;
6146 : }
6147 :
6148 0 : if (state.dataLoopNodes->Node(InletNodeNum).MassFlowRate != waterCoil.OutletWaterMassFlowRate) {
6149 0 : DidAnythingChange = true;
6150 0 : state.dataLoopNodes->Node(OutletNodeNum).MassFlowRate =
6151 0 : state.dataLoopNodes->Node(InletNodeNum).MassFlowRate; // make sure flows are consistent
6152 : }
6153 :
6154 0 : if (state.dataLoopNodes->Node(OutletNodeNum).MassFlowRate != waterCoil.OutletWaterMassFlowRate) {
6155 0 : DidAnythingChange = true;
6156 : }
6157 :
6158 0 : if (DidAnythingChange) {
6159 : // set sim flag for this loop
6160 0 : state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSide).SimLoopSideNeeded = true;
6161 : // set sim flags for air side users of coils
6162 :
6163 0 : state.dataHVACGlobal->SimAirLoopsFlag = true;
6164 0 : state.dataHVACGlobal->SimZoneEquipmentFlag = true;
6165 : } else { // nothing changed so turn off sim flag
6166 0 : state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSide).SimLoopSideNeeded = false;
6167 : }
6168 : }
6169 :
6170 0 : Sched::Schedule *GetWaterCoilAvailSched(EnergyPlusData &state,
6171 : std::string const &CoilType, // must match coil types in this module
6172 : std::string const &CoilName, // must match coil names for the coil type
6173 : bool &ErrorsFound // set to true if problem
6174 : )
6175 : {
6176 :
6177 : // FUNCTION INFORMATION:
6178 : // AUTHOR Chandan Sharma, FSEC
6179 : // DATE WRITTEN February 2013
6180 :
6181 : // PURPOSE OF THIS FUNCTION:
6182 : // This function looks up the given coil and returns the availability schedule index. If
6183 : // incorrect coil type or name is given, ErrorsFound is returned as true and index is returned
6184 : // as zero.
6185 :
6186 : // Obtains and Allocates HeatingCoil related parameters from input file
6187 : // Obtains and Allocates DXCoils
6188 0 : if (state.dataWaterCoils->GetWaterCoilsInputFlag) {
6189 0 : GetWaterCoilInput(state);
6190 0 : state.dataWaterCoils->GetWaterCoilsInputFlag = false;
6191 : }
6192 :
6193 0 : int WhichCoil = 0;
6194 :
6195 0 : if (Util::SameString(CoilType, "Coil:Heating:Water") || Util::SameString(CoilType, "Coil:Cooling:Water") ||
6196 0 : Util::SameString(CoilType, "Coil:Cooling:Water:DetailedGeometry")) {
6197 0 : WhichCoil = Util::FindItem(CoilName, state.dataWaterCoils->WaterCoil);
6198 0 : if (WhichCoil != 0) {
6199 0 : return state.dataWaterCoils->WaterCoil(WhichCoil).availSched;
6200 : }
6201 : } else {
6202 0 : WhichCoil = 0;
6203 : }
6204 :
6205 0 : if (WhichCoil == 0) {
6206 0 : ShowSevereError(state, format("GetCoilAvailScheduleIndex: Could not find Coil, Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
6207 0 : ErrorsFound = true;
6208 0 : return nullptr;
6209 : }
6210 :
6211 0 : return nullptr;
6212 : }
6213 :
6214 2 : void SetWaterCoilData(EnergyPlusData &state,
6215 : int const CoilNum, // Number of hot water heating Coil
6216 : bool &ErrorsFound, // Set to true if certain errors found
6217 : ObjexxFCL::Optional_bool DesiccantRegenerationCoil, // Flag that this coil is used as regeneration air heating coil
6218 : ObjexxFCL::Optional_int DesiccantDehumIndex, // Index for the desiccant dehum system where this caoil is used
6219 : ObjexxFCL::Optional_bool heatRecoveryCoil) // true if water coil is connected to heat recovery loop
6220 : {
6221 :
6222 : // FUNCTION INFORMATION:
6223 : // AUTHOR Bereket Nigusse
6224 : // DATE WRITTEN February 2016
6225 :
6226 : // PURPOSE OF THIS FUNCTION:
6227 : // This function sets data to water Heating Coil using the coil index and arguments passed
6228 :
6229 2 : if (state.dataWaterCoils->GetWaterCoilsInputFlag) {
6230 0 : GetWaterCoilInput(state);
6231 0 : state.dataWaterCoils->GetWaterCoilsInputFlag = false;
6232 : }
6233 :
6234 2 : if (CoilNum <= 0 || CoilNum > state.dataWaterCoils->NumWaterCoils) {
6235 0 : ShowSevereError(state,
6236 0 : format("SetHeatingCoilData: called with heating coil Number out of range={} should be >0 and <{}",
6237 : CoilNum,
6238 0 : state.dataWaterCoils->NumWaterCoils));
6239 0 : ErrorsFound = true;
6240 0 : return;
6241 : }
6242 :
6243 2 : auto &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
6244 2 : if (present(DesiccantRegenerationCoil)) {
6245 0 : waterCoil.DesiccantRegenerationCoil = DesiccantRegenerationCoil;
6246 : }
6247 :
6248 2 : if (present(DesiccantDehumIndex)) {
6249 0 : waterCoil.DesiccantDehumNum = DesiccantDehumIndex;
6250 : }
6251 :
6252 2 : if (present(heatRecoveryCoil)) {
6253 2 : waterCoil.heatRecoveryCoil = heatRecoveryCoil;
6254 : }
6255 : }
6256 :
6257 0 : void EstimateCoilInletWaterTemp(EnergyPlusData &state,
6258 : int const CoilNum, // index to heating coil
6259 : HVAC::FanOp const fanOp, // fan operating mode
6260 : Real64 const PartLoadRatio, // part-load ratio of heating coil
6261 : Real64 const UAMax, // maximum UA-Value = design heating capacity
6262 : Real64 &DesCoilInletWaterTempUsed // estimated coil design inlet water temperature
6263 : )
6264 : {
6265 : // SUBROUTINE INFORMATION:
6266 :
6267 : // PURPOSE OF THIS SUBROUTINE:
6268 : // returns estimated coil inlet water temperature given UA value for assumed
6269 : // maximum effectiveness value for heating coil
6270 :
6271 : // METHODOLOGY EMPLOYED:
6272 : // applies energy balance around the water coil and estimates coil water inlet temperature
6273 : // assuming coil effectiveness of 0.8
6274 :
6275 : // SUBROUTINE PARAMETER DEFINITIONS:
6276 : static constexpr std::string_view RoutineName("EstimateCoilInletWaterTemp");
6277 0 : constexpr Real64 EffectivenessMaxAssumed(0.80);
6278 :
6279 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
6280 : Real64 WaterMassFlowRate;
6281 : Real64 AirMassFlow;
6282 : Real64 TempAirIn;
6283 : Real64 TempAirOut; // [C]
6284 : Real64 Win;
6285 : Real64 TempWaterIn;
6286 : Real64 UA;
6287 : Real64 CapacitanceAir;
6288 : Real64 CapacitanceWater;
6289 : Real64 CapacitanceMin;
6290 : Real64 CapacitanceMax;
6291 : Real64 NTU;
6292 : Real64 ETA;
6293 : Real64 A;
6294 : Real64 CapRatio;
6295 : Real64 E1;
6296 : Real64 E2;
6297 : Real64 Effec;
6298 : Real64 Cp;
6299 :
6300 0 : UA = UAMax;
6301 0 : DesCoilInletWaterTempUsed = HVAC::DesCoilHWInletTempMin;
6302 0 : auto const &waterCoil = state.dataWaterCoils->WaterCoil(CoilNum);
6303 0 : TempAirIn = waterCoil.InletAirTemp;
6304 0 : Win = waterCoil.InletAirHumRat;
6305 0 : TempWaterIn = waterCoil.InletWaterTemp;
6306 : // adjust mass flow rates for cycling fan cycling coil operation
6307 0 : if (fanOp == HVAC::FanOp::Cycling) {
6308 0 : if (PartLoadRatio > 0.0) {
6309 0 : AirMassFlow = waterCoil.InletAirMassFlowRate / PartLoadRatio;
6310 0 : WaterMassFlowRate = min(waterCoil.InletWaterMassFlowRate / PartLoadRatio, waterCoil.MaxWaterMassFlowRate);
6311 : } else {
6312 0 : AirMassFlow = 0.0;
6313 0 : WaterMassFlowRate = 0.0;
6314 0 : return;
6315 : }
6316 : } else {
6317 0 : AirMassFlow = waterCoil.InletAirMassFlowRate;
6318 0 : WaterMassFlowRate = waterCoil.InletWaterMassFlowRate;
6319 : }
6320 0 : if (WaterMassFlowRate > DataBranchAirLoopPlant::MassFlowTolerance) { // if the coil is operating
6321 0 : CapacitanceAir = PsyCpAirFnW(Win) * AirMassFlow;
6322 0 : Cp = state.dataPlnt->PlantLoop(waterCoil.WaterPlantLoc.loopNum).glycol->getSpecificHeat(state, TempWaterIn, RoutineName);
6323 0 : CapacitanceWater = Cp * WaterMassFlowRate;
6324 0 : CapacitanceMin = min(CapacitanceAir, CapacitanceWater);
6325 0 : CapacitanceMax = max(CapacitanceAir, CapacitanceWater);
6326 : } else {
6327 0 : CapacitanceAir = 0.0;
6328 0 : CapacitanceWater = 0.0;
6329 0 : return;
6330 : }
6331 : // calculate DesCoilInletWaterTempUsed
6332 0 : if (((CapacitanceAir > 0.0) && (CapacitanceWater > 0.0))) {
6333 :
6334 0 : if (UA <= 0.0) {
6335 0 : ShowWarningError(state, format("UA is zero for COIL:Heating:Water {}", waterCoil.Name));
6336 0 : return;
6337 : }
6338 0 : NTU = UA / CapacitanceMin;
6339 0 : ETA = std::pow(NTU, 0.22);
6340 0 : CapRatio = CapacitanceMin / CapacitanceMax;
6341 0 : A = CapRatio * NTU / ETA;
6342 :
6343 0 : if (A > 20.0) {
6344 0 : A = ETA * 1.0 / CapRatio;
6345 : } else {
6346 0 : E1 = std::exp(-A);
6347 0 : A = ETA * (1.0 - E1) / CapRatio;
6348 : }
6349 :
6350 0 : if (A > 20.0) {
6351 0 : Effec = 1.0;
6352 : } else {
6353 0 : E2 = std::exp(-A);
6354 0 : Effec = 1.0 - E2;
6355 : }
6356 0 : TempAirOut = TempAirIn + Effec * CapacitanceMin * (TempWaterIn - TempAirIn) / CapacitanceAir;
6357 : // this formulation assumes coil effectiveness of 0.80 to increase the estimated coil water inlet temperatures
6358 0 : DesCoilInletWaterTempUsed = CapacitanceAir * (TempAirOut - TempAirIn) / (CapacitanceMin * EffectivenessMaxAssumed) + TempAirIn;
6359 : // water coil should not be sized at coil water inlet temperature lower than 46.0C (for convergence problem in Regulafalsi)
6360 0 : DesCoilInletWaterTempUsed = max(DesCoilInletWaterTempUsed, HVAC::DesCoilHWInletTempMin);
6361 : }
6362 : }
6363 :
6364 : // End of Coil Utility subroutines
6365 : // *****************************************************************************
6366 :
6367 : } // namespace EnergyPlus::WaterCoils
|