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