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 : #include <ObjexxFCL/Fmath.hh>
54 :
55 : // EnergyPlus Headers
56 : #include <EnergyPlus/Autosizing/All_Simple_Sizing.hh>
57 : #include <EnergyPlus/Autosizing/HeatingCapacitySizing.hh>
58 : #include <EnergyPlus/BranchNodeConnections.hh>
59 : #include <EnergyPlus/Coils/CoilCoolingDX.hh>
60 : #include <EnergyPlus/CurveManager.hh>
61 : #include <EnergyPlus/DXCoils.hh>
62 : #include <EnergyPlus/Data/EnergyPlusData.hh>
63 : #include <EnergyPlus/DataContaminantBalance.hh>
64 : #include <EnergyPlus/DataEnvironment.hh>
65 : #include <EnergyPlus/DataGlobalConstants.hh>
66 : #include <EnergyPlus/DataHVACGlobals.hh>
67 : #include <EnergyPlus/DataHeatBalance.hh>
68 : #include <EnergyPlus/DataLoopNode.hh>
69 : #include <EnergyPlus/DataSizing.hh>
70 : #include <EnergyPlus/EMSManager.hh>
71 : #include <EnergyPlus/FaultsManager.hh>
72 : #include <EnergyPlus/General.hh>
73 : #include <EnergyPlus/GlobalNames.hh>
74 : #include <EnergyPlus/HeatingCoils.hh>
75 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
76 : #include <EnergyPlus/NodeInputManager.hh>
77 : #include <EnergyPlus/OutputProcessor.hh>
78 : #include <EnergyPlus/OutputReportPredefined.hh>
79 : #include <EnergyPlus/Psychrometrics.hh>
80 : #include <EnergyPlus/RefrigeratedCase.hh>
81 : #include <EnergyPlus/ScheduleManager.hh>
82 : #include <EnergyPlus/UtilityRoutines.hh>
83 : #include <EnergyPlus/VariableSpeedCoils.hh>
84 :
85 : namespace EnergyPlus { // NOLINT(modernize-concat-nested-namespaces) // TODO: Take out this lint when we want to apply formatting for nested
86 : // namespacing
87 :
88 : namespace HeatingCoils {
89 : // Module containing the HeatingCoil simulation routines other than the Water coils
90 :
91 : // MODULE INFORMATION:
92 : // AUTHOR Richard J. Liesen
93 : // DATE WRITTEN May 2000
94 : // MODIFIED Therese Stovall June 2008 to add references to refrigeration condensers
95 :
96 : // PURPOSE OF THIS MODULE:
97 : // To encapsulate the data and algorithms required to
98 : // manage the HeatingCoil System Component
99 :
100 233160 : void SimulateHeatingCoilComponents(EnergyPlusData &state,
101 : std::string_view CompName,
102 : bool const FirstHVACIteration,
103 : ObjexxFCL::Optional<Real64 const> QCoilReq, // coil load to be met
104 : ObjexxFCL::Optional_int CompIndex,
105 : ObjexxFCL::Optional<Real64> QCoilActual, // coil load actually delivered returned to calling component
106 : ObjexxFCL::Optional_bool_const SuppHeat, // True if current heating coil is a supplemental heating coil
107 : ObjexxFCL::Optional<HVAC::FanOp const> fanOpMode, // fan operating mode, FanOp::Cycling or FanOp::Continuous
108 : ObjexxFCL::Optional<Real64 const> PartLoadRatio, // part-load ratio of heating coil
109 : ObjexxFCL::Optional_int StageNum,
110 : ObjexxFCL::Optional<Real64 const> SpeedRatio // Speed ratio of MultiStage heating coil
111 : )
112 : {
113 :
114 : // SUBROUTINE INFORMATION:
115 : // AUTHOR Richard Liesen
116 : // DATE WRITTEN May 2000
117 :
118 : // PURPOSE OF THIS SUBROUTINE:
119 : // This subroutine manages HeatingCoil component simulation.
120 :
121 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
122 233160 : int CoilNum(0); // The HeatingCoil that you are currently loading input into
123 : Real64 QCoilActual2; // coil load actually delivered returned from specific coil
124 : HVAC::FanOp fanOp; // fan operating mode
125 : Real64 PartLoadFrac; // part-load fraction of heating coil
126 : Real64 QCoilRequired; // local variable for optional argument
127 :
128 : // Obtains and Allocates HeatingCoil related parameters from input file
129 233160 : if (state.dataHeatingCoils->GetCoilsInputFlag) { // First time subroutine has been entered
130 21 : GetHeatingCoilInput(state);
131 21 : state.dataHeatingCoils->GetCoilsInputFlag = false;
132 : }
133 :
134 : // Find the correct HeatingCoilNumber with the Coil Name
135 233160 : if (present(CompIndex)) {
136 233160 : if (CompIndex == 0) {
137 81878 : CoilNum = Util::FindItemInList(CompName, state.dataHeatingCoils->HeatingCoil);
138 81878 : if (CoilNum == 0) {
139 0 : ShowFatalError(state, format("SimulateHeatingCoilComponents: Coil not found={}", CompName));
140 : }
141 : // CompIndex=CoilNum
142 : } else {
143 151282 : CoilNum = CompIndex;
144 151282 : if (CoilNum > state.dataHeatingCoils->NumHeatingCoils || CoilNum < 1) {
145 0 : ShowFatalError(state,
146 0 : format("SimulateHeatingCoilComponents: Invalid CompIndex passed={}, Number of Heating Coils={}, Coil name={}",
147 : CoilNum,
148 0 : state.dataHeatingCoils->NumHeatingCoils,
149 : CompName));
150 : }
151 151282 : if (state.dataHeatingCoils->CheckEquipName(CoilNum)) {
152 76 : if (!CompName.empty() && CompName != state.dataHeatingCoils->HeatingCoil(CoilNum).Name) {
153 0 : ShowFatalError(
154 : state,
155 0 : format("SimulateHeatingCoilComponents: Invalid CompIndex passed={}, Coil name={}, stored Coil Name for that index={}",
156 : CoilNum,
157 : CompName,
158 0 : state.dataHeatingCoils->HeatingCoil(CoilNum).Name));
159 : }
160 76 : state.dataHeatingCoils->CheckEquipName(CoilNum) = false;
161 : }
162 : }
163 : } else {
164 0 : ShowSevereError(state, "SimulateHeatingCoilComponents: CompIndex argument not used.");
165 0 : ShowContinueError(state, format("..CompName = {}", CompName));
166 0 : ShowFatalError(state, "Preceding conditions cause termination.");
167 : }
168 :
169 233160 : if (present(SuppHeat)) {
170 138362 : state.dataHeatingCoils->CoilIsSuppHeater = SuppHeat;
171 : } else {
172 94798 : state.dataHeatingCoils->CoilIsSuppHeater = false;
173 : }
174 :
175 233160 : if (present(fanOpMode)) {
176 138934 : fanOp = fanOpMode;
177 : } else {
178 94226 : fanOp = HVAC::FanOp::Continuous;
179 : }
180 :
181 233160 : if (present(PartLoadRatio)) {
182 67273 : PartLoadFrac = PartLoadRatio;
183 : } else {
184 165887 : PartLoadFrac = 1.0;
185 : }
186 :
187 233160 : if (present(QCoilReq)) {
188 167678 : QCoilRequired = QCoilReq;
189 : } else {
190 65482 : QCoilRequired = DataLoopNode::SensedLoadFlagValue;
191 : }
192 :
193 : // With the correct CoilNum Initialize
194 233160 : InitHeatingCoil(state, CoilNum, FirstHVACIteration, QCoilRequired); // Initialize all HeatingCoil related parameters
195 :
196 : // Calculate the Correct HeatingCoil Model with the current CoilNum
197 233160 : switch (state.dataHeatingCoils->HeatingCoil(CoilNum).HCoilType_Num) {
198 73698 : case HVAC::Coil_HeatingElectric: {
199 73698 : CalcElectricHeatingCoil(state, CoilNum, QCoilRequired, QCoilActual2, fanOp, PartLoadFrac);
200 73698 : } break;
201 217 : case HVAC::Coil_HeatingElectric_MultiStage: {
202 217 : CalcMultiStageElectricHeatingCoil(
203 : state,
204 : CoilNum,
205 : SpeedRatio,
206 : PartLoadRatio,
207 : StageNum,
208 : fanOp,
209 : QCoilActual2,
210 217 : state.dataHeatingCoils->CoilIsSuppHeater); // Autodesk:OPTIONAL SpeedRatio, PartLoadRatio, StageNum used without PRESENT check
211 217 : } break;
212 159191 : case HVAC::Coil_HeatingGasOrOtherFuel: {
213 159191 : CalcFuelHeatingCoil(state, CoilNum, QCoilRequired, QCoilActual2, fanOp, PartLoadFrac);
214 159191 : } break;
215 50 : case HVAC::Coil_HeatingGas_MultiStage: {
216 50 : CalcMultiStageGasHeatingCoil(state,
217 : CoilNum,
218 : SpeedRatio,
219 : PartLoadRatio,
220 : StageNum,
221 : fanOp); // Autodesk:OPTIONAL SpeedRatio, PartLoadRatio, StageNum used without PRESENT check
222 50 : } break;
223 4 : case HVAC::Coil_HeatingDesuperheater: {
224 4 : CalcDesuperheaterHeatingCoil(state, CoilNum, QCoilRequired, QCoilActual2);
225 4 : } break;
226 0 : default:
227 0 : QCoilActual2 = 0.0;
228 0 : break;
229 : }
230 :
231 : // Update the current HeatingCoil to the outlet nodes
232 233160 : UpdateHeatingCoil(state, CoilNum);
233 :
234 : // Report the current HeatingCoil
235 233160 : ReportHeatingCoil(state, CoilNum, state.dataHeatingCoils->CoilIsSuppHeater);
236 :
237 233160 : if (present(QCoilActual)) {
238 126147 : QCoilActual = QCoilActual2;
239 : }
240 233160 : }
241 :
242 123 : void GetHeatingCoilInput(EnergyPlusData &state)
243 : {
244 :
245 : // SUBROUTINE INFORMATION:
246 : // AUTHOR Richard Liesen
247 : // DATE WRITTEN May 2000
248 :
249 : // PURPOSE OF THIS SUBROUTINE:
250 : // Obtains input data for coils and stores it in coil data structures
251 :
252 : // METHODOLOGY EMPLOYED:
253 : // Uses "Get" routines to read in data.
254 :
255 : // SUBROUTINE PARAMETER DEFINITIONS:
256 : static constexpr std::string_view RoutineName = "GetHeatingCoilInput: "; // include trailing blank space
257 : static constexpr std::string_view routineName = "GetHeatingCoilInput";
258 :
259 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
260 123 : std::string CurrentModuleObject; // for ease in getting objects
261 123 : Array1D_string Alphas; // Alpha input items for object
262 123 : Array1D_string cAlphaFields; // Alpha field names
263 123 : Array1D_string cNumericFields; // Numeric field names
264 123 : Array1D<Real64> Numbers; // Numeric input items for object
265 123 : Array1D_bool lAlphaBlanks; // Logical array, alpha field input BLANK = .TRUE.
266 123 : Array1D_bool lNumericBlanks; // Logical array, numeric field input BLANK = .TRUE.
267 : int NumAlphas;
268 : int NumNums;
269 : int IOStat;
270 : int StageNum;
271 : bool DXCoilErrFlag; // Used in GetDXCoil mining functions
272 : bool errFlag;
273 :
274 123 : state.dataHeatingCoils->NumElecCoil = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Coil:Heating:Electric");
275 246 : state.dataHeatingCoils->NumElecCoilMultiStage =
276 123 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Coil:Heating:Electric:MultiStage");
277 123 : state.dataHeatingCoils->NumFuelCoil = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Coil:Heating:Fuel");
278 246 : state.dataHeatingCoils->NumGasCoilMultiStage =
279 123 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Coil:Heating:Gas:MultiStage");
280 246 : state.dataHeatingCoils->NumDesuperheaterCoil =
281 123 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Coil:Heating:Desuperheater");
282 123 : state.dataHeatingCoils->NumHeatingCoils = state.dataHeatingCoils->NumElecCoil + state.dataHeatingCoils->NumElecCoilMultiStage +
283 123 : state.dataHeatingCoils->NumFuelCoil + state.dataHeatingCoils->NumGasCoilMultiStage +
284 123 : state.dataHeatingCoils->NumDesuperheaterCoil;
285 123 : if (state.dataHeatingCoils->NumHeatingCoils > 0) {
286 123 : state.dataHeatingCoils->HeatingCoil.allocate(state.dataHeatingCoils->NumHeatingCoils);
287 123 : state.dataHeatingCoils->HeatingCoilNumericFields.allocate(state.dataHeatingCoils->NumHeatingCoils);
288 123 : state.dataHeatingCoils->ValidSourceType.dimension(state.dataHeatingCoils->NumHeatingCoils, false);
289 123 : state.dataHeatingCoils->CheckEquipName.dimension(state.dataHeatingCoils->NumHeatingCoils, true);
290 : }
291 :
292 246 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
293 123 : state, "Coil:Heating:Electric", state.dataHeatingCoils->TotalArgs, NumAlphas, NumNums);
294 123 : state.dataHeatingCoils->MaxNums = max(state.dataHeatingCoils->MaxNums, NumNums);
295 123 : state.dataHeatingCoils->MaxAlphas = max(state.dataHeatingCoils->MaxAlphas, NumAlphas);
296 246 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
297 123 : state, "Coil:Heating:Electric:MultiStage", state.dataHeatingCoils->TotalArgs, NumAlphas, NumNums);
298 123 : state.dataHeatingCoils->MaxNums = max(state.dataHeatingCoils->MaxNums, NumNums);
299 123 : state.dataHeatingCoils->MaxAlphas = max(state.dataHeatingCoils->MaxAlphas, NumAlphas);
300 246 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
301 123 : state, "Coil:Heating:Fuel", state.dataHeatingCoils->TotalArgs, NumAlphas, NumNums);
302 123 : state.dataHeatingCoils->MaxNums = max(state.dataHeatingCoils->MaxNums, NumNums);
303 123 : state.dataHeatingCoils->MaxAlphas = max(state.dataHeatingCoils->MaxAlphas, NumAlphas);
304 246 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
305 123 : state, "Coil:Heating:Gas:MultiStage", state.dataHeatingCoils->TotalArgs, NumAlphas, NumNums);
306 123 : state.dataHeatingCoils->MaxNums = max(state.dataHeatingCoils->MaxNums, NumNums);
307 123 : state.dataHeatingCoils->MaxAlphas = max(state.dataHeatingCoils->MaxAlphas, NumAlphas);
308 246 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
309 123 : state, "Coil:Heating:Desuperheater", state.dataHeatingCoils->TotalArgs, NumAlphas, NumNums);
310 123 : state.dataHeatingCoils->MaxNums = max(state.dataHeatingCoils->MaxNums, NumNums);
311 123 : state.dataHeatingCoils->MaxAlphas = max(state.dataHeatingCoils->MaxAlphas, NumAlphas);
312 :
313 123 : Alphas.allocate(state.dataHeatingCoils->MaxAlphas);
314 123 : cAlphaFields.allocate(state.dataHeatingCoils->MaxAlphas);
315 123 : cNumericFields.allocate(state.dataHeatingCoils->MaxNums);
316 123 : Numbers.dimension(state.dataHeatingCoils->MaxNums, 0.0);
317 123 : lAlphaBlanks.dimension(state.dataHeatingCoils->MaxAlphas, true);
318 123 : lNumericBlanks.dimension(state.dataHeatingCoils->MaxNums, true);
319 :
320 : // Get the data for electric heating coils
321 181 : for (int ElecCoilNum = 1; ElecCoilNum <= state.dataHeatingCoils->NumElecCoil; ++ElecCoilNum) {
322 :
323 58 : auto &heatingCoil = state.dataHeatingCoils->HeatingCoil(ElecCoilNum);
324 58 : auto &heatingCoilNumericFields = state.dataHeatingCoils->HeatingCoilNumericFields(ElecCoilNum);
325 :
326 58 : CurrentModuleObject = "Coil:Heating:Electric";
327 58 : heatingCoil.FuelType = Constant::eFuel::Electricity;
328 :
329 58 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
330 : CurrentModuleObject,
331 : ElecCoilNum,
332 : Alphas,
333 : NumAlphas,
334 : Numbers,
335 : NumNums,
336 : IOStat,
337 : lNumericBlanks,
338 : lAlphaBlanks,
339 : cAlphaFields,
340 : cNumericFields);
341 :
342 58 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
343 58 : heatingCoilNumericFields.FieldNames.allocate(state.dataHeatingCoils->MaxNums);
344 58 : heatingCoilNumericFields.FieldNames = cNumericFields;
345 :
346 : // InputErrorsFound will be set to True if problem was found, left untouched otherwise
347 58 : GlobalNames::VerifyUniqueCoilName(
348 58 : state, CurrentModuleObject, Alphas(1), state.dataHeatingCoils->InputErrorsFound, CurrentModuleObject + " Name");
349 :
350 58 : heatingCoil.Name = Alphas(1);
351 58 : if (lAlphaBlanks(2)) {
352 18 : heatingCoil.availSched = Sched::GetScheduleAlwaysOn(state);
353 40 : } else if ((heatingCoil.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
354 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
355 0 : state.dataHeatingCoils->InputErrorsFound = true;
356 : }
357 :
358 58 : heatingCoil.HeatingCoilType = "Heating";
359 58 : heatingCoil.HeatingCoilModel = "Electric";
360 58 : heatingCoil.HCoilType_Num = HVAC::Coil_HeatingElectric;
361 :
362 58 : heatingCoil.Efficiency = Numbers(1);
363 58 : heatingCoil.NominalCapacity = Numbers(2);
364 58 : errFlag = false;
365 58 : heatingCoil.AirInletNodeNum = GetOnlySingleNode(state,
366 58 : Alphas(3),
367 : errFlag,
368 : DataLoopNode::ConnectionObjectType::CoilHeatingElectric,
369 58 : Alphas(1),
370 : DataLoopNode::NodeFluidType::Air,
371 : DataLoopNode::ConnectionType::Inlet,
372 : NodeInputManager::CompFluidStream::Primary,
373 : DataLoopNode::ObjectIsNotParent);
374 58 : state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound;
375 58 : errFlag = false;
376 58 : heatingCoil.AirOutletNodeNum = GetOnlySingleNode(state,
377 58 : Alphas(4),
378 : errFlag,
379 : DataLoopNode::ConnectionObjectType::CoilHeatingElectric,
380 58 : Alphas(1),
381 : DataLoopNode::NodeFluidType::Air,
382 : DataLoopNode::ConnectionType::Outlet,
383 : NodeInputManager::CompFluidStream::Primary,
384 : DataLoopNode::ObjectIsNotParent);
385 58 : state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound;
386 :
387 58 : BranchNodeConnections::TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(3), Alphas(4), "Air Nodes");
388 :
389 58 : errFlag = false;
390 58 : heatingCoil.TempSetPointNodeNum = GetOnlySingleNode(state,
391 58 : Alphas(5),
392 : errFlag,
393 : DataLoopNode::ConnectionObjectType::CoilHeatingElectric,
394 58 : Alphas(1),
395 : DataLoopNode::NodeFluidType::Air,
396 : DataLoopNode::ConnectionType::Sensor,
397 : NodeInputManager::CompFluidStream::Primary,
398 : DataLoopNode::ObjectIsNotParent);
399 58 : state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound;
400 :
401 : // Setup Report variables for the Electric Coils
402 : // CurrentModuleObject = "Coil:Heating:Electric"
403 116 : SetupOutputVariable(state,
404 : "Heating Coil Heating Energy",
405 : Constant::Units::J,
406 58 : heatingCoil.HeatingCoilLoad,
407 : OutputProcessor::TimeStepType::System,
408 : OutputProcessor::StoreType::Sum,
409 58 : heatingCoil.Name,
410 : Constant::eResource::EnergyTransfer,
411 : OutputProcessor::Group::HVAC,
412 : OutputProcessor::EndUseCat::HeatingCoils);
413 116 : SetupOutputVariable(state,
414 : "Heating Coil Heating Rate",
415 : Constant::Units::W,
416 58 : heatingCoil.HeatingCoilRate,
417 : OutputProcessor::TimeStepType::System,
418 : OutputProcessor::StoreType::Average,
419 58 : heatingCoil.Name);
420 116 : SetupOutputVariable(state,
421 : "Heating Coil Electricity Energy",
422 : Constant::Units::J,
423 58 : heatingCoil.ElecUseLoad,
424 : OutputProcessor::TimeStepType::System,
425 : OutputProcessor::StoreType::Sum,
426 58 : heatingCoil.Name,
427 : Constant::eResource::Electricity,
428 : OutputProcessor::Group::HVAC,
429 : OutputProcessor::EndUseCat::Heating);
430 116 : SetupOutputVariable(state,
431 : "Heating Coil Electricity Rate",
432 : Constant::Units::W,
433 58 : heatingCoil.ElecUseRate,
434 : OutputProcessor::TimeStepType::System,
435 : OutputProcessor::StoreType::Average,
436 58 : heatingCoil.Name);
437 : }
438 :
439 : // Get the data for electric heating coils
440 132 : for (int ElecCoilNum = 1; ElecCoilNum <= state.dataHeatingCoils->NumElecCoilMultiStage; ++ElecCoilNum) {
441 :
442 9 : int CoilNum = state.dataHeatingCoils->NumElecCoil + ElecCoilNum;
443 9 : auto &heatingCoil = state.dataHeatingCoils->HeatingCoil(CoilNum);
444 9 : auto &heatingCoilNumericFields = state.dataHeatingCoils->HeatingCoilNumericFields(CoilNum);
445 :
446 9 : CurrentModuleObject = "Coil:Heating:Electric:MultiStage";
447 9 : heatingCoil.FuelType = Constant::eFuel::Electricity;
448 :
449 9 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
450 : CurrentModuleObject,
451 : ElecCoilNum,
452 : Alphas,
453 : NumAlphas,
454 : Numbers,
455 : NumNums,
456 : IOStat,
457 : lNumericBlanks,
458 : lAlphaBlanks,
459 : cAlphaFields,
460 : cNumericFields);
461 :
462 9 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
463 9 : heatingCoilNumericFields.FieldNames.allocate(state.dataHeatingCoils->MaxNums);
464 9 : heatingCoilNumericFields.FieldNames = cNumericFields;
465 :
466 : // InputErrorsFound will be set to True if problem was found, left untouched otherwise
467 9 : GlobalNames::VerifyUniqueCoilName(
468 9 : state, CurrentModuleObject, Alphas(1), state.dataHeatingCoils->InputErrorsFound, CurrentModuleObject + " Name");
469 9 : heatingCoil.Name = Alphas(1);
470 9 : if (lAlphaBlanks(2)) {
471 0 : heatingCoil.availSched = Sched::GetScheduleAlwaysOn(state);
472 9 : } else if ((heatingCoil.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
473 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
474 0 : state.dataHeatingCoils->InputErrorsFound = true;
475 : }
476 :
477 9 : heatingCoil.HeatingCoilType = "Heating";
478 9 : heatingCoil.HeatingCoilModel = "Electric:MultiStage";
479 9 : heatingCoil.HCoilType_Num = HVAC::Coil_HeatingElectric_MultiStage;
480 :
481 9 : heatingCoil.NumOfStages = static_cast<int>(Numbers(1));
482 :
483 9 : heatingCoil.MSEfficiency.allocate(heatingCoil.NumOfStages);
484 9 : heatingCoil.MSNominalCapacity.allocate(heatingCoil.NumOfStages);
485 :
486 27 : for (StageNum = 1; StageNum <= heatingCoil.NumOfStages; ++StageNum) {
487 :
488 18 : heatingCoil.MSEfficiency(StageNum) = Numbers(StageNum * 2);
489 18 : heatingCoil.MSNominalCapacity(StageNum) = Numbers(StageNum * 2 + 1);
490 : }
491 :
492 9 : errFlag = false;
493 9 : heatingCoil.AirInletNodeNum = GetOnlySingleNode(state,
494 9 : Alphas(3),
495 : errFlag,
496 : DataLoopNode::ConnectionObjectType::CoilHeatingElectricMultiStage,
497 9 : Alphas(1),
498 : DataLoopNode::NodeFluidType::Air,
499 : DataLoopNode::ConnectionType::Inlet,
500 : NodeInputManager::CompFluidStream::Primary,
501 : DataLoopNode::ObjectIsNotParent);
502 9 : state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound;
503 9 : errFlag = false;
504 9 : heatingCoil.AirOutletNodeNum = GetOnlySingleNode(state,
505 9 : Alphas(4),
506 : errFlag,
507 : DataLoopNode::ConnectionObjectType::CoilHeatingElectricMultiStage,
508 9 : Alphas(1),
509 : DataLoopNode::NodeFluidType::Air,
510 : DataLoopNode::ConnectionType::Outlet,
511 : NodeInputManager::CompFluidStream::Primary,
512 : DataLoopNode::ObjectIsNotParent);
513 9 : state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound;
514 :
515 9 : BranchNodeConnections::TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(3), Alphas(4), "Air Nodes");
516 :
517 9 : errFlag = false;
518 9 : heatingCoil.TempSetPointNodeNum = GetOnlySingleNode(state,
519 9 : Alphas(5),
520 : errFlag,
521 : DataLoopNode::ConnectionObjectType::CoilHeatingElectricMultiStage,
522 9 : Alphas(1),
523 : DataLoopNode::NodeFluidType::Air,
524 : DataLoopNode::ConnectionType::Sensor,
525 : NodeInputManager::CompFluidStream::Primary,
526 : DataLoopNode::ObjectIsNotParent);
527 9 : state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound;
528 :
529 : // Setup Report variables for the Electric Coils
530 : // CurrentModuleObject = "Coil:Heating:Electric:MultiStage"
531 18 : SetupOutputVariable(state,
532 : "Heating Coil Heating Energy",
533 : Constant::Units::J,
534 9 : heatingCoil.HeatingCoilLoad,
535 : OutputProcessor::TimeStepType::System,
536 : OutputProcessor::StoreType::Sum,
537 9 : heatingCoil.Name,
538 : Constant::eResource::EnergyTransfer,
539 : OutputProcessor::Group::HVAC,
540 : OutputProcessor::EndUseCat::HeatingCoils);
541 18 : SetupOutputVariable(state,
542 : "Heating Coil Heating Rate",
543 : Constant::Units::W,
544 9 : heatingCoil.HeatingCoilRate,
545 : OutputProcessor::TimeStepType::System,
546 : OutputProcessor::StoreType::Average,
547 9 : heatingCoil.Name);
548 18 : SetupOutputVariable(state,
549 : "Heating Coil Electricity Energy",
550 : Constant::Units::J,
551 9 : heatingCoil.ElecUseLoad,
552 : OutputProcessor::TimeStepType::System,
553 : OutputProcessor::StoreType::Sum,
554 9 : heatingCoil.Name,
555 : Constant::eResource::Electricity,
556 : OutputProcessor::Group::HVAC,
557 : OutputProcessor::EndUseCat::Heating);
558 18 : SetupOutputVariable(state,
559 : "Heating Coil Electricity Rate",
560 : Constant::Units::W,
561 9 : heatingCoil.ElecUseRate,
562 : OutputProcessor::TimeStepType::System,
563 : OutputProcessor::StoreType::Average,
564 9 : heatingCoil.Name);
565 : }
566 :
567 : // Get the data for for fuel heating coils
568 230 : for (int FuelCoilNum = 1; FuelCoilNum <= state.dataHeatingCoils->NumFuelCoil; ++FuelCoilNum) {
569 :
570 107 : int CoilNum = state.dataHeatingCoils->NumElecCoil + state.dataHeatingCoils->NumElecCoilMultiStage + FuelCoilNum;
571 107 : auto &heatingCoil = state.dataHeatingCoils->HeatingCoil(CoilNum);
572 107 : auto &heatingCoilNumericFields = state.dataHeatingCoils->HeatingCoilNumericFields(CoilNum);
573 :
574 107 : CurrentModuleObject = "Coil:Heating:Fuel";
575 :
576 107 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
577 : CurrentModuleObject,
578 : FuelCoilNum,
579 : Alphas,
580 : NumAlphas,
581 : Numbers,
582 : NumNums,
583 : IOStat,
584 : lNumericBlanks,
585 : lAlphaBlanks,
586 : cAlphaFields,
587 : cNumericFields);
588 :
589 107 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
590 107 : heatingCoilNumericFields.FieldNames.allocate(state.dataHeatingCoils->MaxNums);
591 107 : heatingCoilNumericFields.FieldNames = cNumericFields;
592 :
593 : // InputErrorsFound will be set to True if problem was found, left untouched otherwise
594 107 : GlobalNames::VerifyUniqueCoilName(
595 107 : state, CurrentModuleObject, Alphas(1), state.dataHeatingCoils->InputErrorsFound, CurrentModuleObject + " Name");
596 107 : heatingCoil.Name = Alphas(1);
597 107 : if (lAlphaBlanks(2)) {
598 13 : heatingCoil.availSched = Sched::GetScheduleAlwaysOn(state);
599 94 : } else if ((heatingCoil.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
600 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
601 0 : state.dataHeatingCoils->InputErrorsFound = true;
602 : }
603 :
604 107 : heatingCoil.HeatingCoilType = "Heating";
605 107 : heatingCoil.HeatingCoilModel = "Fuel";
606 107 : heatingCoil.HCoilType_Num = HVAC::Coil_HeatingGasOrOtherFuel;
607 :
608 107 : heatingCoil.FuelType = static_cast<Constant::eFuel>(getEnumValue(Constant::eFuelNamesUC, Alphas(3)));
609 107 : if (!(heatingCoil.FuelType == Constant::eFuel::NaturalGas || heatingCoil.FuelType == Constant::eFuel::Propane ||
610 3 : heatingCoil.FuelType == Constant::eFuel::Diesel || heatingCoil.FuelType == Constant::eFuel::Gasoline ||
611 3 : heatingCoil.FuelType == Constant::eFuel::FuelOilNo1 || heatingCoil.FuelType == Constant::eFuel::FuelOilNo2 ||
612 3 : heatingCoil.FuelType == Constant::eFuel::OtherFuel1 || heatingCoil.FuelType == Constant::eFuel::OtherFuel2 ||
613 2 : heatingCoil.FuelType == Constant::eFuel::Coal)) {
614 2 : ShowSevereError(state,
615 2 : format("{}{}: Invalid {} entered ={} for {}={}",
616 : RoutineName,
617 : CurrentModuleObject,
618 : cAlphaFields(3),
619 : Alphas(3),
620 : cAlphaFields(1),
621 : Alphas(1)));
622 1 : state.dataHeatingCoils->InputErrorsFound = true;
623 : }
624 107 : std::string const sFuelType(Constant::eFuelNames[static_cast<int>(heatingCoil.FuelType)]);
625 :
626 107 : heatingCoil.Efficiency = Numbers(1);
627 107 : heatingCoil.NominalCapacity = Numbers(2);
628 107 : errFlag = false;
629 107 : heatingCoil.AirInletNodeNum = GetOnlySingleNode(state,
630 107 : Alphas(4),
631 : errFlag,
632 : DataLoopNode::ConnectionObjectType::CoilHeatingFuel,
633 107 : Alphas(1),
634 : DataLoopNode::NodeFluidType::Air,
635 : DataLoopNode::ConnectionType::Inlet,
636 : NodeInputManager::CompFluidStream::Primary,
637 : DataLoopNode::ObjectIsNotParent);
638 107 : state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound;
639 107 : errFlag = false;
640 107 : heatingCoil.AirOutletNodeNum = GetOnlySingleNode(state,
641 107 : Alphas(5),
642 : errFlag,
643 : DataLoopNode::ConnectionObjectType::CoilHeatingFuel,
644 107 : Alphas(1),
645 : DataLoopNode::NodeFluidType::Air,
646 : DataLoopNode::ConnectionType::Outlet,
647 : NodeInputManager::CompFluidStream::Primary,
648 : DataLoopNode::ObjectIsNotParent);
649 107 : state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound;
650 :
651 107 : BranchNodeConnections::TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(4), Alphas(5), "Air Nodes");
652 :
653 107 : errFlag = false;
654 107 : heatingCoil.TempSetPointNodeNum = GetOnlySingleNode(state,
655 107 : Alphas(6),
656 : errFlag,
657 : DataLoopNode::ConnectionObjectType::CoilHeatingFuel,
658 107 : Alphas(1),
659 : DataLoopNode::NodeFluidType::Air,
660 : DataLoopNode::ConnectionType::Sensor,
661 : NodeInputManager::CompFluidStream::Primary,
662 : DataLoopNode::ObjectIsNotParent);
663 107 : state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound;
664 :
665 : // parasitic electric load associated with the fuel heating coil
666 107 : heatingCoil.ParasiticElecLoad = Numbers(3);
667 :
668 107 : heatingCoil.PLFCurveIndex = Curve::GetCurveIndex(state, Alphas(7)); // convert curve name to number
669 :
670 : // parasitic fuel load associated with the gas heating coil (standing pilot light)
671 107 : heatingCoil.ParasiticFuelCapacity = Numbers(4);
672 :
673 : // Setup Report variables for the Fuel Coils
674 : // CurrentModuleObject = "Coil:Heating:OtherFuel"
675 :
676 214 : SetupOutputVariable(state,
677 : "Heating Coil Heating Energy",
678 : Constant::Units::J,
679 107 : heatingCoil.HeatingCoilLoad,
680 : OutputProcessor::TimeStepType::System,
681 : OutputProcessor::StoreType::Sum,
682 107 : heatingCoil.Name,
683 : Constant::eResource::EnergyTransfer,
684 : OutputProcessor::Group::HVAC,
685 : OutputProcessor::EndUseCat::HeatingCoils);
686 214 : SetupOutputVariable(state,
687 : "Heating Coil Heating Rate",
688 : Constant::Units::W,
689 107 : heatingCoil.HeatingCoilRate,
690 : OutputProcessor::TimeStepType::System,
691 : OutputProcessor::StoreType::Average,
692 107 : heatingCoil.Name);
693 321 : SetupOutputVariable(state,
694 214 : format("Heating Coil {} Energy", sFuelType),
695 : Constant::Units::J,
696 107 : heatingCoil.FuelUseLoad,
697 : OutputProcessor::TimeStepType::System,
698 : OutputProcessor::StoreType::Sum,
699 107 : heatingCoil.Name,
700 107 : Constant::eFuel2eResource[(int)heatingCoil.FuelType],
701 : OutputProcessor::Group::HVAC,
702 : OutputProcessor::EndUseCat::Heating);
703 321 : SetupOutputVariable(state,
704 214 : format("Heating Coil {} Rate", sFuelType),
705 : Constant::Units::W,
706 107 : heatingCoil.FuelUseRate,
707 : OutputProcessor::TimeStepType::System,
708 : OutputProcessor::StoreType::Average,
709 107 : heatingCoil.Name);
710 214 : SetupOutputVariable(state,
711 : "Heating Coil Electricity Energy",
712 : Constant::Units::J,
713 107 : heatingCoil.ElecUseLoad,
714 : OutputProcessor::TimeStepType::System,
715 : OutputProcessor::StoreType::Sum,
716 107 : heatingCoil.Name,
717 : Constant::eResource::Electricity,
718 : OutputProcessor::Group::HVAC,
719 : OutputProcessor::EndUseCat::Heating);
720 214 : SetupOutputVariable(state,
721 : "Heating Coil Electricity Rate",
722 : Constant::Units::W,
723 107 : heatingCoil.ElecUseRate,
724 : OutputProcessor::TimeStepType::System,
725 : OutputProcessor::StoreType::Average,
726 107 : heatingCoil.Name);
727 214 : SetupOutputVariable(state,
728 : "Heating Coil Runtime Fraction",
729 : Constant::Units::None,
730 107 : heatingCoil.RTF,
731 : OutputProcessor::TimeStepType::System,
732 : OutputProcessor::StoreType::Average,
733 107 : heatingCoil.Name);
734 321 : SetupOutputVariable(state,
735 214 : "Heating Coil Ancillary " + sFuelType + " Rate",
736 : Constant::Units::W,
737 107 : heatingCoil.ParasiticFuelRate,
738 : OutputProcessor::TimeStepType::System,
739 : OutputProcessor::StoreType::Average,
740 107 : heatingCoil.Name);
741 321 : SetupOutputVariable(state,
742 214 : "Heating Coil Ancillary " + sFuelType + " Energy",
743 : Constant::Units::J,
744 107 : heatingCoil.ParasiticFuelConsumption,
745 : OutputProcessor::TimeStepType::System,
746 : OutputProcessor::StoreType::Sum,
747 107 : heatingCoil.Name,
748 107 : Constant::eFuel2eResource[(int)heatingCoil.FuelType],
749 : OutputProcessor::Group::HVAC,
750 : OutputProcessor::EndUseCat::Heating);
751 107 : }
752 :
753 : // Get the data for for gas multistage heating coils
754 126 : for (int FuelCoilNum = 1; FuelCoilNum <= state.dataHeatingCoils->NumGasCoilMultiStage; ++FuelCoilNum) {
755 :
756 3 : int CoilNum = state.dataHeatingCoils->NumElecCoil + state.dataHeatingCoils->NumElecCoilMultiStage + state.dataHeatingCoils->NumFuelCoil +
757 3 : FuelCoilNum;
758 3 : auto &heatingCoil = state.dataHeatingCoils->HeatingCoil(CoilNum);
759 3 : auto &heatingCoilNumericFields = state.dataHeatingCoils->HeatingCoilNumericFields(CoilNum);
760 3 : CurrentModuleObject = "Coil:Heating:Gas:MultiStage";
761 3 : heatingCoil.FuelType = Constant::eFuel::NaturalGas;
762 :
763 3 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
764 : CurrentModuleObject,
765 : FuelCoilNum,
766 : Alphas,
767 : NumAlphas,
768 : Numbers,
769 : NumNums,
770 : IOStat,
771 : lNumericBlanks,
772 : lAlphaBlanks,
773 : cAlphaFields,
774 : cNumericFields);
775 :
776 3 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
777 :
778 3 : heatingCoilNumericFields.FieldNames.allocate(state.dataHeatingCoils->MaxNums);
779 3 : heatingCoilNumericFields.FieldNames = cNumericFields;
780 :
781 : // InputErrorsFound will be set to True if problem was found, left untouched otherwise
782 3 : GlobalNames::VerifyUniqueCoilName(
783 3 : state, CurrentModuleObject, Alphas(1), state.dataHeatingCoils->InputErrorsFound, CurrentModuleObject + " Name");
784 3 : heatingCoil.Name = Alphas(1);
785 :
786 3 : if (lAlphaBlanks(2)) {
787 0 : heatingCoil.availSched = Sched::GetScheduleAlwaysOn(state);
788 3 : } else if ((heatingCoil.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
789 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
790 0 : state.dataHeatingCoils->InputErrorsFound = true;
791 : }
792 :
793 3 : heatingCoil.HeatingCoilType = "Heating";
794 3 : heatingCoil.HeatingCoilModel = "Gas:MultiStage";
795 3 : heatingCoil.HCoilType_Num = HVAC::Coil_HeatingGas_MultiStage;
796 :
797 3 : heatingCoil.ParasiticFuelCapacity = Numbers(1);
798 :
799 3 : heatingCoil.NumOfStages = static_cast<int>(Numbers(2));
800 :
801 3 : heatingCoil.MSEfficiency.allocate(heatingCoil.NumOfStages);
802 3 : heatingCoil.MSNominalCapacity.allocate(heatingCoil.NumOfStages);
803 3 : heatingCoil.MSParasiticElecLoad.allocate(heatingCoil.NumOfStages);
804 :
805 8 : for (StageNum = 1; StageNum <= heatingCoil.NumOfStages; ++StageNum) {
806 :
807 5 : heatingCoil.MSEfficiency(StageNum) = Numbers(StageNum * 3);
808 5 : heatingCoil.MSNominalCapacity(StageNum) = Numbers(StageNum * 3 + 1);
809 5 : heatingCoil.MSParasiticElecLoad(StageNum) = Numbers(StageNum * 3 + 2);
810 : }
811 :
812 3 : errFlag = false;
813 3 : heatingCoil.AirInletNodeNum = GetOnlySingleNode(state,
814 3 : Alphas(3),
815 : errFlag,
816 : DataLoopNode::ConnectionObjectType::CoilHeatingGasMultiStage,
817 3 : Alphas(1),
818 : DataLoopNode::NodeFluidType::Air,
819 : DataLoopNode::ConnectionType::Inlet,
820 : NodeInputManager::CompFluidStream::Primary,
821 : DataLoopNode::ObjectIsNotParent);
822 3 : state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound;
823 3 : errFlag = false;
824 3 : heatingCoil.AirOutletNodeNum = GetOnlySingleNode(state,
825 3 : Alphas(4),
826 : errFlag,
827 : DataLoopNode::ConnectionObjectType::CoilHeatingGasMultiStage,
828 3 : Alphas(1),
829 : DataLoopNode::NodeFluidType::Air,
830 : DataLoopNode::ConnectionType::Outlet,
831 : NodeInputManager::CompFluidStream::Primary,
832 : DataLoopNode::ObjectIsNotParent);
833 3 : state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound;
834 :
835 3 : BranchNodeConnections::TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(3), Alphas(4), "Air Nodes");
836 :
837 3 : errFlag = false;
838 3 : heatingCoil.TempSetPointNodeNum = GetOnlySingleNode(state,
839 3 : Alphas(5),
840 : errFlag,
841 : DataLoopNode::ConnectionObjectType::CoilHeatingGasMultiStage,
842 3 : Alphas(1),
843 : DataLoopNode::NodeFluidType::Air,
844 : DataLoopNode::ConnectionType::Sensor,
845 : NodeInputManager::CompFluidStream::Primary,
846 : DataLoopNode::ObjectIsNotParent);
847 3 : state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound;
848 :
849 : // parasitic electric load associated with the gas heating coil
850 3 : heatingCoil.ParasiticElecLoad = Numbers(10);
851 :
852 3 : heatingCoil.PLFCurveIndex = Curve::GetCurveIndex(state, Alphas(6)); // convert curve name to number
853 :
854 : // parasitic gas load associated with the gas heating coil (standing pilot light)
855 :
856 : // Setup Report variables for the Gas Coils
857 : // CurrentModuleObject = "Coil:Heating:Gas:MultiStage"
858 6 : SetupOutputVariable(state,
859 : "Heating Coil Heating Energy",
860 : Constant::Units::J,
861 3 : heatingCoil.HeatingCoilLoad,
862 : OutputProcessor::TimeStepType::System,
863 : OutputProcessor::StoreType::Sum,
864 3 : heatingCoil.Name,
865 : Constant::eResource::EnergyTransfer,
866 : OutputProcessor::Group::HVAC,
867 : OutputProcessor::EndUseCat::HeatingCoils);
868 6 : SetupOutputVariable(state,
869 : "Heating Coil Heating Rate",
870 : Constant::Units::W,
871 3 : heatingCoil.HeatingCoilRate,
872 : OutputProcessor::TimeStepType::System,
873 : OutputProcessor::StoreType::Average,
874 3 : heatingCoil.Name);
875 6 : SetupOutputVariable(state,
876 : "Heating Coil NaturalGas Energy",
877 : Constant::Units::J,
878 3 : heatingCoil.FuelUseLoad,
879 : OutputProcessor::TimeStepType::System,
880 : OutputProcessor::StoreType::Sum,
881 3 : heatingCoil.Name,
882 : Constant::eResource::NaturalGas,
883 : OutputProcessor::Group::HVAC,
884 : OutputProcessor::EndUseCat::Heating);
885 6 : SetupOutputVariable(state,
886 : "Heating Coil NaturalGas Rate",
887 : Constant::Units::W,
888 3 : heatingCoil.FuelUseRate,
889 : OutputProcessor::TimeStepType::System,
890 : OutputProcessor::StoreType::Average,
891 3 : heatingCoil.Name);
892 6 : SetupOutputVariable(state,
893 : "Heating Coil Electricity Energy",
894 : Constant::Units::J,
895 3 : heatingCoil.ElecUseLoad,
896 : OutputProcessor::TimeStepType::System,
897 : OutputProcessor::StoreType::Sum,
898 3 : heatingCoil.Name,
899 : Constant::eResource::Electricity,
900 : OutputProcessor::Group::HVAC,
901 : OutputProcessor::EndUseCat::Heating);
902 6 : SetupOutputVariable(state,
903 : "Heating Coil Electricity Rate",
904 : Constant::Units::W,
905 3 : heatingCoil.ElecUseRate,
906 : OutputProcessor::TimeStepType::System,
907 : OutputProcessor::StoreType::Average,
908 3 : heatingCoil.Name);
909 6 : SetupOutputVariable(state,
910 : "Heating Coil Runtime Fraction",
911 : Constant::Units::None,
912 3 : heatingCoil.RTF,
913 : OutputProcessor::TimeStepType::System,
914 : OutputProcessor::StoreType::Average,
915 3 : heatingCoil.Name);
916 6 : SetupOutputVariable(state,
917 : "Heating Coil Ancillary NaturalGas Rate",
918 : Constant::Units::W,
919 3 : heatingCoil.ParasiticFuelRate,
920 : OutputProcessor::TimeStepType::System,
921 : OutputProcessor::StoreType::Average,
922 3 : heatingCoil.Name);
923 6 : SetupOutputVariable(state,
924 : "Heating Coil Ancillary NaturalGas Energy",
925 : Constant::Units::J,
926 3 : heatingCoil.ParasiticFuelConsumption,
927 : OutputProcessor::TimeStepType::System,
928 : OutputProcessor::StoreType::Sum,
929 3 : heatingCoil.Name,
930 : Constant::eResource::NaturalGas,
931 : OutputProcessor::Group::HVAC,
932 : OutputProcessor::EndUseCat::Heating);
933 : }
934 :
935 : // Get the data for for desuperheater heating coils
936 124 : for (int DesuperheaterCoilNum = 1; DesuperheaterCoilNum <= state.dataHeatingCoils->NumDesuperheaterCoil; ++DesuperheaterCoilNum) {
937 :
938 1 : int CoilNum = state.dataHeatingCoils->NumElecCoil + state.dataHeatingCoils->NumElecCoilMultiStage + state.dataHeatingCoils->NumFuelCoil +
939 1 : state.dataHeatingCoils->NumGasCoilMultiStage + DesuperheaterCoilNum;
940 1 : auto &heatingCoil = state.dataHeatingCoils->HeatingCoil(CoilNum);
941 1 : auto &heatingCoilNumericFields = state.dataHeatingCoils->HeatingCoilNumericFields(CoilNum);
942 1 : CurrentModuleObject = "Coil:Heating:Desuperheater";
943 1 : heatingCoil.FuelType = Constant::eFuel::Electricity;
944 :
945 1 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
946 : CurrentModuleObject,
947 : DesuperheaterCoilNum,
948 : Alphas,
949 : NumAlphas,
950 : Numbers,
951 : NumNums,
952 : IOStat,
953 : lNumericBlanks,
954 : lAlphaBlanks,
955 : cAlphaFields,
956 : cNumericFields);
957 :
958 1 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
959 1 : heatingCoilNumericFields.FieldNames.allocate(state.dataHeatingCoils->MaxNums);
960 1 : heatingCoilNumericFields.FieldNames = cNumericFields;
961 :
962 : // InputErrorsFound will be set to True if problem was found, left untouched otherwise
963 1 : GlobalNames::VerifyUniqueCoilName(
964 1 : state, CurrentModuleObject, Alphas(1), state.dataHeatingCoils->InputErrorsFound, CurrentModuleObject + " Name");
965 1 : heatingCoil.Name = Alphas(1);
966 1 : if (lAlphaBlanks(2)) {
967 0 : heatingCoil.availSched = Sched::GetScheduleAlwaysOn(state);
968 1 : } else if ((heatingCoil.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
969 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
970 0 : state.dataHeatingCoils->InputErrorsFound = true;
971 1 : } else if (!heatingCoil.availSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) {
972 0 : Sched::ShowSevereBadMinMax(state, eoh, cAlphaFields(2), Alphas(2), Clusive::In, 0.0, Clusive::In, 1.0);
973 0 : state.dataHeatingCoils->InputErrorsFound = true;
974 : }
975 :
976 1 : heatingCoil.HeatingCoilType = "Heating";
977 1 : heatingCoil.HeatingCoilModel = "Desuperheater";
978 1 : heatingCoil.HCoilType_Num = HVAC::Coil_HeatingDesuperheater;
979 :
980 : // HeatingCoil(CoilNum)%Efficiency = Numbers(1)
981 : //(Numbers(1)) error limits checked and defaults applied on efficiency after
982 : // identifying souce type.
983 :
984 1 : errFlag = false;
985 1 : heatingCoil.AirInletNodeNum = GetOnlySingleNode(state,
986 1 : Alphas(3),
987 : errFlag,
988 : DataLoopNode::ConnectionObjectType::CoilHeatingDesuperheater,
989 1 : Alphas(1),
990 : DataLoopNode::NodeFluidType::Air,
991 : DataLoopNode::ConnectionType::Inlet,
992 : NodeInputManager::CompFluidStream::Primary,
993 : DataLoopNode::ObjectIsNotParent);
994 1 : state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound;
995 1 : errFlag = false;
996 1 : heatingCoil.AirOutletNodeNum = GetOnlySingleNode(state,
997 1 : Alphas(4),
998 : errFlag,
999 : DataLoopNode::ConnectionObjectType::CoilHeatingDesuperheater,
1000 1 : Alphas(1),
1001 : DataLoopNode::NodeFluidType::Air,
1002 : DataLoopNode::ConnectionType::Outlet,
1003 : NodeInputManager::CompFluidStream::Primary,
1004 : DataLoopNode::ObjectIsNotParent);
1005 1 : state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound;
1006 :
1007 1 : BranchNodeConnections::TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(3), Alphas(4), "Air Nodes");
1008 :
1009 2 : if ((Util::SameString(Alphas(5), "Refrigeration:Condenser:AirCooled")) ||
1010 2 : (Util::SameString(Alphas(5), "Refrigeration:Condenser:EvaporativeCooled")) ||
1011 2 : (Util::SameString(Alphas(5), "Refrigeration:Condenser:WaterCooled"))) {
1012 0 : if (lNumericBlanks(1)) {
1013 0 : heatingCoil.Efficiency = 0.8;
1014 : } else {
1015 0 : heatingCoil.Efficiency = Numbers(1);
1016 0 : if (Numbers(1) < 0.0 || Numbers(1) > 0.9) {
1017 0 : ShowSevereError(
1018 : state,
1019 0 : format("{}, \"{}\" heat reclaim recovery efficiency must be >= 0 and <=0.9", CurrentModuleObject, heatingCoil.Name));
1020 0 : state.dataHeatingCoils->InputErrorsFound = true;
1021 : }
1022 : }
1023 : } else {
1024 1 : if (lNumericBlanks(1)) {
1025 0 : heatingCoil.Efficiency = 0.25;
1026 : } else {
1027 1 : heatingCoil.Efficiency = Numbers(1);
1028 1 : if (Numbers(1) < 0.0 || Numbers(1) > 0.3) {
1029 0 : ShowSevereError(
1030 : state,
1031 0 : format("{}, \"{}\" heat reclaim recovery efficiency must be >= 0 and <=0.3", CurrentModuleObject, heatingCoil.Name));
1032 0 : state.dataHeatingCoils->InputErrorsFound = true;
1033 : }
1034 : }
1035 : }
1036 :
1037 : // Find the DX equipment index associated with the desuperheater heating coil.
1038 : // The CoilNum may not be found here when zone heating equip. exists. Check again in InitHeatingCoil.
1039 : // (when zone equipment heating coils are included in the input, the air loop DX equipment has not yet been read in)
1040 1 : if (Util::SameString(Alphas(5), "Refrigeration:CompressorRack")) {
1041 1 : heatingCoil.ReclaimHeatingSource = HeatObjTypes::COMPRESSORRACK_REFRIGERATEDCASE;
1042 2 : RefrigeratedCase::GetRefrigeratedRackIndex(
1043 1 : state, Alphas(6), heatingCoil.ReclaimHeatingSourceIndexNum, DataHeatBalance::RefrigSystemType::Rack, DXCoilErrFlag, Alphas(5));
1044 1 : if (heatingCoil.ReclaimHeatingSourceIndexNum > 0) {
1045 1 : if (allocated(state.dataHeatBal->HeatReclaimRefrigeratedRack)) {
1046 : DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
1047 1 : state.dataHeatBal->HeatReclaimRefrigeratedRack(heatingCoil.ReclaimHeatingSourceIndexNum);
1048 1 : if (!allocated(HeatReclaim.HVACDesuperheaterReclaimedHeat)) {
1049 1 : HeatReclaim.HVACDesuperheaterReclaimedHeat.allocate(state.dataHeatingCoils->NumDesuperheaterCoil);
1050 1 : std::fill(HeatReclaim.HVACDesuperheaterReclaimedHeat.begin(), HeatReclaim.HVACDesuperheaterReclaimedHeat.end(), 0.0);
1051 : }
1052 1 : HeatReclaim.ReclaimEfficiencyTotal += heatingCoil.Efficiency;
1053 1 : if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
1054 0 : ShowSevereError(
1055 : state,
1056 0 : format("{}, \"{}\" sum of heat reclaim recovery efficiencies from the same source coil: \"{} \" cannot be over 0.3",
1057 : HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num),
1058 0 : heatingCoil.Name,
1059 0 : heatingCoil.ReclaimHeatingCoilName));
1060 : }
1061 1 : state.dataHeatingCoils->ValidSourceType(CoilNum) = true;
1062 : }
1063 : }
1064 0 : } else if ((Util::SameString(Alphas(5), "Refrigeration:Condenser:AirCooled")) ||
1065 0 : (Util::SameString(Alphas(5), "Refrigeration:Condenser:EvaporativeCooled")) ||
1066 0 : (Util::SameString(Alphas(5), "Refrigeration:Condenser:WaterCooled"))) {
1067 0 : heatingCoil.ReclaimHeatingSource = HeatObjTypes::CONDENSER_REFRIGERATION;
1068 0 : RefrigeratedCase::GetRefrigeratedRackIndex(state,
1069 0 : Alphas(6),
1070 0 : heatingCoil.ReclaimHeatingSourceIndexNum,
1071 : DataHeatBalance::RefrigSystemType::Detailed,
1072 : DXCoilErrFlag,
1073 0 : Alphas(5));
1074 0 : if (heatingCoil.ReclaimHeatingSourceIndexNum > 0) {
1075 0 : if (allocated(state.dataHeatBal->HeatReclaimRefrigCondenser)) {
1076 : DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
1077 0 : state.dataHeatBal->HeatReclaimRefrigCondenser(heatingCoil.ReclaimHeatingSourceIndexNum);
1078 0 : if (!allocated(HeatReclaim.HVACDesuperheaterReclaimedHeat)) {
1079 0 : HeatReclaim.HVACDesuperheaterReclaimedHeat.allocate(state.dataHeatingCoils->NumDesuperheaterCoil);
1080 0 : std::fill(HeatReclaim.HVACDesuperheaterReclaimedHeat.begin(), HeatReclaim.HVACDesuperheaterReclaimedHeat.end(), 0.0);
1081 : }
1082 0 : HeatReclaim.ReclaimEfficiencyTotal += heatingCoil.Efficiency;
1083 0 : if (HeatReclaim.ReclaimEfficiencyTotal > 0.9) {
1084 0 : ShowSevereError(
1085 : state,
1086 0 : format("{}, \"{}\" sum of heat reclaim recovery efficiencies from the same source coil: \"{} \" cannot be over 0.9",
1087 : HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num),
1088 0 : heatingCoil.Name,
1089 0 : heatingCoil.ReclaimHeatingCoilName));
1090 : }
1091 0 : state.dataHeatingCoils->ValidSourceType(CoilNum) = true;
1092 : }
1093 : }
1094 0 : } else if (Util::SameString(Alphas(5), "Coil:Cooling:DX:SingleSpeed")) {
1095 0 : heatingCoil.ReclaimHeatingSource = HeatObjTypes::COIL_DX_COOLING;
1096 0 : DXCoils::GetDXCoilIndex(state, Alphas(6), heatingCoil.ReclaimHeatingSourceIndexNum, DXCoilErrFlag, Alphas(5));
1097 0 : if (heatingCoil.ReclaimHeatingSourceIndexNum > 0) {
1098 0 : if (allocated(state.dataHeatBal->HeatReclaimDXCoil)) {
1099 : DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
1100 0 : state.dataHeatBal->HeatReclaimDXCoil(heatingCoil.ReclaimHeatingSourceIndexNum);
1101 0 : if (!allocated(HeatReclaim.HVACDesuperheaterReclaimedHeat)) {
1102 0 : HeatReclaim.HVACDesuperheaterReclaimedHeat.allocate(state.dataHeatingCoils->NumDesuperheaterCoil);
1103 0 : std::fill(HeatReclaim.HVACDesuperheaterReclaimedHeat.begin(), HeatReclaim.HVACDesuperheaterReclaimedHeat.end(), 0.0);
1104 : }
1105 0 : HeatReclaim.ReclaimEfficiencyTotal += heatingCoil.Efficiency;
1106 0 : if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
1107 0 : ShowSevereError(
1108 : state,
1109 0 : format("{}, \"{}\" sum of heat reclaim recovery efficiencies from the same source coil: \"{} \" cannot be over 0.3",
1110 : HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num),
1111 0 : heatingCoil.Name,
1112 0 : heatingCoil.ReclaimHeatingCoilName));
1113 : }
1114 0 : state.dataHeatingCoils->ValidSourceType(CoilNum) = true;
1115 : }
1116 : }
1117 0 : if (heatingCoil.ReclaimHeatingSourceIndexNum > 0) state.dataHeatingCoils->ValidSourceType(CoilNum) = true;
1118 0 : } else if (Util::SameString(Alphas(5), "Coil:Cooling:DX:VariableSpeed")) {
1119 0 : heatingCoil.ReclaimHeatingSource = HeatObjTypes::COIL_DX_VARIABLE_COOLING;
1120 0 : heatingCoil.ReclaimHeatingSourceIndexNum = VariableSpeedCoils::GetCoilIndexVariableSpeed(state, Alphas(5), Alphas(6), DXCoilErrFlag);
1121 0 : if (heatingCoil.ReclaimHeatingSourceIndexNum > 0) {
1122 0 : if (allocated(state.dataHeatBal->HeatReclaimVS_Coil)) {
1123 : DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
1124 0 : state.dataHeatBal->HeatReclaimVS_Coil(heatingCoil.ReclaimHeatingSourceIndexNum);
1125 0 : if (!allocated(HeatReclaim.HVACDesuperheaterReclaimedHeat)) {
1126 0 : HeatReclaim.HVACDesuperheaterReclaimedHeat.allocate(state.dataHeatingCoils->NumDesuperheaterCoil);
1127 0 : std::fill(HeatReclaim.HVACDesuperheaterReclaimedHeat.begin(), HeatReclaim.HVACDesuperheaterReclaimedHeat.end(), 0.0);
1128 : }
1129 0 : HeatReclaim.ReclaimEfficiencyTotal += heatingCoil.Efficiency;
1130 0 : if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
1131 0 : ShowSevereError(
1132 : state,
1133 0 : format("{}, \"{}\" sum of heat reclaim recovery efficiencies from the same source coil: \"{} \" cannot be over 0.3",
1134 : HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num),
1135 0 : heatingCoil.Name,
1136 0 : heatingCoil.ReclaimHeatingCoilName));
1137 : }
1138 0 : state.dataHeatingCoils->ValidSourceType(CoilNum) = true;
1139 : }
1140 : }
1141 0 : } else if (Util::SameString(Alphas(5), "Coil:Cooling:DX:TwoSpeed")) {
1142 0 : heatingCoil.ReclaimHeatingSource = HeatObjTypes::COIL_DX_MULTISPEED;
1143 0 : DXCoils::GetDXCoilIndex(state, Alphas(6), heatingCoil.ReclaimHeatingSourceIndexNum, DXCoilErrFlag, Alphas(5));
1144 0 : if (heatingCoil.ReclaimHeatingSourceIndexNum > 0) {
1145 0 : if (allocated(state.dataHeatBal->HeatReclaimDXCoil)) {
1146 : DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
1147 0 : state.dataHeatBal->HeatReclaimDXCoil(heatingCoil.ReclaimHeatingSourceIndexNum);
1148 0 : if (!allocated(HeatReclaim.HVACDesuperheaterReclaimedHeat)) {
1149 0 : HeatReclaim.HVACDesuperheaterReclaimedHeat.allocate(state.dataHeatingCoils->NumDesuperheaterCoil);
1150 0 : std::fill(HeatReclaim.HVACDesuperheaterReclaimedHeat.begin(), HeatReclaim.HVACDesuperheaterReclaimedHeat.end(), 0.0);
1151 : }
1152 0 : HeatReclaim.ReclaimEfficiencyTotal += heatingCoil.Efficiency;
1153 0 : if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
1154 0 : ShowSevereError(
1155 : state,
1156 0 : format("{}, \"{}\" sum of heat reclaim recovery efficiencies from the same source coil: \"{} \" cannot be over 0.3",
1157 : HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num),
1158 0 : heatingCoil.Name,
1159 0 : heatingCoil.ReclaimHeatingCoilName));
1160 : }
1161 0 : state.dataHeatingCoils->ValidSourceType(CoilNum) = true;
1162 : }
1163 : }
1164 0 : } else if (Util::SameString(Alphas(5), "Coil:Cooling:DX:TwoStageWithHumidityControlMode")) {
1165 0 : heatingCoil.ReclaimHeatingSource = HeatObjTypes::COIL_DX_MULTIMODE;
1166 0 : DXCoils::GetDXCoilIndex(state, Alphas(6), heatingCoil.ReclaimHeatingSourceIndexNum, DXCoilErrFlag, Alphas(5));
1167 0 : if (heatingCoil.ReclaimHeatingSourceIndexNum > 0) {
1168 0 : if (allocated(state.dataHeatBal->HeatReclaimDXCoil)) {
1169 : DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
1170 0 : state.dataHeatBal->HeatReclaimDXCoil(heatingCoil.ReclaimHeatingSourceIndexNum);
1171 0 : if (!allocated(HeatReclaim.HVACDesuperheaterReclaimedHeat)) {
1172 0 : HeatReclaim.HVACDesuperheaterReclaimedHeat.allocate(state.dataHeatingCoils->NumDesuperheaterCoil);
1173 0 : std::fill(HeatReclaim.HVACDesuperheaterReclaimedHeat.begin(), HeatReclaim.HVACDesuperheaterReclaimedHeat.end(), 0.0);
1174 : }
1175 0 : HeatReclaim.ReclaimEfficiencyTotal += heatingCoil.Efficiency;
1176 0 : if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
1177 0 : ShowSevereError(
1178 : state,
1179 0 : format(R"({}, "{}" sum of heat reclaim recovery efficiencies from the same source coil: "{} " cannot be over 0.3)",
1180 : HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num),
1181 0 : heatingCoil.Name,
1182 0 : heatingCoil.ReclaimHeatingCoilName));
1183 : }
1184 0 : state.dataHeatingCoils->ValidSourceType(CoilNum) = true;
1185 : }
1186 : }
1187 0 : } else if (Util::SameString(Alphas(5), "Coil:Cooling:DX")) {
1188 0 : heatingCoil.ReclaimHeatingSource = HeatObjTypes::COIL_COOLING_DX_NEW;
1189 0 : heatingCoil.ReclaimHeatingSourceIndexNum = CoilCoolingDX::factory(state, Alphas(6));
1190 0 : if (heatingCoil.ReclaimHeatingSourceIndexNum < 0) {
1191 0 : ShowSevereError(
1192 0 : state, format("{}={}, could not find desuperheater coil {}={}", CurrentModuleObject, heatingCoil.Name, Alphas(5), Alphas(6)));
1193 0 : state.dataHeatingCoils->InputErrorsFound = true;
1194 : }
1195 : DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
1196 0 : state.dataCoilCoolingDX->coilCoolingDXs[heatingCoil.ReclaimHeatingSourceIndexNum].reclaimHeat;
1197 0 : if (!allocated(HeatReclaim.HVACDesuperheaterReclaimedHeat)) {
1198 0 : HeatReclaim.HVACDesuperheaterReclaimedHeat.allocate(state.dataHeatingCoils->NumDesuperheaterCoil);
1199 0 : std::fill(HeatReclaim.HVACDesuperheaterReclaimedHeat.begin(), HeatReclaim.HVACDesuperheaterReclaimedHeat.end(), 0.0);
1200 : }
1201 0 : HeatReclaim.ReclaimEfficiencyTotal += heatingCoil.Efficiency;
1202 0 : if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
1203 0 : ShowSevereError(
1204 : state,
1205 0 : format("{}, \"{}\" sum of heat reclaim recovery efficiencies from the same source coil: \"{}\" cannot be over 0.3",
1206 : HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num),
1207 0 : heatingCoil.Name,
1208 0 : heatingCoil.ReclaimHeatingCoilName));
1209 : }
1210 0 : state.dataHeatingCoils->ValidSourceType(CoilNum) = true;
1211 : } else {
1212 0 : ShowSevereError(
1213 : state,
1214 0 : format("{}, \"{}\" valid desuperheater heat source object type not found: {}", CurrentModuleObject, heatingCoil.Name, Alphas(5)));
1215 0 : ShowContinueError(state, "Valid desuperheater heat source objects are:");
1216 0 : ShowContinueError(state,
1217 : "Refrigeration:CompressorRack, Coil:Cooling:DX:SingleSpeed, Refrigeration:Condenser:AirCooled, "
1218 : "Refrigeration:Condenser:EvaporativeCooled, Refrigeration:Condenser:WaterCooled,Coil:Cooling:DX:TwoSpeed, and "
1219 : "Coil:Cooling:DX:TwoStageWithHumidityControlMode");
1220 0 : state.dataHeatingCoils->InputErrorsFound = true;
1221 : }
1222 :
1223 1 : heatingCoil.ReclaimHeatingCoilName = Alphas(6);
1224 :
1225 1 : errFlag = false;
1226 1 : heatingCoil.TempSetPointNodeNum = GetOnlySingleNode(state,
1227 1 : Alphas(7),
1228 : errFlag,
1229 : DataLoopNode::ConnectionObjectType::CoilHeatingDesuperheater,
1230 1 : Alphas(1),
1231 : DataLoopNode::NodeFluidType::Air,
1232 : DataLoopNode::ConnectionType::Sensor,
1233 : NodeInputManager::CompFluidStream::Primary,
1234 : DataLoopNode::ObjectIsNotParent);
1235 1 : state.dataHeatingCoils->InputErrorsFound = errFlag || state.dataHeatingCoils->InputErrorsFound;
1236 :
1237 : // parasitic electric load associated with the desuperheater heating coil
1238 1 : heatingCoil.ParasiticElecLoad = Numbers(2);
1239 :
1240 1 : if (Numbers(2) < 0.0) {
1241 0 : ShowSevereError(state, format("{}, \"{}\" parasitic electric load must be >= 0", CurrentModuleObject, heatingCoil.Name));
1242 0 : state.dataHeatingCoils->InputErrorsFound = true;
1243 : }
1244 :
1245 : // Setup Report variables for the Desuperheater Heating Coils
1246 : // CurrentModuleObject = "Coil:Heating:Desuperheater"
1247 2 : SetupOutputVariable(state,
1248 : "Heating Coil Heating Energy",
1249 : Constant::Units::J,
1250 1 : heatingCoil.HeatingCoilLoad,
1251 : OutputProcessor::TimeStepType::System,
1252 : OutputProcessor::StoreType::Sum,
1253 1 : heatingCoil.Name,
1254 : Constant::eResource::EnergyTransfer,
1255 : OutputProcessor::Group::HVAC,
1256 : OutputProcessor::EndUseCat::HeatingCoils);
1257 2 : SetupOutputVariable(state,
1258 : "Heating Coil Heating Rate",
1259 : Constant::Units::W,
1260 1 : heatingCoil.HeatingCoilRate,
1261 : OutputProcessor::TimeStepType::System,
1262 : OutputProcessor::StoreType::Average,
1263 1 : heatingCoil.Name);
1264 2 : SetupOutputVariable(state,
1265 : "Heating Coil Electricity Energy",
1266 : Constant::Units::J,
1267 1 : heatingCoil.ElecUseLoad,
1268 : OutputProcessor::TimeStepType::System,
1269 : OutputProcessor::StoreType::Sum,
1270 1 : heatingCoil.Name,
1271 : Constant::eResource::Electricity,
1272 : OutputProcessor::Group::HVAC,
1273 : OutputProcessor::EndUseCat::Heating);
1274 2 : SetupOutputVariable(state,
1275 : "Heating Coil Electricity Rate",
1276 : Constant::Units::W,
1277 1 : heatingCoil.ElecUseRate,
1278 : OutputProcessor::TimeStepType::System,
1279 : OutputProcessor::StoreType::Average,
1280 1 : heatingCoil.Name);
1281 2 : SetupOutputVariable(state,
1282 : "Heating Coil Runtime Fraction",
1283 : Constant::Units::None,
1284 1 : heatingCoil.RTF,
1285 : OutputProcessor::TimeStepType::System,
1286 : OutputProcessor::StoreType::Average,
1287 1 : heatingCoil.Name);
1288 : }
1289 :
1290 123 : if (state.dataHeatingCoils->InputErrorsFound) {
1291 2 : ShowFatalError(state, format("{}Errors found in input. Program terminates.", RoutineName));
1292 : }
1293 :
1294 122 : Alphas.deallocate();
1295 122 : cAlphaFields.deallocate();
1296 122 : cNumericFields.deallocate();
1297 122 : Numbers.deallocate();
1298 122 : lAlphaBlanks.deallocate();
1299 122 : lNumericBlanks.deallocate();
1300 129 : }
1301 :
1302 233160 : void InitHeatingCoil(EnergyPlusData &state, int const CoilNum, bool const FirstHVACIteration, Real64 const QCoilRequired)
1303 : {
1304 :
1305 : // SUBROUTINE INFORMATION:
1306 : // AUTHOR Richard J. Liesen
1307 : // DATE WRITTEN May 2000
1308 : // MODIFIED B. Griffith, May 2009 added EMS setpoint check
1309 :
1310 : // PURPOSE OF THIS SUBROUTINE:
1311 : // This subroutine is for initializations of the HeatingCoil Components.
1312 :
1313 : // METHODOLOGY EMPLOYED:
1314 : // Uses the status flags to trigger initializations.
1315 :
1316 233160 : auto &heatingCoil = state.dataHeatingCoils->HeatingCoil(CoilNum);
1317 :
1318 233160 : if (state.dataHeatingCoils->MyOneTimeFlag) {
1319 : // initialize the environment and sizing flags
1320 94 : Real64 numHeatingCoils = state.dataHeatingCoils->NumHeatingCoils;
1321 94 : state.dataHeatingCoils->MyEnvrnFlag.allocate(numHeatingCoils);
1322 94 : state.dataHeatingCoils->MySizeFlag.allocate(numHeatingCoils);
1323 94 : state.dataHeatingCoils->ShowSingleWarning.allocate(numHeatingCoils);
1324 94 : state.dataHeatingCoils->MySPTestFlag.allocate(numHeatingCoils);
1325 94 : state.dataHeatingCoils->MyEnvrnFlag = true;
1326 94 : state.dataHeatingCoils->MySizeFlag = true;
1327 94 : state.dataHeatingCoils->ShowSingleWarning = true;
1328 94 : state.dataHeatingCoils->MyOneTimeFlag = false;
1329 94 : state.dataHeatingCoils->MySPTestFlag = true;
1330 : }
1331 :
1332 233160 : if (!state.dataGlobal->SysSizingCalc && state.dataHeatingCoils->MySizeFlag(CoilNum)) {
1333 : // for each coil, do the sizing once.
1334 98 : SizeHeatingCoil(state, CoilNum);
1335 :
1336 98 : state.dataHeatingCoils->MySizeFlag(CoilNum) = false;
1337 : }
1338 :
1339 : // Do the following initializations (every time step): This should be the info from
1340 : // the previous components outlets or the node data in this section.
1341 : // First set the conditions for the air into the coil model
1342 233160 : int AirOutletNodeNum = heatingCoil.AirOutletNodeNum;
1343 233160 : int ControlNodeNum = heatingCoil.TempSetPointNodeNum;
1344 233160 : auto const &airInletNode = state.dataLoopNodes->Node(heatingCoil.AirInletNodeNum);
1345 233160 : auto const &airOutletNode = state.dataLoopNodes->Node(AirOutletNodeNum);
1346 233160 : heatingCoil.InletAirMassFlowRate = airInletNode.MassFlowRate;
1347 233160 : heatingCoil.InletAirTemp = airInletNode.Temp;
1348 233160 : heatingCoil.InletAirHumRat = airInletNode.HumRat;
1349 233160 : heatingCoil.InletAirEnthalpy = airInletNode.Enthalpy;
1350 :
1351 : // Set the reporting variables to zero at each timestep.
1352 233160 : heatingCoil.HeatingCoilLoad = 0.0;
1353 233160 : heatingCoil.FuelUseLoad = 0.0;
1354 233160 : heatingCoil.ElecUseLoad = 0.0;
1355 233160 : heatingCoil.RTF = 0.0;
1356 :
1357 : // If a temperature setpoint controlled coil must set the desired outlet temp everytime
1358 233160 : if (ControlNodeNum == 0) {
1359 167841 : heatingCoil.DesiredOutletTemp = 0.0;
1360 : } else {
1361 65319 : auto const &controlNode = state.dataLoopNodes->Node(ControlNodeNum);
1362 65319 : heatingCoil.DesiredOutletTemp =
1363 65319 : controlNode.TempSetPoint - ((ControlNodeNum == AirOutletNodeNum) ? 0 : (controlNode.Temp - airOutletNode.Temp));
1364 : }
1365 :
1366 65486 : if (QCoilRequired == DataLoopNode::SensedLoadFlagValue && state.dataHeatingCoils->MySPTestFlag(CoilNum) &&
1367 298646 : heatingCoil.HCoilType_Num != HVAC::Coil_HeatingElectric_MultiStage && heatingCoil.HCoilType_Num != HVAC::Coil_HeatingGas_MultiStage) {
1368 :
1369 : // If the coil is temperature controlled (QCoilReq == -999.0), both a control node and setpoint are required.
1370 77 : if (!state.dataGlobal->SysSizingCalc && state.dataHVACGlobal->DoSetPointTest) {
1371 : // 3 possibilities here:
1372 : // 1) TempSetPointNodeNum .GT. 0 and TempSetPoint /= SensedNodeFlagValue, this is correct
1373 : // 2) TempSetPointNodeNum .EQ. 0, this is not correct, control node is required
1374 : // 3) TempSetPointNodeNum .GT. 0 and TempSetPoint == SensedNodeFlagValue, this is not correct, missing temperature setpoint
1375 : // test 2) here (fatal message)
1376 15 : if (ControlNodeNum == 0) {
1377 0 : ShowSevereError(state, format("{} \"{}\"", HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num), heatingCoil.Name));
1378 0 : ShowContinueError(state, "... Missing control node for heating coil.");
1379 0 : ShowContinueError(state, "... enter a control node name in the coil temperature setpoint node field for this heating coil.");
1380 0 : ShowContinueError(state, "... use a Setpoint Manager to establish a setpoint at the coil temperature setpoint node.");
1381 0 : state.dataHeatingCoils->HeatingCoilFatalError = true;
1382 : // test 3) here (fatal message)
1383 : } else { // IF(ControlNode .GT. 0)THEN
1384 15 : auto const &controlNode = state.dataLoopNodes->Node(ControlNodeNum);
1385 15 : if (controlNode.TempSetPoint == DataLoopNode::SensedNodeFlagValue) {
1386 0 : if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
1387 0 : ShowSevereError(state, format("{} \"{}\"", HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num), heatingCoil.Name));
1388 0 : ShowContinueError(state, "... Missing temperature setpoint for heating coil.");
1389 0 : ShowContinueError(state, "... use a Setpoint Manager to establish a setpoint at the coil temperature setpoint node.");
1390 0 : state.dataHeatingCoils->HeatingCoilFatalError = true;
1391 : } else {
1392 0 : EMSManager::CheckIfNodeSetPointManagedByEMS(
1393 0 : state, ControlNodeNum, HVAC::CtrlVarType::Temp, state.dataHeatingCoils->HeatingCoilFatalError);
1394 0 : if (state.dataHeatingCoils->HeatingCoilFatalError) {
1395 0 : ShowSevereError(state, format("{} \"{}\"", HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num), heatingCoil.Name));
1396 0 : ShowContinueError(state, "... Missing temperature setpoint for heating coil.");
1397 0 : ShowContinueError(state, "... use a Setpoint Manager to establish a setpoint at the coil temperature setpoint node.");
1398 0 : ShowContinueError(state, "... or use an EMS Actuator to establish a setpoint at the coil temperature setpoint node.");
1399 : }
1400 : }
1401 : }
1402 : }
1403 15 : state.dataHeatingCoils->MySPTestFlag(CoilNum) = false;
1404 : }
1405 233083 : } else if (state.dataHeatingCoils->MySPTestFlag(CoilNum)) {
1406 : // If QCoilReq /= SensedLoadFlagValue, the coil is load controlled and does not require a control node
1407 : // 4 possibilities here:
1408 : // 1) TempSetPointNodeNum .EQ. 0 and TempSetPoint == SensedNodeFlagValue, this is correct
1409 : // 2) TempSetPointNodeNum .EQ. 0 and TempSetPoint /= SensedNodeFlagValue, this may be correct,
1410 : // (if no control node specified and SP on heating coil outlet do not show warning, other SP managers may be using SP)
1411 : // 3) TempSetPointNodeNum .GT. 0 and TempSetPoint == SensedNodeFlagValue, control node not required if load based control
1412 : // 4) TempSetPointNodeNum .GT. 0 and TempSetPoint /= SensedNodeFlagValue, control node not required if load based control
1413 : // test 3) and 4) here (warning only)
1414 106 : if (ControlNodeNum > 0) {
1415 4 : ShowWarningError(state, format("{} \"{}\"", HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num), heatingCoil.Name));
1416 8 : ShowContinueError(state, " The \"Temperature Setpoint Node Name\" input is not required for this heating coil.");
1417 12 : ShowContinueError(state, " Leaving the input field \"Temperature Setpoint Node Name\" blank will eliminate this warning.");
1418 : }
1419 106 : state.dataHeatingCoils->MySPTestFlag(CoilNum) = false;
1420 : }
1421 :
1422 : // delay fatal error until all coils are called
1423 233160 : if (!FirstHVACIteration && state.dataHeatingCoils->HeatingCoilFatalError) {
1424 0 : ShowFatalError(state, "... errors found in heating coil input.");
1425 : }
1426 :
1427 : // Find the heating source index for the desuperheater heating coil if not already found. This occurs when zone heating
1428 : // equip. exists. (when zone equipment heating coils are included in the input, the air loop DX equipment has not yet been read)
1429 : // Issue a single warning if the coil is not found and continue the simulation
1430 233160 : if (!state.dataHeatingCoils->ValidSourceType(CoilNum) && (heatingCoil.HCoilType_Num == HVAC::Coil_HeatingDesuperheater) &&
1431 0 : state.dataHeatingCoils->ShowSingleWarning(CoilNum)) {
1432 0 : ++state.dataHeatingCoils->ValidSourceTypeCounter;
1433 0 : switch (heatingCoil.ReclaimHeatingSource) {
1434 0 : case HeatObjTypes::COMPRESSORRACK_REFRIGERATEDCASE: {
1435 0 : for (int RackNum = 1; RackNum <= state.dataRefrigCase->NumRefrigeratedRacks; ++RackNum) {
1436 0 : if (!Util::SameString(state.dataHeatBal->HeatReclaimRefrigeratedRack(RackNum).Name, heatingCoil.ReclaimHeatingCoilName)) continue;
1437 0 : heatingCoil.ReclaimHeatingSourceIndexNum = RackNum;
1438 0 : if (allocated(state.dataHeatBal->HeatReclaimRefrigeratedRack)) {
1439 : DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
1440 0 : state.dataHeatBal->HeatReclaimRefrigeratedRack(heatingCoil.ReclaimHeatingSourceIndexNum);
1441 0 : if (!allocated(HeatReclaim.HVACDesuperheaterReclaimedHeat)) {
1442 0 : HeatReclaim.HVACDesuperheaterReclaimedHeat.allocate(state.dataHeatingCoils->NumDesuperheaterCoil);
1443 0 : std::fill(HeatReclaim.HVACDesuperheaterReclaimedHeat.begin(), HeatReclaim.HVACDesuperheaterReclaimedHeat.end(), 0.0);
1444 0 : HeatReclaim.ReclaimEfficiencyTotal += heatingCoil.Efficiency;
1445 0 : if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
1446 0 : ShowSevereError(
1447 : state,
1448 0 : format(R"({}, "{}" sum of heat reclaim recovery efficiencies from the same source coil: "{}" cannot be over 0.3)",
1449 : HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num),
1450 0 : heatingCoil.Name,
1451 0 : heatingCoil.ReclaimHeatingCoilName));
1452 : }
1453 : }
1454 0 : state.dataHeatingCoils->ValidSourceType(CoilNum) = true;
1455 : }
1456 0 : break;
1457 : }
1458 0 : } break;
1459 0 : case HeatObjTypes::CONDENSER_REFRIGERATION: {
1460 0 : for (int CondNum = 1; CondNum <= state.dataRefrigCase->NumRefrigCondensers; ++CondNum) {
1461 0 : if (!Util::SameString(state.dataHeatBal->HeatReclaimRefrigCondenser(CondNum).Name, heatingCoil.ReclaimHeatingCoilName)) continue;
1462 0 : heatingCoil.ReclaimHeatingSourceIndexNum = CondNum;
1463 0 : if (allocated(state.dataHeatBal->HeatReclaimRefrigCondenser)) {
1464 : DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
1465 0 : state.dataHeatBal->HeatReclaimRefrigCondenser(heatingCoil.ReclaimHeatingSourceIndexNum);
1466 0 : if (!allocated(HeatReclaim.HVACDesuperheaterReclaimedHeat)) {
1467 0 : HeatReclaim.HVACDesuperheaterReclaimedHeat.allocate(state.dataHeatingCoils->NumDesuperheaterCoil);
1468 0 : std::fill(HeatReclaim.HVACDesuperheaterReclaimedHeat.begin(), HeatReclaim.HVACDesuperheaterReclaimedHeat.end(), 0.0);
1469 0 : HeatReclaim.ReclaimEfficiencyTotal += heatingCoil.Efficiency;
1470 0 : if (HeatReclaim.ReclaimEfficiencyTotal > 0.9) {
1471 0 : ShowSevereError(
1472 : state,
1473 0 : format(R"({}, "{}" sum of heat reclaim recovery efficiencies from the same source coil: "{}" cannot be over 0.9)",
1474 : HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num),
1475 0 : heatingCoil.Name,
1476 0 : heatingCoil.ReclaimHeatingCoilName));
1477 : }
1478 : }
1479 0 : state.dataHeatingCoils->ValidSourceType(CoilNum) = true;
1480 : }
1481 0 : break;
1482 : }
1483 0 : } break;
1484 0 : case HeatObjTypes::COIL_DX_COOLING:
1485 : case HeatObjTypes::COIL_DX_MULTISPEED:
1486 : case HeatObjTypes::COIL_DX_MULTIMODE: {
1487 0 : for (int DXCoilNum = 1; DXCoilNum <= state.dataDXCoils->NumDXCoils; ++DXCoilNum) {
1488 0 : if (!Util::SameString(state.dataHeatBal->HeatReclaimDXCoil(DXCoilNum).Name, heatingCoil.ReclaimHeatingCoilName)) continue;
1489 0 : heatingCoil.ReclaimHeatingSourceIndexNum = DXCoilNum;
1490 0 : if (allocated(state.dataHeatBal->HeatReclaimDXCoil)) {
1491 : DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
1492 0 : state.dataHeatBal->HeatReclaimDXCoil(heatingCoil.ReclaimHeatingSourceIndexNum);
1493 0 : if (!allocated(HeatReclaim.HVACDesuperheaterReclaimedHeat)) {
1494 0 : HeatReclaim.HVACDesuperheaterReclaimedHeat.allocate(state.dataHeatingCoils->NumDesuperheaterCoil);
1495 0 : std::fill(HeatReclaim.HVACDesuperheaterReclaimedHeat.begin(), HeatReclaim.HVACDesuperheaterReclaimedHeat.end(), 0.0);
1496 0 : HeatReclaim.ReclaimEfficiencyTotal += heatingCoil.Efficiency;
1497 0 : if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
1498 0 : ShowSevereError(
1499 : state,
1500 0 : format(R"({}, "{}" sum of heat reclaim recovery efficiencies from the same source coil: "{}" cannot be over 0.3)",
1501 : HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num),
1502 0 : heatingCoil.Name,
1503 0 : heatingCoil.ReclaimHeatingCoilName));
1504 : }
1505 : }
1506 0 : state.dataHeatingCoils->ValidSourceType(CoilNum) = true;
1507 : }
1508 0 : break;
1509 : }
1510 0 : } break;
1511 0 : case HeatObjTypes::COIL_DX_VARIABLE_COOLING: {
1512 0 : for (int DXCoilNum = 1; DXCoilNum <= state.dataVariableSpeedCoils->NumVarSpeedCoils; ++DXCoilNum) {
1513 0 : if (!Util::SameString(state.dataHeatBal->HeatReclaimVS_Coil(DXCoilNum).Name, heatingCoil.ReclaimHeatingCoilName)) continue;
1514 0 : heatingCoil.ReclaimHeatingSourceIndexNum = DXCoilNum;
1515 0 : if (allocated(state.dataHeatBal->HeatReclaimVS_Coil)) {
1516 : DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
1517 0 : state.dataHeatBal->HeatReclaimVS_Coil(heatingCoil.ReclaimHeatingSourceIndexNum);
1518 0 : if (!allocated(HeatReclaim.HVACDesuperheaterReclaimedHeat)) {
1519 0 : HeatReclaim.HVACDesuperheaterReclaimedHeat.allocate(state.dataHeatingCoils->NumDesuperheaterCoil);
1520 0 : std::fill(HeatReclaim.HVACDesuperheaterReclaimedHeat.begin(), HeatReclaim.HVACDesuperheaterReclaimedHeat.end(), 0.0);
1521 0 : HeatReclaim.ReclaimEfficiencyTotal += heatingCoil.Efficiency;
1522 0 : if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
1523 0 : ShowSevereError(
1524 : state,
1525 0 : format(R"({}, "{}" sum of heat reclaim recovery efficiencies from the same source coil: "{}" cannot be over 0.3)",
1526 : HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num),
1527 0 : heatingCoil.Name,
1528 0 : heatingCoil.ReclaimHeatingCoilName));
1529 : }
1530 : }
1531 0 : state.dataHeatingCoils->ValidSourceType(CoilNum) = true;
1532 : }
1533 0 : break;
1534 : }
1535 : case HeatObjTypes::COIL_COOLING_DX_NEW:
1536 : DataHeatBalance::HeatReclaimDataBase &HeatReclaim =
1537 0 : state.dataCoilCoolingDX->coilCoolingDXs[heatingCoil.ReclaimHeatingSourceIndexNum].reclaimHeat;
1538 0 : if (!allocated(HeatReclaim.HVACDesuperheaterReclaimedHeat)) {
1539 0 : HeatReclaim.HVACDesuperheaterReclaimedHeat.allocate(state.dataHeatingCoils->NumDesuperheaterCoil);
1540 0 : std::fill(HeatReclaim.HVACDesuperheaterReclaimedHeat.begin(), HeatReclaim.HVACDesuperheaterReclaimedHeat.end(), 0.0);
1541 0 : HeatReclaim.ReclaimEfficiencyTotal += heatingCoil.Efficiency;
1542 0 : if (HeatReclaim.ReclaimEfficiencyTotal > 0.3) {
1543 0 : ShowSevereError(
1544 : state,
1545 0 : format("{}, \"{}\" sum of heat reclaim recovery efficiencies from the same source coil: \"{}\" cannot be over 0.3",
1546 : HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num),
1547 0 : heatingCoil.Name,
1548 0 : heatingCoil.ReclaimHeatingCoilName));
1549 : }
1550 : }
1551 0 : state.dataHeatingCoils->ValidSourceType(CoilNum) = true;
1552 0 : break;
1553 : } break;
1554 0 : default:
1555 0 : break;
1556 : }
1557 0 : if ((state.dataHeatingCoils->ValidSourceTypeCounter > state.dataHeatingCoils->NumDesuperheaterCoil * 2) &&
1558 0 : state.dataHeatingCoils->ShowSingleWarning(CoilNum) && !state.dataHeatingCoils->ValidSourceType(CoilNum)) {
1559 0 : ShowWarningError(state,
1560 0 : format("Coil:Heating:Desuperheater, \"{}\" desuperheater heat source object name not found: {}",
1561 0 : heatingCoil.Name,
1562 0 : heatingCoil.ReclaimHeatingCoilName));
1563 0 : ShowContinueError(state, " Desuperheater heating coil is not modeled and simulation continues.");
1564 0 : state.dataHeatingCoils->ShowSingleWarning(CoilNum) = false;
1565 : }
1566 : }
1567 233160 : }
1568 :
1569 98 : void SizeHeatingCoil(EnergyPlusData &state, int const CoilNum)
1570 : {
1571 :
1572 : // SUBROUTINE INFORMATION:
1573 : // AUTHOR Fred Buhl
1574 : // DATE WRITTEN January 2002
1575 : // MODIFIED August 2013 Daeho Kang, add component sizing table entries
1576 : // RE-ENGINEERED Mar 2014 FSEC, moved calculations to common routine in BaseSizer
1577 :
1578 : // PURPOSE OF THIS SUBROUTINE:
1579 : // This subroutine is for sizing Heating Coil Components for which nominal capcities have not been
1580 : // specified in the input.
1581 :
1582 : // METHODOLOGY EMPLOYED:
1583 : // Obtains heating capacities from the zone or system sizing arrays or parent object as necessary.
1584 : // heating coil or other routine sets up any required data variables (e.g., DataCoilIsSuppHeater, TermUnitPIU, etc.),
1585 : // sizing variable (e.g., HeatingCoil( CoilNum ).NominalCapacity in this routine since it can be multi-staged and new routine
1586 : // currently only handles single values) and associated string representing that sizing variable.
1587 : // Sizer functions handles the actual sizing and reporting.
1588 :
1589 : // SUBROUTINE PARAMETER DEFINITIONS:
1590 : static constexpr std::string_view RoutineName("SizeHeatingCoil: "); // include trailing blank space
1591 :
1592 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1593 98 : std::string CompName; // component name
1594 98 : std::string CompType; // component type
1595 98 : std::string SizingString; // input field sizing description (e.g., Nominal Capacity)
1596 98 : bool bPRINT = true; // TRUE if sizing is reported to output (eio)
1597 : Real64 NominalCapacityDes; // Autosized nominal capacity for reporting
1598 : Real64 NominalCapacityUser; // Hardsized nominal capacity for reporting
1599 : Real64 TempCap; // autosized capacity of heating coil [W]
1600 98 : int FieldNum = 2; // IDD numeric field number where input field description is found
1601 98 : int NumCoilsSized = 0; // counter used to deallocate temporary string array after all coils have been sized
1602 :
1603 98 : auto &heatingCoil = state.dataHeatingCoils->HeatingCoil(CoilNum);
1604 :
1605 98 : if (heatingCoil.HCoilType_Num == HVAC::Coil_HeatingElectric_MultiStage) {
1606 9 : FieldNum = 1 + (heatingCoil.NumOfStages * 2);
1607 9 : TempCap = heatingCoil.MSNominalCapacity(heatingCoil.NumOfStages);
1608 89 : } else if (heatingCoil.HCoilType_Num == HVAC::Coil_HeatingGas_MultiStage) {
1609 3 : FieldNum = 1 + (heatingCoil.NumOfStages * 3);
1610 3 : TempCap = heatingCoil.MSNominalCapacity(heatingCoil.NumOfStages);
1611 86 : } else if (heatingCoil.HCoilType_Num == HVAC::Coil_HeatingDesuperheater) {
1612 1 : return; // no autosizable inputs for desupterheater
1613 : } else {
1614 85 : FieldNum = 2;
1615 85 : TempCap = heatingCoil.NominalCapacity;
1616 : }
1617 97 : SizingString = state.dataHeatingCoils->HeatingCoilNumericFields(CoilNum).FieldNames(FieldNum) + " [W]";
1618 97 : CompType = "Coil:" + heatingCoil.HeatingCoilType + ':' + heatingCoil.HeatingCoilModel;
1619 97 : CompName = heatingCoil.Name;
1620 97 : state.dataSize->DataCoilIsSuppHeater = state.dataHeatingCoils->CoilIsSuppHeater; // set global instead of using optional argument
1621 97 : state.dataSize->DataCoolCoilCap =
1622 : 0.0; // global only used for heat pump heating coils, non-HP heating coils are sized with other global variables
1623 :
1624 97 : if (TempCap == DataSizing::AutoSize) {
1625 42 : if (heatingCoil.DesiccantRegenerationCoil) {
1626 3 : state.dataSize->DataDesicRegCoil = true;
1627 3 : bPRINT = false;
1628 3 : state.dataSize->DataDesicDehumNum = heatingCoil.DesiccantDehumNum;
1629 3 : HeatingCoilDesAirInletTempSizer sizerHeatingDesInletTemp;
1630 3 : bool ErrorsFound = false;
1631 3 : sizerHeatingDesInletTemp.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
1632 3 : state.dataSize->DataDesInletAirTemp = sizerHeatingDesInletTemp.size(state, DataSizing::AutoSize, ErrorsFound);
1633 :
1634 3 : HeatingCoilDesAirOutletTempSizer sizerHeatingDesOutletTemp;
1635 3 : ErrorsFound = false;
1636 3 : sizerHeatingDesOutletTemp.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
1637 3 : state.dataSize->DataDesOutletAirTemp = sizerHeatingDesOutletTemp.size(state, DataSizing::AutoSize, ErrorsFound);
1638 :
1639 3 : if (state.dataSize->CurOASysNum > 0) {
1640 1 : auto &OASysEqSizing(state.dataSize->OASysEqSizing(state.dataSize->CurOASysNum));
1641 1 : OASysEqSizing.AirFlow = true;
1642 1 : OASysEqSizing.AirVolFlow = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesOutAirVolFlow;
1643 : }
1644 3 : state.dataSize->DataDesicDehumNum = 0;
1645 3 : bPRINT = true;
1646 3 : }
1647 : }
1648 97 : bool errorsFound = false;
1649 97 : HeatingCapacitySizer sizerHeatingCapacity;
1650 97 : sizerHeatingCapacity.overrideSizingString(SizingString);
1651 97 : sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, bPRINT, RoutineName);
1652 97 : TempCap = sizerHeatingCapacity.size(state, TempCap, errorsFound);
1653 97 : state.dataSize->DataCoilIsSuppHeater = false; // reset global to false so other heating coils are not affected
1654 97 : state.dataSize->DataDesicRegCoil = false; // reset global to false so other heating coils are not affected
1655 97 : state.dataSize->DataDesInletAirTemp = 0.0; // reset global data to zero so other heating coils are not
1656 97 : state.dataSize->DataDesOutletAirTemp = 0.0; // reset global data to zero so other heating coils are not affected
1657 :
1658 97 : if (heatingCoil.HCoilType_Num == HVAC::Coil_HeatingElectric_MultiStage || heatingCoil.HCoilType_Num == HVAC::Coil_HeatingGas_MultiStage) {
1659 12 : heatingCoil.MSNominalCapacity(heatingCoil.NumOfStages) = TempCap;
1660 12 : bool IsAutoSize = false;
1661 : int NumOfStages; // total number of stages of multi-stage heating coil
1662 12 : if (any_eq(heatingCoil.MSNominalCapacity, DataSizing::AutoSize)) {
1663 3 : IsAutoSize = true;
1664 : }
1665 12 : if (IsAutoSize) {
1666 3 : NumOfStages = heatingCoil.NumOfStages;
1667 6 : for (int StageNum = NumOfStages - 1; StageNum >= 1; --StageNum) {
1668 3 : bool ThisStageAutoSize = false;
1669 3 : FieldNum = 1 + StageNum * ((heatingCoil.HCoilType_Num == HVAC::Coil_HeatingElectric_MultiStage) ? 2 : 3);
1670 3 : SizingString = state.dataHeatingCoils->HeatingCoilNumericFields(CoilNum).FieldNames(FieldNum) + " [W]";
1671 3 : if (heatingCoil.MSNominalCapacity(StageNum) == DataSizing::AutoSize) {
1672 3 : ThisStageAutoSize = true;
1673 : }
1674 3 : NominalCapacityDes = TempCap * StageNum / NumOfStages;
1675 3 : if (ThisStageAutoSize) {
1676 3 : heatingCoil.MSNominalCapacity(StageNum) = NominalCapacityDes;
1677 3 : BaseSizer::reportSizerOutput(state, CompType, CompName, "Design Size " + SizingString, NominalCapacityDes);
1678 : } else {
1679 0 : if (heatingCoil.MSNominalCapacity(StageNum) > 0.0 && NominalCapacityDes > 0.0) {
1680 0 : NominalCapacityUser = TempCap * StageNum / NumOfStages; // HeatingCoil( CoilNum ).MSNominalCapacity( StageNum );
1681 0 : BaseSizer::reportSizerOutput(state,
1682 : CompType,
1683 : CompName,
1684 0 : "Design Size " + SizingString,
1685 : NominalCapacityDes,
1686 0 : "User-Specified " + SizingString,
1687 : NominalCapacityUser);
1688 0 : if (state.dataGlobal->DisplayExtraWarnings) {
1689 0 : if ((std::abs(NominalCapacityDes - NominalCapacityUser) / NominalCapacityUser) >
1690 0 : state.dataSize->AutoVsHardSizingThreshold) {
1691 0 : ShowMessage(state,
1692 0 : format("SizeHeatingCoil: Potential issue with equipment sizing for {}, {}", CompType, CompName));
1693 0 : ShowContinueError(state, format("User-Specified Nominal Capacity of {:.2R} [W]", NominalCapacityUser));
1694 0 : ShowContinueError(state, format("differs from Design Size Nominal Capacity of {:.2R} [W]", NominalCapacityDes));
1695 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1696 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1697 : }
1698 : }
1699 : }
1700 : }
1701 : }
1702 : } else { // No autosize
1703 9 : NumOfStages = heatingCoil.NumOfStages;
1704 17 : for (int StageNum = NumOfStages - 1; StageNum >= 1; --StageNum) {
1705 8 : if (heatingCoil.MSNominalCapacity(StageNum) > 0.0) {
1706 24 : BaseSizer::reportSizerOutput(
1707 16 : state, CompType, CompName, "User-Specified " + SizingString, heatingCoil.MSNominalCapacity(StageNum));
1708 : }
1709 : }
1710 : }
1711 : // Ensure capacity at lower Stage must be lower or equal to the capacity at higher Stage.
1712 23 : for (int StageNum = 1; StageNum <= heatingCoil.NumOfStages - 1; ++StageNum) {
1713 11 : if (heatingCoil.MSNominalCapacity(StageNum) > heatingCoil.MSNominalCapacity(StageNum + 1)) {
1714 0 : ShowSevereError(state,
1715 0 : format("SizeHeatingCoil: {} {}, Stage {} Nominal Capacity ({:.2R} W) must be less than or equal to Stage {} "
1716 : "Nominal Capacity ({:.2R} W).",
1717 0 : heatingCoil.HeatingCoilType,
1718 0 : heatingCoil.Name,
1719 : StageNum,
1720 : heatingCoil.MSNominalCapacity(StageNum),
1721 0 : StageNum + 1,
1722 : heatingCoil.MSNominalCapacity(StageNum + 1)));
1723 0 : ShowFatalError(state, "Preceding conditions cause termination.");
1724 : }
1725 : }
1726 12 : } else { // not a multi-speed coil
1727 85 : heatingCoil.NominalCapacity = TempCap;
1728 : }
1729 :
1730 97 : if (++NumCoilsSized == state.dataHeatingCoils->NumHeatingCoils)
1731 44 : state.dataHeatingCoils->HeatingCoilNumericFields.deallocate(); // remove temporary array for field names at end of sizing
1732 :
1733 : // create predefined report entries
1734 97 : switch (heatingCoil.HCoilType_Num) {
1735 39 : case HVAC::Coil_HeatingElectric: {
1736 39 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchHeatCoilType, heatingCoil.Name, "Coil:Heating:Electric");
1737 78 : OutputReportPredefined::PreDefTableEntry(
1738 39 : state, state.dataOutRptPredefined->pdchHeatCoilNomCap, heatingCoil.Name, heatingCoil.NominalCapacity);
1739 39 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchHeatCoilNomEff, heatingCoil.Name, heatingCoil.Efficiency);
1740 39 : } break;
1741 9 : case HVAC::Coil_HeatingElectric_MultiStage: {
1742 18 : OutputReportPredefined::PreDefTableEntry(
1743 9 : state, state.dataOutRptPredefined->pdchHeatCoilType, heatingCoil.Name, "Coil:Heating:Electric:MultiStage");
1744 18 : OutputReportPredefined::PreDefTableEntry(
1745 9 : state, state.dataOutRptPredefined->pdchHeatCoilNomCap, heatingCoil.Name, heatingCoil.MSNominalCapacity(heatingCoil.NumOfStages));
1746 18 : OutputReportPredefined::PreDefTableEntry(
1747 9 : state, state.dataOutRptPredefined->pdchHeatCoilNomEff, heatingCoil.Name, heatingCoil.MSEfficiency(heatingCoil.NumOfStages));
1748 9 : } break;
1749 46 : case HVAC::Coil_HeatingGasOrOtherFuel: {
1750 46 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchHeatCoilType, heatingCoil.Name, "Coil:Heating:Fuel");
1751 92 : OutputReportPredefined::PreDefTableEntry(
1752 46 : state, state.dataOutRptPredefined->pdchHeatCoilNomCap, heatingCoil.Name, heatingCoil.NominalCapacity);
1753 46 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchHeatCoilNomEff, heatingCoil.Name, heatingCoil.Efficiency);
1754 46 : } break;
1755 3 : case HVAC::Coil_HeatingGas_MultiStage: {
1756 6 : OutputReportPredefined::PreDefTableEntry(
1757 3 : state, state.dataOutRptPredefined->pdchHeatCoilType, heatingCoil.Name, "Coil:Heating:Gas:MultiStage");
1758 6 : OutputReportPredefined::PreDefTableEntry(
1759 3 : state, state.dataOutRptPredefined->pdchHeatCoilNomCap, heatingCoil.Name, heatingCoil.MSNominalCapacity(heatingCoil.NumOfStages));
1760 6 : OutputReportPredefined::PreDefTableEntry(
1761 3 : state, state.dataOutRptPredefined->pdchHeatCoilNomEff, heatingCoil.Name, heatingCoil.MSEfficiency(heatingCoil.NumOfStages));
1762 3 : } break;
1763 0 : case HVAC::Coil_HeatingDesuperheater: {
1764 0 : OutputReportPredefined::PreDefTableEntry(
1765 0 : state, state.dataOutRptPredefined->pdchHeatCoilType, heatingCoil.Name, "Coil:Heating:Desuperheater");
1766 0 : OutputReportPredefined::PreDefTableEntry(
1767 0 : state, state.dataOutRptPredefined->pdchHeatCoilNomCap, heatingCoil.Name, heatingCoil.NominalCapacity);
1768 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchHeatCoilNomEff, heatingCoil.Name, heatingCoil.Efficiency);
1769 0 : } break;
1770 0 : default:
1771 0 : break;
1772 : }
1773 :
1774 : // std 229 heating coils existing table adding new variables:
1775 : // pdchHeatCoilUsedAsSupHeat is now reported at coil selection report
1776 : // pdchHeatCoilAirloopName is now reported at coil selection report
1777 : // std 229 Coil Connections New table: now all reported at coil selection report
1778 100 : }
1779 :
1780 73698 : void CalcElectricHeatingCoil(EnergyPlusData &state,
1781 : int const CoilNum, // index to heating coil
1782 : Real64 &QCoilReq,
1783 : Real64 &QCoilActual, // coil load actually delivered (W)
1784 : HVAC::FanOp const fanOp, // fan operating mode
1785 : Real64 const PartLoadRatio // part-load ratio of heating coil
1786 : )
1787 : {
1788 : // SUBROUTINE INFORMATION:
1789 : // AUTHOR Rich Liesen
1790 : // DATE WRITTEN May 2000
1791 : // MODIFIED Jul. 2016, R. Zhang, Applied the coil supply air temperature sensor offset
1792 :
1793 : // PURPOSE OF THIS SUBROUTINE:
1794 : // Simulates a simple Electric heating coil with an efficiency
1795 :
1796 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1797 : Real64 AirMassFlow; // [kg/sec]
1798 : Real64 TempAirOut; // [C]
1799 : Real64 HeatingCoilLoad;
1800 : Real64 QCoilCap;
1801 :
1802 73698 : auto &heatingCoil = state.dataHeatingCoils->HeatingCoil(CoilNum);
1803 :
1804 73698 : Real64 Effic = heatingCoil.Efficiency;
1805 73698 : Real64 TempAirIn = heatingCoil.InletAirTemp;
1806 73698 : Real64 Win = heatingCoil.InletAirHumRat;
1807 73698 : Real64 TempSetPoint = heatingCoil.DesiredOutletTemp;
1808 :
1809 : // If there is a fault of coil SAT Sensor
1810 73698 : if (heatingCoil.FaultyCoilSATFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
1811 0 : (!state.dataGlobal->KickOffSimulation)) {
1812 : // calculate the sensor offset using fault information
1813 0 : int FaultIndex = heatingCoil.FaultyCoilSATIndex;
1814 0 : heatingCoil.FaultyCoilSATOffset = state.dataFaultsMgr->FaultsCoilSATSensor(FaultIndex).CalFaultOffsetAct(state);
1815 : // update the TempSetPoint
1816 0 : TempSetPoint -= heatingCoil.FaultyCoilSATOffset;
1817 : }
1818 :
1819 : // adjust mass flow rates for cycling fan cycling coil operation
1820 73698 : if (fanOp == HVAC::FanOp::Cycling) {
1821 61853 : if (PartLoadRatio > 0.0) {
1822 61465 : AirMassFlow = heatingCoil.InletAirMassFlowRate / PartLoadRatio;
1823 61465 : QCoilReq /= PartLoadRatio;
1824 : } else {
1825 388 : AirMassFlow = 0.0;
1826 : }
1827 : } else {
1828 11845 : AirMassFlow = heatingCoil.InletAirMassFlowRate;
1829 : }
1830 :
1831 73698 : Real64 CapacitanceAir = Psychrometrics::PsyCpAirFnW(Win) * AirMassFlow;
1832 :
1833 : // If the coil is operating there should be some heating capacitance
1834 : // across the coil, so do the simulation. If not set outlet to inlet and no load.
1835 : // Also the coil has to be scheduled to be available.
1836 :
1837 : // Control output to meet load QCoilReq (QCoilReq is passed in if load controlled, otherwise QCoilReq=-999)
1838 73698 : if ((AirMassFlow > 0.0 && heatingCoil.NominalCapacity > 0.0) && (heatingCoil.availSched->getCurrentVal() > 0.0) && (QCoilReq > 0.0)) {
1839 :
1840 : // check to see if the Required heating capacity is greater than the user specified capacity.
1841 3697 : if (QCoilReq > heatingCoil.NominalCapacity) {
1842 2 : QCoilCap = heatingCoil.NominalCapacity;
1843 : } else {
1844 3695 : QCoilCap = QCoilReq;
1845 : }
1846 :
1847 3697 : TempAirOut = TempAirIn + QCoilCap / CapacitanceAir;
1848 3697 : HeatingCoilLoad = QCoilCap;
1849 :
1850 : // The HeatingCoilLoad is the change in the enthalpy of the Heating
1851 3697 : heatingCoil.ElecUseLoad = HeatingCoilLoad / Effic;
1852 :
1853 : // Control coil output to meet a setpoint temperature.
1854 50320 : } else if ((AirMassFlow > 0.0 && heatingCoil.NominalCapacity > 0.0) && (heatingCoil.availSched->getCurrentVal() > 0.0) &&
1855 120321 : (QCoilReq == DataLoopNode::SensedLoadFlagValue) && (std::abs(TempSetPoint - TempAirIn) > HVAC::TempControlTol)) {
1856 :
1857 1926 : QCoilCap = CapacitanceAir * (TempSetPoint - TempAirIn);
1858 : // check to see if setpoint above enetering temperature. If not, set
1859 : // output to zero.
1860 1926 : if (QCoilCap <= 0.0) {
1861 129 : QCoilCap = 0.0;
1862 129 : TempAirOut = TempAirIn;
1863 : // check to see if the Required heating capacity is greater than the user
1864 : // specified capacity.
1865 1797 : } else if (QCoilCap > heatingCoil.NominalCapacity) {
1866 100 : QCoilCap = heatingCoil.NominalCapacity;
1867 100 : TempAirOut = TempAirIn + QCoilCap / CapacitanceAir;
1868 : } else {
1869 1697 : TempAirOut = TempSetPoint;
1870 : }
1871 :
1872 1926 : HeatingCoilLoad = QCoilCap;
1873 :
1874 : // The HeatingCoilLoad is the change in the enthalpy of the Heating
1875 1926 : heatingCoil.ElecUseLoad = HeatingCoilLoad / Effic;
1876 :
1877 : } else { // If not running Conditions do not change across coil from inlet to outlet
1878 :
1879 68075 : TempAirOut = TempAirIn;
1880 68075 : HeatingCoilLoad = 0.0;
1881 68075 : heatingCoil.ElecUseLoad = 0.0;
1882 : }
1883 :
1884 73698 : if (fanOp == HVAC::FanOp::Cycling) {
1885 61853 : heatingCoil.ElecUseLoad *= PartLoadRatio;
1886 61853 : HeatingCoilLoad *= PartLoadRatio;
1887 : }
1888 :
1889 73698 : heatingCoil.HeatingCoilLoad = HeatingCoilLoad;
1890 :
1891 : // Set the outlet conditions
1892 73698 : heatingCoil.OutletAirTemp = TempAirOut;
1893 :
1894 : // This HeatingCoil does not change the moisture or Mass Flow across the component
1895 73698 : heatingCoil.OutletAirHumRat = heatingCoil.InletAirHumRat;
1896 73698 : heatingCoil.OutletAirMassFlowRate = heatingCoil.InletAirMassFlowRate;
1897 : // Set the outlet enthalpys for air and Heating
1898 73698 : heatingCoil.OutletAirEnthalpy = Psychrometrics::PsyHFnTdbW(heatingCoil.OutletAirTemp, heatingCoil.OutletAirHumRat);
1899 :
1900 73698 : QCoilActual = HeatingCoilLoad;
1901 73698 : if (std::abs(heatingCoil.NominalCapacity) < 1.e-8) {
1902 21 : if (heatingCoil.AirLoopNum > 0) {
1903 0 : state.dataAirLoop->AirLoopAFNInfo(heatingCoil.AirLoopNum).AFNLoopHeatingCoilMaxRTF =
1904 0 : max(state.dataAirLoop->AirLoopAFNInfo(heatingCoil.AirLoopNum).AFNLoopHeatingCoilMaxRTF, 0.0);
1905 : }
1906 : } else {
1907 73677 : if (heatingCoil.AirLoopNum > 0) {
1908 61404 : state.dataAirLoop->AirLoopAFNInfo(heatingCoil.AirLoopNum).AFNLoopHeatingCoilMaxRTF =
1909 61404 : max(state.dataAirLoop->AirLoopAFNInfo(heatingCoil.AirLoopNum).AFNLoopHeatingCoilMaxRTF,
1910 61404 : HeatingCoilLoad / heatingCoil.NominalCapacity);
1911 : }
1912 : }
1913 :
1914 : // set outlet node temp so parent objects can call calc directly without have to simulate entire model
1915 73698 : state.dataLoopNodes->Node(heatingCoil.AirOutletNodeNum).Temp = heatingCoil.OutletAirTemp;
1916 73698 : }
1917 :
1918 247 : void CalcMultiStageElectricHeatingCoil(EnergyPlusData &state,
1919 : int const CoilNum, // the number of the electric heating coil to be simulated
1920 : Real64 const SpeedRatio, // SpeedRatio varies between 1.0 (maximum speed) and 0.0 (minimum speed)
1921 : Real64 const CycRatio, // cycling part load ratio
1922 : int const StageNum, // Stage number
1923 : HVAC::FanOp const fanOp, // Fan operation mode
1924 : Real64 &QCoilActual, // coil load actually delivered (W)
1925 : bool const SuppHeat)
1926 : {
1927 :
1928 : // SUBROUTINE INFORMATION:
1929 : // AUTHOR Chandan Sharma, FSEC
1930 : // DATE WRITTEN January 2013
1931 :
1932 : // PURPOSE OF THIS SUBROUTINE:
1933 : // Calculates the air-side performance and electrical energy use of multistage electric heating coil.
1934 :
1935 : // METHODOLOGY EMPLOYED:
1936 : // Uses the same methodology as the single stage electric heating unit model (SUBROUTINE CalcelectricHeatingCoil).
1937 : // In addition it assumes that the unit performance is obtained by interpolating between
1938 : // the performance at high stage and that at low stage. If the output needed is below
1939 : // that produced at low stage, the coil cycles between off and low stage.
1940 :
1941 : // SUBROUTINE PARAMETER DEFINITIONS:
1942 : static constexpr std::string_view RoutineName = "CalcMultiStageElectricHeatingCoil";
1943 : static constexpr std::string_view RoutineNameAverageLoad = "CalcMultiStageElectricHeatingCoil:Averageload";
1944 : static constexpr std::string_view RoutineNameFullLoad = "CalcMultiStageElectricHeatingCoil:fullload";
1945 :
1946 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1947 : Real64 OutletAirEnthalpy; // outlet air enthalpy [J/kg]
1948 : Real64 OutletAirHumRat; // outlet air humidity ratio [kg/kg]
1949 : Real64 TotCapHS; // total capacity at high stage [W]
1950 : Real64 TotCapLS; // total capacity at low stage [W]
1951 : Real64 TotCap; // total capacity at current stage [W]
1952 : Real64 EffHS; // total capacity at high stage [W]
1953 : Real64 EffLS; // total capacity at low stage [W]
1954 : int StageNumHS; // High stage number
1955 : int StageNumLS; // Low stage number
1956 : Real64 FullLoadOutAirEnth; // Outlet full load enthalpy
1957 : Real64 FullLoadOutAirHumRat; // Outlet humidity ratio at full load
1958 : Real64 FullLoadOutAirTemp; // Outlet temperature at full load
1959 : Real64 FullLoadOutAirRH; // Outler relative humidity at full load
1960 : Real64 OutletAirTemp; // Supply ari temperature
1961 : Real64 LSElecHeatingPower; // Full load power at low stage
1962 : Real64 HSElecHeatingPower; // Full load power at high stage
1963 : Real64 PartLoadRat; // part load ratio
1964 :
1965 247 : auto &heatingCoil = state.dataHeatingCoils->HeatingCoil(CoilNum);
1966 247 : if (StageNum > 1) {
1967 87 : StageNumLS = StageNum - 1;
1968 87 : StageNumHS = StageNum;
1969 87 : if (StageNum > heatingCoil.NumOfStages) {
1970 0 : StageNumLS = heatingCoil.NumOfStages - 1;
1971 0 : StageNumHS = heatingCoil.NumOfStages;
1972 : }
1973 : } else {
1974 160 : StageNumLS = 1;
1975 160 : StageNumHS = 1;
1976 : }
1977 :
1978 247 : Real64 AirMassFlow = heatingCoil.InletAirMassFlowRate;
1979 247 : Real64 InletAirDryBulbTemp = heatingCoil.InletAirTemp;
1980 247 : Real64 InletAirEnthalpy = heatingCoil.InletAirEnthalpy;
1981 247 : Real64 InletAirHumRat = heatingCoil.InletAirHumRat;
1982 :
1983 247 : Real64 OutdoorPressure = state.dataEnvrn->OutBaroPress;
1984 :
1985 247 : if ((AirMassFlow > 0.0) && (heatingCoil.availSched->getCurrentVal() > 0.0) && ((CycRatio > 0.0) || (SpeedRatio > 0.0))) {
1986 :
1987 137 : if (StageNum > 1) {
1988 :
1989 85 : TotCapLS = heatingCoil.MSNominalCapacity(StageNumLS);
1990 85 : TotCapHS = heatingCoil.MSNominalCapacity(StageNumHS);
1991 :
1992 85 : EffLS = heatingCoil.MSEfficiency(StageNumLS);
1993 85 : EffHS = heatingCoil.MSEfficiency(StageNumHS);
1994 :
1995 : // Get full load output and power
1996 85 : LSElecHeatingPower = TotCapLS / EffLS;
1997 85 : HSElecHeatingPower = TotCapHS / EffHS;
1998 85 : OutletAirHumRat = InletAirHumRat;
1999 :
2000 : // if cycling fan, send coil part-load fraction to on/off fan via HVACDataGlobals
2001 : // IF (FanOpMode .EQ. FanOp::Cycling) OnOffFanPartLoadFraction = 1.0d0
2002 :
2003 : // Power calculation
2004 85 : heatingCoil.ElecUseLoad = SpeedRatio * HSElecHeatingPower + (1.0 - SpeedRatio) * LSElecHeatingPower;
2005 :
2006 85 : heatingCoil.HeatingCoilLoad = TotCapHS * SpeedRatio + TotCapLS * (1.0 - SpeedRatio);
2007 :
2008 85 : OutletAirEnthalpy = InletAirEnthalpy + heatingCoil.HeatingCoilLoad / heatingCoil.InletAirMassFlowRate;
2009 85 : OutletAirTemp = Psychrometrics::PsyTdbFnHW(OutletAirEnthalpy, OutletAirHumRat);
2010 85 : FullLoadOutAirRH = Psychrometrics::PsyRhFnTdbWPb(state, OutletAirTemp, OutletAirHumRat, OutdoorPressure, RoutineNameAverageLoad);
2011 :
2012 85 : if (FullLoadOutAirRH > 1.0) { // Limit to saturated conditions at FullLoadOutAirEnth
2013 0 : OutletAirTemp = Psychrometrics::PsyTsatFnHPb(state, OutletAirEnthalpy, OutdoorPressure, RoutineName);
2014 0 : OutletAirHumRat = Psychrometrics::PsyWFnTdbH(state, OutletAirTemp, OutletAirEnthalpy, RoutineName);
2015 : }
2016 :
2017 85 : heatingCoil.OutletAirTemp = OutletAirTemp;
2018 85 : heatingCoil.OutletAirHumRat = OutletAirHumRat;
2019 85 : heatingCoil.OutletAirEnthalpy = OutletAirEnthalpy;
2020 85 : heatingCoil.OutletAirMassFlowRate = heatingCoil.InletAirMassFlowRate;
2021 :
2022 : // Stage 1
2023 52 : } else if (CycRatio > 0.0) {
2024 :
2025 50 : PartLoadRat = min(1.0, CycRatio);
2026 :
2027 : // for cycling fan, reset mass flow to full on rate
2028 50 : if (fanOp == HVAC::FanOp::Cycling)
2029 20 : AirMassFlow /= PartLoadRat;
2030 30 : else if (fanOp == HVAC::FanOp::Continuous) {
2031 30 : if (!SuppHeat) {
2032 24 : AirMassFlow = state.dataHVACGlobal->MSHPMassFlowRateLow;
2033 : }
2034 : }
2035 :
2036 50 : TotCap = heatingCoil.MSNominalCapacity(StageNumLS);
2037 :
2038 : // Calculate full load outlet conditions
2039 50 : FullLoadOutAirEnth = InletAirEnthalpy + TotCap / AirMassFlow;
2040 50 : FullLoadOutAirHumRat = InletAirHumRat;
2041 50 : FullLoadOutAirTemp = Psychrometrics::PsyTdbFnHW(FullLoadOutAirEnth, FullLoadOutAirHumRat);
2042 : FullLoadOutAirRH =
2043 50 : Psychrometrics::PsyRhFnTdbWPb(state, FullLoadOutAirTemp, FullLoadOutAirHumRat, OutdoorPressure, RoutineNameFullLoad);
2044 :
2045 50 : if (FullLoadOutAirRH > 1.0) { // Limit to saturated conditions at FullLoadOutAirEnth
2046 0 : FullLoadOutAirTemp = Psychrometrics::PsyTsatFnHPb(state, FullLoadOutAirEnth, OutdoorPressure, RoutineName);
2047 : // Eventually inlet air conditions will be used in electric Coil, these lines are commented out and marked with this comment
2048 : // line FullLoadOutAirTemp = PsyTsatFnHPb(FullLoadOutAirEnth,InletAirPressure)
2049 0 : FullLoadOutAirHumRat = Psychrometrics::PsyWFnTdbH(state, FullLoadOutAirTemp, FullLoadOutAirEnth, RoutineName);
2050 : }
2051 :
2052 : // Set outlet conditions from the full load calculation
2053 50 : if (fanOp == HVAC::FanOp::Cycling) {
2054 20 : OutletAirEnthalpy = FullLoadOutAirEnth;
2055 20 : OutletAirHumRat = FullLoadOutAirHumRat;
2056 20 : OutletAirTemp = FullLoadOutAirTemp;
2057 : } else {
2058 30 : OutletAirEnthalpy = PartLoadRat * FullLoadOutAirEnth + (1.0 - PartLoadRat) * InletAirEnthalpy;
2059 30 : OutletAirHumRat = PartLoadRat * FullLoadOutAirHumRat + (1.0 - PartLoadRat) * InletAirHumRat;
2060 30 : OutletAirTemp = PartLoadRat * FullLoadOutAirTemp + (1.0 - PartLoadRat) * InletAirDryBulbTemp;
2061 : }
2062 :
2063 50 : EffLS = heatingCoil.MSEfficiency(StageNumLS);
2064 :
2065 : // HeatingCoil(CoilNum)%HeatingCoilLoad = TotCap
2066 : // This would require a CR to change
2067 50 : heatingCoil.HeatingCoilLoad = TotCap * PartLoadRat;
2068 :
2069 50 : heatingCoil.ElecUseLoad = heatingCoil.HeatingCoilLoad / EffLS;
2070 :
2071 50 : heatingCoil.OutletAirTemp = OutletAirTemp;
2072 50 : heatingCoil.OutletAirHumRat = OutletAirHumRat;
2073 50 : heatingCoil.OutletAirEnthalpy = OutletAirEnthalpy;
2074 50 : heatingCoil.OutletAirMassFlowRate = heatingCoil.InletAirMassFlowRate;
2075 : // this would require a CR to correct (i.e., calculate outputs when coil is off)
2076 : // ELSE
2077 : // ! electric coil is off; just pass through conditions
2078 : // HeatingCoil(CoilNum)%OutletAirEnthalpy = HeatingCoil(CoilNum)%InletAirEnthalpy
2079 : // HeatingCoil(CoilNum)%OutletAirHumRat = HeatingCoil(CoilNum)%InletAirHumRat
2080 : // HeatingCoil(CoilNum)%OutletAirTemp = HeatingCoil(CoilNum)%InletAirTemp
2081 : // HeatingCoil(CoilNum)%OutletAirMassFlowRate = HeatingCoil(CoilNum)%InletAirMassFlowRate
2082 : // HeatingCoil(CoilNum)%ElecUseLoad = 0.0
2083 : // HeatingCoil(CoilNum)%HeatingCoilLoad = 0.0
2084 : // ElecHeatingCoilPower = 0.0
2085 : }
2086 :
2087 : } else {
2088 :
2089 : // electric coil is off; just pass through conditions
2090 110 : heatingCoil.OutletAirEnthalpy = heatingCoil.InletAirEnthalpy;
2091 110 : heatingCoil.OutletAirHumRat = heatingCoil.InletAirHumRat;
2092 110 : heatingCoil.OutletAirTemp = heatingCoil.InletAirTemp;
2093 110 : heatingCoil.OutletAirMassFlowRate = heatingCoil.InletAirMassFlowRate;
2094 :
2095 : // some of these are reset in Init, can be removed to speed up code
2096 110 : heatingCoil.ElecUseLoad = 0.0;
2097 110 : heatingCoil.HeatingCoilLoad = 0.0;
2098 :
2099 : } // end of on/off if - else
2100 :
2101 : // set outlet node temp so parent objects can call calc directly without have to simulate entire model
2102 247 : state.dataLoopNodes->Node(heatingCoil.AirOutletNodeNum).Temp = heatingCoil.OutletAirTemp;
2103 :
2104 247 : QCoilActual = heatingCoil.HeatingCoilLoad;
2105 247 : }
2106 :
2107 159191 : void CalcFuelHeatingCoil(EnergyPlusData &state,
2108 : int const CoilNum, // index to heating coil
2109 : Real64 const QCoilReq,
2110 : Real64 &QCoilActual, // coil load actually delivered (W)
2111 : HVAC::FanOp const fanOp, // fan operating mode
2112 : [[maybe_unused]] Real64 const PartLoadRatio // part-load ratio of heating coil
2113 : )
2114 : {
2115 : // SUBROUTINE INFORMATION:
2116 : // AUTHOR Rich Liesen
2117 : // DATE WRITTEN May 2000
2118 : // MODIFIED Jul. 2016, R. Zhang, Applied the coil supply air temperature sensor offset
2119 :
2120 : // PURPOSE OF THIS SUBROUTINE:
2121 : // Simulates a simple Gas heating coil with a burner efficiency
2122 :
2123 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2124 : Real64 TempAirOut; // [C]
2125 : Real64 HeatingCoilLoad;
2126 : Real64 QCoilCap;
2127 : Real64 PartLoadRat;
2128 : Real64 PLF;
2129 :
2130 159191 : auto &heatingCoil = state.dataHeatingCoils->HeatingCoil(CoilNum);
2131 :
2132 159191 : Real64 Effic = heatingCoil.Efficiency;
2133 159191 : Real64 TempAirIn = heatingCoil.InletAirTemp;
2134 159191 : Real64 Win = heatingCoil.InletAirHumRat;
2135 159191 : Real64 TempSetPoint = heatingCoil.DesiredOutletTemp;
2136 159191 : Real64 AirMassFlow = heatingCoil.InletAirMassFlowRate;
2137 :
2138 159191 : Real64 CapacitanceAir = Psychrometrics::PsyCpAirFnW(Win) * AirMassFlow;
2139 :
2140 : // If there is a fault of coil SAT Sensor
2141 159191 : if (heatingCoil.FaultyCoilSATFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
2142 0 : (!state.dataGlobal->KickOffSimulation)) {
2143 : // calculate the sensor offset using fault information
2144 0 : int FaultIndex = heatingCoil.FaultyCoilSATIndex;
2145 0 : heatingCoil.FaultyCoilSATOffset = state.dataFaultsMgr->FaultsCoilSATSensor(FaultIndex).CalFaultOffsetAct(state);
2146 : // update the TempSetPoint
2147 0 : TempSetPoint -= heatingCoil.FaultyCoilSATOffset;
2148 : }
2149 :
2150 : // If the coil is operating there should be some heating capacitance
2151 : // across the coil, so do the simulation. If not set outlet to inlet and no load.
2152 : // Also the coil has to be scheduled to be available.
2153 :
2154 : // Control output to meet load QCoilReq (QCoilReq is passed in if load controlled, otherwise QCoilReq=-999)
2155 159191 : if ((AirMassFlow > 0.0 && heatingCoil.NominalCapacity > 0.0) && (heatingCoil.availSched->getCurrentVal() > 0.0) && (QCoilReq > 0.0)) {
2156 :
2157 : // check to see if the Required heating capacity is greater than the user specified capacity.
2158 12652 : if (QCoilReq > heatingCoil.NominalCapacity) {
2159 2680 : QCoilCap = heatingCoil.NominalCapacity;
2160 : } else {
2161 9972 : QCoilCap = QCoilReq;
2162 : }
2163 :
2164 12652 : TempAirOut = TempAirIn + QCoilCap / CapacitanceAir;
2165 12652 : HeatingCoilLoad = QCoilCap;
2166 :
2167 12652 : PartLoadRat = HeatingCoilLoad / heatingCoil.NominalCapacity;
2168 :
2169 : // The HeatingCoilLoad is the change in the enthalpy of the Heating
2170 12652 : heatingCoil.FuelUseLoad = HeatingCoilLoad / Effic;
2171 12652 : heatingCoil.ElecUseLoad = heatingCoil.ParasiticElecLoad * PartLoadRat;
2172 12652 : heatingCoil.ParasiticFuelRate = heatingCoil.ParasiticFuelCapacity * (1.0 - PartLoadRat);
2173 :
2174 : // Control coil output to meet a setpoint temperature.
2175 112994 : } else if ((AirMassFlow > 0.0 && heatingCoil.NominalCapacity > 0.0) && (heatingCoil.availSched->getCurrentVal() > 0.0) &&
2176 259533 : (QCoilReq == DataLoopNode::SensedLoadFlagValue) && (std::abs(TempSetPoint - TempAirIn) > HVAC::TempControlTol)) {
2177 :
2178 15405 : QCoilCap = CapacitanceAir * (TempSetPoint - TempAirIn);
2179 : // check to see if setpoint above entering temperature. If not, set
2180 : // output to zero.
2181 15405 : if (QCoilCap <= 0.0) {
2182 43 : QCoilCap = 0.0;
2183 43 : TempAirOut = TempAirIn;
2184 : // check to see if the Required heating capacity is greater than the user
2185 : // specified capacity.
2186 15362 : } else if (QCoilCap > heatingCoil.NominalCapacity) {
2187 10429 : QCoilCap = heatingCoil.NominalCapacity;
2188 10429 : TempAirOut = TempAirIn + QCoilCap / CapacitanceAir;
2189 : } else {
2190 4933 : TempAirOut = TempSetPoint;
2191 : }
2192 :
2193 15405 : HeatingCoilLoad = QCoilCap;
2194 :
2195 15405 : PartLoadRat = HeatingCoilLoad / heatingCoil.NominalCapacity;
2196 :
2197 : // The HeatingCoilLoad is the change in the enthalpy of the Heating
2198 15405 : heatingCoil.FuelUseLoad = HeatingCoilLoad / Effic;
2199 15405 : heatingCoil.ElecUseLoad = heatingCoil.ParasiticElecLoad * PartLoadRat;
2200 15405 : heatingCoil.ParasiticFuelRate = heatingCoil.ParasiticFuelCapacity * (1.0 - PartLoadRat);
2201 :
2202 : } else { // If not running Conditions do not change across coil from inlet to outlet
2203 :
2204 131134 : TempAirOut = TempAirIn;
2205 131134 : HeatingCoilLoad = 0.0;
2206 131134 : PartLoadRat = 0.0;
2207 131134 : heatingCoil.FuelUseLoad = 0.0;
2208 131134 : heatingCoil.ElecUseLoad = 0.0;
2209 131134 : heatingCoil.ParasiticFuelRate = heatingCoil.ParasiticFuelCapacity;
2210 : }
2211 :
2212 159191 : heatingCoil.RTF = PartLoadRat;
2213 :
2214 : // If the PLF curve is defined the gas usage needs to be modified
2215 159191 : if (heatingCoil.PLFCurveIndex > 0) {
2216 90 : if (PartLoadRat == 0) {
2217 90 : heatingCoil.FuelUseLoad = 0.0;
2218 : } else {
2219 0 : PLF = Curve::CurveValue(state, heatingCoil.PLFCurveIndex, PartLoadRat);
2220 0 : if (PLF < 0.7) {
2221 0 : if (heatingCoil.PLFErrorCount < 1) {
2222 0 : ++heatingCoil.PLFErrorCount;
2223 0 : ShowWarningError(state,
2224 0 : format("CalcFuelHeatingCoil: {}=\"{}\", PLF curve values",
2225 : HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num),
2226 0 : heatingCoil.Name));
2227 0 : ShowContinueError(state, format("The PLF curve value = {:.5T} for part-load ratio = {:.5T}", PLF, PartLoadRat));
2228 0 : ShowContinueError(state, "PLF curve values must be >= 0.7. PLF has been reset to 0.7 and the simulation continues...");
2229 0 : ShowContinueError(state, "Check the IO reference manual for PLF curve guidance [Coil:Heating:Fuel].");
2230 : } else {
2231 0 : ShowRecurringWarningErrorAtEnd(
2232 0 : state, heatingCoil.Name + ", Heating coil PLF curve < 0.7 warning continues... ", heatingCoil.PLFErrorIndex, PLF, PLF);
2233 : }
2234 0 : PLF = 0.7;
2235 : }
2236 : // Modify the Gas Coil Consumption and parasitic loads based on PLF curve
2237 0 : heatingCoil.RTF = PartLoadRat / PLF;
2238 0 : if (heatingCoil.RTF > 1.0 && std::abs(heatingCoil.RTF - 1.0) > 0.001) {
2239 0 : if (heatingCoil.RTFErrorCount < 1) {
2240 0 : ++heatingCoil.RTFErrorCount;
2241 0 : ShowWarningError(state,
2242 0 : format("CalcFuelHeatingCoil: {}=\"{}\", runtime fraction",
2243 : HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num),
2244 0 : heatingCoil.Name));
2245 0 : ShowContinueError(state, format("The runtime fraction exceeded 1.0. [{:.4T}].", heatingCoil.RTF));
2246 0 : ShowContinueError(state, "Runtime fraction is set to 1.0 and the simulation continues...");
2247 0 : ShowContinueError(state, "Check the IO reference manual for PLF curve guidance [Coil:Heating:Fuel].");
2248 : } else {
2249 0 : ShowRecurringWarningErrorAtEnd(state,
2250 0 : format("{}, Heating coil runtime fraction > 1.0 warning continues... ", heatingCoil.Name),
2251 0 : heatingCoil.RTFErrorIndex,
2252 0 : heatingCoil.RTF,
2253 0 : heatingCoil.RTF);
2254 : }
2255 0 : heatingCoil.RTF = 1.0; // Reset coil runtime fraction to 1.0
2256 0 : } else if (heatingCoil.RTF > 1.0) {
2257 0 : heatingCoil.RTF = 1.0; // Reset coil runtime fraction to 1.0
2258 : }
2259 0 : heatingCoil.ElecUseLoad = heatingCoil.ParasiticElecLoad * heatingCoil.RTF;
2260 0 : heatingCoil.FuelUseLoad = heatingCoil.NominalCapacity / Effic * heatingCoil.RTF;
2261 0 : heatingCoil.ParasiticFuelRate = heatingCoil.ParasiticFuelCapacity * (1.0 - heatingCoil.RTF);
2262 : // Fan power will also be modified by the heating coil's part load fraction
2263 : // OnOffFanPartLoadFraction passed to fan via DataHVACGlobals (cycling fan only)
2264 0 : if (fanOp == HVAC::FanOp::Cycling) {
2265 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = PLF;
2266 : }
2267 : }
2268 : }
2269 :
2270 : // Set the outlet conditions
2271 159191 : heatingCoil.HeatingCoilLoad = HeatingCoilLoad;
2272 159191 : heatingCoil.OutletAirTemp = TempAirOut;
2273 :
2274 : // This HeatingCoil does not change the moisture or Mass Flow across the component
2275 159191 : heatingCoil.OutletAirHumRat = heatingCoil.InletAirHumRat;
2276 159191 : heatingCoil.OutletAirMassFlowRate = heatingCoil.InletAirMassFlowRate;
2277 : // Set the outlet enthalpys for air and Heating
2278 159191 : heatingCoil.OutletAirEnthalpy = Psychrometrics::PsyHFnTdbW(heatingCoil.OutletAirTemp, heatingCoil.OutletAirHumRat);
2279 :
2280 159191 : QCoilActual = HeatingCoilLoad;
2281 159191 : if (heatingCoil.AirLoopNum > 0) {
2282 0 : state.dataAirLoop->AirLoopAFNInfo(heatingCoil.AirLoopNum).AFNLoopHeatingCoilMaxRTF =
2283 0 : max(state.dataAirLoop->AirLoopAFNInfo(heatingCoil.AirLoopNum).AFNLoopHeatingCoilMaxRTF, heatingCoil.RTF);
2284 : }
2285 159191 : state.dataHVACGlobal->ElecHeatingCoilPower = heatingCoil.ElecUseLoad;
2286 :
2287 : // set outlet node temp so parent objects can call calc directly without have to simulate entire model
2288 159191 : state.dataLoopNodes->Node(heatingCoil.AirOutletNodeNum).Temp = heatingCoil.OutletAirTemp;
2289 159191 : }
2290 :
2291 65 : void CalcMultiStageGasHeatingCoil(EnergyPlusData &state,
2292 : int const CoilNum, // the number of the Gas heating coil to be simulated
2293 : Real64 const SpeedRatio, // SpeedRatio varies between 1.0 (maximum speed) and 0.0 (minimum speed)
2294 : Real64 const CycRatio, // cycling part load ratio
2295 : int const StageNum, // Speed number
2296 : HVAC::FanOp const fanOp // Fan operation mode
2297 : )
2298 : {
2299 :
2300 : // SUBROUTINE INFORMATION:
2301 : // AUTHOR Chandan Sharma, FSEC
2302 : // DATE WRITTEN January 2013
2303 :
2304 : // PURPOSE OF THIS SUBROUTINE:
2305 : // Calculates the air-side performance and energy use of a multi stage gas heating coil.
2306 :
2307 : // METHODOLOGY EMPLOYED:
2308 : // Uses the same methodology as the single speed Gas heating unit model (SUBROUTINE CalcFuelHeatingCoil).
2309 : // In addition it assumes that the unit performance is obtained by interpolating between
2310 : // the performance at high stage and that at low stage. If the output needed is below
2311 : // that produced at low stage, the coil cycles between off and low stage.
2312 :
2313 65 : Real64 const MSHPMassFlowRateHigh = state.dataHVACGlobal->MSHPMassFlowRateHigh;
2314 65 : Real64 const MSHPMassFlowRateLow = state.dataHVACGlobal->MSHPMassFlowRateLow;
2315 :
2316 : // SUBROUTINE PARAMETER DEFINITIONS:
2317 : static constexpr std::string_view RoutineName("CalcMultiStageGasHeatingCoil");
2318 : static constexpr std::string_view RoutineNameAverageLoad("CalcMultiStageGasHeatingCoil:Averageload");
2319 : static constexpr std::string_view RoutineNameFullLoad("CalcMultiStageGasHeatingCoil:fullload");
2320 :
2321 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2322 : Real64 OutletAirEnthalpy; // outlet air enthalpy [J/kg]
2323 : Real64 OutletAirHumRat; // outlet air humidity ratio [kg/kg]
2324 : Real64 TotCapHS; // total capacity at high stage [W]
2325 : Real64 TotCapLS; // total capacity at low stage [W]
2326 : Real64 TotCap; // total capacity at current stage [W]
2327 : Real64 EffHS; // efficiency at high stage
2328 65 : Real64 EffLS(0.0); // efficiency at low stage
2329 : Real64 EffAvg; // average efficiency
2330 : int StageNumHS; // High stage number
2331 : int StageNumLS; // Low stage number
2332 : Real64 FullLoadOutAirEnth; // Outlet full load enthalpy
2333 : Real64 FullLoadOutAirHumRat; // Outlet humidity ratio at full load
2334 : Real64 FullLoadOutAirTemp; // Outlet temperature at full load
2335 : Real64 FullLoadOutAirRH; // Outler relative humidity at full load
2336 : Real64 OutletAirTemp; // Supply ari temperature
2337 : Real64 LSFullLoadOutAirEnth; // Outlet full load enthalpy at low stage
2338 : Real64 HSFullLoadOutAirEnth; // Outlet full load enthalpy at high stage
2339 : Real64 LSGasHeatingPower; // Full load power at low stage
2340 : Real64 HSGasHeatingPower; // Full load power at high stage
2341 65 : Real64 PartLoadRat(0.0); // part load ratio
2342 : Real64 PLF; // part load factor used to calculate RTF
2343 :
2344 65 : auto &heatingCoil = state.dataHeatingCoils->HeatingCoil(CoilNum);
2345 :
2346 65 : if (StageNum > 1) {
2347 14 : StageNumLS = StageNum - 1;
2348 14 : StageNumHS = StageNum;
2349 14 : if (StageNum > heatingCoil.NumOfStages) {
2350 0 : StageNumLS = heatingCoil.NumOfStages - 1;
2351 0 : StageNumHS = heatingCoil.NumOfStages;
2352 : }
2353 : } else {
2354 51 : StageNumLS = 1;
2355 51 : StageNumHS = 1;
2356 : }
2357 :
2358 65 : Real64 AirMassFlow = heatingCoil.InletAirMassFlowRate;
2359 65 : Real64 InletAirEnthalpy = heatingCoil.InletAirEnthalpy;
2360 65 : Real64 InletAirHumRat = heatingCoil.InletAirHumRat;
2361 65 : Real64 OutdoorPressure = state.dataEnvrn->OutBaroPress;
2362 :
2363 65 : if ((AirMassFlow > 0.0) && (heatingCoil.availSched->getCurrentVal() > 0.0) && ((CycRatio > 0.0) || (SpeedRatio > 0.0))) {
2364 :
2365 34 : if (StageNum > 1) {
2366 :
2367 14 : TotCapLS = heatingCoil.MSNominalCapacity(StageNumLS);
2368 14 : TotCapHS = heatingCoil.MSNominalCapacity(StageNumHS);
2369 :
2370 14 : EffLS = heatingCoil.MSEfficiency(StageNumLS);
2371 14 : EffHS = heatingCoil.MSEfficiency(StageNumHS);
2372 :
2373 14 : PartLoadRat = min(1.0, SpeedRatio);
2374 14 : heatingCoil.RTF = 1.0;
2375 :
2376 : // Get full load output and power
2377 14 : LSFullLoadOutAirEnth = InletAirEnthalpy + TotCapLS / MSHPMassFlowRateLow;
2378 14 : HSFullLoadOutAirEnth = InletAirEnthalpy + TotCapHS / MSHPMassFlowRateHigh;
2379 14 : LSGasHeatingPower = TotCapLS / EffLS;
2380 14 : HSGasHeatingPower = TotCapHS / EffHS;
2381 14 : OutletAirHumRat = InletAirHumRat;
2382 :
2383 : // if cycling fan, send coil part-load fraction to on/off fan via HVACDataGlobals
2384 : // IF (FanOpMode .EQ. FanOp::Cycling) OnOffFanPartLoadFraction = 1.0d0
2385 :
2386 : // Power calculation. If PartLoadRat (SpeedRatio) = 0, operate at LS the whole time step
2387 14 : heatingCoil.ElecUseLoad =
2388 14 : PartLoadRat * heatingCoil.MSParasiticElecLoad(StageNumHS) + (1.0 - PartLoadRat) * heatingCoil.MSParasiticElecLoad(StageNumLS);
2389 :
2390 14 : state.dataHVACGlobal->ElecHeatingCoilPower = heatingCoil.ElecUseLoad;
2391 14 : heatingCoil.HeatingCoilLoad = MSHPMassFlowRateHigh * (HSFullLoadOutAirEnth - InletAirEnthalpy) * PartLoadRat +
2392 14 : MSHPMassFlowRateLow * (LSFullLoadOutAirEnth - InletAirEnthalpy) * (1.0 - PartLoadRat);
2393 14 : EffAvg = (EffHS * PartLoadRat) + (EffLS * (1.0 - PartLoadRat));
2394 14 : heatingCoil.FuelUseLoad = heatingCoil.HeatingCoilLoad / EffAvg;
2395 14 : heatingCoil.ParasiticFuelRate = 0.0;
2396 :
2397 14 : OutletAirEnthalpy = InletAirEnthalpy + heatingCoil.HeatingCoilLoad / heatingCoil.InletAirMassFlowRate;
2398 14 : OutletAirTemp = Psychrometrics::PsyTdbFnHW(OutletAirEnthalpy, OutletAirHumRat);
2399 14 : FullLoadOutAirRH = Psychrometrics::PsyRhFnTdbWPb(state, OutletAirTemp, OutletAirHumRat, OutdoorPressure, RoutineNameAverageLoad);
2400 :
2401 14 : if (FullLoadOutAirRH > 1.0) { // Limit to saturated conditions at FullLoadOutAirEnth
2402 0 : OutletAirTemp = Psychrometrics::PsyTsatFnHPb(state, OutletAirEnthalpy, OutdoorPressure, RoutineName);
2403 0 : OutletAirHumRat = Psychrometrics::PsyWFnTdbH(state, OutletAirTemp, OutletAirEnthalpy, RoutineName);
2404 : }
2405 :
2406 14 : heatingCoil.OutletAirTemp = OutletAirTemp;
2407 14 : heatingCoil.OutletAirHumRat = OutletAirHumRat;
2408 14 : heatingCoil.OutletAirEnthalpy = OutletAirEnthalpy;
2409 14 : heatingCoil.OutletAirMassFlowRate = heatingCoil.InletAirMassFlowRate;
2410 :
2411 : // Stage 1
2412 20 : } else if (CycRatio > 0.0) {
2413 :
2414 : // for cycling fan, reset mass flow to full on rate
2415 20 : if (fanOp == HVAC::FanOp::Cycling)
2416 2 : AirMassFlow /= CycRatio;
2417 18 : else if (fanOp == HVAC::FanOp::Continuous)
2418 18 : AirMassFlow = MSHPMassFlowRateLow;
2419 :
2420 20 : TotCap = heatingCoil.MSNominalCapacity(StageNumLS);
2421 :
2422 20 : PartLoadRat = min(1.0, CycRatio);
2423 20 : heatingCoil.RTF = PartLoadRat;
2424 :
2425 : // Calculate full load outlet conditions
2426 20 : FullLoadOutAirEnth = InletAirEnthalpy + TotCap / AirMassFlow;
2427 20 : FullLoadOutAirHumRat = InletAirHumRat;
2428 20 : FullLoadOutAirTemp = Psychrometrics::PsyTdbFnHW(FullLoadOutAirEnth, FullLoadOutAirHumRat);
2429 : FullLoadOutAirRH =
2430 20 : Psychrometrics::PsyRhFnTdbWPb(state, FullLoadOutAirTemp, FullLoadOutAirHumRat, OutdoorPressure, RoutineNameFullLoad);
2431 :
2432 20 : if (FullLoadOutAirRH > 1.0) { // Limit to saturated conditions at FullLoadOutAirEnth
2433 0 : FullLoadOutAirTemp = Psychrometrics::PsyTsatFnHPb(state, FullLoadOutAirEnth, OutdoorPressure, RoutineName);
2434 : // Eventually inlet air conditions will be used in Gas Coil, these lines are commented out and marked with this comment line
2435 : // FullLoadOutAirTemp = PsyTsatFnHPb(FullLoadOutAirEnth,InletAirPressure)
2436 0 : FullLoadOutAirHumRat = Psychrometrics::PsyWFnTdbH(state, FullLoadOutAirTemp, FullLoadOutAirEnth, RoutineName);
2437 : }
2438 :
2439 : // Set outlet conditions from the full load calculation
2440 20 : if (fanOp == HVAC::FanOp::Cycling) {
2441 2 : OutletAirEnthalpy = FullLoadOutAirEnth;
2442 2 : OutletAirHumRat = FullLoadOutAirHumRat;
2443 2 : OutletAirTemp = FullLoadOutAirTemp;
2444 : } else {
2445 18 : OutletAirEnthalpy =
2446 18 : PartLoadRat * AirMassFlow / heatingCoil.InletAirMassFlowRate * (FullLoadOutAirEnth - InletAirEnthalpy) + InletAirEnthalpy;
2447 18 : OutletAirHumRat =
2448 18 : PartLoadRat * AirMassFlow / heatingCoil.InletAirMassFlowRate * (FullLoadOutAirHumRat - InletAirHumRat) + InletAirHumRat;
2449 18 : OutletAirTemp = Psychrometrics::PsyTdbFnHW(OutletAirEnthalpy, OutletAirHumRat);
2450 : }
2451 :
2452 20 : EffLS = heatingCoil.MSEfficiency(StageNumLS);
2453 :
2454 20 : heatingCoil.HeatingCoilLoad = TotCap * PartLoadRat;
2455 :
2456 20 : heatingCoil.FuelUseLoad = heatingCoil.HeatingCoilLoad / EffLS;
2457 : // parasitics are calculated when the coil is off (1-PLR)
2458 20 : heatingCoil.ElecUseLoad = heatingCoil.MSParasiticElecLoad(StageNumLS) * (1.0 - PartLoadRat);
2459 20 : heatingCoil.ParasiticFuelRate = heatingCoil.ParasiticFuelCapacity * (1.0 - PartLoadRat);
2460 20 : state.dataHVACGlobal->ElecHeatingCoilPower = heatingCoil.ElecUseLoad;
2461 :
2462 20 : heatingCoil.OutletAirTemp = OutletAirTemp;
2463 20 : heatingCoil.OutletAirHumRat = OutletAirHumRat;
2464 20 : heatingCoil.OutletAirEnthalpy = OutletAirEnthalpy;
2465 20 : heatingCoil.OutletAirMassFlowRate = heatingCoil.InletAirMassFlowRate;
2466 : }
2467 :
2468 : // This requires a CR to correct (i.e., calculate outputs when coil is off)
2469 : } else {
2470 :
2471 : // Gas coil is off; just pass through conditions
2472 31 : heatingCoil.OutletAirEnthalpy = heatingCoil.InletAirEnthalpy;
2473 31 : heatingCoil.OutletAirHumRat = heatingCoil.InletAirHumRat;
2474 31 : heatingCoil.OutletAirTemp = heatingCoil.InletAirTemp;
2475 31 : heatingCoil.OutletAirMassFlowRate = heatingCoil.InletAirMassFlowRate;
2476 :
2477 : // some of these are reset in Init, can be removed to speed up code
2478 31 : heatingCoil.ElecUseLoad = 0.0;
2479 31 : heatingCoil.HeatingCoilLoad = 0.0;
2480 31 : heatingCoil.FuelUseLoad = 0.0;
2481 31 : heatingCoil.ParasiticFuelRate = heatingCoil.ParasiticFuelCapacity;
2482 31 : state.dataHVACGlobal->ElecHeatingCoilPower = 0.0;
2483 31 : PartLoadRat = 0.0;
2484 :
2485 : } // end of on/off if - else
2486 :
2487 : // If the PLF curve is defined the gas usage needs to be modified.
2488 : // The PLF curve is only used when the coil cycles.
2489 65 : if (heatingCoil.PLFCurveIndex > 0) {
2490 62 : if (PartLoadRat > 0.0 && StageNum < 2) {
2491 18 : PLF = Curve::CurveValue(state, heatingCoil.PLFCurveIndex, PartLoadRat);
2492 18 : if (PLF < 0.7) {
2493 0 : if (heatingCoil.PLFErrorCount < 1) {
2494 0 : ++heatingCoil.PLFErrorCount;
2495 0 : ShowWarningError(state,
2496 0 : format("CalcFuelHeatingCoil: {}=\"{}\", PLF curve values",
2497 : HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num),
2498 0 : heatingCoil.Name));
2499 0 : ShowContinueError(state, format("The PLF curve value = {:.5T} for part-load ratio = {:.5T}", PLF, PartLoadRat));
2500 0 : ShowContinueError(state, "PLF curve values must be >= 0.7. PLF has been reset to 0.7 and the simulation continues...");
2501 0 : ShowContinueError(state, "Check the IO reference manual for PLF curve guidance [Coil:Heating:Fuel].");
2502 : } else {
2503 0 : ShowRecurringWarningErrorAtEnd(state,
2504 0 : format("{}, Heating coil PLF curve < 0.7 warning continues... ", heatingCoil.Name),
2505 0 : heatingCoil.PLFErrorIndex,
2506 : PLF,
2507 : PLF);
2508 : }
2509 0 : PLF = 0.7;
2510 : }
2511 : // Modify the Gas Coil Consumption and parasitic loads based on PLF curve
2512 18 : heatingCoil.RTF = PartLoadRat / PLF;
2513 18 : if (heatingCoil.RTF > 1.0 && std::abs(heatingCoil.RTF - 1.0) > 0.001) {
2514 0 : if (heatingCoil.RTFErrorCount < 1) {
2515 0 : ++heatingCoil.RTFErrorCount;
2516 0 : ShowWarningError(state,
2517 0 : format("CalcFuelHeatingCoil: {}=\"{}\", runtime fraction",
2518 : HVAC::cAllCoilTypes(heatingCoil.HCoilType_Num),
2519 0 : heatingCoil.Name));
2520 0 : ShowContinueError(state, format("The runtime fraction exceeded 1.0. [{:.4T}].", heatingCoil.RTF));
2521 0 : ShowContinueError(state, "Runtime fraction is set to 1.0 and the simulation continues...");
2522 0 : ShowContinueError(state, "Check the IO reference manual for PLF curve guidance [Coil:Heating:Fuel].");
2523 : } else {
2524 0 : ShowRecurringWarningErrorAtEnd(state,
2525 0 : format("{}, Heating coil runtime fraction > 1.0 warning continues... ", heatingCoil.Name),
2526 0 : heatingCoil.RTFErrorIndex,
2527 0 : heatingCoil.RTF,
2528 0 : heatingCoil.RTF);
2529 : }
2530 0 : heatingCoil.RTF = 1.0; // Reset coil runtime fraction to 1.0
2531 18 : } else if (heatingCoil.RTF > 1.0) {
2532 0 : heatingCoil.RTF = 1.0; // Reset coil runtime fraction to 1.0
2533 : }
2534 18 : heatingCoil.ElecUseLoad = heatingCoil.MSParasiticElecLoad(StageNum) * heatingCoil.RTF;
2535 18 : heatingCoil.FuelUseLoad = (heatingCoil.MSNominalCapacity(StageNum) / EffLS) * heatingCoil.RTF;
2536 18 : heatingCoil.ParasiticFuelRate = heatingCoil.ParasiticFuelCapacity * (1.0 - heatingCoil.RTF);
2537 : // Fan power will also be modified by the heating coil's part load fraction
2538 : // OnOffFanPartLoadFraction passed to fan via DataHVACGlobals (cycling fan only)
2539 18 : if (fanOp == HVAC::FanOp::Cycling) {
2540 2 : state.dataHVACGlobal->OnOffFanPartLoadFraction = PLF;
2541 : }
2542 : }
2543 : }
2544 :
2545 : // set outlet node temp so parent objects can call calc directly without have to simulate entire model
2546 65 : state.dataLoopNodes->Node(heatingCoil.AirOutletNodeNum).Temp = heatingCoil.OutletAirTemp;
2547 65 : }
2548 :
2549 4 : void CalcDesuperheaterHeatingCoil(EnergyPlusData &state,
2550 : int const CoilNum, // index to desuperheater heating coil
2551 : Real64 const QCoilReq, // load requested by the simulation for load based control [W]
2552 : Real64 &QCoilActual // coil load actually delivered
2553 : )
2554 : {
2555 : // SUBROUTINE INFORMATION:
2556 : // AUTHOR Richard Raustad
2557 : // DATE WRITTEN January 2005
2558 : // MODIFIED Jul. 2016, R. Zhang, Applied the coil supply air temperature sensor offset
2559 :
2560 : // PURPOSE OF THIS SUBROUTINE:
2561 : // Simulates a simple desuperheater heating coil with a heat reclaim efficiency
2562 : // (eff = ratio of condenser waste heat reclaimed to total condenser waste heat rejected)
2563 :
2564 : // METHODOLOGY EMPLOYED:
2565 : // The available capacity of the desuperheater heating coil is determined by the
2566 : // amount of heat rejected at the heating source condenser multiplied by the
2567 : // desuperheater heat reclaim efficiency. This capacity is either applied towards
2568 : // a requested load (load based control) or applied to the air stream to meet a
2569 : // heating setpoint (temperature based control). This subroutine is similar to
2570 : // the electric or gas heating coil except that the NominalCapacity is variable
2571 : // and based on the runtime fraction and heat rejection of the heat source object.
2572 :
2573 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2574 : Real64 AvailTemp; // Lowest temperature available from desuperheater (~T condensing)[C]
2575 : Real64 TempAirOut; // temperature of the air leaving the desuperheater heating coil [C]
2576 : Real64 HeatingCoilLoad; // actual load delivered by the desuperheater heating coil [W]
2577 : Real64 QCoilCap; // available capacity of the desuperheater heating coil [W]
2578 : int SourceID; // waste heat source id number
2579 :
2580 4 : auto &heatingCoil = state.dataHeatingCoils->HeatingCoil(CoilNum);
2581 :
2582 4 : Real64 Effic = heatingCoil.Efficiency;
2583 4 : Real64 AirMassFlow = heatingCoil.InletAirMassFlowRate;
2584 4 : Real64 TempAirIn = heatingCoil.InletAirTemp;
2585 4 : Real64 Win = heatingCoil.InletAirHumRat;
2586 4 : Real64 CapacitanceAir = Psychrometrics::PsyCpAirFnW(Win) * AirMassFlow;
2587 4 : Real64 TempSetPoint = heatingCoil.DesiredOutletTemp;
2588 :
2589 : // If there is a fault of coil SAT Sensor
2590 4 : if (heatingCoil.FaultyCoilSATFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
2591 0 : (!state.dataGlobal->KickOffSimulation)) {
2592 : // calculate the sensor offset using fault information
2593 0 : int FaultIndex = heatingCoil.FaultyCoilSATIndex;
2594 0 : heatingCoil.FaultyCoilSATOffset = state.dataFaultsMgr->FaultsCoilSATSensor(FaultIndex).CalFaultOffsetAct(state);
2595 : // update the TempSetPoint
2596 0 : TempSetPoint -= heatingCoil.FaultyCoilSATOffset;
2597 : }
2598 :
2599 : // Access the appropriate structure to find the available heating capacity of the desuperheater heating coil
2600 : // The nominal capacity of the desuperheater heating coil varies based on the amount of heat rejected by the source
2601 : // Stovall 2011, add comparison to available temperature of heat reclaim source
2602 4 : if (state.dataHeatingCoils->ValidSourceType(CoilNum)) {
2603 4 : SourceID = heatingCoil.ReclaimHeatingSourceIndexNum;
2604 4 : switch (heatingCoil.ReclaimHeatingSource) {
2605 4 : case HeatObjTypes::COMPRESSORRACK_REFRIGERATEDCASE:
2606 : // Added last term to available energy equations to avoid double counting reclaimed energy
2607 : // because refrigeration systems are solved outside the hvac time step iterations
2608 4 : heatingCoil.RTF = 1.0;
2609 4 : heatingCoil.NominalCapacity = state.dataHeatBal->HeatReclaimRefrigeratedRack(SourceID).AvailCapacity * Effic -
2610 4 : state.dataHeatBal->HeatReclaimRefrigeratedRack(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal;
2611 4 : break;
2612 0 : case HeatObjTypes::CONDENSER_REFRIGERATION:
2613 0 : AvailTemp = state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).AvailTemperature;
2614 0 : heatingCoil.RTF = 1.0;
2615 0 : if (AvailTemp <= TempAirIn) {
2616 0 : heatingCoil.NominalCapacity = 0.0;
2617 0 : ShowRecurringWarningErrorAtEnd(
2618 : state,
2619 0 : format("Coil:Heating:Desuperheater {} - Waste heat source temperature was too low to be useful.", heatingCoil.Name),
2620 0 : heatingCoil.InsuffTemperatureWarn);
2621 : } else {
2622 0 : heatingCoil.NominalCapacity = state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).AvailCapacity * Effic -
2623 0 : state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal;
2624 : }
2625 0 : break;
2626 0 : case HeatObjTypes::COIL_DX_COOLING:
2627 : case HeatObjTypes::COIL_DX_MULTISPEED:
2628 : case HeatObjTypes::COIL_DX_MULTIMODE:
2629 0 : heatingCoil.RTF = state.dataDXCoils->DXCoil(SourceID).CoolingCoilRuntimeFraction;
2630 0 : heatingCoil.NominalCapacity = state.dataHeatBal->HeatReclaimDXCoil(SourceID).AvailCapacity * Effic -
2631 0 : state.dataHeatBal->HeatReclaimDXCoil(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal;
2632 0 : break;
2633 0 : case HeatObjTypes::COIL_DX_VARIABLE_COOLING:
2634 : // condenser heat rejection
2635 0 : heatingCoil.RTF = state.dataVariableSpeedCoils->VarSpeedCoil(SourceID).RunFrac;
2636 0 : heatingCoil.NominalCapacity = state.dataHeatBal->HeatReclaimVS_Coil(SourceID).AvailCapacity * Effic -
2637 0 : state.dataHeatBal->HeatReclaimVS_Coil(SourceID).WaterHeatingDesuperheaterReclaimedHeatTotal;
2638 0 : break;
2639 0 : case HeatObjTypes::COIL_COOLING_DX_NEW:
2640 : // get RTF and NominalCapacity from Coil:CoolingDX
2641 : {
2642 0 : auto const &thisCoolingCoil = state.dataCoilCoolingDX->coilCoolingDXs[SourceID];
2643 0 : heatingCoil.RTF = thisCoolingCoil.runTimeFraction;
2644 0 : heatingCoil.NominalCapacity =
2645 0 : thisCoolingCoil.reclaimHeat.AvailCapacity * Effic - thisCoolingCoil.reclaimHeat.WaterHeatingDesuperheaterReclaimedHeatTotal;
2646 : }
2647 0 : break;
2648 0 : default:
2649 0 : assert(false);
2650 : }
2651 :
2652 : } else {
2653 0 : heatingCoil.NominalCapacity = 0.0;
2654 : }
2655 :
2656 : // Control output to meet load (QCoilReq)
2657 4 : if ((AirMassFlow > 0.0) && (heatingCoil.availSched->getCurrentVal() > 0.0) && (QCoilReq > 0.0)) {
2658 :
2659 : // check to see if the Required heating capacity is greater than the available heating capacity.
2660 2 : if (QCoilReq > heatingCoil.NominalCapacity) {
2661 0 : QCoilCap = heatingCoil.NominalCapacity;
2662 : } else {
2663 2 : QCoilCap = QCoilReq;
2664 : }
2665 :
2666 : // report the runtime fraction of the desuperheater heating coil
2667 2 : if (heatingCoil.NominalCapacity > 0.0) {
2668 2 : heatingCoil.RTF *= (QCoilCap / heatingCoil.NominalCapacity);
2669 2 : TempAirOut = TempAirIn + QCoilCap / CapacitanceAir;
2670 2 : HeatingCoilLoad = QCoilCap;
2671 : } else {
2672 0 : heatingCoil.RTF = 0.0;
2673 0 : TempAirOut = TempAirIn;
2674 0 : HeatingCoilLoad = 0.0;
2675 : }
2676 :
2677 : // Control coil output to meet a setpoint temperature.
2678 1 : } else if ((AirMassFlow > 0.0 && heatingCoil.NominalCapacity > 0.0) && (heatingCoil.availSched->getCurrentVal() > 0.0) &&
2679 3 : (QCoilReq == DataLoopNode::SensedLoadFlagValue) && (std::abs(TempSetPoint - TempAirIn) > HVAC::TempControlTol)) {
2680 :
2681 0 : QCoilCap = CapacitanceAir * (TempSetPoint - TempAirIn);
2682 : // check to see if setpoint is above entering air temperature. If not, set output to zero.
2683 0 : if (QCoilCap <= 0.0) {
2684 0 : QCoilCap = 0.0;
2685 0 : TempAirOut = TempAirIn;
2686 : // check to see if the required heating capacity is greater than the available capacity.
2687 0 : } else if (QCoilCap > heatingCoil.NominalCapacity) {
2688 0 : QCoilCap = heatingCoil.NominalCapacity;
2689 0 : TempAirOut = TempAirIn + QCoilCap / CapacitanceAir;
2690 : } else {
2691 0 : TempAirOut = TempSetPoint;
2692 : }
2693 :
2694 0 : HeatingCoilLoad = QCoilCap;
2695 : // report the runtime fraction of the desuperheater heating coil
2696 0 : heatingCoil.RTF *= (QCoilCap / heatingCoil.NominalCapacity);
2697 :
2698 : } else { // If not running, conditions do not change across heating coil from inlet to outlet
2699 :
2700 2 : TempAirOut = TempAirIn;
2701 2 : HeatingCoilLoad = 0.0;
2702 2 : heatingCoil.ElecUseLoad = 0.0;
2703 2 : heatingCoil.RTF = 0.0;
2704 : }
2705 :
2706 : // Set the outlet conditions
2707 4 : heatingCoil.HeatingCoilLoad = HeatingCoilLoad;
2708 4 : heatingCoil.OutletAirTemp = TempAirOut;
2709 :
2710 : // This HeatingCoil does not change the moisture or Mass Flow across the component
2711 4 : heatingCoil.OutletAirHumRat = heatingCoil.InletAirHumRat;
2712 4 : heatingCoil.OutletAirMassFlowRate = heatingCoil.InletAirMassFlowRate;
2713 : // Set the outlet enthalpy
2714 4 : heatingCoil.OutletAirEnthalpy = Psychrometrics::PsyHFnTdbW(heatingCoil.OutletAirTemp, heatingCoil.OutletAirHumRat);
2715 :
2716 4 : heatingCoil.ElecUseLoad = heatingCoil.ParasiticElecLoad * heatingCoil.RTF;
2717 4 : QCoilActual = HeatingCoilLoad;
2718 :
2719 : // Update remaining waste heat (just in case multiple users of waste heat use same source)
2720 4 : if (state.dataHeatingCoils->ValidSourceType(CoilNum)) {
2721 4 : SourceID = heatingCoil.ReclaimHeatingSourceIndexNum;
2722 : // Refrigerated cases are simulated at the zone time step, do not decrement available capacity
2723 : // (the heat reclaim available capacity will not get reinitialized as the air loop iterates)
2724 4 : int DesuperheaterNum = CoilNum - state.dataHeatingCoils->NumElecCoil - state.dataHeatingCoils->NumElecCoilMultiStage -
2725 4 : state.dataHeatingCoils->NumFuelCoil - state.dataHeatingCoils->NumGasCoilMultiStage;
2726 4 : switch (heatingCoil.ReclaimHeatingSource) {
2727 4 : case HeatObjTypes::COMPRESSORRACK_REFRIGERATEDCASE: {
2728 4 : state.dataHeatBal->HeatReclaimRefrigeratedRack(SourceID).HVACDesuperheaterReclaimedHeat(DesuperheaterNum) = HeatingCoilLoad;
2729 4 : state.dataHeatBal->HeatReclaimRefrigeratedRack(SourceID).HVACDesuperheaterReclaimedHeatTotal = 0.0;
2730 8 : for (auto const &num : state.dataHeatBal->HeatReclaimRefrigeratedRack(SourceID).HVACDesuperheaterReclaimedHeat)
2731 4 : state.dataHeatBal->HeatReclaimRefrigeratedRack(SourceID).HVACDesuperheaterReclaimedHeatTotal += num;
2732 4 : } break;
2733 0 : case HeatObjTypes::CONDENSER_REFRIGERATION: {
2734 0 : state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).HVACDesuperheaterReclaimedHeat(DesuperheaterNum) = HeatingCoilLoad;
2735 0 : state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).HVACDesuperheaterReclaimedHeatTotal = 0.0;
2736 0 : for (auto const &num : state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).HVACDesuperheaterReclaimedHeat)
2737 0 : state.dataHeatBal->HeatReclaimRefrigCondenser(SourceID).HVACDesuperheaterReclaimedHeatTotal += num;
2738 0 : } break;
2739 0 : case HeatObjTypes::COIL_DX_COOLING:
2740 : case HeatObjTypes::COIL_DX_MULTISPEED:
2741 : case HeatObjTypes::COIL_DX_MULTIMODE: {
2742 0 : state.dataHeatBal->HeatReclaimDXCoil(SourceID).HVACDesuperheaterReclaimedHeat(DesuperheaterNum) = HeatingCoilLoad;
2743 0 : state.dataHeatBal->HeatReclaimDXCoil(SourceID).HVACDesuperheaterReclaimedHeatTotal = 0.0;
2744 0 : for (auto const &num : state.dataHeatBal->HeatReclaimDXCoil(SourceID).HVACDesuperheaterReclaimedHeat)
2745 0 : state.dataHeatBal->HeatReclaimDXCoil(SourceID).HVACDesuperheaterReclaimedHeatTotal += num;
2746 0 : } break;
2747 0 : case HeatObjTypes::COIL_DX_VARIABLE_COOLING: {
2748 0 : state.dataHeatBal->HeatReclaimVS_Coil(SourceID).HVACDesuperheaterReclaimedHeat(DesuperheaterNum) = HeatingCoilLoad;
2749 0 : state.dataHeatBal->HeatReclaimVS_Coil(SourceID).HVACDesuperheaterReclaimedHeatTotal = 0.0;
2750 0 : for (auto const &num : state.dataHeatBal->HeatReclaimVS_Coil(SourceID).HVACDesuperheaterReclaimedHeat)
2751 0 : state.dataHeatBal->HeatReclaimVS_Coil(SourceID).HVACDesuperheaterReclaimedHeatTotal += num;
2752 0 : } break;
2753 0 : default:
2754 0 : break;
2755 : }
2756 : }
2757 4 : }
2758 :
2759 233160 : void UpdateHeatingCoil(EnergyPlusData &state, int const CoilNum)
2760 : {
2761 : // SUBROUTINE INFORMATION:
2762 : // AUTHOR Richard Liesen
2763 : // DATE WRITTEN May 2000
2764 :
2765 : // PURPOSE OF THIS SUBROUTINE:
2766 : // This subroutine updates the coil outlet nodes.
2767 :
2768 : // METHODOLOGY EMPLOYED:
2769 : // Data is moved from the coil data structure to the coil outlet nodes.
2770 :
2771 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2772 233160 : auto const &heatingCoil = state.dataHeatingCoils->HeatingCoil(CoilNum);
2773 233160 : auto const &airInletNode = state.dataLoopNodes->Node(heatingCoil.AirInletNodeNum);
2774 233160 : auto &airOuletNode = state.dataLoopNodes->Node(heatingCoil.AirOutletNodeNum);
2775 :
2776 : // Set the outlet air nodes of the HeatingCoil
2777 233160 : airOuletNode.MassFlowRate = heatingCoil.OutletAirMassFlowRate;
2778 233160 : airOuletNode.Temp = heatingCoil.OutletAirTemp;
2779 233160 : airOuletNode.HumRat = heatingCoil.OutletAirHumRat;
2780 233160 : airOuletNode.Enthalpy = heatingCoil.OutletAirEnthalpy;
2781 :
2782 : // Set the outlet nodes for properties that just pass through & not used
2783 233160 : airOuletNode.Quality = airInletNode.Quality;
2784 233160 : airOuletNode.Press = airInletNode.Press;
2785 233160 : airOuletNode.MassFlowRateMin = airInletNode.MassFlowRateMin;
2786 233160 : airOuletNode.MassFlowRateMax = airInletNode.MassFlowRateMax;
2787 233160 : airOuletNode.MassFlowRateMinAvail = airInletNode.MassFlowRateMinAvail;
2788 233160 : airOuletNode.MassFlowRateMaxAvail = airInletNode.MassFlowRateMaxAvail;
2789 :
2790 233160 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
2791 0 : airOuletNode.CO2 = airInletNode.CO2;
2792 : }
2793 :
2794 233160 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
2795 0 : airOuletNode.GenContam = airInletNode.GenContam;
2796 : }
2797 233160 : }
2798 :
2799 233160 : void ReportHeatingCoil(EnergyPlusData &state, int const CoilNum, bool const coilIsSuppHeater)
2800 : {
2801 :
2802 : // SUBROUTINE INFORMATION:
2803 : // AUTHOR Richard Liesen
2804 : // DATE WRITTEN May 2000
2805 :
2806 : // PURPOSE OF THIS SUBROUTINE:
2807 : // This subroutine updates the report variable for the coils.
2808 :
2809 : // Using/Aliasing
2810 233160 : Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
2811 233160 : auto &heatingCoil = state.dataHeatingCoils->HeatingCoil(CoilNum);
2812 :
2813 : // report the HeatingCoil energy from this component
2814 233160 : heatingCoil.HeatingCoilRate = heatingCoil.HeatingCoilLoad;
2815 233160 : heatingCoil.HeatingCoilLoad *= TimeStepSysSec;
2816 :
2817 233160 : heatingCoil.FuelUseRate = heatingCoil.FuelUseLoad;
2818 233160 : heatingCoil.ElecUseRate = heatingCoil.ElecUseLoad;
2819 233160 : if (coilIsSuppHeater) {
2820 137752 : state.dataHVACGlobal->SuppHeatingCoilPower = heatingCoil.ElecUseLoad;
2821 : } else {
2822 95408 : state.dataHVACGlobal->ElecHeatingCoilPower = heatingCoil.ElecUseLoad;
2823 : }
2824 233160 : heatingCoil.FuelUseLoad *= TimeStepSysSec;
2825 233160 : heatingCoil.ElecUseLoad *= TimeStepSysSec;
2826 :
2827 233160 : heatingCoil.ParasiticFuelConsumption = heatingCoil.ParasiticFuelRate * TimeStepSysSec;
2828 :
2829 233160 : std::string coilObjClassName;
2830 233160 : switch (heatingCoil.HCoilType_Num) {
2831 73698 : case HVAC::Coil_HeatingElectric: {
2832 73698 : coilObjClassName = "Coil:Heating:Electric";
2833 73698 : } break;
2834 217 : case HVAC::Coil_HeatingElectric_MultiStage: {
2835 217 : coilObjClassName = "Coil:Heating:Electric:MultiStage";
2836 217 : } break;
2837 159191 : case HVAC::Coil_HeatingGasOrOtherFuel: {
2838 159191 : coilObjClassName = "Coil:Heating:Fuel";
2839 159191 : } break;
2840 50 : case HVAC::Coil_HeatingGas_MultiStage: {
2841 50 : coilObjClassName = "Coil:Heating:Gas:MultiStage";
2842 50 : } break;
2843 4 : case HVAC::Coil_HeatingDesuperheater: {
2844 4 : coilObjClassName = "Coil:Heating:Desuperheater";
2845 4 : } break;
2846 0 : default:
2847 0 : break;
2848 : }
2849 233160 : if (heatingCoil.reportCoilFinalSizes) {
2850 56127 : if (!state.dataGlobal->WarmupFlag && !state.dataGlobal->DoingHVACSizingSimulations && !state.dataGlobal->DoingSizing) {
2851 117 : state.dataRptCoilSelection->coilSelectionReportObj->setCoilFinalSizes(
2852 117 : state, heatingCoil.Name, coilObjClassName, heatingCoil.NominalCapacity, heatingCoil.NominalCapacity, -999.0, -999.0);
2853 117 : heatingCoil.reportCoilFinalSizes = false;
2854 : }
2855 : }
2856 233160 : }
2857 :
2858 : // End of Reporting subroutines for the HeatingCoil Module
2859 :
2860 84 : void GetCoilIndex(EnergyPlusData &state, std::string const &HeatingCoilName, int &HeatingCoilIndex, bool &ErrorsFound)
2861 : {
2862 :
2863 : // SUBROUTINE INFORMATION:
2864 : // AUTHOR Richard Raustad
2865 : // DATE WRITTEN March 2005
2866 :
2867 : // PURPOSE OF THIS SUBROUTINE:
2868 : // This subroutine sets an index for a given DX Coil -- issues error message if that
2869 : // DX Coil is not a legal DX Coil.
2870 :
2871 : // Obtains and Allocates HeatingCoil related parameters from input file
2872 84 : if (state.dataHeatingCoils->GetCoilsInputFlag) { // First time subroutine has been entered
2873 36 : GetHeatingCoilInput(state);
2874 36 : state.dataHeatingCoils->GetCoilsInputFlag = false;
2875 : }
2876 :
2877 84 : HeatingCoilIndex = Util::FindItem(HeatingCoilName, state.dataHeatingCoils->HeatingCoil);
2878 84 : if (HeatingCoilIndex == 0) {
2879 0 : ShowSevereError(state, format("GetCoilIndex: Heating coil not found={}", HeatingCoilName));
2880 0 : ErrorsFound = true;
2881 : }
2882 84 : }
2883 :
2884 2 : void CheckHeatingCoilSchedule(EnergyPlusData &state,
2885 : std::string const &CompType, // unused1208
2886 : std::string_view CompName,
2887 : Real64 &Value,
2888 : int &CompIndex)
2889 : {
2890 :
2891 : // SUBROUTINE INFORMATION:
2892 : // AUTHOR Linda Lawrie
2893 : // DATE WRITTEN October 2005
2894 :
2895 : // PURPOSE OF THIS SUBROUTINE:
2896 : // This routine provides a method for outside routines to check if
2897 : // the heating coil is scheduled to be on.
2898 :
2899 : // Obtains and Allocates HeatingCoil related parameters from input file
2900 2 : if (state.dataHeatingCoils->GetCoilsInputFlag) { // First time subroutine has been entered
2901 2 : GetHeatingCoilInput(state);
2902 2 : state.dataHeatingCoils->GetCoilsInputFlag = false;
2903 : }
2904 :
2905 : // Find the correct Coil number
2906 2 : if (CompIndex == 0) {
2907 2 : int CoilNum = Util::FindItem(CompName, state.dataHeatingCoils->HeatingCoil);
2908 2 : if (CoilNum == 0) {
2909 0 : ShowFatalError(state, format("CheckHeatingCoilSchedule: Coil not found=\"{}\".", CompName));
2910 : }
2911 2 : if (!Util::SameString(CompType, HVAC::cAllCoilTypes(state.dataHeatingCoils->HeatingCoil(CoilNum).HCoilType_Num))) {
2912 0 : ShowSevereError(state, format("CheckHeatingCoilSchedule: Coil=\"{}\"", CompName));
2913 0 : ShowContinueError(state,
2914 0 : format("...expected type=\"{}\", actual type=\"{}\".",
2915 : CompType,
2916 0 : HVAC::cAllCoilTypes(state.dataHeatingCoils->HeatingCoil(CoilNum).HCoilType_Num)));
2917 0 : ShowFatalError(state, "Program terminates due to preceding conditions.");
2918 : }
2919 2 : CompIndex = CoilNum;
2920 2 : Value = state.dataHeatingCoils->HeatingCoil(CoilNum).availSched->getCurrentVal(); // not scheduled?
2921 : } else {
2922 0 : int CoilNum = CompIndex;
2923 0 : if (CoilNum > state.dataHeatingCoils->NumHeatingCoils || CoilNum < 1) {
2924 0 : ShowFatalError(state,
2925 0 : format("CheckHeatingCoilSchedule: Invalid CompIndex passed={}, Number of Heating Coils={}, Coil name={}",
2926 : CoilNum,
2927 0 : state.dataHeatingCoils->NumHeatingCoils,
2928 : CompName));
2929 : }
2930 0 : if (CompName != state.dataHeatingCoils->HeatingCoil(CoilNum).Name) {
2931 0 : ShowSevereError(state,
2932 0 : format("CheckHeatingCoilSchedule: Invalid CompIndex passed={}, Coil name={}, stored Coil Name for that index={}",
2933 : CoilNum,
2934 : CompName,
2935 0 : state.dataHeatingCoils->HeatingCoil(CoilNum).Name));
2936 0 : ShowContinueError(state,
2937 0 : format("...expected type=\"{}\", actual type=\"{}\".",
2938 : CompType,
2939 0 : HVAC::cAllCoilTypes(state.dataHeatingCoils->HeatingCoil(CoilNum).HCoilType_Num)));
2940 0 : ShowFatalError(state, "Program terminates due to preceding conditions.");
2941 : }
2942 0 : Value = state.dataHeatingCoils->HeatingCoil(CoilNum).availSched->getCurrentVal(); // not scheduled?
2943 : }
2944 2 : }
2945 :
2946 22 : Real64 GetCoilCapacity(EnergyPlusData &state,
2947 : std::string const &CoilType, // must match coil types in this module
2948 : std::string const &CoilName, // must match coil names for the coil type
2949 : bool &ErrorsFound // set to true if problem
2950 : )
2951 : {
2952 :
2953 : // FUNCTION INFORMATION:
2954 : // AUTHOR Linda Lawrie
2955 : // DATE WRITTEN February 2006
2956 :
2957 : // PURPOSE OF THIS FUNCTION:
2958 : // This function looks up the coil capacity for the given coil and returns it. If
2959 : // incorrect coil type or name is given, ErrorsFound is returned as true and capacity is returned
2960 : // as negative.
2961 :
2962 : // Return value
2963 : Real64 CoilCapacity; // returned capacity of matched coil
2964 :
2965 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
2966 : int WhichCoil;
2967 :
2968 : // Obtains and Allocates HeatingCoil related parameters from input file
2969 22 : if (state.dataHeatingCoils->GetCoilsInputFlag) { // First time subroutine has been entered
2970 0 : GetHeatingCoilInput(state);
2971 0 : state.dataHeatingCoils->GetCoilsInputFlag = false;
2972 : }
2973 :
2974 22 : int FoundType = Util::FindItem(CoilType, HVAC::cAllCoilTypes, HVAC::NumAllCoilTypes);
2975 22 : if (FoundType == HVAC::Coil_HeatingElectric || FoundType == HVAC::Coil_HeatingGasOrOtherFuel ||
2976 : FoundType == HVAC::Coil_HeatingDesuperheater) {
2977 22 : WhichCoil = Util::FindItem(CoilName, state.dataHeatingCoils->HeatingCoil);
2978 22 : if (WhichCoil != 0) {
2979 22 : CoilCapacity = state.dataHeatingCoils->HeatingCoil(WhichCoil).NominalCapacity;
2980 : }
2981 0 : } else if (FoundType == HVAC::Coil_HeatingElectric_MultiStage || FoundType == HVAC::Coil_HeatingGas_MultiStage) {
2982 0 : WhichCoil = Util::FindItem(CoilName, state.dataHeatingCoils->HeatingCoil);
2983 0 : if (WhichCoil != 0) {
2984 0 : CoilCapacity =
2985 0 : state.dataHeatingCoils->HeatingCoil(WhichCoil).MSNominalCapacity(state.dataHeatingCoils->HeatingCoil(WhichCoil).NumOfStages);
2986 : }
2987 : } else {
2988 0 : WhichCoil = 0;
2989 : }
2990 :
2991 22 : if (WhichCoil == 0) { // Autodesk:Return Reworked block to assure CoilCapacity is set before return
2992 0 : if (FoundType == 0) {
2993 0 : ShowSevereError(state, format("GetCoilCapacity: Could not find Coil, Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
2994 0 : } else if (FoundType > 0) {
2995 0 : ShowSevereError(state, format("GetCoilCapacity: Invalid coil type for capacity, Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
2996 0 : ShowContinueError(state,
2997 0 : format("...only {}, {} or {} are valid in this context.",
2998 : HVAC::cAllCoilTypes(HVAC::Coil_HeatingElectric),
2999 : HVAC::cAllCoilTypes(HVAC::Coil_HeatingGasOrOtherFuel),
3000 : HVAC::cAllCoilTypes(HVAC::Coil_HeatingDesuperheater)));
3001 : }
3002 0 : ShowContinueError(state, "... returning Coil Capacity as -1000.");
3003 0 : ErrorsFound = true;
3004 0 : CoilCapacity = -1000.0;
3005 : }
3006 :
3007 22 : return CoilCapacity;
3008 : }
3009 :
3010 0 : Sched::Schedule *GetCoilAvailSched(EnergyPlusData &state,
3011 : std::string const &CoilType, // must match coil types in this module
3012 : std::string const &CoilName, // must match coil names for the coil type
3013 : bool &ErrorsFound // set to true if problem
3014 : )
3015 : {
3016 :
3017 : // FUNCTION INFORMATION:
3018 : // AUTHOR Richard Raustad, FSEC
3019 : // DATE WRITTEN February 2013
3020 :
3021 : // PURPOSE OF THIS FUNCTION:
3022 : // This function looks up the given coil and returns the availability schedule index. If
3023 : // incorrect coil type or name is given, ErrorsFound is returned as true and index is returned
3024 : // as zero.
3025 :
3026 : // Obtains and Allocates HeatingCoil related parameters from input file
3027 0 : if (state.dataHeatingCoils->GetCoilsInputFlag) { // First time subroutine has been entered
3028 0 : GetHeatingCoilInput(state);
3029 0 : state.dataHeatingCoils->GetCoilsInputFlag = false;
3030 : }
3031 :
3032 0 : int WhichCoil = 0;
3033 0 : int FoundType = Util::FindItem(CoilType, HVAC::cAllCoilTypes, HVAC::NumAllCoilTypes);
3034 0 : if (FoundType == HVAC::Coil_HeatingElectric || FoundType == HVAC::Coil_HeatingElectric_MultiStage ||
3035 0 : FoundType == HVAC::Coil_HeatingGasOrOtherFuel || FoundType == HVAC::Coil_HeatingGas_MultiStage ||
3036 : FoundType == HVAC::Coil_HeatingDesuperheater) {
3037 0 : WhichCoil = Util::FindItem(CoilName, state.dataHeatingCoils->HeatingCoil);
3038 0 : if (WhichCoil != 0) {
3039 0 : return state.dataHeatingCoils->HeatingCoil(WhichCoil).availSched;
3040 : }
3041 : } else {
3042 0 : WhichCoil = 0;
3043 : }
3044 :
3045 0 : if (WhichCoil == 0) {
3046 0 : ShowSevereError(state, format("GetCoilAvailScheduleIndex: Could not find Coil, Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
3047 0 : ErrorsFound = true;
3048 : }
3049 :
3050 0 : return nullptr;
3051 : }
3052 :
3053 21 : int GetCoilInletNode(EnergyPlusData &state,
3054 : std::string_view CoilType, // must match coil types in this module
3055 : std::string const &CoilName, // must match coil names for the coil type
3056 : bool &ErrorsFound // set to true if problem
3057 : )
3058 : {
3059 :
3060 : // FUNCTION INFORMATION:
3061 : // AUTHOR Linda Lawrie
3062 : // DATE WRITTEN February 2006
3063 :
3064 : // PURPOSE OF THIS FUNCTION:
3065 : // This function looks up the given coil and returns the inlet node number. If
3066 : // incorrect coil type or name is given, ErrorsFound is returned as true and node number is returned
3067 : // as zero.
3068 :
3069 : // Obtains and Allocates HeatingCoil related parameters from input file
3070 21 : if (state.dataHeatingCoils->GetCoilsInputFlag) { // First time subroutine has been entered
3071 6 : GetHeatingCoilInput(state);
3072 6 : state.dataHeatingCoils->GetCoilsInputFlag = false;
3073 : }
3074 :
3075 21 : int WhichCoil = 0;
3076 21 : int NodeNumber = 0;
3077 21 : int FoundType = Util::FindItem(CoilType, HVAC::cAllCoilTypes, HVAC::NumAllCoilTypes);
3078 21 : if (FoundType == HVAC::Coil_HeatingElectric || FoundType == HVAC::Coil_HeatingElectric_MultiStage ||
3079 0 : FoundType == HVAC::Coil_HeatingGasOrOtherFuel || FoundType == HVAC::Coil_HeatingGas_MultiStage ||
3080 : FoundType == HVAC::Coil_HeatingDesuperheater) {
3081 21 : WhichCoil = Util::FindItem(CoilName, state.dataHeatingCoils->HeatingCoil);
3082 21 : if (WhichCoil != 0) {
3083 21 : NodeNumber = state.dataHeatingCoils->HeatingCoil(WhichCoil).AirInletNodeNum;
3084 : }
3085 : } else {
3086 0 : WhichCoil = 0;
3087 : }
3088 :
3089 21 : if (WhichCoil == 0) {
3090 0 : ShowSevereError(state, format("GetCoilInletNode: Could not find Coil, Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
3091 0 : ErrorsFound = true;
3092 0 : NodeNumber = 0;
3093 : }
3094 :
3095 21 : return NodeNumber;
3096 : }
3097 :
3098 24 : int GetCoilOutletNode(EnergyPlusData &state,
3099 : std::string_view CoilType, // must match coil types in this module
3100 : std::string const &CoilName, // must match coil names for the coil type
3101 : bool &ErrorsFound // set to true if problem
3102 : )
3103 : {
3104 :
3105 : // FUNCTION INFORMATION:
3106 : // AUTHOR Richard Raustad
3107 : // DATE WRITTEN August 2006
3108 :
3109 : // PURPOSE OF THIS FUNCTION:
3110 : // This function looks up the given coil and returns the outlet node number. If
3111 : // incorrect coil type or name is given, ErrorsFound is returned as true and node number is returned
3112 : // as zero.
3113 :
3114 : // Obtains and Allocates HeatingCoil related parameters from input file
3115 24 : if (state.dataHeatingCoils->GetCoilsInputFlag) { // First time subroutine has been entered
3116 2 : GetHeatingCoilInput(state);
3117 2 : state.dataHeatingCoils->GetCoilsInputFlag = false;
3118 : }
3119 :
3120 24 : int WhichCoil = 0;
3121 24 : int NodeNumber = 0;
3122 24 : int FoundType = Util::FindItem(CoilType, HVAC::cAllCoilTypes, HVAC::NumAllCoilTypes);
3123 24 : if (FoundType == HVAC::Coil_HeatingElectric || FoundType == HVAC::Coil_HeatingElectric_MultiStage ||
3124 0 : FoundType == HVAC::Coil_HeatingGasOrOtherFuel || FoundType == HVAC::Coil_HeatingGas_MultiStage ||
3125 : FoundType == HVAC::Coil_HeatingDesuperheater) {
3126 24 : WhichCoil = Util::FindItem(CoilName, state.dataHeatingCoils->HeatingCoil);
3127 24 : if (WhichCoil != 0) {
3128 24 : NodeNumber = state.dataHeatingCoils->HeatingCoil(WhichCoil).AirOutletNodeNum;
3129 : }
3130 : } else {
3131 0 : WhichCoil = 0;
3132 : }
3133 :
3134 24 : if (WhichCoil == 0) {
3135 0 : ShowSevereError(state, format("GetCoilOutletNode: Could not find Coil, Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
3136 0 : ErrorsFound = true;
3137 0 : NodeNumber = 0;
3138 : }
3139 :
3140 24 : return NodeNumber;
3141 : }
3142 :
3143 3 : int GetHeatReclaimSourceIndex(EnergyPlusData &state,
3144 : std::string const &CoilType, // must match coil types in this module
3145 : std::string const &CoilName, // must match coil names for the coil type
3146 : bool &ErrorsFound // set to true if problem
3147 : )
3148 : {
3149 :
3150 : // FUNCTION INFORMATION:
3151 : // AUTHOR Richard Raustad
3152 : // DATE WRITTEN June 2007
3153 :
3154 : // PURPOSE OF THIS FUNCTION:
3155 : // This function looks up the given coil and returns the heating coil index number if it is a desuperheating coil.
3156 : // If incorrect coil type or name is given, ErrorsFound is returned as true and index number is returned
3157 : // as zero.
3158 :
3159 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
3160 : bool GetCoilErrFlag;
3161 : int NumCoil;
3162 3 : int CoilNum(0);
3163 :
3164 : // Obtains and Allocates HeatingCoil related parameters from input file
3165 3 : if (state.dataHeatingCoils->GetCoilsInputFlag) { // First time subroutine has been entered
3166 1 : GetHeatingCoilInput(state);
3167 1 : state.dataHeatingCoils->GetCoilsInputFlag = false;
3168 : }
3169 :
3170 3 : int CoilFound = 0;
3171 :
3172 : // note should eventually get rid of this string comparison
3173 4 : if (Util::SameString(CoilType, "COIL:COOLING:DX:SINGLESPEED") || Util::SameString(CoilType, "COIL:COOLING:DX:TWOSPEED") ||
3174 4 : Util::SameString(CoilType, "COIL:COOLING:DX:TWOSTAGEWITHHUMIDITYCONTROLMODE")) {
3175 2 : bool SuppressWarning = true;
3176 2 : DXCoils::GetDXCoilIndex(state, CoilName, CoilNum, GetCoilErrFlag, CoilType, SuppressWarning);
3177 5 : for (NumCoil = 1; NumCoil <= state.dataHeatingCoils->NumHeatingCoils; ++NumCoil) {
3178 3 : if (state.dataHeatingCoils->HeatingCoil(NumCoil).ReclaimHeatingSource != HeatObjTypes::COIL_DX_COOLING &&
3179 3 : state.dataHeatingCoils->HeatingCoil(NumCoil).ReclaimHeatingSource != HeatObjTypes::COIL_DX_MULTISPEED &&
3180 9 : state.dataHeatingCoils->HeatingCoil(NumCoil).ReclaimHeatingSource != HeatObjTypes::COIL_DX_MULTIMODE &&
3181 3 : state.dataHeatingCoils->HeatingCoil(NumCoil).ReclaimHeatingCoilName != CoilName)
3182 3 : continue;
3183 0 : CoilFound = CoilNum;
3184 0 : break;
3185 : }
3186 1 : } else if (Util::SameString(CoilType, "COIL:COOLING:DX:VARIABLESPEED")) {
3187 1 : CoilNum = VariableSpeedCoils::GetCoilIndexVariableSpeed(state, CoilType, CoilName, GetCoilErrFlag);
3188 3 : for (NumCoil = 1; NumCoil <= state.dataHeatingCoils->NumHeatingCoils; ++NumCoil) {
3189 4 : if (state.dataHeatingCoils->HeatingCoil(NumCoil).ReclaimHeatingSource != HeatObjTypes::COIL_DX_VARIABLE_COOLING &&
3190 2 : state.dataHeatingCoils->HeatingCoil(NumCoil).ReclaimHeatingCoilName != CoilName)
3191 2 : continue;
3192 0 : CoilFound = CoilNum;
3193 0 : break;
3194 : }
3195 : }
3196 :
3197 3 : if (CoilNum == 0) {
3198 0 : ErrorsFound = true;
3199 : }
3200 :
3201 3 : return CoilFound;
3202 : }
3203 :
3204 3 : int GetCoilControlNodeNum(EnergyPlusData &state,
3205 : std::string const &CoilType, // must match coil types in this module
3206 : std::string const &CoilName, // must match coil names for the coil type
3207 : bool &ErrorsFound // set to true if problem
3208 : )
3209 : {
3210 :
3211 : // FUNCTION INFORMATION:
3212 : // AUTHOR Richard Raustad
3213 : // DATE WRITTEN June 2007
3214 :
3215 : // PURPOSE OF THIS FUNCTION:
3216 : // This function looks up the given coil and returns the control node number. If
3217 : // incorrect coil type or name is given, ErrorsFound is returned as true and node number is returned
3218 : // as zero.
3219 :
3220 : // Obtains and Allocates HeatingCoil related parameters from input file
3221 3 : if (state.dataHeatingCoils->GetCoilsInputFlag) { // First time subroutine has been entered
3222 0 : GetHeatingCoilInput(state);
3223 0 : state.dataHeatingCoils->GetCoilsInputFlag = false;
3224 : }
3225 :
3226 3 : int FoundType = Util::FindItem(CoilType, HVAC::cAllCoilTypes, HVAC::NumAllCoilTypes);
3227 3 : if (FoundType == HVAC::Coil_HeatingElectric || FoundType == HVAC::Coil_HeatingElectric_MultiStage ||
3228 0 : FoundType == HVAC::Coil_HeatingGasOrOtherFuel || FoundType == HVAC::Coil_HeatingGas_MultiStage ||
3229 : FoundType == HVAC::Coil_HeatingDesuperheater) {
3230 3 : int WhichCoil = Util::FindItem(CoilName, state.dataHeatingCoils->HeatingCoil);
3231 3 : if (WhichCoil != 0) {
3232 3 : return state.dataHeatingCoils->HeatingCoil(WhichCoil).TempSetPointNodeNum;
3233 : }
3234 : }
3235 :
3236 0 : ShowSevereError(state, format("GetCoilControlNodeNum: Could not find Coil, Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
3237 0 : ErrorsFound = true;
3238 0 : return 0;
3239 : }
3240 :
3241 81 : int GetHeatingCoilTypeNum(EnergyPlusData &state,
3242 : std::string const &CoilType, // must match coil types in this module
3243 : std::string const &CoilName, // must match coil names for the coil type
3244 : bool &ErrorsFound // set to true if problem
3245 : )
3246 : {
3247 :
3248 : // FUNCTION INFORMATION:
3249 : // AUTHOR Richard Raustad
3250 : // DATE WRITTEN August 2008
3251 :
3252 : // PURPOSE OF THIS FUNCTION:
3253 : // This function looks up the given coil and returns the type number. If
3254 : // incorrect coil type or name is given, ErrorsFound is returned as true and type number is returned
3255 : // as zero.
3256 :
3257 : // Obtains and Allocates HeatingCoil related parameters from input file
3258 81 : if (state.dataHeatingCoils->GetCoilsInputFlag) { // First time subroutine has been entered
3259 49 : GetHeatingCoilInput(state);
3260 49 : state.dataHeatingCoils->GetCoilsInputFlag = false;
3261 : }
3262 :
3263 81 : int FoundType = Util::FindItem(CoilType, HVAC::cAllCoilTypes, HVAC::NumAllCoilTypes);
3264 81 : if (FoundType == HVAC::Coil_HeatingElectric || FoundType == HVAC::Coil_HeatingElectric_MultiStage ||
3265 1 : FoundType == HVAC::Coil_HeatingGasOrOtherFuel || FoundType == HVAC::Coil_HeatingGas_MultiStage ||
3266 : FoundType == HVAC::Coil_HeatingDesuperheater) {
3267 81 : int WhichCoil = Util::FindItem(CoilName, state.dataHeatingCoils->HeatingCoil);
3268 81 : if (WhichCoil != 0) {
3269 81 : return state.dataHeatingCoils->HeatingCoil(WhichCoil).HCoilType_Num;
3270 : }
3271 : }
3272 :
3273 0 : ShowSevereError(state, format("GetHeatingCoilTypeNum: Could not find Coil, Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
3274 0 : ErrorsFound = true;
3275 0 : return 0;
3276 : }
3277 :
3278 37 : int GetHeatingCoilIndex(EnergyPlusData &state,
3279 : std::string const &CoilType, // must match coil types in this module
3280 : std::string const &CoilName, // must match coil names for the coil type
3281 : bool &ErrorsFound // set to true if problem
3282 : )
3283 : {
3284 :
3285 : // FUNCTION INFORMATION:
3286 : // AUTHOR Linda Lawrie
3287 : // DATE WRITTEN February 2011
3288 :
3289 : // PURPOSE OF THIS FUNCTION:
3290 : // This function looks up the given coil and returns the index into the structure. If
3291 : // incorrect coil type or name is given, ErrorsFound is returned as true and index is returned
3292 : // as zero.
3293 :
3294 : // Obtains and Allocates HeatingCoil related parameters from input file
3295 37 : if (state.dataHeatingCoils->GetCoilsInputFlag) { // First time subroutine has been entered
3296 2 : GetHeatingCoilInput(state);
3297 2 : state.dataHeatingCoils->GetCoilsInputFlag = false;
3298 : }
3299 :
3300 37 : int WhichCoil = 0;
3301 37 : int FoundType = Util::FindItem(CoilType, HVAC::cAllCoilTypes, HVAC::NumAllCoilTypes);
3302 37 : if (FoundType == HVAC::Coil_HeatingElectric || FoundType == HVAC::Coil_HeatingElectric_MultiStage ||
3303 0 : FoundType == HVAC::Coil_HeatingGasOrOtherFuel || FoundType == HVAC::Coil_HeatingGas_MultiStage ||
3304 : FoundType == HVAC::Coil_HeatingDesuperheater) {
3305 37 : WhichCoil = Util::FindItem(CoilName, state.dataHeatingCoils->HeatingCoil);
3306 : }
3307 :
3308 37 : if (WhichCoil == 0) {
3309 0 : ShowSevereError(state, format("GetHeatingCoilIndex: Could not find Coil, Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
3310 0 : ErrorsFound = true;
3311 : }
3312 :
3313 37 : return WhichCoil;
3314 : }
3315 :
3316 0 : int GetHeatingCoilPLFCurveIndex(EnergyPlusData &state,
3317 : std::string const &CoilType, // must match coil types in this module
3318 : std::string const &CoilName, // must match coil names for the coil type
3319 : bool &ErrorsFound // set to true if problem
3320 : )
3321 : {
3322 :
3323 : // FUNCTION INFORMATION:
3324 : // AUTHOR Richard Raustad
3325 : // DATE WRITTEN December 2008
3326 :
3327 : // PURPOSE OF THIS FUNCTION:
3328 : // This function looks up the given coil and returns the PLF curve index. If
3329 : // incorrect coil name is given for gas or electric heating coils, ErrorsFound
3330 : // is returned as true and curve index is returned as zero.
3331 : // If not a gas or electric heating coil, ErrorsFound is unchanged and index is 0.
3332 :
3333 : // Obtains and Allocates HeatingCoil related parameters from input file
3334 0 : if (state.dataHeatingCoils->GetCoilsInputFlag) { // First time subroutine has been entered
3335 0 : GetHeatingCoilInput(state);
3336 0 : state.dataHeatingCoils->GetCoilsInputFlag = false;
3337 : }
3338 :
3339 0 : int FoundType = Util::FindItem(CoilType, HVAC::cAllCoilTypes, HVAC::NumAllCoilTypes);
3340 0 : if (FoundType == HVAC::Coil_HeatingElectric || FoundType == HVAC::Coil_HeatingElectric_MultiStage ||
3341 0 : FoundType == HVAC::Coil_HeatingGasOrOtherFuel || FoundType == HVAC::Coil_HeatingGas_MultiStage ||
3342 : FoundType == HVAC::Coil_HeatingDesuperheater) {
3343 0 : int WhichCoil = Util::FindItem(CoilName, state.dataHeatingCoils->HeatingCoil);
3344 0 : if (WhichCoil != 0) {
3345 0 : return state.dataHeatingCoils->HeatingCoil(WhichCoil).PLFCurveIndex;
3346 : } else {
3347 0 : ShowSevereError(state, format("GetHeatingCoilPLFCurveIndex: Could not find Coil, Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
3348 0 : ErrorsFound = true;
3349 0 : return 0;
3350 : }
3351 : } else {
3352 0 : return 0;
3353 : }
3354 : }
3355 :
3356 0 : int GetHeatingCoilNumberOfStages(EnergyPlusData &state,
3357 : std::string const &CoilType, // must match coil types in this module
3358 : std::string const &CoilName, // must match coil names for the coil type
3359 : bool &ErrorsFound // set to true if problem
3360 : )
3361 : {
3362 :
3363 : // FUNCTION INFORMATION:
3364 : // AUTHOR Chandan Sharma
3365 : // DATE WRITTEN February 2013
3366 :
3367 : // PURPOSE OF THIS FUNCTION:
3368 : // This function looks up the given coil and returns the number of speeds for multistage coils.
3369 : // If incorrect coil type or name is given, ErrorsFound is returned as true.
3370 :
3371 : // Obtains and Allocates HeatingCoils
3372 0 : if (state.dataHeatingCoils->GetCoilsInputFlag) { // First time subroutine has been entered
3373 0 : GetHeatingCoilInput(state);
3374 0 : state.dataHeatingCoils->GetCoilsInputFlag = false;
3375 : }
3376 :
3377 0 : int WhichCoil = Util::FindItemInList(CoilName, state.dataHeatingCoils->HeatingCoil);
3378 0 : if (WhichCoil != 0) {
3379 0 : return state.dataHeatingCoils->HeatingCoil(WhichCoil).NumOfStages;
3380 : } else {
3381 0 : ShowSevereError(state, format("GetHeatingCoilNumberOfSpeeds: Invalid Heating Coil Type=\"{}\" Name=\"{}\"", CoilType, CoilName));
3382 0 : ErrorsFound = true;
3383 0 : return 0;
3384 : }
3385 : }
3386 :
3387 3 : void SetHeatingCoilData(EnergyPlusData &state,
3388 : int const CoilNum, // Number of electric or gas heating Coil
3389 : bool &ErrorsFound, // Set to true if certain errors found
3390 : ObjexxFCL::Optional_bool DesiccantRegenerationCoil, // Flag that this coil is used as regeneration air heating coil
3391 : ObjexxFCL::Optional_int DesiccantDehumIndex // Index for the desiccant dehum system where this coil is used
3392 : )
3393 : {
3394 :
3395 : // FUNCTION INFORMATION:
3396 : // AUTHOR Bereket Nigusse
3397 : // DATE WRITTEN February 2016
3398 :
3399 : // PURPOSE OF THIS FUNCTION:
3400 : // This function sets data to Heating Coil using the coil index and arguments passed
3401 :
3402 3 : auto &heatingCoil = state.dataHeatingCoils->HeatingCoil(CoilNum);
3403 3 : if (state.dataHeatingCoils->GetCoilsInputFlag) {
3404 0 : GetHeatingCoilInput(state);
3405 0 : state.dataHeatingCoils->GetCoilsInputFlag = false;
3406 : }
3407 :
3408 3 : if (CoilNum <= 0 || CoilNum > state.dataHeatingCoils->NumHeatingCoils) {
3409 0 : ShowSevereError(state,
3410 0 : format("SetHeatingCoilData: called with heating coil Number out of range={} should be >0 and <{}",
3411 : CoilNum,
3412 0 : state.dataHeatingCoils->NumHeatingCoils));
3413 0 : ErrorsFound = true;
3414 0 : return;
3415 : }
3416 :
3417 3 : if (present(DesiccantRegenerationCoil)) {
3418 3 : heatingCoil.DesiccantRegenerationCoil = DesiccantRegenerationCoil;
3419 : }
3420 :
3421 3 : if (present(DesiccantDehumIndex)) {
3422 3 : heatingCoil.DesiccantDehumNum = DesiccantDehumIndex;
3423 : }
3424 : }
3425 :
3426 3 : void SetHeatingCoilAirLoopNumber(EnergyPlusData &state, std::string const &HeatingCoilName, int AirLoopNum, bool &ErrorsFound)
3427 : {
3428 : // SUBROUTINE INFORMATION:
3429 : // AUTHOR L.Gu
3430 : // DATE WRITTEN March 2018
3431 :
3432 : // PURPOSE OF THIS SUBROUTINE:
3433 : // This subroutine sets an AirLoopNum for a given heating Coil
3434 :
3435 : int HeatingCoilIndex;
3436 :
3437 3 : if (state.dataHeatingCoils->GetCoilsInputFlag) { // First time subroutine has been entered
3438 0 : GetHeatingCoilInput(state);
3439 0 : state.dataHeatingCoils->GetCoilsInputFlag = false;
3440 : }
3441 :
3442 3 : HeatingCoilIndex = Util::FindItem(HeatingCoilName, state.dataHeatingCoils->HeatingCoil);
3443 3 : if (HeatingCoilIndex == 0) {
3444 0 : ShowSevereError(state, format("GetCoilIndex: Heating coil not found={}", HeatingCoilName));
3445 0 : ErrorsFound = true;
3446 : } else {
3447 3 : state.dataHeatingCoils->HeatingCoil(HeatingCoilIndex).AirLoopNum = AirLoopNum;
3448 : }
3449 3 : }
3450 : } // namespace HeatingCoils
3451 :
3452 : } // namespace EnergyPlus
|