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