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 <cassert>
50 : #include <cmath>
51 :
52 : // ObjexxFCL Headers
53 : #include <ObjexxFCL/Array.functions.hh>
54 :
55 : // EnergyPlus Headers
56 : #include <AirflowNetwork/Solver.hpp>
57 : #include <EnergyPlus/Autosizing/Base.hh>
58 : #include <EnergyPlus/BranchInputManager.hh>
59 : #include <EnergyPlus/BranchNodeConnections.hh>
60 : #include <EnergyPlus/Coils/CoilCoolingDX.hh>
61 : #include <EnergyPlus/DXCoils.hh>
62 : #include <EnergyPlus/Data/EnergyPlusData.hh>
63 : #include <EnergyPlus/DataAirSystems.hh>
64 : #include <EnergyPlus/DataHVACGlobals.hh>
65 : #include <EnergyPlus/DataHeatBalFanSys.hh>
66 : #include <EnergyPlus/DataHeatBalance.hh>
67 : #include <EnergyPlus/DataIPShortCuts.hh>
68 : #include <EnergyPlus/DataSizing.hh>
69 : #include <EnergyPlus/DataZoneControls.hh>
70 : #include <EnergyPlus/DataZoneEnergyDemands.hh>
71 : #include <EnergyPlus/DataZoneEquipment.hh>
72 : #include <EnergyPlus/EMSManager.hh>
73 : #include <EnergyPlus/Fans.hh>
74 : #include <EnergyPlus/FluidProperties.hh>
75 : #include <EnergyPlus/Furnaces.hh>
76 : #include <EnergyPlus/General.hh>
77 : #include <EnergyPlus/GeneralRoutines.hh>
78 : #include <EnergyPlus/GlobalNames.hh>
79 : #include <EnergyPlus/HVACControllers.hh>
80 : #include <EnergyPlus/HVACHXAssistedCoolingCoil.hh>
81 : #include <EnergyPlus/HeatingCoils.hh>
82 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
83 : #include <EnergyPlus/IntegratedHeatPump.hh>
84 : #include <EnergyPlus/NodeInputManager.hh>
85 : #include <EnergyPlus/OutAirNodeManager.hh>
86 : #include <EnergyPlus/OutputProcessor.hh>
87 : #include <EnergyPlus/OutputReportPredefined.hh>
88 : #include <EnergyPlus/PlantUtilities.hh>
89 : #include <EnergyPlus/Psychrometrics.hh>
90 : #include <EnergyPlus/ScheduleManager.hh>
91 : #include <EnergyPlus/SteamCoils.hh>
92 : #include <EnergyPlus/WaterCoils.hh>
93 : #include <EnergyPlus/WaterToAirHeatPump.hh>
94 : #include <EnergyPlus/WaterToAirHeatPumpSimple.hh>
95 : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
96 :
97 : namespace EnergyPlus {
98 :
99 : namespace Furnaces {
100 : // Module containing the Furnace and Unitary System simulation routines
101 :
102 : // MODULE INFORMATION:
103 : // AUTHOR Dan Fisher
104 : // DATE WRITTEN Jan 2001
105 : // MODIFIED Richard Liesen, Feb 2001; Don Shirey, Mar/Oct 2001, Oct 2003
106 : // Richard Raustad, Nov 2006 - allow draw through fan and alternate air flow in cooling,
107 : // heating, and when no cooling or heating is required.
108 : // Bereket Nigusse, FSEC, June 2010 - deprecated supply air flow fraction through controlled
109 : // zone from the furnace object input field. Now, the flow fraction is calculated internally
110 : // B. Nigusse, FSEC, Jan 2012 - added steam and hot water heating coils as an option
111 : // Bo Shen, ORNL, March 2012 - added variable-speed water source heat pump cooling and heating coils, using curve-fits
112 : // Bo Shen, ORNL, July 2012 - added variable-speed air source heat pump cooling and heating coils, using curve-fits
113 :
114 : // PURPOSE OF THIS MODULE:
115 : // To encapsulate the data and algorithms required to
116 : // manage the Furnace/Unitary System Compound Component
117 :
118 : // METHODOLOGY EMPLOYED:
119 : // Calculates the part-load ratio of the HVAC system to meet the zone sensible load. For non-heat pump HVAC systems,
120 : // if humidity control is specified and the latent capacity at the sensible PLR is insufficient to meet the latent load,
121 : // calculate a latent part-load ratio to meet the zone sensible load (MultiMode dehumidification control) or the zone
122 : // latent load (CoolReheat dehumidification control). Use the greater of the sensible PLR and latent PLR to control
123 : // the HVAC system.
124 : // Subroutines:
125 : // SimFurnace - Top level simulate routine CALLed by other modules. Each child object is simulated a final time after
126 : // the part-load ratio for child components has been determined.
127 : // Note: A supplemental heater augments the heating capacity for both air-to-air and water-to-air heat pump systems.
128 : // A reheat coil is used for the HeatCool furnace/unitarysystem to offset the sensible cooling when the
129 : // dehumidification control type is COOLREHEAT. Both the supplemental and reheat heating coil load is calculated
130 : // in the Calc routines. The actual simulation of these coils is performed in the SimFurnace routine (i.e. the
131 : // supplemental and reheat coil loads are passed as 0 to CalcFurnaceOutput).
132 : // CalcNewZoneHeatOnlyFlowRates - HeatOnly furnace/unitarysystem routine.
133 : // Calculates a part-load ratio to meet the sensible load.
134 : // CalcNewZoneHeatCoolFlowRates - HeatCool furnace/unitarysystem and air-to-air HeatPump routine.
135 : // Calculates a part-load ratio for the system (sensible and/or latent).
136 : // For dehumidification control type COOLREHEAT, both a sensible and latent PLR
137 : // may exist for a single time step (heating and dehumidification can occur). For all
138 : // other system types, only a single PLR is allowed for any given time step.
139 : // Order of simulation depends on dehumidification control option as described below.
140 : // Dehumidification control options (non-heat pump versions):
141 : // Dehumidification Control NONE: Cooling performance is simulated first and then heating performance. If a HX
142 : // assisted cooling coil is selected, the HX is always active (cooling).
143 : // Dehumidification Control COOLREHEAT: For cooling operation, the sensible capacity is calculated to
144 : // meet the thermostat setpoint. If a HX assisted cooling coil is selected,
145 : // the HX is always active. If the latent load is not met by operating the
146 : // system at the sensible PLR, a new PLR is calculated to meet the humidistat
147 : // setpoint. The reheat coil load is then calculated to meet the HEATING
148 : // setpoint temperature.
149 : // Dehumidification Control MULTIMODE: For cooling operation, the sensible capacity is calculated to
150 : // meet the thermostat setpoint. If a HX assisted cooling coil is selected,
151 : // the HX is off for this calculation. If the latent load is not met by operating
152 : // the system at the sensible PLR, a new PLR is calculated with the HX operating
153 : // and the target is the zone SENSIBLE load (thermostat setpoint). Humidity is not
154 : // controlled in this mode. No reheat coil is used in this configuration.
155 : // CalcWaterToAirHeatPump - Water-to-air HeatPump routine.
156 : // Calculates a part-load ratio to meet the sensible load.
157 : // CalcFurnaceOutput - Simulates each child component in order.
158 : // For cooling operation, the heating coil is off.
159 : // For heating operation, the cooling coil is off.
160 : // Reheat or supplemental heating coil is simulated here just to pass the inlet node conditions
161 : // to the output node (actual simulation of these coils is done on the final simulation of the
162 : // child components in SimFurnace).
163 : // Fan is simulated based on placement (drawthru or blowthru).
164 :
165 : // MODULE PARAMETER DEFINITIONS
166 : static constexpr std::string_view BlankString;
167 :
168 : // Functions
169 :
170 15222 : void SimFurnace(EnergyPlusData &state,
171 : std::string_view FurnaceName,
172 : bool const FirstHVACIteration,
173 : int const AirLoopNum, // Primary air loop number
174 : int &CompIndex // Pointer to which furnace
175 : )
176 : {
177 :
178 : // SUBROUTINE INFORMATION:
179 : // AUTHOR Dan Fisher
180 : // DATE WRITTEN Jan 2001
181 : // MODIFIED Richard Liesen, Oct 2001 - Richard Raustad; Bo Shen, March 2012, for VS WSHP
182 : // RE-ENGINEERED Feb 2001
183 :
184 : // PURPOSE OF THIS SUBROUTINE:
185 : // This subroutine manages Furnace component simulation.
186 :
187 : // METHODOLOGY EMPLOYED:
188 : // Call the calc routine to determine an operating PLR. Resimulate child components at this PLR.
189 : // A supplemental heater augments the heating capacity for both air-to-air and water-to-air heat pump systems.
190 : // A reheat coil is used for the HeatCool furnace/unitarysystem to offset the sensible cooling when the
191 : // dehumidification control type is COOLREHEAT. Both the supplemental and reheat heating coil load is calculated
192 : // in the Calc routines and returned here through subroutine arguments. The actual simulation of these coils is
193 : // performed here (i.e. the supplemental and reheat coil loads are passed as 0 to CalcFurnaceOutput).
194 :
195 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
196 : int FurnaceNum; // Furnace number
197 15222 : Real64 HeatCoilLoad(0.0); // Zone heating coil load
198 : Real64 ReheatCoilLoad; // Load to be met by the reheat coil (if high humidity control)
199 : Real64 MoistureLoad; // Control zone latent load
200 15222 : Real64 Dummy(0.0);
201 15222 : HVAC::FanOp fanOp = HVAC::FanOp::Invalid; // Fan operating mode (1=FanOp::Cycling, 2=FanOp::Continuous)
202 :
203 : Real64 QActual; // actual heating coil output (W)
204 : bool SuppHeatingCoilFlag; // true if supplemental heating coil
205 :
206 : // Obtains and Allocates Furnace related parameters from input file
207 15222 : if (state.dataFurnaces->GetFurnaceInputFlag) { // First time subroutine has been entered
208 : // Get the furnace input
209 2 : GetFurnaceInput(state);
210 2 : state.dataFurnaces->GetFurnaceInputFlag = false;
211 : }
212 :
213 : // Find the correct Furnace
214 15222 : if (CompIndex == 0) {
215 3 : FurnaceNum = Util::FindItemInList(FurnaceName, state.dataFurnaces->Furnace);
216 3 : if (FurnaceNum == 0) {
217 0 : ShowFatalError(state, format("SimFurnace: Unit not found={}", FurnaceName));
218 : }
219 3 : CompIndex = FurnaceNum;
220 : } else {
221 15219 : FurnaceNum = CompIndex;
222 15219 : if (FurnaceNum > state.dataFurnaces->NumFurnaces || FurnaceNum < 1) {
223 0 : ShowFatalError(state,
224 0 : format("SimFurnace: Invalid CompIndex passed={}, Number of Units={}, Entered Unit name={}",
225 : FurnaceNum,
226 0 : state.dataFurnaces->NumFurnaces,
227 : FurnaceName));
228 : }
229 15219 : if (state.dataFurnaces->CheckEquipName(FurnaceNum)) {
230 2 : if (FurnaceName != state.dataFurnaces->Furnace(FurnaceNum).Name) {
231 0 : ShowFatalError(state,
232 0 : format("SimFurnace: Invalid CompIndex passed={}, Unit name={}, stored Unit Name for that index={}",
233 : FurnaceNum,
234 : FurnaceName,
235 0 : state.dataFurnaces->Furnace(FurnaceNum).Name));
236 : }
237 2 : state.dataFurnaces->CheckEquipName(FurnaceNum) = false;
238 : }
239 : }
240 :
241 15222 : bool HXUnitOn = false; // flag to control HX assisted cooling coil
242 15222 : Real64 OnOffAirFlowRatio = 0.0; // Ratio of compressor ON air flow to AVERAGE air flow over time step
243 : // here we need to deal with sequenced zone equip sensible load in control zone
244 15222 : Real64 ZoneLoad = 0.0;
245 :
246 15222 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
247 15222 : auto &zoneSysEnergyDemand = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(thisFurnace.ControlZoneNum);
248 15222 : if (thisFurnace.ZoneSequenceCoolingNum > 0 && thisFurnace.ZoneSequenceHeatingNum > 0) {
249 15220 : Real64 ZoneLoadToCoolSPSequenced = zoneSysEnergyDemand.SequencedOutputRequiredToCoolingSP(thisFurnace.ZoneSequenceCoolingNum);
250 15220 : Real64 ZoneLoadToHeatSPSequenced = zoneSysEnergyDemand.SequencedOutputRequiredToHeatingSP(thisFurnace.ZoneSequenceHeatingNum);
251 15220 : auto const &tempControlType = state.dataHeatBalFanSys->TempControlType(thisFurnace.ControlZoneNum);
252 15220 : if (ZoneLoadToHeatSPSequenced > 0.0 && ZoneLoadToCoolSPSequenced > 0.0 && tempControlType != HVAC::SetptType::SingleCool) {
253 8360 : ZoneLoad = ZoneLoadToHeatSPSequenced;
254 6860 : } else if (ZoneLoadToHeatSPSequenced > 0.0 && ZoneLoadToCoolSPSequenced > 0.0 && tempControlType == HVAC::SetptType::SingleCool) {
255 0 : ZoneLoad = 0.0;
256 6860 : } else if (ZoneLoadToHeatSPSequenced < 0.0 && ZoneLoadToCoolSPSequenced < 0.0 && tempControlType != HVAC::SetptType::SingleHeat) {
257 6748 : ZoneLoad = ZoneLoadToCoolSPSequenced;
258 112 : } else if (ZoneLoadToHeatSPSequenced < 0.0 && ZoneLoadToCoolSPSequenced < 0.0 && tempControlType == HVAC::SetptType::SingleHeat) {
259 0 : ZoneLoad = 0.0;
260 112 : } else if (ZoneLoadToHeatSPSequenced <= 0.0 && ZoneLoadToCoolSPSequenced >= 0.0) {
261 112 : ZoneLoad = 0.0;
262 : }
263 15220 : MoistureLoad = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(thisFurnace.ControlZoneNum)
264 15220 : .SequencedOutputRequiredToDehumidSP(thisFurnace.ZoneSequenceCoolingNum);
265 15220 : } else {
266 2 : ZoneLoad = zoneSysEnergyDemand.RemainingOutputRequired;
267 2 : MoistureLoad = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(thisFurnace.ControlZoneNum).OutputRequiredToDehumidifyingSP;
268 : }
269 :
270 : // H2OHtOfVap
271 15222 : MoistureLoad *= Psychrometrics::PsyHfgAirFnWTdb(state.dataLoopNodes->Node(thisFurnace.NodeNumOfControlledZone).HumRat,
272 15222 : state.dataLoopNodes->Node(thisFurnace.NodeNumOfControlledZone).Temp);
273 :
274 : // Initialize Furnace Flows
275 15222 : InitFurnace(state, FurnaceNum, AirLoopNum, OnOffAirFlowRatio, fanOp, ZoneLoad, MoistureLoad, FirstHVACIteration);
276 :
277 15222 : int FurnaceInletNode = thisFurnace.FurnaceInletNodeNum;
278 :
279 : // MassFlowRateMaxAvail issues are impeding non-VAV air loop equipment by limiting air flow
280 : // temporarily open up flow limits while simulating, and then set this same value at the INLET after this parent has simulated
281 15222 : Real64 TempMassFlowRateMaxAvail = state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRateMaxAvail;
282 15222 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRateMaxAvail = thisFurnace.DesignMassFlowRate;
283 :
284 15222 : Real64 FurnaceSavMdot = state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate;
285 15222 : HVAC::CompressorOp compressorOp = HVAC::CompressorOp::On;
286 15222 : state.dataFurnaces->CoolHeatPLRRat = 1.0;
287 :
288 : // Simulate correct system type (1 of 4 choices)
289 15222 : switch (thisFurnace.type) {
290 : // Simulate HeatOnly systems:
291 0 : case HVAC::UnitarySysType::Furnace_HeatOnly:
292 : case HVAC::UnitarySysType::Unitary_HeatOnly: {
293 : // Update the furnace flow rates
294 0 : CalcNewZoneHeatOnlyFlowRates(state, FurnaceNum, FirstHVACIteration, ZoneLoad, HeatCoilLoad, OnOffAirFlowRatio);
295 :
296 0 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
297 : // simulate fan
298 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
299 : }
300 :
301 : // simulate furnace heating coil
302 0 : SuppHeatingCoilFlag = false; // if true simulates supplemental heating coil
303 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, fanOp, QActual);
304 :
305 0 : if (thisFurnace.fanPlace == HVAC::FanPlace::DrawThru) {
306 : // simulate fan
307 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
308 : }
309 0 : } break;
310 : // Simulate HeatCool systems:
311 0 : case HVAC::UnitarySysType::Furnace_HeatCool:
312 : case HVAC::UnitarySysType::Unitary_HeatCool: {
313 0 : if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) {
314 : // variable speed cooling coil
315 0 : HeatCoilLoad = 0.0;
316 0 : if (thisFurnace.bIsIHP) {
317 0 : state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).ControlledZoneTemp =
318 0 : state.dataLoopNodes->Node(thisFurnace.NodeNumOfControlledZone).Temp;
319 : }
320 0 : SimVariableSpeedHP(state, FurnaceNum, FirstHVACIteration, AirLoopNum, ZoneLoad, MoistureLoad, OnOffAirFlowRatio);
321 : } else {
322 : // calculate the system flow rate
323 0 : if (!FirstHVACIteration && thisFurnace.fanOp == HVAC::FanOp::Cycling && state.dataFurnaces->CoolingLoad &&
324 0 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).EconoActive) {
325 : // for cycling fan, cooling load, check whether furnace can meet load with compressor off
326 0 : compressorOp = HVAC::CompressorOp::Off;
327 0 : CalcNewZoneHeatCoolFlowRates(state,
328 : FurnaceNum,
329 : FirstHVACIteration,
330 : compressorOp,
331 : ZoneLoad,
332 : MoistureLoad,
333 : HeatCoilLoad,
334 : ReheatCoilLoad,
335 : OnOffAirFlowRatio,
336 : HXUnitOn);
337 0 : if (thisFurnace.CoolPartLoadRatio >= 1.0 || thisFurnace.HeatPartLoadRatio >= 1.0 ||
338 0 : (thisFurnace.CoolPartLoadRatio <= 0.0 && thisFurnace.HeatPartLoadRatio <= 0.0)) {
339 : // compressor on (reset inlet air mass flow rate to starting value)
340 0 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = FurnaceSavMdot;
341 0 : compressorOp = HVAC::CompressorOp::On;
342 0 : CalcNewZoneHeatCoolFlowRates(state,
343 : FurnaceNum,
344 : FirstHVACIteration,
345 : compressorOp,
346 : ZoneLoad,
347 : MoistureLoad,
348 : HeatCoilLoad,
349 : ReheatCoilLoad,
350 : OnOffAirFlowRatio,
351 : HXUnitOn);
352 : }
353 : } else {
354 : // compressor on
355 0 : CalcNewZoneHeatCoolFlowRates(state,
356 : FurnaceNum,
357 : FirstHVACIteration,
358 : compressorOp,
359 : ZoneLoad,
360 : MoistureLoad,
361 : HeatCoilLoad,
362 : ReheatCoilLoad,
363 : OnOffAirFlowRatio,
364 : HXUnitOn);
365 : }
366 :
367 0 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
368 : // simulate fan
369 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
370 : }
371 :
372 0 : if (!thisFurnace.CoolingCoilUpstream) {
373 : // simulate furnace heating coil
374 0 : SuppHeatingCoilFlag = false; // if true simulates supplemental heating coil
375 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, fanOp, QActual);
376 : }
377 :
378 : // simulate furnace DX cooling coil
379 0 : if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) {
380 0 : HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(state,
381 : BlankString,
382 : FirstHVACIteration,
383 : compressorOp,
384 : thisFurnace.CoolPartLoadRatio,
385 0 : thisFurnace.CoolingCoilIndex,
386 : fanOp,
387 : HXUnitOn,
388 : OnOffAirFlowRatio,
389 0 : state.dataFurnaces->EconomizerFlag);
390 : } else {
391 0 : DXCoils::SimDXCoil(state,
392 : BlankString,
393 : compressorOp,
394 : FirstHVACIteration,
395 0 : thisFurnace.CoolingCoilIndex,
396 : fanOp,
397 0 : thisFurnace.CoolPartLoadRatio,
398 : OnOffAirFlowRatio,
399 0 : state.dataFurnaces->CoolHeatPLRRat);
400 : }
401 :
402 0 : if (thisFurnace.CoolingCoilUpstream) {
403 : // simulate furnace heating coil
404 0 : SuppHeatingCoilFlag = false; // if true simulates supplemental heating coil
405 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, fanOp, QActual);
406 : }
407 :
408 0 : if (thisFurnace.fanPlace == HVAC::FanPlace::DrawThru) {
409 : // simulate fan
410 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
411 : }
412 :
413 : // Simulate furnace reheat coil if a humidistat is used or if the reheat coil is present
414 0 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat || thisFurnace.SuppHeatCoilIndex > 0) {
415 0 : SuppHeatingCoilFlag = true; // if true simulates supplemental heating coil
416 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, ReheatCoilLoad, fanOp, QActual);
417 : }
418 : }
419 0 : } break;
420 : // Simulate air-to-air heat pumps:
421 15222 : case HVAC::UnitarySysType::Unitary_HeatPump_AirToAir: {
422 15222 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed) {
423 : // variable speed heat pump
424 0 : HeatCoilLoad = 0.0;
425 0 : if (thisFurnace.bIsIHP) {
426 0 : auto &integratedHP = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex);
427 0 : integratedHP.ControlledZoneTemp = state.dataLoopNodes->Node(thisFurnace.NodeNumOfControlledZone).Temp;
428 0 : integratedHP.IDFanID = thisFurnace.FanIndex; // why do this every time?
429 0 : integratedHP.IDFanName = BlankString;
430 0 : integratedHP.fanPlace = thisFurnace.fanPlace;
431 : }
432 :
433 0 : SimVariableSpeedHP(state, FurnaceNum, FirstHVACIteration, AirLoopNum, ZoneLoad, MoistureLoad, OnOffAirFlowRatio);
434 : } else {
435 : // Update the furnace flow rates
436 20283 : if (!FirstHVACIteration && thisFurnace.fanOp == HVAC::FanOp::Cycling && state.dataFurnaces->CoolingLoad &&
437 5061 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).EconoActive) {
438 : // for cycling fan, cooling load, check whether furnace can meet load with compressor off
439 0 : compressorOp = HVAC::CompressorOp::Off;
440 0 : CalcNewZoneHeatCoolFlowRates(state,
441 : FurnaceNum,
442 : FirstHVACIteration,
443 : compressorOp,
444 : ZoneLoad,
445 : MoistureLoad,
446 : HeatCoilLoad,
447 : ReheatCoilLoad,
448 : OnOffAirFlowRatio,
449 : HXUnitOn);
450 0 : if (thisFurnace.CoolPartLoadRatio >= 1.0 || thisFurnace.HeatPartLoadRatio >= 1.0 ||
451 0 : (thisFurnace.CoolPartLoadRatio <= 0.0 && thisFurnace.HeatPartLoadRatio <= 0.0)) {
452 : // compressor on (reset inlet air mass flow rate to starting value)
453 0 : compressorOp = HVAC::CompressorOp::On;
454 0 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = FurnaceSavMdot;
455 0 : CalcNewZoneHeatCoolFlowRates(state,
456 : FurnaceNum,
457 : FirstHVACIteration,
458 : compressorOp,
459 : ZoneLoad,
460 : MoistureLoad,
461 : HeatCoilLoad,
462 : ReheatCoilLoad,
463 : OnOffAirFlowRatio,
464 : HXUnitOn);
465 : }
466 : } else {
467 : // compressor on
468 15222 : CalcNewZoneHeatCoolFlowRates(state,
469 : FurnaceNum,
470 : FirstHVACIteration,
471 : compressorOp,
472 : ZoneLoad,
473 : MoistureLoad,
474 : HeatCoilLoad,
475 : ReheatCoilLoad,
476 : OnOffAirFlowRatio,
477 : HXUnitOn);
478 : }
479 :
480 15222 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
481 15222 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
482 : }
483 :
484 15222 : if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) {
485 0 : HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(state,
486 : BlankString,
487 : FirstHVACIteration,
488 : compressorOp,
489 : thisFurnace.CoolPartLoadRatio,
490 0 : thisFurnace.CoolingCoilIndex,
491 : fanOp,
492 : HXUnitOn,
493 : OnOffAirFlowRatio,
494 0 : state.dataFurnaces->EconomizerFlag);
495 : } else {
496 30444 : DXCoils::SimDXCoil(state,
497 : BlankString,
498 : compressorOp,
499 : FirstHVACIteration,
500 15222 : thisFurnace.CoolingCoilIndex,
501 : fanOp,
502 15222 : thisFurnace.CoolPartLoadRatio,
503 : OnOffAirFlowRatio);
504 : }
505 30444 : DXCoils::SimDXCoil(state,
506 : BlankString,
507 : compressorOp,
508 : FirstHVACIteration,
509 15222 : thisFurnace.HeatingCoilIndex,
510 : fanOp,
511 15222 : thisFurnace.HeatPartLoadRatio,
512 : OnOffAirFlowRatio);
513 15222 : if (thisFurnace.fanPlace == HVAC::FanPlace::DrawThru) {
514 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
515 : }
516 :
517 : // Simulate furnace reheat coil if a humidistat is present, the dehumidification type of coolreheat and
518 : // reheat coil load exists
519 15222 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat && ReheatCoilLoad > 0.0) {
520 0 : SuppHeatingCoilFlag = true; // if true simulates supplemental heating coil
521 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, ReheatCoilLoad, fanOp, QActual);
522 : } else {
523 15222 : SuppHeatingCoilFlag = true; // if true simulates supplemental heating coil
524 15222 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, fanOp, QActual);
525 : }
526 : }
527 15222 : } break;
528 : // Simulate water-to-air systems:
529 0 : case HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir: {
530 0 : if (thisFurnace.WatertoAirHPType == WAHPCoilType::Simple) {
531 : // Update the furnace flow rates
532 : // When CompressorOp logic is added to the child cooling coil (COIL:WaterToAirHP:EquationFit:Cooling), then this logic
533 : // needs to be reinstated... to align with Unitary/Furnace HeatCool and Unitary Air-to-Air Heat Pump (see above).
534 0 : if (!FirstHVACIteration && thisFurnace.fanOp == HVAC::FanOp::Cycling && state.dataFurnaces->CoolingLoad &&
535 0 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).EconoActive) {
536 : // for cycling fan, cooling load, check whether furnace can meet load with compressor off
537 0 : compressorOp = HVAC::CompressorOp::Off;
538 0 : CalcNewZoneHeatCoolFlowRates(state,
539 : FurnaceNum,
540 : FirstHVACIteration,
541 : compressorOp,
542 : ZoneLoad,
543 : MoistureLoad,
544 : HeatCoilLoad,
545 : ReheatCoilLoad,
546 : OnOffAirFlowRatio,
547 : HXUnitOn);
548 0 : if (thisFurnace.CoolPartLoadRatio >= 1.0 || thisFurnace.HeatPartLoadRatio >= 1.0 ||
549 0 : (thisFurnace.CoolPartLoadRatio <= 0.0 && thisFurnace.HeatPartLoadRatio <= 0.0)) {
550 : // compressor on (reset inlet air mass flow rate to starting value)
551 0 : compressorOp = HVAC::CompressorOp::On;
552 0 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = FurnaceSavMdot;
553 0 : CalcNewZoneHeatCoolFlowRates(state,
554 : FurnaceNum,
555 : FirstHVACIteration,
556 : compressorOp,
557 : ZoneLoad,
558 : MoistureLoad,
559 : HeatCoilLoad,
560 : ReheatCoilLoad,
561 : OnOffAirFlowRatio,
562 : HXUnitOn);
563 : }
564 : } else {
565 : // compressor on
566 0 : CalcNewZoneHeatCoolFlowRates(state,
567 : FurnaceNum,
568 : FirstHVACIteration,
569 : compressorOp,
570 : ZoneLoad,
571 : MoistureLoad,
572 : HeatCoilLoad,
573 : ReheatCoilLoad,
574 : OnOffAirFlowRatio,
575 : HXUnitOn);
576 : }
577 0 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
578 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
579 : }
580 :
581 0 : WaterToAirHeatPumpSimple::SimWatertoAirHPSimple(state,
582 : BlankString,
583 0 : thisFurnace.CoolingCoilIndex,
584 : thisFurnace.CoolingCoilSensDemand,
585 : thisFurnace.CoolingCoilLatentDemand,
586 : thisFurnace.fanOp,
587 : compressorOp,
588 : thisFurnace.CoolPartLoadRatio,
589 : FirstHVACIteration);
590 0 : WaterToAirHeatPumpSimple::SimWatertoAirHPSimple(state,
591 : BlankString,
592 0 : thisFurnace.HeatingCoilIndex,
593 : thisFurnace.HeatingCoilSensDemand,
594 : Dummy,
595 : thisFurnace.fanOp,
596 : compressorOp,
597 : thisFurnace.HeatPartLoadRatio,
598 : FirstHVACIteration);
599 :
600 0 : if (thisFurnace.fanPlace == HVAC::FanPlace::DrawThru) {
601 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
602 : }
603 0 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat && ReheatCoilLoad > 0.0) {
604 0 : SuppHeatingCoilFlag = true; // if true simulates supplemental heating coil
605 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, ReheatCoilLoad, fanOp, QActual);
606 : } else {
607 0 : SuppHeatingCoilFlag = true; // if true simulates supplemental heating coil
608 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, fanOp, QActual);
609 : }
610 0 : } else if (thisFurnace.WatertoAirHPType == WAHPCoilType::ParEst) {
611 :
612 : // simulate the heat pump
613 0 : HeatCoilLoad = 0.0;
614 0 : CalcWaterToAirHeatPump(state, FurnaceNum, FirstHVACIteration, compressorOp, ZoneLoad, MoistureLoad);
615 0 : } else if (thisFurnace.WatertoAirHPType == WAHPCoilType::VarSpeedEquationFit) {
616 : // simulate the heat pump
617 0 : HeatCoilLoad = 0.0;
618 0 : if (thisFurnace.bIsIHP) {
619 0 : state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).ControlledZoneTemp =
620 0 : state.dataLoopNodes->Node(thisFurnace.NodeNumOfControlledZone).Temp;
621 : }
622 0 : SimVariableSpeedHP(state, FurnaceNum, FirstHVACIteration, AirLoopNum, ZoneLoad, MoistureLoad, OnOffAirFlowRatio);
623 :
624 0 : } else if (thisFurnace.WatertoAirHPType == WAHPCoilType::VarSpeedLookupTable) {
625 0 : HeatCoilLoad = 0.0; // Added: Used below
626 : } else {
627 0 : assert(false); //? If all possible states covered by if conditions change to HeatCoilLoad = 0.0;
628 : }
629 0 : } break;
630 0 : default: {
631 : // will never get here, all system types are simulated above
632 0 : assert(false);
633 : } break;
634 : }
635 :
636 : // set the econo lockout flags
637 15222 : auto &airLoopControlInfo = state.dataAirLoop->AirLoopControlInfo(AirLoopNum);
638 15222 : if (thisFurnace.CompPartLoadRatio > 0.0 && airLoopControlInfo.CanLockoutEconoWithCompressor) {
639 0 : airLoopControlInfo.ReqstEconoLockoutWithCompressor = true;
640 : } else {
641 15222 : airLoopControlInfo.ReqstEconoLockoutWithCompressor = false;
642 : }
643 :
644 15222 : if ((HeatCoilLoad > 0.0 || thisFurnace.HeatPartLoadRatio > 0.0) &&
645 8361 : (airLoopControlInfo.CanLockoutEconoWithCompressor || airLoopControlInfo.CanLockoutEconoWithHeating)) {
646 0 : airLoopControlInfo.ReqstEconoLockoutWithHeating = true;
647 : } else {
648 15222 : airLoopControlInfo.ReqstEconoLockoutWithHeating = false;
649 : }
650 :
651 15222 : if (thisFurnace.fanOp == HVAC::FanOp::Cycling) {
652 15222 : state.dataAirLoop->AirLoopFlow(AirLoopNum).FanPLR = thisFurnace.FanPartLoadRatio;
653 : } else {
654 0 : state.dataAirLoop->AirLoopFlow(AirLoopNum).FanPLR = 1.0; // 1 means constant fan does not cycle.
655 : }
656 :
657 : // Report the current Furnace output
658 15222 : ReportFurnace(state, FurnaceNum, AirLoopNum);
659 :
660 : // Reset OnOffFanPartLoadFraction to 1 in case another on/off fan is called without a part-load curve
661 15222 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
662 :
663 15222 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRateMaxAvail = TempMassFlowRateMaxAvail;
664 15222 : }
665 :
666 : // Get Input Section of the Module
667 : //******************************************************************************
668 :
669 2 : void GetFurnaceInput(EnergyPlusData &state)
670 : {
671 :
672 : // SUBROUTINE INFORMATION:
673 : // AUTHOR Richard Liesen
674 : // DATE WRITTEN Feb 2001
675 : // MODIFIED Don Shirey and Rich Raustad, Mar/Oct 2001, Mar 2003
676 : // Bereket Nigusse, April 2010 - deprecated supply air flow fraction through
677 : // controlled zone from the input field.
678 : // Bo Shen, March 2012, add inputs for VS WSHP,
679 : // Bo Shen, ORNL, July 2012 - added variable-speed air source heat pump cooling and heating coils, using curve-fits
680 :
681 : // PURPOSE OF THIS SUBROUTINE:
682 : // Obtains input data for fans and coils and stores it in the Furnace data structures
683 :
684 : // METHODOLOGY EMPLOYED:
685 : // Uses "Get" routines to read in data.
686 :
687 : // SUBROUTINE PARAMETER DEFINITIONS:
688 2 : std::string_view constexpr getUnitaryHeatOnly("GetUnitaryHeatOnly");
689 2 : std::string_view constexpr getAirLoopHVACHeatCoolInput("GetAirLoopHVACHeatCoolInput");
690 2 : std::string_view constexpr routineName = "GetFurnaceInput";
691 :
692 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
693 : int FurnaceNum; // The Furnace that you are currently loading input into
694 : int GetObjectNum; // The index to each specific object name
695 : int NumFields; // Total number of fields in object
696 : int NumAlphas; // Total number of alpha fields in object
697 : int NumNumbers; // Total number of numeric fields in object
698 : int IOStatus; // Function call status
699 2 : Array1D<Real64> Numbers; // Numeric data
700 2 : Array1D_string Alphas; // Alpha data
701 2 : Array1D_string cAlphaFields; // Alpha field names
702 2 : Array1D_string cNumericFields; // Numeric field names
703 2 : Array1D_bool lAlphaBlanks; // Logical array, alpha field input BLANK = .TRUE.
704 2 : Array1D_bool lNumericBlanks; // Logical array, numeric field input BLANK = .TRUE.
705 2 : std::string CompSetFanInlet;
706 2 : std::string CompSetFanOutlet;
707 2 : std::string CompSetCoolInlet;
708 2 : std::string CompSetHeatInlet;
709 2 : std::string CompSetHeatOutlet;
710 2 : bool ErrorsFound(false); // If errors detected in input
711 : bool IsNotOK; // Flag to verify name
712 : bool AirNodeFound; // Used to determine if control zone is valid
713 : bool AirLoopFound; // Used to determine if control zone is served by furnace air loop
714 : int TstatZoneNum; // Used to determine if control zone has a thermostat object
715 : int HStatZoneNum; // Used to determine if control zone has a humidistat object
716 : bool errFlag; // Mining function error flag
717 : int FanInletNode; // Used for node checking warning messages
718 : int FanOutletNode; // Used for node checking warning messages
719 : int CoolingCoilInletNode; // Used for node checking warning messages
720 : int CoolingCoilOutletNode; // Used for node checking warning messages
721 : int HeatingCoilInletNode; // Used for node checking warning messages
722 : int HeatingCoilOutletNode; // Used for node checking warning messages
723 : int SupHeatCoilInletNode; // Used for node checking warning messages
724 : int SupHeatCoilOutletNode; // Used for node checking warning messages
725 2 : std::string CoolingCoilType; // Used in mining function CALLS
726 2 : std::string CoolingCoilName; // Used in mining function CALLS
727 2 : std::string HeatingCoilType; // Used in mining function CALLS
728 2 : std::string HeatingCoilName; // Used in mining function CALLS
729 2 : std::string ReheatingCoilType; // Used in mining function CALLS
730 2 : std::string ReheatingCoilName; // Used in mining function CALLS
731 2 : std::string SuppHeatCoilType; // Used in mining function CALLS
732 2 : std::string SuppHeatCoilName; // Used in mining function CALLS
733 2 : std::string FanName; // Used in mining function CALLS
734 : bool PrintMessage; // Used in mining function CALLS
735 : int HeatingCoilPLFCurveIndex; // index of heating coil PLF curve
736 : Real64 SteamDensity; // density of steam at 100C
737 : int DXCoilIndex; // Index to DX coil in HXAssited object
738 2 : std::string IHPCoilName; // IHP cooling coil name
739 2 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
740 : DataLoopNode::ConnectionObjectType currentModuleObjectType;
741 :
742 2 : state.dataFurnaces->GetFurnaceInputFlag = false;
743 2 : int MaxNumbers = 0;
744 2 : int MaxAlphas = 0;
745 :
746 2 : std::string_view CurrentModuleObject = "AirLoopHVAC:Unitary:Furnace:HeatOnly";
747 2 : int NumHeatOnly = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
748 2 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, NumFields, NumAlphas, NumNumbers);
749 2 : MaxNumbers = max(MaxNumbers, NumNumbers);
750 2 : MaxAlphas = max(MaxAlphas, NumAlphas);
751 :
752 2 : CurrentModuleObject = "AirLoopHVAC:Unitary:Furnace:HeatCool";
753 2 : int NumHeatCool = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
754 2 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, NumFields, NumAlphas, NumNumbers);
755 2 : MaxNumbers = max(MaxNumbers, NumNumbers);
756 2 : MaxAlphas = max(MaxAlphas, NumAlphas);
757 :
758 2 : CurrentModuleObject = "AirLoopHVAC:UnitaryHeatOnly";
759 2 : int NumUnitaryHeatOnly = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
760 2 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, NumFields, NumAlphas, NumNumbers);
761 2 : MaxNumbers = max(MaxNumbers, NumNumbers);
762 2 : MaxAlphas = max(MaxAlphas, NumAlphas);
763 :
764 2 : CurrentModuleObject = "AirLoopHVAC:UnitaryHeatCool";
765 2 : int NumUnitaryHeatCool = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
766 2 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, NumFields, NumAlphas, NumNumbers);
767 2 : MaxNumbers = max(MaxNumbers, NumNumbers);
768 2 : MaxAlphas = max(MaxAlphas, NumAlphas);
769 :
770 2 : CurrentModuleObject = "AirLoopHVAC:UnitaryHeatPump:AirToAir";
771 2 : int NumHeatPump = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
772 2 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, NumFields, NumAlphas, NumNumbers);
773 2 : MaxNumbers = max(MaxNumbers, NumNumbers);
774 2 : MaxAlphas = max(MaxAlphas, NumAlphas);
775 :
776 2 : CurrentModuleObject = "AirLoopHVAC:UnitaryHeatPump:WaterToAir";
777 2 : int NumWaterToAirHeatPump = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
778 2 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, NumFields, NumAlphas, NumNumbers);
779 2 : MaxNumbers = max(MaxNumbers, NumNumbers);
780 2 : MaxAlphas = max(MaxAlphas, NumAlphas);
781 :
782 2 : Alphas.allocate(MaxAlphas);
783 2 : Numbers.dimension(MaxNumbers, 0.0);
784 2 : cAlphaFields.allocate(MaxAlphas);
785 2 : cNumericFields.allocate(MaxNumbers);
786 2 : lAlphaBlanks.dimension(MaxAlphas, true);
787 2 : lNumericBlanks.dimension(MaxNumbers, true);
788 :
789 2 : state.dataFurnaces->NumFurnaces = NumHeatOnly + NumHeatCool + NumUnitaryHeatOnly + NumUnitaryHeatCool + NumHeatPump + NumWaterToAirHeatPump;
790 :
791 2 : if (state.dataFurnaces->NumFurnaces > 0) {
792 2 : state.dataFurnaces->Furnace.allocate(state.dataFurnaces->NumFurnaces);
793 2 : state.dataFurnaces->UniqueFurnaceNames.reserve(state.dataFurnaces->NumFurnaces);
794 : }
795 2 : state.dataFurnaces->CheckEquipName.dimension(state.dataFurnaces->NumFurnaces, true);
796 :
797 2 : int IHPCoilIndex = 0;
798 :
799 : // Get the data for the HeatOnly Furnace
800 2 : for (int HeatOnlyNum = 1; HeatOnlyNum <= NumHeatOnly + NumUnitaryHeatOnly; ++HeatOnlyNum) {
801 :
802 0 : FanInletNode = 0;
803 0 : FanOutletNode = 0;
804 0 : HeatingCoilInletNode = 0;
805 0 : HeatingCoilOutletNode = 0;
806 0 : CoolingCoilType = ' ';
807 0 : CoolingCoilName = ' ';
808 0 : HeatingCoilType = ' ';
809 0 : HeatingCoilName = ' ';
810 :
811 0 : FurnaceNum = HeatOnlyNum;
812 0 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
813 :
814 : // Furnace and UnitarySystem objects are both read in here.
815 : // Will still have 2 differently named objects for the user, but read in with 1 DO loop.
816 0 : if (HeatOnlyNum <= NumHeatOnly) {
817 0 : CurrentModuleObject = "AirLoopHVAC:Unitary:Furnace:HeatOnly";
818 0 : currentModuleObjectType = DataLoopNode::ConnectionObjectType::AirLoopHVACUnitaryFurnaceHeatOnly;
819 0 : thisFurnace.type = HVAC::UnitarySysType::Furnace_HeatOnly;
820 0 : GetObjectNum = HeatOnlyNum;
821 : } else {
822 0 : CurrentModuleObject = "AirLoopHVAC:UnitaryHeatOnly";
823 0 : currentModuleObjectType = DataLoopNode::ConnectionObjectType::AirLoopHVACUnitaryHeatOnly;
824 0 : thisFurnace.type = HVAC::UnitarySysType::Unitary_HeatOnly;
825 0 : GetObjectNum = HeatOnlyNum - NumHeatOnly;
826 : }
827 :
828 0 : thisFurnace.iterationMode.allocate(3);
829 :
830 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
831 : CurrentModuleObject,
832 : GetObjectNum,
833 : Alphas,
834 : NumAlphas,
835 : Numbers,
836 : NumNumbers,
837 : IOStatus,
838 : lNumericBlanks,
839 : lAlphaBlanks,
840 : cAlphaFields,
841 : cNumericFields);
842 :
843 0 : GlobalNames::VerifyUniqueInterObjectName(
844 0 : state, state.dataFurnaces->UniqueFurnaceNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
845 :
846 0 : thisFurnace.Name = Alphas(1);
847 0 : ErrorObjectHeader eoh{routineName, cAlphaFields(1), thisFurnace.Name};
848 :
849 0 : if (lAlphaBlanks(2)) {
850 0 : thisFurnace.availSched = Sched::GetScheduleAlwaysOn(state);
851 0 : } else if ((thisFurnace.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
852 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
853 0 : ErrorsFound = true;
854 : }
855 :
856 0 : thisFurnace.FurnaceInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
857 0 : Alphas(3),
858 : ErrorsFound,
859 : currentModuleObjectType,
860 0 : Alphas(1),
861 : DataLoopNode::NodeFluidType::Air,
862 : DataLoopNode::ConnectionType::Inlet,
863 : NodeInputManager::CompFluidStream::Primary,
864 : DataLoopNode::ObjectIsParent);
865 0 : thisFurnace.FurnaceOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
866 0 : Alphas(4),
867 : ErrorsFound,
868 : currentModuleObjectType,
869 0 : Alphas(1),
870 : DataLoopNode::NodeFluidType::Air,
871 : DataLoopNode::ConnectionType::Outlet,
872 : NodeInputManager::CompFluidStream::Primary,
873 : DataLoopNode::ObjectIsParent);
874 :
875 0 : BranchNodeConnections::TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(3), Alphas(4), "Air Nodes");
876 :
877 0 : if (lAlphaBlanks(5)) {
878 0 : thisFurnace.fanOp = HVAC::FanOp::Cycling;
879 0 : } else if ((thisFurnace.fanOpModeSched = Sched::GetSchedule(state, Alphas(5))) == nullptr) {
880 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(5), Alphas(5));
881 0 : ErrorsFound = true;
882 : }
883 :
884 : // Get the Controlling Zone or Location of the Furnace Thermostat
885 :
886 0 : thisFurnace.ControlZoneNum = Util::FindItemInList(Alphas(6), state.dataHeatBal->Zone);
887 0 : if (thisFurnace.ControlZoneNum == 0) {
888 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
889 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(6), Alphas(6)));
890 0 : ErrorsFound = true;
891 : }
892 :
893 : // Get the node number for the zone with the thermostat
894 0 : if (thisFurnace.ControlZoneNum > 0) {
895 0 : AirNodeFound = false;
896 0 : AirLoopFound = false;
897 0 : int ControlledZoneNum = thisFurnace.ControlZoneNum;
898 : // Find the controlled zone number for the specified thermostat location
899 0 : thisFurnace.NodeNumOfControlledZone = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneNode;
900 : // Determine if furnace is on air loop served by the thermostat location specified
901 0 : for (int zoneInNode = 1; zoneInNode <= state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumInletNodes; ++zoneInNode) {
902 0 : int AirLoopNumber = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNodeAirLoopNum(zoneInNode);
903 0 : if (AirLoopNumber > 0) {
904 0 : for (int BranchNum = 1; BranchNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).NumBranches; ++BranchNum) {
905 0 : for (int CompNum = 1;
906 0 : CompNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).TotalComponents;
907 : ++CompNum) {
908 0 : if (!Util::SameString(state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).Name,
909 0 : thisFurnace.Name) ||
910 0 : !Util::SameString(
911 0 : state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).TypeOf,
912 : CurrentModuleObject)) {
913 0 : continue;
914 : }
915 0 : AirLoopFound = true;
916 0 : thisFurnace.ZoneInletNode = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNode(zoneInNode);
917 0 : break;
918 : }
919 0 : if (AirLoopFound) {
920 0 : break;
921 : }
922 : }
923 0 : for (TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumTempControlledZones; ++TstatZoneNum) {
924 0 : if (state.dataZoneCtrls->TempControlledZone(TstatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) {
925 0 : continue;
926 : }
927 0 : AirNodeFound = true;
928 : }
929 0 : for (TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumComfortControlledZones; ++TstatZoneNum) {
930 0 : if (state.dataZoneCtrls->ComfortControlledZone(TstatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) {
931 0 : continue;
932 : }
933 0 : AirNodeFound = true;
934 : }
935 : }
936 0 : if (AirLoopFound) {
937 0 : break;
938 : }
939 : }
940 0 : if (!AirNodeFound) {
941 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
942 0 : ShowContinueError(state, "Did not find Air Node (Zone with Thermostat).");
943 0 : ShowContinueError(state, format("Specified {} = {}", cAlphaFields(6), Alphas(6)));
944 0 : ShowContinueError(
945 : state, "Both a ZoneHVAC:EquipmentConnections object and a ZoneControl:Thermostat object must be specified for this zone.");
946 0 : ErrorsFound = true;
947 : }
948 0 : if (!AirLoopFound) {
949 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
950 0 : ShowContinueError(state, "Did not find correct Primary Air Loop.");
951 0 : ShowContinueError(state, format("Specified {} = {} is not served by this AirLoopHVAC equipment.", cAlphaFields(6), Alphas(6)));
952 0 : ErrorsFound = true;
953 : }
954 : }
955 :
956 : // Get fan data
957 0 : FanName = Alphas(8);
958 0 : errFlag = false;
959 :
960 0 : thisFurnace.fanType = static_cast<HVAC::FanType>(getEnumValue(HVAC::fanTypeNamesUC, Alphas(7)));
961 0 : if (thisFurnace.fanType != HVAC::FanType::OnOff && thisFurnace.fanType != HVAC::FanType::Constant) {
962 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
963 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(7), Alphas(7)));
964 0 : ErrorsFound = true;
965 :
966 0 : } else if ((thisFurnace.FanIndex = Fans::GetFanIndex(state, FanName)) == 0) {
967 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(8), FanName);
968 0 : ErrorsFound = true;
969 :
970 : } else {
971 0 : auto *fan = state.dataFans->fans(thisFurnace.FanIndex);
972 0 : thisFurnace.ActualFanVolFlowRate = fan->maxAirFlowRate;
973 0 : FanInletNode = fan->inletNodeNum;
974 0 : FanOutletNode = fan->outletNodeNum;
975 0 : thisFurnace.fanAvailSched = fan->availSched;
976 :
977 : // Check fan's schedule for cycling fan operation if constant volume fan is used
978 0 : if (thisFurnace.fanOpModeSched != nullptr && thisFurnace.fanType == HVAC::FanType::Constant) {
979 0 : if (!thisFurnace.fanOpModeSched->checkMinMaxVals(state, Clusive::Ex, 0.0, Clusive::In, 1.0)) {
980 0 : Sched::ShowSevereBadMinMax(
981 : state,
982 : eoh,
983 0 : cAlphaFields(5),
984 0 : Alphas(5),
985 : Clusive::Ex,
986 : 0.0,
987 : Clusive::In,
988 : 1.0,
989 0 : format("For {} = {}, Fan operating mode must be continuous (schedule values > 0)", cAlphaFields(7), Alphas(7)));
990 0 : ErrorsFound = true;
991 : }
992 0 : } else if (lAlphaBlanks(5) && thisFurnace.fanType != HVAC::FanType::OnOff) {
993 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisFurnace.Name));
994 0 : ShowContinueError(state, format("{} = {}", cAlphaFields(7), Alphas(7)));
995 0 : ShowContinueError(state, format("Fan type must be Fan:OnOff when {} = Blank.", cAlphaFields(5)));
996 0 : ErrorsFound = true;
997 : }
998 : }
999 :
1000 0 : thisFurnace.fanPlace = static_cast<HVAC::FanPlace>(getEnumValue(HVAC::fanPlaceNamesUC, Alphas(9)));
1001 0 : assert(thisFurnace.fanPlace != HVAC::FanPlace::Invalid);
1002 :
1003 : // Get coil data
1004 0 : HeatingCoilType = Alphas(10);
1005 0 : HeatingCoilName = Alphas(11);
1006 0 : thisFurnace.HeatingCoilType = HeatingCoilType;
1007 0 : thisFurnace.HeatingCoilName = HeatingCoilName;
1008 0 : if (Util::SameString(HeatingCoilType, "Coil:Heating:Fuel") || Util::SameString(HeatingCoilType, "Coil:Heating:Electric")) {
1009 0 : errFlag = false;
1010 0 : thisFurnace.HeatingCoilType_Num = HeatingCoils::GetHeatingCoilTypeNum(state, HeatingCoilType, HeatingCoilName, errFlag);
1011 0 : if (errFlag) {
1012 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1013 0 : ErrorsFound = true;
1014 : } else {
1015 0 : ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject);
1016 0 : if (IsNotOK) {
1017 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1018 0 : ErrorsFound = true;
1019 :
1020 : } else { // mine data from heating coil object
1021 :
1022 : // Get index to Heating Coil
1023 0 : errFlag = false;
1024 0 : HeatingCoils::GetCoilIndex(state, HeatingCoilName, thisFurnace.HeatingCoilIndex, errFlag);
1025 0 : if (errFlag) {
1026 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1027 0 : ErrorsFound = true;
1028 : }
1029 :
1030 : // Get the furnace design capacity
1031 0 : errFlag = false;
1032 0 : thisFurnace.DesignHeatingCapacity = HeatingCoils::GetCoilCapacity(state, HeatingCoilType, HeatingCoilName, errFlag);
1033 0 : if (errFlag) {
1034 0 : ShowContinueError(state, format("...occurs in {} ={}", CurrentModuleObject, Alphas(1)));
1035 0 : ErrorsFound = true;
1036 : }
1037 :
1038 : // Get the Heating Coil Inlet Node
1039 0 : errFlag = false;
1040 0 : HeatingCoilInletNode = HeatingCoils::GetCoilInletNode(state, HeatingCoilType, HeatingCoilName, errFlag);
1041 0 : thisFurnace.HWCoilAirInletNode = HeatingCoilInletNode;
1042 0 : if (errFlag) {
1043 0 : ShowContinueError(state, format("...occurs in {} ={}", CurrentModuleObject, Alphas(1)));
1044 0 : ErrorsFound = true;
1045 : }
1046 :
1047 : // Get the Heating Coil Outlet Node
1048 0 : errFlag = false;
1049 0 : HeatingCoilOutletNode = HeatingCoils::GetCoilOutletNode(state, HeatingCoilType, HeatingCoilName, errFlag);
1050 0 : if (errFlag) {
1051 0 : ShowContinueError(state, format("...occurs in {} ={}", CurrentModuleObject, Alphas(1)));
1052 0 : ErrorsFound = true;
1053 : }
1054 :
1055 : } // IF (IsNotOK) THEN
1056 : }
1057 :
1058 0 : } else if (Util::SameString(HeatingCoilType, "Coil:Heating:Water")) {
1059 0 : thisFurnace.HeatingCoilType_Num = HVAC::Coil_HeatingWater;
1060 0 : ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject);
1061 0 : if (IsNotOK) {
1062 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1063 0 : ErrorsFound = true;
1064 : } else { // mine data from heating coil object
1065 :
1066 : // Get the Heating Coil water Inlet or control Node number
1067 0 : errFlag = false;
1068 0 : thisFurnace.CoilControlNode = WaterCoils::GetCoilWaterInletNode(state, "Coil:Heating:Water", HeatingCoilName, errFlag);
1069 0 : if (errFlag) {
1070 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1071 0 : ErrorsFound = true;
1072 : }
1073 :
1074 : // Get the Heating Coil hot water max volume flow rate
1075 0 : errFlag = false;
1076 0 : thisFurnace.MaxHeatCoilFluidFlow = WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", HeatingCoilName, errFlag);
1077 0 : if (errFlag) {
1078 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1079 0 : ErrorsFound = true;
1080 : }
1081 :
1082 : // Get the Heating Coil Inlet Node
1083 0 : errFlag = false;
1084 0 : HeatingCoilInletNode = WaterCoils::GetCoilInletNode(state, "Coil:Heating:Water", HeatingCoilName, errFlag);
1085 0 : thisFurnace.HWCoilAirInletNode = HeatingCoilInletNode;
1086 0 : if (errFlag) {
1087 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1088 0 : ErrorsFound = true;
1089 : }
1090 :
1091 : // Get the Heating Coil Outlet Node
1092 0 : errFlag = false;
1093 0 : HeatingCoilOutletNode = WaterCoils::GetCoilOutletNode(state, "Coil:Heating:Water", HeatingCoilName, errFlag);
1094 0 : thisFurnace.HWCoilAirOutletNode = HeatingCoilOutletNode;
1095 0 : if (errFlag) {
1096 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1097 0 : ErrorsFound = true;
1098 : }
1099 :
1100 : // check if user has also used a water coil controller, which they should not do
1101 0 : errFlag = false;
1102 0 : HVACControllers::CheckCoilWaterInletNode(state, thisFurnace.CoilControlNode, errFlag);
1103 0 : if (!errFlag) { // then did find a controller so that is bad
1104 0 : ShowSevereError(state,
1105 0 : format("{} = {} has a conflicting Controller:WaterCoil object", CurrentModuleObject, thisFurnace.Name));
1106 0 : ShowContinueError(state, "Hot water coils are controlled directly by unitary and furnace systems.");
1107 0 : ShowContinueError(state, "No water coil controller should be input for the coil.");
1108 0 : ErrorsFound = true;
1109 : }
1110 : }
1111 :
1112 0 : } else if (Util::SameString(HeatingCoilType, "Coil:Heating:Steam")) {
1113 0 : thisFurnace.HeatingCoilType_Num = HVAC::Coil_HeatingSteam;
1114 0 : ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject);
1115 0 : if (IsNotOK) {
1116 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1117 0 : ErrorsFound = true;
1118 : } else { // mine data from heating coil object
1119 :
1120 0 : errFlag = false;
1121 0 : thisFurnace.HeatingCoilIndex = SteamCoils::GetSteamCoilIndex(state, "COIL:HEATING:STEAM", HeatingCoilName, errFlag);
1122 0 : if (thisFurnace.HeatingCoilIndex == 0) {
1123 0 : ShowSevereError(state, format("{} illegal {} = {}", CurrentModuleObject, cAlphaFields(11), HeatingCoilName));
1124 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1125 0 : ErrorsFound = true;
1126 : }
1127 :
1128 : // Get the Heating Coil steam inlet node number
1129 0 : errFlag = false;
1130 0 : thisFurnace.CoilControlNode = SteamCoils::GetCoilSteamInletNode(state, "COIL:HEATING:STEAM", HeatingCoilName, errFlag);
1131 0 : if (errFlag) {
1132 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1133 0 : ErrorsFound = true;
1134 : }
1135 :
1136 : // Get the Heating Coil steam max volume flow rate
1137 0 : thisFurnace.MaxHeatCoilFluidFlow = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.HeatingCoilIndex, errFlag);
1138 0 : if (thisFurnace.MaxHeatCoilFluidFlow > 0.0) {
1139 0 : SteamDensity = Fluid::GetSteam(state)->getSatDensity(state, state.dataFurnaces->TempSteamIn, 1.0, getUnitaryHeatOnly);
1140 0 : thisFurnace.MaxHeatCoilFluidFlow *= SteamDensity;
1141 : }
1142 :
1143 : // Get the Heating Coil Inlet Node
1144 0 : errFlag = false;
1145 0 : HeatingCoilInletNode = SteamCoils::GetCoilAirInletNode(state, thisFurnace.HeatingCoilIndex, HeatingCoilName, errFlag);
1146 0 : thisFurnace.HWCoilAirInletNode = HeatingCoilInletNode;
1147 0 : if (errFlag) {
1148 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1149 0 : ErrorsFound = true;
1150 : }
1151 :
1152 : // Get the Heating Coil Outlet Node
1153 0 : errFlag = false;
1154 0 : HeatingCoilOutletNode = SteamCoils::GetCoilAirOutletNode(state, thisFurnace.HeatingCoilIndex, HeatingCoilName, errFlag);
1155 0 : thisFurnace.HWCoilAirOutletNode = HeatingCoilOutletNode;
1156 0 : if (errFlag) {
1157 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1158 0 : ErrorsFound = true;
1159 : }
1160 : }
1161 :
1162 : } else {
1163 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1164 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(11), Alphas(11)));
1165 0 : ErrorsFound = true;
1166 : } // IF (Furnace(FurnaceNum)%HeatingCoilType_Num == Coil_HeatingGasOrOtherFuel .OR. &, etc.
1167 :
1168 : // Add component sets array
1169 0 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
1170 0 : CompSetFanInlet = Alphas(3);
1171 0 : CompSetFanOutlet = state.dataLoopNodes->NodeID(FanOutletNode);
1172 0 : CompSetHeatInlet = state.dataLoopNodes->NodeID(FanOutletNode);
1173 0 : CompSetHeatOutlet = Alphas(4);
1174 : // Fan inlet node name must not be the same as the furnace inlet node name
1175 0 : if (FanInletNode != thisFurnace.FurnaceInletNodeNum) {
1176 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1177 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatOnly) {
1178 0 : ShowContinueError(
1179 : state, "When a blow through fan is specified, the fan inlet node name must be the same as the furnace inlet node name.");
1180 0 : ShowContinueError(state, format("...Fan inlet node name = {}", state.dataLoopNodes->NodeID(FanInletNode)));
1181 0 : ShowContinueError(state,
1182 0 : format("...Furnace inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
1183 : } else {
1184 0 : ShowContinueError(
1185 : state,
1186 : "When a blow through fan is specified, the fan inlet node name must be the same as the unitary system inlet node name.");
1187 0 : ShowContinueError(state, format("...Fan inlet node name = {}", state.dataLoopNodes->NodeID(FanInletNode)));
1188 0 : ShowContinueError(
1189 0 : state, format("...Unitary System inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
1190 : }
1191 0 : ErrorsFound = true;
1192 : }
1193 : // Fan outlet node name must be the same as the heating coil inlet node name
1194 0 : if (FanOutletNode != HeatingCoilInletNode) {
1195 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1196 0 : ShowContinueError(
1197 : state,
1198 : "When a blow through fan is specified, the fan outlet node name must be the same as the heating coil inlet node name.");
1199 0 : ShowContinueError(state, format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
1200 0 : ShowContinueError(state, format("...Heating coil inlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
1201 0 : ErrorsFound = true;
1202 : }
1203 : // Heating coil outlet node name must be the same as the furnace outlet node name
1204 0 : if (HeatingCoilOutletNode != thisFurnace.FurnaceOutletNodeNum) {
1205 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1206 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatOnly) {
1207 0 : ShowContinueError(state,
1208 : "When a blow through fan is specified, the heating coil outlet node name must be the same as the furnace "
1209 : "outlet node name.");
1210 0 : ShowContinueError(state, format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
1211 0 : ShowContinueError(
1212 0 : state, format("...Furnace outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
1213 : } else {
1214 0 : ShowContinueError(state,
1215 : "When a blow through fan is specified, the heating coil outlet node name must be the same as the unitary "
1216 : "system outlet node name.");
1217 0 : ShowContinueError(state,
1218 0 : format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
1219 0 : ShowContinueError(
1220 0 : state, format("...UnitarySystem outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
1221 : }
1222 0 : ErrorsFound = true;
1223 : }
1224 : } else { // draw through fan
1225 0 : CompSetHeatInlet = Alphas(3);
1226 0 : CompSetHeatOutlet = state.dataLoopNodes->NodeID(FanInletNode);
1227 0 : CompSetFanInlet = state.dataLoopNodes->NodeID(FanInletNode);
1228 0 : CompSetFanOutlet = Alphas(4);
1229 : // Heating coil inlet node name must not be the same as the furnace inlet node name
1230 0 : if (HeatingCoilInletNode != thisFurnace.FurnaceInletNodeNum) {
1231 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1232 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatOnly) {
1233 0 : ShowContinueError(state,
1234 : "When a draw through fan is specified, the heating coil inlet node name must be the same as the furnace "
1235 : "inlet node name.");
1236 0 : ShowContinueError(state, format("...Heating coil inlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
1237 0 : ShowContinueError(
1238 0 : state, format("...Furnace inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
1239 : } else {
1240 0 : ShowContinueError(state,
1241 : "When a draw through fan is specified, the heating coil inlet node name must be the same as the unitary "
1242 : "system inlet node name.");
1243 0 : ShowContinueError(state, format("...Heating coil inlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
1244 0 : ShowContinueError(
1245 0 : state, format("...UnitarySystem inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
1246 : }
1247 0 : ErrorsFound = true;
1248 : }
1249 : // Heating coil outlet node name must be the same as the fan inlet node name
1250 0 : if (HeatingCoilOutletNode != FanInletNode) {
1251 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1252 0 : ShowContinueError(
1253 : state,
1254 : "When a draw through fan is specified, the heating coil outlet node name must be the same as the fan inlet node name.");
1255 0 : ShowContinueError(state, format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
1256 0 : ShowContinueError(state, format("...Fan inlet node name = {}", state.dataLoopNodes->NodeID(FanInletNode)));
1257 0 : ErrorsFound = true;
1258 : }
1259 : // Fan coil outlet node name must be the same as the furnace outlet node name
1260 0 : if (FanOutletNode != thisFurnace.FurnaceOutletNodeNum) {
1261 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1262 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatOnly) {
1263 0 : ShowContinueError(
1264 : state,
1265 : "When a draw through fan is specified, the fan outlet node name must be the same as the furnace outlet node name.");
1266 0 : ShowContinueError(state, format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
1267 0 : ShowContinueError(state,
1268 0 : format("...Furnace outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
1269 : } else {
1270 0 : ShowContinueError(state,
1271 : "When a draw through fan is specified, the fan outlet node name must be the same as the unitary system "
1272 : "outlet node name.");
1273 0 : ShowContinueError(state, format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
1274 0 : ShowContinueError(
1275 0 : state, format("...UnitarySystem outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
1276 : }
1277 0 : ErrorsFound = true;
1278 : }
1279 : }
1280 :
1281 : // Add fan to component sets array
1282 0 : BranchNodeConnections::SetUpCompSets(
1283 0 : state, CurrentModuleObject, thisFurnace.Name, Alphas(7), Alphas(8), CompSetFanInlet, CompSetFanOutlet);
1284 : // Add heating coil to component sets array
1285 0 : BranchNodeConnections::SetUpCompSets(
1286 0 : state, CurrentModuleObject, thisFurnace.Name, Alphas(10), Alphas(11), CompSetHeatInlet, CompSetHeatOutlet);
1287 :
1288 : // Set the furnace max outlet temperature
1289 0 : thisFurnace.DesignMaxOutletTemp = Numbers(1);
1290 :
1291 : // Set the furnace design fan volumetric flow rate
1292 0 : thisFurnace.DesignFanVolFlowRate = Numbers(2);
1293 :
1294 : // Compare the flow rates.
1295 0 : if (thisFurnace.ActualFanVolFlowRate != DataSizing::AutoSize && thisFurnace.DesignFanVolFlowRate != DataSizing::AutoSize) {
1296 0 : if (thisFurnace.DesignFanVolFlowRate > thisFurnace.ActualFanVolFlowRate) {
1297 0 : ShowWarningError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1298 0 : ShowContinueError(
1299 0 : state, format("... The {} > Max Volume Flow Rate defined in the associated fan object, should be <=.", cNumericFields(2)));
1300 0 : ShowContinueError(state,
1301 0 : format("... Entered value = {:.4R}... Fan [{} = {}] Max Value = {:.4R}",
1302 0 : thisFurnace.DesignFanVolFlowRate,
1303 0 : HVAC::fanTypeNames[(int)thisFurnace.fanType],
1304 : FanName,
1305 0 : thisFurnace.ActualFanVolFlowRate));
1306 0 : ShowContinueError(state, " The HVAC system flow rate is reset to the fan flow rate and the simulation continues.");
1307 0 : thisFurnace.DesignFanVolFlowRate = thisFurnace.ActualFanVolFlowRate;
1308 : }
1309 : }
1310 0 : if (thisFurnace.DesignFanVolFlowRate != DataSizing::AutoSize) {
1311 0 : if (thisFurnace.DesignFanVolFlowRate <= 0.0) {
1312 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1313 0 : ShowContinueError(state, format("... The {} <= 0.0, it must be > 0.0.", cNumericFields(2)));
1314 0 : ShowContinueError(state, format("... Entered value = {:.2R}", thisFurnace.DesignFanVolFlowRate));
1315 0 : ErrorsFound = true;
1316 : }
1317 : }
1318 :
1319 : // HeatOnly furnace has only 1 flow rate, initialize other variables used in this module
1320 0 : thisFurnace.MaxHeatAirVolFlow = thisFurnace.DesignFanVolFlowRate;
1321 0 : thisFurnace.MaxCoolAirVolFlow = thisFurnace.DesignFanVolFlowRate;
1322 0 : thisFurnace.MaxNoCoolHeatAirVolFlow = thisFurnace.DesignFanVolFlowRate;
1323 0 : thisFurnace.AirFlowControl = AirFlowControlConstFan::UseCompressorOnFlow;
1324 :
1325 : // Set heating convergence tolerance
1326 0 : thisFurnace.HeatingConvergenceTolerance = 0.001;
1327 :
1328 : // set minimum outdoor temperature for compressor operation
1329 0 : SetMinOATCompressor(state, FurnaceNum, cCurrentModuleObject, ErrorsFound);
1330 :
1331 : } // End of the HeatOnly Furnace Loop
1332 :
1333 : // Get the data for the HeatCool Furnace or UnitarySystem
1334 2 : for (int HeatCoolNum = 1; HeatCoolNum <= NumHeatCool + NumUnitaryHeatCool; ++HeatCoolNum) {
1335 :
1336 0 : FanInletNode = 0;
1337 0 : FanOutletNode = 0;
1338 0 : CoolingCoilInletNode = 0;
1339 0 : CoolingCoilOutletNode = 0;
1340 0 : HeatingCoilInletNode = 0;
1341 0 : HeatingCoilOutletNode = 0;
1342 0 : int ReheatCoilInletNode = 0;
1343 0 : int ReheatCoilOutletNode = 0;
1344 0 : CoolingCoilType = ' ';
1345 0 : CoolingCoilName = ' ';
1346 0 : HeatingCoilType = ' ';
1347 0 : HeatingCoilName = ' ';
1348 :
1349 0 : FurnaceNum = HeatCoolNum + NumHeatOnly + NumUnitaryHeatOnly;
1350 0 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
1351 :
1352 : // Furnace and UnitarySystem objects are both read in here.
1353 : // Will still have 2 differently named objects for the user, but read in with 1 DO loop.
1354 0 : if (HeatCoolNum <= NumHeatCool) {
1355 0 : CurrentModuleObject = "AirLoopHVAC:Unitary:Furnace:HeatCool";
1356 0 : currentModuleObjectType = DataLoopNode::ConnectionObjectType::AirLoopHVACUnitaryFurnaceHeatCool;
1357 0 : thisFurnace.type = HVAC::UnitarySysType::Furnace_HeatCool;
1358 0 : GetObjectNum = HeatCoolNum;
1359 : } else {
1360 0 : CurrentModuleObject = "AirLoopHVAC:UnitaryHeatCool";
1361 0 : currentModuleObjectType = DataLoopNode::ConnectionObjectType::AirLoopHVACUnitaryHeatCool;
1362 0 : thisFurnace.type = HVAC::UnitarySysType::Unitary_HeatCool;
1363 0 : GetObjectNum = HeatCoolNum - NumHeatCool;
1364 : }
1365 :
1366 0 : thisFurnace.iterationMode.allocate(3);
1367 :
1368 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1369 : CurrentModuleObject,
1370 : GetObjectNum,
1371 : Alphas,
1372 : NumAlphas,
1373 : Numbers,
1374 : NumNumbers,
1375 : IOStatus,
1376 : lNumericBlanks,
1377 : lAlphaBlanks,
1378 : cAlphaFields,
1379 : cNumericFields);
1380 :
1381 0 : GlobalNames::VerifyUniqueInterObjectName(
1382 0 : state, state.dataFurnaces->UniqueFurnaceNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
1383 :
1384 0 : thisFurnace.Name = Alphas(1);
1385 :
1386 0 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, thisFurnace.Name};
1387 :
1388 0 : if (lAlphaBlanks(2)) {
1389 0 : thisFurnace.availSched = Sched::GetScheduleAlwaysOn(state);
1390 0 : } else if ((thisFurnace.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
1391 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
1392 0 : ErrorsFound = true;
1393 : }
1394 :
1395 0 : thisFurnace.FurnaceInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
1396 0 : Alphas(3),
1397 : ErrorsFound,
1398 : currentModuleObjectType,
1399 0 : Alphas(1),
1400 : DataLoopNode::NodeFluidType::Air,
1401 : DataLoopNode::ConnectionType::Inlet,
1402 : NodeInputManager::CompFluidStream::Primary,
1403 : DataLoopNode::ObjectIsParent);
1404 0 : thisFurnace.FurnaceOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
1405 0 : Alphas(4),
1406 : ErrorsFound,
1407 : currentModuleObjectType,
1408 0 : Alphas(1),
1409 : DataLoopNode::NodeFluidType::Air,
1410 : DataLoopNode::ConnectionType::Outlet,
1411 : NodeInputManager::CompFluidStream::Primary,
1412 : DataLoopNode::ObjectIsParent);
1413 :
1414 0 : BranchNodeConnections::TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(3), Alphas(4), "Air Nodes");
1415 :
1416 0 : if (lAlphaBlanks(5)) {
1417 0 : thisFurnace.fanOp = HVAC::FanOp::Cycling;
1418 0 : } else if ((thisFurnace.fanOpModeSched = Sched::GetSchedule(state, Alphas(5))) == nullptr) {
1419 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(5), Alphas(5));
1420 0 : ErrorsFound = true;
1421 : }
1422 :
1423 : // Get the Controlling Zone or Location of the Furnace Thermostat
1424 0 : thisFurnace.ControlZoneNum = Util::FindItemInList(Alphas(6), state.dataHeatBal->Zone);
1425 0 : if (thisFurnace.ControlZoneNum == 0) {
1426 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1427 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(6), Alphas(6)));
1428 0 : ErrorsFound = true;
1429 : }
1430 :
1431 : // Get the node number for the zone with the thermostat
1432 0 : if (thisFurnace.ControlZoneNum > 0) {
1433 0 : AirNodeFound = false;
1434 0 : AirLoopFound = false;
1435 0 : int ControlledZoneNum = thisFurnace.ControlZoneNum;
1436 : // Find the controlled zone number for the specified thermostat location
1437 0 : thisFurnace.NodeNumOfControlledZone = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneNode;
1438 : // Determine if system is on air loop served by the thermostat location specified
1439 0 : for (int zoneInNode = 1; zoneInNode <= state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumInletNodes; ++zoneInNode) {
1440 0 : int AirLoopNumber = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNodeAirLoopNum(zoneInNode);
1441 0 : if (AirLoopNumber > 0) {
1442 0 : for (int BranchNum = 1; BranchNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).NumBranches; ++BranchNum) {
1443 0 : for (int CompNum = 1;
1444 0 : CompNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).TotalComponents;
1445 : ++CompNum) {
1446 0 : if (!Util::SameString(state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).Name,
1447 0 : Alphas(1)) ||
1448 0 : !Util::SameString(
1449 0 : state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).TypeOf,
1450 : CurrentModuleObject)) {
1451 0 : continue;
1452 : }
1453 0 : AirLoopFound = true;
1454 0 : thisFurnace.ZoneInletNode = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNode(zoneInNode);
1455 0 : break;
1456 : }
1457 0 : if (AirLoopFound) {
1458 0 : break;
1459 : }
1460 : }
1461 0 : for (TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumTempControlledZones; ++TstatZoneNum) {
1462 0 : if (state.dataZoneCtrls->TempControlledZone(TstatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) {
1463 0 : continue;
1464 : }
1465 0 : AirNodeFound = true;
1466 : }
1467 0 : for (TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumComfortControlledZones; ++TstatZoneNum) {
1468 0 : if (state.dataZoneCtrls->ComfortControlledZone(TstatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) {
1469 0 : continue;
1470 : }
1471 0 : AirNodeFound = true;
1472 : }
1473 : }
1474 0 : if (AirLoopFound) {
1475 0 : break;
1476 : }
1477 : }
1478 0 : if (!AirNodeFound) {
1479 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1480 0 : ShowContinueError(state, "Did not find air node (zone with thermostat).");
1481 0 : ShowContinueError(state, format("Specified {} = {}", cAlphaFields(6), Alphas(6)));
1482 0 : ShowContinueError(
1483 : state, "Both a ZoneHVAC:EquipmentConnections object and a ZoneControl:Thermostat object must be specified for this zone.");
1484 0 : ErrorsFound = true;
1485 : }
1486 0 : if (!AirLoopFound) {
1487 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1488 0 : ShowContinueError(state, "Did not find correct AirLoopHVAC.");
1489 0 : ShowContinueError(state, format("Specified {} = {}", cAlphaFields(6), Alphas(6)));
1490 0 : ErrorsFound = true;
1491 : }
1492 : }
1493 :
1494 : // Get fan data
1495 0 : FanName = Alphas(8);
1496 :
1497 0 : thisFurnace.fanType = static_cast<HVAC::FanType>(getEnumValue(HVAC::fanTypeNamesUC, Alphas(7)));
1498 :
1499 0 : if (thisFurnace.fanType != HVAC::FanType::OnOff && thisFurnace.fanType != HVAC::FanType::Constant) {
1500 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1501 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(7), Alphas(7)));
1502 0 : ErrorsFound = true;
1503 :
1504 0 : } else if ((thisFurnace.FanIndex = Fans::GetFanIndex(state, FanName)) == 0) {
1505 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(8), FanName);
1506 0 : ErrorsFound = true;
1507 :
1508 : } else {
1509 0 : auto *fan = state.dataFans->fans(thisFurnace.FanIndex);
1510 0 : thisFurnace.ActualFanVolFlowRate = fan->maxAirFlowRate;
1511 0 : FanInletNode = fan->inletNodeNum;
1512 0 : FanOutletNode = fan->outletNodeNum;
1513 0 : thisFurnace.fanAvailSched = fan->availSched;
1514 :
1515 : // Check fan's schedule for cycling fan operation if constant volume fan is used
1516 0 : if (thisFurnace.fanOpModeSched != nullptr && thisFurnace.fanType == HVAC::FanType::Constant) {
1517 0 : if (!thisFurnace.fanOpModeSched->checkMinMaxVals(state, Clusive::Ex, 0.0, Clusive::In, 1.0)) {
1518 0 : Sched::ShowSevereBadMinMax(
1519 : state,
1520 : eoh,
1521 0 : cAlphaFields(5),
1522 0 : Alphas(5),
1523 : Clusive::In,
1524 : 0.0,
1525 : Clusive::In,
1526 : 1.0,
1527 0 : format("For {} = {}, fan operating mode must be continuous (schedule values > 0)", cAlphaFields(7), Alphas(7)));
1528 0 : ErrorsFound = true;
1529 : }
1530 0 : } else if (lAlphaBlanks(5) && thisFurnace.fanType != HVAC::FanType::OnOff) {
1531 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisFurnace.Name));
1532 0 : ShowContinueError(state, format("{} = {}", cAlphaFields(7), Alphas(7)));
1533 0 : ShowContinueError(state, format("Fan type must be Fan:OnOff when {} = Blank.", cAlphaFields(5)));
1534 0 : ErrorsFound = true;
1535 : }
1536 : }
1537 :
1538 0 : thisFurnace.fanPlace = static_cast<HVAC::FanPlace>(getEnumValue(HVAC::fanPlaceNamesUC, Alphas(9)));
1539 0 : assert(thisFurnace.fanPlace != HVAC::FanPlace::Invalid);
1540 :
1541 : // Get coil data
1542 0 : HeatingCoilType = Alphas(10);
1543 0 : HeatingCoilName = Alphas(11);
1544 0 : HeatingCoilPLFCurveIndex = 0;
1545 0 : thisFurnace.HeatingCoilType = HeatingCoilType;
1546 0 : thisFurnace.HeatingCoilName = HeatingCoilName;
1547 0 : if (Util::SameString(HeatingCoilType, "Coil:Heating:Fuel") || Util::SameString(HeatingCoilType, "Coil:Heating:Electric")) {
1548 0 : errFlag = false;
1549 0 : thisFurnace.HeatingCoilType_Num = HeatingCoils::GetHeatingCoilTypeNum(state, HeatingCoilType, HeatingCoilName, errFlag);
1550 0 : if (errFlag) {
1551 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1552 0 : ErrorsFound = true;
1553 : } else {
1554 :
1555 0 : ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject);
1556 0 : if (IsNotOK) {
1557 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1558 0 : ErrorsFound = true;
1559 :
1560 : } else { // mine data from heating coil
1561 :
1562 : // Get heating coil index
1563 0 : errFlag = false;
1564 0 : HeatingCoils::GetCoilIndex(state, HeatingCoilName, thisFurnace.HeatingCoilIndex, errFlag);
1565 0 : if (errFlag) {
1566 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1567 0 : ErrorsFound = true;
1568 : }
1569 :
1570 : // Get the design heating capacity
1571 0 : errFlag = false;
1572 0 : thisFurnace.DesignHeatingCapacity = HeatingCoils::GetCoilCapacity(state, HeatingCoilType, HeatingCoilName, errFlag);
1573 0 : if (errFlag) {
1574 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1575 0 : ErrorsFound = true;
1576 : }
1577 :
1578 : // Get the Heating Coil Inlet Node
1579 0 : errFlag = false;
1580 0 : HeatingCoilInletNode = HeatingCoils::GetCoilInletNode(state, HeatingCoilType, HeatingCoilName, errFlag);
1581 0 : if (errFlag) {
1582 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1583 0 : ErrorsFound = true;
1584 : }
1585 :
1586 : // Get the Heating Coil Outlet Node
1587 0 : errFlag = false;
1588 0 : HeatingCoilOutletNode = HeatingCoils::GetCoilOutletNode(state, HeatingCoilType, HeatingCoilName, errFlag);
1589 0 : if (errFlag) {
1590 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1591 0 : ErrorsFound = true;
1592 : }
1593 :
1594 : // Get the Heating Coil PLF Curve Index
1595 0 : errFlag = false;
1596 0 : HeatingCoilPLFCurveIndex = HeatingCoils::GetHeatingCoilPLFCurveIndex(state, HeatingCoilType, HeatingCoilName, errFlag);
1597 0 : if (errFlag) {
1598 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1599 0 : ErrorsFound = true;
1600 : }
1601 :
1602 : } // IF (IsNotOK) THEN
1603 : }
1604 :
1605 0 : } else if (Util::SameString(HeatingCoilType, "Coil:Heating:Water")) {
1606 0 : thisFurnace.HeatingCoilType_Num = HVAC::Coil_HeatingWater;
1607 0 : ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject);
1608 0 : if (IsNotOK) {
1609 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1610 0 : ErrorsFound = true;
1611 : } else { // mine data from heating coil object
1612 :
1613 : // Get the Heating Coil water Inlet or control Node number
1614 0 : errFlag = false;
1615 0 : thisFurnace.CoilControlNode = WaterCoils::GetCoilWaterInletNode(state, "Coil:Heating:Water", HeatingCoilName, errFlag);
1616 0 : if (errFlag) {
1617 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1618 0 : ErrorsFound = true;
1619 : }
1620 :
1621 : // Get the Heating Coil hot water max volume flow rate
1622 0 : errFlag = false;
1623 0 : thisFurnace.MaxHeatCoilFluidFlow = WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", HeatingCoilName, errFlag);
1624 0 : if (errFlag) {
1625 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1626 0 : ErrorsFound = true;
1627 : }
1628 :
1629 : // Get the Heating Coil Inlet Node
1630 0 : errFlag = false;
1631 0 : HeatingCoilInletNode = WaterCoils::GetCoilInletNode(state, "Coil:Heating:Water", HeatingCoilName, errFlag);
1632 0 : thisFurnace.HWCoilAirInletNode = HeatingCoilInletNode;
1633 0 : if (errFlag) {
1634 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1635 0 : ErrorsFound = true;
1636 : }
1637 :
1638 : // Get the Heating Coil Outlet Node
1639 0 : errFlag = false;
1640 0 : HeatingCoilOutletNode = WaterCoils::GetCoilOutletNode(state, "Coil:Heating:Water", HeatingCoilName, errFlag);
1641 0 : thisFurnace.HWCoilAirOutletNode = HeatingCoilOutletNode;
1642 0 : if (errFlag) {
1643 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1644 0 : ErrorsFound = true;
1645 : }
1646 :
1647 : // check if user has also used a water coil controller, which they should not do
1648 0 : errFlag = false;
1649 0 : HVACControllers::CheckCoilWaterInletNode(state, thisFurnace.CoilControlNode, errFlag);
1650 0 : if (!errFlag) { // then did find a controller so that is bad
1651 0 : ShowSevereError(state,
1652 0 : format("{} = {} has a conflicting Controller:WaterCoil object", CurrentModuleObject, thisFurnace.Name));
1653 0 : ShowContinueError(state, "Hot water coils are controlled directly by unitary and furnace systems.");
1654 0 : ShowContinueError(state, "No water coil controller should be input for the coil.");
1655 0 : ErrorsFound = true;
1656 : }
1657 : }
1658 :
1659 0 : } else if (Util::SameString(HeatingCoilType, "Coil:Heating:Steam")) {
1660 0 : thisFurnace.HeatingCoilType_Num = HVAC::Coil_HeatingSteam;
1661 0 : ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject);
1662 0 : if (IsNotOK) {
1663 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1664 0 : ErrorsFound = true;
1665 : } else { // mine data from heating coil object
1666 :
1667 0 : errFlag = false;
1668 0 : thisFurnace.HeatingCoilIndex = SteamCoils::GetSteamCoilIndex(state, "COIL:HEATING:STEAM", HeatingCoilName, errFlag);
1669 0 : if (thisFurnace.HeatingCoilIndex == 0) {
1670 0 : ShowSevereError(state, format("{} illegal {} = {}", CurrentModuleObject, cAlphaFields(11), HeatingCoilName));
1671 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1672 0 : ErrorsFound = true;
1673 : }
1674 :
1675 : // Get the Heating Coil steam inlet node number
1676 0 : errFlag = false;
1677 0 : thisFurnace.CoilControlNode = SteamCoils::GetCoilSteamInletNode(state, "Coil:Heating:Steam", HeatingCoilName, errFlag);
1678 0 : if (errFlag) {
1679 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1680 0 : ErrorsFound = true;
1681 : }
1682 :
1683 : // Get the Heating Coil steam max volume flow rate
1684 0 : thisFurnace.MaxHeatCoilFluidFlow = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.HeatingCoilIndex, errFlag);
1685 0 : if (thisFurnace.MaxHeatCoilFluidFlow > 0.0) {
1686 : SteamDensity =
1687 0 : Fluid::GetSteam(state)->getSatDensity(state, state.dataFurnaces->TempSteamIn, 1.0, getAirLoopHVACHeatCoolInput);
1688 0 : thisFurnace.MaxHeatCoilFluidFlow *= SteamDensity;
1689 : }
1690 :
1691 : // Get the Heating Coil Inlet Node
1692 0 : errFlag = false;
1693 0 : HeatingCoilInletNode = SteamCoils::GetCoilAirInletNode(state, thisFurnace.HeatingCoilIndex, HeatingCoilName, errFlag);
1694 0 : thisFurnace.HWCoilAirInletNode = HeatingCoilInletNode;
1695 0 : if (errFlag) {
1696 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1697 0 : ErrorsFound = true;
1698 : }
1699 :
1700 : // Get the Heating Coil Outlet Node
1701 0 : errFlag = false;
1702 0 : HeatingCoilOutletNode = SteamCoils::GetCoilAirOutletNode(state, thisFurnace.HeatingCoilIndex, HeatingCoilName, errFlag);
1703 0 : thisFurnace.HWCoilAirOutletNode = HeatingCoilOutletNode;
1704 0 : if (errFlag) {
1705 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1706 0 : ErrorsFound = true;
1707 : }
1708 : }
1709 :
1710 : } else {
1711 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1712 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(11), Alphas(11)));
1713 0 : ErrorsFound = true;
1714 : } // IF (Furnace(FurnaceNum)%HeatingCoilType_Num == Coil_HeatingGasOrOtherFuel .OR. &, etc.
1715 :
1716 : // Get Cooling Coil Information if available
1717 0 : CoolingCoilType = Alphas(12);
1718 0 : CoolingCoilName = Alphas(13);
1719 : // Find the type of coil. Do not print message since this may not be the correct coil type.
1720 0 : errFlag = false;
1721 0 : PrintMessage = false;
1722 :
1723 0 : if (Util::SameString(CoolingCoilType, "COIL:COOLING:DX:VARIABLESPEED") ||
1724 0 : Util::SameString(CoolingCoilType, "COILSYSTEM:INTEGRATEDHEATPUMP:AIRSOURCE")) {
1725 0 : thisFurnace.CoolingCoilType_Num = HVAC::Coil_CoolingAirToAirVariableSpeed;
1726 0 : if (Util::SameString(CoolingCoilType, "COILSYSTEM:INTEGRATEDHEATPUMP:AIRSOURCE")) {
1727 0 : thisFurnace.bIsIHP = true;
1728 : }
1729 : } else {
1730 0 : thisFurnace.CoolingCoilType_Num = DXCoils::GetCoilTypeNum(state, CoolingCoilType, CoolingCoilName, errFlag, PrintMessage);
1731 : }
1732 :
1733 : // If coil type not found, check to see if a HX assisted cooling coil is used.
1734 0 : if (thisFurnace.CoolingCoilType_Num == 0) {
1735 0 : errFlag = false;
1736 0 : thisFurnace.CoolingCoilType_Num =
1737 0 : HVACHXAssistedCoolingCoil::GetCoilGroupTypeNum(state, CoolingCoilType, CoolingCoilName, errFlag, PrintMessage);
1738 : }
1739 :
1740 0 : if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingSingleSpeed) {
1741 0 : ValidateComponent(state, CoolingCoilType, CoolingCoilName, IsNotOK, CurrentModuleObject);
1742 0 : if (IsNotOK) {
1743 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1744 0 : ErrorsFound = true;
1745 :
1746 : } else { // mine data from DX cooling coil
1747 :
1748 : // Get DX cooling coil index
1749 0 : DXCoils::GetDXCoilIndex(state, CoolingCoilName, thisFurnace.CoolingCoilIndex, IsNotOK);
1750 0 : if (IsNotOK) {
1751 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1752 0 : ErrorsFound = true;
1753 : }
1754 :
1755 : // Get DX cooling coil capacity
1756 0 : errFlag = false;
1757 0 : thisFurnace.DesignCoolingCapacity = DXCoils::GetCoilCapacity(state, CoolingCoilType, CoolingCoilName, errFlag);
1758 0 : if (errFlag) {
1759 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1760 0 : ErrorsFound = true;
1761 : }
1762 :
1763 : // Get the Cooling Coil Nodes
1764 0 : errFlag = false;
1765 0 : CoolingCoilInletNode = DXCoils::GetCoilInletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
1766 0 : CoolingCoilOutletNode = DXCoils::GetCoilOutletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
1767 0 : if (errFlag) {
1768 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1769 0 : ErrorsFound = true;
1770 : }
1771 :
1772 : // Get outdoor condenser node from DX coil object
1773 0 : errFlag = false;
1774 0 : if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) {
1775 0 : if (thisFurnace.bIsIHP) {
1776 0 : IHPCoilIndex = IntegratedHeatPump::GetCoilIndexIHP(state, CoolingCoilType, CoolingCoilName, errFlag);
1777 0 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(IHPCoilIndex).SCCoilName;
1778 0 : thisFurnace.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, IHPCoilName, errFlag);
1779 : } else {
1780 0 : thisFurnace.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, CoolingCoilName, errFlag);
1781 : }
1782 : } else {
1783 0 : thisFurnace.CondenserNodeNum = DXCoils::GetCoilCondenserInletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
1784 : }
1785 0 : if (errFlag) {
1786 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1787 0 : ErrorsFound = true;
1788 : }
1789 :
1790 : } // IF (IsNotOK) THEN
1791 :
1792 : // Push heating coil PLF curve index to DX coil
1793 0 : if (HeatingCoilPLFCurveIndex > 0) {
1794 0 : DXCoils::SetDXCoolingCoilData(state, thisFurnace.CoolingCoilIndex, ErrorsFound, HeatingCoilPLFCurveIndex);
1795 : }
1796 :
1797 0 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) {
1798 0 : ValidateComponent(state, CoolingCoilType, CoolingCoilName, IsNotOK, CurrentModuleObject);
1799 0 : if (IsNotOK) {
1800 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1801 0 : ErrorsFound = true;
1802 :
1803 : } else { // mine data from heat exchanger assisted cooling coil
1804 :
1805 : // Get DX heat exchanger assisted cooling coil index
1806 0 : HVACHXAssistedCoolingCoil::GetHXDXCoilIndex(state, CoolingCoilName, thisFurnace.CoolingCoilIndex, IsNotOK);
1807 0 : if (IsNotOK) {
1808 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1809 0 : ErrorsFound = true;
1810 : }
1811 :
1812 : // Get DX cooling coil capacity
1813 0 : errFlag = false;
1814 0 : thisFurnace.DesignCoolingCapacity = HVACHXAssistedCoolingCoil::GetCoilCapacity(state, CoolingCoilType, CoolingCoilName, errFlag);
1815 0 : if (errFlag) {
1816 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1817 0 : ErrorsFound = true;
1818 : }
1819 :
1820 : // Get the Cooling Coil Nodes
1821 0 : errFlag = false;
1822 0 : CoolingCoilInletNode = HVACHXAssistedCoolingCoil::GetCoilInletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
1823 0 : CoolingCoilOutletNode = HVACHXAssistedCoolingCoil::GetCoilOutletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
1824 0 : if (errFlag) {
1825 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1826 0 : ErrorsFound = true;
1827 : }
1828 :
1829 : // Get outdoor condenser node from heat exchanger assisted DX coil object
1830 0 : errFlag = false;
1831 0 : std::string ChildCoolingCoilName = HVACHXAssistedCoolingCoil::GetHXDXCoilName(state, CoolingCoilType, CoolingCoilName, IsNotOK);
1832 0 : std::string ChildCoolingCoilType = HVACHXAssistedCoolingCoil::GetHXDXCoilType(state, CoolingCoilType, CoolingCoilName, IsNotOK);
1833 0 : if (IsNotOK) {
1834 0 : ShowContinueError(state, format("Occurs in {} = {}", cCurrentModuleObject, Alphas(1)));
1835 0 : ErrorsFound = true;
1836 : }
1837 :
1838 : // if (thisFurnace.CoolingCoilType_Num == CoilDX_CoolingHXAssisted) {
1839 0 : if (Util::SameString(ChildCoolingCoilType, "COIL:COOLING:DX")) {
1840 :
1841 0 : int childCCIndex = CoilCoolingDX::factory(state, ChildCoolingCoilName);
1842 0 : if (childCCIndex < 0) {
1843 0 : ShowContinueError(state, format("Occurs in {} = {}", cCurrentModuleObject, Alphas(1)));
1844 0 : errFlag = true;
1845 0 : ErrorsFound = true;
1846 : }
1847 0 : auto const &newCoil = state.dataCoilCoolingDX->coilCoolingDXs[childCCIndex];
1848 :
1849 0 : thisFurnace.CondenserNodeNum = newCoil.condInletNodeIndex;
1850 :
1851 : }
1852 : // else if (thisFurnace.CoolingCoilType_Num == Coil_CoolingAirToAirVariableSpeed) {
1853 0 : else if (Util::SameString(ChildCoolingCoilType, "Coil:Cooling:DX:VariableSpeed")) {
1854 0 : if (thisFurnace.bIsIHP) {
1855 0 : IHPCoilIndex = IntegratedHeatPump::GetCoilIndexIHP(state, CoolingCoilType, CoolingCoilName, errFlag);
1856 0 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(IHPCoilIndex).SCCoilName;
1857 0 : thisFurnace.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, IHPCoilName, errFlag);
1858 : } else {
1859 0 : thisFurnace.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, CoolingCoilName, errFlag);
1860 : }
1861 : } else {
1862 0 : thisFurnace.CondenserNodeNum = DXCoils::GetCoilCondenserInletNode(
1863 : state,
1864 : "COIL:COOLING:DX:SINGLESPEED",
1865 0 : HVACHXAssistedCoolingCoil::GetHXDXCoilName(state, CoolingCoilType, CoolingCoilName, errFlag),
1866 : errFlag);
1867 : }
1868 :
1869 0 : if (errFlag) {
1870 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1871 0 : ErrorsFound = true;
1872 : }
1873 :
1874 : // Push heating coil PLF curve index to DX coil
1875 0 : if (HeatingCoilPLFCurveIndex > 0) {
1876 : // get the actual index to the DX cooling coil object
1877 0 : DXCoilIndex = HVACHXAssistedCoolingCoil::GetActualDXCoilIndex(state, CoolingCoilType, CoolingCoilName, ErrorsFound);
1878 0 : thisFurnace.ActualDXCoilIndexForHXAssisted = DXCoilIndex;
1879 : int ActualCoolCoilType =
1880 0 : HVACHXAssistedCoolingCoil::GetCoilObjectTypeNum(state, CoolingCoilType, CoolingCoilName, errFlag, true);
1881 0 : if (ActualCoolCoilType == HVAC::CoilDX_CoolingSingleSpeed) {
1882 0 : DXCoils::SetDXCoolingCoilData(state, DXCoilIndex, ErrorsFound, HeatingCoilPLFCurveIndex);
1883 : }
1884 : // what could we do for VS coil here? odd thing here
1885 : }
1886 :
1887 0 : } // IF (IsNotOK) THEN
1888 0 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) {
1889 : // BOS ADDED, AUG/2012, VARIIABLE SPEED DX COOLING COIL
1890 : // Furnace(FurnaceNum)%DXCoolCoilType = 'COIL:COOLING:DX:VARIABLESPEED'
1891 : // Furnace(FurnaceNum)%DXCoolCoilName = CoolingCoilName
1892 0 : if (Util::SameString(CoolingCoilType, "COILSYSTEM:INTEGRATEDHEATPUMP:AIRSOURCE")) {
1893 0 : thisFurnace.bIsIHP = true;
1894 : }
1895 0 : ValidateComponent(state, CoolingCoilType, CoolingCoilName, IsNotOK, CurrentModuleObject);
1896 :
1897 0 : if (IsNotOK) {
1898 0 : ShowContinueError(state, format("...specified in {}=\"{}\".", CurrentModuleObject, Alphas(1)));
1899 0 : ErrorsFound = true;
1900 : } else {
1901 0 : errFlag = false;
1902 0 : if (thisFurnace.bIsIHP) {
1903 0 : thisFurnace.CoolingCoilIndex = IntegratedHeatPump::GetCoilIndexIHP(state, CoolingCoilType, CoolingCoilName, errFlag);
1904 0 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SCCoilName;
1905 : } else {
1906 0 : thisFurnace.CoolingCoilIndex =
1907 0 : VariableSpeedCoils::GetCoilIndexVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
1908 0 : IHPCoilName = CoolingCoilName;
1909 : }
1910 :
1911 0 : if (errFlag) {
1912 0 : ShowContinueError(state, format("...specified in {}=\"{}\".", CurrentModuleObject, Alphas(1)));
1913 0 : ErrorsFound = true;
1914 : }
1915 :
1916 0 : if (thisFurnace.bIsIHP) {
1917 : CoolingCoilInletNode =
1918 0 : VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, "COIL:COOLING:DX:VARIABLESPEED", IHPCoilName, errFlag);
1919 : CoolingCoilOutletNode =
1920 0 : VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, "COIL:COOLING:DX:VARIABLESPEED", IHPCoilName, errFlag);
1921 0 : thisFurnace.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, IHPCoilName, errFlag);
1922 : } else {
1923 0 : CoolingCoilInletNode = VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
1924 0 : CoolingCoilOutletNode = VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
1925 0 : thisFurnace.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, CoolingCoilName, errFlag);
1926 : }
1927 :
1928 0 : if (errFlag) {
1929 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1930 0 : ErrorsFound = true;
1931 : }
1932 : }
1933 : } else {
1934 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1935 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(12), Alphas(12)));
1936 0 : ErrorsFound = true;
1937 : }
1938 :
1939 0 : if (Util::SameString(Alphas(14), "None") || Util::SameString(Alphas(14), "Multimode") || Util::SameString(Alphas(14), "CoolReheat")) {
1940 0 : AirNodeFound = false;
1941 0 : if (Util::SameString(Alphas(14), "Multimode")) {
1942 0 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::Multimode;
1943 0 : thisFurnace.Humidistat = true;
1944 0 : if (thisFurnace.CoolingCoilType_Num != HVAC::CoilDX_CoolingHXAssisted) {
1945 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1946 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(14), Alphas(14)));
1947 0 : ShowContinueError(state, "Multimode control must be used with a Heat Exchanger Assisted Cooling Coil.");
1948 0 : if (lAlphaBlanks(15)) {
1949 0 : ShowContinueError(state,
1950 : "Dehumidification control type is assumed to be None since a reheat coil has not been specified and "
1951 : "the simulation continues.");
1952 0 : thisFurnace.Humidistat = false;
1953 0 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::None;
1954 : } else {
1955 0 : ShowContinueError(state, "Dehumidification control type is assumed to be CoolReheat and the simulation continues.");
1956 0 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::CoolReheat;
1957 : }
1958 : }
1959 : }
1960 0 : if (Util::SameString(Alphas(14), "CoolReheat")) {
1961 0 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::CoolReheat;
1962 0 : thisFurnace.Humidistat = true;
1963 0 : if (lAlphaBlanks(15)) {
1964 0 : ShowWarningError(state, format("{} \"{}\"", CurrentModuleObject, Alphas(1)));
1965 0 : ShowContinueError(state,
1966 : "Dehumidification control type is assumed to be None since a reheat coil has not been specified and the "
1967 : "simulation continues.");
1968 0 : thisFurnace.Humidistat = false;
1969 0 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::None;
1970 : }
1971 : }
1972 0 : if (Util::SameString(Alphas(14), "None")) {
1973 0 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::None;
1974 0 : thisFurnace.Humidistat = false;
1975 : }
1976 0 : if (thisFurnace.Humidistat) {
1977 0 : for (HStatZoneNum = 1; HStatZoneNum <= state.dataZoneCtrls->NumHumidityControlZones; ++HStatZoneNum) {
1978 0 : if (state.dataZoneCtrls->HumidityControlZone(HStatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) {
1979 0 : continue;
1980 : }
1981 0 : AirNodeFound = true;
1982 : }
1983 0 : if (!AirNodeFound) {
1984 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1985 0 : ShowContinueError(state, "Did not find Air Node (Zone with Humidistat).");
1986 0 : ShowContinueError(state, format("Specified {} = {}", cAlphaFields(6), Alphas(6)));
1987 0 : ErrorsFound = true;
1988 : }
1989 : }
1990 : } else { // invalid input
1991 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1992 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(14), Alphas(14)));
1993 0 : thisFurnace.Humidistat = false;
1994 0 : ErrorsFound = true;
1995 : }
1996 :
1997 : // Check placement of cooling coil with respect to fan placement and dehumidification control type
1998 0 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
1999 0 : if (FanOutletNode == HeatingCoilInletNode && thisFurnace.DehumidControlType_Num != DehumidificationControlMode::CoolReheat) {
2000 0 : thisFurnace.CoolingCoilUpstream = false;
2001 : }
2002 : } else {
2003 0 : if (HeatingCoilOutletNode == CoolingCoilInletNode && thisFurnace.DehumidControlType_Num != DehumidificationControlMode::CoolReheat) {
2004 0 : thisFurnace.CoolingCoilUpstream = false;
2005 : }
2006 : }
2007 :
2008 : // Get reheat coil data if humidistat is used
2009 0 : ReheatingCoilType = Alphas(15);
2010 0 : ReheatingCoilName = Alphas(16);
2011 0 : thisFurnace.SuppHeatCoilType = ReheatingCoilType;
2012 0 : thisFurnace.SuppHeatCoilName = ReheatingCoilName;
2013 0 : errFlag = false;
2014 0 : if (!lAlphaBlanks(15)) {
2015 0 : if (Util::SameString(ReheatingCoilType, "Coil:Heating:Fuel") || Util::SameString(ReheatingCoilType, "Coil:Heating:Electric") ||
2016 0 : Util::SameString(ReheatingCoilType, "Coil:Heating:Desuperheater")) {
2017 :
2018 0 : thisFurnace.SuppHeatCoilType_Num = HeatingCoils::GetHeatingCoilTypeNum(state, ReheatingCoilType, ReheatingCoilName, errFlag);
2019 0 : if (errFlag) {
2020 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2021 0 : ErrorsFound = true;
2022 : } else {
2023 :
2024 0 : ValidateComponent(state, ReheatingCoilType, ReheatingCoilName, IsNotOK, CurrentModuleObject);
2025 0 : if (IsNotOK) {
2026 0 : ShowContinueError(state, format("In {} \"{}\"", CurrentModuleObject, Alphas(1)));
2027 0 : ErrorsFound = true;
2028 :
2029 : } else { // mine data from reheat coil
2030 :
2031 : // Get the heating coil index
2032 0 : HeatingCoils::GetCoilIndex(state, ReheatingCoilName, thisFurnace.SuppHeatCoilIndex, IsNotOK);
2033 0 : if (IsNotOK) {
2034 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2035 0 : ErrorsFound = true;
2036 : }
2037 :
2038 : // Get the design supplemental heating capacity
2039 0 : errFlag = false;
2040 0 : thisFurnace.DesignSuppHeatingCapacity =
2041 0 : HeatingCoils::GetCoilCapacity(state, ReheatingCoilType, ReheatingCoilName, errFlag);
2042 0 : if (errFlag) {
2043 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2044 0 : ErrorsFound = true;
2045 : }
2046 :
2047 : // Get the Reheat Coil Inlet Node
2048 0 : errFlag = false;
2049 0 : ReheatCoilInletNode = HeatingCoils::GetCoilInletNode(state, ReheatingCoilType, ReheatingCoilName, errFlag);
2050 0 : if (errFlag) {
2051 0 : ShowContinueError(state, format("...occurs in {} \"{}\"", CurrentModuleObject, Alphas(1)));
2052 0 : ErrorsFound = true;
2053 : }
2054 :
2055 : // Get the Reheat Coil Outlet Node
2056 0 : errFlag = false;
2057 0 : ReheatCoilOutletNode = HeatingCoils::GetCoilOutletNode(state, ReheatingCoilType, ReheatingCoilName, errFlag);
2058 0 : if (errFlag) {
2059 0 : ShowContinueError(state, format("...occurs in {} \"{}\"", CurrentModuleObject, Alphas(1)));
2060 0 : ErrorsFound = true;
2061 : }
2062 :
2063 : } // IF (IsNotOK) THEN
2064 : }
2065 :
2066 0 : } else if (Util::SameString(ReheatingCoilType, "Coil:Heating:Water")) {
2067 0 : thisFurnace.SuppHeatCoilType_Num = HVAC::Coil_HeatingWater;
2068 0 : ValidateComponent(state, ReheatingCoilType, ReheatingCoilName, IsNotOK, CurrentModuleObject);
2069 0 : if (IsNotOK) {
2070 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2071 0 : ErrorsFound = true;
2072 : } else { // mine data from heating coil object
2073 :
2074 : // Get the Heating Coil water Inlet or control Node number
2075 0 : errFlag = false;
2076 0 : thisFurnace.SuppCoilControlNode = WaterCoils::GetCoilWaterInletNode(state, "Coil:Heating:Water", ReheatingCoilName, errFlag);
2077 0 : if (errFlag) {
2078 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
2079 0 : ErrorsFound = true;
2080 : }
2081 :
2082 : // Get the ReHeat Coil hot water max volume flow rate
2083 0 : errFlag = false;
2084 0 : thisFurnace.MaxSuppCoilFluidFlow =
2085 0 : WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", ReheatingCoilName, errFlag);
2086 0 : if (errFlag) {
2087 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
2088 0 : ErrorsFound = true;
2089 : }
2090 :
2091 : // Get the ReHeat Coil Inlet Node
2092 0 : errFlag = false;
2093 0 : ReheatCoilInletNode = WaterCoils::GetCoilInletNode(state, "Coil:Heating:Water", ReheatingCoilName, errFlag);
2094 0 : thisFurnace.SuppCoilAirInletNode = ReheatCoilInletNode;
2095 0 : if (errFlag) {
2096 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
2097 0 : ErrorsFound = true;
2098 : }
2099 :
2100 : // Get the ReHeat Coil Outlet Node
2101 0 : errFlag = false;
2102 0 : ReheatCoilOutletNode = WaterCoils::GetCoilOutletNode(state, "Coil:Heating:Water", ReheatingCoilName, errFlag);
2103 0 : thisFurnace.SuppCoilAirOutletNode = ReheatCoilOutletNode;
2104 0 : if (errFlag) {
2105 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
2106 0 : ErrorsFound = true;
2107 : }
2108 :
2109 : // check if user has also used a water coil controller, which they should not do
2110 0 : errFlag = false;
2111 0 : HVACControllers::CheckCoilWaterInletNode(state, thisFurnace.CoilControlNode, errFlag);
2112 0 : if (!errFlag) { // then did find a controller so that is bad
2113 0 : ShowSevereError(state,
2114 0 : format("{} = {} has a conflicting Controller:WaterCoil object", CurrentModuleObject, thisFurnace.Name));
2115 0 : ShowContinueError(state, "Hot water coils are controlled directly by unitary and furnace systems.");
2116 0 : ShowContinueError(state, "No water coil controller should be input for the coil.");
2117 0 : ErrorsFound = true;
2118 : }
2119 : }
2120 :
2121 0 : } else if (Util::SameString(ReheatingCoilType, "Coil:Heating:Steam")) {
2122 0 : thisFurnace.SuppHeatCoilType_Num = HVAC::Coil_HeatingSteam;
2123 0 : ValidateComponent(state, ReheatingCoilType, ReheatingCoilName, IsNotOK, CurrentModuleObject);
2124 0 : if (IsNotOK) {
2125 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2126 0 : ErrorsFound = true;
2127 : } else { // mine data from heating coil object
2128 :
2129 0 : errFlag = false;
2130 0 : thisFurnace.SuppHeatCoilIndex = SteamCoils::GetSteamCoilIndex(state, "COIL:HEATING:STEAM", ReheatingCoilName, errFlag);
2131 0 : if (thisFurnace.SuppHeatCoilIndex == 0) {
2132 0 : ShowSevereError(state, format("{} illegal {} = {}", CurrentModuleObject, cAlphaFields(11), ReheatingCoilName));
2133 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
2134 0 : ErrorsFound = true;
2135 : }
2136 :
2137 : // Get the Heating Coil steam inlet node number
2138 0 : errFlag = false;
2139 0 : thisFurnace.SuppCoilControlNode = SteamCoils::GetCoilSteamInletNode(state, "Coil:Heating:Steam", ReheatingCoilName, errFlag);
2140 0 : if (errFlag) {
2141 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
2142 0 : ErrorsFound = true;
2143 : }
2144 :
2145 : // Get the Heating Coil steam max volume flow rate
2146 0 : thisFurnace.MaxSuppCoilFluidFlow = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.SuppHeatCoilIndex, errFlag);
2147 0 : if (thisFurnace.MaxSuppCoilFluidFlow > 0.0) {
2148 : SteamDensity =
2149 0 : Fluid::GetSteam(state)->getSatDensity(state, state.dataFurnaces->TempSteamIn, 1.0, getAirLoopHVACHeatCoolInput);
2150 0 : thisFurnace.MaxSuppCoilFluidFlow =
2151 0 : SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.SuppHeatCoilIndex, errFlag) * SteamDensity;
2152 : }
2153 :
2154 : // Get the Heating Coil Inlet Node
2155 0 : errFlag = false;
2156 0 : ReheatCoilInletNode = SteamCoils::GetCoilAirInletNode(state, thisFurnace.SuppHeatCoilIndex, ReheatingCoilName, errFlag);
2157 0 : thisFurnace.SuppCoilAirInletNode = ReheatCoilInletNode;
2158 0 : if (errFlag) {
2159 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
2160 0 : ErrorsFound = true;
2161 : }
2162 :
2163 : // Get the Heating Coil Outlet Node
2164 0 : errFlag = false;
2165 0 : ReheatCoilOutletNode = SteamCoils::GetCoilAirOutletNode(state, thisFurnace.SuppHeatCoilIndex, ReheatingCoilName, errFlag);
2166 0 : thisFurnace.SuppCoilAirOutletNode = ReheatCoilOutletNode;
2167 0 : if (errFlag) {
2168 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
2169 0 : ErrorsFound = true;
2170 : }
2171 : }
2172 :
2173 : } else { // Illegal heating coil
2174 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2175 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(15), Alphas(15)));
2176 0 : ErrorsFound = true;
2177 : } // IF (Furnace(FurnaceNum)%SuppHeatCoilType_Num == Coil_HeatingGasOrOtherFuel .OR. &, etc.
2178 :
2179 : } // IF(.NOT. lAlphaBlanks(15))THEN
2180 :
2181 0 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
2182 :
2183 0 : if (FanInletNode != thisFurnace.FurnaceInletNodeNum) {
2184 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2185 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatCool) {
2186 0 : ShowContinueError(
2187 : state, "When a blow through fan is specified, the fan inlet node name must be the same as the furnace inlet node name.");
2188 0 : ShowContinueError(state, format("...Fan inlet node name = {}", state.dataLoopNodes->NodeID(FanInletNode)));
2189 0 : ShowContinueError(state,
2190 0 : format("...Furnace inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
2191 : } else {
2192 0 : ShowContinueError(
2193 : state,
2194 : "When a blow through fan is specified, the fan inlet node name must be the same as the unitary system inlet node name.");
2195 0 : ShowContinueError(state, format("...Fan inlet node name = {}", state.dataLoopNodes->NodeID(FanInletNode)));
2196 0 : ShowContinueError(
2197 0 : state, format("...UnitarySystem inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
2198 : }
2199 0 : ErrorsFound = true;
2200 : }
2201 0 : if (thisFurnace.CoolingCoilUpstream) {
2202 0 : if (FanOutletNode != CoolingCoilInletNode) {
2203 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2204 0 : ShowContinueError(
2205 : state,
2206 : "When a blow through fan is specified, the fan outlet node name must be the same as the cooling coil inlet node name.");
2207 0 : ShowContinueError(state, format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
2208 0 : ShowContinueError(state, format("...Cooling coil inlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilInletNode)));
2209 0 : ErrorsFound = true;
2210 : }
2211 0 : if (CoolingCoilOutletNode != HeatingCoilInletNode) {
2212 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2213 0 : ShowContinueError(state, "The cooling coil outlet node name must be the same as the heating coil inlet node name.");
2214 0 : ShowContinueError(state, format("...Cooling coil outlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilOutletNode)));
2215 0 : ShowContinueError(state, format("...Heating coil inlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
2216 0 : ErrorsFound = true;
2217 : }
2218 0 : if ((thisFurnace.Humidistat && thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat) ||
2219 : ReheatCoilInletNode > 0) {
2220 0 : if (HeatingCoilOutletNode != ReheatCoilInletNode) {
2221 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2222 0 : ShowContinueError(state,
2223 : "When a blow through fan is specified, the heating coil outlet node name must be the same as the "
2224 : "reheat coil inlet node name.");
2225 0 : ShowContinueError(state,
2226 0 : format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
2227 0 : ShowContinueError(state,
2228 0 : format("...Reheat coil inlet node name = {}", state.dataLoopNodes->NodeID(ReheatCoilInletNode)));
2229 0 : ErrorsFound = true;
2230 : }
2231 0 : if (ReheatCoilOutletNode != thisFurnace.FurnaceOutletNodeNum) {
2232 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2233 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatCool) {
2234 0 : ShowContinueError(state, "The reheat coil outlet node name must be the same as the furnace outlet node name.");
2235 0 : ShowContinueError(state,
2236 0 : format("...Reheat coil outlet node name = {}", state.dataLoopNodes->NodeID(ReheatCoilOutletNode)));
2237 0 : ShowContinueError(
2238 : state,
2239 0 : format("...Furnace outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
2240 : } else {
2241 0 : ShowContinueError(state, "The reheat coil outlet node name must be the same as the unitary system outlet node name.");
2242 0 : ShowContinueError(
2243 0 : state, format("...Reheat coil outlet node name = {}", state.dataLoopNodes->NodeID(ReheatCoilOutletNode)));
2244 0 : ShowContinueError(
2245 : state,
2246 0 : format("...UnitarySystem outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
2247 : }
2248 0 : ErrorsFound = true;
2249 : }
2250 : } else { // IF((Furnace(FurnaceNum)%Humidistat ...
2251 : // Heating coil outlet node name must be the same as the furnace outlet node name
2252 0 : if (HeatingCoilOutletNode != thisFurnace.FurnaceOutletNodeNum) {
2253 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2254 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatOnly) {
2255 0 : ShowContinueError(state,
2256 : "When a blow through fan is specified, the heating coil outlet node name must be the same as the "
2257 : "furnace outlet node name.");
2258 0 : ShowContinueError(
2259 0 : state, format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
2260 0 : ShowContinueError(
2261 : state,
2262 0 : format("...Furnace outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
2263 : } else {
2264 0 : ShowContinueError(state,
2265 : "When a blow through fan is specified, the heating coil outlet node name must be the same as the "
2266 : "unitary system outlet node name.");
2267 0 : ShowContinueError(
2268 0 : state, format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
2269 0 : ShowContinueError(
2270 : state,
2271 0 : format("...UnitarySystem outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
2272 : }
2273 0 : ErrorsFound = true;
2274 : }
2275 : }
2276 : } else { // IF(Furnace(FurnaceNum)%CoolingCoilUpstream)THEN
2277 0 : if (FanOutletNode != HeatingCoilInletNode) {
2278 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2279 0 : ShowContinueError(
2280 : state,
2281 : "When a blow through fan is specified, the fan outlet node name must be the same as the heating coil inlet node name.");
2282 0 : ShowContinueError(state, format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
2283 0 : ShowContinueError(state, format("...Heating coil inlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
2284 0 : ErrorsFound = true;
2285 : }
2286 0 : if (HeatingCoilOutletNode != CoolingCoilInletNode) {
2287 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2288 0 : ShowContinueError(state, "The heating coil outlet node name must be the same as the cooling coil inlet node name.");
2289 0 : ShowContinueError(state, format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
2290 0 : ShowContinueError(state, format("...Cooling coil inlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilInletNode)));
2291 0 : ErrorsFound = true;
2292 : }
2293 0 : if (CoolingCoilOutletNode != thisFurnace.FurnaceOutletNodeNum) {
2294 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2295 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatCool) {
2296 0 : ShowContinueError(state,
2297 : "When a blow through fan is specified, the cooling coil outlet node name must be the same as the "
2298 : "furnace outlet node name.");
2299 0 : ShowContinueError(state,
2300 0 : format("...Cooling coil outlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilOutletNode)));
2301 0 : ShowContinueError(
2302 : state,
2303 0 : format("...Furnace outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
2304 : } else {
2305 0 : ShowContinueError(state,
2306 : "When a blow through fan is specified, the cooling coil outlet node name must be the same as the "
2307 : "unitary system outlet node name.");
2308 0 : ShowContinueError(state,
2309 0 : format("...Cooling coil outlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilOutletNode)));
2310 0 : ShowContinueError(
2311 : state,
2312 0 : format("...UnitarySystem outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
2313 : }
2314 0 : ErrorsFound = true;
2315 : }
2316 : }
2317 :
2318 : } else { // ELSE from IF(Furnace(FurnaceNum)%FanPlace .EQ. BlowThru)THEN
2319 :
2320 0 : if (thisFurnace.CoolingCoilUpstream) {
2321 0 : if (CoolingCoilInletNode != thisFurnace.FurnaceInletNodeNum) {
2322 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2323 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatCool) {
2324 0 : ShowContinueError(state,
2325 : "When a draw through fan is specified, the cooling coil inlet node name must be the same as the "
2326 : "furnace inlet node name.");
2327 0 : ShowContinueError(state,
2328 0 : format("...Cooling coil inlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilInletNode)));
2329 0 : ShowContinueError(
2330 0 : state, format("...Furnace inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
2331 : } else {
2332 0 : ShowContinueError(state,
2333 : "When a draw through fan is specified, the cooling coil inlet node name must be the same as the "
2334 : "unitary system inlet node name.");
2335 0 : ShowContinueError(state,
2336 0 : format("...Cooling coil inlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilInletNode)));
2337 0 : ShowContinueError(
2338 0 : state, format("...UnitarySystem inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
2339 : }
2340 0 : ErrorsFound = true;
2341 : }
2342 0 : if (CoolingCoilOutletNode != HeatingCoilInletNode) {
2343 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2344 0 : ShowContinueError(state, "The cooling coil outlet node name must be the same as the heating coil inlet node name.");
2345 0 : ShowContinueError(state, format("...Cooling coil outlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilOutletNode)));
2346 0 : ShowContinueError(state, format("...Heating coil inlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
2347 0 : ErrorsFound = true;
2348 : }
2349 0 : if (HeatingCoilOutletNode != FanInletNode) {
2350 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2351 0 : ShowContinueError(
2352 : state,
2353 : "When a draw through fan is specified, the heating coil outlet node name must be the same as the fan inlet node name.");
2354 0 : ShowContinueError(state, format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
2355 0 : ShowContinueError(state, format("...Fan inlet node name = {}", state.dataLoopNodes->NodeID(FanInletNode)));
2356 0 : ErrorsFound = true;
2357 : }
2358 0 : if ((thisFurnace.Humidistat && thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat) ||
2359 : ReheatCoilInletNode > 0) {
2360 0 : if (FanOutletNode != ReheatCoilInletNode) {
2361 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2362 0 : ShowContinueError(state,
2363 : "When a draw through fan is specified, the fan outlet node name must be the same as the reheat coil "
2364 : "inlet node name.");
2365 0 : ShowContinueError(state, format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
2366 0 : ShowContinueError(state, format("...Reheat coil inlet node name = {}", state.dataLoopNodes->NodeID(ReheatCoilInletNode)));
2367 0 : ErrorsFound = true;
2368 : }
2369 0 : if (ReheatCoilOutletNode != thisFurnace.FurnaceOutletNodeNum) {
2370 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2371 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatCool) {
2372 0 : ShowContinueError(state, "The reheat coil outlet node name must be the same as the furnace outlet node name.");
2373 0 : ShowContinueError(state,
2374 0 : format("...Reheat coil outlet node name = {}", state.dataLoopNodes->NodeID(ReheatCoilOutletNode)));
2375 0 : ShowContinueError(
2376 : state,
2377 0 : format("...Furnace outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
2378 : } else {
2379 0 : ShowContinueError(state, "The reheat coil outlet node name must be the same as the unitary system outlet node name.");
2380 0 : ShowContinueError(
2381 0 : state, format("...Reheat coil outlet node name = {}", state.dataLoopNodes->NodeID(ReheatCoilOutletNode)));
2382 0 : ShowContinueError(
2383 : state,
2384 0 : format("...UnitarySystem outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
2385 : }
2386 0 : ErrorsFound = true;
2387 : }
2388 : } else {
2389 0 : if (FanOutletNode != thisFurnace.FurnaceOutletNodeNum) {
2390 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2391 0 : ShowContinueError(state,
2392 : "When a draw through fan is specified, the fan outlet node name must be the same as the unitary system "
2393 : "outlet node name.");
2394 0 : ShowContinueError(state, format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
2395 0 : ShowContinueError(
2396 : state,
2397 0 : format("...Unitary system outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
2398 0 : ErrorsFound = true;
2399 : }
2400 : }
2401 : } else { // IF(Furnace(FurnaceNum)%CoolingCoilUpstream)THEN
2402 0 : if (HeatingCoilInletNode != thisFurnace.FurnaceInletNodeNum) {
2403 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2404 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatCool) {
2405 0 : ShowContinueError(state,
2406 : "When a draw through fan is specified, the heating coil inlet node name must be the same as the "
2407 : "furnace inlet node name.");
2408 0 : ShowContinueError(state,
2409 0 : format("...Heating coil inlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
2410 0 : ShowContinueError(
2411 0 : state, format("...Furnace inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
2412 : } else {
2413 0 : ShowContinueError(state,
2414 : "When a draw through fan is specified, the heating coil inlet node name must be the same as the "
2415 : "unitary system inlet node name.");
2416 0 : ShowContinueError(state,
2417 0 : format("...Heating coil inlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
2418 0 : ShowContinueError(
2419 0 : state, format("...UnitarySystem inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
2420 : }
2421 0 : ErrorsFound = true;
2422 : }
2423 0 : if (HeatingCoilOutletNode != CoolingCoilInletNode) {
2424 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2425 0 : ShowContinueError(state, "The heating coil outlet node name must be the same as the cooling coil inlet node name.");
2426 0 : ShowContinueError(state, format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
2427 0 : ShowContinueError(state, format("...Cooling coil inlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilInletNode)));
2428 0 : ErrorsFound = true;
2429 : }
2430 0 : if (CoolingCoilOutletNode != FanInletNode) {
2431 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2432 0 : ShowContinueError(
2433 : state,
2434 : "When a draw through fan is specified, the cooling coil outlet node name must be the same as the fan inlet node name.");
2435 0 : ShowContinueError(state, format("...Cooling coil outlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilOutletNode)));
2436 0 : ShowContinueError(state, format("...Fan inlet node name = {}", state.dataLoopNodes->NodeID(FanInletNode)));
2437 0 : ErrorsFound = true;
2438 : }
2439 0 : if (FanOutletNode != thisFurnace.FurnaceOutletNodeNum) {
2440 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2441 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatCool) {
2442 0 : ShowContinueError(
2443 : state,
2444 : "When a draw through fan is specified, the fan outlet node name must be the same as the furnace outlet node name.");
2445 0 : ShowContinueError(state, format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
2446 0 : ShowContinueError(
2447 0 : state, format("...Furnace outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
2448 : } else {
2449 0 : ShowContinueError(state,
2450 : "When a draw through fan is specified, the fan outlet node name must be the same as the unitary system "
2451 : "outlet node name.");
2452 0 : ShowContinueError(state, format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
2453 0 : ShowContinueError(
2454 : state,
2455 0 : format("...UnitarySystem outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
2456 : }
2457 0 : ErrorsFound = true;
2458 : }
2459 : }
2460 : } // ELSE from IF(Furnace(FurnaceNum)%FanPlace .EQ. BlowThru)THEN
2461 :
2462 : // Add fan to component sets array
2463 0 : BranchNodeConnections::SetUpCompSets(state,
2464 : CurrentModuleObject,
2465 0 : Alphas(1),
2466 0 : Alphas(7),
2467 0 : Alphas(8),
2468 0 : state.dataLoopNodes->NodeID(FanInletNode),
2469 0 : state.dataLoopNodes->NodeID(FanOutletNode));
2470 :
2471 : // Add DX cooling coil to component sets array
2472 0 : if (thisFurnace.bIsIHP) {
2473 0 : BranchNodeConnections::SetUpCompSets(state,
2474 : CurrentModuleObject,
2475 0 : Alphas(1),
2476 0 : Alphas(12),
2477 0 : Alphas(13) + " Cooling Coil",
2478 0 : state.dataLoopNodes->NodeID(CoolingCoilInletNode),
2479 0 : state.dataLoopNodes->NodeID(CoolingCoilOutletNode));
2480 : } else {
2481 0 : BranchNodeConnections::SetUpCompSets(state,
2482 : CurrentModuleObject,
2483 0 : Alphas(1),
2484 0 : Alphas(12),
2485 0 : Alphas(13),
2486 0 : state.dataLoopNodes->NodeID(CoolingCoilInletNode),
2487 0 : state.dataLoopNodes->NodeID(CoolingCoilOutletNode));
2488 : }
2489 :
2490 : // Add heating coil to component sets array
2491 0 : if (thisFurnace.bIsIHP) {
2492 0 : BranchNodeConnections::SetUpCompSets(state,
2493 : CurrentModuleObject,
2494 0 : Alphas(1),
2495 0 : Alphas(10),
2496 0 : Alphas(11) + " Heating Coil",
2497 0 : state.dataLoopNodes->NodeID(HeatingCoilInletNode),
2498 0 : state.dataLoopNodes->NodeID(HeatingCoilOutletNode));
2499 : } else {
2500 0 : BranchNodeConnections::SetUpCompSets(state,
2501 : CurrentModuleObject,
2502 0 : Alphas(1),
2503 0 : Alphas(10),
2504 0 : Alphas(11),
2505 0 : state.dataLoopNodes->NodeID(HeatingCoilInletNode),
2506 0 : state.dataLoopNodes->NodeID(HeatingCoilOutletNode));
2507 : }
2508 :
2509 0 : if (ReheatCoilInletNode > 0) {
2510 :
2511 : // Add reheating coil to component sets array
2512 0 : BranchNodeConnections::SetUpCompSets(state,
2513 : CurrentModuleObject,
2514 0 : Alphas(1),
2515 0 : Alphas(15),
2516 0 : Alphas(16),
2517 0 : state.dataLoopNodes->NodeID(ReheatCoilInletNode),
2518 0 : state.dataLoopNodes->NodeID(ReheatCoilOutletNode));
2519 : }
2520 :
2521 : // Set the furnace max outlet temperature
2522 0 : thisFurnace.DesignMaxOutletTemp = Numbers(1);
2523 :
2524 0 : thisFurnace.MaxCoolAirVolFlow = Numbers(2);
2525 0 : if (thisFurnace.MaxCoolAirVolFlow <= 0 && thisFurnace.MaxCoolAirVolFlow != DataSizing::AutoSize) {
2526 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2527 0 : ShowContinueError(state, format("Illegal {} = {:.7T}", cNumericFields(2), Numbers(2)));
2528 0 : ErrorsFound = true;
2529 : }
2530 :
2531 0 : thisFurnace.MaxHeatAirVolFlow = Numbers(3);
2532 0 : if (thisFurnace.MaxHeatAirVolFlow <= 0 && thisFurnace.MaxHeatAirVolFlow != DataSizing::AutoSize) {
2533 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2534 0 : ShowContinueError(state, format("Illegal {} = {:.7T}", cNumericFields(3), Numbers(3)));
2535 0 : ErrorsFound = true;
2536 : }
2537 :
2538 0 : thisFurnace.MaxNoCoolHeatAirVolFlow = Numbers(4);
2539 0 : if (thisFurnace.MaxNoCoolHeatAirVolFlow < 0 && thisFurnace.MaxNoCoolHeatAirVolFlow != DataSizing::AutoSize) {
2540 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2541 0 : ShowContinueError(state, format("Illegal {} = {:.7T}", cNumericFields(4), Numbers(4)));
2542 0 : ErrorsFound = true;
2543 : }
2544 :
2545 0 : if (Numbers(2) != DataSizing::AutoSize && Numbers(3) != DataSizing::AutoSize && Numbers(4) != DataSizing::AutoSize) {
2546 0 : thisFurnace.DesignFanVolFlowRate = max(Numbers(2), Numbers(3), Numbers(4));
2547 : } else {
2548 0 : thisFurnace.DesignFanVolFlowRate = DataSizing::AutoSize;
2549 : }
2550 :
2551 0 : if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) {
2552 0 : errFlag = false;
2553 0 : if (thisFurnace.bIsIHP) {
2554 0 : thisFurnace.CoolingCoilIndex = IntegratedHeatPump::GetCoilIndexIHP(state, CoolingCoilType, CoolingCoilName, errFlag);
2555 0 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SCCoilName;
2556 0 : thisFurnace.MaxCoolAirVolFlow =
2557 0 : VariableSpeedCoils::GetCoilAirFlowRateVariableSpeed(state, "COIL:COOLING:DX:VARIABLESPEED", IHPCoilName, errFlag);
2558 : } else {
2559 0 : thisFurnace.MaxCoolAirVolFlow =
2560 0 : VariableSpeedCoils::GetCoilAirFlowRateVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
2561 : }
2562 :
2563 0 : if (errFlag) {
2564 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2565 0 : ErrorsFound = true;
2566 : }
2567 :
2568 0 : thisFurnace.MaxNoCoolHeatAirVolFlow = min(thisFurnace.MaxHeatAirVolFlow, thisFurnace.MaxCoolAirVolFlow);
2569 0 : if (thisFurnace.MaxHeatAirVolFlow != DataSizing::AutoSize && thisFurnace.MaxCoolAirVolFlow != DataSizing::AutoSize) {
2570 0 : thisFurnace.DesignFanVolFlowRate = max(thisFurnace.MaxHeatAirVolFlow, thisFurnace.MaxCoolAirVolFlow);
2571 : } else {
2572 0 : thisFurnace.DesignFanVolFlowRate = DataSizing::AutoSize;
2573 : }
2574 : }
2575 :
2576 0 : if (thisFurnace.ActualFanVolFlowRate != DataSizing::AutoSize) {
2577 0 : if (thisFurnace.ActualFanVolFlowRate < thisFurnace.MaxCoolAirVolFlow && thisFurnace.MaxCoolAirVolFlow != DataSizing::AutoSize) {
2578 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2579 0 : ShowContinueError(
2580 : state,
2581 0 : format("... air flow rate = {:.7T} in fan object {} is less than the maximum HVAC system air flow rate in cooling mode.",
2582 0 : thisFurnace.ActualFanVolFlowRate,
2583 : FanName));
2584 0 : ShowContinueError(state, format(" The {} is reset to the fan flow rate and the simulation continues.", cNumericFields(2)));
2585 0 : thisFurnace.MaxCoolAirVolFlow = thisFurnace.ActualFanVolFlowRate;
2586 0 : thisFurnace.DesignFanVolFlowRate = thisFurnace.ActualFanVolFlowRate;
2587 : }
2588 0 : if (thisFurnace.ActualFanVolFlowRate < thisFurnace.MaxHeatAirVolFlow && thisFurnace.MaxHeatAirVolFlow != DataSizing::AutoSize) {
2589 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2590 0 : ShowContinueError(
2591 : state,
2592 0 : format("... air flow rate = {:.7T} in fan object {} is less than the maximum HVAC system air flow rate in heating mode.",
2593 0 : thisFurnace.ActualFanVolFlowRate,
2594 : FanName));
2595 0 : ShowContinueError(state, format(" The {} is reset to the fan flow rate and the simulation continues.", cNumericFields(3)));
2596 0 : thisFurnace.MaxHeatAirVolFlow = thisFurnace.ActualFanVolFlowRate;
2597 0 : thisFurnace.DesignFanVolFlowRate = thisFurnace.ActualFanVolFlowRate;
2598 : }
2599 : }
2600 :
2601 0 : if (thisFurnace.fanOpModeSched != nullptr) {
2602 : // Is this correct? 0.0 for max also?
2603 0 : if (!thisFurnace.fanOpModeSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 0.0)) {
2604 : // set air flow control mode:
2605 : // UseCompressorOnFlow = operate at last cooling or heating air flow requested when compressor is off
2606 : // UseCompressorOffFlow = operate at value specified by user
2607 : // AirFlowControl only valid if fan opmode = ContFanCycComp
2608 0 : if (thisFurnace.MaxNoCoolHeatAirVolFlow == 0.0) {
2609 0 : thisFurnace.AirFlowControl = AirFlowControlConstFan::UseCompressorOnFlow;
2610 : } else {
2611 0 : thisFurnace.AirFlowControl = AirFlowControlConstFan::UseCompressorOffFlow;
2612 : }
2613 : }
2614 : }
2615 :
2616 0 : if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) {
2617 0 : errFlag = false;
2618 0 : if (thisFurnace.bIsIHP) {
2619 0 : thisFurnace.CoolingCoilIndex = IntegratedHeatPump::GetCoilIndexIHP(state, CoolingCoilType, CoolingCoilName, errFlag);
2620 0 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SCCoilName;
2621 0 : thisFurnace.DesignCoolingCapacity =
2622 0 : VariableSpeedCoils::GetCoilCapacityVariableSpeed(state, "COIL:COOLING:DX:VARIABLESPEED", IHPCoilName, errFlag);
2623 : } else {
2624 0 : thisFurnace.DesignCoolingCapacity =
2625 0 : VariableSpeedCoils::GetCoilCapacityVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
2626 : }
2627 :
2628 0 : if (errFlag) {
2629 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2630 0 : ErrorsFound = true;
2631 : }
2632 : }
2633 :
2634 : // Set heating convergence tolerance
2635 0 : thisFurnace.HeatingConvergenceTolerance = 0.001;
2636 :
2637 : // Set cooling convergence tolerance
2638 0 : thisFurnace.CoolingConvergenceTolerance = 0.001;
2639 :
2640 : // set minimum outdoor temperature for compressor operation
2641 0 : SetMinOATCompressor(state, FurnaceNum, cCurrentModuleObject, ErrorsFound);
2642 :
2643 : } // End of the HeatCool Furnace Loop
2644 :
2645 : // Get the data for the Unitary System HeatPump AirToAir (UnitarySystem:HeatPump:AirToAir)
2646 4 : for (int HeatPumpNum = 1; HeatPumpNum <= NumHeatPump; ++HeatPumpNum) {
2647 :
2648 2 : CurrentModuleObject = "AirLoopHVAC:UnitaryHeatPump:AirToAir";
2649 2 : FanInletNode = 0;
2650 2 : FanOutletNode = 0;
2651 2 : CoolingCoilInletNode = 0;
2652 2 : CoolingCoilOutletNode = 0;
2653 2 : HeatingCoilInletNode = 0;
2654 2 : HeatingCoilOutletNode = 0;
2655 2 : SupHeatCoilInletNode = 0;
2656 2 : SupHeatCoilOutletNode = 0;
2657 2 : CoolingCoilType = ' ';
2658 2 : CoolingCoilName = ' ';
2659 2 : HeatingCoilType = ' ';
2660 2 : HeatingCoilName = ' ';
2661 :
2662 2 : FurnaceNum = NumHeatOnly + NumHeatCool + NumUnitaryHeatOnly + NumUnitaryHeatCool + HeatPumpNum;
2663 2 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
2664 2 : thisFurnace.iterationMode.allocate(3);
2665 :
2666 2 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
2667 : CurrentModuleObject,
2668 : HeatPumpNum,
2669 : Alphas,
2670 : NumAlphas,
2671 : Numbers,
2672 : NumNumbers,
2673 : IOStatus,
2674 : lNumericBlanks,
2675 : lAlphaBlanks,
2676 : cAlphaFields,
2677 : cNumericFields);
2678 :
2679 4 : GlobalNames::VerifyUniqueInterObjectName(
2680 2 : state, state.dataFurnaces->UniqueFurnaceNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
2681 :
2682 2 : thisFurnace.type = HVAC::UnitarySysType::Unitary_HeatPump_AirToAir;
2683 2 : thisFurnace.Name = Alphas(1);
2684 :
2685 2 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, thisFurnace.Name};
2686 :
2687 2 : if (lAlphaBlanks(2)) {
2688 0 : thisFurnace.availSched = Sched::GetScheduleAlwaysOn(state);
2689 2 : } else if ((thisFurnace.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
2690 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
2691 0 : ErrorsFound = true;
2692 : }
2693 :
2694 2 : thisFurnace.FurnaceInletNodeNum =
2695 2 : NodeInputManager::GetOnlySingleNode(state,
2696 2 : Alphas(3),
2697 : ErrorsFound,
2698 : DataLoopNode::ConnectionObjectType::AirLoopHVACUnitaryHeatPumpAirToAir,
2699 2 : Alphas(1),
2700 : DataLoopNode::NodeFluidType::Air,
2701 : DataLoopNode::ConnectionType::Inlet,
2702 : NodeInputManager::CompFluidStream::Primary,
2703 : DataLoopNode::ObjectIsParent);
2704 :
2705 2 : thisFurnace.FurnaceOutletNodeNum =
2706 4 : NodeInputManager::GetOnlySingleNode(state,
2707 2 : Alphas(4),
2708 : ErrorsFound,
2709 : DataLoopNode::ConnectionObjectType::AirLoopHVACUnitaryHeatPumpAirToAir,
2710 2 : Alphas(1),
2711 : DataLoopNode::NodeFluidType::Air,
2712 : DataLoopNode::ConnectionType::Outlet,
2713 : NodeInputManager::CompFluidStream::Primary,
2714 : DataLoopNode::ObjectIsParent);
2715 :
2716 2 : BranchNodeConnections::TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(3), Alphas(4), "Air Nodes");
2717 :
2718 : // Get the Controlling Zone or Location of the Furnace Thermostat
2719 2 : thisFurnace.ControlZoneNum = Util::FindItemInList(Alphas(5), state.dataHeatBal->Zone);
2720 2 : if (thisFurnace.ControlZoneNum == 0) {
2721 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2722 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(5), Alphas(5)));
2723 0 : ErrorsFound = true;
2724 : }
2725 :
2726 : // Get the node number for the zone with the thermostat
2727 2 : if (thisFurnace.ControlZoneNum > 0) {
2728 2 : AirNodeFound = false;
2729 2 : AirLoopFound = false;
2730 2 : int ControlledZoneNum = thisFurnace.ControlZoneNum;
2731 : // Find the controlled zone number for the specified thermostat location
2732 2 : thisFurnace.NodeNumOfControlledZone = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneNode;
2733 : // Determine if furnace is on air loop served by the thermostat location specified
2734 3 : for (int zoneInNode = 1; zoneInNode <= state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumInletNodes; ++zoneInNode) {
2735 3 : int AirLoopNumber = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNodeAirLoopNum(zoneInNode);
2736 3 : if (AirLoopNumber > 0) {
2737 2 : for (int BranchNum = 1; BranchNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).NumBranches; ++BranchNum) {
2738 3 : for (int CompNum = 1;
2739 3 : CompNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).TotalComponents;
2740 : ++CompNum) {
2741 3 : if (!Util::SameString(state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).Name,
2742 8 : Alphas(1)) ||
2743 2 : !Util::SameString(
2744 2 : state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).TypeOf,
2745 : CurrentModuleObject)) {
2746 1 : continue;
2747 : }
2748 2 : AirLoopFound = true;
2749 2 : thisFurnace.ZoneInletNode = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNode(zoneInNode);
2750 2 : break;
2751 : }
2752 2 : if (AirLoopFound) {
2753 2 : break;
2754 : }
2755 : }
2756 4 : for (TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumTempControlledZones; ++TstatZoneNum) {
2757 2 : if (state.dataZoneCtrls->TempControlledZone(TstatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) {
2758 0 : continue;
2759 : }
2760 2 : AirNodeFound = true;
2761 : }
2762 2 : for (TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumComfortControlledZones; ++TstatZoneNum) {
2763 0 : if (state.dataZoneCtrls->ComfortControlledZone(TstatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) {
2764 0 : continue;
2765 : }
2766 0 : AirNodeFound = true;
2767 : }
2768 : }
2769 3 : if (AirLoopFound) {
2770 2 : break;
2771 : }
2772 : }
2773 2 : if (!AirNodeFound) {
2774 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2775 0 : ShowContinueError(state, "Did not find air node (zone with thermostat).");
2776 0 : ShowContinueError(state, format("Specified {} = {}", cAlphaFields(5), Alphas(5)));
2777 0 : ShowContinueError(
2778 : state, "Both a ZoneHVAC:EquipmentConnections object and a ZoneControl:Thermostat object must be specified for this zone.");
2779 0 : ErrorsFound = true;
2780 : }
2781 2 : if (!AirLoopFound) {
2782 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2783 0 : ShowContinueError(state, "Did not find correct AirLoopHVAC.");
2784 0 : ShowContinueError(state, format("Specified {} = {}", cAlphaFields(5), Alphas(5)));
2785 0 : ErrorsFound = true;
2786 : }
2787 : }
2788 :
2789 : // Get fan data
2790 2 : FanName = Alphas(7);
2791 :
2792 2 : thisFurnace.fanType = static_cast<HVAC::FanType>(getEnumValue(HVAC::fanTypeNamesUC, Alphas(6)));
2793 :
2794 2 : if (thisFurnace.fanType == HVAC::FanType::OnOff || thisFurnace.fanType == HVAC::FanType::Constant) {
2795 :
2796 2 : if ((thisFurnace.FanIndex = Fans::GetFanIndex(state, FanName)) == 0) {
2797 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(7), FanName);
2798 0 : ErrorsFound = true;
2799 : } else {
2800 2 : auto *fan = state.dataFans->fans(thisFurnace.FanIndex);
2801 2 : FanInletNode = fan->inletNodeNum;
2802 2 : FanOutletNode = fan->outletNodeNum;
2803 2 : thisFurnace.fanAvailSched = fan->availSched;
2804 2 : thisFurnace.ActualFanVolFlowRate = fan->maxAirFlowRate;
2805 : }
2806 : }
2807 :
2808 : // Get heating coil type and name data
2809 2 : HeatingCoilType = Alphas(8);
2810 2 : HeatingCoilName = Alphas(9);
2811 :
2812 2 : errFlag = false;
2813 :
2814 4 : if (Util::SameString(HeatingCoilType, "COIL:HEATING:DX:VARIABLESPEED") ||
2815 4 : Util::SameString(HeatingCoilType, "COILSYSTEM:INTEGRATEDHEATPUMP:AIRSOURCE")) {
2816 0 : thisFurnace.HeatingCoilType_Num = HVAC::Coil_HeatingAirToAirVariableSpeed;
2817 0 : if (Util::SameString(HeatingCoilType, "COILSYSTEM:INTEGRATEDHEATPUMP:AIRSOURCE")) {
2818 0 : thisFurnace.bIsIHP = true;
2819 : }
2820 : } else {
2821 2 : thisFurnace.HeatingCoilType_Num = DXCoils::GetCoilTypeNum(state, HeatingCoilType, HeatingCoilName, errFlag);
2822 : }
2823 :
2824 2 : if (errFlag) {
2825 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2826 0 : ErrorsFound = true;
2827 : }
2828 :
2829 2 : if (thisFurnace.HeatingCoilType_Num == HVAC::CoilDX_HeatingEmpirical) {
2830 2 : ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject);
2831 2 : if (IsNotOK) {
2832 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2833 0 : ErrorsFound = true;
2834 :
2835 : } else { // mine data from DX heating coil
2836 :
2837 2 : DXCoils::GetDXCoilIndex(state, HeatingCoilName, thisFurnace.HeatingCoilIndex, IsNotOK);
2838 2 : if (IsNotOK) {
2839 0 : ShowContinueError(state, format("...occurs {} = {}", CurrentModuleObject, Alphas(1)));
2840 0 : ErrorsFound = true;
2841 : }
2842 :
2843 : // Get the Heating Coil Node Names
2844 2 : errFlag = false;
2845 2 : HeatingCoilInletNode = DXCoils::GetCoilInletNode(state, HeatingCoilType, HeatingCoilName, errFlag);
2846 2 : HeatingCoilOutletNode = DXCoils::GetCoilOutletNode(state, HeatingCoilType, HeatingCoilName, errFlag);
2847 2 : if (errFlag) {
2848 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2849 0 : ErrorsFound = true;
2850 : }
2851 :
2852 : // Get the design heating capacity
2853 2 : errFlag = false;
2854 2 : thisFurnace.DesignHeatingCapacity = DXCoils::GetCoilCapacity(state, HeatingCoilType, HeatingCoilName, errFlag);
2855 2 : if (errFlag) {
2856 0 : ShowContinueError(state, format("...occurs in {} ={}", CurrentModuleObject, Alphas(1)));
2857 0 : ErrorsFound = true;
2858 : }
2859 :
2860 : } // IF (IsNotOK) THEN
2861 0 : } else if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed) {
2862 0 : ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject);
2863 0 : if (IsNotOK) {
2864 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2865 0 : ErrorsFound = true;
2866 : } else {
2867 0 : if (thisFurnace.bIsIHP) {
2868 0 : thisFurnace.HeatingCoilIndex = IntegratedHeatPump::GetCoilIndexIHP(state, HeatingCoilType, HeatingCoilName, errFlag);
2869 0 : IHPCoilIndex = thisFurnace.HeatingCoilIndex;
2870 0 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(IHPCoilIndex).SHCoilName;
2871 : HeatingCoilInletNode =
2872 0 : VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, "COIL:HEATING:DX:VARIABLESPEED", IHPCoilName, errFlag);
2873 : HeatingCoilOutletNode =
2874 0 : VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, "COIL:HEATING:DX:VARIABLESPEED", IHPCoilName, errFlag);
2875 : } else {
2876 0 : thisFurnace.HeatingCoilIndex =
2877 0 : VariableSpeedCoils::GetCoilIndexVariableSpeed(state, HeatingCoilType, HeatingCoilName, errFlag);
2878 0 : HeatingCoilInletNode = VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, HeatingCoilType, HeatingCoilName, errFlag);
2879 0 : HeatingCoilOutletNode = VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, HeatingCoilType, HeatingCoilName, errFlag);
2880 : }
2881 : }
2882 : } else {
2883 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2884 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(8), Alphas(8)));
2885 0 : ErrorsFound = true;
2886 : }
2887 :
2888 : // Get Cooling Coil Information if available
2889 2 : CoolingCoilType = Alphas(10);
2890 2 : CoolingCoilName = Alphas(11);
2891 :
2892 4 : if (Util::SameString(CoolingCoilType, "COIL:COOLING:DX:VARIABLESPEED") ||
2893 4 : Util::SameString(CoolingCoilType, "COILSYSTEM:INTEGRATEDHEATPUMP:AIRSOURCE")) {
2894 0 : thisFurnace.CoolingCoilType_Num = HVAC::Coil_CoolingAirToAirVariableSpeed;
2895 0 : if (Util::SameString(CoolingCoilType, "COILSYSTEM:INTEGRATEDHEATPUMP:AIRSOURCE")) {
2896 0 : thisFurnace.bIsIHP = true;
2897 : }
2898 : }
2899 :
2900 2 : ValidateComponent(state, CoolingCoilType, CoolingCoilName, IsNotOK, CurrentModuleObject);
2901 :
2902 2 : if (IsNotOK) {
2903 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2904 0 : ErrorsFound = true;
2905 :
2906 : } else { // mine data from DX cooling coil
2907 :
2908 2 : errFlag = false;
2909 2 : PrintMessage = false;
2910 :
2911 2 : if (thisFurnace.CoolingCoilType_Num != HVAC::Coil_CoolingAirToAirVariableSpeed) {
2912 2 : thisFurnace.CoolingCoilType_Num = DXCoils::GetCoilTypeNum(state, CoolingCoilType, CoolingCoilName, errFlag, PrintMessage);
2913 : }
2914 :
2915 : // If coil type not found, check to see if a HX assisted cooling coil is used.
2916 2 : if (thisFurnace.CoolingCoilType_Num == 0) {
2917 0 : errFlag = false;
2918 0 : PrintMessage = false;
2919 0 : thisFurnace.CoolingCoilType_Num =
2920 0 : HVACHXAssistedCoolingCoil::GetCoilGroupTypeNum(state, CoolingCoilType, CoolingCoilName, errFlag, PrintMessage);
2921 : }
2922 :
2923 2 : if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingSingleSpeed) {
2924 :
2925 : // Get the cooling coil node numbers
2926 2 : errFlag = false;
2927 2 : DXCoils::GetDXCoilIndex(state, CoolingCoilName, thisFurnace.CoolingCoilIndex, errFlag);
2928 2 : CoolingCoilInletNode = DXCoils::GetCoilInletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
2929 2 : CoolingCoilOutletNode = DXCoils::GetCoilOutletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
2930 2 : if (errFlag) {
2931 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2932 0 : ErrorsFound = true;
2933 : }
2934 :
2935 : // Get the DX cooling coil design capacity
2936 2 : errFlag = false;
2937 2 : thisFurnace.DesignCoolingCapacity = DXCoils::GetCoilCapacity(state, CoolingCoilType, CoolingCoilName, errFlag);
2938 2 : if (errFlag) {
2939 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2940 0 : ErrorsFound = true;
2941 : }
2942 :
2943 0 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) {
2944 :
2945 : // Get the cooling coil node numbers
2946 0 : errFlag = false;
2947 0 : HVACHXAssistedCoolingCoil::GetHXDXCoilIndex(state, CoolingCoilName, thisFurnace.CoolingCoilIndex, errFlag);
2948 0 : CoolingCoilInletNode = HVACHXAssistedCoolingCoil::GetCoilInletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
2949 0 : CoolingCoilOutletNode = HVACHXAssistedCoolingCoil::GetCoilOutletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
2950 0 : if (errFlag) {
2951 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2952 0 : ErrorsFound = true;
2953 : }
2954 :
2955 : // Get the heat exchanger assisted cooling coil design capacity
2956 0 : errFlag = false;
2957 0 : thisFurnace.DesignCoolingCapacity = HVACHXAssistedCoolingCoil::GetCoilCapacity(state, CoolingCoilType, CoolingCoilName, errFlag);
2958 0 : if (errFlag) {
2959 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2960 0 : ErrorsFound = true;
2961 : }
2962 :
2963 : // get the actual index to the DX cooling coil object
2964 0 : DXCoilIndex = HVACHXAssistedCoolingCoil::GetActualDXCoilIndex(state, CoolingCoilType, CoolingCoilName, ErrorsFound);
2965 0 : thisFurnace.ActualDXCoilIndexForHXAssisted = DXCoilIndex;
2966 :
2967 0 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) {
2968 : // BOS ADDED, AUG/2012, VARIIABLE SPEED DX COOLING COIL
2969 : // Furnace(FurnaceNum)%DXCoolCoilType = 'COIL:COOLING:DX:VARIABLESPEED'
2970 : // Furnace(FurnaceNum)%DXCoolCoilName = CoolingCoilName
2971 0 : ValidateComponent(state, CoolingCoilType, CoolingCoilName, IsNotOK, CurrentModuleObject);
2972 0 : if (IsNotOK) {
2973 0 : ShowContinueError(state, format("...specified in {}=\"{}\".", CurrentModuleObject, Alphas(1)));
2974 0 : ErrorsFound = true;
2975 : } else {
2976 0 : errFlag = false;
2977 0 : if (thisFurnace.bIsIHP) {
2978 0 : thisFurnace.CoolingCoilIndex = IntegratedHeatPump::GetCoilIndexIHP(state, CoolingCoilType, CoolingCoilName, errFlag);
2979 0 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SCCoilName;
2980 : } else {
2981 0 : thisFurnace.CoolingCoilIndex =
2982 0 : VariableSpeedCoils::GetCoilIndexVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
2983 0 : IHPCoilName = CoolingCoilName;
2984 : }
2985 :
2986 0 : if (errFlag) {
2987 0 : ShowContinueError(state, format("...specified in {}=\"{}\".", CurrentModuleObject, Alphas(1)));
2988 0 : ErrorsFound = true;
2989 : }
2990 :
2991 0 : if (thisFurnace.bIsIHP) {
2992 : CoolingCoilInletNode =
2993 0 : VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, "COIL:COOLING:DX:VARIABLESPEED", IHPCoilName, errFlag);
2994 : CoolingCoilOutletNode =
2995 0 : VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, "COIL:COOLING:DX:VARIABLESPEED", IHPCoilName, errFlag);
2996 0 : thisFurnace.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, IHPCoilName, errFlag);
2997 : } else {
2998 : CoolingCoilInletNode =
2999 0 : VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
3000 : CoolingCoilOutletNode =
3001 0 : VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
3002 0 : thisFurnace.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, CoolingCoilName, errFlag);
3003 : }
3004 :
3005 0 : if (errFlag) {
3006 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3007 0 : ErrorsFound = true;
3008 : }
3009 : }
3010 : } else {
3011 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3012 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(10), Alphas(10)));
3013 0 : ErrorsFound = true;
3014 : }
3015 : }
3016 :
3017 2 : if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed &&
3018 0 : thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed) {
3019 : // Furnace(FurnaceNum)%WatertoAirHPType = WatertoAir_VarSpeedEquationFit
3020 0 : if (thisFurnace.bIsIHP) {
3021 0 : VariableSpeedCoils::SetVarSpeedCoilData(state,
3022 0 : state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SCCoilIndex,
3023 : ErrorsFound,
3024 : _,
3025 0 : state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SHCoilIndex);
3026 : } else {
3027 0 : VariableSpeedCoils::SetVarSpeedCoilData(state, thisFurnace.CoolingCoilIndex, ErrorsFound, _, thisFurnace.HeatingCoilIndex);
3028 : }
3029 : }
3030 :
3031 : // Get supplemental heating coil information
3032 2 : SuppHeatCoilType = Alphas(12);
3033 2 : SuppHeatCoilName = Alphas(13);
3034 2 : thisFurnace.SuppHeatCoilType = SuppHeatCoilType;
3035 2 : thisFurnace.SuppHeatCoilName = SuppHeatCoilName;
3036 2 : errFlag = false;
3037 2 : if (Util::SameString(SuppHeatCoilType, "Coil:Heating:Fuel") || Util::SameString(SuppHeatCoilType, "Coil:Heating:Electric")) {
3038 :
3039 2 : thisFurnace.SuppHeatCoilType_Num = HeatingCoils::GetHeatingCoilTypeNum(state, SuppHeatCoilType, SuppHeatCoilName, errFlag);
3040 2 : if (errFlag) {
3041 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3042 0 : ErrorsFound = true;
3043 : } else {
3044 2 : IsNotOK = false;
3045 2 : ValidateComponent(state, SuppHeatCoilType, SuppHeatCoilName, IsNotOK, CurrentModuleObject);
3046 2 : if (IsNotOK) {
3047 0 : ShowContinueError(state, format("In {} \"{}\"", CurrentModuleObject, Alphas(1)));
3048 0 : ErrorsFound = true;
3049 :
3050 : } else { // mine data from the supplemental heating coil
3051 :
3052 2 : HeatingCoils::GetCoilIndex(state, SuppHeatCoilName, thisFurnace.SuppHeatCoilIndex, IsNotOK);
3053 2 : if (IsNotOK) {
3054 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3055 0 : ErrorsFound = true;
3056 : }
3057 :
3058 : // Get the Supplemental Heating Coil Inlet Node Number
3059 2 : errFlag = false;
3060 2 : SupHeatCoilInletNode = HeatingCoils::GetCoilInletNode(state, SuppHeatCoilType, SuppHeatCoilName, errFlag);
3061 2 : if (errFlag) {
3062 0 : ShowContinueError(state, format("...occurs in {} \"{}\"", CurrentModuleObject, Alphas(1)));
3063 0 : ErrorsFound = true;
3064 : }
3065 :
3066 : // Get the Supplemental Heating Coil Outlet Node Number
3067 2 : errFlag = false;
3068 2 : SupHeatCoilOutletNode = HeatingCoils::GetCoilOutletNode(state, SuppHeatCoilType, SuppHeatCoilName, errFlag);
3069 :
3070 2 : if (errFlag) {
3071 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3072 0 : ErrorsFound = true;
3073 : }
3074 :
3075 : // Get the supplemental heating coil design capacity
3076 2 : errFlag = false;
3077 2 : thisFurnace.DesignSuppHeatingCapacity = HeatingCoils::GetCoilCapacity(state, SuppHeatCoilType, SuppHeatCoilName, errFlag);
3078 2 : if (errFlag) {
3079 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3080 0 : ErrorsFound = true;
3081 : }
3082 :
3083 : } // IF (IsNotOK) THEN
3084 : }
3085 0 : } else if (Util::SameString(SuppHeatCoilType, "Coil:Heating:Water")) {
3086 0 : thisFurnace.SuppHeatCoilType_Num = HVAC::Coil_HeatingWater;
3087 0 : ValidateComponent(state, SuppHeatCoilType, SuppHeatCoilName, IsNotOK, CurrentModuleObject);
3088 0 : if (IsNotOK) {
3089 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3090 0 : ErrorsFound = true;
3091 : } else { // mine data from heating coil object
3092 :
3093 : // Get the Heating Coil water Inlet or control Node number
3094 0 : errFlag = false;
3095 0 : thisFurnace.SuppCoilControlNode = WaterCoils::GetCoilWaterInletNode(state, "Coil:Heating:Water", SuppHeatCoilName, errFlag);
3096 0 : if (errFlag) {
3097 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3098 0 : ErrorsFound = true;
3099 : }
3100 :
3101 : // Get the ReHeat Coil hot water max volume flow rate
3102 0 : errFlag = false;
3103 0 : thisFurnace.MaxSuppCoilFluidFlow = WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", SuppHeatCoilName, errFlag);
3104 0 : if (errFlag) {
3105 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3106 0 : ErrorsFound = true;
3107 : }
3108 :
3109 : // Get the ReHeat Coil Inlet Node
3110 0 : errFlag = false;
3111 0 : SupHeatCoilInletNode = WaterCoils::GetCoilInletNode(state, "Coil:Heating:Water", SuppHeatCoilName, errFlag);
3112 0 : thisFurnace.SuppCoilAirInletNode = SupHeatCoilInletNode;
3113 0 : if (errFlag) {
3114 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3115 0 : ErrorsFound = true;
3116 : }
3117 :
3118 : // Get the ReHeat Coil Outlet Node
3119 0 : errFlag = false;
3120 0 : SupHeatCoilOutletNode = WaterCoils::GetCoilOutletNode(state, "Coil:Heating:Water", SuppHeatCoilName, errFlag);
3121 0 : thisFurnace.SuppCoilAirOutletNode = SupHeatCoilOutletNode;
3122 0 : if (errFlag) {
3123 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3124 0 : ErrorsFound = true;
3125 : }
3126 0 : errFlag = false;
3127 0 : HVACControllers::CheckCoilWaterInletNode(state, thisFurnace.CoilControlNode, errFlag);
3128 0 : if (!errFlag) { // then did find a controller so that is bad
3129 0 : ShowSevereError(state,
3130 0 : format("{} = {} has a conflicting Controller:WaterCoil object", CurrentModuleObject, thisFurnace.Name));
3131 0 : ShowContinueError(state, "Hot water coils are controlled directly by unitary and furnace systems.");
3132 0 : ShowContinueError(state, "No water coil controller should be input for the coil.");
3133 0 : ErrorsFound = true;
3134 : }
3135 : }
3136 :
3137 0 : } else if (Util::SameString(SuppHeatCoilType, "Coil:Heating:Steam")) {
3138 0 : thisFurnace.SuppHeatCoilType_Num = HVAC::Coil_HeatingSteam;
3139 0 : ValidateComponent(state, SuppHeatCoilType, SuppHeatCoilName, IsNotOK, CurrentModuleObject);
3140 0 : if (IsNotOK) {
3141 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3142 0 : ErrorsFound = true;
3143 : } else { // mine data from heating coil object
3144 :
3145 0 : errFlag = false;
3146 0 : thisFurnace.SuppHeatCoilIndex = SteamCoils::GetSteamCoilIndex(state, "COIL:HEATING:STEAM", SuppHeatCoilName, errFlag);
3147 0 : if (thisFurnace.SuppHeatCoilIndex == 0) {
3148 0 : ShowSevereError(state, format("{} illegal {} = {}", CurrentModuleObject, cAlphaFields(12), SuppHeatCoilName));
3149 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3150 0 : ErrorsFound = true;
3151 : }
3152 :
3153 : // Get the Heating Coil steam inlet node number
3154 0 : errFlag = false;
3155 0 : thisFurnace.SuppCoilControlNode = SteamCoils::GetCoilSteamInletNode(state, "Coil:Heating:Steam", SuppHeatCoilName, errFlag);
3156 0 : if (errFlag) {
3157 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3158 0 : ErrorsFound = true;
3159 : }
3160 :
3161 : // Get the Heating Coil steam max volume flow rate
3162 0 : thisFurnace.MaxSuppCoilFluidFlow = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.SuppHeatCoilIndex, errFlag);
3163 0 : if (thisFurnace.MaxSuppCoilFluidFlow > 0.0) {
3164 : SteamDensity =
3165 0 : Fluid::GetSteam(state)->getSatDensity(state, state.dataFurnaces->TempSteamIn, 1.0, getAirLoopHVACHeatCoolInput);
3166 0 : thisFurnace.MaxSuppCoilFluidFlow =
3167 0 : SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.SuppHeatCoilIndex, errFlag) * SteamDensity;
3168 : }
3169 :
3170 : // Get the Heating Coil Inlet Node
3171 0 : errFlag = false;
3172 0 : SupHeatCoilInletNode = SteamCoils::GetCoilAirInletNode(state, thisFurnace.SuppHeatCoilIndex, SuppHeatCoilName, errFlag);
3173 0 : thisFurnace.SuppCoilAirInletNode = SupHeatCoilInletNode;
3174 0 : if (errFlag) {
3175 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3176 0 : ErrorsFound = true;
3177 : }
3178 :
3179 : // Get the Heating Coil Outlet Node
3180 0 : errFlag = false;
3181 0 : SupHeatCoilOutletNode = SteamCoils::GetCoilAirOutletNode(state, thisFurnace.SuppHeatCoilIndex, SuppHeatCoilName, errFlag);
3182 0 : thisFurnace.SuppCoilAirOutletNode = SupHeatCoilOutletNode;
3183 0 : if (errFlag) {
3184 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3185 0 : ErrorsFound = true;
3186 : }
3187 : }
3188 :
3189 : } else {
3190 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3191 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(12), Alphas(12)));
3192 0 : ErrorsFound = true;
3193 : } // IF (Furnace(FurnaceNum)%HeatingCoilType_Num == Coil_HeatingGasOrOtherFuel .OR. &, etc.
3194 :
3195 2 : thisFurnace.fanPlace = static_cast<HVAC::FanPlace>(getEnumValue(HVAC::fanPlaceNamesUC, Alphas(14)));
3196 2 : assert(thisFurnace.fanPlace != HVAC::FanPlace::Invalid);
3197 :
3198 2 : if (lAlphaBlanks(15)) {
3199 0 : thisFurnace.fanOp = HVAC::FanOp::Cycling;
3200 0 : if (thisFurnace.fanType != HVAC::FanType::OnOff) {
3201 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisFurnace.Name));
3202 0 : ShowContinueError(state, format("{} = {}", cAlphaFields(6), Alphas(6)));
3203 0 : ShowContinueError(state, format("Fan type must be Fan:OnOff when {} = Blank.", cAlphaFields(15)));
3204 0 : ErrorsFound = true;
3205 : }
3206 2 : } else if ((thisFurnace.fanOpModeSched = Sched::GetSchedule(state, Alphas(15))) == nullptr) {
3207 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(15), Alphas(15));
3208 0 : ErrorsFound = true;
3209 : }
3210 :
3211 2 : if (thisFurnace.fanType == HVAC::FanType::Constant && thisFurnace.fanOpModeSched != nullptr &&
3212 0 : !thisFurnace.fanOpModeSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) {
3213 0 : Sched::ShowSevereBadMinMax(
3214 : state,
3215 : eoh,
3216 0 : cAlphaFields(15),
3217 0 : Alphas(15),
3218 : Clusive::In,
3219 : 0.0,
3220 : Clusive::In,
3221 : 1.0,
3222 0 : format("For {} = {}, fan operating mode must be continuous (schedule values > 0)", cAlphaFields(7), Alphas(7)));
3223 0 : ErrorsFound = true;
3224 : }
3225 :
3226 : // Dehumidification Control Type
3227 2 : if (Util::SameString(Alphas(16), "None") || Util::SameString(Alphas(16), "Multimode") || Util::SameString(Alphas(16), "CoolReheat")) {
3228 2 : AirNodeFound = false;
3229 2 : if (Util::SameString(Alphas(16), "Multimode")) {
3230 0 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::Multimode;
3231 0 : thisFurnace.Humidistat = true;
3232 0 : if (thisFurnace.CoolingCoilType_Num != HVAC::CoilDX_CoolingHXAssisted) {
3233 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3234 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(16), Alphas(16)));
3235 0 : ShowContinueError(state, "Multimode control must be used with a Heat Exchanger Assisted Cooling Coil.");
3236 0 : ErrorsFound = true;
3237 : }
3238 : }
3239 2 : if (Util::SameString(Alphas(16), "CoolReheat")) {
3240 0 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::CoolReheat;
3241 0 : thisFurnace.Humidistat = true;
3242 : }
3243 2 : if (Util::SameString(Alphas(16), "None")) {
3244 2 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::None;
3245 2 : thisFurnace.Humidistat = false;
3246 : }
3247 2 : if (thisFurnace.Humidistat) {
3248 0 : for (HStatZoneNum = 1; HStatZoneNum <= state.dataZoneCtrls->NumHumidityControlZones; ++HStatZoneNum) {
3249 0 : if (state.dataZoneCtrls->HumidityControlZone(HStatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) {
3250 0 : continue;
3251 : }
3252 0 : AirNodeFound = true;
3253 : }
3254 0 : if (!AirNodeFound) {
3255 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3256 0 : ShowContinueError(state, "Did not find Air Node (Zone with Humidistat).");
3257 0 : ShowContinueError(state, format("Specified {} = {}", cAlphaFields(5), Alphas(5)));
3258 0 : ErrorsFound = true;
3259 : }
3260 : }
3261 : } else { // invalid input or blank
3262 0 : if (!lAlphaBlanks(16)) {
3263 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3264 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(16), Alphas(16)));
3265 0 : ErrorsFound = true;
3266 : } else {
3267 0 : thisFurnace.Humidistat = false;
3268 0 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::None;
3269 : }
3270 : }
3271 :
3272 : // Check node names for child components
3273 2 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
3274 2 : if (FanInletNode != thisFurnace.FurnaceInletNodeNum) {
3275 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, Alphas(1)));
3276 0 : ShowContinueError(
3277 : state,
3278 : "When a blow through fan is specified, the fan inlet node name must be the same as the unitary system inlet node name.");
3279 0 : ShowContinueError(state, format("...Fan inlet node name = {}", state.dataLoopNodes->NodeID(FanInletNode)));
3280 0 : ShowContinueError(state,
3281 0 : format("...Unitary system inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
3282 0 : ErrorsFound = true;
3283 : }
3284 2 : if (FanOutletNode != CoolingCoilInletNode) {
3285 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, Alphas(1)));
3286 0 : ShowContinueError(
3287 : state,
3288 : "When a blow through fan is specified, the fan outlet node name must be the same as the cooling coil inlet node name.");
3289 0 : ShowContinueError(state, format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
3290 0 : ShowContinueError(state, format("...Cooling coil inlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilInletNode)));
3291 0 : ErrorsFound = true;
3292 : }
3293 2 : if (CoolingCoilOutletNode != HeatingCoilInletNode) {
3294 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, Alphas(1)));
3295 0 : ShowContinueError(state, "The cooling coil outlet node name must be the same as the heating coil inlet node name.");
3296 0 : ShowContinueError(state, format("...Cooling coil outlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilOutletNode)));
3297 0 : ShowContinueError(state, format("...Heating coil inlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
3298 0 : ErrorsFound = true;
3299 : }
3300 2 : if (HeatingCoilOutletNode != SupHeatCoilInletNode) {
3301 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, Alphas(1)));
3302 0 : ShowContinueError(state,
3303 : "When a blow through fan is specified, the heating coil outlet node name must be the same as the supplemental "
3304 : "heating coil inlet node name.");
3305 0 : ShowContinueError(
3306 0 : state, format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
3307 0 : ShowContinueError(
3308 0 : state, format("...Supplemental heating coil inlet node name = {}", state.dataLoopNodes->NodeID(SupHeatCoilInletNode)));
3309 0 : ErrorsFound = true;
3310 : }
3311 2 : if (SupHeatCoilOutletNode != thisFurnace.FurnaceOutletNodeNum) {
3312 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, Alphas(1)));
3313 0 : ShowContinueError(state,
3314 : "The supplemental heating coil outlet node name must be the same as the unitary system outlet node name.");
3315 0 : ShowContinueError(
3316 0 : state, format("...Supplemental heating coil outlet node name = {}", state.dataLoopNodes->NodeID(SupHeatCoilOutletNode)));
3317 0 : ShowContinueError(
3318 : state,
3319 0 : format("...Unitary system outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
3320 0 : ErrorsFound = true;
3321 : }
3322 : } else {
3323 0 : if (CoolingCoilInletNode != thisFurnace.FurnaceInletNodeNum) {
3324 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, Alphas(1)));
3325 0 : ShowContinueError(state,
3326 : "When a draw through fan is specified, the cooling coil inlet node name must be the same as the unitary system "
3327 : "inlet node name.");
3328 0 : ShowContinueError(state, format("...Cooling coil inlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilInletNode)));
3329 0 : ShowContinueError(state,
3330 0 : format("...Unitary system inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
3331 0 : ErrorsFound = true;
3332 : }
3333 0 : if (CoolingCoilOutletNode != HeatingCoilInletNode) {
3334 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, Alphas(1)));
3335 0 : ShowContinueError(state, "The cooling coil outlet node name must be the same as the heating coil inlet node name.");
3336 0 : ShowContinueError(state, format("...Cooling coil outlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilOutletNode)));
3337 0 : ShowContinueError(state, format("...Heating coil inlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
3338 0 : ErrorsFound = true;
3339 : }
3340 0 : if (HeatingCoilOutletNode != FanInletNode) {
3341 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, Alphas(1)));
3342 0 : ShowContinueError(
3343 : state,
3344 : "When a draw through fan is specified, the heating coil outlet node name must be the same as the fan inlet node name.");
3345 0 : ShowContinueError(state, format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
3346 0 : ShowContinueError(state, format("...Fan inlet node name = {}", state.dataLoopNodes->NodeID(FanInletNode)));
3347 0 : ErrorsFound = true;
3348 : }
3349 0 : if (FanOutletNode != SupHeatCoilInletNode) {
3350 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, Alphas(1)));
3351 0 : ShowContinueError(state,
3352 : "When a draw through fan is specified, the fan outlet node name must be the same as the supplemental heating "
3353 : "coil inlet node name.");
3354 0 : ShowContinueError(state,
3355 0 : format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
3356 0 : ShowContinueError(
3357 0 : state, format("...Supplemental heating coil inlet node name = {}", state.dataLoopNodes->NodeID(SupHeatCoilInletNode)));
3358 0 : ErrorsFound = true;
3359 : }
3360 0 : if (SupHeatCoilOutletNode != thisFurnace.FurnaceOutletNodeNum) {
3361 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, Alphas(1)));
3362 0 : ShowContinueError(state,
3363 : "The supplemental heating coil outlet node name must be the same as the unitary system outlet node name.");
3364 0 : ShowContinueError(
3365 0 : state, format("...Supplemental heating coil outlet node name = {}", state.dataLoopNodes->NodeID(SupHeatCoilOutletNode)));
3366 0 : ShowContinueError(
3367 : state,
3368 0 : format("...Unitary system outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
3369 0 : ErrorsFound = true;
3370 : }
3371 : }
3372 :
3373 : // Add component sets array
3374 2 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
3375 2 : CompSetFanInlet = Alphas(3);
3376 2 : CompSetCoolInlet = "UNDEFINED";
3377 : } else {
3378 0 : CompSetFanInlet = "UNDEFINED";
3379 0 : CompSetCoolInlet = Alphas(3);
3380 : }
3381 2 : BranchNodeConnections::SetUpCompSets(state, CurrentModuleObject, Alphas(1), Alphas(6), Alphas(7), CompSetFanInlet, "UNDEFINED");
3382 :
3383 : // Add DX cooling coil to component sets array
3384 2 : if (thisFurnace.bIsIHP) {
3385 0 : BranchNodeConnections::SetUpCompSets(
3386 0 : state, CurrentModuleObject, Alphas(1), Alphas(10), Alphas(11) + " Cooling Coil", CompSetCoolInlet, "UNDEFINED");
3387 : } else {
3388 2 : BranchNodeConnections::SetUpCompSets(state, CurrentModuleObject, Alphas(1), Alphas(10), Alphas(11), CompSetCoolInlet, "UNDEFINED");
3389 : }
3390 : // Add DX heating coil to component sets array
3391 2 : if (thisFurnace.bIsIHP) {
3392 0 : BranchNodeConnections::SetUpCompSets(
3393 0 : state, CurrentModuleObject, Alphas(1), Alphas(8), Alphas(9) + " Heating Coil", "UNDEFINED", "UNDEFINED");
3394 : } else {
3395 2 : BranchNodeConnections::SetUpCompSets(state, CurrentModuleObject, Alphas(1), Alphas(8), Alphas(9), "UNDEFINED", "UNDEFINED");
3396 : }
3397 :
3398 : // Add supplemental heating coil to component sets array
3399 2 : BranchNodeConnections::SetUpCompSets(state, CurrentModuleObject, Alphas(1), Alphas(12), Alphas(13), "UNDEFINED", Alphas(4));
3400 :
3401 2 : thisFurnace.MaxCoolAirVolFlow = Numbers(1);
3402 2 : if (thisFurnace.MaxCoolAirVolFlow <= 0 && thisFurnace.MaxCoolAirVolFlow != DataSizing::AutoSize) {
3403 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3404 0 : ShowContinueError(state, format("Illegal {} = {:.7T}", cNumericFields(1), Numbers(1)));
3405 0 : ErrorsFound = true;
3406 : }
3407 :
3408 2 : thisFurnace.MaxHeatAirVolFlow = Numbers(2);
3409 2 : if (thisFurnace.MaxHeatAirVolFlow <= 0 && thisFurnace.MaxHeatAirVolFlow != DataSizing::AutoSize) {
3410 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3411 0 : ShowContinueError(state, format("Illegal {} = {:.7T}", cNumericFields(2), Numbers(2)));
3412 0 : ErrorsFound = true;
3413 : }
3414 :
3415 2 : thisFurnace.MaxNoCoolHeatAirVolFlow = Numbers(3);
3416 2 : if (thisFurnace.MaxNoCoolHeatAirVolFlow < 0 && thisFurnace.MaxNoCoolHeatAirVolFlow != DataSizing::AutoSize) {
3417 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3418 0 : ShowContinueError(state, format("Illegal {} = {:.7T}", cNumericFields(3), Numbers(3)));
3419 0 : ErrorsFound = true;
3420 : }
3421 :
3422 2 : if (thisFurnace.fanOpModeSched != nullptr) {
3423 2 : if (!thisFurnace.fanOpModeSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 0.0)) { // Autodesk:Note Range is 0 to 0?
3424 : // set air flow control mode:
3425 : // UseCompressorOnFlow = operate at last cooling or heating air flow requested when compressor is off
3426 : // UseCompressorOffFlow = operate at value specified by user
3427 : // AirFlowControl only valid if fan opmode = ContFanCycComp
3428 0 : if (thisFurnace.MaxNoCoolHeatAirVolFlow == 0.0) {
3429 0 : thisFurnace.AirFlowControl = AirFlowControlConstFan::UseCompressorOnFlow;
3430 : } else {
3431 0 : thisFurnace.AirFlowControl = AirFlowControlConstFan::UseCompressorOffFlow;
3432 : }
3433 : }
3434 : }
3435 :
3436 2 : if (Numbers(1) != DataSizing::AutoSize && Numbers(2) != DataSizing::AutoSize && Numbers(3) != DataSizing::AutoSize) {
3437 0 : thisFurnace.DesignFanVolFlowRate = max(Numbers(1), Numbers(2), Numbers(3));
3438 : } else {
3439 2 : thisFurnace.DesignFanVolFlowRate = DataSizing::AutoSize;
3440 : }
3441 :
3442 2 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed) {
3443 0 : errFlag = false;
3444 :
3445 0 : if (thisFurnace.bIsIHP) {
3446 0 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SHCoilName;
3447 0 : thisFurnace.MaxHeatAirVolFlow =
3448 0 : VariableSpeedCoils::GetCoilAirFlowRateVariableSpeed(state, "COIL:HEATING:DX:VARIABLESPEED", IHPCoilName, errFlag);
3449 0 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SCCoilName;
3450 0 : thisFurnace.MaxCoolAirVolFlow =
3451 0 : VariableSpeedCoils::GetCoilAirFlowRateVariableSpeed(state, "COIL:COOLING:DX:VARIABLESPEED", IHPCoilName, errFlag);
3452 : } else {
3453 0 : thisFurnace.MaxHeatAirVolFlow =
3454 0 : VariableSpeedCoils::GetCoilAirFlowRateVariableSpeed(state, HeatingCoilType, HeatingCoilName, errFlag);
3455 0 : thisFurnace.MaxCoolAirVolFlow =
3456 0 : VariableSpeedCoils::GetCoilAirFlowRateVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
3457 : }
3458 :
3459 0 : if (errFlag) {
3460 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3461 0 : ErrorsFound = true;
3462 : }
3463 :
3464 0 : thisFurnace.MaxNoCoolHeatAirVolFlow = min(thisFurnace.MaxHeatAirVolFlow, thisFurnace.MaxCoolAirVolFlow);
3465 0 : if (thisFurnace.MaxHeatAirVolFlow != DataSizing::AutoSize && thisFurnace.MaxCoolAirVolFlow != DataSizing::AutoSize) {
3466 0 : thisFurnace.DesignFanVolFlowRate = max(thisFurnace.MaxHeatAirVolFlow, thisFurnace.MaxCoolAirVolFlow);
3467 : } else {
3468 0 : thisFurnace.DesignFanVolFlowRate = DataSizing::AutoSize;
3469 : }
3470 : }
3471 :
3472 2 : if (thisFurnace.ActualFanVolFlowRate != DataSizing::AutoSize) {
3473 0 : if (thisFurnace.ActualFanVolFlowRate < thisFurnace.MaxCoolAirVolFlow && thisFurnace.MaxCoolAirVolFlow != DataSizing::AutoSize) {
3474 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3475 0 : ShowContinueError(
3476 : state,
3477 0 : format("... air flow rate = {:.7T} in fan object {} is less than the maximum HVAC system air flow rate in cooling mode.",
3478 0 : thisFurnace.ActualFanVolFlowRate,
3479 : FanName));
3480 0 : ShowContinueError(state, format(" The {} is reset to the fan flow rate and the simulation continues.", cNumericFields(1)));
3481 0 : thisFurnace.MaxCoolAirVolFlow = thisFurnace.ActualFanVolFlowRate;
3482 0 : thisFurnace.DesignFanVolFlowRate = thisFurnace.ActualFanVolFlowRate;
3483 : }
3484 0 : if (thisFurnace.ActualFanVolFlowRate < thisFurnace.MaxHeatAirVolFlow && thisFurnace.MaxHeatAirVolFlow != DataSizing::AutoSize) {
3485 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3486 0 : ShowContinueError(
3487 : state,
3488 0 : format("... air flow rate = {:.7T} in fan object {} is less than the maximum HVAC system air flow rate in heating mode.",
3489 0 : thisFurnace.ActualFanVolFlowRate,
3490 : FanName));
3491 0 : ShowContinueError(state, format(" The {} is reset to the fan flow rate and the simulation continues.", cNumericFields(2)));
3492 0 : thisFurnace.MaxHeatAirVolFlow = thisFurnace.ActualFanVolFlowRate;
3493 0 : thisFurnace.DesignFanVolFlowRate = thisFurnace.ActualFanVolFlowRate;
3494 : }
3495 : }
3496 :
3497 : // Set heating convergence tolerance
3498 2 : thisFurnace.HeatingConvergenceTolerance = 0.001;
3499 :
3500 : // Mine heatpump outdoor condenser node from DX coil object
3501 2 : errFlag = false;
3502 2 : if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingSingleSpeed) {
3503 2 : thisFurnace.CondenserNodeNum = DXCoils::GetCoilCondenserInletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
3504 0 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) {
3505 0 : if (thisFurnace.bIsIHP) {
3506 0 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SCCoilName;
3507 0 : thisFurnace.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, IHPCoilName, errFlag);
3508 : } else {
3509 0 : thisFurnace.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, CoolingCoilName, errFlag);
3510 : }
3511 : } else {
3512 0 : thisFurnace.CondenserNodeNum =
3513 0 : DXCoils::GetCoilCondenserInletNode(state,
3514 : "Coil:Cooling:DX:SingleSpeed",
3515 0 : HVACHXAssistedCoolingCoil::GetHXDXCoilName(state, CoolingCoilType, CoolingCoilName, errFlag),
3516 : errFlag);
3517 : }
3518 2 : if (errFlag) {
3519 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3520 0 : ErrorsFound = true;
3521 : }
3522 :
3523 2 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed) {
3524 0 : errFlag = false;
3525 0 : if (thisFurnace.bIsIHP) {
3526 0 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SHCoilName;
3527 0 : thisFurnace.DesignHeatingCapacity =
3528 0 : VariableSpeedCoils::GetCoilCapacityVariableSpeed(state, "Coil:Heating:DX:VariableSpeed", IHPCoilName, errFlag);
3529 : } else {
3530 0 : thisFurnace.DesignHeatingCapacity =
3531 0 : VariableSpeedCoils::GetCoilCapacityVariableSpeed(state, HeatingCoilType, HeatingCoilName, errFlag);
3532 : }
3533 :
3534 0 : if (errFlag) {
3535 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3536 0 : ErrorsFound = true;
3537 : }
3538 : }
3539 :
3540 2 : if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) {
3541 0 : errFlag = false;
3542 0 : if (thisFurnace.bIsIHP) {
3543 0 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SCCoilName;
3544 0 : thisFurnace.DesignCoolingCapacity =
3545 0 : VariableSpeedCoils::GetCoilCapacityVariableSpeed(state, "COIL:COOLING:DX:VARIABLESPEED", IHPCoilName, errFlag);
3546 : } else {
3547 0 : thisFurnace.DesignCoolingCapacity =
3548 0 : VariableSpeedCoils::GetCoilCapacityVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
3549 : }
3550 :
3551 0 : if (errFlag) {
3552 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3553 0 : ErrorsFound = true;
3554 : }
3555 : }
3556 :
3557 : // Set cooling convergence tolerance
3558 2 : thisFurnace.CoolingConvergenceTolerance = 0.001;
3559 :
3560 : // Set the furnace max outlet temperature
3561 2 : thisFurnace.DesignMaxOutletTemp = Numbers(4);
3562 :
3563 : // Set maximum supply air temperature for supplemental heating coil
3564 2 : thisFurnace.MaxOATSuppHeat = Numbers(5);
3565 4 : OutputReportPredefined::PreDefTableEntry(
3566 2 : state, state.dataOutRptPredefined->pdchDXHeatCoilSuppHiT, HeatingCoilName, thisFurnace.MaxOATSuppHeat);
3567 :
3568 : // set minimum outdoor temperature for compressor operation
3569 2 : SetMinOATCompressor(state, FurnaceNum, cCurrentModuleObject, ErrorsFound);
3570 :
3571 : } // End of the Unitary System HeatPump Loop
3572 :
3573 : // Get the Input for the Water to Air Heat Pump (UnitarySystem:HeatPump:WaterToAir)
3574 2 : for (int HeatPumpNum = 1; HeatPumpNum <= NumWaterToAirHeatPump; ++HeatPumpNum) {
3575 :
3576 0 : CurrentModuleObject = "AirLoopHVAC:UnitaryHeatPump:WaterToAir";
3577 0 : FanInletNode = 0;
3578 0 : FanOutletNode = 0;
3579 0 : CoolingCoilInletNode = 0;
3580 0 : CoolingCoilOutletNode = 0;
3581 0 : HeatingCoilInletNode = 0;
3582 0 : HeatingCoilOutletNode = 0;
3583 0 : SupHeatCoilInletNode = 0;
3584 0 : SupHeatCoilOutletNode = 0;
3585 0 : CoolingCoilType = ' ';
3586 0 : CoolingCoilName = ' ';
3587 0 : HeatingCoilType = ' ';
3588 0 : HeatingCoilName = ' ';
3589 :
3590 0 : FurnaceNum = NumHeatOnly + NumHeatCool + NumUnitaryHeatOnly + NumUnitaryHeatCool + NumHeatPump + HeatPumpNum;
3591 0 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
3592 0 : thisFurnace.iterationMode.allocate(3);
3593 :
3594 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
3595 : CurrentModuleObject,
3596 : HeatPumpNum,
3597 : Alphas,
3598 : NumAlphas,
3599 : Numbers,
3600 : NumNumbers,
3601 : IOStatus,
3602 : lNumericBlanks,
3603 : lAlphaBlanks,
3604 : cAlphaFields,
3605 : cNumericFields);
3606 :
3607 0 : GlobalNames::VerifyUniqueInterObjectName(
3608 0 : state, state.dataFurnaces->UniqueFurnaceNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
3609 :
3610 0 : thisFurnace.type = HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir;
3611 0 : thisFurnace.Name = Alphas(1);
3612 :
3613 0 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, thisFurnace.Name};
3614 :
3615 0 : if (lAlphaBlanks(2)) {
3616 0 : thisFurnace.availSched = Sched::GetScheduleAlwaysOn(state);
3617 0 : } else if ((thisFurnace.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
3618 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
3619 0 : ErrorsFound = true;
3620 : }
3621 :
3622 0 : thisFurnace.FurnaceInletNodeNum =
3623 0 : NodeInputManager::GetOnlySingleNode(state,
3624 0 : Alphas(3),
3625 : ErrorsFound,
3626 : DataLoopNode::ConnectionObjectType::AirLoopHVACUnitaryHeatPumpWaterToAir,
3627 0 : Alphas(1),
3628 : DataLoopNode::NodeFluidType::Air,
3629 : DataLoopNode::ConnectionType::Inlet,
3630 : NodeInputManager::CompFluidStream::Primary,
3631 : DataLoopNode::ObjectIsParent);
3632 :
3633 0 : thisFurnace.FurnaceOutletNodeNum =
3634 0 : NodeInputManager::GetOnlySingleNode(state,
3635 0 : Alphas(4),
3636 : ErrorsFound,
3637 : DataLoopNode::ConnectionObjectType::AirLoopHVACUnitaryHeatPumpWaterToAir,
3638 0 : Alphas(1),
3639 : DataLoopNode::NodeFluidType::Air,
3640 : DataLoopNode::ConnectionType::Outlet,
3641 : NodeInputManager::CompFluidStream::Primary,
3642 : DataLoopNode::ObjectIsParent);
3643 :
3644 0 : BranchNodeConnections::TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(3), Alphas(4), "Air Nodes");
3645 :
3646 : // Get the Controlling Zone or Location of the Furnace Thermostat
3647 0 : thisFurnace.ControlZoneNum = Util::FindItemInList(Alphas(5), state.dataHeatBal->Zone);
3648 0 : if (thisFurnace.ControlZoneNum == 0) {
3649 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3650 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(5), Alphas(5)));
3651 0 : ErrorsFound = true;
3652 : }
3653 :
3654 : // Get the node number for the zone with the thermostat
3655 0 : if (thisFurnace.ControlZoneNum > 0) {
3656 0 : AirNodeFound = false;
3657 0 : AirLoopFound = false;
3658 0 : int ControlledZoneNum = thisFurnace.ControlZoneNum;
3659 : // Find the controlled zone number for the specified thermostat location
3660 0 : thisFurnace.NodeNumOfControlledZone = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneNode;
3661 : // Determine if furnace is on air loop served by the thermostat location specified
3662 0 : for (int zoneInNode = 1; zoneInNode <= state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumInletNodes; ++zoneInNode) {
3663 0 : int AirLoopNumber = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNodeAirLoopNum(zoneInNode);
3664 0 : if (AirLoopNumber > 0) {
3665 0 : for (int BranchNum = 1; BranchNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).NumBranches; ++BranchNum) {
3666 0 : for (int CompNum = 1;
3667 0 : CompNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).TotalComponents;
3668 : ++CompNum) {
3669 0 : if (!Util::SameString(state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).Name,
3670 0 : Alphas(1)) ||
3671 0 : !Util::SameString(
3672 0 : state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).TypeOf,
3673 : CurrentModuleObject)) {
3674 0 : continue;
3675 : }
3676 0 : AirLoopFound = true;
3677 0 : thisFurnace.ZoneInletNode = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNode(zoneInNode);
3678 0 : break;
3679 : }
3680 0 : if (AirLoopFound) {
3681 0 : break;
3682 : }
3683 : }
3684 0 : for (TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumTempControlledZones; ++TstatZoneNum) {
3685 0 : if (state.dataZoneCtrls->TempControlledZone(TstatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) {
3686 0 : continue;
3687 : }
3688 0 : AirNodeFound = true;
3689 : }
3690 0 : for (TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumComfortControlledZones; ++TstatZoneNum) {
3691 0 : if (state.dataZoneCtrls->ComfortControlledZone(TstatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) {
3692 0 : continue;
3693 : }
3694 0 : AirNodeFound = true;
3695 : }
3696 : }
3697 0 : if (AirLoopFound) {
3698 0 : break;
3699 : }
3700 : }
3701 0 : if (!AirNodeFound) {
3702 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3703 0 : ShowContinueError(state, "Did not find air node (zone with thermostat).");
3704 0 : ShowContinueError(state, format("Specified {} = {}", cAlphaFields(5), Alphas(5)));
3705 0 : ShowContinueError(
3706 : state, "Both a ZoneHVAC:EquipmentConnections object and a ZoneControl:Thermostat object must be specified for this zone.");
3707 0 : ErrorsFound = true;
3708 : }
3709 0 : if (!AirLoopFound) {
3710 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3711 0 : ShowContinueError(state, "Did not find correct AirLoopHVAC.");
3712 0 : ShowContinueError(state, format("Specified {} = {}", cAlphaFields(5), Alphas(5)));
3713 0 : ErrorsFound = true;
3714 : }
3715 : }
3716 :
3717 : // Get fan data
3718 0 : FanName = Alphas(7);
3719 0 : errFlag = false;
3720 0 : thisFurnace.fanType = static_cast<HVAC::FanType>(getEnumValue(HVAC::fanTypeNamesUC, Alphas(6)));
3721 :
3722 0 : if (thisFurnace.fanType != HVAC::FanType::OnOff) {
3723 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3724 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(6), Alphas(6)));
3725 0 : ErrorsFound = true;
3726 :
3727 0 : } else if ((thisFurnace.FanIndex = Fans::GetFanIndex(state, FanName)) == 0) {
3728 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(7), FanName);
3729 0 : ErrorsFound = true;
3730 :
3731 : } else {
3732 0 : auto *fan = state.dataFans->fans(thisFurnace.FanIndex);
3733 0 : FanInletNode = fan->inletNodeNum;
3734 0 : FanOutletNode = fan->outletNodeNum;
3735 0 : thisFurnace.fanAvailSched = fan->availSched;
3736 : }
3737 :
3738 : // Get heating coil type and name data
3739 0 : if (Alphas(8) == "COIL:HEATING:WATERTOAIRHEATPUMP:PARAMETERESTIMATION") {
3740 0 : HeatingCoilType = Alphas(8);
3741 0 : thisFurnace.HeatingCoilType_Num = HVAC::Coil_HeatingWaterToAirHP;
3742 0 : HeatingCoilName = Alphas(9);
3743 0 : ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject);
3744 0 : if (IsNotOK) {
3745 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3746 0 : ErrorsFound = true;
3747 : } else {
3748 0 : thisFurnace.HeatingCoilIndex = WaterToAirHeatPump::GetCoilIndex(state, HeatingCoilType, HeatingCoilName, errFlag);
3749 0 : HeatingCoilInletNode = WaterToAirHeatPump::GetCoilInletNode(state, HeatingCoilType, HeatingCoilName, errFlag);
3750 0 : HeatingCoilOutletNode = WaterToAirHeatPump::GetCoilOutletNode(state, HeatingCoilType, HeatingCoilName, errFlag);
3751 : }
3752 0 : } else if (Alphas(8) == "COIL:HEATING:WATERTOAIRHEATPUMP:EQUATIONFIT") {
3753 0 : HeatingCoilType = Alphas(8);
3754 0 : thisFurnace.HeatingCoilType_Num = HVAC::Coil_HeatingWaterToAirHPSimple;
3755 0 : HeatingCoilName = Alphas(9);
3756 0 : ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject);
3757 0 : if (IsNotOK) {
3758 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3759 0 : ErrorsFound = true;
3760 : } else {
3761 0 : thisFurnace.HeatingCoilIndex = WaterToAirHeatPumpSimple::GetCoilIndex(state, HeatingCoilType, HeatingCoilName, errFlag);
3762 0 : HeatingCoilInletNode = WaterToAirHeatPumpSimple::GetCoilInletNode(state, HeatingCoilType, HeatingCoilName, errFlag);
3763 0 : HeatingCoilOutletNode = WaterToAirHeatPumpSimple::GetCoilOutletNode(state, HeatingCoilType, HeatingCoilName, errFlag);
3764 : }
3765 0 : } else if (Alphas(8) == "COIL:HEATING:WATERTOAIRHEATPUMP:VARIABLESPEEDEQUATIONFIT") {
3766 0 : HeatingCoilType = Alphas(8);
3767 0 : thisFurnace.HeatingCoilType_Num = HVAC::Coil_HeatingWaterToAirHPVSEquationFit;
3768 0 : HeatingCoilName = Alphas(9);
3769 0 : ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject);
3770 0 : if (IsNotOK) {
3771 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3772 0 : ErrorsFound = true;
3773 : } else {
3774 0 : thisFurnace.HeatingCoilIndex = VariableSpeedCoils::GetCoilIndexVariableSpeed(state, HeatingCoilType, HeatingCoilName, errFlag);
3775 0 : HeatingCoilInletNode = VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, HeatingCoilType, HeatingCoilName, errFlag);
3776 0 : HeatingCoilOutletNode = VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, HeatingCoilType, HeatingCoilName, errFlag);
3777 : }
3778 : } else {
3779 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3780 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(8), Alphas(8)));
3781 0 : ErrorsFound = true;
3782 : }
3783 :
3784 : // Get Cooling Coil Information if available
3785 0 : if (Alphas(10) == "COIL:COOLING:WATERTOAIRHEATPUMP:PARAMETERESTIMATION") {
3786 0 : CoolingCoilType = Alphas(10);
3787 0 : thisFurnace.CoolingCoilType_Num = HVAC::Coil_CoolingWaterToAirHP;
3788 0 : CoolingCoilName = Alphas(11);
3789 0 : ValidateComponent(state, CoolingCoilType, CoolingCoilName, IsNotOK, CurrentModuleObject);
3790 0 : if (IsNotOK) {
3791 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3792 0 : ErrorsFound = true;
3793 : } else {
3794 0 : thisFurnace.CoolingCoilIndex = WaterToAirHeatPump::GetCoilIndex(state, CoolingCoilType, CoolingCoilName, errFlag);
3795 0 : CoolingCoilInletNode = WaterToAirHeatPump::GetCoilInletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
3796 0 : CoolingCoilOutletNode = WaterToAirHeatPump::GetCoilOutletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
3797 : }
3798 0 : } else if (Alphas(10) == "COIL:COOLING:WATERTOAIRHEATPUMP:EQUATIONFIT") {
3799 0 : CoolingCoilType = Alphas(10);
3800 0 : thisFurnace.CoolingCoilType_Num = HVAC::Coil_CoolingWaterToAirHPSimple;
3801 0 : CoolingCoilName = Alphas(11);
3802 0 : ValidateComponent(state, CoolingCoilType, CoolingCoilName, IsNotOK, CurrentModuleObject);
3803 0 : if (IsNotOK) {
3804 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3805 0 : ErrorsFound = true;
3806 : } else {
3807 0 : thisFurnace.CoolingCoilIndex = WaterToAirHeatPumpSimple::GetCoilIndex(state, CoolingCoilType, CoolingCoilName, errFlag);
3808 0 : CoolingCoilInletNode = WaterToAirHeatPumpSimple::GetCoilInletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
3809 0 : CoolingCoilOutletNode = WaterToAirHeatPumpSimple::GetCoilOutletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
3810 : }
3811 0 : } else if (Alphas(10) == "COIL:COOLING:WATERTOAIRHEATPUMP:VARIABLESPEEDEQUATIONFIT") {
3812 0 : CoolingCoilType = Alphas(10);
3813 0 : thisFurnace.CoolingCoilType_Num = HVAC::Coil_CoolingWaterToAirHPVSEquationFit;
3814 0 : CoolingCoilName = Alphas(11);
3815 0 : ValidateComponent(state, CoolingCoilType, CoolingCoilName, IsNotOK, CurrentModuleObject);
3816 0 : if (IsNotOK) {
3817 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3818 0 : ErrorsFound = true;
3819 : } else {
3820 0 : thisFurnace.CoolingCoilIndex = VariableSpeedCoils::GetCoilIndexVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
3821 0 : CoolingCoilInletNode = VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
3822 0 : CoolingCoilOutletNode = VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
3823 : }
3824 : } else {
3825 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3826 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(10), Alphas(10)));
3827 0 : ErrorsFound = true;
3828 : }
3829 :
3830 0 : thisFurnace.WaterCyclingMode = (NumAlphas < 18 || lAlphaBlanks(18))
3831 0 : ? HVAC::WaterFlow::Cycling
3832 0 : : static_cast<HVAC::WaterFlow>(getEnumValue(HVAC::waterFlowNamesUC, Alphas(18)));
3833 :
3834 : // end get water flow mode info
3835 0 : if (Alphas(8) == "COIL:HEATING:WATERTOAIRHEATPUMP:EQUATIONFIT" && Alphas(10) == "COIL:COOLING:WATERTOAIRHEATPUMP:EQUATIONFIT") {
3836 0 : thisFurnace.WatertoAirHPType = WAHPCoilType::Simple;
3837 0 : WaterToAirHeatPumpSimple::SetSimpleWSHPData(
3838 0 : state, thisFurnace.CoolingCoilIndex, ErrorsFound, thisFurnace.WaterCyclingMode, _, thisFurnace.HeatingCoilIndex);
3839 0 : } else if (Alphas(8) == "COIL:HEATING:WATERTOAIRHEATPUMP:PARAMETERESTIMATION" &&
3840 0 : Alphas(10) == "COIL:COOLING:WATERTOAIRHEATPUMP:PARAMETERESTIMATION") {
3841 0 : thisFurnace.WatertoAirHPType = WAHPCoilType::ParEst;
3842 0 : } else if (Alphas(8) == "COIL:HEATING:WATERTOAIRHEATPUMP:VARIABLESPEEDEQUATIONFIT" &&
3843 0 : Alphas(10) == "COIL:COOLING:WATERTOAIRHEATPUMP:VARIABLESPEEDEQUATIONFIT") {
3844 0 : thisFurnace.WatertoAirHPType = WAHPCoilType::VarSpeedEquationFit;
3845 0 : VariableSpeedCoils::SetVarSpeedCoilData(state, thisFurnace.CoolingCoilIndex, ErrorsFound, _, thisFurnace.HeatingCoilIndex);
3846 : } else {
3847 0 : ShowContinueError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
3848 0 : ShowContinueError(state, "Cooling coil and heating coil should be of same general type");
3849 0 : ErrorsFound = true;
3850 : }
3851 :
3852 : // Get supplemental heating coil information
3853 :
3854 0 : SuppHeatCoilType = Alphas(12);
3855 0 : SuppHeatCoilName = Alphas(13);
3856 0 : thisFurnace.SuppHeatCoilType = SuppHeatCoilType;
3857 0 : thisFurnace.SuppHeatCoilName = SuppHeatCoilName;
3858 0 : errFlag = false;
3859 0 : if (Util::SameString(SuppHeatCoilType, "Coil:Heating:Fuel") || Util::SameString(SuppHeatCoilType, "Coil:Heating:Electric")) {
3860 :
3861 0 : thisFurnace.SuppHeatCoilType_Num = HeatingCoils::GetHeatingCoilTypeNum(state, SuppHeatCoilType, SuppHeatCoilName, errFlag);
3862 0 : if (errFlag) {
3863 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3864 0 : ErrorsFound = true;
3865 : } else {
3866 0 : IsNotOK = false;
3867 0 : ValidateComponent(state, SuppHeatCoilType, SuppHeatCoilName, IsNotOK, CurrentModuleObject);
3868 0 : if (IsNotOK) {
3869 0 : ShowContinueError(state, format("In {} \"{}\"", CurrentModuleObject, Alphas(1)));
3870 0 : ErrorsFound = true;
3871 :
3872 : } else { // mine data from the supplemental heating coil
3873 :
3874 0 : HeatingCoils::GetCoilIndex(state, SuppHeatCoilName, thisFurnace.SuppHeatCoilIndex, IsNotOK);
3875 0 : if (IsNotOK) {
3876 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3877 0 : ErrorsFound = true;
3878 : }
3879 :
3880 : // Get the Supplemental Heating Coil Inlet Node Number
3881 0 : errFlag = false;
3882 0 : SupHeatCoilInletNode = HeatingCoils::GetCoilInletNode(state, SuppHeatCoilType, SuppHeatCoilName, errFlag);
3883 0 : if (errFlag) {
3884 0 : ShowContinueError(state, format("...occurs in {} \"{}\"", CurrentModuleObject, Alphas(1)));
3885 0 : ErrorsFound = true;
3886 : }
3887 :
3888 : // Get the Supplemental Heating Coil Outlet Node Number
3889 0 : errFlag = false;
3890 0 : SupHeatCoilOutletNode = HeatingCoils::GetCoilOutletNode(state, SuppHeatCoilType, SuppHeatCoilName, errFlag);
3891 0 : if (errFlag) {
3892 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3893 0 : ErrorsFound = true;
3894 : }
3895 :
3896 : // Get the supplemental heating coil design capacity
3897 0 : errFlag = false;
3898 0 : thisFurnace.DesignSuppHeatingCapacity = HeatingCoils::GetCoilCapacity(state, SuppHeatCoilType, SuppHeatCoilName, errFlag);
3899 0 : if (errFlag) {
3900 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3901 0 : ErrorsFound = true;
3902 : }
3903 :
3904 : } // IF (IsNotOK) THEN
3905 : }
3906 0 : } else if (Util::SameString(SuppHeatCoilType, "Coil:Heating:Water")) {
3907 0 : thisFurnace.SuppHeatCoilType_Num = HVAC::Coil_HeatingWater;
3908 0 : ValidateComponent(state, SuppHeatCoilType, SuppHeatCoilName, IsNotOK, CurrentModuleObject);
3909 0 : if (IsNotOK) {
3910 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3911 0 : ErrorsFound = true;
3912 : } else { // mine data from heating coil object
3913 :
3914 : // Get the Heating Coil water Inlet or control Node number
3915 0 : errFlag = false;
3916 0 : thisFurnace.SuppCoilControlNode = WaterCoils::GetCoilWaterInletNode(state, "Coil:Heating:Water", SuppHeatCoilName, errFlag);
3917 0 : if (errFlag) {
3918 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3919 0 : ErrorsFound = true;
3920 : }
3921 :
3922 : // Get the ReHeat Coil hot water max volume flow rate
3923 0 : errFlag = false;
3924 0 : thisFurnace.MaxSuppCoilFluidFlow = WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", SuppHeatCoilName, errFlag);
3925 0 : if (errFlag) {
3926 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3927 0 : ErrorsFound = true;
3928 : }
3929 :
3930 : // Get the ReHeat Coil Inlet Node
3931 0 : errFlag = false;
3932 0 : SupHeatCoilInletNode = WaterCoils::GetCoilInletNode(state, "Coil:Heating:Water", SuppHeatCoilName, errFlag);
3933 0 : thisFurnace.SuppCoilAirInletNode = SupHeatCoilInletNode;
3934 0 : if (errFlag) {
3935 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3936 0 : ErrorsFound = true;
3937 : }
3938 :
3939 : // Get the ReHeat Coil Outlet Node
3940 0 : errFlag = false;
3941 0 : SupHeatCoilOutletNode = WaterCoils::GetCoilOutletNode(state, "Coil:Heating:Water", SuppHeatCoilName, errFlag);
3942 0 : thisFurnace.SuppCoilAirOutletNode = SupHeatCoilOutletNode;
3943 0 : if (errFlag) {
3944 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3945 0 : ErrorsFound = true;
3946 : }
3947 :
3948 0 : errFlag = false;
3949 0 : HVACControllers::CheckCoilWaterInletNode(state, thisFurnace.CoilControlNode, errFlag);
3950 0 : if (!errFlag) { // then did find a controller so that is bad
3951 0 : ShowSevereError(state,
3952 0 : format("{} = {} has a conflicting Controller:WaterCoil object", CurrentModuleObject, thisFurnace.Name));
3953 0 : ShowContinueError(state, "Hot water coils are controlled directly by unitary and furnace systems.");
3954 0 : ShowContinueError(state, "No water coil controller should be input for the coil.");
3955 0 : ErrorsFound = true;
3956 : }
3957 : }
3958 :
3959 0 : } else if (Util::SameString(SuppHeatCoilType, "Coil:Heating:Steam")) {
3960 0 : thisFurnace.SuppHeatCoilType_Num = HVAC::Coil_HeatingSteam;
3961 0 : ValidateComponent(state, SuppHeatCoilType, SuppHeatCoilName, IsNotOK, CurrentModuleObject);
3962 0 : if (IsNotOK) {
3963 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3964 0 : ErrorsFound = true;
3965 : } else { // mine data from heating coil object
3966 :
3967 0 : errFlag = false;
3968 0 : thisFurnace.SuppHeatCoilIndex = SteamCoils::GetSteamCoilIndex(state, SuppHeatCoilType, SuppHeatCoilName, errFlag);
3969 0 : if (thisFurnace.SuppHeatCoilIndex == 0) {
3970 0 : ShowSevereError(state, format("{} illegal {} = {}", CurrentModuleObject, cAlphaFields(12), SuppHeatCoilName));
3971 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3972 0 : ErrorsFound = true;
3973 : }
3974 :
3975 : // Get the Heating Coil steam inlet node number
3976 0 : errFlag = false;
3977 0 : thisFurnace.SuppCoilControlNode = SteamCoils::GetCoilSteamInletNode(state, "Coil:Heating:Steam", SuppHeatCoilName, errFlag);
3978 0 : if (errFlag) {
3979 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3980 0 : ErrorsFound = true;
3981 : }
3982 :
3983 : // Get the Heating Coil steam max volume flow rate
3984 0 : thisFurnace.MaxSuppCoilFluidFlow = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.SuppHeatCoilIndex, errFlag);
3985 0 : if (thisFurnace.MaxSuppCoilFluidFlow > 0.0) {
3986 : SteamDensity =
3987 0 : Fluid::GetSteam(state)->getSatDensity(state, state.dataFurnaces->TempSteamIn, 1.0, getAirLoopHVACHeatCoolInput);
3988 0 : thisFurnace.MaxSuppCoilFluidFlow =
3989 0 : SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.SuppHeatCoilIndex, errFlag) * SteamDensity;
3990 : }
3991 :
3992 : // Get the Heating Coil Inlet Node
3993 0 : errFlag = false;
3994 0 : SupHeatCoilInletNode = SteamCoils::GetCoilAirInletNode(state, thisFurnace.SuppHeatCoilIndex, SuppHeatCoilName, errFlag);
3995 0 : thisFurnace.SuppCoilAirInletNode = SupHeatCoilInletNode;
3996 0 : if (errFlag) {
3997 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3998 0 : ErrorsFound = true;
3999 : }
4000 :
4001 : // Get the Heating Coil Outlet Node
4002 0 : errFlag = false;
4003 0 : SupHeatCoilOutletNode = SteamCoils::GetCoilAirOutletNode(state, thisFurnace.SuppHeatCoilIndex, SuppHeatCoilName, errFlag);
4004 0 : thisFurnace.SuppCoilAirOutletNode = SupHeatCoilOutletNode;
4005 0 : if (errFlag) {
4006 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
4007 0 : ErrorsFound = true;
4008 : }
4009 : }
4010 :
4011 : } else {
4012 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
4013 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(12), Alphas(12)));
4014 0 : ErrorsFound = true;
4015 : } // IF (Furnace(FurnaceNum)%HeatingCoilType_Num == Coil_HeatingGasOrOtherFuel .OR. &, etc.
4016 :
4017 0 : if (lAlphaBlanks(14)) {
4018 0 : thisFurnace.CondenserNodeNum = 0;
4019 : } else {
4020 0 : thisFurnace.CondenserNodeNum =
4021 0 : NodeInputManager::GetOnlySingleNode(state,
4022 0 : Alphas(14),
4023 : ErrorsFound,
4024 : DataLoopNode::ConnectionObjectType::AirLoopHVACUnitaryHeatPumpWaterToAir,
4025 0 : Alphas(1),
4026 : DataLoopNode::NodeFluidType::Air,
4027 : DataLoopNode::ConnectionType::OutsideAirReference,
4028 : NodeInputManager::CompFluidStream::Primary,
4029 : DataLoopNode::ObjectIsNotParent);
4030 : // need better verification.
4031 0 : if (!OutAirNodeManager::CheckOutAirNodeNumber(state, thisFurnace.CondenserNodeNum)) {
4032 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
4033 0 : ShowContinueError(state, format(" Node name of outdoor dry-bulb temperature sensor not valid outdoor air node= {}", Alphas(14)));
4034 0 : ShowContinueError(state, "...does not appear in an OutdoorAir:NodeList or as an OutdoorAir:Node.");
4035 0 : ErrorsFound = true;
4036 : }
4037 : }
4038 :
4039 0 : thisFurnace.fanPlace = static_cast<HVAC::FanPlace>(getEnumValue(HVAC::fanPlaceNamesUC, Alphas(15)));
4040 0 : assert(thisFurnace.fanPlace != HVAC::FanPlace::Invalid);
4041 :
4042 0 : if (lAlphaBlanks(16)) {
4043 0 : thisFurnace.fanOp = HVAC::FanOp::Cycling;
4044 0 : if (thisFurnace.fanType != HVAC::FanType::OnOff) {
4045 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisFurnace.Name));
4046 0 : ShowContinueError(state, format("{} = {}", cAlphaFields(6), Alphas(6)));
4047 0 : ShowContinueError(state, format("Fan type must be Fan:OnOff when {} = Blank.", cAlphaFields(16)));
4048 0 : ErrorsFound = true;
4049 : }
4050 0 : } else if ((thisFurnace.fanOpModeSched = Sched::GetSchedule(state, Alphas(16))) == nullptr) {
4051 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(16), Alphas(16));
4052 0 : ErrorsFound = true;
4053 : }
4054 :
4055 : // add the Dehumidification Type
4056 0 : if (Util::SameString(Alphas(17), "None") || Util::SameString(Alphas(17), "CoolReheat")) {
4057 0 : AirNodeFound = false;
4058 0 : if (Util::SameString(Alphas(17), "CoolReheat")) {
4059 0 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::CoolReheat;
4060 0 : thisFurnace.Humidistat = true;
4061 0 : if (lAlphaBlanks(17)) {
4062 0 : ShowWarningError(state, format("{} \"{}\"", CurrentModuleObject, Alphas(1)));
4063 0 : ShowContinueError(state,
4064 : "Dehumidification control type is assumed to be None since a supplemental reheat coil has not been "
4065 : "specified and the simulation continues.");
4066 0 : thisFurnace.Humidistat = false;
4067 0 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::None;
4068 : }
4069 : }
4070 0 : if (Util::SameString(Alphas(17), "None")) {
4071 0 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::None;
4072 0 : thisFurnace.Humidistat = false;
4073 : }
4074 0 : if (thisFurnace.Humidistat) {
4075 0 : for (HStatZoneNum = 1; HStatZoneNum <= state.dataZoneCtrls->NumHumidityControlZones; ++HStatZoneNum) {
4076 0 : if (state.dataZoneCtrls->HumidityControlZone(HStatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) {
4077 0 : continue;
4078 : }
4079 0 : AirNodeFound = true;
4080 : }
4081 0 : if (!AirNodeFound) {
4082 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
4083 0 : ShowContinueError(state, "Did not find Air Node (Zone with Humidistat).");
4084 0 : ShowContinueError(state, format("Specified {} = {}", cAlphaFields(5), Alphas(5)));
4085 0 : ErrorsFound = true;
4086 : }
4087 : }
4088 : } else { // invalid input or blank
4089 0 : if (!lAlphaBlanks(17)) {
4090 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
4091 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(17), Alphas(17)));
4092 0 : ErrorsFound = true;
4093 : } else {
4094 0 : thisFurnace.Humidistat = false;
4095 0 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::None;
4096 : }
4097 : }
4098 :
4099 : // Add fan to component sets array
4100 :
4101 0 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
4102 0 : CompSetFanInlet = Alphas(3);
4103 0 : CompSetCoolInlet = "UNDEFINED";
4104 0 : if (FanInletNode != thisFurnace.FurnaceInletNodeNum) {
4105 0 : ShowSevereError(
4106 0 : state, format("For {} = {}, Mismatch between unitary system inlet node and fan inlet node.", CurrentModuleObject, Alphas(1)));
4107 0 : ShowContinueError(state, "..For \"BlowThrough\" fan, the inlet node name for the HeatPump should match the fan inlet node name.");
4108 0 : ShowContinueError(state, format("..HeatPump Inlet Node = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
4109 0 : ShowContinueError(state, format("..Fan Inlet Node = {}", state.dataLoopNodes->NodeID(FanInletNode)));
4110 0 : ErrorsFound = true;
4111 : }
4112 0 : if (FanOutletNode != CoolingCoilInletNode) {
4113 0 : ShowSevereError(
4114 0 : state, format("For {} = {}, Mismatch between fan outlet node and cooling coil inlet node.", CurrentModuleObject, Alphas(1)));
4115 0 : ShowContinueError(state, "..For \"BlowThrough\" fan, the fan outlet node name must match the cooling coil inlet node name.");
4116 0 : ShowContinueError(state, format("..Fan outlet node = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
4117 0 : ShowContinueError(state, format("..Cooling coil inlet node = {}", state.dataLoopNodes->NodeID(CoolingCoilInletNode)));
4118 0 : ErrorsFound = true;
4119 : }
4120 0 : if (CoolingCoilOutletNode != HeatingCoilInletNode) {
4121 0 : ShowSevereError(state,
4122 0 : format("For {} = {}, Mismatch between cooling coil outlet node and heating coil inlet node.",
4123 : CurrentModuleObject,
4124 : Alphas(1)));
4125 0 : ShowContinueError(state, "..The cooling coil outlet node name must match the heating coil inlet node name.");
4126 0 : ShowContinueError(state, format("..Cooling coil outlet node = {}", state.dataLoopNodes->NodeID(CoolingCoilOutletNode)));
4127 0 : ShowContinueError(state, format("..Heating coil inlet node = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
4128 0 : ErrorsFound = true;
4129 : }
4130 0 : if (HeatingCoilOutletNode != SupHeatCoilInletNode) {
4131 0 : ShowSevereError(state,
4132 0 : format("For {} = {}, Mismatch between heating coil outlet node and supplemental heating coil inlet node.",
4133 : CurrentModuleObject,
4134 : Alphas(1)));
4135 0 : ShowContinueError(
4136 : state,
4137 : "..For \"BlowThrough\" fan, the heating coil outlet node name must match the supplemental heating coil inlet node name.");
4138 0 : ShowContinueError(state,
4139 0 : format("..Heating coil outlet node = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
4140 0 : ShowContinueError(state,
4141 0 : format("..Supplemental heating coil inlet node = {}", state.dataLoopNodes->NodeID(SupHeatCoilInletNode)));
4142 0 : ErrorsFound = true;
4143 : }
4144 0 : if (SupHeatCoilOutletNode != thisFurnace.FurnaceOutletNodeNum) {
4145 0 : ShowSevereError(state,
4146 0 : format("For {} = {}, Mismatch between supplemental heating coil outlet node and HeatPump outlet node.",
4147 : CurrentModuleObject,
4148 : Alphas(1)));
4149 0 : ShowContinueError(state, "..The supplemental heating coil outlet node name must match the HeatPump outlet node name.");
4150 0 : ShowContinueError(state,
4151 0 : format("..Supplemental heating coil outlet node = {}", state.dataLoopNodes->NodeID(SupHeatCoilOutletNode)));
4152 0 : ShowContinueError(
4153 0 : state, format("..HeatPump outlet node = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
4154 0 : ErrorsFound = true;
4155 : }
4156 : } else {
4157 0 : CompSetFanInlet = "UNDEFINED";
4158 0 : CompSetCoolInlet = Alphas(3);
4159 0 : if (CoolingCoilInletNode != thisFurnace.FurnaceInletNodeNum) {
4160 0 : ShowSevereError(state,
4161 0 : format("For {} = {}, Mismatch between unitary system inlet node and cooling coil inlet node.",
4162 : CurrentModuleObject,
4163 : Alphas(1)));
4164 0 : ShowContinueError(
4165 : state, "..For \"DrawThrough\" fan, the inlet node name for the HeatPump should match the cooling coil inlet node name.");
4166 0 : ShowContinueError(state, format("..HeatPump inlet node = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
4167 0 : ShowContinueError(state, format("..Cooling coil inlet node = {}", state.dataLoopNodes->NodeID(CoolingCoilInletNode)));
4168 0 : ErrorsFound = true;
4169 : }
4170 0 : if (CoolingCoilOutletNode != HeatingCoilInletNode) {
4171 0 : ShowSevereError(state,
4172 0 : format("For {} = {}, Mismatch between cooling coil outlet node and heating coil inlet node.",
4173 : CurrentModuleObject,
4174 : Alphas(1)));
4175 0 : ShowContinueError(state, "..The outlet node name for the cooling coil should match the heating coil inlet node name.");
4176 0 : ShowContinueError(state, format("..Cooling coil outlet node = {}", state.dataLoopNodes->NodeID(CoolingCoilOutletNode)));
4177 0 : ShowContinueError(state, format("..Heating coil inlet node = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
4178 0 : ErrorsFound = true;
4179 : }
4180 0 : if (HeatingCoilOutletNode != FanInletNode) {
4181 0 : ShowSevereError(
4182 0 : state, format("For {} = {}, Mismatch between heating coil outlet node and fan inlet node.", CurrentModuleObject, Alphas(1)));
4183 0 : ShowContinueError(state,
4184 : "..For \"DrawThrough\" fan, the outlet node name for the heating coil should match the fan inlet node name.");
4185 0 : ShowContinueError(state, format("..Heating coil outlet node = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
4186 0 : ShowContinueError(state, format("..Fan inlet node = {}", state.dataLoopNodes->NodeID(FanInletNode)));
4187 0 : ErrorsFound = true;
4188 : }
4189 0 : if (FanOutletNode != SupHeatCoilInletNode) {
4190 0 : ShowSevereError(state,
4191 0 : format("For {} = {}, Mismatch between fan outlet node and supplemental heating coil inlet node.",
4192 : CurrentModuleObject,
4193 : Alphas(1)));
4194 0 : ShowContinueError(
4195 : state,
4196 : "..For \"DrawThrough\" fan, the outlet node name for the fan should match the supplemental heating coil inlet node name.");
4197 0 : ShowContinueError(state, format("..Fan outlet node = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
4198 0 : ShowContinueError(state,
4199 0 : format("..Supplemental heating coil inlet node = {}", state.dataLoopNodes->NodeID(SupHeatCoilInletNode)));
4200 0 : ErrorsFound = true;
4201 : }
4202 0 : if (SupHeatCoilOutletNode != thisFurnace.FurnaceOutletNodeNum) {
4203 0 : ShowSevereError(state,
4204 0 : format("For {} = {}, Mismatch between supplemental heating coil outlet node and HeatPump outlet node.",
4205 : CurrentModuleObject,
4206 : Alphas(1)));
4207 0 : ShowContinueError(state, "..The supplemental heating coil outlet node name must match the HeatPump outlet node name.");
4208 0 : ShowContinueError(state,
4209 0 : format("..Supplemental heating coil outlet node = {}", state.dataLoopNodes->NodeID(SupHeatCoilOutletNode)));
4210 0 : ShowContinueError(
4211 0 : state, format("..HeatPump outlet node = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
4212 0 : ErrorsFound = true;
4213 : }
4214 : }
4215 : // (Set up validation here for the fan or cooling coil inlet?)
4216 0 : BranchNodeConnections::SetUpCompSets(state, CurrentModuleObject, Alphas(1), Alphas(6), Alphas(7), CompSetFanInlet, "UNDEFINED");
4217 :
4218 : // Add DX heating coil to component sets array
4219 0 : BranchNodeConnections::SetUpCompSets(state, CurrentModuleObject, Alphas(1), Alphas(8), Alphas(9), "UNDEFINED", "UNDEFINED");
4220 :
4221 : // Add DX cooling coil to component sets array
4222 0 : BranchNodeConnections::SetUpCompSets(state, CurrentModuleObject, Alphas(1), Alphas(10), Alphas(11), CompSetCoolInlet, "UNDEFINED");
4223 :
4224 : // Add supplemental heating coil to component sets array
4225 0 : BranchNodeConnections::SetUpCompSets(state, CurrentModuleObject, Alphas(1), Alphas(12), Alphas(13), "UNDEFINED", Alphas(4));
4226 :
4227 : // Set the Design Fan Volume Flow Rate
4228 0 : thisFurnace.ActualFanVolFlowRate = state.dataFans->fans(thisFurnace.FanIndex)->maxAirFlowRate;
4229 :
4230 : // CR8094 - simple water to air heat pump MUST operate at the same flow rate specified in the coil objects
4231 : // Furnace(FurnaceNum)%DesignFanVolFlowRate = Numbers(1)
4232 : // Furnace(FurnaceNum)%MaxHeatAirVolFlow = Furnace(FurnaceNum)%DesignFanVolFlowRate
4233 : // Furnace(FurnaceNum)%MaxCoolAirVolFlow = Furnace(FurnaceNum)%DesignFanVolFlowRate
4234 :
4235 : // parameter estimate model only specifies air flow rate in parent object
4236 0 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHP) {
4237 0 : thisFurnace.MaxHeatAirVolFlow = Numbers(1);
4238 0 : thisFurnace.MaxCoolAirVolFlow = Numbers(1);
4239 : // simple HP model specifies air flow rate in both the parent and child coils. Use coil air flow rates.
4240 : // simple HP model air flow rate input will not be used.
4241 0 : } else if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPSimple) {
4242 0 : errFlag = false;
4243 0 : thisFurnace.MaxHeatAirVolFlow = WaterToAirHeatPumpSimple::GetCoilAirFlowRate(state, HeatingCoilType, HeatingCoilName, errFlag);
4244 0 : thisFurnace.MaxCoolAirVolFlow = WaterToAirHeatPumpSimple::GetCoilAirFlowRate(state, CoolingCoilType, CoolingCoilName, errFlag);
4245 0 : if (errFlag) {
4246 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
4247 0 : ErrorsFound = true;
4248 : }
4249 0 : } else if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPVSEquationFit) {
4250 0 : errFlag = false;
4251 0 : thisFurnace.MaxHeatAirVolFlow = VariableSpeedCoils::GetCoilAirFlowRateVariableSpeed(state, HeatingCoilType, HeatingCoilName, errFlag);
4252 0 : thisFurnace.MaxCoolAirVolFlow = VariableSpeedCoils::GetCoilAirFlowRateVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
4253 0 : if (errFlag) {
4254 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
4255 0 : ErrorsFound = true;
4256 : }
4257 : }
4258 :
4259 0 : thisFurnace.MaxNoCoolHeatAirVolFlow = min(thisFurnace.MaxHeatAirVolFlow, thisFurnace.MaxCoolAirVolFlow);
4260 0 : if (thisFurnace.MaxHeatAirVolFlow != DataSizing::AutoSize && thisFurnace.MaxCoolAirVolFlow != DataSizing::AutoSize) {
4261 0 : thisFurnace.DesignFanVolFlowRate = max(thisFurnace.MaxHeatAirVolFlow, thisFurnace.MaxCoolAirVolFlow);
4262 : } else {
4263 0 : thisFurnace.DesignFanVolFlowRate = DataSizing::AutoSize;
4264 : }
4265 :
4266 0 : thisFurnace.AirFlowControl = AirFlowControlConstFan::UseCompressorOnFlow;
4267 :
4268 0 : if (thisFurnace.ActualFanVolFlowRate != DataSizing::AutoSize && thisFurnace.DesignFanVolFlowRate != DataSizing::AutoSize) {
4269 0 : if (thisFurnace.DesignFanVolFlowRate > thisFurnace.ActualFanVolFlowRate) {
4270 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
4271 0 : ShowContinueError(state, "... has a Cooling or Heating Air Flow Rate > Max Fan Volume Flow Rate, should be <=.");
4272 0 : ShowContinueError(state,
4273 0 : format("... Entered value={:.2R}... Fan [{}:{}] Max Value={:.2R}",
4274 0 : thisFurnace.DesignFanVolFlowRate,
4275 0 : HVAC::fanTypeNames[(int)thisFurnace.fanType],
4276 : FanName,
4277 0 : thisFurnace.ActualFanVolFlowRate));
4278 : }
4279 : }
4280 0 : if (thisFurnace.ActualFanVolFlowRate != DataSizing::AutoSize && thisFurnace.DesignFanVolFlowRate != DataSizing::AutoSize) {
4281 0 : if (thisFurnace.DesignFanVolFlowRate <= 0.0) {
4282 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
4283 0 : ShowContinueError(state, "... has a Design Fan Flow Rate <= 0.0, it must be >0.0");
4284 0 : ShowContinueError(state, format("... Entered value={:.2R}", thisFurnace.DesignFanVolFlowRate));
4285 0 : ErrorsFound = true;
4286 : }
4287 : }
4288 :
4289 : // Set the heat pump heating coil capacity
4290 : // Get from coil module.
4291 0 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHP) {
4292 0 : errFlag = false;
4293 0 : thisFurnace.DesignHeatingCapacity = WaterToAirHeatPump::GetCoilCapacity(state, HeatingCoilType, HeatingCoilName, errFlag);
4294 0 : if (errFlag) {
4295 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
4296 0 : ErrorsFound = true;
4297 : }
4298 0 : } else if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPSimple) {
4299 0 : errFlag = false;
4300 0 : thisFurnace.DesignHeatingCapacity = WaterToAirHeatPumpSimple::GetCoilCapacity(state, HeatingCoilType, HeatingCoilName, errFlag);
4301 0 : if (errFlag) {
4302 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
4303 0 : ErrorsFound = true;
4304 : }
4305 0 : } else if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPVSEquationFit) {
4306 0 : errFlag = false;
4307 0 : thisFurnace.DesignHeatingCapacity =
4308 0 : VariableSpeedCoils::GetCoilCapacityVariableSpeed(state, HeatingCoilType, HeatingCoilName, errFlag);
4309 0 : if (errFlag) {
4310 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
4311 0 : ErrorsFound = true;
4312 : }
4313 : }
4314 : // Set the heat pump heating coil convergence
4315 0 : thisFurnace.HeatingConvergenceTolerance = Numbers(2);
4316 : // Set the heat pump cooling coil capacity (Total capacity)
4317 : // Get from coil module.
4318 0 : if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingWaterToAirHP) {
4319 0 : errFlag = false;
4320 0 : thisFurnace.DesignCoolingCapacity = WaterToAirHeatPump::GetCoilCapacity(state, CoolingCoilType, CoolingCoilName, errFlag);
4321 0 : if (errFlag) {
4322 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
4323 0 : ErrorsFound = true;
4324 : }
4325 0 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingWaterToAirHPSimple) {
4326 0 : errFlag = false;
4327 0 : thisFurnace.DesignCoolingCapacity = WaterToAirHeatPumpSimple::GetCoilCapacity(state, CoolingCoilType, CoolingCoilName, errFlag);
4328 0 : if (errFlag) {
4329 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
4330 0 : ErrorsFound = true;
4331 : }
4332 0 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingWaterToAirHPVSEquationFit) {
4333 0 : errFlag = false;
4334 0 : thisFurnace.DesignCoolingCapacity =
4335 0 : VariableSpeedCoils::GetCoilCapacityVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
4336 0 : if (errFlag) {
4337 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
4338 0 : ErrorsFound = true;
4339 : }
4340 : }
4341 : // Set the heat pump cooling coil convergence
4342 0 : thisFurnace.CoolingConvergenceTolerance = Numbers(3);
4343 :
4344 : // Set the heatpump design supplemental heating capacity
4345 : // Get from coil module.
4346 :
4347 : // Set the heatpump max outlet temperature
4348 0 : thisFurnace.DesignMaxOutletTemp = Numbers(4);
4349 :
4350 : // Set maximum supply air temperature for supplemental heating coil
4351 0 : thisFurnace.MaxOATSuppHeat = Numbers(5);
4352 0 : OutputReportPredefined::PreDefTableEntry(
4353 0 : state, state.dataOutRptPredefined->pdchDXHeatCoilSuppHiT, HeatingCoilName, thisFurnace.MaxOATSuppHeat);
4354 :
4355 : // set minimum outdoor temperature for compressor operation
4356 0 : SetMinOATCompressor(state, FurnaceNum, cCurrentModuleObject, ErrorsFound);
4357 :
4358 : } // End of the Unitary System WaterToAirHeatPump Loop
4359 :
4360 2 : Alphas.deallocate();
4361 2 : Numbers.deallocate();
4362 :
4363 2 : if (ErrorsFound) {
4364 0 : ShowFatalError(state, "Errors found in getting Furnace or Unitary System input.");
4365 : }
4366 :
4367 2 : for (int HeatOnlyNum = 1; HeatOnlyNum <= NumHeatOnly; ++HeatOnlyNum) {
4368 0 : FurnaceNum = HeatOnlyNum;
4369 0 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
4370 : // Setup Report variables for the Furnace that are not reported in the components themselves
4371 0 : SetupOutputVariable(state,
4372 : "Unitary System Fan Part Load Ratio",
4373 : Constant::Units::None,
4374 0 : thisFurnace.FanPartLoadRatio,
4375 : OutputProcessor::TimeStepType::System,
4376 : OutputProcessor::StoreType::Average,
4377 0 : thisFurnace.Name);
4378 0 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
4379 0 : SetupEMSActuator(state,
4380 : "AirLoopHVAC:Unitary:Furnace:HeatOnly",
4381 : thisFurnace.Name,
4382 : "Autosized Supply Air Flow Rate",
4383 : "[m3/s]",
4384 0 : thisFurnace.DesignFanVolFlowRateEMSOverrideOn,
4385 0 : thisFurnace.DesignFanVolFlowRateEMSOverrideValue);
4386 : }
4387 : }
4388 :
4389 2 : for (int UnitaryHeatOnlyNum = NumHeatOnly + 1; UnitaryHeatOnlyNum <= NumHeatOnly + NumUnitaryHeatOnly; ++UnitaryHeatOnlyNum) {
4390 0 : FurnaceNum = UnitaryHeatOnlyNum;
4391 0 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
4392 : // Setup Report variables for Unitary System that are not reported in the components themselves
4393 0 : SetupOutputVariable(state,
4394 : "Unitary System Fan Part Load Ratio",
4395 : Constant::Units::None,
4396 0 : thisFurnace.FanPartLoadRatio,
4397 : OutputProcessor::TimeStepType::System,
4398 : OutputProcessor::StoreType::Average,
4399 0 : thisFurnace.Name);
4400 0 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
4401 0 : SetupEMSActuator(state,
4402 : "AirLoopHVAC:UnitaryHeatOnly",
4403 : thisFurnace.Name,
4404 : "Autosized Supply Air Flow Rate",
4405 : "[m3/s]",
4406 0 : thisFurnace.DesignFanVolFlowRateEMSOverrideOn,
4407 0 : thisFurnace.DesignFanVolFlowRateEMSOverrideValue);
4408 : }
4409 : }
4410 :
4411 2 : for (int HeatCoolNum = NumHeatOnly + NumUnitaryHeatOnly + 1; HeatCoolNum <= NumHeatOnly + NumUnitaryHeatOnly + NumHeatCool; ++HeatCoolNum) {
4412 0 : FurnaceNum = HeatCoolNum;
4413 0 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
4414 : // Setup Report variables for the Furnace that are not reported in the components themselves
4415 0 : SetupOutputVariable(state,
4416 : "Unitary System Fan Part Load Ratio",
4417 : Constant::Units::None,
4418 0 : thisFurnace.FanPartLoadRatio,
4419 : OutputProcessor::TimeStepType::System,
4420 : OutputProcessor::StoreType::Average,
4421 0 : thisFurnace.Name);
4422 0 : SetupOutputVariable(state,
4423 : "Unitary System Compressor Part Load Ratio",
4424 : Constant::Units::None,
4425 0 : thisFurnace.CompPartLoadRatio,
4426 : OutputProcessor::TimeStepType::System,
4427 : OutputProcessor::StoreType::Average,
4428 0 : thisFurnace.Name);
4429 :
4430 0 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
4431 0 : SetupEMSActuator(state,
4432 : "AirLoopHVAC:Unitary:Furnace:HeatCool",
4433 : thisFurnace.Name,
4434 : "Autosized Supply Air Flow Rate",
4435 : "[m3/s]",
4436 0 : thisFurnace.DesignFanVolFlowRateEMSOverrideOn,
4437 0 : thisFurnace.DesignFanVolFlowRateEMSOverrideValue);
4438 0 : SetupEMSActuator(state,
4439 : "AirLoopHVAC:Unitary:Furnace:HeatCool",
4440 : thisFurnace.Name,
4441 : "Autosized Supply Air Flow Rate During Cooling Operation",
4442 : "[m3/s]",
4443 0 : thisFurnace.MaxCoolAirVolFlowEMSOverrideOn,
4444 0 : thisFurnace.MaxCoolAirVolFlowEMSOverrideValue);
4445 0 : SetupEMSActuator(state,
4446 : "AirLoopHVAC:Unitary:Furnace:HeatCool",
4447 : thisFurnace.Name,
4448 : "Autosized Supply Air Flow Rate During Heating Operation",
4449 : "[m3/s]",
4450 0 : thisFurnace.MaxHeatAirVolFlowEMSOverrideOn,
4451 0 : thisFurnace.MaxHeatAirVolFlowEMSOverrideValue);
4452 0 : SetupEMSActuator(state,
4453 : "AirLoopHVAC:Unitary:Furnace:HeatCool",
4454 : thisFurnace.Name,
4455 : "Autosized Supply Air Flow Rate During No Heating or Cooling Operation",
4456 : "[m3/s]",
4457 0 : thisFurnace.MaxNoCoolHeatAirVolFlowEMSOverrideOn,
4458 0 : thisFurnace.MaxNoCoolHeatAirVolFlowEMSOverrideValue);
4459 : }
4460 : }
4461 :
4462 2 : for (int UnitaryHeatCoolNum = NumHeatOnly + NumHeatCool + NumUnitaryHeatOnly + 1;
4463 2 : UnitaryHeatCoolNum <= NumHeatOnly + NumHeatCool + NumUnitaryHeatOnly + NumUnitaryHeatCool;
4464 : ++UnitaryHeatCoolNum) {
4465 0 : FurnaceNum = UnitaryHeatCoolNum;
4466 0 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
4467 : // Setup Report variables for Unitary System that are not reported in the components themselves
4468 0 : SetupOutputVariable(state,
4469 : "Unitary System Fan Part Load Ratio",
4470 : Constant::Units::None,
4471 0 : thisFurnace.FanPartLoadRatio,
4472 : OutputProcessor::TimeStepType::System,
4473 : OutputProcessor::StoreType::Average,
4474 0 : thisFurnace.Name);
4475 0 : SetupOutputVariable(state,
4476 : "Unitary System Compressor Part Load Ratio",
4477 : Constant::Units::None,
4478 0 : thisFurnace.CompPartLoadRatio,
4479 : OutputProcessor::TimeStepType::System,
4480 : OutputProcessor::StoreType::Average,
4481 0 : thisFurnace.Name);
4482 0 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
4483 0 : SetupEMSActuator(state,
4484 : "AirLoopHVAC:UnitaryHeatCool",
4485 : thisFurnace.Name,
4486 : "Autosized Supply Air Flow Rate",
4487 : "[m3/s]",
4488 0 : thisFurnace.DesignFanVolFlowRateEMSOverrideOn,
4489 0 : thisFurnace.DesignFanVolFlowRateEMSOverrideValue);
4490 0 : SetupEMSActuator(state,
4491 : "AirLoopHVAC:UnitaryHeatCool",
4492 : thisFurnace.Name,
4493 : "Autosized Supply Air Flow Rate During Cooling Operation",
4494 : "[m3/s]",
4495 0 : thisFurnace.MaxCoolAirVolFlowEMSOverrideOn,
4496 0 : thisFurnace.MaxCoolAirVolFlowEMSOverrideValue);
4497 0 : SetupEMSActuator(state,
4498 : "AirLoopHVAC:UnitaryHeatCool",
4499 : thisFurnace.Name,
4500 : "Autosized Supply Air Flow Rate During Heating Operation",
4501 : "[m3/s]",
4502 0 : thisFurnace.MaxHeatAirVolFlowEMSOverrideOn,
4503 0 : thisFurnace.MaxHeatAirVolFlowEMSOverrideValue);
4504 0 : SetupEMSActuator(state,
4505 : "AirLoopHVAC:UnitaryHeatCool",
4506 : thisFurnace.Name,
4507 : "Autosized Supply Air Flow Rate During No Heating or Cooling Operation",
4508 : "[m3/s]",
4509 0 : thisFurnace.MaxNoCoolHeatAirVolFlowEMSOverrideOn,
4510 0 : thisFurnace.MaxNoCoolHeatAirVolFlowEMSOverrideValue);
4511 : }
4512 : }
4513 :
4514 4 : for (int HeatPumpNum = NumHeatOnly + NumHeatCool + NumUnitaryHeatOnly + NumUnitaryHeatCool + 1;
4515 4 : HeatPumpNum <= state.dataFurnaces->NumFurnaces - NumWaterToAirHeatPump;
4516 : ++HeatPumpNum) {
4517 2 : FurnaceNum = HeatPumpNum;
4518 2 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
4519 : // Setup Report variables for Unitary System that are not reported in the components themselves
4520 4 : SetupOutputVariable(state,
4521 : "Unitary System Fan Part Load Ratio",
4522 : Constant::Units::None,
4523 2 : thisFurnace.FanPartLoadRatio,
4524 : OutputProcessor::TimeStepType::System,
4525 : OutputProcessor::StoreType::Average,
4526 2 : thisFurnace.Name);
4527 4 : SetupOutputVariable(state,
4528 : "Unitary System Compressor Part Load Ratio",
4529 : Constant::Units::None,
4530 2 : thisFurnace.CompPartLoadRatio,
4531 : OutputProcessor::TimeStepType::System,
4532 : OutputProcessor::StoreType::Average,
4533 2 : thisFurnace.Name);
4534 4 : SetupOutputVariable(state,
4535 : "Unitary System Dehumidification Induced Heating Demand Rate",
4536 : Constant::Units::W,
4537 2 : thisFurnace.DehumidInducedHeatingDemandRate,
4538 : OutputProcessor::TimeStepType::System,
4539 : OutputProcessor::StoreType::Average,
4540 2 : thisFurnace.Name);
4541 :
4542 2 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
4543 0 : SetupEMSActuator(state,
4544 : "AirLoopHVAC:UnitaryHeatPump:AirToAir",
4545 : thisFurnace.Name,
4546 : "Autosized Supply Air Flow Rate",
4547 : "[m3/s]",
4548 0 : thisFurnace.DesignFanVolFlowRateEMSOverrideOn,
4549 0 : thisFurnace.DesignFanVolFlowRateEMSOverrideValue);
4550 : }
4551 : }
4552 :
4553 2 : for (int HeatPumpNum = NumHeatOnly + NumHeatCool + NumUnitaryHeatOnly + NumUnitaryHeatCool + NumHeatPump + 1;
4554 2 : HeatPumpNum <= state.dataFurnaces->NumFurnaces;
4555 : ++HeatPumpNum) {
4556 0 : FurnaceNum = HeatPumpNum;
4557 0 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
4558 : // Setup Report variables for Unitary System that are not reported in the components themselves
4559 0 : SetupOutputVariable(state,
4560 : "Unitary System Fan Part Load Ratio",
4561 : Constant::Units::None,
4562 0 : thisFurnace.FanPartLoadRatio,
4563 : OutputProcessor::TimeStepType::System,
4564 : OutputProcessor::StoreType::Average,
4565 0 : thisFurnace.Name);
4566 0 : SetupOutputVariable(state,
4567 : "Unitary System Compressor Part Load Ratio",
4568 : Constant::Units::None,
4569 0 : thisFurnace.CompPartLoadRatio,
4570 : OutputProcessor::TimeStepType::System,
4571 : OutputProcessor::StoreType::Average,
4572 0 : thisFurnace.Name);
4573 0 : SetupOutputVariable(state,
4574 : "Unitary System Requested Sensible Cooling Rate",
4575 : Constant::Units::W,
4576 0 : thisFurnace.CoolingCoilSensDemand,
4577 : OutputProcessor::TimeStepType::System,
4578 : OutputProcessor::StoreType::Average,
4579 0 : thisFurnace.Name);
4580 0 : SetupOutputVariable(state,
4581 : "Unitary System Requested Latent Cooling Rate",
4582 : Constant::Units::W,
4583 0 : thisFurnace.CoolingCoilLatentDemand,
4584 : OutputProcessor::TimeStepType::System,
4585 : OutputProcessor::StoreType::Average,
4586 0 : thisFurnace.Name);
4587 0 : SetupOutputVariable(state,
4588 : "Unitary System Requested Heating Rate",
4589 : Constant::Units::W,
4590 0 : thisFurnace.HeatingCoilSensDemand,
4591 : OutputProcessor::TimeStepType::System,
4592 : OutputProcessor::StoreType::Average,
4593 0 : thisFurnace.Name);
4594 0 : SetupOutputVariable(state,
4595 : "Unitary System Dehumidification Induced Heating Demand Rate",
4596 : Constant::Units::W,
4597 0 : thisFurnace.DehumidInducedHeatingDemandRate,
4598 : OutputProcessor::TimeStepType::System,
4599 : OutputProcessor::StoreType::Average,
4600 0 : thisFurnace.Name);
4601 :
4602 0 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
4603 0 : SetupEMSActuator(state,
4604 : "AirLoopHVAC:UnitaryHeatPump:WaterToAir",
4605 : thisFurnace.Name,
4606 : "Autosized Supply Air Flow Rate",
4607 : "[m3/s]",
4608 0 : thisFurnace.DesignFanVolFlowRateEMSOverrideOn,
4609 0 : thisFurnace.DesignFanVolFlowRateEMSOverrideValue);
4610 : }
4611 : }
4612 :
4613 2 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
4614 0 : for (FurnaceNum = 1; FurnaceNum <= state.dataFurnaces->NumFurnaces; ++FurnaceNum) {
4615 0 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
4616 0 : SetupEMSInternalVariable(state, "Unitary HVAC Design Heating Capacity", thisFurnace.Name, "[W]", thisFurnace.DesignHeatingCapacity);
4617 0 : SetupEMSInternalVariable(state, "Unitary HVAC Design Cooling Capacity", thisFurnace.Name, "[W]", thisFurnace.DesignCoolingCapacity);
4618 0 : SetupEMSActuator(state,
4619 : "Unitary HVAC",
4620 : thisFurnace.Name,
4621 : "Sensible Load Request",
4622 : "[W]",
4623 0 : thisFurnace.EMSOverrideSensZoneLoadRequest,
4624 0 : thisFurnace.EMSSensibleZoneLoadValue);
4625 0 : SetupEMSActuator(state,
4626 : "Unitary HVAC",
4627 : thisFurnace.Name,
4628 : "Moisture Load Request",
4629 : "[W]",
4630 0 : thisFurnace.EMSOverrideMoistZoneLoadRequest,
4631 0 : thisFurnace.EMSMoistureZoneLoadValue);
4632 : }
4633 : }
4634 : bool anyRan;
4635 2 : EMSManager::ManageEMS(state, EMSManager::EMSCallFrom::ComponentGetInput, anyRan, ObjexxFCL::Optional_int_const());
4636 2 : }
4637 :
4638 : // End of Get Input subroutines for this Module
4639 : //******************************************************************************
4640 :
4641 : // Beginning Initialization Section of the Module
4642 : //******************************************************************************
4643 :
4644 15222 : void InitFurnace(EnergyPlusData &state,
4645 : int const FurnaceNum, // index to Furnace
4646 : int const AirLoopNum, // index to air loop
4647 : Real64 &OnOffAirFlowRatio, // ratio of on to off air mass flow rate
4648 : HVAC::FanOp &fanOp, // fan operating mode
4649 : Real64 &ZoneLoad, // zone sensible load to be met (modified here as needed) (W)
4650 : Real64 &MoistureLoad, // zone moisture load (W)
4651 : bool const FirstHVACIteration // TRUE if first HVAC iteration
4652 : )
4653 : {
4654 :
4655 : // SUBROUTINE INFORMATION:
4656 : // AUTHOR Richard J. Liesen
4657 : // DATE WRITTEN Feb 2001
4658 : // MODIFIED Oct 2001, Richard Raustad
4659 : // Sep 2008, R. Raustad - revised logic to determine load to be met
4660 : // Bereket Nigusse, June 2010 - added a procedure to calculate supply air flow fraction
4661 : // through controlled zone
4662 : // Bo Shen, March 2012 - for VS WSHP
4663 : // Bo Shen, ORNL, July 2012 - added variable-speed air source heat pump cooling and heating coils, using curve-fits
4664 :
4665 : // PURPOSE OF THIS SUBROUTINE:
4666 : // This subroutine is for initializations of the Furnace Components.
4667 :
4668 : // METHODOLOGY EMPLOYED:
4669 : // Uses the status flags to trigger initializations.
4670 : // The HeatCool furnace/unitarysystem and air-to-air heat pump may have alternate air flow rates
4671 : // in cooling, heating, and when no cooling or heating is needed. Set up the coil (comp) ON and OFF
4672 : // air flow rates during InitFurnace. Use these flow rates during the Calc routines to set the
4673 : // average mass flow rates based on PLR.
4674 :
4675 : // SUBROUTINE PARAMETER DEFINITIONS:
4676 15222 : Real64 constexpr Small5WLoad(5.0);
4677 15222 : std::string_view constexpr RoutineName("InitFurnace");
4678 :
4679 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4680 : bool errFlag; // error flag for mining functions
4681 : Real64 QZnReq; // furnace load based on control zone frac (W)
4682 : Real64 PartLoadRatio; // furnace part-load ratio
4683 : Real64 SensibleOutput; // no load sensible output (coils off) (W)
4684 : Real64 LatentOutput; // no load latent output (coils off) (W)
4685 : Real64 QToCoolSetPt; // sensible load to cooling setpoint (W)
4686 : Real64 QToHeatSetPt; // sensible load to heating setpoint (W)
4687 : // calculation (kg/kg)
4688 : Real64 DeltaMassRate; // Difference of mass flow rate between
4689 : // inlet node and system outlet node
4690 : Real64 MassFlowRate; // mass flow rate to calculate loss
4691 :
4692 15222 : Real64 SumOfMassFlowRateMax(0.0); // the sum of mass flow rates at inlet to zones in an airloop
4693 15222 : Real64 CntrlZoneTerminalUnitMassFlowRateMax(0.0); // Maximum mass flow rate through controlled zone terminal unit
4694 :
4695 15222 : bool ErrorsFound(false); // flag returned from mining call
4696 15222 : Real64 mdot(0.0); // local temporary for mass flow rate (kg/s)
4697 15222 : Real64 rho(0.0); // local for fluid density
4698 15222 : Real64 SteamDensity(0.0); // density of steam at 100C, used for steam heating coils
4699 15222 : Real64 CoilMaxVolFlowRate(0.0); // coil fluid maximum volume flow rate
4700 15222 : Real64 QActual(0.0); // coil actual capacity
4701 15222 : Real64 SUPHEATERLOAD(0.0); // SUPPLEMENTAL HEATER LOAD
4702 : Real64 RhoAir; // Air density at InNode
4703 : Furnaces::ModeOfOperation OperatingMode; // track cooling, heating, and no cooling or heating modes
4704 : Furnaces::ModeOfOperation OperatingModeMinusOne;
4705 : Furnaces::ModeOfOperation OperatingModeMinusTwo;
4706 : bool Oscillate; // detection of oscillating operating modes
4707 :
4708 15222 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
4709 15222 : int InNode = thisFurnace.FurnaceInletNodeNum;
4710 15222 : int OutNode = thisFurnace.FurnaceOutletNodeNum;
4711 :
4712 15222 : if (state.dataFurnaces->InitFurnaceMyOneTimeFlag) {
4713 : // initialize the environment and sizing flags
4714 2 : state.dataFurnaces->MyEnvrnFlag.allocate(state.dataFurnaces->NumFurnaces);
4715 2 : state.dataFurnaces->MySizeFlag.allocate(state.dataFurnaces->NumFurnaces);
4716 2 : state.dataFurnaces->MySecondOneTimeFlag.allocate(state.dataFurnaces->NumFurnaces);
4717 2 : state.dataFurnaces->MyFanFlag.allocate(state.dataFurnaces->NumFurnaces);
4718 2 : state.dataFurnaces->MyCheckFlag.allocate(state.dataFurnaces->NumFurnaces);
4719 2 : state.dataFurnaces->MyFlowFracFlag.allocate(state.dataFurnaces->NumFurnaces);
4720 2 : state.dataFurnaces->MyPlantScanFlag.allocate(state.dataFurnaces->NumFurnaces);
4721 2 : state.dataFurnaces->MySuppCoilPlantScanFlag.allocate(state.dataFurnaces->NumFurnaces);
4722 2 : state.dataFurnaces->MyEnvrnFlag = true;
4723 2 : state.dataFurnaces->MySizeFlag = true;
4724 2 : state.dataFurnaces->MySecondOneTimeFlag = true;
4725 2 : state.dataFurnaces->MyFanFlag = true;
4726 2 : state.dataFurnaces->MyCheckFlag = true;
4727 2 : state.dataFurnaces->MyFlowFracFlag = true;
4728 2 : state.dataFurnaces->InitFurnaceMyOneTimeFlag = false;
4729 2 : state.dataFurnaces->MyPlantScanFlag = true;
4730 2 : state.dataFurnaces->MySuppCoilPlantScanFlag = true;
4731 : }
4732 :
4733 15222 : if (state.dataGlobal->BeginEnvrnFlag && state.dataFurnaces->MyAirLoopPass) {
4734 6 : state.dataFurnaces->AirLoopPass = 0;
4735 6 : state.dataFurnaces->MyAirLoopPass = false;
4736 : }
4737 15222 : if (!state.dataGlobal->BeginEnvrnFlag) {
4738 15136 : state.dataFurnaces->MyAirLoopPass = true;
4739 : }
4740 :
4741 15222 : ++state.dataFurnaces->AirLoopPass;
4742 15222 : if (state.dataFurnaces->AirLoopPass > 2) {
4743 7605 : state.dataFurnaces->AirLoopPass = 1;
4744 : }
4745 :
4746 15222 : if (!state.dataGlobal->SysSizingCalc && state.dataFurnaces->MySizeFlag(FurnaceNum)) {
4747 : // for each furnace, do the sizing once.
4748 2 : SizeFurnace(state, FurnaceNum, FirstHVACIteration);
4749 2 : thisFurnace.ControlZoneMassFlowFrac = 1.0;
4750 :
4751 2 : state.dataFurnaces->MySizeFlag(FurnaceNum) = false;
4752 : // Pass the fan cycling schedule index up to the air loop. Set the air loop unitary system flag.
4753 2 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).cycFanSched = thisFurnace.fanOpModeSched;
4754 2 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).UnitarySys = true;
4755 : // RR this is wrong, Op mode needs to be updated each time atep
4756 2 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).fanOp = thisFurnace.fanOp;
4757 :
4758 : // Check that heat pump heating capacity is within 20% of cooling capacity
4759 2 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir) {
4760 2 : if (std::abs(thisFurnace.DesignCoolingCapacity - thisFurnace.DesignHeatingCapacity) / thisFurnace.DesignCoolingCapacity > 0.2) {
4761 0 : ShowWarningError(state,
4762 0 : format("{} \"{}\" heating capacity is disproportionate (> 20% different) to total cooling capacity",
4763 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
4764 0 : thisFurnace.Name));
4765 : }
4766 : }
4767 : }
4768 :
4769 15222 : if (!state.dataGlobal->DoingSizing && state.dataFurnaces->MySecondOneTimeFlag(FurnaceNum)) {
4770 : // sizing all done. check fan air flow rates
4771 4 : thisFurnace.ActualFanVolFlowRate = state.dataFans->fans(thisFurnace.FanIndex)->maxAirFlowRate;
4772 4 : if (thisFurnace.ActualFanVolFlowRate != DataSizing::AutoSize) {
4773 2 : if (thisFurnace.DesignFanVolFlowRate > thisFurnace.ActualFanVolFlowRate) {
4774 0 : ShowWarningError(state,
4775 0 : format("{}={} has a Design Fan Volume Flow Rate > Max Fan Volume Flow Rate, should be <=",
4776 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
4777 0 : thisFurnace.Name));
4778 0 : ShowContinueError(state,
4779 0 : format("... Entered value={:.2R}... Fan [{}] Max Value={:.2R}",
4780 0 : thisFurnace.DesignFanVolFlowRate,
4781 0 : HVAC::fanTypeNames[(int)thisFurnace.fanType],
4782 0 : thisFurnace.ActualFanVolFlowRate));
4783 : }
4784 2 : if (thisFurnace.DesignFanVolFlowRate <= 0.0) {
4785 0 : ShowSevereError(state,
4786 0 : format("{}={} has a Design Fan Volume Flow Rate <= 0.0, it must be >0.0",
4787 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
4788 0 : thisFurnace.Name));
4789 0 : ShowContinueError(state, format("... Entered value={:.2R}", thisFurnace.DesignFanVolFlowRate));
4790 : }
4791 :
4792 2 : state.dataFurnaces->MySecondOneTimeFlag(FurnaceNum) = false;
4793 : }
4794 : }
4795 :
4796 : // Scan hot water and steam heating coil plant components for one time initializations
4797 15222 : if (state.dataFurnaces->MyPlantScanFlag(FurnaceNum) && allocated(state.dataPlnt->PlantLoop)) {
4798 2 : if ((thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWater) || (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingSteam)) {
4799 :
4800 0 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWater) {
4801 :
4802 0 : errFlag = false;
4803 0 : PlantUtilities::ScanPlantLoopsForObject(state,
4804 : thisFurnace.HeatingCoilName,
4805 : DataPlant::PlantEquipmentType::CoilWaterSimpleHeating,
4806 0 : thisFurnace.plantLoc,
4807 : errFlag,
4808 : _,
4809 : _,
4810 : _,
4811 : _,
4812 : _);
4813 0 : if (errFlag) {
4814 0 : ShowFatalError(state, "InitFurnace: Program terminated for previous conditions.");
4815 : }
4816 0 : thisFurnace.MaxHeatCoilFluidFlow =
4817 0 : WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", thisFurnace.HeatingCoilName, ErrorsFound);
4818 0 : if (thisFurnace.MaxHeatCoilFluidFlow > 0.0) {
4819 : rho =
4820 0 : state.dataPlnt->PlantLoop(thisFurnace.plantLoc.loopNum).glycol->getDensity(state, Constant::HWInitConvTemp, RoutineName);
4821 0 : thisFurnace.MaxHeatCoilFluidFlow *= rho;
4822 : }
4823 0 : } else if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingSteam) {
4824 :
4825 0 : errFlag = false;
4826 0 : PlantUtilities::ScanPlantLoopsForObject(state,
4827 : thisFurnace.HeatingCoilName,
4828 : DataPlant::PlantEquipmentType::CoilSteamAirHeating,
4829 0 : thisFurnace.plantLoc,
4830 : errFlag,
4831 : _,
4832 : _,
4833 : _,
4834 : _,
4835 : _);
4836 0 : if (errFlag) {
4837 0 : ShowFatalError(state, "InitFurnace: Program terminated for previous conditions.");
4838 : }
4839 0 : thisFurnace.MaxHeatCoilFluidFlow = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.HeatingCoilIndex, ErrorsFound);
4840 0 : if (thisFurnace.MaxHeatCoilFluidFlow > 0.0) {
4841 0 : SteamDensity = Fluid::GetSteam(state)->getSatDensity(state, state.dataFurnaces->TempSteamIn, 1.0, RoutineName);
4842 0 : thisFurnace.MaxHeatCoilFluidFlow *= SteamDensity;
4843 : }
4844 : }
4845 : // fill outlet node for coil
4846 0 : thisFurnace.CoilOutletNode = DataPlant::CompData::getPlantComponent(state, thisFurnace.plantLoc).NodeNumOut;
4847 0 : state.dataFurnaces->MyPlantScanFlag(FurnaceNum) = false;
4848 : } else { // pthp not connected to plant
4849 2 : state.dataFurnaces->MyPlantScanFlag(FurnaceNum) = false;
4850 : }
4851 15220 : } else if (state.dataFurnaces->MyPlantScanFlag(FurnaceNum) && !state.dataGlobal->AnyPlantInModel) {
4852 0 : state.dataFurnaces->MyPlantScanFlag(FurnaceNum) = false;
4853 : }
4854 :
4855 : // Scan Supplemental hot water and steam heating coil plant components for one time initializations
4856 15222 : if (state.dataFurnaces->MySuppCoilPlantScanFlag(FurnaceNum) && allocated(state.dataPlnt->PlantLoop)) {
4857 2 : if ((thisFurnace.SuppHeatCoilType_Num == HVAC::Coil_HeatingWater) || (thisFurnace.SuppHeatCoilType_Num == HVAC::Coil_HeatingSteam)) {
4858 :
4859 0 : if (thisFurnace.SuppHeatCoilType_Num == HVAC::Coil_HeatingWater) {
4860 0 : errFlag = false;
4861 0 : PlantUtilities::ScanPlantLoopsForObject(state,
4862 : thisFurnace.SuppHeatCoilName,
4863 : DataPlant::PlantEquipmentType::CoilWaterSimpleHeating,
4864 0 : thisFurnace.SuppPlantLoc,
4865 : errFlag,
4866 : _,
4867 : _,
4868 : _,
4869 : _,
4870 : _);
4871 0 : if (errFlag) {
4872 0 : ShowFatalError(state, "InitFurnace: Program terminated for previous conditions.");
4873 : }
4874 0 : thisFurnace.MaxSuppCoilFluidFlow =
4875 0 : WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", thisFurnace.SuppHeatCoilName, ErrorsFound);
4876 0 : if (thisFurnace.MaxSuppCoilFluidFlow > 0.0) {
4877 0 : rho = state.dataPlnt->PlantLoop(thisFurnace.SuppPlantLoc.loopNum)
4878 0 : .glycol->getDensity(state, Constant::HWInitConvTemp, RoutineName);
4879 0 : thisFurnace.MaxSuppCoilFluidFlow *= rho;
4880 : }
4881 0 : } else if (thisFurnace.SuppHeatCoilType_Num == HVAC::Coil_HeatingSteam) {
4882 0 : errFlag = false;
4883 0 : PlantUtilities::ScanPlantLoopsForObject(state,
4884 : thisFurnace.SuppHeatCoilName,
4885 : DataPlant::PlantEquipmentType::CoilSteamAirHeating,
4886 0 : thisFurnace.SuppPlantLoc,
4887 : errFlag,
4888 : _,
4889 : _,
4890 : _,
4891 : _,
4892 : _);
4893 0 : if (errFlag) {
4894 0 : ShowFatalError(state, "InitFurnace: Program terminated for previous conditions.");
4895 : }
4896 0 : thisFurnace.MaxSuppCoilFluidFlow = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.SuppHeatCoilIndex, ErrorsFound);
4897 0 : if (thisFurnace.MaxSuppCoilFluidFlow > 0.0) {
4898 0 : SteamDensity = Fluid::GetSteam(state)->getSatDensity(state, state.dataFurnaces->TempSteamIn, 1.0, RoutineName);
4899 0 : thisFurnace.MaxSuppCoilFluidFlow *= SteamDensity;
4900 : }
4901 : }
4902 : // fill outlet node for coil
4903 0 : thisFurnace.SuppCoilOutletNode = DataPlant::CompData::getPlantComponent(state, thisFurnace.SuppPlantLoc).NodeNumOut;
4904 0 : state.dataFurnaces->MySuppCoilPlantScanFlag(FurnaceNum) = false;
4905 : } else { // pthp not connected to plant
4906 2 : state.dataFurnaces->MySuppCoilPlantScanFlag(FurnaceNum) = false;
4907 : }
4908 :
4909 15220 : } else if (state.dataFurnaces->MySuppCoilPlantScanFlag(FurnaceNum) && !state.dataGlobal->AnyPlantInModel) {
4910 0 : state.dataFurnaces->MySuppCoilPlantScanFlag(FurnaceNum) = false;
4911 : }
4912 :
4913 : // Do the Begin Environment initializations
4914 15222 : if (state.dataGlobal->BeginEnvrnFlag && state.dataFurnaces->MyEnvrnFlag(FurnaceNum)) {
4915 : // Change the Volume Flow Rates to Mass Flow Rates
4916 6 : thisFurnace.DesignMassFlowRate = thisFurnace.DesignFanVolFlowRate * state.dataEnvrn->StdRhoAir;
4917 6 : thisFurnace.MaxCoolAirMassFlow = thisFurnace.MaxCoolAirVolFlow * state.dataEnvrn->StdRhoAir;
4918 6 : thisFurnace.MaxHeatAirMassFlow = thisFurnace.MaxHeatAirVolFlow * state.dataEnvrn->StdRhoAir;
4919 6 : thisFurnace.MaxNoCoolHeatAirMassFlow = thisFurnace.MaxNoCoolHeatAirVolFlow * state.dataEnvrn->StdRhoAir;
4920 6 : thisFurnace.CompPartLoadRatio = 0.0;
4921 6 : thisFurnace.CoolingCoilSensDemand = 0.0;
4922 6 : thisFurnace.CoolingCoilLatentDemand = 0.0;
4923 6 : thisFurnace.HeatingCoilSensDemand = 0.0;
4924 :
4925 6 : thisFurnace.SenLoadLoss = 0.0;
4926 6 : if (thisFurnace.Humidistat) {
4927 0 : thisFurnace.LatLoadLoss = 0.0;
4928 : }
4929 :
4930 : // set fluid-side hardware limits
4931 6 : if (thisFurnace.CoilControlNode > 0) {
4932 :
4933 0 : if (thisFurnace.MaxHeatCoilFluidFlow == DataSizing::AutoSize) {
4934 : // If water coil max water flow rate is autosized, simulate once in order to mine max flow rate
4935 0 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWater) {
4936 0 : WaterCoils::SimulateWaterCoilComponents(state, thisFurnace.HeatingCoilName, FirstHVACIteration, thisFurnace.HeatingCoilIndex);
4937 : CoilMaxVolFlowRate =
4938 0 : WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", thisFurnace.HeatingCoilName, ErrorsFound);
4939 0 : if (CoilMaxVolFlowRate != DataSizing::AutoSize) {
4940 0 : rho = state.dataPlnt->PlantLoop(thisFurnace.plantLoc.loopNum)
4941 0 : .glycol->getDensity(state, Constant::HWInitConvTemp, RoutineName);
4942 0 : thisFurnace.MaxHeatCoilFluidFlow = CoilMaxVolFlowRate * rho;
4943 : }
4944 : }
4945 : // If steam coil max steam flow rate is autosized, simulate once in order to mine max flow rate
4946 0 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingSteam) {
4947 0 : SteamCoils::SimulateSteamCoilComponents(state,
4948 : thisFurnace.HeatingCoilName,
4949 : FirstHVACIteration,
4950 0 : thisFurnace.HeatingCoilIndex,
4951 0 : 1.0,
4952 : QActual); // QCoilReq, simulate any load > 0 to get max capacity
4953 0 : CoilMaxVolFlowRate = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.HeatingCoilIndex, ErrorsFound);
4954 0 : if (CoilMaxVolFlowRate != DataSizing::AutoSize) {
4955 0 : SteamDensity = Fluid::GetSteam(state)->getSatDensity(state, state.dataFurnaces->TempSteamIn, 1.0, RoutineName);
4956 0 : thisFurnace.MaxHeatCoilFluidFlow = CoilMaxVolFlowRate * SteamDensity;
4957 : }
4958 : }
4959 : }
4960 :
4961 0 : PlantUtilities::InitComponentNodes(
4962 : state, 0.0, thisFurnace.MaxHeatCoilFluidFlow, thisFurnace.CoilControlNode, thisFurnace.CoilOutletNode);
4963 : }
4964 6 : if (thisFurnace.SuppCoilControlNode > 0) {
4965 0 : if (thisFurnace.MaxSuppCoilFluidFlow == DataSizing::AutoSize) {
4966 0 : if (thisFurnace.SuppHeatCoilType_Num == HVAC::Coil_HeatingWater) {
4967 : // If water coil max water flow rate is autosized, simulate once in order to mine max flow rate
4968 0 : WaterCoils::SimulateWaterCoilComponents(
4969 0 : state, thisFurnace.SuppHeatCoilName, FirstHVACIteration, thisFurnace.SuppHeatCoilIndex);
4970 : CoilMaxVolFlowRate =
4971 0 : WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", thisFurnace.SuppHeatCoilName, ErrorsFound);
4972 0 : if (CoilMaxVolFlowRate != DataSizing::AutoSize) {
4973 0 : rho = state.dataPlnt->PlantLoop(thisFurnace.SuppPlantLoc.loopNum)
4974 0 : .glycol->getDensity(state, Constant::HWInitConvTemp, RoutineName);
4975 0 : thisFurnace.MaxSuppCoilFluidFlow = CoilMaxVolFlowRate * rho;
4976 : }
4977 : }
4978 0 : if (thisFurnace.SuppHeatCoilType_Num == HVAC::Coil_HeatingSteam) {
4979 0 : SteamCoils::SimulateSteamCoilComponents(state,
4980 : thisFurnace.SuppHeatCoilName,
4981 : FirstHVACIteration,
4982 0 : thisFurnace.SuppHeatCoilIndex,
4983 0 : 1.0,
4984 : QActual); // QCoilReq, simulate any load > 0 to get max capacity
4985 0 : CoilMaxVolFlowRate = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.SuppHeatCoilIndex, ErrorsFound);
4986 0 : if (CoilMaxVolFlowRate != DataSizing::AutoSize) {
4987 0 : SteamDensity = Fluid::GetSteam(state)->getSatDensity(state, state.dataFurnaces->TempSteamIn, 1.0, RoutineName);
4988 0 : thisFurnace.MaxSuppCoilFluidFlow = CoilMaxVolFlowRate * SteamDensity;
4989 : }
4990 : }
4991 0 : PlantUtilities::InitComponentNodes(
4992 : state, 0.0, thisFurnace.MaxSuppCoilFluidFlow, thisFurnace.SuppCoilControlNode, thisFurnace.SuppCoilOutletNode);
4993 : }
4994 : }
4995 6 : state.dataFurnaces->MyEnvrnFlag(FurnaceNum) = false;
4996 : }
4997 :
4998 15222 : if (!state.dataGlobal->BeginEnvrnFlag) {
4999 15136 : state.dataFurnaces->MyEnvrnFlag(FurnaceNum) = true;
5000 : }
5001 :
5002 15222 : if (state.dataFurnaces->MyFanFlag(FurnaceNum)) {
5003 4 : if (thisFurnace.ActualFanVolFlowRate != DataSizing::AutoSize) {
5004 2 : if (thisFurnace.ActualFanVolFlowRate > 0.0) {
5005 2 : thisFurnace.HeatingSpeedRatio = thisFurnace.MaxHeatAirVolFlow / thisFurnace.ActualFanVolFlowRate;
5006 2 : thisFurnace.CoolingSpeedRatio = thisFurnace.MaxCoolAirVolFlow / thisFurnace.ActualFanVolFlowRate;
5007 2 : thisFurnace.NoHeatCoolSpeedRatio = thisFurnace.MaxNoCoolHeatAirVolFlow / thisFurnace.ActualFanVolFlowRate;
5008 : }
5009 2 : if (dynamic_cast<Fans::FanComponent *>(state.dataFans->fans(thisFurnace.FanIndex))->powerRatioAtSpeedRatioCurveNum > 0) {
5010 0 : if (thisFurnace.ActualFanVolFlowRate == thisFurnace.MaxHeatAirVolFlow &&
5011 0 : thisFurnace.ActualFanVolFlowRate == thisFurnace.MaxCoolAirVolFlow &&
5012 0 : thisFurnace.ActualFanVolFlowRate == thisFurnace.MaxNoCoolHeatAirVolFlow) {
5013 0 : std::string FanName = state.dataFans->fans(thisFurnace.FanIndex)->Name;
5014 0 : ShowWarningError(state, format("{} \"{}\"", HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name));
5015 0 : ShowContinueError(state,
5016 0 : format("...For fan type and name = {} \"{}\"", HVAC::fanTypeNames[(int)thisFurnace.fanType], FanName));
5017 0 : ShowContinueError(state,
5018 : "...Fan power ratio function of speed ratio curve has no impact if fan volumetric flow rate is the same as "
5019 : "the unitary system volumetric flow rate.");
5020 0 : ShowContinueError(state, format("...Fan volumetric flow rate = {:.5R} m3/s.", thisFurnace.ActualFanVolFlowRate));
5021 0 : ShowContinueError(state, format("...Unitary system volumetric flow rate = {:.5R} m3/s.", thisFurnace.MaxHeatAirVolFlow));
5022 0 : }
5023 : }
5024 2 : state.dataFurnaces->MyFanFlag(FurnaceNum) = false;
5025 : } else {
5026 2 : thisFurnace.ActualFanVolFlowRate = state.dataFans->fans(thisFurnace.FanIndex)->maxAirFlowRate;
5027 : }
5028 : }
5029 :
5030 15222 : if (allocated(state.dataZoneEquip->ZoneEquipConfig) && state.dataFurnaces->MyCheckFlag(FurnaceNum)) {
5031 2 : int zoneNum = thisFurnace.ControlZoneNum;
5032 2 : int zoneInlet = thisFurnace.ZoneInletNode;
5033 : // setup furnace zone equipment sequence information based on finding matching air terminal
5034 2 : if (state.dataZoneEquip->ZoneEquipConfig(zoneNum).EquipListIndex > 0) {
5035 2 : int coolingPriority = 0;
5036 2 : int heatingPriority = 0;
5037 2 : state.dataZoneEquip->ZoneEquipList(state.dataZoneEquip->ZoneEquipConfig(zoneNum).EquipListIndex)
5038 2 : .getPrioritiesForInletNode(state, zoneInlet, coolingPriority, heatingPriority);
5039 2 : thisFurnace.ZoneSequenceCoolingNum = coolingPriority;
5040 2 : thisFurnace.ZoneSequenceHeatingNum = heatingPriority;
5041 : }
5042 2 : state.dataFurnaces->MyCheckFlag(FurnaceNum) = false;
5043 2 : if (thisFurnace.ZoneSequenceCoolingNum == 0 || thisFurnace.ZoneSequenceHeatingNum == 0) {
5044 0 : ShowSevereError(state,
5045 0 : format("{} \"{}\": Airloop air terminal in the zone equipment list for zone = {} not found or is not allowed Zone "
5046 : "Equipment Cooling or Heating Sequence = 0.",
5047 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
5048 0 : thisFurnace.Name,
5049 0 : state.dataHeatBal->Zone(thisFurnace.ControlZoneNum).Name));
5050 0 : ShowFatalError(state,
5051 0 : format("Subroutine InitFurnace: Errors found in getting {} input. Preceding condition(s) causes termination.",
5052 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type]));
5053 : }
5054 : }
5055 :
5056 : // Find the number of zones (zone Inlet Nodes) attached to an air loop from the air loop number
5057 : int NumAirLoopZones =
5058 15222 : state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesCooled + state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesHeated;
5059 15222 : if (allocated(state.dataAirLoop->AirToZoneNodeInfo) && state.dataFurnaces->MyFlowFracFlag(FurnaceNum)) {
5060 2 : state.dataFurnaces->FlowFracFlagReady = true;
5061 4 : for (int ZoneInSysIndex = 1; ZoneInSysIndex <= NumAirLoopZones; ++ZoneInSysIndex) {
5062 : // zone inlet nodes for cooling
5063 2 : if (state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesCooled > 0) {
5064 2 : if (state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolInletNodes(ZoneInSysIndex) == -999) {
5065 : // the data structure for the zones inlet nodes has not been filled
5066 0 : state.dataFurnaces->FlowFracFlagReady = false;
5067 : }
5068 : }
5069 : // zone inlet nodes for heating
5070 2 : if (state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesHeated > 0) {
5071 0 : if (state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitHeatInletNodes(ZoneInSysIndex) == -999) {
5072 : // the data structure for the zones inlet nodes has not been filled
5073 0 : state.dataFurnaces->FlowFracFlagReady = false;
5074 : }
5075 : }
5076 : }
5077 : }
5078 :
5079 15222 : if (state.dataFurnaces->MyFlowFracFlag(FurnaceNum)) {
5080 2 : if (allocated(state.dataAirLoop->AirToZoneNodeInfo) && state.dataFurnaces->FlowFracFlagReady) {
5081 2 : SumOfMassFlowRateMax = 0.0; // initialize the sum of the maximum flows
5082 4 : for (int ZoneInSysIndex = 1; ZoneInSysIndex <= NumAirLoopZones; ++ZoneInSysIndex) {
5083 2 : int ZoneInletNodeNum = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolInletNodes(ZoneInSysIndex);
5084 2 : SumOfMassFlowRateMax += state.dataLoopNodes->Node(ZoneInletNodeNum).MassFlowRateMax;
5085 2 : if (state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).CoolCtrlZoneNums(ZoneInSysIndex) == thisFurnace.ControlZoneNum) {
5086 2 : CntrlZoneTerminalUnitMassFlowRateMax = state.dataLoopNodes->Node(ZoneInletNodeNum).MassFlowRateMax;
5087 : }
5088 : }
5089 2 : if (SumOfMassFlowRateMax != 0.0) {
5090 2 : if (CntrlZoneTerminalUnitMassFlowRateMax >= HVAC::SmallAirVolFlow) {
5091 2 : thisFurnace.ControlZoneMassFlowFrac = CntrlZoneTerminalUnitMassFlowRateMax / SumOfMassFlowRateMax;
5092 : } else {
5093 0 : ShowSevereError(state, format("{} = {}", HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name));
5094 0 : ShowContinueError(state, " The Fraction of Supply Air Flow That Goes Through the Controlling Zone is set to 1.");
5095 : }
5096 4 : BaseSizer::reportSizerOutput(state,
5097 2 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
5098 : thisFurnace.Name,
5099 : "Fraction of Supply Air Flow That Goes Through the Controlling Zone",
5100 : thisFurnace.ControlZoneMassFlowFrac);
5101 2 : state.dataFurnaces->MyFlowFracFlag(FurnaceNum) = false;
5102 : }
5103 : }
5104 : }
5105 :
5106 : // Calculate air distribution losses
5107 15222 : if (!FirstHVACIteration && state.dataFurnaces->AirLoopPass == 1) {
5108 3778 : int ZoneInNode = thisFurnace.ZoneInletNode;
5109 3778 : MassFlowRate = state.dataLoopNodes->Node(ZoneInNode).MassFlowRate / thisFurnace.ControlZoneMassFlowFrac;
5110 3778 : if (state.afn->distribution_simulated) {
5111 2764 : DeltaMassRate = state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum).MassFlowRate -
5112 2764 : state.dataLoopNodes->Node(ZoneInNode).MassFlowRate / thisFurnace.ControlZoneMassFlowFrac;
5113 2764 : if (DeltaMassRate < 0.0) {
5114 1077 : DeltaMassRate = 0.0;
5115 : }
5116 : } else {
5117 1014 : MassFlowRate = state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum).MassFlowRate;
5118 1014 : DeltaMassRate = 0.0;
5119 : }
5120 3778 : Real64 TotalOutput(0.0); // total output rate, {W}
5121 3778 : Real64 SensibleOutputDelta(0.0); // delta sensible output rate, {W}
5122 3778 : Real64 LatentOutputDelta(0.0); // delta latent output rate, {W}
5123 3778 : Real64 TotalOutputDelta(0.0); // delta total output rate, {W}
5124 15112 : CalcZoneSensibleLatentOutput(MassFlowRate,
5125 3778 : state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum).Temp,
5126 3778 : state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum).HumRat,
5127 3778 : state.dataLoopNodes->Node(ZoneInNode).Temp,
5128 3778 : state.dataLoopNodes->Node(ZoneInNode).HumRat,
5129 3778 : thisFurnace.SenLoadLoss,
5130 3778 : thisFurnace.LatLoadLoss,
5131 : TotalOutput);
5132 15112 : CalcZoneSensibleLatentOutput(DeltaMassRate,
5133 3778 : state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum).Temp,
5134 3778 : state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum).HumRat,
5135 3778 : state.dataLoopNodes->Node(thisFurnace.NodeNumOfControlledZone).Temp,
5136 3778 : state.dataLoopNodes->Node(thisFurnace.NodeNumOfControlledZone).HumRat,
5137 : SensibleOutputDelta,
5138 : LatentOutputDelta,
5139 : TotalOutputDelta);
5140 3778 : thisFurnace.SenLoadLoss = thisFurnace.SenLoadLoss + SensibleOutputDelta;
5141 3778 : if (std::abs(thisFurnace.SensibleLoadMet) > 0.0) {
5142 3777 : if (std::abs(thisFurnace.SenLoadLoss / thisFurnace.SensibleLoadMet) < 0.001) {
5143 1013 : thisFurnace.SenLoadLoss = 0.0;
5144 : }
5145 : }
5146 3778 : if (thisFurnace.Humidistat) {
5147 0 : thisFurnace.LatLoadLoss = thisFurnace.LatLoadLoss + LatentOutputDelta;
5148 0 : if (std::abs(thisFurnace.LatentLoadMet) > 0.0) {
5149 0 : if (std::abs(thisFurnace.LatLoadLoss / thisFurnace.LatentLoadMet) < 0.001) {
5150 0 : thisFurnace.LatLoadLoss = 0.0;
5151 : }
5152 : }
5153 : }
5154 : }
5155 :
5156 15222 : if (thisFurnace.fanOpModeSched != nullptr) {
5157 15222 : thisFurnace.fanOp = (thisFurnace.fanOpModeSched->getCurrentVal() == 0.0) ? HVAC::FanOp::Cycling : HVAC::FanOp::Continuous;
5158 15222 : if (AirLoopNum > 0) {
5159 15222 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).fanOp = thisFurnace.fanOp;
5160 : }
5161 : }
5162 :
5163 15222 : fanOp = thisFurnace.fanOp;
5164 15222 : state.dataFurnaces->EconomizerFlag = state.dataAirLoop->AirLoopControlInfo(AirLoopNum).EconoActive;
5165 :
5166 15222 : if (thisFurnace.ControlZoneMassFlowFrac > 0.0) {
5167 15222 : QZnReq = ZoneLoad / thisFurnace.ControlZoneMassFlowFrac;
5168 15222 : MoistureLoad /= thisFurnace.ControlZoneMassFlowFrac;
5169 15222 : ZoneLoad = QZnReq;
5170 : } else {
5171 0 : QZnReq = ZoneLoad;
5172 : }
5173 :
5174 : // Original thermostat control logic (works only for cycling fan systems)
5175 23584 : if (QZnReq > HVAC::SmallLoad && QZnReq > (Small5WLoad / thisFurnace.ControlZoneMassFlowFrac) &&
5176 8362 : !state.dataZoneEnergyDemand->CurDeadBandOrSetback(thisFurnace.ControlZoneNum)) {
5177 8362 : state.dataFurnaces->HeatingLoad = true;
5178 8362 : state.dataFurnaces->CoolingLoad = false;
5179 13608 : } else if (QZnReq < -HVAC::SmallLoad && std::abs(QZnReq) > (Small5WLoad / thisFurnace.ControlZoneMassFlowFrac) &&
5180 6748 : !state.dataZoneEnergyDemand->CurDeadBandOrSetback(thisFurnace.ControlZoneNum)) {
5181 6748 : state.dataFurnaces->HeatingLoad = false;
5182 6748 : state.dataFurnaces->CoolingLoad = true;
5183 : } else {
5184 112 : state.dataFurnaces->HeatingLoad = false;
5185 112 : state.dataFurnaces->CoolingLoad = false;
5186 : }
5187 :
5188 15222 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir ||
5189 0 : (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir &&
5190 0 : (thisFurnace.WatertoAirHPType == WAHPCoilType::Simple || thisFurnace.WatertoAirHPType == WAHPCoilType::VarSpeedEquationFit))) {
5191 15222 : if (MoistureLoad < 0.0 && thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat) {
5192 0 : state.dataFurnaces->HPDehumidificationLoadFlag = true;
5193 0 : state.dataFurnaces->HeatingLoad = false;
5194 0 : state.dataFurnaces->CoolingLoad = true;
5195 : } else {
5196 15222 : state.dataFurnaces->HPDehumidificationLoadFlag = false;
5197 : }
5198 : }
5199 :
5200 : // Check for heat only furnace
5201 15222 : if (thisFurnace.type != HVAC::UnitarySysType::Furnace_HeatOnly && thisFurnace.type != HVAC::UnitarySysType::Unitary_HeatOnly) {
5202 :
5203 30444 : if (thisFurnace.availSched->getCurrentVal() > 0.0) {
5204 15222 : if ((state.dataFurnaces->HeatingLoad || state.dataFurnaces->CoolingLoad) || (thisFurnace.Humidistat && MoistureLoad < 0.0)) {
5205 15110 : PartLoadRatio = 1.0;
5206 : } else {
5207 112 : PartLoadRatio = 0.0;
5208 : }
5209 : } else {
5210 0 : PartLoadRatio = 0.0;
5211 : }
5212 : } else {
5213 0 : PartLoadRatio = 1.0;
5214 : }
5215 :
5216 : // get current time step operating capacity of water and steam coils
5217 : // (dependent on entering water and steam temperature)
5218 15222 : if (FirstHVACIteration) {
5219 4846 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWater) {
5220 : // set water-side mass flow rates
5221 0 : state.dataLoopNodes->Node(thisFurnace.HWCoilAirInletNode).MassFlowRate = state.dataFurnaces->CompOnMassFlow;
5222 0 : mdot = thisFurnace.MaxHeatCoilFluidFlow;
5223 0 : PlantUtilities::SetComponentFlowRate(state, mdot, thisFurnace.CoilControlNode, thisFurnace.CoilOutletNode, thisFurnace.plantLoc);
5224 : // simulate water coil to find operating capacity
5225 0 : WaterCoils::SimulateWaterCoilComponents(
5226 0 : state, thisFurnace.HeatingCoilName, FirstHVACIteration, thisFurnace.HeatingCoilIndex, QActual);
5227 0 : thisFurnace.DesignHeatingCapacity = QActual;
5228 :
5229 : } // from IF(furnace%HeatingCoilType_Num == Coil_HeatingWater) THEN
5230 :
5231 4846 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingSteam) {
5232 : // set air-side and steam-side mass flow rates
5233 0 : state.dataLoopNodes->Node(thisFurnace.HWCoilAirInletNode).MassFlowRate = state.dataFurnaces->CompOnMassFlow;
5234 0 : mdot = thisFurnace.MaxHeatCoilFluidFlow;
5235 0 : PlantUtilities::SetComponentFlowRate(state, mdot, thisFurnace.CoilControlNode, thisFurnace.CoilOutletNode, thisFurnace.plantLoc);
5236 :
5237 : // simulate steam coil to find operating capacity
5238 0 : SteamCoils::SimulateSteamCoilComponents(state,
5239 : thisFurnace.HeatingCoilName,
5240 : FirstHVACIteration,
5241 0 : thisFurnace.HeatingCoilIndex,
5242 0 : 1.0,
5243 : QActual); // QCoilReq, simulate any load > 0 to get max capacity of steam coil
5244 0 : thisFurnace.DesignHeatingCapacity =
5245 0 : SteamCoils::GetCoilCapacity(state, thisFurnace.HeatingCoilType, thisFurnace.HeatingCoilName, ErrorsFound);
5246 :
5247 : } // from IF(Furnace(FurnaceNum)%HeatingCoilType_Num == Coil_HeatingSteam) THEN
5248 :
5249 4846 : if (thisFurnace.SuppHeatCoilType_Num == HVAC::Coil_HeatingWater) {
5250 :
5251 : // set air-side and steam-side mass flow rates
5252 0 : state.dataLoopNodes->Node(thisFurnace.SuppCoilAirInletNode).MassFlowRate = state.dataFurnaces->CompOnMassFlow;
5253 0 : mdot = thisFurnace.MaxSuppCoilFluidFlow;
5254 0 : PlantUtilities::SetComponentFlowRate(
5255 0 : state, mdot, thisFurnace.SuppCoilControlNode, thisFurnace.SuppCoilOutletNode, thisFurnace.SuppPlantLoc);
5256 :
5257 : // simulate water coil to find operating capacity
5258 0 : WaterCoils::SimulateWaterCoilComponents(
5259 0 : state, thisFurnace.SuppHeatCoilName, FirstHVACIteration, thisFurnace.SuppHeatCoilIndex, QActual);
5260 0 : thisFurnace.DesignSuppHeatingCapacity = QActual;
5261 :
5262 : } // from IF(Furnace(FurnaceNum)%SuppHeatCoilType_Num == Coil_HeatingWater) THEN
5263 4846 : if (thisFurnace.SuppHeatCoilType_Num == HVAC::Coil_HeatingSteam) {
5264 : // set air-side and steam-side mass flow rates
5265 0 : state.dataLoopNodes->Node(thisFurnace.SuppCoilAirInletNode).MassFlowRate = state.dataFurnaces->CompOnMassFlow;
5266 0 : mdot = thisFurnace.MaxSuppCoilFluidFlow;
5267 0 : PlantUtilities::SetComponentFlowRate(
5268 0 : state, mdot, thisFurnace.SuppCoilControlNode, thisFurnace.SuppCoilOutletNode, thisFurnace.SuppPlantLoc);
5269 :
5270 : // simulate steam coil to find operating capacity
5271 0 : SteamCoils::SimulateSteamCoilComponents(state,
5272 : thisFurnace.SuppHeatCoilName,
5273 : FirstHVACIteration,
5274 0 : thisFurnace.SuppHeatCoilIndex,
5275 0 : 1.0,
5276 : QActual); // QCoilReq, simulate any load > 0 to get max capacity of steam coil
5277 0 : thisFurnace.DesignSuppHeatingCapacity =
5278 0 : SteamCoils::GetCoilCapacity(state, thisFurnace.SuppHeatCoilType, thisFurnace.SuppHeatCoilName, ErrorsFound);
5279 :
5280 : } // from IF(Furnace(FurnaceNum)%SuppHeatCoilType_Num == Coil_HeatingSteam) THEN
5281 : } // from IF( FirstHVACIteration ) THEN
5282 :
5283 15222 : if (thisFurnace.NumOfSpeedCooling > 0) { // BoS, variable-speed water source hp
5284 : // Furnace(FurnaceNum)%IdleMassFlowRate = RhoAir*Furnace(FurnaceNum)%IdleVolumeAirRate
5285 0 : int NumOfSpeedCooling = thisFurnace.NumOfSpeedCooling;
5286 0 : int NumOfSpeedHeating = thisFurnace.NumOfSpeedHeating;
5287 : // IF MSHP system was not autosized and the fan is autosized, check that fan volumetric flow rate is greater than MSHP flow rates
5288 0 : if (thisFurnace.CheckFanFlow) {
5289 0 : state.dataFurnaces->CurrentModuleObject = "AirLoopHVAC:UnitaryHeatPump:VariableSpeed";
5290 0 : thisFurnace.FanVolFlow = state.dataFans->fans(thisFurnace.FanIndex)->maxAirFlowRate;
5291 :
5292 0 : if (thisFurnace.FanVolFlow != DataSizing::AutoSize) {
5293 : // Check fan versus system supply air flow rates
5294 0 : if (thisFurnace.FanVolFlow + 1e-10 < thisFurnace.CoolVolumeFlowRate(NumOfSpeedCooling)) {
5295 0 : ShowWarningError(state,
5296 0 : format("{} - air flow rate = {:.7T} in fan object is less than the MSHP system air flow rate when cooling "
5297 : "is required ({:.7T}).",
5298 0 : state.dataFurnaces->CurrentModuleObject,
5299 0 : thisFurnace.FanVolFlow,
5300 : thisFurnace.CoolVolumeFlowRate(NumOfSpeedCooling)));
5301 0 : ShowContinueError(
5302 : state, " The MSHP system flow rate when cooling is required is reset to the fan flow rate and the simulation continues.");
5303 0 : ShowContinueError(state, format(" Occurs in {} = {}", state.dataFurnaces->CurrentModuleObject, thisFurnace.Name));
5304 0 : thisFurnace.CoolVolumeFlowRate(NumOfSpeedCooling) = thisFurnace.FanVolFlow;
5305 :
5306 0 : if (thisFurnace.bIsIHP) // set max fan flow rate to the IHP collection
5307 : {
5308 0 : state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).MaxCoolAirVolFlow = thisFurnace.FanVolFlow;
5309 0 : state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).MaxCoolAirMassFlow =
5310 0 : thisFurnace.FanVolFlow * state.dataEnvrn->StdRhoAir;
5311 : }
5312 :
5313 : // Check flow rates in other speeds and ensure flow rates are not above the max flow rate
5314 0 : for (int i = NumOfSpeedCooling - 1; i >= 1; --i) {
5315 0 : if (thisFurnace.CoolVolumeFlowRate(i) > thisFurnace.CoolVolumeFlowRate(i + 1)) {
5316 0 : ShowContinueError(state,
5317 0 : format(" The MSHP system flow rate when cooling is required is reset to the flow rate at higher "
5318 : "speed and the simulation continues at Speed{}.",
5319 : i));
5320 0 : ShowContinueError(state, format(" Occurs in {} = {}", state.dataFurnaces->CurrentModuleObject, thisFurnace.Name));
5321 0 : thisFurnace.CoolVolumeFlowRate(i) = thisFurnace.CoolVolumeFlowRate(i + 1);
5322 : }
5323 : }
5324 : }
5325 0 : if (NumOfSpeedHeating > 0) {
5326 0 : if (thisFurnace.FanVolFlow + 1e-10 < thisFurnace.HeatVolumeFlowRate(NumOfSpeedHeating)) {
5327 0 : ShowWarningError(state,
5328 0 : format("{} - air flow rate = {:.7T} in fan object is less than the MSHP system air flow rate when "
5329 : "heating is required ({:.7T}).",
5330 0 : state.dataFurnaces->CurrentModuleObject,
5331 0 : thisFurnace.FanVolFlow,
5332 : thisFurnace.HeatVolumeFlowRate(NumOfSpeedHeating)));
5333 0 : ShowContinueError(
5334 : state,
5335 : " The MSHP system flow rate when heating is required is reset to the fan flow rate and the simulation continues.");
5336 0 : ShowContinueError(state, format(" Occurs in {} = {}", state.dataFurnaces->CurrentModuleObject, thisFurnace.Name));
5337 0 : thisFurnace.HeatVolumeFlowRate(NumOfSpeedHeating) = thisFurnace.FanVolFlow;
5338 :
5339 0 : if (thisFurnace.bIsIHP) // set max fan flow rate to the IHP collection
5340 : {
5341 0 : state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).MaxHeatAirVolFlow = thisFurnace.FanVolFlow;
5342 0 : state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).MaxHeatAirMassFlow =
5343 0 : thisFurnace.FanVolFlow * state.dataEnvrn->StdRhoAir;
5344 : }
5345 :
5346 0 : for (int i = NumOfSpeedHeating - 1; i >= 1; --i) {
5347 0 : if (thisFurnace.HeatVolumeFlowRate(i) > thisFurnace.HeatVolumeFlowRate(i + 1)) {
5348 0 : ShowContinueError(state,
5349 0 : format(" The MSHP system flow rate when heating is required is reset to the flow rate at "
5350 : "higher speed and the simulation continues at Speed{}.",
5351 : i));
5352 0 : ShowContinueError(state,
5353 0 : format(" Occurs in {} system = {}", state.dataFurnaces->CurrentModuleObject, thisFurnace.Name));
5354 0 : thisFurnace.HeatVolumeFlowRate(i) = thisFurnace.HeatVolumeFlowRate(i + 1);
5355 : }
5356 : }
5357 : }
5358 : }
5359 0 : if (thisFurnace.FanVolFlow < thisFurnace.IdleVolumeAirRate && thisFurnace.IdleVolumeAirRate != 0.0) {
5360 0 : ShowWarningError(state,
5361 0 : format("{} - air flow rate = {:.7T} in fan object is less than the MSHP system air flow rate when no "
5362 : "heating or cooling is needed ({:.7T}).",
5363 0 : state.dataFurnaces->CurrentModuleObject,
5364 0 : thisFurnace.FanVolFlow,
5365 0 : thisFurnace.IdleVolumeAirRate));
5366 0 : ShowContinueError(state,
5367 : " The MSHP system flow rate when no heating or cooling is needed is reset to the fan flow rate and the "
5368 : "simulation continues.");
5369 0 : ShowContinueError(state, format(" Occurs in {} = {}", state.dataFurnaces->CurrentModuleObject, thisFurnace.Name));
5370 0 : thisFurnace.IdleVolumeAirRate = thisFurnace.FanVolFlow;
5371 : }
5372 0 : RhoAir = state.dataEnvrn->StdRhoAir;
5373 : // set the mass flow rates from the reset volume flow rates
5374 0 : for (int i = 1; i <= NumOfSpeedCooling; ++i) {
5375 0 : thisFurnace.CoolMassFlowRate(i) = RhoAir * thisFurnace.CoolVolumeFlowRate(i);
5376 0 : if (thisFurnace.FanVolFlow > 0.0) {
5377 0 : thisFurnace.MSCoolingSpeedRatio(i) = thisFurnace.CoolVolumeFlowRate(i) / thisFurnace.FanVolFlow;
5378 : }
5379 : }
5380 0 : for (int i = 1; i <= NumOfSpeedHeating; ++i) {
5381 0 : thisFurnace.HeatMassFlowRate(i) = RhoAir * thisFurnace.HeatVolumeFlowRate(i);
5382 0 : if (thisFurnace.FanVolFlow > 0.0) {
5383 0 : thisFurnace.MSHeatingSpeedRatio(i) = thisFurnace.HeatVolumeFlowRate(i) / thisFurnace.FanVolFlow;
5384 : }
5385 : }
5386 0 : thisFurnace.IdleMassFlowRate = RhoAir * thisFurnace.IdleVolumeAirRate;
5387 0 : if (thisFurnace.FanVolFlow > 0.0) {
5388 0 : thisFurnace.IdleSpeedRatio = thisFurnace.IdleVolumeAirRate / thisFurnace.FanVolFlow;
5389 : }
5390 : // set the node max and min mass flow rates based on reset volume flow rates
5391 0 : if (NumOfSpeedCooling > 0 && NumOfSpeedHeating == 0) {
5392 0 : state.dataLoopNodes->Node(InNode).MassFlowRateMax =
5393 0 : max(thisFurnace.CoolMassFlowRate(NumOfSpeedCooling), thisFurnace.MaxHeatAirMassFlow);
5394 0 : state.dataLoopNodes->Node(InNode).MassFlowRateMaxAvail =
5395 0 : max(thisFurnace.CoolMassFlowRate(NumOfSpeedCooling), thisFurnace.MaxHeatAirMassFlow);
5396 0 : } else if (NumOfSpeedCooling == 0 && NumOfSpeedHeating > 0) {
5397 0 : state.dataLoopNodes->Node(InNode).MassFlowRateMax =
5398 0 : max(thisFurnace.MaxCoolAirMassFlow, thisFurnace.HeatMassFlowRate(NumOfSpeedHeating));
5399 0 : state.dataLoopNodes->Node(InNode).MassFlowRateMaxAvail =
5400 0 : max(thisFurnace.MaxCoolAirMassFlow, thisFurnace.HeatMassFlowRate(NumOfSpeedHeating));
5401 : } else {
5402 0 : state.dataLoopNodes->Node(InNode).MassFlowRateMax =
5403 0 : max(thisFurnace.CoolMassFlowRate(NumOfSpeedCooling), thisFurnace.HeatMassFlowRate(NumOfSpeedHeating));
5404 0 : state.dataLoopNodes->Node(InNode).MassFlowRateMaxAvail =
5405 0 : max(thisFurnace.CoolMassFlowRate(NumOfSpeedCooling), thisFurnace.HeatMassFlowRate(NumOfSpeedHeating));
5406 : }
5407 0 : state.dataLoopNodes->Node(InNode).MassFlowRateMin = 0.0;
5408 0 : state.dataLoopNodes->Node(InNode).MassFlowRateMinAvail = 0.0;
5409 0 : state.dataLoopNodes->Node(OutNode) = state.dataLoopNodes->Node(InNode);
5410 : }
5411 : }
5412 :
5413 0 : thisFurnace.CheckFanFlow = false;
5414 : }
5415 15222 : SetOnOffMassFlowRate(state, FurnaceNum, AirLoopNum, OnOffAirFlowRatio, fanOp, QZnReq, MoistureLoad, PartLoadRatio);
5416 :
5417 : // Check ventilation/fan load for constant fan systems to see if load to be met changes
5418 : // Same IF logic used in Subroutine SetAverageAirFlow to determine if unit is ON or OFF
5419 :
5420 15222 : QToCoolSetPt = 0.0;
5421 15222 : QToHeatSetPt = 0.0;
5422 15222 : if (fanOp == HVAC::FanOp::Continuous && thisFurnace.availSched->getCurrentVal() > 0.0 &&
5423 0 : ((thisFurnace.fanAvailSched->getCurrentVal() > 0.0 || state.dataHVACGlobal->TurnFansOn) && !state.dataHVACGlobal->TurnFansOff)) {
5424 :
5425 0 : if (thisFurnace.NumOfSpeedCooling > 0) {
5426 0 : CalcVarSpeedHeatPump(state,
5427 : FurnaceNum,
5428 : false,
5429 : HVAC::CompressorOp::Off,
5430 : 1,
5431 : 0.0,
5432 : 0.0,
5433 : SensibleOutput,
5434 : LatentOutput,
5435 : 0.0,
5436 : 0.0,
5437 : OnOffAirFlowRatio,
5438 : SUPHEATERLOAD);
5439 : } else {
5440 0 : CalcFurnaceOutput(state,
5441 : FurnaceNum,
5442 : false,
5443 : HVAC::FanOp::Invalid, // Looks like Invalid is used to mean that the fan is off here?
5444 : HVAC::CompressorOp::Off,
5445 : 0.0,
5446 : 0.0,
5447 : 0.0,
5448 : 0.0,
5449 : SensibleOutput,
5450 : LatentOutput,
5451 : OnOffAirFlowRatio,
5452 : false);
5453 : }
5454 :
5455 0 : if (thisFurnace.ControlZoneMassFlowFrac > 0.0) {
5456 0 : if (thisFurnace.ZoneSequenceCoolingNum > 0 && thisFurnace.ZoneSequenceHeatingNum > 0) {
5457 0 : QToCoolSetPt = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(thisFurnace.ControlZoneNum)
5458 0 : .SequencedOutputRequiredToCoolingSP(thisFurnace.ZoneSequenceCoolingNum) /
5459 0 : thisFurnace.ControlZoneMassFlowFrac;
5460 0 : QToHeatSetPt = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(thisFurnace.ControlZoneNum)
5461 0 : .SequencedOutputRequiredToHeatingSP(thisFurnace.ZoneSequenceHeatingNum) /
5462 0 : thisFurnace.ControlZoneMassFlowFrac;
5463 : } else {
5464 0 : QToCoolSetPt = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(thisFurnace.ControlZoneNum).OutputRequiredToCoolingSP /
5465 0 : thisFurnace.ControlZoneMassFlowFrac;
5466 0 : QToHeatSetPt = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(thisFurnace.ControlZoneNum).OutputRequiredToHeatingSP /
5467 0 : thisFurnace.ControlZoneMassFlowFrac;
5468 : }
5469 : // If the furnace has a net cooling capacity (SensibleOutput < 0) and
5470 : // the zone temp is above the Tstat heating setpoint (QToHeatSetPt < 0) and
5471 : // the net cooling capacity does not just offset the cooling load
5472 0 : if (SensibleOutput < 0.0 && QToHeatSetPt < 0.0 &&
5473 0 : std::abs(QToCoolSetPt - SensibleOutput) > (Small5WLoad / thisFurnace.ControlZoneMassFlowFrac)) {
5474 : // Only switch modes when humidistat is not used or no moisture load exists, otherwise let
5475 : // reheat coil pick up load
5476 : // IF((SensibleOutput .LT. QToHeatSetPt .AND. .NOT. Furnace(FurnaceNum)%Humidistat) .OR. &
5477 : // (SensibleOutput .LT. QToHeatSetPt .AND. Furnace(FurnaceNum)%Humidistat .AND. MoistureLoad .GE. 0.0))THEN
5478 0 : if ((SensibleOutput < QToHeatSetPt && !thisFurnace.Humidistat) ||
5479 0 : (SensibleOutput < QToHeatSetPt && thisFurnace.Humidistat && MoistureLoad >= 0.0)) {
5480 0 : QZnReq = QToHeatSetPt;
5481 0 : state.dataFurnaces->CoolingLoad = false;
5482 : // Don't set mode TRUE unless mode is allowed. Also check for floating zone.
5483 0 : if (state.dataHeatBalFanSys->TempControlType(thisFurnace.ControlZoneNum) == HVAC::SetptType::SingleCool ||
5484 0 : state.dataHeatBalFanSys->TempControlType(thisFurnace.ControlZoneNum) == HVAC::SetptType::Uncontrolled) {
5485 0 : state.dataFurnaces->HeatingLoad = false;
5486 : } else {
5487 0 : state.dataFurnaces->HeatingLoad = true;
5488 : }
5489 :
5490 0 : SetOnOffMassFlowRate(state, FurnaceNum, AirLoopNum, OnOffAirFlowRatio, fanOp, QZnReq, MoistureLoad, PartLoadRatio);
5491 0 : if (thisFurnace.NumOfSpeedCooling > 0) {
5492 0 : CalcVarSpeedHeatPump(state,
5493 : FurnaceNum,
5494 : false,
5495 : HVAC::CompressorOp::Off,
5496 : 1,
5497 : 0.0,
5498 : 0.0,
5499 : SensibleOutput,
5500 : LatentOutput,
5501 : 0.0,
5502 : 0.0,
5503 : OnOffAirFlowRatio,
5504 : SUPHEATERLOAD);
5505 : } else {
5506 0 : CalcFurnaceOutput(state,
5507 : FurnaceNum,
5508 : false,
5509 : HVAC::FanOp::Invalid,
5510 : HVAC::CompressorOp::Off,
5511 : 0.0,
5512 : 0.0,
5513 : 0.0,
5514 : 0.0,
5515 : SensibleOutput,
5516 : LatentOutput,
5517 : OnOffAirFlowRatio,
5518 : false);
5519 : }
5520 0 : if (SensibleOutput > QToHeatSetPt) {
5521 : // If changing operating mode (flow rates) does not overshoot heating setpoint, turn off heating
5522 0 : QZnReq = 0.0;
5523 0 : state.dataFurnaces->HeatingLoad = false;
5524 0 : SetOnOffMassFlowRate(state, FurnaceNum, AirLoopNum, OnOffAirFlowRatio, fanOp, QZnReq, MoistureLoad, PartLoadRatio);
5525 : }
5526 0 : } else if (SensibleOutput < QZnReq) {
5527 : // If the net cooling capacity meets the zone cooling load but does not overshoot heating setpoint, turn off cooling
5528 : // (dehumidification may still occur)
5529 0 : QZnReq = 0.0;
5530 0 : state.dataFurnaces->CoolingLoad = false;
5531 0 : if (state.dataFurnaces->HPDehumidificationLoadFlag) {
5532 0 : state.dataFurnaces->CoolingLoad = true;
5533 0 : state.dataFurnaces->HeatingLoad = false;
5534 : }
5535 0 : SetOnOffMassFlowRate(state, FurnaceNum, AirLoopNum, OnOffAirFlowRatio, fanOp, QZnReq, MoistureLoad, PartLoadRatio);
5536 : }
5537 : // the net cooling capacity just offsets the cooling load, turn off cooling
5538 0 : } else if (SensibleOutput < 0.0 && QToCoolSetPt < 0.0 &&
5539 0 : std::abs(QToCoolSetPt - SensibleOutput) < (Small5WLoad / thisFurnace.ControlZoneMassFlowFrac)) {
5540 0 : state.dataFurnaces->CoolingLoad = false;
5541 0 : if (state.dataFurnaces->HPDehumidificationLoadFlag) {
5542 0 : state.dataFurnaces->CoolingLoad = true;
5543 0 : state.dataFurnaces->HeatingLoad = false;
5544 : }
5545 : } // SensibleOutput .LT. 0.0d0 .AND. QToHeatSetPt .LT. 0.0d0
5546 :
5547 : // If the furnace has a net heating capacity and the zone temp is below the Tstat cooling setpoint and
5548 : // the net heating capacity does not just offset the heating load
5549 0 : if (SensibleOutput > 0.0 && QToCoolSetPt > 0.0 &&
5550 0 : std::abs(SensibleOutput - QToHeatSetPt) > (Small5WLoad / thisFurnace.ControlZoneMassFlowFrac)) {
5551 0 : if (SensibleOutput > QToCoolSetPt) {
5552 0 : QZnReq = QToCoolSetPt;
5553 : // Don't set mode TRUE unless mode is allowed. Also check for floating zone.
5554 0 : if (state.dataHeatBalFanSys->TempControlType(thisFurnace.ControlZoneNum) == HVAC::SetptType::SingleHeat ||
5555 0 : state.dataHeatBalFanSys->TempControlType(thisFurnace.ControlZoneNum) == HVAC::SetptType::Uncontrolled) {
5556 0 : state.dataFurnaces->CoolingLoad = false;
5557 : } else {
5558 0 : state.dataFurnaces->CoolingLoad = true;
5559 : }
5560 0 : state.dataFurnaces->HeatingLoad = false;
5561 :
5562 0 : SetOnOffMassFlowRate(state, FurnaceNum, AirLoopNum, OnOffAirFlowRatio, fanOp, QZnReq, MoistureLoad, PartLoadRatio);
5563 0 : if (thisFurnace.NumOfSpeedCooling > 0) {
5564 0 : CalcVarSpeedHeatPump(state,
5565 : FurnaceNum,
5566 : false,
5567 : HVAC::CompressorOp::Off,
5568 : 1,
5569 : 0.0,
5570 : 0.0,
5571 : SensibleOutput,
5572 : LatentOutput,
5573 : 0.0,
5574 : 0.0,
5575 : OnOffAirFlowRatio,
5576 : SUPHEATERLOAD);
5577 : } else {
5578 0 : CalcFurnaceOutput(state,
5579 : FurnaceNum,
5580 : false,
5581 : HVAC::FanOp::Invalid,
5582 : HVAC::CompressorOp::Off,
5583 : 0.0,
5584 : 0.0,
5585 : 0.0,
5586 : 0.0,
5587 : SensibleOutput,
5588 : LatentOutput,
5589 : OnOffAirFlowRatio,
5590 : false);
5591 : }
5592 0 : if (SensibleOutput < QToCoolSetPt) {
5593 : // If changing operating mode (flow rates) does not overshoot cooling setpoint, turn off cooling
5594 0 : if (state.dataFurnaces->HPDehumidificationLoadFlag) {
5595 0 : state.dataFurnaces->CoolingLoad = true;
5596 0 : state.dataFurnaces->HeatingLoad = false;
5597 : } else {
5598 0 : QZnReq = 0.0;
5599 0 : state.dataFurnaces->CoolingLoad = false;
5600 : }
5601 0 : SetOnOffMassFlowRate(state, FurnaceNum, AirLoopNum, OnOffAirFlowRatio, fanOp, QZnReq, MoistureLoad, PartLoadRatio);
5602 : }
5603 0 : } else if (SensibleOutput > QZnReq) {
5604 : // If the net heating capacity meets the zone heating load but does not overshoot, turn off heating
5605 0 : QZnReq = 0.0;
5606 0 : state.dataFurnaces->HeatingLoad = false;
5607 0 : SetOnOffMassFlowRate(state, FurnaceNum, AirLoopNum, OnOffAirFlowRatio, fanOp, QZnReq, MoistureLoad, PartLoadRatio);
5608 : }
5609 : // the net heating capacity just offsets the heating load, turn off heating
5610 0 : } else if (SensibleOutput > 0.0 && QToHeatSetPt > 0.0 &&
5611 0 : std::abs(SensibleOutput - QToHeatSetPt) < (Small5WLoad / thisFurnace.ControlZoneMassFlowFrac)) {
5612 0 : state.dataFurnaces->HeatingLoad = false;
5613 : } // SensibleOutput .GT. 0.0d0 .AND. QToCoolSetPt .GT. 0.0d0
5614 : } // Furnace(FurnaceNum)%ControlZoneMassFlowFrac .GT. 0.0d0
5615 0 : ZoneLoad = QZnReq;
5616 : } // fanOp .EQ. FanOp::Continuous
5617 :
5618 15222 : if (FirstHVACIteration) {
5619 4846 : thisFurnace.iterationCounter = 0;
5620 4846 : thisFurnace.iterationMode = Furnaces::ModeOfOperation::NoCoolHeat;
5621 : }
5622 15222 : thisFurnace.iterationCounter += 1;
5623 :
5624 : // push iteration mode stack and set current mode
5625 15222 : thisFurnace.iterationMode(3) = thisFurnace.iterationMode(2);
5626 15222 : thisFurnace.iterationMode(2) = thisFurnace.iterationMode(1);
5627 15222 : if (state.dataFurnaces->CoolingLoad) {
5628 6748 : thisFurnace.iterationMode(1) = Furnaces::ModeOfOperation::CoolingMode;
5629 8474 : } else if (state.dataFurnaces->HeatingLoad) {
5630 8362 : thisFurnace.iterationMode(1) = Furnaces::ModeOfOperation::HeatingMode;
5631 : } else {
5632 112 : thisFurnace.iterationMode(1) = Furnaces::ModeOfOperation::NoCoolHeat;
5633 : }
5634 :
5635 : // IF small loads to meet or not converging, just shut down unit
5636 15222 : if (std::abs(ZoneLoad) < Small5WLoad) {
5637 112 : ZoneLoad = 0.0;
5638 112 : state.dataFurnaces->CoolingLoad = false;
5639 112 : state.dataFurnaces->HeatingLoad = false;
5640 15110 : } else if (thisFurnace.iterationCounter > (state.dataHVACGlobal->MinAirLoopIterationsAfterFirst + 4)) {
5641 : // attempt to lock output (air flow) if oscillations are detected
5642 0 : OperatingMode = thisFurnace.iterationMode(1);
5643 0 : OperatingModeMinusOne = thisFurnace.iterationMode(2);
5644 0 : OperatingModeMinusTwo = thisFurnace.iterationMode(3);
5645 0 : Oscillate = true;
5646 0 : if (OperatingMode == OperatingModeMinusOne && OperatingMode == OperatingModeMinusTwo) {
5647 0 : Oscillate = false;
5648 : }
5649 0 : if (Oscillate) {
5650 0 : if (QToCoolSetPt < 0.0) {
5651 0 : state.dataFurnaces->HeatingLoad = false;
5652 0 : state.dataFurnaces->CoolingLoad = true;
5653 0 : ZoneLoad = QToCoolSetPt;
5654 0 : } else if (QToHeatSetPt > 0.0) {
5655 0 : state.dataFurnaces->HeatingLoad = true;
5656 0 : state.dataFurnaces->CoolingLoad = false;
5657 0 : ZoneLoad = QToHeatSetPt;
5658 : } else {
5659 0 : state.dataFurnaces->HeatingLoad = false;
5660 0 : state.dataFurnaces->CoolingLoad = false;
5661 0 : ZoneLoad = 0.0;
5662 : }
5663 : }
5664 : }
5665 :
5666 : // EMS override point
5667 15222 : if (thisFurnace.EMSOverrideSensZoneLoadRequest) {
5668 0 : ZoneLoad = thisFurnace.EMSSensibleZoneLoadValue;
5669 : }
5670 15222 : if (thisFurnace.EMSOverrideMoistZoneLoadRequest) {
5671 0 : MoistureLoad = thisFurnace.EMSMoistureZoneLoadValue;
5672 : }
5673 15222 : if (thisFurnace.EMSOverrideSensZoneLoadRequest || thisFurnace.EMSOverrideMoistZoneLoadRequest) {
5674 0 : if ((ZoneLoad != 0.0) && (thisFurnace.EMSOverrideSensZoneLoadRequest)) {
5675 0 : PartLoadRatio = 1.0;
5676 0 : } else if ((MoistureLoad != 0.0) && (thisFurnace.EMSOverrideMoistZoneLoadRequest)) {
5677 0 : PartLoadRatio = 1.0;
5678 : } else {
5679 0 : PartLoadRatio = 0.0;
5680 : }
5681 0 : if (thisFurnace.NumOfSpeedCooling > 0) {
5682 0 : SetOnOffMassFlowRate(state, FurnaceNum, AirLoopNum, OnOffAirFlowRatio, fanOp, QZnReq, MoistureLoad, PartLoadRatio);
5683 : } else {
5684 : // This line is suspicious - all other calls to SetOnOffMassFlowRate pass in QZnReq, not ZoneLoad
5685 : // either way, it seems these two should be using the same parameters.
5686 0 : SetOnOffMassFlowRate(state, FurnaceNum, AirLoopNum, OnOffAirFlowRatio, fanOp, ZoneLoad, MoistureLoad, PartLoadRatio);
5687 : }
5688 : }
5689 :
5690 : // AirflowNetwork global variable
5691 15222 : if (state.afn->distribution_simulated) {
5692 11168 : state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).AFNLoopHeatingCoilMaxRTF = 0.0;
5693 : }
5694 15222 : }
5695 :
5696 15222 : void SetOnOffMassFlowRate(EnergyPlusData &state,
5697 : int const FurnaceNum, // index to furnace
5698 : [[maybe_unused]] int const AirLoopNum, // index to air loop !unused1208
5699 : Real64 &OnOffAirFlowRatio, // ratio of coil on to coil off air flow rate
5700 : HVAC::FanOp const fanOp, // fan operating mode
5701 : [[maybe_unused]] Real64 const ZoneLoad, // sensible load to be met (W) !unused1208
5702 : Real64 const MoistureLoad, // moisture load to be met (W)
5703 : Real64 const PartLoadRatio // coil part-load ratio
5704 : )
5705 : {
5706 :
5707 : // SUBROUTINE INFORMATION:
5708 : // AUTHOR Richard Raustad
5709 : // DATE WRITTEN Sep 2008
5710 :
5711 : // PURPOSE OF THIS SUBROUTINE:
5712 : // This subroutine is for initializations of the Furnace Components.
5713 :
5714 : // METHODOLOGY EMPLOYED:
5715 : // The HeatCool furnace/unitarysystem and air-to-air heat pump may have alternate air flow rates
5716 : // in cooling, heating, and when no cooling or heating is needed. Set up the coil (comp) ON and OFF
5717 : // air flow rates. Use these flow rates during the Calc routines to set the average mass flow rates
5718 : // based on PLR.
5719 :
5720 15222 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
5721 : // Check for heat only furnace
5722 15222 : if (thisFurnace.type != HVAC::UnitarySysType::Furnace_HeatOnly && thisFurnace.type != HVAC::UnitarySysType::Unitary_HeatOnly) {
5723 :
5724 : // Set the system mass flow rates
5725 15222 : if (fanOp == HVAC::FanOp::Continuous) {
5726 : // Set the compressor or coil ON mass flow rate
5727 : // constant fan mode
5728 0 : if (state.dataFurnaces->HeatingLoad) {
5729 : // IF a heating and moisture load exists, operate at the cooling mass flow rate ELSE operate at the heating flow rate
5730 0 : if (MoistureLoad < 0.0 && thisFurnace.Humidistat &&
5731 0 : thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat) {
5732 0 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxCoolAirMassFlow;
5733 0 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.CoolingSpeedRatio;
5734 : } else {
5735 0 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxHeatAirMassFlow;
5736 0 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.HeatingSpeedRatio;
5737 : }
5738 0 : thisFurnace.LastMode = Furnaces::ModeOfOperation::HeatingMode;
5739 : // IF a cooling load exists, operate at the cooling mass flow rate
5740 0 : } else if (state.dataFurnaces->CoolingLoad) {
5741 0 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxCoolAirMassFlow;
5742 0 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.CoolingSpeedRatio;
5743 0 : thisFurnace.LastMode = Furnaces::ModeOfOperation::CoolingMode;
5744 : // If no load exists, set the compressor on mass flow rate.
5745 : // Set equal the mass flow rate when no heating or cooling is needed if no moisture load exists.
5746 : // If the user has set the off mass flow rate to 0, set according to the last operating mode.
5747 : } else {
5748 0 : if (MoistureLoad < 0.0 && thisFurnace.Humidistat &&
5749 0 : thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat) {
5750 0 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxCoolAirMassFlow;
5751 0 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.CoolingSpeedRatio;
5752 : } else {
5753 0 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxNoCoolHeatAirMassFlow;
5754 0 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.HeatingSpeedRatio;
5755 : // User may have entered a 0 for MaxNoCoolHeatAirMassFlow
5756 0 : if (state.dataFurnaces->CompOnMassFlow == 0.0) {
5757 0 : if (thisFurnace.LastMode == Furnaces::ModeOfOperation::HeatingMode) {
5758 0 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxHeatAirMassFlow;
5759 0 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.HeatingSpeedRatio;
5760 : } else {
5761 0 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxCoolAirMassFlow;
5762 0 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.CoolingSpeedRatio;
5763 : }
5764 : }
5765 : }
5766 : }
5767 :
5768 : // Set the compressor or coil OFF mass flow rate based on LOGICAL flag
5769 : // UseCompressorOnFlow is used when the user does not enter a value for no cooling or heating flow rate
5770 0 : if (thisFurnace.AirFlowControl == AirFlowControlConstFan::UseCompressorOnFlow) {
5771 0 : if (thisFurnace.LastMode == Furnaces::ModeOfOperation::HeatingMode) {
5772 0 : if (MoistureLoad < 0.0 && thisFurnace.Humidistat &&
5773 0 : thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat) {
5774 0 : state.dataFurnaces->CompOffMassFlow = thisFurnace.MaxCoolAirMassFlow;
5775 0 : state.dataFurnaces->CompOffFlowRatio = thisFurnace.CoolingSpeedRatio;
5776 : } else {
5777 0 : state.dataFurnaces->CompOffMassFlow = thisFurnace.MaxHeatAirMassFlow;
5778 0 : state.dataFurnaces->CompOffFlowRatio = thisFurnace.HeatingSpeedRatio;
5779 : }
5780 : } else {
5781 0 : state.dataFurnaces->CompOffMassFlow = thisFurnace.MaxCoolAirMassFlow;
5782 0 : state.dataFurnaces->CompOffFlowRatio = thisFurnace.CoolingSpeedRatio;
5783 : }
5784 : // ELSE use the user specified value
5785 : } else {
5786 0 : state.dataFurnaces->CompOffMassFlow = thisFurnace.MaxNoCoolHeatAirMassFlow;
5787 0 : state.dataFurnaces->CompOffFlowRatio = thisFurnace.NoHeatCoolSpeedRatio;
5788 : }
5789 : } else {
5790 : // cycling fan mode
5791 22082 : if (state.dataFurnaces->HeatingLoad ||
5792 6860 : (thisFurnace.Humidistat && MoistureLoad < 0.0 && thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat)) {
5793 :
5794 8362 : if (thisFurnace.Humidistat && MoistureLoad < 0.0 &&
5795 0 : thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat) {
5796 0 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxCoolAirMassFlow;
5797 0 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.CoolingSpeedRatio;
5798 0 : thisFurnace.LastMode = Furnaces::ModeOfOperation::CoolingMode;
5799 : } else {
5800 8362 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxHeatAirMassFlow;
5801 8362 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.HeatingSpeedRatio;
5802 8362 : thisFurnace.LastMode = Furnaces::ModeOfOperation::HeatingMode;
5803 : }
5804 6860 : } else if (state.dataFurnaces->CoolingLoad) {
5805 6748 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxCoolAirMassFlow;
5806 6748 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.CoolingSpeedRatio;
5807 : } else {
5808 112 : state.dataFurnaces->CompOnMassFlow = 0.0;
5809 112 : state.dataFurnaces->CompOnFlowRatio = 0.0;
5810 : }
5811 15222 : state.dataFurnaces->CompOffMassFlow = 0.0;
5812 15222 : state.dataFurnaces->CompOffFlowRatio = 0.0;
5813 : }
5814 : } else { // Is a HeatOnly furnace
5815 :
5816 0 : state.dataFurnaces->CompOnMassFlow = thisFurnace.DesignMassFlowRate;
5817 0 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.HeatingSpeedRatio;
5818 0 : if (fanOp == HVAC::FanOp::Continuous) {
5819 0 : state.dataFurnaces->CompOffMassFlow = thisFurnace.MaxNoCoolHeatAirMassFlow;
5820 0 : state.dataFurnaces->CompOffFlowRatio = thisFurnace.HeatingSpeedRatio;
5821 : } else {
5822 0 : state.dataFurnaces->CompOffMassFlow = 0.0;
5823 0 : state.dataFurnaces->CompOffFlowRatio = 0.0;
5824 : }
5825 :
5826 : } // End check for heat only furnace or water-to-air heat pump
5827 :
5828 : // Set the system mass flow rates
5829 15222 : SetAverageAirFlow(state, FurnaceNum, PartLoadRatio, OnOffAirFlowRatio);
5830 15222 : }
5831 :
5832 2 : void SizeFurnace(EnergyPlusData &state, int const FurnaceNum, bool const FirstHVACIteration)
5833 : {
5834 :
5835 : // SUBROUTINE INFORMATION:
5836 : // AUTHOR Fred Buhl
5837 : // DATE WRITTEN January 2002
5838 : // MODIFIED Bereket Nigusse, May 2010, removed the autosize option for the input field supply air
5839 : // flow fraction through controlled zone.
5840 : // Bo Shen, March 2012, size the air flow rates at individual speed levels for VS WSHP
5841 : // Bo Shen, ORNL, July 2012 - added variable-speed air source heat pump cooling and heating coils, using curve-fits
5842 :
5843 : // PURPOSE OF THIS SUBROUTINE:
5844 : // This subroutine is for sizing Furnace Components for which nominal capacities
5845 : // and flow rates have not been specified in the input
5846 :
5847 : // METHODOLOGY EMPLOYED:
5848 : // Obtains heating capacities and flow rates from the zone or system sizing arrays.
5849 : // NOTE: In UNITARYSYSTEM:HEATPUMP:AIRTOAIR we are sizing the heating capacity to be
5850 : // equal to the cooling capacity. Thus the cooling and
5851 : // and heating capacities of a DX heat pump system will be identical. In real life the ARI
5852 : // heating and cooling capacities are close but not identical.
5853 :
5854 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5855 : int Iter; // iteration count
5856 : Real64 MulSpeedFlowScale; // variable speed air flow scaling factor
5857 : int IHPCoilIndex; // refer to cooling or heating coil in IHP
5858 2 : Real64 dummy(0.0);
5859 : bool anyRan;
5860 2 : EMSManager::ManageEMS(state, EMSManager::EMSCallFrom::UnitarySystemSizing, anyRan, ObjexxFCL::Optional_int_const()); // calling point
5861 :
5862 2 : state.dataSize->DXCoolCap = 0.0;
5863 2 : state.dataSize->UnitaryHeatCap = 0.0;
5864 2 : state.dataSize->SuppHeatCap = 0.0;
5865 2 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
5866 :
5867 2 : state.dataAirSystemsData->PrimaryAirSystems(state.dataSize->CurSysNum).supFanNum = thisFurnace.FanIndex;
5868 2 : state.dataAirSystemsData->PrimaryAirSystems(state.dataSize->CurSysNum).supFanType = thisFurnace.fanType;
5869 2 : state.dataSize->DataFanType = thisFurnace.fanType;
5870 2 : state.dataSize->DataFanIndex = thisFurnace.FanIndex;
5871 :
5872 2 : state.dataAirSystemsData->PrimaryAirSystems(state.dataSize->CurSysNum).supFanPlace = thisFurnace.fanPlace;
5873 :
5874 2 : if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingSingleSpeed) {
5875 2 : DXCoils::SimDXCoil(state, BlankString, HVAC::CompressorOp::On, true, thisFurnace.CoolingCoilIndex, HVAC::FanOp::Cycling, 0.0);
5876 0 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) {
5877 0 : int HXCC_Index = thisFurnace.CoolingCoilIndex;
5878 0 : int childCCType_Num = state.dataHVACAssistedCC->HXAssistedCoil(HXCC_Index).CoolingCoilType_Num;
5879 0 : if (childCCType_Num == HVAC::CoilDX_Cooling) {
5880 0 : int childCCIndex = state.dataHVACAssistedCC->HXAssistedCoil(HXCC_Index).CoolingCoilIndex;
5881 0 : if (childCCIndex < 0) {
5882 0 : ShowContinueError(state, "Occurs in sizing HeatExchangerAssistedCoolingCoil.");
5883 : }
5884 0 : auto &newCoil = state.dataCoilCoolingDX->coilCoolingDXs[childCCIndex];
5885 0 : newCoil.size(state);
5886 : }
5887 0 : HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(
5888 0 : state, BlankString, true, HVAC::CompressorOp::On, 0.0, thisFurnace.CoolingCoilIndex, HVAC::FanOp::Cycling, false, 1.0, false);
5889 0 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingWaterToAirHPSimple) {
5890 0 : WaterToAirHeatPumpSimple::SimWatertoAirHPSimple(state,
5891 : BlankString,
5892 0 : thisFurnace.CoolingCoilIndex,
5893 : thisFurnace.CoolingCoilSensDemand,
5894 : thisFurnace.CoolingCoilLatentDemand,
5895 : HVAC::FanOp::Invalid, // Using invalid to mean off?
5896 : HVAC::CompressorOp::Off,
5897 : 0.0,
5898 : FirstHVACIteration); // CoolPartLoadRatio
5899 0 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPSimple) {
5900 0 : WaterToAirHeatPumpSimple::SimWatertoAirHPSimple(state,
5901 : BlankString,
5902 0 : thisFurnace.HeatingCoilIndex,
5903 : thisFurnace.HeatingCoilSensDemand,
5904 : dummy,
5905 : HVAC::FanOp::Invalid, // using Invalid to mean off?
5906 : HVAC::CompressorOp::Off,
5907 : 0.0,
5908 : FirstHVACIteration);
5909 : }
5910 0 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingWaterToAirHPVSEquationFit ||
5911 0 : thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) {
5912 0 : if (thisFurnace.bIsIHP) {
5913 0 : IntegratedHeatPump::SizeIHP(state, thisFurnace.CoolingCoilIndex);
5914 0 : IHPCoilIndex = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SCCoilIndex;
5915 0 : thisFurnace.NumOfSpeedCooling = state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).NumOfSpeeds;
5916 0 : MulSpeedFlowScale = state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).RatedAirVolFlowRate /
5917 0 : state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex)
5918 0 : .MSRatedAirVolFlowRate(state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).NormSpedLevel);
5919 0 : state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).CoolVolFlowScale = MulSpeedFlowScale;
5920 : } else {
5921 0 : VariableSpeedCoils::SimVariableSpeedCoils(state,
5922 : BlankString,
5923 0 : thisFurnace.CoolingCoilIndex,
5924 : HVAC::FanOp::Invalid, // USing Invalid for off?
5925 : HVAC::CompressorOp::Off,
5926 : 0.0,
5927 : 1,
5928 : 0.0,
5929 : 0.0,
5930 : 0.0,
5931 : 0.0); // conduct the sizing operation in the VS WSHP
5932 0 : thisFurnace.NumOfSpeedCooling = state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.CoolingCoilIndex).NumOfSpeeds;
5933 0 : MulSpeedFlowScale =
5934 0 : state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.CoolingCoilIndex).RatedAirVolFlowRate /
5935 0 : state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.CoolingCoilIndex)
5936 0 : .MSRatedAirVolFlowRate(state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.CoolingCoilIndex).NormSpedLevel);
5937 0 : IHPCoilIndex = thisFurnace.CoolingCoilIndex;
5938 : }
5939 :
5940 0 : for (Iter = 1; Iter <= thisFurnace.NumOfSpeedCooling; ++Iter) {
5941 0 : thisFurnace.CoolVolumeFlowRate(Iter) =
5942 0 : state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).MSRatedAirVolFlowRate(Iter) * MulSpeedFlowScale;
5943 0 : thisFurnace.CoolMassFlowRate(Iter) =
5944 0 : state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).MSRatedAirMassFlowRate(Iter) * MulSpeedFlowScale;
5945 0 : thisFurnace.MSCoolingSpeedRatio(Iter) =
5946 0 : state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).MSRatedAirVolFlowRate(Iter) /
5947 0 : state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).MSRatedAirVolFlowRate(thisFurnace.NumOfSpeedCooling);
5948 : }
5949 :
5950 0 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPVSEquationFit ||
5951 0 : thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed) {
5952 :
5953 0 : if (thisFurnace.bIsIHP) {
5954 0 : IntegratedHeatPump::SizeIHP(state, thisFurnace.CoolingCoilIndex);
5955 0 : IHPCoilIndex = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SHCoilIndex;
5956 0 : thisFurnace.NumOfSpeedHeating = state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).NumOfSpeeds;
5957 0 : MulSpeedFlowScale = state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).RatedAirVolFlowRate /
5958 0 : state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex)
5959 0 : .MSRatedAirVolFlowRate(state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).NormSpedLevel);
5960 0 : state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).HeatVolFlowScale = MulSpeedFlowScale;
5961 : } else {
5962 0 : VariableSpeedCoils::SimVariableSpeedCoils(state,
5963 : BlankString,
5964 0 : thisFurnace.HeatingCoilIndex,
5965 : HVAC::FanOp::Invalid, // Invalid for off?
5966 : HVAC::CompressorOp::Off,
5967 : 0.0,
5968 : 1,
5969 : 0.0,
5970 : 0.0,
5971 : 0.0,
5972 : 0.0); // conduct the sizing operation in the VS WSHP
5973 0 : thisFurnace.NumOfSpeedHeating = state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.HeatingCoilIndex).NumOfSpeeds;
5974 0 : MulSpeedFlowScale =
5975 0 : state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.HeatingCoilIndex).RatedAirVolFlowRate /
5976 0 : state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.HeatingCoilIndex)
5977 0 : .MSRatedAirVolFlowRate(state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.HeatingCoilIndex).NormSpedLevel);
5978 0 : IHPCoilIndex = thisFurnace.HeatingCoilIndex;
5979 : }
5980 :
5981 0 : for (Iter = 1; Iter <= thisFurnace.NumOfSpeedHeating; ++Iter) {
5982 0 : thisFurnace.HeatVolumeFlowRate(Iter) =
5983 0 : state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).MSRatedAirVolFlowRate(Iter) * MulSpeedFlowScale;
5984 0 : thisFurnace.HeatMassFlowRate(Iter) =
5985 0 : state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).MSRatedAirMassFlowRate(Iter) * MulSpeedFlowScale;
5986 0 : thisFurnace.MSHeatingSpeedRatio(Iter) =
5987 0 : state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).MSRatedAirVolFlowRate(Iter) /
5988 0 : state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).MSRatedAirVolFlowRate(thisFurnace.NumOfSpeedHeating);
5989 : }
5990 : }
5991 :
5992 0 : if (thisFurnace.NumOfSpeedHeating > 0) {
5993 0 : thisFurnace.IdleMassFlowRate = min(thisFurnace.HeatMassFlowRate(1), thisFurnace.CoolMassFlowRate(1));
5994 0 : thisFurnace.IdleSpeedRatio = min(thisFurnace.MSHeatingSpeedRatio(1), thisFurnace.MSCoolingSpeedRatio(1));
5995 0 : thisFurnace.IdleVolumeAirRate = min(thisFurnace.HeatVolumeFlowRate(1), thisFurnace.CoolVolumeFlowRate(1));
5996 : } else {
5997 0 : thisFurnace.IdleMassFlowRate = thisFurnace.CoolMassFlowRate(1);
5998 0 : thisFurnace.IdleSpeedRatio = thisFurnace.MSCoolingSpeedRatio(1);
5999 0 : thisFurnace.IdleVolumeAirRate = thisFurnace.CoolVolumeFlowRate(1);
6000 : }
6001 :
6002 0 : if (thisFurnace.fanOp == HVAC::FanOp::Continuous) {
6003 0 : thisFurnace.MaxNoCoolHeatAirVolFlow = thisFurnace.IdleVolumeAirRate;
6004 0 : thisFurnace.MaxNoCoolHeatAirMassFlow = thisFurnace.IdleMassFlowRate;
6005 0 : thisFurnace.NoHeatCoolSpeedRatio = thisFurnace.IdleSpeedRatio;
6006 : }
6007 : }
6008 :
6009 2 : if (thisFurnace.DesignFanVolFlowRate == DataSizing::AutoSize) {
6010 :
6011 2 : if (state.dataSize->CurSysNum > 0) {
6012 :
6013 2 : CheckSysSizing(state, HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name);
6014 2 : if (state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesMainVolFlow >= HVAC::SmallAirVolFlow) {
6015 2 : thisFurnace.DesignFanVolFlowRate = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesMainVolFlow;
6016 : } else {
6017 0 : thisFurnace.DesignFanVolFlowRate = 0.0;
6018 : }
6019 :
6020 2 : if (thisFurnace.DesignFanVolFlowRateEMSOverrideOn) {
6021 0 : thisFurnace.DesignFanVolFlowRate = thisFurnace.DesignFanVolFlowRateEMSOverrideValue;
6022 : }
6023 :
6024 4 : BaseSizer::reportSizerOutput(state,
6025 2 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6026 : thisFurnace.Name,
6027 : "Supply Air Flow Rate [m3/s]",
6028 : thisFurnace.DesignFanVolFlowRate);
6029 : }
6030 : }
6031 :
6032 2 : if (thisFurnace.MaxHeatAirVolFlow == DataSizing::AutoSize) {
6033 :
6034 2 : if (state.dataSize->CurSysNum > 0) {
6035 :
6036 2 : CheckSysSizing(state, HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name);
6037 2 : if (state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesMainVolFlow >= HVAC::SmallAirVolFlow) {
6038 2 : thisFurnace.MaxHeatAirVolFlow = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesMainVolFlow;
6039 : } else {
6040 0 : thisFurnace.MaxHeatAirVolFlow = 0.0;
6041 : }
6042 :
6043 2 : if (thisFurnace.MaxHeatAirVolFlowEMSOverrideOn) {
6044 0 : thisFurnace.MaxHeatAirVolFlow = thisFurnace.MaxHeatAirVolFlowEMSOverrideValue;
6045 : }
6046 4 : BaseSizer::reportSizerOutput(state,
6047 2 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6048 : thisFurnace.Name,
6049 : "Supply Air Flow Rate During Heating Operation [m3/s]",
6050 : thisFurnace.MaxHeatAirVolFlow);
6051 : }
6052 : }
6053 :
6054 2 : if (thisFurnace.MaxCoolAirVolFlow == DataSizing::AutoSize) {
6055 :
6056 2 : if (state.dataSize->CurSysNum > 0) {
6057 :
6058 2 : CheckSysSizing(state, HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name);
6059 2 : if (state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesMainVolFlow >= HVAC::SmallAirVolFlow) {
6060 2 : thisFurnace.MaxCoolAirVolFlow = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesMainVolFlow;
6061 : } else {
6062 0 : thisFurnace.MaxCoolAirVolFlow = 0.0;
6063 : }
6064 :
6065 2 : if (thisFurnace.MaxCoolAirVolFlowEMSOverrideOn) {
6066 0 : thisFurnace.MaxCoolAirVolFlow = thisFurnace.MaxCoolAirVolFlowEMSOverrideValue;
6067 : }
6068 :
6069 4 : BaseSizer::reportSizerOutput(state,
6070 2 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6071 : thisFurnace.Name,
6072 : "Supply Air Flow Rate During Cooling Operation [m3/s]",
6073 : thisFurnace.MaxCoolAirVolFlow);
6074 : }
6075 : }
6076 :
6077 2 : if (thisFurnace.MaxNoCoolHeatAirVolFlow == DataSizing::AutoSize) {
6078 :
6079 1 : if (state.dataSize->CurSysNum > 0) {
6080 :
6081 1 : CheckSysSizing(state, HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name);
6082 1 : if (state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesMainVolFlow >= HVAC::SmallAirVolFlow) {
6083 1 : thisFurnace.MaxNoCoolHeatAirVolFlow = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesMainVolFlow;
6084 : } else {
6085 0 : thisFurnace.MaxNoCoolHeatAirVolFlow = 0.0;
6086 : }
6087 :
6088 1 : if (thisFurnace.MaxNoCoolHeatAirVolFlowEMSOverrideOn) {
6089 0 : thisFurnace.MaxNoCoolHeatAirVolFlow = thisFurnace.MaxNoCoolHeatAirVolFlowEMSOverrideValue;
6090 : }
6091 :
6092 2 : BaseSizer::reportSizerOutput(state,
6093 1 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6094 : thisFurnace.Name,
6095 : "Supply Air Flow Rate When No Cooling or Heating is Needed [m3/s]",
6096 : thisFurnace.MaxNoCoolHeatAirVolFlow);
6097 : }
6098 : }
6099 :
6100 2 : if (thisFurnace.DesignHeatingCapacity == DataSizing::AutoSize) {
6101 :
6102 2 : if (state.dataSize->CurSysNum > 0) {
6103 :
6104 2 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir ||
6105 0 : thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir) {
6106 :
6107 2 : CheckSysSizing(state, HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name);
6108 :
6109 2 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPSimple) {
6110 0 : thisFurnace.DesignHeatingCapacity =
6111 0 : state.dataWaterToAirHeatPumpSimple->SimpleWatertoAirHP(thisFurnace.HeatingCoilIndex).RatedCapHeat;
6112 : } else {
6113 2 : thisFurnace.DesignHeatingCapacity = state.dataSize->DXCoolCap;
6114 : }
6115 :
6116 : } else {
6117 :
6118 0 : CheckSysSizing(state, HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name);
6119 :
6120 0 : thisFurnace.DesignHeatingCapacity = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).HeatCap;
6121 : }
6122 :
6123 2 : if (thisFurnace.DesignHeatingCapacity < HVAC::SmallLoad) {
6124 0 : thisFurnace.DesignHeatingCapacity = 0.0;
6125 : }
6126 :
6127 4 : BaseSizer::reportSizerOutput(state,
6128 2 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6129 : thisFurnace.Name,
6130 : "Nominal Heating Capacity [W]",
6131 : thisFurnace.DesignHeatingCapacity);
6132 : }
6133 : }
6134 :
6135 2 : if (thisFurnace.DesignCoolingCapacity == DataSizing::AutoSize) {
6136 :
6137 2 : if (state.dataSize->CurSysNum > 0) {
6138 :
6139 2 : CheckSysSizing(state, HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name);
6140 2 : if (state.dataSize->DXCoolCap >= HVAC::SmallLoad) {
6141 2 : thisFurnace.DesignCoolingCapacity = state.dataSize->DXCoolCap;
6142 : } else {
6143 0 : thisFurnace.DesignCoolingCapacity = 0.0;
6144 : }
6145 4 : BaseSizer::reportSizerOutput(state,
6146 2 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6147 : thisFurnace.Name,
6148 : "Nominal Cooling Capacity [W]",
6149 : thisFurnace.DesignCoolingCapacity);
6150 : }
6151 : }
6152 :
6153 2 : if (thisFurnace.DesignMaxOutletTemp == DataSizing::AutoSize) {
6154 :
6155 1 : if (state.dataSize->CurSysNum > 0) {
6156 :
6157 1 : CheckSysSizing(state, HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name);
6158 1 : thisFurnace.DesignMaxOutletTemp = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).HeatSupTemp;
6159 2 : BaseSizer::reportSizerOutput(state,
6160 1 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6161 : thisFurnace.Name,
6162 : "Maximum Supply Air Temperature from Supplemental Heater [C]",
6163 : thisFurnace.DesignMaxOutletTemp);
6164 : }
6165 : }
6166 :
6167 2 : if (thisFurnace.DesignSuppHeatingCapacity == DataSizing::AutoSize) {
6168 :
6169 1 : if (state.dataSize->CurSysNum > 0) {
6170 :
6171 1 : CheckSysSizing(state, HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name);
6172 1 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir ||
6173 0 : thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir) {
6174 : // set the supplemental heating capacity to the actual heating load
6175 1 : thisFurnace.DesignSuppHeatingCapacity = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).HeatCap;
6176 : // if reheat needed for humidity control, make sure supplemental heating is at least as big
6177 : // as the cooling capacity
6178 1 : if (thisFurnace.Humidistat && thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat) {
6179 0 : thisFurnace.DesignSuppHeatingCapacity = max(thisFurnace.DesignSuppHeatingCapacity, thisFurnace.DesignCoolingCapacity);
6180 0 : if (thisFurnace.DesignSuppHeatingCapacity < HVAC::SmallLoad) {
6181 0 : thisFurnace.DesignSuppHeatingCapacity = 0.0;
6182 : }
6183 : }
6184 :
6185 : } else {
6186 :
6187 0 : if (thisFurnace.Humidistat && thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat) {
6188 0 : thisFurnace.DesignSuppHeatingCapacity = thisFurnace.DesignCoolingCapacity;
6189 : } else {
6190 0 : thisFurnace.DesignSuppHeatingCapacity = 0.0;
6191 : }
6192 : }
6193 :
6194 2 : BaseSizer::reportSizerOutput(state,
6195 1 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6196 : thisFurnace.Name,
6197 : "Supplemental Heating Coil Nominal Capacity [W]",
6198 : thisFurnace.DesignSuppHeatingCapacity);
6199 : }
6200 : }
6201 :
6202 2 : state.dataSize->UnitaryHeatCap = thisFurnace.DesignHeatingCapacity;
6203 2 : state.dataSize->SuppHeatCap = thisFurnace.DesignSuppHeatingCapacity;
6204 2 : }
6205 :
6206 : // End Initialization Section of the Module
6207 : //******************************************************************************
6208 :
6209 : // Beginning of Update subroutines for the Furnace Module
6210 : // *****************************************************************************
6211 :
6212 0 : void CalcNewZoneHeatOnlyFlowRates(EnergyPlusData &state,
6213 : int const FurnaceNum, // Index to furnace
6214 : bool const FirstHVACIteration, // Iteration flag
6215 : Real64 const ZoneLoad, // load to be met by furnace (W)
6216 : Real64 &HeatCoilLoad, // actual load passed to heating coil (W)
6217 : Real64 &OnOffAirFlowRatio // ratio of coil on to coil off air flow rate
6218 : )
6219 : {
6220 : // SUBROUTINE INFORMATION:
6221 : // AUTHOR Richard Liesen
6222 : // DATE WRITTEN Feb 2001
6223 : // MODIFIED Don Shirey and R. Raustad, Mar 2001 & Mar 2003
6224 :
6225 : // PURPOSE OF THIS SUBROUTINE:
6226 : // This subroutine updates the coil outlet nodes by simulating a heat-only
6227 : // furnace or unitary system.
6228 :
6229 : // METHODOLOGY EMPLOYED:
6230 : // Determine the operating PLR to meet the zone sensible load.
6231 :
6232 : // SUBROUTINE PARAMETER DEFINITIONS:
6233 0 : int constexpr MaxIter(15); // maximum number of iterations
6234 0 : Real64 constexpr MinPLR(0.0); // minimum part load ratio allowed
6235 :
6236 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
6237 0 : Real64 Error(1.0);
6238 : Real64 SystemSensibleLoad; // Sensible load to be met by furnace (W)
6239 : Real64 FullSensibleOutput; // Full sensible output of furnace (W)
6240 : Real64 FullLatentOutput; // Full latent output of furnace = 0 (W)
6241 : Real64 NoSensibleOutput; // Sensible output of furnace with no heating allowed (W)
6242 : Real64 NoLatentOutput; // Latent output of furnace = 0 (W)
6243 : Real64 PartLoadRatio; // Part load ratio of furnace
6244 : Real64 HeatErrorToler; // Error tolerance in heating mode
6245 : Real64 IterRelax; // Relaxation factor for iterations
6246 : Real64 ActualSensibleOutput; // Actual furnace sensible capacity
6247 : Real64 ActualLatentOutput; // Actual furnace latent capacity = 0
6248 : Real64 deltaT; // Heater outlet temp minus design heater outlet temp
6249 :
6250 0 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
6251 : // Retrieve the load on the controlled zone
6252 0 : auto &furnaceInNode = state.dataLoopNodes->Node(thisFurnace.FurnaceInletNodeNum);
6253 0 : auto const &furnaceOutNode = state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum);
6254 0 : int ControlZoneNode = thisFurnace.NodeNumOfControlledZone;
6255 0 : HVAC::FanOp fanOp = thisFurnace.fanOp; // fan operating mode
6256 0 : thisFurnace.MdotFurnace = thisFurnace.DesignMassFlowRate;
6257 0 : thisFurnace.CoolPartLoadRatio = 0.0;
6258 :
6259 : // Calculate the Cp Air of zone
6260 0 : Real64 cpair = Psychrometrics::PsyCpAirFnW(state.dataLoopNodes->Node(ControlZoneNode).HumRat);
6261 :
6262 0 : if (FirstHVACIteration) {
6263 0 : HeatCoilLoad = ZoneLoad;
6264 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
6265 : } else {
6266 : // If Furnace runs then set HeatCoilLoad on Heating Coil and the Mass Flow
6267 0 : if ((thisFurnace.availSched->getCurrentVal() > 0.0) && (furnaceInNode.MassFlowRate > 0.0) && (state.dataFurnaces->HeatingLoad)) {
6268 :
6269 0 : furnaceInNode.MassFlowRate = thisFurnace.MdotFurnace;
6270 0 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity;
6271 0 : SystemSensibleLoad = ZoneLoad;
6272 :
6273 : // Get no load result
6274 0 : if (fanOp == HVAC::FanOp::Cycling) {
6275 0 : furnaceInNode.MassFlowRate = 0.0;
6276 : }
6277 0 : if (fanOp == HVAC::FanOp::Continuous) {
6278 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0; // The on/off fan will not cycle, so set part-load fraction = 1
6279 : }
6280 :
6281 : // Set the inlet mass flow rate based on user specified coil OFF flow rate
6282 0 : PartLoadRatio = 0.0;
6283 0 : SetAverageAirFlow(state, FurnaceNum, PartLoadRatio, OnOffAirFlowRatio);
6284 :
6285 0 : CalcFurnaceOutput(state,
6286 : FurnaceNum,
6287 : FirstHVACIteration,
6288 : fanOp,
6289 : HVAC::CompressorOp::On,
6290 : 0.0,
6291 : 0.0,
6292 : 0.0,
6293 : 0.0,
6294 : NoSensibleOutput,
6295 : NoLatentOutput,
6296 : OnOffAirFlowRatio,
6297 : false);
6298 :
6299 0 : furnaceInNode.MassFlowRate = thisFurnace.MdotFurnace;
6300 :
6301 : // Set fan part-load fraction equal to 1 while getting full load result
6302 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
6303 0 : OnOffAirFlowRatio = 1.0;
6304 :
6305 : // Get full load result
6306 0 : CalcFurnaceOutput(state,
6307 : FurnaceNum,
6308 : FirstHVACIteration,
6309 : fanOp,
6310 : HVAC::CompressorOp::On,
6311 : 0.0,
6312 : 1.0,
6313 : HeatCoilLoad,
6314 : 0.0,
6315 : FullSensibleOutput,
6316 : FullLatentOutput,
6317 : OnOffAirFlowRatio,
6318 : false);
6319 :
6320 : // Since we are heating, we expect FullSensibleOutput to be > 0 and FullSensibleOutput > NoSensibleOutput
6321 : // Check that this is the case; if not set PartLoadRatio = 0.0d0 (off) and return
6322 :
6323 0 : if (FullSensibleOutput > NoSensibleOutput) {
6324 : PartLoadRatio =
6325 0 : max(MinPLR, min(1.0, std::abs(SystemSensibleLoad - NoSensibleOutput) / std::abs(FullSensibleOutput - NoSensibleOutput)));
6326 0 : if (fanOp == HVAC::FanOp::Cycling) {
6327 0 : furnaceInNode.MassFlowRate = thisFurnace.MdotFurnace * PartLoadRatio;
6328 0 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity * PartLoadRatio;
6329 : } else { // FanOp::Continuous
6330 0 : if (furnaceOutNode.Temp > thisFurnace.DesignMaxOutletTemp) {
6331 0 : deltaT = furnaceOutNode.Temp - thisFurnace.DesignMaxOutletTemp;
6332 0 : if (HeatCoilLoad > thisFurnace.DesignHeatingCapacity) {
6333 0 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity;
6334 : }
6335 0 : HeatCoilLoad -= furnaceInNode.MassFlowRate * cpair * deltaT;
6336 : } else {
6337 0 : HeatCoilLoad = SystemSensibleLoad - NoSensibleOutput;
6338 : }
6339 : }
6340 :
6341 : // Calculate the part load ratio through iteration
6342 0 : HeatErrorToler = thisFurnace.HeatingConvergenceTolerance; // Error tolerance for convergence from input deck
6343 0 : Error = 1.0; // initialize error value for comparison against tolerance
6344 0 : state.dataFurnaces->Iter = 0; // initialize iteration counter
6345 0 : IterRelax = 0.9; // relaxation factor for iterations
6346 0 : while (state.dataFurnaces->Iter <= MaxIter) {
6347 :
6348 0 : if (fanOp == HVAC::FanOp::Cycling) {
6349 0 : furnaceInNode.MassFlowRate = thisFurnace.MdotFurnace * PartLoadRatio;
6350 : }
6351 0 : CalcFurnaceOutput(state,
6352 : FurnaceNum,
6353 : FirstHVACIteration,
6354 : fanOp,
6355 : HVAC::CompressorOp::On,
6356 : 0.0,
6357 : PartLoadRatio,
6358 : HeatCoilLoad,
6359 : 0.0,
6360 : ActualSensibleOutput,
6361 : ActualLatentOutput,
6362 : OnOffAirFlowRatio,
6363 : false);
6364 :
6365 0 : if (SystemSensibleLoad != 0.0) {
6366 0 : Error = (SystemSensibleLoad - ActualSensibleOutput) / (SystemSensibleLoad);
6367 : }
6368 0 : if (std::abs(Error) <= HeatErrorToler) {
6369 0 : break;
6370 : }
6371 0 : PartLoadRatio = max(
6372 : MinPLR,
6373 : min(1.0,
6374 0 : PartLoadRatio + IterRelax * (SystemSensibleLoad - ActualSensibleOutput) / (FullSensibleOutput - NoSensibleOutput)));
6375 :
6376 : // limit the heating coil outlet air temperature to DesignMaxOutletTemp
6377 0 : if (furnaceOutNode.Temp > thisFurnace.DesignMaxOutletTemp) {
6378 0 : deltaT = furnaceOutNode.Temp - thisFurnace.DesignMaxOutletTemp;
6379 0 : if (HeatCoilLoad > thisFurnace.DesignHeatingCapacity) {
6380 0 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity;
6381 : }
6382 0 : HeatCoilLoad -= furnaceInNode.MassFlowRate * cpair * deltaT;
6383 0 : CalcFurnaceOutput(state,
6384 : FurnaceNum,
6385 : FirstHVACIteration,
6386 : fanOp,
6387 : HVAC::CompressorOp::On,
6388 : 0.0,
6389 : PartLoadRatio,
6390 : HeatCoilLoad,
6391 : 0.0,
6392 : ActualSensibleOutput,
6393 : ActualLatentOutput,
6394 : OnOffAirFlowRatio,
6395 : false);
6396 :
6397 0 : if (SystemSensibleLoad != 0.0) {
6398 0 : Error = (SystemSensibleLoad - ActualSensibleOutput) / (SystemSensibleLoad);
6399 : }
6400 0 : PartLoadRatio = max(MinPLR,
6401 : min(1.0,
6402 0 : PartLoadRatio + IterRelax * (SystemSensibleLoad - ActualSensibleOutput) /
6403 0 : (FullSensibleOutput - NoSensibleOutput)));
6404 : } else {
6405 0 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity * PartLoadRatio;
6406 : }
6407 :
6408 0 : if (PartLoadRatio == MinPLR) {
6409 0 : break;
6410 : }
6411 0 : if (PartLoadRatio == 1.0) {
6412 0 : break;
6413 : }
6414 0 : ++state.dataFurnaces->Iter;
6415 0 : if (state.dataFurnaces->Iter == 7) {
6416 0 : IterRelax = 0.7;
6417 : }
6418 0 : if (state.dataFurnaces->Iter == 15) {
6419 0 : IterRelax = 0.4;
6420 : }
6421 : }
6422 :
6423 0 : if (state.dataFurnaces->Iter > MaxIter) {
6424 0 : if (thisFurnace.HeatingMaxIterIndex2 == 0) {
6425 0 : ShowWarningMessage(state,
6426 0 : format("{} \"{}\" -- Exceeded max heating iterations ({}) while adjusting furnace runtime.",
6427 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6428 0 : thisFurnace.Name,
6429 : MaxIter));
6430 0 : ShowContinueErrorTimeStamp(state, "");
6431 : }
6432 0 : ShowRecurringWarningErrorAtEnd(state,
6433 0 : format("{} \"{}\" -- Exceeded max heating iterations error continues...",
6434 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6435 0 : thisFurnace.Name),
6436 0 : thisFurnace.HeatingMaxIterIndex2);
6437 : }
6438 :
6439 : } else { // ELSE from IF(FullSensibleOutput.GT.NoSensibleOutput)THEN above
6440 : // Set part load ratio to 1 and run heater at design heating capacity
6441 0 : PartLoadRatio = 1.0;
6442 0 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity;
6443 : }
6444 : // Set the final results
6445 : // IF (fanOp .EQ. FanOp::Cycling) THEN
6446 : // Furnace(FurnaceNum)%MdotFurnace = Furnace(FurnaceNum)%MdotFurnace * PartLoadRatio
6447 : // END IF
6448 0 : thisFurnace.MdotFurnace = furnaceInNode.MassFlowRate;
6449 :
6450 0 : } else if ((thisFurnace.availSched->getCurrentVal() > 0.0) && (furnaceInNode.MassFlowRate > 0.0) && (fanOp == HVAC::FanOp::Continuous)) {
6451 0 : HeatCoilLoad = 0.0;
6452 : } else { // no heating and no flow
6453 0 : thisFurnace.MdotFurnace = 0.0;
6454 0 : HeatCoilLoad = 0.0;
6455 : } // End of the Scheduled Furnace If block
6456 :
6457 : } // End of the FirstHVACIteration control of the mass flow If block
6458 :
6459 : // Set the fan inlet node flow rates
6460 0 : furnaceInNode.MassFlowRateMaxAvail = thisFurnace.MdotFurnace;
6461 0 : furnaceInNode.MassFlowRate = thisFurnace.MdotFurnace;
6462 0 : }
6463 :
6464 15225 : void CalcNewZoneHeatCoolFlowRates(EnergyPlusData &state,
6465 : int const FurnaceNum,
6466 : bool const FirstHVACIteration,
6467 : HVAC::CompressorOp const compressorOp, // compressor operation flag (1=On, 0=Off)
6468 : Real64 const ZoneLoad, // the control zone load (watts)
6469 : Real64 const MoistureLoad, // the control zone latent load (watts)
6470 : Real64 &HeatCoilLoad, // Heating load to be met by heating coil ( excluding heat pump DX coil)
6471 : Real64 &ReheatCoilLoad, // Heating load to be met by reheat coil using hstat (excluding HP DX coil)
6472 : Real64 &OnOffAirFlowRatio, // Ratio of compressor ON air flow to AVERAGE air flow over time step
6473 : bool &HXUnitOn // flag to control HX based on zone moisture load
6474 : )
6475 : {
6476 : // SUBROUTINE INFORMATION:
6477 : // AUTHOR Richard Liesen
6478 : // DATE WRITTEN Feb 2001
6479 : // MODIFIED R. Raustad and D. Shirey, Feb/Mar/Sept/Oct/Dec 2001, Jan/Oct 2002
6480 : // RE-ENGINEERED R. Raustad, Feb. 2005 (added RegulaFalsi for iteration technique)
6481 :
6482 : // PURPOSE OF THIS SUBROUTINE:
6483 : // This subroutine updates the coil outlet nodes.
6484 :
6485 : // METHODOLOGY EMPLOYED:
6486 : // Determine the operating PLR to meet the zone sensible load. If a humidistat is specified, determine
6487 : // the operating PLR (greater of the sensible and latent PLR) to meet the zone SENSIBLE load
6488 : // (Multimode dehumidification control) or zone LATENT load (CoolReheat dehumidification control).
6489 : // For dehumidification control type COOLREHEAT, both a sensible and latent PLR may exist for a
6490 : // single time step (heating and dehumidification can occur). For all other system types,
6491 : // only a single PLR is allowed for any given time step.
6492 : // Order of simulation depends on dehumidification control option as described below.
6493 : // Dehumidification control options:
6494 : // Dehumidification Control NONE: Cooling performance is simulated first and then heating performance. If a HX
6495 : // assisted cooling coil is selected, the HX is always active.
6496 : // Dehumidification Control COOLREHEAT: Continuous Fan Operation:
6497 : // For cooling operation, the sensible and latent capacities are calculated to
6498 : // meet the thermostat setpoint. If a HX assisted cooling coil is selected,
6499 : // the HX is always active. If the latent load is not met by operating the
6500 : // system at the sensible PLR, a new PLR is calculated to meet the humidistat
6501 : // setpoint. The reheat coil load is then calculated to meet the HEATING
6502 : // setpoint temperature.
6503 : // Cycling Fan Operation:
6504 : // The heating part-load ratio is calculated first. Since the fan will be
6505 : // controlled at the higher of the heating or cooling PLR's, a ratio of the
6506 : // cooling to heating PLR is used to pass to the cooling coil (MAX=1). This allows
6507 : // the cooling coil to operate at the heating PLR when the heating PLR is
6508 : // higher than the cooling PLR. The sensible and latent capacities are then
6509 : // calculated to meet the thermostat setpoint.
6510 : // If a HX assisted cooling coil is selected, the HX is always active.
6511 : // If the latent load is not met by operating the system at the sensible PLR,
6512 : // a new PLR is calculated to meet the humidistat setpoint.
6513 : // The reheat coil load is then calculated to meet the HEATING setpoint temperature.
6514 : // Dehumidification Control MULTIMODE: For cooling operation, the sensible and latent capacities are calculated to
6515 : // meet the thermostat setpoint. If a HX assisted cooling coil is selected,
6516 : // the HX is off for this calculation. If the latent load is not met by operating
6517 : // the system at the sensible PLR, a new PLR is calculated with the HX operating
6518 : // and the target is the thermostat setpoint. Humidity is not controlled in this
6519 : // mode. No reheat coil is used in this configuration.
6520 : // Note: A supplemental heater augments the heating capacity for air-to-air heat pumps.
6521 : // A reheat coil is used for the HeatCool furnace/unitarysystem to offset the sensible cooling when the
6522 : // dehumidification control type is COOLREHEAT. Both the supplemental and reheat heating coil load is calculated
6523 : // in the Calc routines. The actual simulation of these coils is performed in the SimFurnace routine (i.e. the
6524 : // supplemental and reheat coil loads are passed as 0 to CalcFurnaceOutput).
6525 :
6526 : // SUBROUTINE PARAMETER DEFINITIONS:
6527 15225 : int constexpr MaxIter(100); // maximum number of iterations
6528 15225 : Real64 constexpr MinPLR(0.0); // minimum part load ratio allowed
6529 :
6530 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
6531 : Real64 SystemMoistureLoad; // Total latent load to be removed by furnace/unitary system
6532 : Real64 deltaT; // Temperature rise across heating coil (C)
6533 : Real64 TempOutHeatingCoil; // Temperature leaving heating coil (C)
6534 : Real64 FullSensibleOutput; // Full sensible output of AC (W)
6535 : Real64 FullLatentOutput; // Full latent output of AC (W)
6536 : Real64 NoCoolOutput; // Sensible output of AC with no cooling allowed (W)
6537 : Real64 NoHeatOutput; // Sensible output of heater with no heating allowed (W)
6538 : Real64 NoLatentOutput; // Latent output of AC with no cooling allowed (W)
6539 : Real64 CoolErrorToler; // Error tolerance in cooling mode
6540 : Real64 HeatErrorToler; // Error tolerance in heating mode
6541 : Real64 ActualSensibleOutput; // Actual furnace sensible capacity
6542 : Real64 ActualLatentOutput; // Actual furnace latent capacity
6543 : Real64 PartLoadRatio; // Part load ratio (greater of sensible or latent part load ratio for cooling,
6544 : // or heating PLR)
6545 : Real64 LatentPartLoadRatio; // Part load ratio to meet dehumidification load
6546 : Real64 TempCoolOutput; // Temporary Sensible output of AC while iterating on PLR (W)
6547 : Real64 TempHeatOutput; // Temporary Sensible output of heating coil while iterating on PLR (W)
6548 : Real64 TempLatentOutput; // Temporary Latent output of AC at increasing PLR (W)
6549 : // ! (Temp variables are used to find min PLR for positive latent removal)
6550 : Real64 TempMinPLR; // Temporary min latent PLR when hum control is required and iter is exceeded
6551 : Real64 TempMinPLR2; // Temporary min latent PLR when cyc fan hum control is required and iter is exceeded
6552 : Real64 TempMaxPLR; // Temporary max latent PLR when hum control is required and iter is exceeded
6553 : Real64 QToHeatSetPt; // Load required to meet heating setpoint temp (>0 is a heating load)
6554 : Real64 CoolingHeatingPLRRatio; // ratio of cooling to heating PLR (MAX=1). Used in heating mode.
6555 : Real64 HeatingSensibleOutput;
6556 : Real64 HeatingLatentOutput;
6557 : Real64 OutdoorDryBulbTemp; // secondary coil (condenser) entering dry bulb temperature
6558 :
6559 15225 : Real64 &SystemSensibleLoad = state.dataFurnaces->SystemSensibleLoad;
6560 15225 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
6561 : // Set local variables
6562 15225 : int FurnaceOutletNode = thisFurnace.FurnaceOutletNodeNum;
6563 15225 : int FurnaceInletNode = thisFurnace.FurnaceInletNodeNum;
6564 15225 : int ControlZoneNode = thisFurnace.NodeNumOfControlledZone;
6565 15225 : HVAC::FanOp fanOp = thisFurnace.fanOp; // fan operating mode
6566 15225 : bool HumControl = false;
6567 : // Calculate the Cp Air of zone
6568 15225 : Real64 cpair = Psychrometrics::PsyCpAirFnW(state.dataLoopNodes->Node(ControlZoneNode).HumRat);
6569 15225 : NoHeatOutput = 0.0;
6570 15225 : SystemSensibleLoad = 0.0;
6571 15225 : ReheatCoilLoad = 0.0;
6572 15225 : HeatCoilLoad = 0.0;
6573 15225 : ReheatCoilLoad = 0.0;
6574 15225 : PartLoadRatio = 0.0;
6575 :
6576 15225 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir) {
6577 15222 : if (state.dataDXCoils->DXCoil(thisFurnace.HeatingCoilIndex)
6578 15222 : .IsSecondaryDXCoilInZone) { // assumes compressor is in same location as secondary coil
6579 0 : OutdoorDryBulbTemp =
6580 0 : state.dataZoneTempPredictorCorrector->zoneHeatBalance(state.dataDXCoils->DXCoil(thisFurnace.HeatingCoilIndex).SecZonePtr).ZT;
6581 15222 : } else if (state.dataDXCoils->DXCoil(thisFurnace.CoolingCoilIndex).IsSecondaryDXCoilInZone) {
6582 0 : OutdoorDryBulbTemp =
6583 0 : state.dataZoneTempPredictorCorrector->zoneHeatBalance(state.dataDXCoils->DXCoil(thisFurnace.CoolingCoilIndex).SecZonePtr).ZT;
6584 : } else {
6585 15222 : if (thisFurnace.CondenserNodeNum > 0) {
6586 0 : OutdoorDryBulbTemp = state.dataLoopNodes->Node(thisFurnace.CondenserNodeNum).Temp;
6587 : } else {
6588 15222 : OutdoorDryBulbTemp = state.dataEnvrn->OutDryBulbTemp;
6589 : }
6590 : }
6591 : } else {
6592 3 : OutdoorDryBulbTemp = state.dataEnvrn->OutDryBulbTemp;
6593 : }
6594 15225 : if (FirstHVACIteration) {
6595 : // Set selected values during first HVAC iteration
6596 :
6597 : // Init for heating
6598 4847 : if (state.dataFurnaces->HeatingLoad) {
6599 3103 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir ||
6600 0 : (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir && thisFurnace.WatertoAirHPType == WAHPCoilType::Simple)) {
6601 3103 : thisFurnace.HeatPartLoadRatio = 1.0;
6602 3103 : HeatCoilLoad = 0.0;
6603 3103 : thisFurnace.HeatingCoilSensDemand = 0.0;
6604 3103 : thisFurnace.CoolingCoilSensDemand = 0.0;
6605 3103 : thisFurnace.CoolingCoilLatentDemand = 0.0;
6606 : } else { // for furnaces
6607 0 : thisFurnace.HeatPartLoadRatio = 0.0;
6608 0 : HeatCoilLoad = ZoneLoad;
6609 0 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.MdotFurnace;
6610 0 : thisFurnace.HeatingCoilSensDemand = 0.0;
6611 0 : thisFurnace.CoolingCoilSensDemand = 0.0;
6612 0 : thisFurnace.CoolingCoilLatentDemand = 0.0;
6613 : }
6614 3103 : ReheatCoilLoad = 0.0;
6615 3103 : thisFurnace.CoolPartLoadRatio = 0.0;
6616 :
6617 : // Init for cooling
6618 1744 : } else if (state.dataFurnaces->CoolingLoad) {
6619 : // air to air heat pumps
6620 1687 : thisFurnace.CoolPartLoadRatio = 1.0;
6621 1687 : thisFurnace.HeatPartLoadRatio = 0.0;
6622 1687 : HeatCoilLoad = 0.0;
6623 1687 : ReheatCoilLoad = 0.0;
6624 :
6625 : // Init for moisture load only
6626 : } else {
6627 57 : thisFurnace.CoolPartLoadRatio = 0.0;
6628 57 : thisFurnace.HeatPartLoadRatio = 0.0;
6629 57 : HeatCoilLoad = 0.0;
6630 57 : ReheatCoilLoad = 0.0;
6631 57 : thisFurnace.HeatingCoilSensDemand = 0.0;
6632 57 : thisFurnace.CoolingCoilSensDemand = 0.0;
6633 57 : thisFurnace.CoolingCoilLatentDemand = 0.0;
6634 : }
6635 :
6636 4847 : SetAverageAirFlow(state, FurnaceNum, max(thisFurnace.HeatPartLoadRatio, thisFurnace.CoolPartLoadRatio), OnOffAirFlowRatio);
6637 : // if dehumidification load exists (for heat pumps) turn on the supplemental heater
6638 4847 : if (state.dataFurnaces->HPDehumidificationLoadFlag) {
6639 0 : HumControl = true;
6640 : }
6641 : } else { // not FirstHVACIteration
6642 : // Init for heating
6643 10378 : Real64 &CoolCoilLoad = state.dataFurnaces->CoolCoilLoad;
6644 10378 : if (state.dataFurnaces->HeatingLoad) {
6645 5260 : CoolCoilLoad = 0.0;
6646 5260 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir ||
6647 1 : (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir && thisFurnace.WatertoAirHPType == WAHPCoilType::Simple)) {
6648 5260 : SystemSensibleLoad = ZoneLoad;
6649 5260 : SystemMoistureLoad = 0.0;
6650 5260 : HeatCoilLoad = 0.0;
6651 5260 : thisFurnace.HeatingCoilSensDemand = SystemSensibleLoad;
6652 5260 : thisFurnace.CoolingCoilSensDemand = 0.0;
6653 5260 : thisFurnace.CoolingCoilLatentDemand = 0.0;
6654 : } else {
6655 0 : SystemMoistureLoad = MoistureLoad;
6656 0 : HeatCoilLoad = ZoneLoad;
6657 : }
6658 :
6659 : // Init for cooling
6660 5118 : } else if (state.dataFurnaces->CoolingLoad) {
6661 5061 : CoolCoilLoad = ZoneLoad;
6662 5061 : SystemMoistureLoad = MoistureLoad;
6663 5061 : HeatCoilLoad = 0.0;
6664 5061 : thisFurnace.CoolingCoilSensDemand = std::abs(CoolCoilLoad);
6665 5061 : thisFurnace.CoolingCoilLatentDemand = std::abs(SystemMoistureLoad);
6666 5061 : thisFurnace.HeatingCoilSensDemand = 0.0;
6667 :
6668 : // Init for latent
6669 : } else {
6670 57 : SystemMoistureLoad = MoistureLoad;
6671 57 : CoolCoilLoad = 0.0;
6672 57 : HeatCoilLoad = 0.0;
6673 : // set report variables
6674 57 : thisFurnace.CoolingCoilSensDemand = 0.0;
6675 57 : thisFurnace.CoolingCoilLatentDemand = SystemMoistureLoad;
6676 57 : thisFurnace.HeatingCoilSensDemand = 0.0;
6677 : }
6678 10378 : HeatingSensibleOutput = 0.0;
6679 10378 : HeatingLatentOutput = 0.0;
6680 10378 : ReheatCoilLoad = 0.0;
6681 10378 : thisFurnace.CoolPartLoadRatio = 0.0;
6682 10378 : thisFurnace.HeatPartLoadRatio = 0.0;
6683 10378 : thisFurnace.CompPartLoadRatio = 0.0;
6684 10378 : thisFurnace.DehumidInducedHeatingDemandRate = 0.0;
6685 :
6686 : // When humidity control is used with cycling fan control and a heating load exists, if a moisture load
6687 : // also exists, the heating PLR must be available for the cooling coil calculations.
6688 : //*********** Heating Section ************
6689 : // If Furnace runs with a heating load then set HeatCoilLoad on Heating Coil and the Mass Flow
6690 : // (Node(FurnaceInletNode)%MassFlowRate .gt. 0.0d0) .and. &
6691 10378 : if ((thisFurnace.availSched->getCurrentVal() > 0.0) && (state.dataFurnaces->HeatingLoad)) {
6692 :
6693 : // Heat pumps only calculate a single PLR each time step (i.e. only cooling or heating allowed in a single time step)
6694 5260 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir ||
6695 1 : (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir && thisFurnace.WatertoAirHPType == WAHPCoilType::Simple)) {
6696 :
6697 5260 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.MdotFurnace;
6698 :
6699 : // Get no load result
6700 5260 : if (fanOp == HVAC::FanOp::Cycling) {
6701 5259 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = 0.0;
6702 : }
6703 :
6704 : // Set the inlet mass flow rate based on user specified coil OFF flow rate
6705 5260 : PartLoadRatio = 0.0;
6706 :
6707 5260 : SetAverageAirFlow(state, FurnaceNum, PartLoadRatio, OnOffAirFlowRatio);
6708 :
6709 : // Set the input parameters for CalcFurnaceOutput
6710 5260 : thisFurnace.CompPartLoadRatio = 0.0; // compressor off
6711 :
6712 5260 : CalcFurnaceOutput(state,
6713 : FurnaceNum,
6714 : FirstHVACIteration,
6715 : fanOp,
6716 : compressorOp,
6717 : 0.0,
6718 : MinPLR,
6719 : 0.0,
6720 : 0.0,
6721 : NoHeatOutput,
6722 : NoLatentOutput,
6723 : OnOffAirFlowRatio,
6724 : false);
6725 :
6726 5260 : PartLoadRatio = 1.0;
6727 5260 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.MdotFurnace;
6728 :
6729 5260 : thisFurnace.CompPartLoadRatio = 1.0; // compressor ON
6730 :
6731 : // Set fan part-load fraction equal to 1 while getting full load result
6732 5260 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
6733 5260 : OnOffAirFlowRatio = 1.0;
6734 :
6735 : // Get full load result
6736 5260 : CalcFurnaceOutput(state,
6737 : FurnaceNum,
6738 : FirstHVACIteration,
6739 : fanOp,
6740 : compressorOp,
6741 : 0.0,
6742 : PartLoadRatio,
6743 : 0.0,
6744 : 0.0,
6745 : FullSensibleOutput,
6746 : FullLatentOutput,
6747 : OnOffAirFlowRatio,
6748 : false);
6749 :
6750 : // Check that SystemSensibleLoad is between FullSensibleOutput and NoHeatOutput
6751 : // If so then calculate PartLoadRatio for the DX Heating coil
6752 5260 : if (SystemSensibleLoad < FullSensibleOutput && SystemSensibleLoad > NoHeatOutput) {
6753 :
6754 : // Calculate the part load ratio through iteration
6755 8 : HeatErrorToler = thisFurnace.HeatingConvergenceTolerance; // Error tolerance for convergence from input deck
6756 :
6757 8 : int SolFlag = 0; // # of iterations if positive, -1 means failed to converge, -2 means bounds are incorrect
6758 : // HeatErrorToler is in fraction of load, MaxIter = 30, SolFalg = # of iterations or error as appropriate
6759 32 : auto f = [&state, FurnaceNum, FirstHVACIteration, fanOp, compressorOp, SystemSensibleLoad](Real64 const PartLoadRatio) {
6760 24 : return CalcFurnaceResidual(state,
6761 : PartLoadRatio,
6762 : FurnaceNum,
6763 : FirstHVACIteration,
6764 : fanOp,
6765 : compressorOp,
6766 : SystemSensibleLoad,
6767 : 0.0, // par6_loadFlag,
6768 : 1.0, // par7_sensLatentFlag,
6769 : 0.0, // par9_HXOnFlag,
6770 24 : 0.0); // par10_HeatingCoilPLR);
6771 8 : };
6772 8 : General::SolveRoot(state, HeatErrorToler, MaxIter, SolFlag, PartLoadRatio, f, 0.0, 1.0);
6773 : // OnOffAirFlowRatio is updated during the above iteration. Reset to correct value based on PLR.
6774 8 : OnOffAirFlowRatio = state.dataFurnaces->OnOffAirFlowRatioSave;
6775 8 : if (SolFlag < 0) {
6776 0 : if (SolFlag == -1) {
6777 0 : CalcFurnaceOutput(state,
6778 : FurnaceNum,
6779 : FirstHVACIteration,
6780 : fanOp,
6781 : compressorOp,
6782 : 0.0,
6783 : PartLoadRatio,
6784 : 0.0,
6785 : 0.0,
6786 : TempHeatOutput,
6787 : TempLatentOutput,
6788 : OnOffAirFlowRatio,
6789 : false);
6790 0 : if (std::abs(SystemSensibleLoad - TempHeatOutput) > HVAC::SmallLoad) {
6791 0 : if (thisFurnace.DXHeatingMaxIterIndex == 0) {
6792 0 : ShowWarningMessage(state,
6793 0 : format("Heating coil control failed to converge for {}:{}",
6794 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6795 0 : thisFurnace.Name));
6796 0 : ShowContinueError(state,
6797 : " Iteration limit exceeded in calculating DX heating coil sensible part-load ratio.");
6798 0 : ShowContinueErrorTimeStamp(
6799 : state,
6800 0 : format("Sensible load to be met by DX heating coil = {:.2T} (watts), sensible output of DX heating "
6801 : "coil = {:.2T} (watts), and the simulation continues.",
6802 : SystemSensibleLoad,
6803 : TempHeatOutput));
6804 : }
6805 0 : ShowRecurringWarningErrorAtEnd(state,
6806 0 : format("{} \"{}\" - Iteration limit exceeded in calculating DX sensible heating "
6807 : "part-load ratio error continues. "
6808 : "Sensible load statistics:",
6809 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6810 0 : thisFurnace.Name),
6811 0 : thisFurnace.DXHeatingMaxIterIndex,
6812 : SystemSensibleLoad,
6813 : SystemSensibleLoad);
6814 : }
6815 0 : } else if (SolFlag == -2) {
6816 0 : if (thisFurnace.DXHeatingRegulaFalsiFailedIndex == 0) {
6817 0 : ShowWarningMessage(state,
6818 0 : format("Heating coil control failed for {}:{}",
6819 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6820 0 : thisFurnace.Name));
6821 0 : ShowContinueError(state, " DX sensible heating part-load ratio determined to be outside the range of 0-1.");
6822 0 : ShowContinueErrorTimeStamp(
6823 : state,
6824 0 : format("Sensible load to be met by DX heating coil = {:.2T} (watts), and the simulation continues.",
6825 : SystemSensibleLoad));
6826 : }
6827 0 : ShowRecurringWarningErrorAtEnd(
6828 : state,
6829 0 : format("{} \"{}\" - DX sensible heating part-load ratio out of range error continues. Sensible load statistics:",
6830 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6831 0 : thisFurnace.Name),
6832 0 : thisFurnace.DXHeatingRegulaFalsiFailedIndex,
6833 : SystemSensibleLoad,
6834 : SystemSensibleLoad);
6835 : }
6836 : }
6837 :
6838 8 : thisFurnace.HeatPartLoadRatio = PartLoadRatio;
6839 : // Check if Heat Pump compressor is allowed to run based on outdoor temperature
6840 8 : if (OutdoorDryBulbTemp > thisFurnace.MinOATCompressorHeating) {
6841 0 : thisFurnace.CompPartLoadRatio = PartLoadRatio;
6842 : } else {
6843 8 : thisFurnace.CompPartLoadRatio = 0.0;
6844 : }
6845 5260 : } else if (SystemSensibleLoad > FullSensibleOutput) {
6846 : // SystemSensibleLoad is greater than full DX Heating coil output so heat pump runs entire
6847 : // timestep and additional supplemental heating is required
6848 5252 : thisFurnace.HeatPartLoadRatio = 1.0;
6849 5252 : if (OutdoorDryBulbTemp > thisFurnace.MinOATCompressorHeating) {
6850 : // Check to see if Heat Pump compressor was allowed to run based on outdoor temperature
6851 1 : thisFurnace.CompPartLoadRatio = 1.0;
6852 : } else {
6853 5251 : thisFurnace.CompPartLoadRatio = 0.0;
6854 : }
6855 0 : } else if (SystemSensibleLoad < NoHeatOutput) {
6856 : // SystemSensibleLoad is less than minimum DX Heating coil output so heat pump does not run and
6857 : // the load will be met by the supplemental heater
6858 0 : thisFurnace.CompPartLoadRatio = 0.0;
6859 0 : thisFurnace.HeatPartLoadRatio = 1.0;
6860 : }
6861 5260 : if (thisFurnace.HeatPartLoadRatio == 1.0) {
6862 : // Determine the load on the supplemental heating coil
6863 5252 : if ((SystemSensibleLoad - FullSensibleOutput) > thisFurnace.DesignSuppHeatingCapacity) {
6864 1 : HeatCoilLoad = thisFurnace.DesignSuppHeatingCapacity;
6865 1 : TempOutHeatingCoil = state.dataLoopNodes->Node(FurnaceOutletNode).Temp + HeatCoilLoad / (cpair * thisFurnace.MdotFurnace);
6866 5251 : } else if (SystemSensibleLoad < NoHeatOutput) {
6867 0 : HeatCoilLoad = max(0.0, SystemSensibleLoad); // BG 10/22/2008 need a case for when its all suppl heat
6868 0 : TempOutHeatingCoil = state.dataLoopNodes->Node(FurnaceInletNode).Temp + HeatCoilLoad / (cpair * thisFurnace.MdotFurnace);
6869 : } else {
6870 5251 : HeatCoilLoad = max(0.0, (SystemSensibleLoad - FullSensibleOutput));
6871 5251 : TempOutHeatingCoil = state.dataLoopNodes->Node(FurnaceOutletNode).Temp + HeatCoilLoad / (cpair * thisFurnace.MdotFurnace);
6872 : }
6873 5252 : if (OutdoorDryBulbTemp > thisFurnace.MaxOATSuppHeat) {
6874 1 : HeatCoilLoad = 0.0;
6875 1 : if (SystemSensibleLoad < NoHeatOutput) {
6876 0 : TempOutHeatingCoil = state.dataLoopNodes->Node(FurnaceInletNode).Temp;
6877 : } else {
6878 1 : TempOutHeatingCoil = state.dataLoopNodes->Node(FurnaceOutletNode).Temp;
6879 : }
6880 : }
6881 5252 : if ((TempOutHeatingCoil > thisFurnace.DesignMaxOutletTemp) && (HeatCoilLoad > 0.0)) {
6882 : // deltaT = Furnace(FurnaceNum)%DesignMaxOutletTemp - Node(FurnaceOutletNode)%Temp
6883 : // BG 10/22/2008 above made no sense if DX heat is off and its all supplemental,
6884 : // because Node(FurnaceOutletNode)%Temp will have been calc'd with full DX heat in last faux call to CalcFurnaceOutput
6885 :
6886 1584 : Real64 cpairSupply = Psychrometrics::PsyCpAirFnW(state.dataLoopNodes->Node(FurnaceInletNode).HumRat);
6887 1584 : deltaT = (thisFurnace.DesignMaxOutletTemp - TempOutHeatingCoil);
6888 1584 : HeatCoilLoad += (state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate * cpairSupply * deltaT);
6889 1584 : HeatCoilLoad = max(0.0, HeatCoilLoad);
6890 : }
6891 : } else {
6892 8 : HeatCoilLoad = 0.0;
6893 : }
6894 5260 : PartLoadRatio = 0.0;
6895 :
6896 : // HeatCool systems can have both a sensible and latent PLR in a single time step
6897 : // (i.e. both cooling and heating can occur in a single time step)
6898 5260 : } else { // else not a heatpump DX coil ** non-HP heating coils are not DX so testing if OutdoorDryBulbTemp < MinOATCompressorHeating
6899 : // is not necessary **
6900 :
6901 0 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.MdotFurnace;
6902 0 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity;
6903 0 : SystemSensibleLoad = ZoneLoad;
6904 :
6905 : // Get no load result
6906 0 : if (fanOp == HVAC::FanOp::Cycling) {
6907 0 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = 0.0;
6908 : }
6909 0 : if (fanOp == HVAC::FanOp::Continuous) {
6910 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0; // The on/off fan will not cycle, so set part-load fraction = 1
6911 : }
6912 :
6913 : // Set the inlet mass flow rate based on user specified coil OFF flow rate
6914 0 : PartLoadRatio = 0.0;
6915 0 : SetAverageAirFlow(state, FurnaceNum, PartLoadRatio, OnOffAirFlowRatio);
6916 :
6917 0 : CalcFurnaceOutput(state,
6918 : FurnaceNum,
6919 : FirstHVACIteration,
6920 : fanOp,
6921 : compressorOp,
6922 : 0.0,
6923 : MinPLR,
6924 : 0.0,
6925 : 0.0,
6926 : NoHeatOutput,
6927 : NoLatentOutput,
6928 : OnOffAirFlowRatio,
6929 : false);
6930 :
6931 0 : if (NoHeatOutput < SystemSensibleLoad) {
6932 0 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.MdotFurnace;
6933 :
6934 : // Set fan part-load fraction equal to 1 while getting full load result
6935 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
6936 0 : OnOffAirFlowRatio = 1.0;
6937 :
6938 : // Get full load result
6939 0 : CalcFurnaceOutput(state,
6940 : FurnaceNum,
6941 : FirstHVACIteration,
6942 : fanOp,
6943 : compressorOp,
6944 : 0.0,
6945 : 1.0,
6946 : HeatCoilLoad,
6947 : 0.0,
6948 : FullSensibleOutput,
6949 : FullLatentOutput,
6950 : OnOffAirFlowRatio,
6951 : false);
6952 : } else {
6953 0 : FullSensibleOutput = NoHeatOutput + 0.000000001;
6954 : }
6955 :
6956 : // Since we are heating, we expect FullSensibleOutput to be > 0 and FullSensibleOutput > NoSensibleOutput
6957 : // Check that this is the case; if not set PartLoadRatio = 0.0 (off) and return
6958 :
6959 0 : if (FullSensibleOutput > NoHeatOutput) {
6960 :
6961 : // check bounds on sensible output prior to iteration using RegulaFalsi
6962 0 : if (FullSensibleOutput <= SystemSensibleLoad) {
6963 0 : PartLoadRatio = 1.0;
6964 : // save modified HeatCoilLoad in case it was reset because outlet temp > DesignMaxOutletTemp
6965 0 : if (state.dataFurnaces->ModifiedHeatCoilLoad > 0.0) {
6966 0 : HeatCoilLoad = state.dataFurnaces->ModifiedHeatCoilLoad;
6967 : } else {
6968 0 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity;
6969 : }
6970 0 : } else if (NoHeatOutput >= SystemSensibleLoad) {
6971 0 : PartLoadRatio = 0.0;
6972 0 : HeatCoilLoad = 0.0;
6973 : } else {
6974 :
6975 : // Calculate the part load ratio through iteration
6976 0 : HeatErrorToler = thisFurnace.HeatingConvergenceTolerance; // Error tolerance for convergence from input deck
6977 :
6978 0 : int SolFlag = 0; // # of iterations if positive, -1 means failed to converge, -2 means bounds are incorrect
6979 : // HeatErrorToler is in fraction load, MaxIter = 30, SolFalg = # of iterations or error as appropriate
6980 0 : auto f = [&state, FurnaceNum, FirstHVACIteration, fanOp, compressorOp, SystemSensibleLoad](Real64 const PartLoadRatio) {
6981 0 : return CalcFurnaceResidual(state,
6982 : PartLoadRatio,
6983 : FurnaceNum,
6984 : FirstHVACIteration,
6985 : fanOp,
6986 : compressorOp,
6987 : SystemSensibleLoad,
6988 : 0.0, // par6_loadFlag,
6989 : 1.0, // par7_sensLatentFlag,
6990 : 0.0, // par9_HXOnFlag,
6991 0 : 0.0); // par10_HeatingCoilPLR);
6992 0 : };
6993 0 : General::SolveRoot(state, HeatErrorToler, MaxIter, SolFlag, PartLoadRatio, f, 0.0, 1.0);
6994 : // OnOffAirFlowRatio is updated during the above iteration. Reset to correct value based on PLR.
6995 0 : OnOffAirFlowRatio = state.dataFurnaces->OnOffAirFlowRatioSave;
6996 : // Reset HeatCoilLoad calculated in CalcFurnaceResidual (in case it was reset because output temp >
6997 : // DesignMaxOutletTemp)
6998 0 : if (state.dataFurnaces->ModifiedHeatCoilLoad > 0.0) {
6999 0 : HeatCoilLoad = state.dataFurnaces->ModifiedHeatCoilLoad;
7000 : } else {
7001 0 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity * PartLoadRatio;
7002 : }
7003 0 : if (SolFlag == -1) {
7004 :
7005 : // RegulaFalsi may not find heating PLR when the maximum supply air temperature is exceeded.
7006 : // If iteration limit is exceeded, find tighter boundary of solution and repeat RegulaFalsi
7007 0 : TempMaxPLR = -0.1;
7008 0 : TempHeatOutput = NoHeatOutput;
7009 0 : while ((TempHeatOutput - SystemSensibleLoad) < 0.0 && TempMaxPLR < 1.0) {
7010 : // find upper limit of HeatingPLR
7011 0 : TempMaxPLR += 0.1;
7012 0 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity * TempMaxPLR;
7013 0 : CalcFurnaceOutput(state,
7014 : FurnaceNum,
7015 : FirstHVACIteration,
7016 : fanOp,
7017 : compressorOp,
7018 : 0.0,
7019 : TempMaxPLR,
7020 : HeatCoilLoad,
7021 : 0.0,
7022 : TempHeatOutput,
7023 : TempLatentOutput,
7024 : OnOffAirFlowRatio,
7025 : false);
7026 : }
7027 0 : TempMinPLR = TempMaxPLR;
7028 0 : while ((TempHeatOutput - SystemSensibleLoad) > 0.0 && TempMinPLR > 0.0) {
7029 : // pull upper limit of HeatingPLR down to last valid limit (i.e. heat output still exceeds
7030 : // SystemSensibleLoad)
7031 0 : TempMaxPLR = TempMinPLR;
7032 : // find minimum limit of HeatingPLR
7033 0 : TempMinPLR -= 0.01;
7034 :
7035 0 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity * TempMinPLR;
7036 0 : CalcFurnaceOutput(state,
7037 : FurnaceNum,
7038 : FirstHVACIteration,
7039 : fanOp,
7040 : compressorOp,
7041 : 0.0,
7042 : TempMinPLR,
7043 : HeatCoilLoad,
7044 : 0.0,
7045 : TempHeatOutput,
7046 : TempLatentOutput,
7047 : OnOffAirFlowRatio,
7048 : false);
7049 : }
7050 : // Now solve again with tighter PLR limits
7051 : auto f2 = // (AUTO_OK_LAMBDA)
7052 0 : [&state, FurnaceNum, FirstHVACIteration, fanOp, compressorOp, SystemSensibleLoad](Real64 const PartLoadRatio) {
7053 0 : return CalcFurnaceResidual(state,
7054 : PartLoadRatio,
7055 : FurnaceNum,
7056 : FirstHVACIteration,
7057 : fanOp,
7058 : compressorOp,
7059 : SystemSensibleLoad,
7060 : 0.0, // par6_loadFlag,
7061 : 1.0, // par7_sensLatentFlag,
7062 : 0.0, // par9_HXOnFlag,
7063 0 : 0.0); // par10_HeatingCoilPLR);
7064 0 : };
7065 0 : General::SolveRoot(state, HeatErrorToler, MaxIter, SolFlag, PartLoadRatio, f2, TempMinPLR, TempMaxPLR);
7066 0 : if (state.dataFurnaces->ModifiedHeatCoilLoad > 0.0) {
7067 0 : HeatCoilLoad = state.dataFurnaces->ModifiedHeatCoilLoad;
7068 : } else {
7069 0 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity * PartLoadRatio;
7070 : }
7071 0 : CalcFurnaceOutput(state,
7072 : FurnaceNum,
7073 : FirstHVACIteration,
7074 : fanOp,
7075 : compressorOp,
7076 : 0.0,
7077 : PartLoadRatio,
7078 : HeatCoilLoad,
7079 : 0.0,
7080 : TempHeatOutput,
7081 : TempLatentOutput,
7082 : OnOffAirFlowRatio,
7083 : false);
7084 :
7085 : // After iterating with tighter boundaries, if still out of tolerance, show warning.
7086 0 : if (SolFlag == -1 && std::abs(SystemSensibleLoad - TempHeatOutput) > HVAC::SmallLoad) {
7087 0 : if (thisFurnace.HeatingMaxIterIndex == 0) {
7088 0 : ShowWarningMessage(state,
7089 0 : format("Heating coil control failed to converge for {}:{}",
7090 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7091 0 : thisFurnace.Name));
7092 0 : ShowContinueError(state, " Iteration limit exceeded in calculating heating coil sensible part-load ratio.");
7093 0 : ShowContinueErrorTimeStamp(state,
7094 0 : format("Sensible load to be met by heating coil = {:.2T} (watts), sensible output "
7095 : "of heating coil = {:.2T} (watts), and the simulation continues.",
7096 : SystemSensibleLoad,
7097 : TempHeatOutput));
7098 : }
7099 0 : ShowRecurringWarningErrorAtEnd(
7100 : state,
7101 0 : format("{} \"{}\" - Iteration limit exceeded in calculating sensible heating part-load "
7102 : "ratio error continues. Sensible load statistics:",
7103 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7104 0 : thisFurnace.Name),
7105 0 : thisFurnace.HeatingMaxIterIndex,
7106 : SystemSensibleLoad,
7107 : SystemSensibleLoad);
7108 : }
7109 0 : } else if (SolFlag == -2) {
7110 0 : if (thisFurnace.HeatingRegulaFalsiFailedIndex == 0) {
7111 0 : ShowWarningMessage(state,
7112 0 : format("Heating coil control failed for {}:{}",
7113 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7114 0 : thisFurnace.Name));
7115 0 : ShowContinueError(state, " Sensible heating part-load ratio determined to be outside the range of 0-1.");
7116 0 : ShowContinueErrorTimeStamp(
7117 : state,
7118 0 : format("Sensible load to be met by heating coil = {:.2T} (watts), and the simulation continues.",
7119 : SystemSensibleLoad));
7120 : }
7121 0 : ShowRecurringWarningErrorAtEnd(
7122 : state,
7123 0 : format("{} \"{}\" - Sensible heating part-load ratio out of range error continues. Sensible load statistics:",
7124 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7125 0 : thisFurnace.Name),
7126 0 : thisFurnace.HeatingRegulaFalsiFailedIndex,
7127 : SystemSensibleLoad,
7128 : SystemSensibleLoad);
7129 : }
7130 : }
7131 :
7132 : } else { // ELSE from IF(FullSensibleOutput.GT.NoSensibleOutput)THEN above
7133 : // Set part load ratio to 1 and run heater at design heating capacity
7134 0 : PartLoadRatio = 1.0;
7135 0 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity;
7136 : }
7137 :
7138 : } // End of IF HeatPump
7139 :
7140 : } // End of IF for heating
7141 :
7142 : // Non-heat pump systems do not set a heating PLR, set it here for use with the DX cooling coil calculations.
7143 : // Set this variable back to 0 for non-heat pump systems at the end of this routine.
7144 10378 : thisFurnace.HeatPartLoadRatio = max(PartLoadRatio, thisFurnace.HeatPartLoadRatio);
7145 10378 : CalcFurnaceOutput(state,
7146 : FurnaceNum,
7147 : FirstHVACIteration,
7148 : fanOp,
7149 : compressorOp,
7150 : 0.0,
7151 : thisFurnace.HeatPartLoadRatio,
7152 : HeatCoilLoad,
7153 : 0.0,
7154 : HeatingSensibleOutput,
7155 : HeatingLatentOutput,
7156 : OnOffAirFlowRatio,
7157 : false);
7158 :
7159 10380 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir ||
7160 2 : (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir && thisFurnace.WatertoAirHPType == WAHPCoilType::Simple &&
7161 2 : state.dataFurnaces->CoolingLoad)) {
7162 10376 : HeatingSensibleOutput = 0.0;
7163 10376 : HeatingLatentOutput = 0.0;
7164 : }
7165 : //***********Cooling Section*****************
7166 : // Simulate if scheduled ON and cooling load or if a moisture load exists when using a humidistat
7167 : // Check of HeatingLatentOutput is used to reduce overshoot during simultaneous heating and cooling
7168 : // Setback flag is used to avoid continued RH control when Tstat is setback (RH should float down)
7169 15695 : if ((thisFurnace.availSched->getCurrentVal() > 0.0 && state.dataFurnaces->CoolingLoad) ||
7170 5317 : (thisFurnace.Humidistat && thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat &&
7171 0 : (SystemMoistureLoad < 0.0 || (SystemMoistureLoad >= 0.0 && HeatingLatentOutput > SystemMoistureLoad &&
7172 0 : !state.dataZoneEnergyDemand->Setback(thisFurnace.ControlZoneNum))))) {
7173 :
7174 : // For cooling operation, the first step is to set the HX operation flag in case a HX assisted coil is used.
7175 : // (if a HX assisted coil is not used, this flag is not used. It's only used in the CALL to SimHXAssistedCoolingCoil)
7176 : // Check the dehumidification control type:
7177 : // For dehumidification control options CoolReheat and None, the HX is always active (locked ON).
7178 : // For dehumidification control option Multimode, the system is operated first with the HX off.
7179 : // If the moisture load is not met, the HX will then be turned on and the system is re-simulated.
7180 :
7181 5061 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat ||
7182 5061 : thisFurnace.DehumidControlType_Num == DehumidificationControlMode::None) {
7183 5061 : HXUnitOn = true;
7184 : } else {
7185 0 : HXUnitOn = false;
7186 : }
7187 :
7188 : // The next step is to determine the system output at no load (PLR=0) and full load (PLR=1)
7189 :
7190 : // Set the inlet mass flow rate based on user specified coil OFF flow rate
7191 5061 : PartLoadRatio = 0.0;
7192 :
7193 5061 : thisFurnace.CompPartLoadRatio = 0.0; // compressor off
7194 :
7195 : // SetAverageAirFlow calculates the operating mass flow rate based on PLR and the user specified inputs
7196 : // for MaxCoolAirMassFlow and MaxNoCoolHeatAirMassFlow.
7197 : // Air flow rate is set according to max of cooling and heating PLR if heating and latent load exists.
7198 5061 : if (fanOp == HVAC::FanOp::Cycling && thisFurnace.HeatPartLoadRatio > 0.0 && thisFurnace.Humidistat &&
7199 10122 : thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat &&
7200 0 : (SystemMoistureLoad < 0.0 || (SystemMoistureLoad >= 0.0 && HeatingLatentOutput > SystemMoistureLoad &&
7201 0 : !state.dataZoneEnergyDemand->Setback(thisFurnace.ControlZoneNum)))) {
7202 0 : CoolingHeatingPLRRatio = min(1.0, PartLoadRatio / thisFurnace.HeatPartLoadRatio);
7203 0 : SetAverageAirFlow(state, FurnaceNum, max(PartLoadRatio, thisFurnace.HeatPartLoadRatio), OnOffAirFlowRatio);
7204 :
7205 : } else {
7206 5061 : CoolingHeatingPLRRatio = 1.0;
7207 5061 : SetAverageAirFlow(state, FurnaceNum, PartLoadRatio, OnOffAirFlowRatio);
7208 : }
7209 :
7210 : // Get no load result (coils simulated OFF)
7211 5061 : CalcFurnaceOutput(state,
7212 : FurnaceNum,
7213 : FirstHVACIteration,
7214 : fanOp,
7215 : compressorOp,
7216 : MinPLR,
7217 : PartLoadRatio,
7218 : 0.0,
7219 : 0.0,
7220 : NoCoolOutput,
7221 : NoLatentOutput,
7222 : OnOffAirFlowRatio,
7223 5061 : HXUnitOn,
7224 : CoolingHeatingPLRRatio);
7225 :
7226 : // Don't calculate full load output if no load output can meet sensible load
7227 5061 : if (NoCoolOutput >= CoolCoilLoad && (CoolCoilLoad != 0.0 || state.dataFurnaces->HPDehumidificationLoadFlag)) {
7228 : // Set full mass flow rate for full load calculation
7229 5061 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.MdotFurnace;
7230 :
7231 : // Set fan part-load fraction equal to 1 while getting full load result
7232 5061 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
7233 5061 : OnOffAirFlowRatio = 1.0;
7234 5061 : PartLoadRatio = 1.0;
7235 5061 : thisFurnace.CompPartLoadRatio = 1.0; // compressor ON
7236 :
7237 : // Get full load result (coils simulated full ON)
7238 5061 : CalcFurnaceOutput(state,
7239 : FurnaceNum,
7240 : FirstHVACIteration,
7241 : fanOp,
7242 : compressorOp,
7243 : PartLoadRatio,
7244 : 0.0,
7245 : 0.0,
7246 : 0.0,
7247 : FullSensibleOutput,
7248 : FullLatentOutput,
7249 : OnOffAirFlowRatio,
7250 5061 : HXUnitOn);
7251 : } else {
7252 0 : FullSensibleOutput = NoCoolOutput - 0.00000001;
7253 : }
7254 :
7255 : // The next step is to compare the results of the full load and no load results
7256 : // 1) Since we are cooling, we expect FullSensibleOutput < NoCoolOutput
7257 : // Check that this is the case; if not set PartLoadRatio = 0.0 (off)
7258 : // 2) Verify that the load to be met is within the range of available output
7259 : // (i.e. between FullSensibleOutput and NoCoolOutput)
7260 : // 3) Set PLR if load is out of range or RegulaFalsi on PLR if system can meet the load
7261 5061 : if (FullSensibleOutput < NoCoolOutput) {
7262 5061 : if (CoolCoilLoad != 0.0 || state.dataFurnaces->HPDehumidificationLoadFlag) {
7263 :
7264 : // check bounds on sensible output prior to iteration using RegulaFalsi
7265 : // Negative value represents cooling load, IF FullSensibleOutput .GT. CoolCoilLoad, load is greater than capacity
7266 5061 : if (FullSensibleOutput >= CoolCoilLoad) {
7267 0 : PartLoadRatio = 1.0;
7268 : // Likewise IF NoCoolOutput .LT. CoolCoilLoad, then load can be met using only the fan (constant fan mode only)
7269 5061 : } else if (NoCoolOutput <= CoolCoilLoad) {
7270 0 : PartLoadRatio = 0.0;
7271 : // ELSE load is between NoCoolOutput and FullSensibleOuput, find PLR required to meet load
7272 : } else {
7273 :
7274 : // Calculate the sensible part load ratio through iteration
7275 5061 : CoolErrorToler = thisFurnace.CoolingConvergenceTolerance; // Error tolerance for convergence from input deck
7276 5061 : int SolFlag = 0; // # of iterations if positive, -1 means failed to converge, -2 means bounds are incorrect
7277 5061 : Real64 par8_HXFlag = HXUnitOn ? 1.0 : 0.0;
7278 : // CoolErrorToler is in fraction of load, MaxIter = 30, SolFalg = # of iterations or error as appropriate
7279 : auto f =
7280 25305 : [&state, FurnaceNum, FirstHVACIteration, fanOp, compressorOp, CoolCoilLoad, par8_HXFlag](Real64 const PartLoadRatio) {
7281 20244 : return CalcFurnaceResidual(state,
7282 : PartLoadRatio,
7283 : FurnaceNum,
7284 : FirstHVACIteration,
7285 : fanOp,
7286 : compressorOp,
7287 : CoolCoilLoad,
7288 : 1.0, // par6_loadFlag,
7289 : 1.0, // par7_sensLatentFlag,
7290 : par8_HXFlag, // par9_HXOnFlag,
7291 20244 : 0.0); // par10_HeatingCoilPLR);
7292 5061 : };
7293 5061 : General::SolveRoot(state, CoolErrorToler, MaxIter, SolFlag, PartLoadRatio, f, 0.0, 1.0);
7294 : // OnOffAirFlowRatio is updated during the above iteration. Reset to correct value based on PLR.
7295 5061 : OnOffAirFlowRatio = state.dataFurnaces->OnOffAirFlowRatioSave;
7296 5061 : if (SolFlag < 0) {
7297 0 : if (SolFlag == -1) {
7298 0 : CalcFurnaceOutput(state,
7299 : FurnaceNum,
7300 : FirstHVACIteration,
7301 : fanOp,
7302 : compressorOp,
7303 : PartLoadRatio,
7304 : 0.0,
7305 : 0.0,
7306 : 0.0,
7307 : TempCoolOutput,
7308 : TempLatentOutput,
7309 : OnOffAirFlowRatio,
7310 0 : HXUnitOn);
7311 0 : if (!state.dataGlobal->WarmupFlag) {
7312 0 : if (std::abs(CoolCoilLoad - TempCoolOutput) > HVAC::SmallLoad) {
7313 0 : if (thisFurnace.SensibleMaxIterIndex == 0) {
7314 0 : ShowWarningMessage(state,
7315 0 : format("Cooling coil control failed to converge for {}:{}",
7316 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7317 0 : thisFurnace.Name));
7318 0 : ShowContinueError(
7319 : state, " Iteration limit exceeded in calculating DX cooling coil sensible part-load ratio.");
7320 0 : ShowContinueErrorTimeStamp(state,
7321 0 : format("Sensible load to be met by DX coil = {:.2T} (watts), sensible "
7322 : "output of DX coil = {:.2T} (watts), and the simulation continues.",
7323 : CoolCoilLoad,
7324 : TempCoolOutput));
7325 : }
7326 0 : ShowRecurringWarningErrorAtEnd(
7327 : state,
7328 0 : format("{} \"{}\" - Iteration limit exceeded in calculating sensible cooling "
7329 : "part-load ratio error continues. Sensible load statistics:",
7330 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7331 0 : thisFurnace.Name),
7332 0 : thisFurnace.SensibleMaxIterIndex,
7333 : CoolCoilLoad,
7334 : CoolCoilLoad);
7335 : }
7336 : }
7337 0 : } else if (SolFlag == -2) {
7338 0 : if (!state.dataGlobal->WarmupFlag) {
7339 0 : if (thisFurnace.SensibleRegulaFalsiFailedIndex == 0) {
7340 0 : ShowWarningMessage(state,
7341 0 : format("Cooling coil control failed for {}:{}",
7342 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7343 0 : thisFurnace.Name));
7344 0 : ShowContinueError(state, " Cooling sensible part-load ratio determined to be outside the range of 0-1.");
7345 0 : ShowContinueErrorTimeStamp(state, format(" Cooling sensible load = {:.2T}", CoolCoilLoad));
7346 : }
7347 0 : ShowRecurringWarningErrorAtEnd(
7348 : state,
7349 0 : format("{} \"{}\" - Cooling sensible part-load ratio out of range error continues. Sensible cooling load "
7350 : "statistics:",
7351 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7352 0 : thisFurnace.Name),
7353 0 : thisFurnace.SensibleRegulaFalsiFailedIndex,
7354 : CoolCoilLoad,
7355 : CoolCoilLoad);
7356 : }
7357 : }
7358 : }
7359 : }
7360 :
7361 : } else {
7362 0 : PartLoadRatio = 0.0;
7363 : } // EndIf for IF(CoolCoilLoad.NE.0.0)
7364 :
7365 : // Calculate the delivered capacity from the PLR calculated above
7366 5061 : CalcFurnaceOutput(state,
7367 : FurnaceNum,
7368 : FirstHVACIteration,
7369 : fanOp,
7370 : compressorOp,
7371 : PartLoadRatio,
7372 : thisFurnace.HeatPartLoadRatio,
7373 : 0.0,
7374 : 0.0,
7375 : TempCoolOutput,
7376 : TempLatentOutput,
7377 : OnOffAirFlowRatio,
7378 5061 : HXUnitOn);
7379 :
7380 : // Calculate the latent part load ratio through iteration
7381 : // Negative SystemMoistureLoad means dehumidification load is present
7382 : // IF this furnace uses MultiMode control AND there is a moisture load AND the moisture load met by the furnace in
7383 : // cooling only mode above is sufficient to meet the moisture demand OR there is no sensible load (PLR=0 from above)
7384 : // then set LatentPartLoadRatio to 0 (no additional dehumidification is required).
7385 5061 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::Multimode &&
7386 0 : ((SystemMoistureLoad < 0.0 && TempLatentOutput < SystemMoistureLoad) || PartLoadRatio == 0.0)) {
7387 0 : LatentPartLoadRatio = 0.0;
7388 : // ELSE calculate a new PLR for valid dehumidification control types if a moisture load exists.
7389 5061 : } else if (thisFurnace.DehumidControlType_Num != DehumidificationControlMode::None &&
7390 0 : (SystemMoistureLoad < 0.0 || (SystemMoistureLoad >= 0.0 && TempLatentOutput > SystemMoistureLoad &&
7391 0 : !state.dataZoneEnergyDemand->Setback(thisFurnace.ControlZoneNum)))) {
7392 :
7393 : // IF the furnace uses dehumidification control MultiMode, turn on the HX and calculate the latent output with
7394 : // the HX ON to compare to the moisture load predicted by the humidistat.
7395 0 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::Multimode) {
7396 0 : HXUnitOn = true;
7397 0 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.MdotFurnace;
7398 : // Set fan part-load fraction equal to 1 while getting full load result
7399 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
7400 0 : OnOffAirFlowRatio = 1.0;
7401 : // Get full load result
7402 0 : CalcFurnaceOutput(state,
7403 : FurnaceNum,
7404 : FirstHVACIteration,
7405 : fanOp,
7406 : compressorOp,
7407 : 1.0,
7408 : 0.0,
7409 : 0.0,
7410 : 0.0,
7411 : TempCoolOutput,
7412 : TempLatentOutput,
7413 : OnOffAirFlowRatio,
7414 0 : HXUnitOn);
7415 : }
7416 :
7417 : // Set the global cooling to heating PLR ratio. CoolHeatPLRRat = MIN(1,CoolingPLR/HeatingPLR)
7418 0 : state.dataFurnaces->CoolHeatPLRRat = 1.0; // means cooling dominated operation (applies to cycling fan mode)
7419 :
7420 0 : if (TempLatentOutput > SystemMoistureLoad) {
7421 : // Set full mass flow rate for full load calculation
7422 0 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.MdotFurnace;
7423 :
7424 : // Set fan part-load fraction equal to 1 while getting full load result
7425 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
7426 0 : OnOffAirFlowRatio = 1.0;
7427 0 : thisFurnace.CompPartLoadRatio = 1.0; // compressor ON
7428 :
7429 : // Get full load result (coils simulated full ON)
7430 0 : CalcFurnaceOutput(state,
7431 : FurnaceNum,
7432 : FirstHVACIteration,
7433 : fanOp,
7434 : compressorOp,
7435 : 1.0,
7436 : 0.0,
7437 : 0.0,
7438 : 0.0,
7439 : TempCoolOutput,
7440 : TempLatentOutput,
7441 : OnOffAirFlowRatio,
7442 0 : HXUnitOn);
7443 : }
7444 :
7445 : // check bounds on latent output prior to iteration using RegulaFalsi
7446 0 : if (TempLatentOutput > SystemMoistureLoad ||
7447 0 : (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::Multimode && TempCoolOutput > CoolCoilLoad)) {
7448 0 : LatentPartLoadRatio = 1.0;
7449 0 : } else if (NoLatentOutput < SystemMoistureLoad || HeatingLatentOutput < SystemMoistureLoad) {
7450 0 : LatentPartLoadRatio = 0.0;
7451 : } else {
7452 :
7453 0 : CoolErrorToler = thisFurnace.CoolingConvergenceTolerance; // Error tolerance for convergence
7454 :
7455 0 : int SolFlag = 0; // # of iterations if positive, -1 means failed to converge, -2 means bounds are incorrect
7456 : // Multimode always controls to meet the SENSIBLE load (however, HXUnitOn is now TRUE)
7457 : Real64 par4_load;
7458 0 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::Multimode) {
7459 0 : par4_load = CoolCoilLoad;
7460 : } else {
7461 0 : par4_load = SystemMoistureLoad;
7462 : }
7463 : // Multimode always controls to meet the SENSIBLE load (however, HXUnitOn is now TRUE)
7464 : Real64 par6_LatentSens;
7465 0 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::Multimode) {
7466 0 : par6_LatentSens = 1.0;
7467 : } else {
7468 0 : par6_LatentSens = 0.0;
7469 : }
7470 0 : Real64 par8_HXUnit = HXUnitOn ? 1.0 : 0.0;
7471 : Real64 par9_HtgCoilPLR;
7472 0 : if (fanOp == HVAC::FanOp::Cycling && thisFurnace.HeatPartLoadRatio > 0.0 && par6_LatentSens == 0.0) {
7473 0 : par9_HtgCoilPLR = thisFurnace.HeatPartLoadRatio;
7474 : } else {
7475 0 : par9_HtgCoilPLR = 0.0;
7476 : }
7477 0 : auto f = [&state,
7478 : FurnaceNum,
7479 : FirstHVACIteration,
7480 : fanOp,
7481 : compressorOp,
7482 : par4_load,
7483 : par6_LatentSens,
7484 : par8_HXUnit,
7485 : par9_HtgCoilPLR](Real64 const PartLoadRatio) {
7486 0 : return CalcFurnaceResidual(state,
7487 : PartLoadRatio,
7488 : FurnaceNum,
7489 : FirstHVACIteration,
7490 : fanOp,
7491 : compressorOp,
7492 : par4_load,
7493 : 1.0, // par6_loadFlag,
7494 : par6_LatentSens, // par7_sensLatentFlag,
7495 : par8_HXUnit, // par9_HXOnFlag,
7496 0 : par9_HtgCoilPLR); // par10_HeatingCoilPLR);
7497 0 : };
7498 : // CoolErrorToler is in fraction of load, MaxIter = 30, SolFalg = # of iterations or error as appropriate
7499 0 : General::SolveRoot(state, CoolErrorToler, MaxIter, SolFlag, LatentPartLoadRatio, f, 0.0, 1.0);
7500 : // OnOffAirFlowRatio is updated during the above iteration. Reset to correct value based on PLR.
7501 0 : OnOffAirFlowRatio = state.dataFurnaces->OnOffAirFlowRatioSave;
7502 0 : if (SolFlag == -1) {
7503 : // RegulaFalsi may not find latent PLR when the latent degradation model is used.
7504 : // If iteration limit is exceeded, find tighter boundary of solution and repeat RegulaFalsi
7505 0 : TempMaxPLR = -0.1;
7506 0 : TempLatentOutput = NoLatentOutput;
7507 0 : while ((TempLatentOutput - SystemMoistureLoad) > 0.0 && TempMaxPLR < 1.0) {
7508 : // find upper limit of LatentPLR
7509 0 : TempMaxPLR += 0.1;
7510 :
7511 : // Same calculation as is done in Function CalcFurnaceResidual for latent PLR calculation.
7512 : // Set cooling to heating PLR for use with Subroutine CalcFurnaceOutput. IF Par(10) = 0,
7513 : // heating PLR = 0 so set the CoolingHeatingPLRRatio to 1 so the cooling PLR is used in the
7514 : // DX cooling coil calculations.
7515 0 : if (par9_HtgCoilPLR > 0.0) {
7516 : // Par(10) = Furnace(FurnaceNum)%HeatPartLoadRatio
7517 : // fanOp = CycFan and Furnace(FurnaceNum)%HeatPartLoadRatio must be > 0 for Part(10) to be
7518 : // greater than 0
7519 0 : CoolingHeatingPLRRatio = min(1.0, TempMaxPLR / thisFurnace.HeatPartLoadRatio);
7520 : } else {
7521 0 : CoolingHeatingPLRRatio = 1.0;
7522 : }
7523 :
7524 0 : CalcFurnaceOutput(state,
7525 : FurnaceNum,
7526 : FirstHVACIteration,
7527 : fanOp,
7528 : compressorOp,
7529 : TempMaxPLR,
7530 : 0.0,
7531 : 0.0,
7532 : 0.0,
7533 : TempCoolOutput,
7534 : TempLatentOutput,
7535 : OnOffAirFlowRatio,
7536 0 : HXUnitOn,
7537 : CoolingHeatingPLRRatio);
7538 : }
7539 0 : TempMinPLR = TempMaxPLR;
7540 0 : while ((TempLatentOutput - SystemMoistureLoad) < 0.0 && TempMinPLR > 0.0) {
7541 : // pull upper limit of LatentPLR down to last valid limit (i.e. latent output still exceeds
7542 : // SystemMoisuterLoad) CR7558 - relax final limits to allow HX assisted coils to converge
7543 0 : TempMaxPLR = TempMinPLR + 0.001;
7544 : // find minimum limit of Latent PLR
7545 0 : TempMinPLR -= 0.001;
7546 :
7547 : // Set cooling to heating PLR for use with Subroutine CalcFurnaceOutput.
7548 0 : if (par9_HtgCoilPLR > 0.0) {
7549 : // Par(10) = Furnace(FurnaceNum)%HeatPartLoadRatio
7550 : // fanOp = CycFan and Furnace(FurnaceNum)%HeatPartLoadRatio must be > 0 for Part(10) to be
7551 : // greater than 0 Since the latent output of cycling fan systems is 0 at PLR=0, do not allow
7552 : // the PLR to be 0, otherwise RegulaFalsi can fail when a heating and moisture load exists and
7553 : // heating PLR > latent PLR.
7554 0 : TempMinPLR2 = max(0.0000000001, TempMinPLR);
7555 0 : CoolingHeatingPLRRatio = min(1.0, TempMinPLR2 / thisFurnace.HeatPartLoadRatio);
7556 : } else {
7557 0 : TempMinPLR2 = TempMinPLR;
7558 0 : CoolingHeatingPLRRatio = 1.0;
7559 : }
7560 :
7561 0 : CalcFurnaceOutput(state,
7562 : FurnaceNum,
7563 : FirstHVACIteration,
7564 : fanOp,
7565 : compressorOp,
7566 : TempMinPLR2,
7567 : 0.0,
7568 : 0.0,
7569 : 0.0,
7570 : TempCoolOutput,
7571 : TempLatentOutput,
7572 : OnOffAirFlowRatio,
7573 0 : HXUnitOn,
7574 : CoolingHeatingPLRRatio);
7575 : }
7576 : // tighter boundary of solution has been found, call RegulaFalsi a second time
7577 0 : auto f2 = [&state,
7578 : FurnaceNum,
7579 : FirstHVACIteration,
7580 : fanOp,
7581 : compressorOp,
7582 : par4_load,
7583 : par6_LatentSens,
7584 : par8_HXUnit,
7585 : par9_HtgCoilPLR](Real64 const PartLoadRatio) {
7586 0 : return CalcFurnaceResidual(state,
7587 : PartLoadRatio,
7588 : FurnaceNum,
7589 : FirstHVACIteration,
7590 : fanOp,
7591 : compressorOp,
7592 : par4_load,
7593 : 1.0, // par6_loadFlag,
7594 : par6_LatentSens, // par7_sensLatentFlag,
7595 : par8_HXUnit, // par9_HXOnFlag,
7596 0 : par9_HtgCoilPLR); // par10_HeatingCoilPLR);
7597 0 : };
7598 0 : General::SolveRoot(state, CoolErrorToler, MaxIter, SolFlag, LatentPartLoadRatio, f2, TempMinPLR2, TempMaxPLR);
7599 : // OnOffAirFlowRatio is updated during the above iteration. Reset to correct value based on PLR.
7600 0 : OnOffAirFlowRatio = state.dataFurnaces->OnOffAirFlowRatioSave;
7601 0 : if (SolFlag == -1) {
7602 :
7603 : // Set cooling to heating PLR for use with Subroutine CalcFurnaceOutput.
7604 0 : if (par9_HtgCoilPLR > 0.0) {
7605 : // Par(10) = Furnace(FurnaceNum)%HeatPartLoadRatio
7606 : // fanOp = CycFan and Furnace(FurnaceNum)%HeatPartLoadRatio must be > 0 for Part(10) to be
7607 : // greater than 0
7608 0 : CoolingHeatingPLRRatio = min(1.0, LatentPartLoadRatio / thisFurnace.HeatPartLoadRatio);
7609 : } else {
7610 0 : CoolingHeatingPLRRatio = 1.0;
7611 : }
7612 :
7613 0 : CalcFurnaceOutput(state,
7614 : FurnaceNum,
7615 : FirstHVACIteration,
7616 : fanOp,
7617 : compressorOp,
7618 : LatentPartLoadRatio,
7619 : 0.0,
7620 : 0.0,
7621 : 0.0,
7622 : TempCoolOutput,
7623 : TempLatentOutput,
7624 : OnOffAirFlowRatio,
7625 0 : HXUnitOn,
7626 : CoolingHeatingPLRRatio);
7627 0 : if (std::abs((SystemMoistureLoad - TempLatentOutput) / SystemMoistureLoad) > CoolErrorToler &&
7628 0 : std::abs(SystemMoistureLoad - TempLatentOutput) > 10.0) {
7629 0 : if (!state.dataGlobal->WarmupFlag) {
7630 0 : if (thisFurnace.LatentMaxIterIndex == 0) {
7631 0 : ShowWarningMessage(state,
7632 0 : format("Cooling coil control failed to converge for {}:{}",
7633 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7634 0 : thisFurnace.Name));
7635 0 : ShowContinueError(state,
7636 : " Iteration limit exceeded in calculating cooling coil latent part-load ratio.");
7637 0 : ShowContinueError(
7638 : state,
7639 0 : format(" Latent load convergence error (percent) = {:.2T}",
7640 0 : 100.0 * std::abs((SystemMoistureLoad - TempLatentOutput) / SystemMoistureLoad)));
7641 0 : ShowContinueErrorTimeStamp(state,
7642 0 : format("Moisture load to be met by DX coil = {:.2T} (watts), Latent "
7643 : "output of DX coil = {:.2T} (watts), and the simulation continues.",
7644 : SystemMoistureLoad,
7645 : TempLatentOutput));
7646 : }
7647 0 : ShowRecurringWarningErrorAtEnd(
7648 : state,
7649 0 : format("{} \"{}\" - Iteration limit exceeded in calculating latent part-load ratio error continues. "
7650 : "Latent "
7651 : "load convergence error (percent) statistics follow.",
7652 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7653 0 : thisFurnace.Name),
7654 0 : thisFurnace.LatentMaxIterIndex,
7655 0 : 100.0 * std::abs((SystemMoistureLoad - TempLatentOutput) / SystemMoistureLoad),
7656 0 : 100.0 * std::abs((SystemMoistureLoad - TempLatentOutput) / SystemMoistureLoad));
7657 : }
7658 : }
7659 0 : } else if (SolFlag == -2) {
7660 0 : if (thisFurnace.LatentRegulaFalsiFailedIndex2 == 0) {
7661 0 : ShowWarningMessage(state,
7662 0 : format("Cooling coil control failed for {}:{}",
7663 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7664 0 : thisFurnace.Name));
7665 0 : ShowContinueError(state,
7666 0 : format(" Latent part-load ratio determined to be outside the range of {:.3T} to {:.3T}.",
7667 : TempMinPLR,
7668 : TempMaxPLR));
7669 0 : ShowContinueErrorTimeStamp(state,
7670 0 : format("A PLR of {:.3T} will be used and the simulation continues.", TempMinPLR));
7671 : }
7672 0 : ShowRecurringWarningErrorAtEnd(state,
7673 0 : format("{} \"{}\" - Cooling sensible part-load ratio out of range error "
7674 : "continues. System moisture load statistics:",
7675 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7676 0 : thisFurnace.Name),
7677 0 : thisFurnace.LatentRegulaFalsiFailedIndex2,
7678 : SystemMoistureLoad,
7679 : SystemMoistureLoad);
7680 0 : LatentPartLoadRatio = TempMinPLR;
7681 : }
7682 0 : } else if (SolFlag == -2) {
7683 0 : if (thisFurnace.LatentRegulaFalsiFailedIndex == 0) {
7684 0 : ShowWarningMessage(state,
7685 0 : format("Cooling coil control failed for {}:{}",
7686 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7687 0 : thisFurnace.Name));
7688 0 : ShowContinueError(state, " Latent part-load ratio determined to be outside the range of 0-1.");
7689 0 : ShowContinueErrorTimeStamp(state, "A PLR of 0 will be used and the simulation continues.");
7690 : }
7691 0 : ShowRecurringWarningErrorAtEnd(
7692 : state,
7693 0 : format("{} \"{}\" - Latent part-load ratio out of range or 0-1 error continues. System moisture load statistics:",
7694 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7695 0 : thisFurnace.Name),
7696 0 : thisFurnace.LatentRegulaFalsiFailedIndex,
7697 : SystemMoistureLoad,
7698 : SystemMoistureLoad);
7699 0 : LatentPartLoadRatio = 0.0;
7700 : }
7701 : }
7702 :
7703 : // Cooling to heating PLR ratio is now known as CoolHeatPLRRat (Module level global set in CalcFurnaceOutput
7704 : // This same variable is use in Subroutine SimFurnace for final calculations.
7705 : // Get the actual output in case reheat needs to be calculated (HumControl=TRUE [latent PLR > sensible PLR])
7706 0 : CalcFurnaceOutput(state,
7707 : FurnaceNum,
7708 : FirstHVACIteration,
7709 : fanOp,
7710 : compressorOp,
7711 : LatentPartLoadRatio,
7712 : 0.0,
7713 : 0.0,
7714 : 0.0,
7715 : ActualSensibleOutput,
7716 : ActualLatentOutput,
7717 : OnOffAirFlowRatio,
7718 0 : HXUnitOn,
7719 0 : state.dataFurnaces->CoolHeatPLRRat);
7720 :
7721 : } else {
7722 5061 : LatentPartLoadRatio = 0.0;
7723 : } // ENDIF for valid dehumidification control types
7724 :
7725 : // IF a humidistat is used and there is a moisture load, check if the latent PLR is greater than the (sensible) PLR
7726 : // IF(LatentPartLoadRatio .GT. PartLoadRatio .and. SystemMoistureLoad .lt. 0.0 .and. Furnace(FurnaceNum)%Humidistat) THEN
7727 5061 : if (LatentPartLoadRatio > PartLoadRatio && thisFurnace.Humidistat) {
7728 : // For dehumidification mode CoolReheat, compare the Sensible and Latent PLR values, if latentPLR is greater
7729 : // than PLR (sensible), then overcooling is required and reheat will be activated using the HumControl flag.
7730 0 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat) {
7731 0 : PartLoadRatio = LatentPartLoadRatio;
7732 0 : HumControl = true;
7733 : }
7734 : // For dehumidification mode MultiMode, compare the Sensible and Latent PLR values, if latentPLR is
7735 : // greater than PLR (sensible), then use the latent PLR to control the unit.
7736 : // For MultiMode control, the latent PLR is found by enabling the HX and calculating a PLR required to meet the
7737 : // sensible load. Overcooling is not required, and reheat will not be activated using the HumControl flag.
7738 0 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::Multimode) {
7739 0 : PartLoadRatio = LatentPartLoadRatio;
7740 : }
7741 : }
7742 :
7743 5061 : thisFurnace.CoolPartLoadRatio = PartLoadRatio;
7744 5061 : if (compressorOp == HVAC::CompressorOp::Off) {
7745 0 : thisFurnace.CompPartLoadRatio = 0.0;
7746 : } else {
7747 5061 : thisFurnace.CompPartLoadRatio = PartLoadRatio;
7748 : }
7749 :
7750 : } else { // ELSE from IF(FullSensibleOutput.LT.NoCoolOutput)THEN above
7751 : // CR8679 - Unitary Heat Cool control problem, will not run to meeting cooling load
7752 : // underlying problem is that FullSensibleOutput is greater than 0 due to very high inlet temp, so the system should be on
7753 : // NoCoolOutput was 0 since the defect file is a cycling fan system and the system was turned off
7754 :
7755 : // if FullSensibleOutput > NoCoolOutput, it means the system cannot meet the load and will run full out
7756 : // this same logic for WSHP does not seem to work (only the Unitary Heat Pump Compressor Part-Load Ratio report
7757 : // variable was affected in the HeatPumpWaterToAirRHControl.idf file while other variables showed very small diffs).
7758 : // The defect files meter.csv showed 2% diffs so this IF test is used to keep the results the same in that file.
7759 : // Additional logic is used here to make sure the coil actually turned on, e.g., if DX coil PLR > 0 then set to 1,
7760 : // otherwise 0 (to make sure coil is actually ON and not off due to schedule, OAT, or other reason).
7761 : // The global variable DXCoilPartLoadRatio(DXCoilNum) is not yet used for the WSHP to make the same check.
7762 0 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir) {
7763 0 : thisFurnace.CoolPartLoadRatio = 0.0;
7764 0 : thisFurnace.CompPartLoadRatio = 0.0;
7765 : } else {
7766 0 : if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) {
7767 :
7768 : // VS coil issue here...
7769 0 : if (state.dataDXCoils->DXCoilPartLoadRatio(thisFurnace.ActualDXCoilIndexForHXAssisted) > 0.0) {
7770 0 : thisFurnace.CoolPartLoadRatio = 1.0;
7771 0 : thisFurnace.CompPartLoadRatio = 1.0;
7772 : } else {
7773 0 : thisFurnace.CoolPartLoadRatio = 0.0;
7774 0 : thisFurnace.CompPartLoadRatio = 0.0;
7775 : }
7776 : } else {
7777 0 : if (state.dataDXCoils->DXCoilPartLoadRatio(thisFurnace.CoolingCoilIndex) > 0.0) {
7778 0 : thisFurnace.CoolPartLoadRatio = 1.0;
7779 0 : thisFurnace.CompPartLoadRatio = 1.0;
7780 : } else {
7781 0 : thisFurnace.CoolPartLoadRatio = 0.0;
7782 0 : thisFurnace.CompPartLoadRatio = 0.0;
7783 : }
7784 : }
7785 : }
7786 : }
7787 :
7788 : // Calculate the reheat coil output
7789 5061 : if (HumControl) { // HumControl = .TRUE. if a Humidistat is installed and dehumidification control type is CoolReheat
7790 0 : if (thisFurnace.ZoneSequenceHeatingNum > 0) {
7791 0 : QToHeatSetPt = (state.dataZoneEnergyDemand->ZoneSysEnergyDemand(thisFurnace.ControlZoneNum)
7792 0 : .SequencedOutputRequiredToHeatingSP(thisFurnace.ZoneSequenceHeatingNum) /
7793 0 : thisFurnace.ControlZoneMassFlowFrac);
7794 : } else {
7795 0 : QToHeatSetPt = (state.dataZoneEnergyDemand->ZoneSysEnergyDemand(thisFurnace.ControlZoneNum).OutputRequiredToHeatingSP /
7796 0 : thisFurnace.ControlZoneMassFlowFrac);
7797 : }
7798 : // Cooling mode or floating condition and dehumidification is required
7799 0 : if (QToHeatSetPt < 0.0) {
7800 : // Calculate the reheat coil load wrt the heating setpoint temperature. Reheat coil picks up
7801 : // the entire excess sensible cooling (DX cooling coil and impact of outdoor air).
7802 0 : ReheatCoilLoad = max(0.0, (QToHeatSetPt - ActualSensibleOutput));
7803 0 : thisFurnace.DehumidInducedHeatingDemandRate = ReheatCoilLoad;
7804 : // Heating mode and dehumidification is required
7805 : } else {
7806 : // Calculate the reheat coil load as the sensible capacity of the DX cooling coil only. Let
7807 : // the heating coil pick up the load due to outdoor air.
7808 0 : ReheatCoilLoad = max(0.0, (ActualSensibleOutput - NoCoolOutput) * (-1.0));
7809 : // Dehumidification is not required
7810 0 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir ||
7811 0 : (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir &&
7812 0 : thisFurnace.WatertoAirHPType == WAHPCoilType::Simple)) {
7813 0 : ReheatCoilLoad = max(QToHeatSetPt, QToHeatSetPt - ActualSensibleOutput);
7814 : }
7815 0 : thisFurnace.DehumidInducedHeatingDemandRate = max(0.0, ActualSensibleOutput * (-1.0));
7816 : }
7817 : } else {
7818 : // No humidistat installed
7819 5061 : ReheatCoilLoad = 0.0;
7820 : }
7821 : } // End of cooling section IF statement
7822 :
7823 10378 : if (NoHeatOutput > SystemSensibleLoad && ReheatCoilLoad > 0.0) {
7824 : // Reduce reheat coil load if you are controlling high humidity but outside air
7825 : // and/or the supply air fan is providing enough heat to meet the system sensible load.
7826 : // This will bring the zone temp closer to the heating setpoint temp.
7827 0 : ReheatCoilLoad = max(0.0, ReheatCoilLoad - (NoHeatOutput - SystemSensibleLoad));
7828 : }
7829 :
7830 : // Set the final air flow. MdotFurnace will be used to set the fan part-load ratio in ReportFurnace
7831 10378 : if (HumControl && SystemMoistureLoad < 0.0) {
7832 0 : if (fanOp == HVAC::FanOp::Cycling) {
7833 : // set the flow rate at the maximum of the cooling and heating PLR's
7834 0 : SetAverageAirFlow(state, FurnaceNum, max(thisFurnace.CoolPartLoadRatio, thisFurnace.HeatPartLoadRatio), OnOffAirFlowRatio);
7835 : } else {
7836 : // ELSE set the flow rate at the cooling PLR
7837 0 : SetAverageAirFlow(state, FurnaceNum, thisFurnace.CoolPartLoadRatio, OnOffAirFlowRatio);
7838 : }
7839 : } else {
7840 10378 : SetAverageAirFlow(state, FurnaceNum, max(thisFurnace.CoolPartLoadRatio, thisFurnace.HeatPartLoadRatio), OnOffAirFlowRatio);
7841 : }
7842 10378 : thisFurnace.MdotFurnace = state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate;
7843 :
7844 10378 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir ||
7845 2 : (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir && thisFurnace.WatertoAirHPType == WAHPCoilType::Simple)) {
7846 : } else {
7847 : // Non-HeatPump (non-DX) heating coils do not set PLR, reset to 0 here. This variable was set for non-DX
7848 : // coils to allow the SetAverageAirFlow CALL above to set the correct air mass flow rate. See this
7849 : // IF block above in heating section. HeatPLR is not set in the ELSE part of the IF (only HeatCoilLoad is set).
7850 0 : thisFurnace.HeatPartLoadRatio = 0.0;
7851 : }
7852 :
7853 : //*********HVAC Scheduled OFF*************
7854 : // No heating or cooling or dehumidification
7855 : //!!LKL discrepancy with < 0?
7856 10378 : if (thisFurnace.availSched->getCurrentVal() == 0.0 || state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate == 0.0) {
7857 57 : thisFurnace.MdotFurnace = 0.0;
7858 57 : CoolCoilLoad = 0.0;
7859 57 : HeatCoilLoad = 0.0;
7860 57 : ReheatCoilLoad = 0.0;
7861 57 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0; // System off, so set on/off fan part-load fraction = 1
7862 57 : thisFurnace.CoolPartLoadRatio = 0.0;
7863 57 : thisFurnace.HeatPartLoadRatio = 0.0;
7864 57 : thisFurnace.CompPartLoadRatio = 0.0;
7865 : // set report variables
7866 57 : thisFurnace.CoolingCoilSensDemand = 0.0;
7867 57 : thisFurnace.CoolingCoilLatentDemand = 0.0;
7868 57 : thisFurnace.HeatingCoilSensDemand = 0.0;
7869 : }
7870 :
7871 : } // End of the FirstHVACIteration control of the mass flow If block
7872 :
7873 : // Set the fan inlet node flow rates
7874 15225 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRateMaxAvail = thisFurnace.MdotFurnace;
7875 15225 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.MdotFurnace;
7876 15225 : }
7877 :
7878 0 : void CalcWaterToAirHeatPump(EnergyPlusData &state,
7879 : int const FurnaceNum, // index to Furnace
7880 : bool const FirstHVACIteration, // TRUE on first HVAC iteration
7881 : HVAC::CompressorOp const compressorOp, // compressor operation flag (1=On, 0=Off)
7882 : Real64 const ZoneLoad, // the control zone load (watts)
7883 : Real64 const MoistureLoad // the control zone latent load (watts)
7884 : )
7885 : {
7886 :
7887 : // SUBROUTINE INFORMATION:
7888 : // AUTHOR Dan Fisher
7889 : // DATE WRITTEN Feb 2004
7890 : // MODIFIED R. Raustad (Oct 2006) Revised iteration technique
7891 :
7892 : // PURPOSE OF THIS SUBROUTINE:
7893 : // This subroutine manages the heat pump simulation
7894 :
7895 : // METHODOLOGY EMPLOYED:
7896 : // Calculate the part-load ratio required to meet the zone sensible load.
7897 :
7898 : // SUBROUTINE PARAMETER DEFINITIONS:
7899 0 : int constexpr MaxIter(600); // maximum number of iterations
7900 0 : Real64 constexpr MinPLR(0.0); // minimum part load ratio allowed
7901 :
7902 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
7903 : Real64 ZoneSensLoadMet; // Actual zone sensible load met by heat pump (W)
7904 : Real64 ZoneLatLoadMet; // Actual zone latent load met by heat pump (W)
7905 : Real64 ZoneSensLoadMetFanONCompON; // Max Zone sensible load heat pump can meet (W)
7906 : Real64 ZoneLatLoadMetFanONCompON; // Max Zone latent load heat pump can meet (W)
7907 : Real64 ZoneSensLoadMetFanONCompOFF; // control zone sensible load met using only outside air
7908 : // and fan heat (no coil output) (W)
7909 : Real64 ZoneLatLoadMetFanONCompOFF; // control zone Latent load met using only outside air
7910 : // and fan heat (no coil output) (W)
7911 : Real64 HPCoilSensDemand; // Heat pump sensible demand
7912 : Real64 HPCoilSensCapacity; // Heat pump sensible capacity
7913 :
7914 : Real64 SuppHeatCoilLoad; // Load passed to supplemental heater (W)
7915 : Real64 CoolErrorToler; // convergence tolerance used in cooling mode
7916 : Real64 HeatErrorToler; // convergence tolerance used in heating mode
7917 : int SolFlag; // flag returned from iteration routine to denote problems
7918 :
7919 0 : Real64 &TotalZoneLatentLoad = state.dataFurnaces->TotalZoneLatentLoad;
7920 0 : Real64 &TotalZoneSensLoad = state.dataFurnaces->TotalZoneSensLoad;
7921 0 : Real64 &CoolPartLoadRatio = state.dataFurnaces->CoolPartLoadRatio;
7922 0 : Real64 &HeatPartLoadRatio = state.dataFurnaces->HeatPartLoadRatio;
7923 0 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
7924 :
7925 : // Set local variables
7926 0 : Real64 Dummy2 = 0.0; // used as dummy heat and reheat coil load
7927 0 : Real64 OnOffAirFlowRatio = 1.0; // Ratio of compressor ON air mass flow to AVERAGE air mass flow over time step
7928 0 : int FurnaceInletNode = thisFurnace.FurnaceInletNodeNum;
7929 0 : HVAC::FanOp fanOp = thisFurnace.fanOp; // fan operating mode
7930 0 : thisFurnace.MdotFurnace = thisFurnace.DesignMassFlowRate;
7931 :
7932 : //*********INITIAL CALCULATIONS****************
7933 : // set the fan part load fraction
7934 : // Note: OnOffFanPartLoadFraction is passed to the
7935 : // fan module by DataHVACGlobals. It should be
7936 : // set =1 for all cases except cycling fan/cycling
7937 : // coil. For this case it is set to the part load
7938 : // factor. In SimOnOffFan, the part load ratio is
7939 : // divided by the part load factor (OnOffFanPartLoadFraction)
7940 : // in order to match the run time fraction of the cycling
7941 : // fan with the run time fraction of the cycling compressor
7942 0 : if (FirstHVACIteration) {
7943 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
7944 : }
7945 :
7946 : // Calc Zone sensible loads for heating (+) and cooling (-)
7947 0 : TotalZoneSensLoad = ZoneLoad;
7948 :
7949 0 : if (state.dataFurnaces->HeatingLoad) {
7950 0 : TotalZoneLatentLoad = 0.0; // Set latent load for heating
7951 : } else {
7952 0 : TotalZoneLatentLoad = MoistureLoad; // Set latent load for cooling and no sensible load condition
7953 : }
7954 :
7955 : //*********COOLING CALCULATIONS****************
7956 : // IF scheduled on...
7957 : // AND air flow rate is greater than zero...
7958 : // AND the air system has a cooling load and is not set back or in the deadband...
7959 : // OR the system is controlled by a humidistat and there is a latent load
7960 0 : if ((thisFurnace.availSched->getCurrentVal() > 0.0 && state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate > 0.0) &&
7961 0 : ((state.dataFurnaces->CoolingLoad) || (thisFurnace.Humidistat && thisFurnace.CoolingCoilLatentDemand < 0.0))) {
7962 :
7963 : // Set the air flow rate to the design flow rate and set the fan operation fraction to 1 (continuous operation)
7964 0 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.DesignMassFlowRate;
7965 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0; // see 'Note' under INITIAL CALCULATIONS
7966 :
7967 : // !Set the operation flag to run the fan continuously
7968 : // fanOp = FanOp::Continuous
7969 :
7970 : // Set the input parameters for CalcFurnaceOutput
7971 0 : thisFurnace.HeatingCoilSensDemand = 0.0;
7972 0 : thisFurnace.CoolingCoilLatentDemand = 0.0;
7973 0 : thisFurnace.CoolingCoilSensDemand = 0.0;
7974 0 : thisFurnace.CompPartLoadRatio = 0.0; // compressor off
7975 0 : thisFurnace.InitHeatPump = true; // initialization call to Calc Furnace
7976 0 : CoolPartLoadRatio = 0.0;
7977 :
7978 : // Get no load result in order to calculate the effect of the fan and the mixed air equipment
7979 0 : CalcFurnaceOutput(state,
7980 : FurnaceNum,
7981 : FirstHVACIteration,
7982 : fanOp,
7983 : compressorOp,
7984 : CoolPartLoadRatio,
7985 : HeatPartLoadRatio,
7986 : Dummy2,
7987 : Dummy2,
7988 : ZoneSensLoadMetFanONCompOFF,
7989 : ZoneLatLoadMetFanONCompOFF,
7990 : OnOffAirFlowRatio,
7991 : false);
7992 :
7993 : // Set the input parameters for CalcFurnaceOutput
7994 0 : thisFurnace.CoolingCoilSensDemand = 1.0;
7995 0 : thisFurnace.CompPartLoadRatio = 1.0; // compressor ON
7996 0 : CoolPartLoadRatio = 1.0;
7997 :
7998 : // Get full load result in order to estimate the operating part load ratio for continuous fan operation
7999 0 : CalcFurnaceOutput(state,
8000 : FurnaceNum,
8001 : FirstHVACIteration,
8002 : fanOp,
8003 : compressorOp,
8004 : CoolPartLoadRatio,
8005 : HeatPartLoadRatio,
8006 : Dummy2,
8007 : Dummy2,
8008 : ZoneSensLoadMetFanONCompON,
8009 : ZoneLatLoadMetFanONCompON,
8010 : OnOffAirFlowRatio,
8011 : false);
8012 :
8013 : // Calculate the heating coil demand for continuous fan operation as:
8014 : // (the zone sensible load - the zone sensible load met by fan heat and mixed air)
8015 : // Note; The sensible zone load met by fan heat and mixed air is calculated as:
8016 : // mdotsys(control zone inlet enthalpy - control zone outlet enthalpy)
8017 : // This accounts for the negative sign in the equation.
8018 0 : HPCoilSensDemand = TotalZoneSensLoad - ZoneSensLoadMetFanONCompOFF;
8019 :
8020 : // Calculate the heating coil capacity for continuous fan operation as:
8021 : // (the zone sensible load met by fan heat and mixed air and coil
8022 : // - the zone sensible load met by fan heat and mixed air)
8023 0 : HPCoilSensCapacity = ZoneSensLoadMetFanONCompON - ZoneSensLoadMetFanONCompOFF;
8024 :
8025 : // Calculate the part load ratio for continuous fan operation with cycling coil
8026 0 : if (HPCoilSensCapacity == 0.0) {
8027 0 : CoolPartLoadRatio = 0.0;
8028 : } else {
8029 0 : CoolPartLoadRatio = max(MinPLR, min(1.0, std::abs(HPCoilSensDemand) / std::abs(HPCoilSensCapacity)));
8030 : }
8031 :
8032 0 : thisFurnace.InitHeatPump = false;
8033 :
8034 : // check bounds on sensible output prior to iteration using RegulaFalsi
8035 0 : if (ZoneSensLoadMetFanONCompON > TotalZoneSensLoad) {
8036 0 : CoolPartLoadRatio = 1.0;
8037 0 : HPCoilSensDemand = std::abs(ZoneSensLoadMetFanONCompON - ZoneSensLoadMetFanONCompOFF);
8038 0 : thisFurnace.CoolingCoilSensDemand = HPCoilSensDemand;
8039 0 : } else if (ZoneSensLoadMetFanONCompOFF < TotalZoneSensLoad) {
8040 0 : CoolPartLoadRatio = 0.0;
8041 0 : thisFurnace.CompPartLoadRatio = 0.0; // compressor OFF
8042 0 : thisFurnace.CoolingCoilSensDemand = 0.0;
8043 0 : CalcFurnaceOutput(state,
8044 : FurnaceNum,
8045 : FirstHVACIteration,
8046 : fanOp,
8047 : compressorOp,
8048 : CoolPartLoadRatio,
8049 : HeatPartLoadRatio,
8050 : Dummy2,
8051 : Dummy2,
8052 : ZoneSensLoadMetFanONCompOFF,
8053 : ZoneLatLoadMetFanONCompOFF,
8054 : OnOffAirFlowRatio,
8055 : false);
8056 : } else {
8057 : // Calculate the sensible part load ratio through iteration
8058 0 : CoolErrorToler = thisFurnace.CoolingConvergenceTolerance;
8059 0 : SolFlag = 0; // # of iterations if positive, -1 means failed to converge, -2 means bounds are incorrect
8060 : // CoolErrorToler is in fraction of load, MaxIter = 600, SolFalg = # of iterations or error as appropriate
8061 0 : auto f = [&state, FurnaceNum, FirstHVACIteration, fanOp, compressorOp, TotalZoneSensLoad, ZoneSensLoadMetFanONCompOFF](
8062 : Real64 const PartLoadRatio) {
8063 0 : return CalcWaterToAirResidual(state,
8064 : PartLoadRatio,
8065 : FurnaceNum,
8066 : FirstHVACIteration,
8067 : fanOp,
8068 : compressorOp,
8069 : TotalZoneSensLoad,
8070 : 1.0,
8071 : 1.0,
8072 : ZoneSensLoadMetFanONCompOFF,
8073 0 : 0.0);
8074 0 : };
8075 0 : General::SolveRoot(state, CoolErrorToler, MaxIter, SolFlag, CoolPartLoadRatio, f, 0.0, 1.0);
8076 0 : if (SolFlag == -1 && !state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
8077 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = state.dataFurnaces->OnOffFanPartLoadFractionSave;
8078 0 : CalcFurnaceOutput(state,
8079 : FurnaceNum,
8080 : FirstHVACIteration,
8081 : fanOp,
8082 : compressorOp,
8083 : CoolPartLoadRatio,
8084 : 0.0,
8085 : 0.0,
8086 : 0.0,
8087 : ZoneSensLoadMet,
8088 : ZoneLatLoadMet,
8089 : OnOffAirFlowRatio,
8090 : false);
8091 0 : if (std::abs(ZoneSensLoadMet - TotalZoneSensLoad) / TotalZoneSensLoad > CoolErrorToler) {
8092 0 : if (thisFurnace.SensibleMaxIterIndex == 0) {
8093 0 : ShowWarningMessage(state,
8094 0 : format("Cooling coil control failed to converge for {}:{}",
8095 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
8096 0 : thisFurnace.Name));
8097 0 : ShowContinueError(state, " Iteration limit exceeded in calculating DX cooling coil sensible part-load ratio.");
8098 0 : ShowContinueErrorTimeStamp(state,
8099 0 : format("Sensible load to be met by DX coil = {:.2T} (watts), sensible output of DX coil = "
8100 : "{:.2T} (watts), and the simulation continues.",
8101 : TotalZoneSensLoad,
8102 : ZoneSensLoadMet));
8103 : }
8104 0 : ShowRecurringWarningErrorAtEnd(
8105 : state,
8106 0 : format("{} \"{}\" - Iteration limit exceeded in calculating sensible cooling part-load ratio error "
8107 : "continues. Sensible load statistics:",
8108 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
8109 0 : thisFurnace.Name),
8110 0 : thisFurnace.SensibleMaxIterIndex,
8111 : TotalZoneSensLoad,
8112 : TotalZoneSensLoad);
8113 : }
8114 0 : } else if (SolFlag == -2 && !state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
8115 0 : CoolPartLoadRatio = max(MinPLR, min(1.0, std::abs(HPCoilSensDemand) / std::abs(HPCoilSensCapacity)));
8116 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
8117 0 : CalcFurnaceOutput(state,
8118 : FurnaceNum,
8119 : FirstHVACIteration,
8120 : fanOp,
8121 : compressorOp,
8122 : CoolPartLoadRatio,
8123 : 0.0,
8124 : 0.0,
8125 : 0.0,
8126 : ZoneSensLoadMet,
8127 : ZoneLatLoadMet,
8128 : OnOffAirFlowRatio,
8129 : false);
8130 0 : if ((ZoneSensLoadMet - TotalZoneSensLoad) / TotalZoneSensLoad > CoolErrorToler) {
8131 0 : if (thisFurnace.SensibleRegulaFalsiFailedIndex == 0) {
8132 0 : ShowWarningMessage(
8133 : state,
8134 0 : format("Cooling coil control failed for {}:{}", HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name));
8135 0 : ShowContinueError(state, " Cooling sensible part-load ratio determined to be outside the range of 0-1.");
8136 0 : ShowContinueError(
8137 : state,
8138 0 : format(" An estimated part-load ratio = {:.2T} will be used and the simulation continues.", CoolPartLoadRatio));
8139 0 : ShowContinueError(
8140 0 : state, format(" The estimated part-load ratio provides a cooling sensible capacity = {:.2T}", ZoneSensLoadMet));
8141 0 : ShowContinueErrorTimeStamp(state, format(" Cooling sensible load required = {:.2T}", TotalZoneSensLoad));
8142 : }
8143 0 : ShowRecurringWarningErrorAtEnd(
8144 : state,
8145 0 : format("{} \"{}\" - Cooling sensible part-load ratio out of range error continues. Sensible cooling load statistics:",
8146 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
8147 0 : thisFurnace.Name),
8148 0 : thisFurnace.SensibleRegulaFalsiFailedIndex,
8149 : TotalZoneSensLoad,
8150 : TotalZoneSensLoad);
8151 : }
8152 : }
8153 : }
8154 :
8155 0 : if (fanOp == HVAC::FanOp::Cycling) {
8156 0 : thisFurnace.MdotFurnace *= CoolPartLoadRatio;
8157 : }
8158 :
8159 : //*********HEATING CALCULATIONS****************
8160 : // If Furnace runs with a heating load then set HeatCoilLoad on Heating Coil and the Mass Flow
8161 0 : } else if ((thisFurnace.availSched->getCurrentVal() > 0.0) && (state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate > 0.0) &&
8162 0 : state.dataFurnaces->HeatingLoad) {
8163 :
8164 : // Set the air flow rate to the design flow rate and set the fan operation fraction to 1 (continuous operation)
8165 0 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.DesignMassFlowRate;
8166 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0; // see 'Note' under INITIAL CALCULATIONS
8167 :
8168 : // !Set the operation flag to run the fan continuously
8169 : // fanOp = FanOp::Continuous
8170 :
8171 : // Set the input parameters for CalcFurnaceOutput
8172 0 : thisFurnace.HeatingCoilSensDemand = 0.0;
8173 0 : thisFurnace.CoolingCoilLatentDemand = 0.0;
8174 0 : thisFurnace.CoolingCoilSensDemand = 0.0;
8175 0 : thisFurnace.CompPartLoadRatio = 0.0; // compressor off
8176 0 : thisFurnace.InitHeatPump = true; // initialization call to Calc Furnace
8177 0 : HeatPartLoadRatio = 0.0;
8178 :
8179 : // Get no load result in order to calculate the effect of the fan and the mixed air equipment
8180 0 : CalcFurnaceOutput(state,
8181 : FurnaceNum,
8182 : FirstHVACIteration,
8183 : fanOp,
8184 : compressorOp,
8185 : CoolPartLoadRatio,
8186 : HeatPartLoadRatio,
8187 : Dummy2,
8188 : Dummy2,
8189 : ZoneSensLoadMetFanONCompOFF,
8190 : ZoneLatLoadMetFanONCompOFF,
8191 : OnOffAirFlowRatio,
8192 : false);
8193 :
8194 : // Set the input parameters for CalcFurnaceOutput
8195 0 : thisFurnace.HeatingCoilSensDemand = 1.0;
8196 0 : thisFurnace.CompPartLoadRatio = 1.0; // compressor ON
8197 0 : HeatPartLoadRatio = 1.0;
8198 :
8199 : // Get full load result in order to estimate the operating part load ratio for continuous fan operation
8200 :
8201 0 : CalcFurnaceOutput(state,
8202 : FurnaceNum,
8203 : FirstHVACIteration,
8204 : fanOp,
8205 : compressorOp,
8206 : CoolPartLoadRatio,
8207 : HeatPartLoadRatio,
8208 : Dummy2,
8209 : Dummy2,
8210 : ZoneSensLoadMetFanONCompON,
8211 : ZoneLatLoadMetFanONCompON,
8212 : OnOffAirFlowRatio,
8213 : false);
8214 :
8215 : // Calculate the heating coil demand for continuous fan operation as:
8216 : // (the zone sensible load - the zone sensible load met by fan heat and mixed air)
8217 : // Note; The sensible zone load met by fan heat and mixed air is calculated as:
8218 : // mdotsys(control zone inlet enthalpy - control zone outlet enthalpy)
8219 : // This accounts for the negative sign in the equation.
8220 0 : HPCoilSensDemand = TotalZoneSensLoad - ZoneSensLoadMetFanONCompOFF;
8221 :
8222 : // Calculate the heating coil capacity for continuous fan operation as:
8223 : // (the zone sensible load met by fan heat and mixed air and coil
8224 : // - the zone sensible load met by fan heat and mixed air)
8225 0 : HPCoilSensCapacity = ZoneSensLoadMetFanONCompON - ZoneSensLoadMetFanONCompOFF;
8226 :
8227 : // Calculate the part load ratio for continuous fan operation with cycling coil
8228 0 : if (HPCoilSensCapacity == 0.0) {
8229 0 : HeatPartLoadRatio = 0.0;
8230 : } else {
8231 0 : HeatPartLoadRatio = max(MinPLR, min(1.0, std::abs(HPCoilSensDemand) / std::abs(HPCoilSensCapacity)));
8232 : }
8233 :
8234 0 : thisFurnace.InitHeatPump = false;
8235 :
8236 : // check bounds on sensible output prior to iteration using RegulaFalsi
8237 0 : if (ZoneSensLoadMetFanONCompON < TotalZoneSensLoad) {
8238 0 : HeatPartLoadRatio = 1.0;
8239 0 : ZoneSensLoadMet = ZoneSensLoadMetFanONCompON;
8240 0 : HPCoilSensDemand = std::abs(ZoneSensLoadMetFanONCompON - ZoneSensLoadMetFanONCompOFF);
8241 0 : thisFurnace.HeatingCoilSensDemand = HPCoilSensDemand;
8242 0 : } else if (ZoneSensLoadMetFanONCompOFF > TotalZoneSensLoad) {
8243 0 : HeatPartLoadRatio = 0.0;
8244 0 : ZoneSensLoadMet = ZoneSensLoadMetFanONCompOFF;
8245 0 : thisFurnace.CompPartLoadRatio = 0.0; // compressor ON
8246 0 : CalcFurnaceOutput(state,
8247 : FurnaceNum,
8248 : FirstHVACIteration,
8249 : fanOp,
8250 : compressorOp,
8251 : CoolPartLoadRatio,
8252 : HeatPartLoadRatio,
8253 : Dummy2,
8254 : Dummy2,
8255 : ZoneSensLoadMet,
8256 : ZoneLatLoadMet,
8257 : OnOffAirFlowRatio,
8258 : false);
8259 : } else {
8260 : // Calculate the sensible part load ratio through iteration
8261 0 : HeatErrorToler = thisFurnace.HeatingConvergenceTolerance;
8262 0 : SolFlag = 0; // # of iterations if positive, -1 means failed to converge, -2 means bounds are incorrect
8263 : // HeatErrorToler is in fraction of load, MaxIter = 600, SolFalg = # of iterations or error as appropriate
8264 0 : auto f = [&state, FurnaceNum, FirstHVACIteration, fanOp, compressorOp, TotalZoneSensLoad, ZoneSensLoadMetFanONCompOFF](
8265 : Real64 const PartLoadRatio) {
8266 0 : return CalcWaterToAirResidual(state,
8267 : PartLoadRatio,
8268 : FurnaceNum,
8269 : FirstHVACIteration,
8270 : fanOp,
8271 : compressorOp,
8272 : TotalZoneSensLoad,
8273 : 0.0,
8274 : 1.0,
8275 : ZoneSensLoadMetFanONCompOFF,
8276 0 : 0.0);
8277 0 : };
8278 0 : General::SolveRoot(state, HeatErrorToler, MaxIter, SolFlag, HeatPartLoadRatio, f, 0.0, 1.0);
8279 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = state.dataFurnaces->OnOffFanPartLoadFractionSave;
8280 0 : CalcFurnaceOutput(state,
8281 : FurnaceNum,
8282 : FirstHVACIteration,
8283 : fanOp,
8284 : compressorOp,
8285 : CoolPartLoadRatio,
8286 : HeatPartLoadRatio,
8287 : Dummy2,
8288 : Dummy2,
8289 : ZoneSensLoadMet,
8290 : ZoneLatLoadMet,
8291 : OnOffAirFlowRatio,
8292 : false);
8293 0 : if (SolFlag == -1 && !state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
8294 0 : if (std::abs(ZoneSensLoadMet - TotalZoneSensLoad) / TotalZoneSensLoad > HeatErrorToler) {
8295 0 : if (thisFurnace.WSHPHeatMaxIterIndex == 0) {
8296 0 : ShowWarningMessage(state,
8297 0 : format("Heating coil control failed to converge for {}:{}",
8298 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
8299 0 : thisFurnace.Name));
8300 0 : ShowContinueError(state, " Iteration limit exceeded in calculating DX heating coil sensible part-load ratio.");
8301 0 : ShowContinueErrorTimeStamp(state,
8302 0 : format("Sensible load to be met by DX coil = {:.2T} (watts), sensible output of DX coil = "
8303 : "{:.2T} (watts), and the simulation continues.",
8304 : TotalZoneSensLoad,
8305 : ZoneSensLoadMet));
8306 : }
8307 0 : ShowRecurringWarningErrorAtEnd(
8308 : state,
8309 0 : format("{} \"{}\" - Iteration limit exceeded in calculating sensible heating part-load ratio error continues.",
8310 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
8311 0 : thisFurnace.Name),
8312 0 : thisFurnace.WSHPHeatMaxIterIndex,
8313 : TotalZoneSensLoad,
8314 : TotalZoneSensLoad);
8315 : }
8316 0 : } else if (SolFlag == -2) {
8317 0 : HeatPartLoadRatio = max(MinPLR, min(1.0, std::abs(HPCoilSensDemand) / std::abs(HPCoilSensCapacity)));
8318 0 : CalcFurnaceOutput(state,
8319 : FurnaceNum,
8320 : FirstHVACIteration,
8321 : fanOp,
8322 : compressorOp,
8323 : 0.0,
8324 : HeatPartLoadRatio,
8325 : 0.0,
8326 : 0.0,
8327 : ZoneSensLoadMet,
8328 : ZoneLatLoadMet,
8329 : OnOffAirFlowRatio,
8330 : false);
8331 0 : if ((ZoneSensLoadMet - TotalZoneSensLoad) / TotalZoneSensLoad > HeatErrorToler) {
8332 0 : if (thisFurnace.WSHPHeatRegulaFalsiFailedIndex == 0) {
8333 0 : ShowWarningError(
8334 : state,
8335 0 : format("Heating coil control failed for {}:{}", HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name));
8336 0 : ShowContinueError(state, " Heating sensible part-load ratio determined to be outside the range of 0-1.");
8337 0 : ShowContinueError(
8338 : state,
8339 0 : format(" An estimated part-load ratio = {:.2T} will be used and the simulation continues.", HeatPartLoadRatio));
8340 0 : ShowContinueError(
8341 0 : state, format(" The estimated part-load ratio provides a heating sensible capacity = {:.2T}", ZoneSensLoadMet));
8342 0 : ShowContinueErrorTimeStamp(state, format(" Heating sensible load required = {:.2T}", TotalZoneSensLoad));
8343 : }
8344 0 : ShowRecurringWarningErrorAtEnd(state,
8345 0 : format("{} \"{}\" - Heating sensible part-load ratio out of range error continues.",
8346 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
8347 0 : thisFurnace.Name),
8348 0 : thisFurnace.WSHPHeatRegulaFalsiFailedIndex,
8349 : TotalZoneSensLoad,
8350 : TotalZoneSensLoad);
8351 : }
8352 : }
8353 : }
8354 :
8355 : // CALL supplemental heater if required
8356 0 : if ((TotalZoneSensLoad - ZoneSensLoadMet) > HVAC::SmallLoad && HeatPartLoadRatio >= 1.0) {
8357 0 : SuppHeatCoilLoad = TotalZoneSensLoad - ZoneSensLoadMet;
8358 0 : CalcFurnaceOutput(state,
8359 : FurnaceNum,
8360 : FirstHVACIteration,
8361 : fanOp,
8362 : compressorOp,
8363 : CoolPartLoadRatio,
8364 : HeatPartLoadRatio,
8365 : SuppHeatCoilLoad,
8366 : Dummy2,
8367 : ZoneSensLoadMet,
8368 : ZoneLatLoadMet,
8369 : OnOffAirFlowRatio,
8370 : false);
8371 : }
8372 :
8373 0 : if (fanOp == HVAC::FanOp::Cycling) {
8374 0 : thisFurnace.MdotFurnace *= HeatPartLoadRatio;
8375 : }
8376 :
8377 : //**********HVAC Scheduled ON, but no cooling, dehumidification or heating load*********
8378 0 : } else if (thisFurnace.availSched->getCurrentVal() > 0.0) {
8379 0 : thisFurnace.InitHeatPump = true; // initialization call to Calc Furnace
8380 0 : HeatPartLoadRatio = 0.0;
8381 0 : CoolPartLoadRatio = 0.0;
8382 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0; //! see 'Note' under INITIAL CALCULATIONS
8383 : // set report variables
8384 0 : thisFurnace.CompPartLoadRatio = 0.0;
8385 0 : thisFurnace.CoolingCoilSensDemand = 0.0;
8386 0 : thisFurnace.CoolingCoilLatentDemand = 0.0;
8387 0 : thisFurnace.HeatingCoilSensDemand = 0.0;
8388 0 : if (fanOp == HVAC::FanOp::Cycling) {
8389 0 : thisFurnace.MdotFurnace = 0.0;
8390 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0; // see 'Note' under INITIAL CALCULATIONS
8391 0 : CalcFurnaceOutput(state,
8392 : FurnaceNum,
8393 : FirstHVACIteration,
8394 : fanOp,
8395 : compressorOp,
8396 : CoolPartLoadRatio,
8397 : HeatPartLoadRatio,
8398 : Dummy2,
8399 : Dummy2,
8400 : ZoneSensLoadMet,
8401 : ZoneLatLoadMet,
8402 : OnOffAirFlowRatio,
8403 : false);
8404 0 : thisFurnace.MdotFurnace = 0.0;
8405 : } else { // continuous fan, cycling coil
8406 0 : CalcFurnaceOutput(state,
8407 : FurnaceNum,
8408 : FirstHVACIteration,
8409 : fanOp,
8410 : compressorOp,
8411 : CoolPartLoadRatio,
8412 : HeatPartLoadRatio,
8413 : Dummy2,
8414 : Dummy2,
8415 : ZoneSensLoadMet,
8416 : ZoneLatLoadMet,
8417 : OnOffAirFlowRatio,
8418 : false);
8419 : }
8420 : //*********No heating or cooling or dehumidification*********
8421 : } else {
8422 0 : thisFurnace.InitHeatPump = true; // initialization call to Calc Furnace
8423 0 : thisFurnace.MdotFurnace = 0.0;
8424 0 : HeatPartLoadRatio = 0.0;
8425 0 : CoolPartLoadRatio = 0.0;
8426 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0; // see 'Note' under INITIAL CALCULATIONS
8427 0 : thisFurnace.CompPartLoadRatio = 0.0;
8428 0 : thisFurnace.CoolingCoilSensDemand = 0.0;
8429 0 : thisFurnace.CoolingCoilLatentDemand = 0.0;
8430 0 : thisFurnace.HeatingCoilSensDemand = 0.0;
8431 0 : CalcFurnaceOutput(state,
8432 : FurnaceNum,
8433 : FirstHVACIteration,
8434 : fanOp,
8435 : compressorOp,
8436 : CoolPartLoadRatio,
8437 : HeatPartLoadRatio,
8438 : Dummy2,
8439 : Dummy2,
8440 : ZoneSensLoadMet,
8441 : ZoneLatLoadMet,
8442 : OnOffAirFlowRatio,
8443 : false);
8444 0 : thisFurnace.MdotFurnace = 0.0;
8445 : }
8446 :
8447 : // Set the fan inlet node flow rates
8448 0 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRateMaxAvail = thisFurnace.MdotFurnace;
8449 0 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.MdotFurnace;
8450 0 : }
8451 :
8452 56349 : void CalcFurnaceOutput(EnergyPlusData &state,
8453 : int const FurnaceNum,
8454 : bool const FirstHVACIteration,
8455 : HVAC::FanOp const fanOp, // Cycling fan or constant fan
8456 : HVAC::CompressorOp const compressorOp, // Compressor on/off; 1=on, 0=off
8457 : Real64 const CoolPartLoadRatio, // DX cooling coil part load ratio
8458 : Real64 const HeatPartLoadRatio, // DX heating coil part load ratio (0 for other heating coil types)
8459 : Real64 const HeatCoilLoad, // Heating coil load for gas heater
8460 : Real64 const ReheatCoilLoad, // Reheating coil load for gas heater
8461 : Real64 &SensibleLoadMet, // Sensible cooling load met (furnace outlet with respect to control zone temp)
8462 : Real64 &LatentLoadMet, // Latent cooling load met (furnace outlet with respect to control zone humidity ratio)
8463 : Real64 &OnOffAirFlowRatio, // Ratio of compressor ON mass flow rate to AVERAGE
8464 : bool const HXUnitOn, // flag to enable HX based on zone moisture load
8465 : Real64 const CoolingHeatingPLRRatio // cooling PLR to heating PLR ratio, used for cycling fan RH control
8466 : )
8467 : {
8468 :
8469 : // SUBROUTINE INFORMATION:
8470 : // AUTHOR Richard Raustad
8471 : // DATE WRITTEN Sept 2001
8472 : // MODIFIED Dec 2001
8473 :
8474 : // PURPOSE OF THIS SUBROUTINE:
8475 : // This subroutine calculates to sensible and latent loads met by the DX coils
8476 : // specified. Load met is the outlet node with respect to the control zone's
8477 : // temperature and humidity ratio.
8478 :
8479 : // METHODOLOGY EMPLOYED:
8480 : // Simulate each child object in the correct order for each system type. This routine is used in the
8481 : // RegulaFalsi function CALL. Air mass flow rate is set each iteration based on PLR.
8482 :
8483 56349 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
8484 56349 : auto &inletNode = state.dataLoopNodes->Node(thisFurnace.FurnaceInletNodeNum);
8485 56349 : int CoolingCoilType_Num = thisFurnace.CoolingCoilType_Num;
8486 56349 : Real64 QActual = 0.0; // heating coil load met or delivered
8487 56349 : state.dataFurnaces->ModifiedHeatCoilLoad = 0.0;
8488 :
8489 56349 : state.dataFurnaces->CoolHeatPLRRat = CoolingHeatingPLRRatio;
8490 :
8491 : // Cooling to Heating PLR Ratio (CoolHeatPLRRat) is used to track the air mass flow rate of both the heating
8492 : // and cooling coils when RH control is used and the heating coil operates longer than the cooling coil.
8493 : // When CoolPartLoadRatio/CoolHeatPLRRat is used, the PLR calculated is actually the PLR for the heating
8494 : // coil (heating PLR is greater than cooling PLR), it is this PLR that determines the air mass flow rate.
8495 : // When MAX(HeatPartLoadRatio,CoolPartLoadRatio) is used, only one of these values is non-zero.
8496 56349 : if (fanOp == HVAC::FanOp::Cycling) {
8497 56345 : if (state.dataFurnaces->CoolHeatPLRRat < 1.0) {
8498 0 : if (state.dataFurnaces->CoolHeatPLRRat > 0.0) {
8499 0 : inletNode.MassFlowRate = state.dataFurnaces->CompOnMassFlow * CoolPartLoadRatio / state.dataFurnaces->CoolHeatPLRRat;
8500 0 : if (thisFurnace.type != HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir) {
8501 0 : SetAverageAirFlow(state, FurnaceNum, CoolPartLoadRatio / state.dataFurnaces->CoolHeatPLRRat, OnOffAirFlowRatio);
8502 : }
8503 : } else {
8504 0 : inletNode.MassFlowRate = state.dataFurnaces->CompOnMassFlow * CoolPartLoadRatio;
8505 0 : if (thisFurnace.type != HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir) {
8506 0 : SetAverageAirFlow(state, FurnaceNum, max(HeatPartLoadRatio, CoolPartLoadRatio), OnOffAirFlowRatio);
8507 : }
8508 : }
8509 : } else {
8510 56345 : inletNode.MassFlowRate = state.dataFurnaces->CompOnMassFlow * max(HeatPartLoadRatio, CoolPartLoadRatio);
8511 56345 : if (thisFurnace.type != HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir) {
8512 56345 : SetAverageAirFlow(state, FurnaceNum, max(HeatPartLoadRatio, CoolPartLoadRatio), OnOffAirFlowRatio);
8513 : }
8514 : }
8515 : } else {
8516 4 : if (thisFurnace.type != HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir) {
8517 0 : SetAverageAirFlow(state, FurnaceNum, max(HeatPartLoadRatio, CoolPartLoadRatio), OnOffAirFlowRatio);
8518 : }
8519 : }
8520 :
8521 56349 : inletNode.MassFlowRateMaxAvail = inletNode.MassFlowRate;
8522 :
8523 : // Simulate the air-to-air heat pump
8524 56349 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir) {
8525 : // Simulate blow-thru fan and non-linear coils twice to update PLF used by the ONOFF Fan
8526 56345 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
8527 56345 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
8528 56345 : if (CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) {
8529 0 : HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(state,
8530 : BlankString,
8531 : FirstHVACIteration,
8532 : compressorOp,
8533 : CoolPartLoadRatio,
8534 0 : thisFurnace.CoolingCoilIndex,
8535 : fanOp,
8536 : HXUnitOn,
8537 : OnOffAirFlowRatio,
8538 0 : state.dataFurnaces->EconomizerFlag);
8539 : } else {
8540 112690 : DXCoils::SimDXCoil(state,
8541 : BlankString,
8542 : compressorOp,
8543 : FirstHVACIteration,
8544 56345 : thisFurnace.CoolingCoilIndex,
8545 : fanOp,
8546 : CoolPartLoadRatio,
8547 : OnOffAirFlowRatio);
8548 : }
8549 112690 : DXCoils::SimDXCoil(
8550 56345 : state, BlankString, compressorOp, FirstHVACIteration, thisFurnace.HeatingCoilIndex, fanOp, HeatPartLoadRatio, OnOffAirFlowRatio);
8551 56345 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
8552 : }
8553 : // Simulate cooling and heating coils
8554 56345 : if (CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) {
8555 0 : HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(state,
8556 : BlankString,
8557 : FirstHVACIteration,
8558 : compressorOp,
8559 : CoolPartLoadRatio,
8560 0 : thisFurnace.CoolingCoilIndex,
8561 : fanOp,
8562 : HXUnitOn,
8563 : OnOffAirFlowRatio,
8564 0 : state.dataFurnaces->EconomizerFlag);
8565 : } else {
8566 112690 : DXCoils::SimDXCoil(
8567 56345 : state, BlankString, compressorOp, FirstHVACIteration, thisFurnace.CoolingCoilIndex, fanOp, CoolPartLoadRatio, OnOffAirFlowRatio);
8568 : }
8569 112690 : DXCoils::SimDXCoil(
8570 56345 : state, BlankString, compressorOp, FirstHVACIteration, thisFurnace.HeatingCoilIndex, fanOp, HeatPartLoadRatio, OnOffAirFlowRatio);
8571 : // Simulate the draw-thru fan
8572 56345 : if (thisFurnace.fanPlace == HVAC::FanPlace::DrawThru) {
8573 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
8574 : }
8575 : // Simulate the supplemental heating coil
8576 56345 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat && ReheatCoilLoad > 0.0) {
8577 0 : bool SuppHeatingCoilFlag = true;
8578 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, ReheatCoilLoad, fanOp, QActual);
8579 0 : } else {
8580 : // equivalent to QCoilReq=0.0d0 or ReHeatCoilLoad = 0.0d0
8581 56345 : bool SuppHeatingCoilFlag = true;
8582 56345 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, ReheatCoilLoad, fanOp, QActual);
8583 : }
8584 : // Simulate the parameter estimate water-to-air heat pump
8585 4 : } else if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir && thisFurnace.WatertoAirHPType == WAHPCoilType::Simple) {
8586 : // Simulate blow-thru fan and non-linear coils twice to update PLF used by the ONOFF Fan
8587 4 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
8588 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
8589 : // COIL:WATERTOAIRHPSIMPLE:COOLING
8590 0 : WaterToAirHeatPumpSimple::SimWatertoAirHPSimple(state,
8591 : BlankString,
8592 0 : thisFurnace.CoolingCoilIndex,
8593 : thisFurnace.CoolingCoilSensDemand,
8594 : thisFurnace.CoolingCoilLatentDemand,
8595 : fanOp,
8596 : compressorOp,
8597 : CoolPartLoadRatio,
8598 : FirstHVACIteration); // CoolPartLoadRatio
8599 0 : Real64 Dummy = 0.0;
8600 : // COIL:WATERTOAIRHPSIMPLE:HEATING
8601 0 : WaterToAirHeatPumpSimple::SimWatertoAirHPSimple(state,
8602 : BlankString,
8603 0 : thisFurnace.HeatingCoilIndex,
8604 : thisFurnace.HeatingCoilSensDemand,
8605 : Dummy,
8606 : fanOp,
8607 : compressorOp,
8608 : HeatPartLoadRatio,
8609 : FirstHVACIteration); // HeatPartLoadRatio
8610 : // Simulate the whole thing a second time so that the correct PLF required by the coils is used by the Fan. *******
8611 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
8612 : }
8613 : // Simulate the cooling and heating coils
8614 : // COIL:WATERTOAIRHPSIMPLE:COOLING
8615 4 : WaterToAirHeatPumpSimple::SimWatertoAirHPSimple(state,
8616 : BlankString,
8617 4 : thisFurnace.CoolingCoilIndex,
8618 : thisFurnace.CoolingCoilSensDemand,
8619 : thisFurnace.CoolingCoilLatentDemand,
8620 : fanOp,
8621 : compressorOp,
8622 : CoolPartLoadRatio,
8623 : FirstHVACIteration); // CoolPartLoadRatio
8624 4 : Real64 Dummy = 0.0;
8625 : // COIL:WATERTOAIRHPSIMPLE:HEATING
8626 4 : WaterToAirHeatPumpSimple::SimWatertoAirHPSimple(state,
8627 : BlankString,
8628 4 : thisFurnace.HeatingCoilIndex,
8629 : thisFurnace.HeatingCoilSensDemand,
8630 : Dummy,
8631 : fanOp,
8632 : compressorOp,
8633 : HeatPartLoadRatio,
8634 : FirstHVACIteration); // HeatPartLoadRatio
8635 : // Simulate the draw-thru fan
8636 4 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
8637 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
8638 : }
8639 : // Simulate the supplemental heating coil
8640 4 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat && ReheatCoilLoad > 0.0) {
8641 0 : bool SuppHeatingCoilFlag = true; // if true simulates supplemental heating coil
8642 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, ReheatCoilLoad, fanOp, QActual);
8643 0 : } else {
8644 4 : bool SuppHeatingCoilFlag = true; // if true simulates supplemental heating coil
8645 4 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, fanOp, QActual);
8646 : }
8647 : // Simulate the detailed water-to-air heat pump
8648 4 : } else if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir && thisFurnace.WatertoAirHPType == WAHPCoilType::ParEst) {
8649 : // Simulate the draw-thru fan
8650 0 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
8651 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
8652 : }
8653 : // Simulate the cooling and heating coils
8654 0 : WaterToAirHeatPump::SimWatertoAirHP(state,
8655 : BlankString,
8656 0 : thisFurnace.CoolingCoilIndex,
8657 : thisFurnace.DesignMassFlowRate,
8658 : fanOp,
8659 : FirstHVACIteration,
8660 0 : thisFurnace.InitHeatPump,
8661 : thisFurnace.CoolingCoilSensDemand,
8662 : thisFurnace.CoolingCoilLatentDemand,
8663 : compressorOp,
8664 : CoolPartLoadRatio);
8665 0 : Real64 Dummy = 0.0;
8666 0 : WaterToAirHeatPump::SimWatertoAirHP(state,
8667 : BlankString,
8668 0 : thisFurnace.HeatingCoilIndex,
8669 : thisFurnace.DesignMassFlowRate,
8670 : fanOp,
8671 : FirstHVACIteration,
8672 0 : thisFurnace.InitHeatPump,
8673 : thisFurnace.HeatingCoilSensDemand,
8674 : Dummy,
8675 : compressorOp,
8676 : HeatPartLoadRatio);
8677 : // Simulate the draw-thru fan
8678 0 : if (thisFurnace.fanPlace == HVAC::FanPlace::DrawThru) {
8679 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
8680 : }
8681 : // Simulate the supplemental heating coil
8682 0 : HeatingCoils::SimulateHeatingCoilComponents(
8683 0 : state, BlankString, FirstHVACIteration, HeatCoilLoad, thisFurnace.SuppHeatCoilIndex, _, true, fanOp);
8684 :
8685 0 : } else { // ELSE it's not a heat pump
8686 : // Simulate blow-thru fan
8687 0 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
8688 :
8689 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
8690 :
8691 : // For non-linear coils, simulate coil to update PLF used by the ONOFF Fan
8692 0 : if (thisFurnace.fanType == HVAC::FanType::OnOff) {
8693 0 : if (thisFurnace.type != HVAC::UnitarySysType::Unitary_HeatOnly && thisFurnace.type != HVAC::UnitarySysType::Furnace_HeatOnly) {
8694 :
8695 0 : if (!thisFurnace.CoolingCoilUpstream) {
8696 0 : bool SuppHeatingCoilFlag = false; // if false simulates heating coil
8697 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, fanOp, QActual);
8698 : }
8699 :
8700 0 : if (CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) {
8701 0 : HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(state,
8702 : BlankString,
8703 : FirstHVACIteration,
8704 : compressorOp,
8705 : CoolPartLoadRatio,
8706 0 : thisFurnace.CoolingCoilIndex,
8707 : fanOp,
8708 : HXUnitOn,
8709 : OnOffAirFlowRatio,
8710 0 : state.dataFurnaces->EconomizerFlag);
8711 : } else {
8712 0 : DXCoils::SimDXCoil(state,
8713 : BlankString,
8714 : compressorOp,
8715 : FirstHVACIteration,
8716 0 : thisFurnace.CoolingCoilIndex,
8717 : fanOp,
8718 : CoolPartLoadRatio,
8719 : OnOffAirFlowRatio,
8720 0 : state.dataFurnaces->CoolHeatPLRRat);
8721 : }
8722 : }
8723 :
8724 0 : if (thisFurnace.CoolingCoilUpstream) {
8725 0 : bool SuppHeatingCoilFlag = false; // if false simulates heating coil
8726 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, fanOp, QActual);
8727 : }
8728 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
8729 : } // Simple OnOff fan
8730 :
8731 : } // Blow thru fan
8732 :
8733 : // Simulate the cooling and heating coils
8734 0 : if (thisFurnace.type != HVAC::UnitarySysType::Unitary_HeatOnly && thisFurnace.type != HVAC::UnitarySysType::Furnace_HeatOnly) {
8735 :
8736 0 : if (!thisFurnace.CoolingCoilUpstream) {
8737 0 : bool SuppHeatingCoilFlag = false; // if false simulates heating coil
8738 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, fanOp, QActual);
8739 : }
8740 :
8741 0 : if (CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) {
8742 0 : HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(state,
8743 : BlankString,
8744 : FirstHVACIteration,
8745 : compressorOp,
8746 : CoolPartLoadRatio,
8747 0 : thisFurnace.CoolingCoilIndex,
8748 : fanOp,
8749 : HXUnitOn,
8750 : OnOffAirFlowRatio,
8751 0 : state.dataFurnaces->EconomizerFlag);
8752 : } else {
8753 0 : DXCoils::SimDXCoil(state,
8754 : BlankString,
8755 : compressorOp,
8756 : FirstHVACIteration,
8757 0 : thisFurnace.CoolingCoilIndex,
8758 : fanOp,
8759 : CoolPartLoadRatio,
8760 : OnOffAirFlowRatio,
8761 0 : state.dataFurnaces->CoolHeatPLRRat);
8762 : }
8763 : }
8764 :
8765 0 : if (thisFurnace.CoolingCoilUpstream) {
8766 0 : bool SuppHeatingCoilFlag = false; // if false simulates heating coil
8767 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, fanOp, QActual);
8768 : }
8769 : // Simulate the draw-thru fan
8770 0 : if (thisFurnace.fanPlace == HVAC::FanPlace::DrawThru) {
8771 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
8772 : }
8773 0 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat || thisFurnace.SuppHeatCoilIndex > 0) {
8774 0 : bool SuppHeatingCoilFlag = true; // if true simulates supplemental heating coil
8775 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, ReheatCoilLoad, fanOp, QActual);
8776 : }
8777 : } // IF(Furnace(FurnaceNum)%type == UnitarySys_HeatPump_AirToAir)THEN
8778 :
8779 : // Get mass flow rate after components are simulated
8780 56349 : auto &outletNode = state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum);
8781 56349 : Real64 AirMassFlow = inletNode.MassFlowRate; // this should be outlet node as in 9897?
8782 :
8783 : // check the DesignMaxOutletTemp and reset if necessary (for Coil:Gas:Heating or Coil:Electric:Heating only)
8784 56349 : if (outletNode.Temp > thisFurnace.DesignMaxOutletTemp) {
8785 0 : Real64 Wout = outletNode.HumRat;
8786 0 : Real64 Tout = thisFurnace.DesignMaxOutletTemp;
8787 0 : state.dataFurnaces->ModifiedHeatCoilLoad = HeatCoilLoad - (AirMassFlow * Psychrometrics::PsyCpAirFnW(Wout) * (outletNode.Temp - Tout));
8788 0 : outletNode.Temp = Tout;
8789 : }
8790 :
8791 : // If the fan runs continually do not allow coils to set OnOffFanPartLoadRatio.
8792 56349 : if (fanOp == HVAC::FanOp::Continuous) {
8793 4 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
8794 : }
8795 :
8796 56349 : Real64 SensibleOutput = 0.0; // sensible output rate, {W}
8797 56349 : Real64 LatentOutput = 0.0; // latent output rate, {W}
8798 56349 : Real64 TotalOutput = 0.0; // total output rate, {W}
8799 112698 : CalcZoneSensibleLatentOutput(AirMassFlow,
8800 : outletNode.Temp,
8801 : outletNode.HumRat,
8802 56349 : state.dataLoopNodes->Node(thisFurnace.NodeNumOfControlledZone).Temp,
8803 56349 : state.dataLoopNodes->Node(thisFurnace.NodeNumOfControlledZone).HumRat,
8804 : SensibleOutput,
8805 : LatentOutput,
8806 : TotalOutput);
8807 56349 : SensibleLoadMet = SensibleOutput - thisFurnace.SenLoadLoss;
8808 56349 : thisFurnace.SensibleLoadMet = SensibleLoadMet;
8809 :
8810 56349 : if (thisFurnace.Humidistat) {
8811 0 : LatentLoadMet = LatentOutput - thisFurnace.LatLoadLoss;
8812 : } else {
8813 56349 : LatentLoadMet = 0.0;
8814 : }
8815 56349 : thisFurnace.LatentLoadMet = LatentLoadMet;
8816 56349 : }
8817 :
8818 : // End of Update subroutines for the Furnace Module
8819 : // *****************************************************************************
8820 :
8821 20268 : Real64 CalcFurnaceResidual(EnergyPlusData &state,
8822 : Real64 const PartLoadRatio, // DX cooling coil part load ratio
8823 : int FurnaceNum,
8824 : bool FirstHVACIteration,
8825 : HVAC::FanOp const fanOp,
8826 : HVAC::CompressorOp compressorOp,
8827 : Real64 LoadToBeMet,
8828 : Real64 par6_loadFlag,
8829 : Real64 par7_sensLatentFlag,
8830 : Real64 par9_HXOnFlag,
8831 : Real64 par10_HeatingCoilPLR)
8832 : {
8833 :
8834 : // FUNCTION INFORMATION:
8835 : // AUTHOR Richard Raustad
8836 : // DATE WRITTEN Feb 2005
8837 :
8838 : // PURPOSE OF THIS SUBROUTINE:
8839 : // To calculate the part-load ratio for cooling and heating coils
8840 :
8841 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
8842 : Real64 CoolPartLoadRatio; // DX cooling coil part load ratio
8843 : Real64 HeatPartLoadRatio; // DX heating coil part load ratio (0 for other heating coil types)
8844 : Real64 HeatCoilLoad; // Heating coil load for gas heater
8845 : Real64 SensibleLoadMet; // Sensible cooling load met (furnace outlet with respect to control zone temp)
8846 : Real64 LatentLoadMet; // Latent cooling load met (furnace outlet with respect to control zone humidity ratio)
8847 : Real64 OnOffAirFlowRatio; // Ratio of compressor ON air mass flow to AVERAGE air mass flow over time step
8848 : Real64 CoolingHeatingPLRRatio; // ratio of cooling PLR to heating PLR, used for cycling fan RH control
8849 : bool HXUnitOn; // flag to enable HX based on zone moisture load
8850 :
8851 : // // Convert parameters to usable variables
8852 : // int FurnaceNum = int(Par(1));
8853 : // bool FirstHVACIteration = Par(2) == 1.0;
8854 : // int FanfanOp = int(Par(3));
8855 : // CompressorOperation CompressorOp = static_cast<CompressorOperation>(Par(4));
8856 : // Real64 LoadToBeMet = Par(5);
8857 : // Real64 par6_loadFlag = Par(6);
8858 : // Real64 par7_sensLatentFlag = Par(7);
8859 : // Real64 par9_HXOnFlag = Par(9);
8860 : // Real64 par10_HeatingCoilPLR = Par(10);
8861 :
8862 20268 : if (par6_loadFlag == 1.0) {
8863 20244 : CoolPartLoadRatio = PartLoadRatio;
8864 20244 : HeatPartLoadRatio = 0.0;
8865 20244 : HeatCoilLoad = 0.0;
8866 : } else {
8867 24 : CoolPartLoadRatio = 0.0;
8868 24 : HeatPartLoadRatio = PartLoadRatio;
8869 :
8870 24 : int const HeatingCoilType_Num(state.dataFurnaces->Furnace(FurnaceNum).HeatingCoilType_Num);
8871 24 : if (HeatingCoilType_Num == HVAC::Coil_HeatingGasOrOtherFuel || HeatingCoilType_Num == HVAC::Coil_HeatingElectric ||
8872 24 : HeatingCoilType_Num == HVAC::Coil_HeatingWater || HeatingCoilType_Num == HVAC::Coil_HeatingSteam) {
8873 0 : HeatCoilLoad = state.dataFurnaces->Furnace(FurnaceNum).DesignHeatingCapacity * PartLoadRatio;
8874 : } else {
8875 24 : HeatCoilLoad = 0.0;
8876 : }
8877 : }
8878 :
8879 : // OnOffAirFlowRatio = Par(8)
8880 20268 : if (state.dataFurnaces->Furnace(FurnaceNum).type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir) {
8881 0 : state.dataFurnaces->Furnace(FurnaceNum).CompPartLoadRatio = PartLoadRatio;
8882 : }
8883 :
8884 20268 : if (par9_HXOnFlag == 1.0) {
8885 20244 : HXUnitOn = true;
8886 : } else {
8887 24 : HXUnitOn = false;
8888 : }
8889 :
8890 20268 : if (par10_HeatingCoilPLR > 0.0) {
8891 : // Par(10) = Furnace(FurnaceNum)%HeatPartLoadRatio
8892 : // FanOp = CycFan and Furnace(FurnaceNum)%HeatPartLoadRatio must be > 0 for Part(10) to be greater than 0
8893 : // This variable used when in heating mode and dehumidification (cooling) is required.
8894 0 : CoolingHeatingPLRRatio = min(1.0, CoolPartLoadRatio / state.dataFurnaces->Furnace(FurnaceNum).HeatPartLoadRatio);
8895 : } else {
8896 20268 : CoolingHeatingPLRRatio = 1.0;
8897 : }
8898 :
8899 : // Subroutine arguments
8900 20268 : CalcFurnaceOutput(state,
8901 : FurnaceNum,
8902 : FirstHVACIteration,
8903 : fanOp,
8904 : compressorOp,
8905 : CoolPartLoadRatio,
8906 : HeatPartLoadRatio,
8907 : HeatCoilLoad,
8908 : 0.0,
8909 : SensibleLoadMet,
8910 : LatentLoadMet,
8911 : OnOffAirFlowRatio,
8912 : HXUnitOn,
8913 : CoolingHeatingPLRRatio);
8914 :
8915 : // Calculate residual based on output calculation flag
8916 20268 : if (par7_sensLatentFlag == 1.0) {
8917 20268 : if (LoadToBeMet == 0.0) {
8918 0 : return (SensibleLoadMet - LoadToBeMet) / 100.0;
8919 : } else {
8920 20268 : return (SensibleLoadMet - LoadToBeMet) / LoadToBeMet;
8921 : }
8922 : } else {
8923 0 : if (LoadToBeMet == 0.0) {
8924 0 : return (LatentLoadMet - LoadToBeMet) / 100.0;
8925 : } else {
8926 0 : return (LatentLoadMet - LoadToBeMet) / LoadToBeMet;
8927 : }
8928 : }
8929 : }
8930 :
8931 0 : Real64 CalcWaterToAirResidual(EnergyPlusData &state,
8932 : Real64 const PartLoadRatio, // DX cooling coil part load ratio
8933 : int FurnaceNum,
8934 : bool FirstHVACIteration,
8935 : HVAC::FanOp const fanOp,
8936 : HVAC::CompressorOp compressorOp,
8937 : Real64 LoadToBeMet,
8938 : Real64 par6_loadTypeFlag,
8939 : Real64 par7_latentOrSensible,
8940 : Real64 ZoneSensLoadMetFanONCompOFF,
8941 : Real64 par9_HXUnitOne)
8942 : {
8943 :
8944 : // FUNCTION INFORMATION:
8945 : // AUTHOR Richard Raustad
8946 : // DATE WRITTEN October 2006
8947 :
8948 : // PURPOSE OF THIS SUBROUTINE:
8949 : // To calculate the part-load ratio for water to air HP's
8950 : // this is used for parameter estimation WAHPs but not equation fit WAHPs
8951 :
8952 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
8953 : Real64 CoolPartLoadRatio; // DX cooling coil part load ratio
8954 : Real64 HeatPartLoadRatio; // DX heating coil part load ratio (0 for other heating coil types)
8955 : Real64 HeatCoilLoad; // Heating coil load for gas heater
8956 : Real64 ZoneSensLoadMet; // Sensible cooling load met (furnace outlet with respect to control zone temp)
8957 : Real64 ZoneLatLoadMet; // Latent cooling load met (furnace outlet with respect to control zone humidity ratio)
8958 : Real64 Dummy;
8959 : Real64 HPCoilSensDemand;
8960 : Real64 OnOffAirFlowRatio;
8961 : bool HXUnitOn; // flag to enable HX based on zone moisture load (not valid for water-to-air HP's
8962 :
8963 : // Convert parameters to usable variables
8964 : // int FurnaceNum = int(Par[0]);
8965 : // bool FirstHVACIteration = Par[1] == 1.0;
8966 : // int FanOp = int(Par[2]);
8967 : // CompressorOperation CompressorOp = static_cast<CompressorOperation>(Par[3]);
8968 : // Real64 LoadToBeMet = Par[4];
8969 : // Real64 par6_loadTypeFlag = Par[5];
8970 : // Real64 par7_latentOrSensible = Par[6];
8971 : // Real64 ZoneSensLoadMetFanONCompOFF = Par[7];
8972 : // Real64 par9_HXUnitOne = Par[8];
8973 :
8974 : int CoilIndex;
8975 0 : if (par6_loadTypeFlag == 1.0) {
8976 0 : CoolPartLoadRatio = PartLoadRatio;
8977 0 : HeatPartLoadRatio = 0.0;
8978 0 : HeatCoilLoad = 0.0;
8979 0 : CoilIndex = state.dataFurnaces->Furnace(FurnaceNum).CoolingCoilIndex;
8980 : } else {
8981 0 : CoolPartLoadRatio = 0.0;
8982 0 : HeatPartLoadRatio = PartLoadRatio;
8983 0 : CoilIndex = state.dataFurnaces->Furnace(FurnaceNum).HeatingCoilIndex;
8984 : }
8985 :
8986 : // Get child component RuntimeFrac
8987 : Real64 RuntimeFrac;
8988 0 : switch (state.dataFurnaces->Furnace(FurnaceNum).WatertoAirHPType) {
8989 0 : case WAHPCoilType::Simple: {
8990 0 : RuntimeFrac = state.dataWaterToAirHeatPumpSimple->SimpleWatertoAirHP(CoilIndex).RunFrac;
8991 0 : break;
8992 : }
8993 0 : case WAHPCoilType::ParEst: {
8994 0 : RuntimeFrac = state.dataWaterToAirHeatPump->WatertoAirHP(CoilIndex).RunFrac;
8995 0 : break;
8996 : }
8997 0 : case WAHPCoilType::VarSpeedEquationFit: {
8998 0 : RuntimeFrac = state.dataVariableSpeedCoils->VarSpeedCoil(CoilIndex).RunFrac;
8999 0 : break;
9000 : }
9001 0 : default:
9002 0 : RuntimeFrac = 1.0; // Programming error. Assert failure?
9003 : }
9004 :
9005 0 : state.dataFurnaces->OnOffFanPartLoadFractionSave = state.dataHVACGlobal->OnOffFanPartLoadFraction;
9006 : // update fan and compressor run times
9007 0 : state.dataFurnaces->Furnace(FurnaceNum).CompPartLoadRatio = PartLoadRatio;
9008 :
9009 : // Calculate the heating coil demand as (the zone sensible load - load met by fan heat and mixed air)
9010 : // Note; The load met by fan heat and mixed air is calculated as mdot(zoneinletenthalpy-zoneoutletenthalpy)
9011 : // This accounts for the negative sign in the equation.
9012 :
9013 : // Calculate the heat coil sensible capacity as the load met by the system with the fan and compressor on less
9014 : // the load met by the system with the compressor off.
9015 : // HPCoilSensCapacity = ZoneSensLoadMetFanONCompON - ZoneSensLoadMetFanONCompOFF
9016 :
9017 : // Set input parameters for heat pump coil model
9018 0 : HPCoilSensDemand = LoadToBeMet - RuntimeFrac * ZoneSensLoadMetFanONCompOFF;
9019 : // HPCoilSensDemand = LoadToBeMet - PartLoadRatio*ZoneSensLoadMetFanONCompOFF
9020 0 : if (par6_loadTypeFlag == 1.0) {
9021 0 : state.dataFurnaces->Furnace(FurnaceNum).HeatingCoilSensDemand = 0.0;
9022 0 : state.dataFurnaces->Furnace(FurnaceNum).CoolingCoilSensDemand = std::abs(HPCoilSensDemand);
9023 : } else {
9024 0 : state.dataFurnaces->Furnace(FurnaceNum).HeatingCoilSensDemand = HPCoilSensDemand;
9025 0 : state.dataFurnaces->Furnace(FurnaceNum).CoolingCoilSensDemand = 0.0;
9026 : }
9027 0 : state.dataFurnaces->Furnace(FurnaceNum).InitHeatPump = false; // initialization call to Calc Furnace
9028 :
9029 : // Calculate the zone loads met and the new part load ratio and for the specified run time
9030 0 : Dummy = 0.0;
9031 0 : OnOffAirFlowRatio = 1.0;
9032 0 : if (par9_HXUnitOne == 1.0) {
9033 0 : HXUnitOn = true;
9034 : } else {
9035 0 : HXUnitOn = false;
9036 : }
9037 :
9038 : // Subroutine arguments
9039 : // CALL CalcFurnaceOutput(FurnaceNum,FirstHVACIteration,FanOp,compressorOp,CoolPartLoadRatio,&
9040 : // HeatPartLoadRatio, HeatCoilLoad, ReHeatCoilLoad, SensibleLoadMet, LatentLoadMet, HXUnitOn)
9041 0 : CalcFurnaceOutput(state,
9042 : FurnaceNum,
9043 : FirstHVACIteration,
9044 : fanOp,
9045 : compressorOp,
9046 : CoolPartLoadRatio,
9047 : HeatPartLoadRatio,
9048 : Dummy,
9049 : Dummy,
9050 : ZoneSensLoadMet,
9051 : ZoneLatLoadMet,
9052 : OnOffAirFlowRatio,
9053 : HXUnitOn);
9054 :
9055 : // Calculate residual based on output calculation flag
9056 0 : if (par7_latentOrSensible == 1.0) {
9057 0 : return (ZoneSensLoadMet - LoadToBeMet) / LoadToBeMet;
9058 : } else {
9059 0 : return (ZoneLatLoadMet - LoadToBeMet) / LoadToBeMet;
9060 : }
9061 : }
9062 :
9063 97113 : void SetAverageAirFlow(EnergyPlusData &state,
9064 : int const FurnaceNum, // Unit index
9065 : Real64 const PartLoadRatio, // unit part load ratio
9066 : Real64 &OnOffAirFlowRatio // ratio of compressor ON airflow to AVERAGE airflow over timestep
9067 : )
9068 : {
9069 :
9070 : // SUBROUTINE INFORMATION:
9071 : // AUTHOR Richard Raustad
9072 : // DATE WRITTEN July 2005
9073 :
9074 : // PURPOSE OF THIS SUBROUTINE:
9075 : // Set the average air mass flow rates using the part-load fraction of the HVAC system for this time step
9076 : // Set OnOffAirFlowRatio to be used by DX coils
9077 :
9078 : // METHODOLOGY EMPLOYED:
9079 : // The air flow rate in cooling, heating, and no cooling or heating can be different.
9080 : // Calculate the air flow rate based on initializations made in InitFurnace.
9081 :
9082 97113 : int InletNode = state.dataFurnaces->Furnace(FurnaceNum).FurnaceInletNodeNum;
9083 : Real64 AverageUnitMassFlow =
9084 97113 : (PartLoadRatio * state.dataFurnaces->CompOnMassFlow) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffMassFlow);
9085 97113 : if (state.dataFurnaces->CompOffFlowRatio > 0.0) {
9086 4 : state.dataFurnaces->FanSpeedRatio =
9087 4 : (PartLoadRatio * state.dataFurnaces->CompOnFlowRatio) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffFlowRatio);
9088 : } else {
9089 97109 : state.dataFurnaces->FanSpeedRatio = state.dataFurnaces->CompOnFlowRatio;
9090 : }
9091 :
9092 : // IF the furnace is scheduled on or nightime cycle overrides fan schedule. Uses same logic as fan.
9093 291339 : if (state.dataFurnaces->Furnace(FurnaceNum).availSched->getCurrentVal() > 0.0 &&
9094 97113 : ((state.dataFurnaces->Furnace(FurnaceNum).fanAvailSched->getCurrentVal() > 0.0 || state.dataHVACGlobal->TurnFansOn) &&
9095 97113 : !state.dataHVACGlobal->TurnFansOff)) {
9096 97107 : state.dataLoopNodes->Node(InletNode).MassFlowRate = AverageUnitMassFlow;
9097 97107 : state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AverageUnitMassFlow;
9098 97107 : if (AverageUnitMassFlow > 0.0) {
9099 66059 : OnOffAirFlowRatio = state.dataFurnaces->CompOnMassFlow / AverageUnitMassFlow;
9100 : } else {
9101 31048 : OnOffAirFlowRatio = 0.0;
9102 : }
9103 : } else {
9104 6 : state.dataLoopNodes->Node(InletNode).MassFlowRate = 0.0;
9105 6 : OnOffAirFlowRatio = 1.0;
9106 : }
9107 :
9108 97113 : state.dataFurnaces->Furnace(FurnaceNum).MdotFurnace = state.dataFurnaces->CompOnMassFlow;
9109 97113 : state.dataFurnaces->OnOffAirFlowRatioSave = OnOffAirFlowRatio;
9110 97113 : }
9111 :
9112 : // Beginning of Reporting subroutines for the Furnace Module
9113 : // *****************************************************************************
9114 :
9115 15224 : void ReportFurnace(EnergyPlusData &state, int const FurnaceNum, int const AirLoopNum)
9116 : {
9117 :
9118 : // SUBROUTINE INFORMATION:
9119 : // AUTHOR Richard Liesen
9120 : // DATE WRITTEN Feb 2001
9121 :
9122 : // PURPOSE OF THIS SUBROUTINE:
9123 : // This subroutine updates the report variable for the coils.
9124 :
9125 : // METHODOLOGY EMPLOYED:
9126 : // Update fan part-load ratio based on mass flow rate ratio.
9127 : // Update global variables used by AirflowNetwork module.
9128 :
9129 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
9130 : Real64 ratio;
9131 : Real64 OnOffRatio;
9132 15224 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
9133 :
9134 : // Report the Furnace Fan Part Load Ratio
9135 15224 : if (thisFurnace.NumOfSpeedCooling < 1) {
9136 15224 : if (thisFurnace.DesignMassFlowRate > 0.0) {
9137 15224 : thisFurnace.FanPartLoadRatio = thisFurnace.MdotFurnace / thisFurnace.DesignMassFlowRate;
9138 : } else {
9139 0 : thisFurnace.FanPartLoadRatio = 0.0;
9140 : }
9141 : }
9142 :
9143 : // Set mass flow rates during on and off cycle using an OnOff fan
9144 15224 : if (state.afn->distribution_simulated) {
9145 11170 : state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopSystemOnMassFlowrate = state.dataFurnaces->CompOnMassFlow;
9146 11170 : state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopSystemOffMassFlowrate = state.dataFurnaces->CompOffMassFlow;
9147 11170 : state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopFanOperationMode = thisFurnace.fanOp;
9148 11170 : state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopOnOffFanPartLoadRatio = thisFurnace.FanPartLoadRatio;
9149 11170 : OnOffRatio = state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopOnOffFanPartLoadRatio;
9150 11170 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir) {
9151 11169 : state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopOnOffFanPartLoadRatio =
9152 11169 : max(thisFurnace.FanPartLoadRatio, thisFurnace.HeatPartLoadRatio, thisFurnace.CoolPartLoadRatio);
9153 11169 : state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopOnOffFanPartLoadRatio =
9154 11169 : min(1.0, state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopOnOffFanPartLoadRatio);
9155 : }
9156 11170 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool) {
9157 1 : if (thisFurnace.HeatPartLoadRatio == 0.0 && thisFurnace.CoolPartLoadRatio == 0.0 && thisFurnace.FanPartLoadRatio > 0.0) {
9158 2 : if (state.dataFurnaces->CompOnMassFlow < max(thisFurnace.MaxCoolAirMassFlow, thisFurnace.MaxHeatAirMassFlow) &&
9159 1 : state.dataFurnaces->CompOnMassFlow > 0.0) {
9160 1 : ratio = max(thisFurnace.MaxCoolAirMassFlow, thisFurnace.MaxHeatAirMassFlow) / state.dataFurnaces->CompOnMassFlow;
9161 1 : state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopOnOffFanPartLoadRatio =
9162 1 : state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopOnOffFanPartLoadRatio * ratio;
9163 : }
9164 : }
9165 : }
9166 : }
9167 15224 : if (thisFurnace.FirstPass) {
9168 3 : if (!state.dataGlobal->SysSizingCalc) {
9169 3 : DataSizing::resetHVACSizingGlobals(state, 0, state.dataSize->CurSysNum, thisFurnace.FirstPass);
9170 : }
9171 : }
9172 15224 : state.dataHVACGlobal->OnOffFanPartLoadFraction =
9173 : 1.0; // reset to 1 in case blow through fan configuration (fan resets to 1, but for blow thru fans coil sets back down < 1)
9174 15224 : }
9175 :
9176 71571 : void CalcNonDXHeatingCoils(EnergyPlusData &state,
9177 : int const FurnaceNum, // Furnace Index
9178 : bool const SuppHeatingCoilFlag, // .TRUE. if supplemental heating coil
9179 : bool const FirstHVACIteration, // flag for first HVAC iteration in the time step
9180 : Real64 const QCoilLoad, // load met by unit (watts)
9181 : HVAC::FanOp const fanOp, // fan operation mode
9182 : Real64 &HeatCoilLoadmet // Heating Load Met
9183 : )
9184 : {
9185 : // SUBROUTINE INFORMATION:
9186 : // AUTHOR Bereket Nigusse, FSEC/UCF
9187 : // DATE WRITTEN January 2012
9188 :
9189 : // PURPOSE OF THIS SUBROUTINE:
9190 : // This subroutine simulates the four non dx heating coil types: Gas, Electric, hot water and steam.
9191 :
9192 : // METHODOLOGY EMPLOYED:
9193 : // Simply calls the different heating coil component. The hot water flow rate matching the coil load
9194 : // is calculated iteratively.
9195 :
9196 : // SUBROUTINE PARAMETER DEFINITIONS:
9197 71571 : Real64 constexpr ErrTolerance(0.001); // convergence limit for hotwater coil
9198 71571 : int constexpr SolveMaxIter(50);
9199 :
9200 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
9201 : Real64 mdot; // heating coil steam or hot water mass flow rate
9202 : Real64 MinWaterFlow; // coil minimum hot water mass flow rate, kg/s
9203 : Real64 MaxHotWaterFlow; // coil maximum hot water mass flow rate, kg/s
9204 : Real64 HotWaterMdot; // actual hot water mass flow rate
9205 71571 : int CoilTypeNum(0); // heating coil type number
9206 71571 : int HeatingCoilIndex(0); // heating coil index
9207 71571 : int CoilControlNode(0); // control node for hot water and steam heating coils
9208 71571 : int CoilOutletNode(0); // air outlet node of the heating coils
9209 71571 : PlantLocation plantLoc{}; // plant loop location
9210 :
9211 71571 : Real64 QActual = 0.0; // actual heating load
9212 71571 : std::string &HeatingCoilName = state.dataFurnaces->HeatingCoilName; // name of heating coil
9213 71571 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
9214 :
9215 71571 : if (SuppHeatingCoilFlag) {
9216 71571 : HeatingCoilName = thisFurnace.SuppHeatCoilName;
9217 71571 : HeatingCoilIndex = thisFurnace.SuppHeatCoilIndex;
9218 71571 : CoilControlNode = thisFurnace.SuppCoilControlNode;
9219 71571 : CoilOutletNode = thisFurnace.SuppCoilOutletNode;
9220 71571 : CoilTypeNum = thisFurnace.SuppHeatCoilType_Num;
9221 71571 : plantLoc = thisFurnace.SuppPlantLoc;
9222 71571 : MaxHotWaterFlow = thisFurnace.MaxSuppCoilFluidFlow;
9223 : } else {
9224 0 : HeatingCoilName = thisFurnace.HeatingCoilName;
9225 0 : HeatingCoilIndex = thisFurnace.HeatingCoilIndex;
9226 0 : CoilControlNode = thisFurnace.CoilControlNode;
9227 0 : CoilOutletNode = thisFurnace.CoilOutletNode;
9228 0 : CoilTypeNum = thisFurnace.HeatingCoilType_Num;
9229 0 : plantLoc = thisFurnace.plantLoc;
9230 0 : MaxHotWaterFlow = thisFurnace.MaxHeatCoilFluidFlow;
9231 : }
9232 :
9233 71571 : switch (CoilTypeNum) {
9234 71567 : case HVAC::Coil_HeatingGasOrOtherFuel:
9235 : case HVAC::Coil_HeatingElectric:
9236 : case HVAC::Coil_HeatingDesuperheater: {
9237 71567 : HeatingCoils::SimulateHeatingCoilComponents(
9238 : state, HeatingCoilName, FirstHVACIteration, QCoilLoad, HeatingCoilIndex, QActual, SuppHeatingCoilFlag, fanOp);
9239 71567 : } break;
9240 0 : case HVAC::Coil_HeatingWater: {
9241 0 : if (QCoilLoad > HVAC::SmallLoad) {
9242 0 : PlantUtilities::SetComponentFlowRate(state, MaxHotWaterFlow, CoilControlNode, CoilOutletNode, plantLoc);
9243 0 : WaterCoils::SimulateWaterCoilComponents(state, HeatingCoilName, FirstHVACIteration, HeatingCoilIndex, QActual, fanOp);
9244 :
9245 0 : if (QActual > (QCoilLoad + HVAC::SmallLoad)) {
9246 : // control water flow to obtain output matching QCoilLoad
9247 0 : MinWaterFlow = 0.0;
9248 0 : auto f = [&state, FurnaceNum, FirstHVACIteration, QCoilLoad, SuppHeatingCoilFlag](Real64 const HWFlow) {
9249 0 : Real64 QCoilRequested = QCoilLoad;
9250 :
9251 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
9252 : Real64 QCoilActual; // delivered coil load, W
9253 0 : Real64 mdot = HWFlow; // to get non-const argument
9254 0 : QCoilActual = QCoilRequested;
9255 0 : if (!SuppHeatingCoilFlag) {
9256 0 : PlantUtilities::SetComponentFlowRate(state,
9257 : mdot,
9258 0 : state.dataFurnaces->Furnace(FurnaceNum).CoilControlNode,
9259 0 : state.dataFurnaces->Furnace(FurnaceNum).CoilOutletNode,
9260 0 : state.dataFurnaces->Furnace(FurnaceNum).plantLoc);
9261 0 : WaterCoils::SimulateWaterCoilComponents(state,
9262 0 : state.dataFurnaces->Furnace(FurnaceNum).HeatingCoilName,
9263 : FirstHVACIteration,
9264 0 : state.dataFurnaces->Furnace(FurnaceNum).HeatingCoilIndex,
9265 : QCoilActual,
9266 0 : state.dataFurnaces->Furnace(FurnaceNum).fanOp);
9267 : } else {
9268 : // supplemental coil
9269 0 : PlantUtilities::SetComponentFlowRate(state,
9270 : mdot,
9271 0 : state.dataFurnaces->Furnace(FurnaceNum).SuppCoilControlNode,
9272 0 : state.dataFurnaces->Furnace(FurnaceNum).SuppCoilOutletNode,
9273 0 : state.dataFurnaces->Furnace(FurnaceNum).SuppPlantLoc);
9274 : // simulate the hot water supplemental heating coil
9275 0 : WaterCoils::SimulateWaterCoilComponents(state,
9276 0 : state.dataFurnaces->Furnace(FurnaceNum).SuppHeatCoilName,
9277 : FirstHVACIteration,
9278 0 : state.dataFurnaces->Furnace(FurnaceNum).SuppHeatCoilIndex,
9279 : QCoilActual,
9280 0 : state.dataFurnaces->Furnace(FurnaceNum).fanOp);
9281 : }
9282 0 : return QCoilRequested != 0.0 ? (QCoilActual - QCoilRequested) / QCoilRequested : 0.0;
9283 0 : };
9284 0 : int SolFlag = 0;
9285 0 : General::SolveRoot(state, ErrTolerance, SolveMaxIter, SolFlag, HotWaterMdot, f, MinWaterFlow, MaxHotWaterFlow);
9286 0 : if (SolFlag == -1) {
9287 0 : if (thisFurnace.HotWaterCoilMaxIterIndex == 0) {
9288 0 : ShowWarningMessage(state,
9289 0 : format("CalcNonDXHeatingCoils: Hot water coil control failed for {}=\"{}\"",
9290 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
9291 0 : thisFurnace.Name));
9292 0 : ShowContinueErrorTimeStamp(state, "");
9293 0 : ShowContinueError(state, format(" Iteration limit [{}] exceeded in calculating hot water mass flow rate", SolveMaxIter));
9294 : }
9295 0 : ShowRecurringWarningErrorAtEnd(
9296 : state,
9297 0 : format("CalcNonDXHeatingCoils: Hot water coil control failed (iteration limit [{}]) for {}=\"{}",
9298 : SolveMaxIter,
9299 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
9300 0 : thisFurnace.Name),
9301 0 : thisFurnace.HotWaterCoilMaxIterIndex);
9302 0 : } else if (SolFlag == -2) {
9303 0 : if (thisFurnace.HotWaterCoilMaxIterIndex2 == 0) {
9304 0 : ShowWarningMessage(state,
9305 0 : format("CalcNonDXHeatingCoils: Hot water coil control failed (maximum flow limits) for {}=\"{}\"",
9306 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
9307 0 : thisFurnace.Name));
9308 0 : ShowContinueErrorTimeStamp(state, "");
9309 0 : ShowContinueError(state, "...Bad hot water maximum flow rate limits");
9310 0 : ShowContinueError(state, format("...Given minimum water flow rate={:.3R} kg/s", MinWaterFlow));
9311 0 : ShowContinueError(state, format("...Given maximum water flow rate={:.3R} kg/s", MaxHotWaterFlow));
9312 : }
9313 0 : ShowRecurringWarningErrorAtEnd(state,
9314 0 : format("CalcNonDXHeatingCoils: Hot water coil control failed (flow limits) for {}=\"{}\"",
9315 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
9316 0 : thisFurnace.Name),
9317 0 : thisFurnace.HotWaterCoilMaxIterIndex2,
9318 : MaxHotWaterFlow,
9319 : MinWaterFlow,
9320 : _,
9321 : "[kg/s]",
9322 : "[kg/s]");
9323 : }
9324 : }
9325 : } else {
9326 0 : mdot = 0.0;
9327 0 : PlantUtilities::SetComponentFlowRate(state, mdot, CoilControlNode, CoilOutletNode, plantLoc);
9328 : }
9329 : // simulate the hot water heating coil
9330 0 : WaterCoils::SimulateWaterCoilComponents(state, HeatingCoilName, FirstHVACIteration, HeatingCoilIndex, QActual, fanOp);
9331 0 : } break;
9332 0 : case HVAC::Coil_HeatingSteam: {
9333 0 : if (QCoilLoad > HVAC::SmallLoad) {
9334 0 : PlantUtilities::SetComponentFlowRate(state, MaxHotWaterFlow, CoilControlNode, CoilOutletNode, plantLoc);
9335 : // simulate the steam heating coil
9336 0 : SteamCoils::SimulateSteamCoilComponents(state, HeatingCoilName, FirstHVACIteration, HeatingCoilIndex, QCoilLoad, QActual, fanOp);
9337 : } else {
9338 0 : mdot = 0.0;
9339 0 : PlantUtilities::SetComponentFlowRate(state, mdot, CoilControlNode, CoilOutletNode, plantLoc);
9340 : // simulate the steam heating coil
9341 0 : SteamCoils::SimulateSteamCoilComponents(state, HeatingCoilName, FirstHVACIteration, HeatingCoilIndex, QCoilLoad, QActual, fanOp);
9342 : }
9343 0 : } break;
9344 4 : default:
9345 4 : break;
9346 : }
9347 :
9348 71571 : HeatCoilLoadmet = QActual;
9349 71571 : }
9350 :
9351 : // End of Reporting subroutines for the Furnace Module
9352 :
9353 : //******************************************************************************
9354 :
9355 0 : void SimVariableSpeedHP(EnergyPlusData &state,
9356 : int const FurnaceNum, // number of the current engine driven Heat Pump being simulated
9357 : bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
9358 : int const AirLoopNum, // index to air loop
9359 : Real64 const QZnReq, // required zone load
9360 : Real64 const QLatReq, // required latent load
9361 : Real64 &OnOffAirFlowRatio // ratio of compressor ON airflow to AVERAGE airflow over timestep
9362 : )
9363 : {
9364 :
9365 : // SUBROUTINE INFORMATION:
9366 : // AUTHOR Bo Shen, based on HVACMultiSpeedHeatPump:CalcMSHeatPump
9367 : // DATE WRITTEN March, 2012
9368 :
9369 : // PURPOSE OF THIS SUBROUTINE:
9370 : // Simulate a multispeed heat pump; adjust its output to match the
9371 : // required system load.
9372 :
9373 : // METHODOLOGY EMPLOYED:
9374 : // Calls ControlMSHPOutput to obtain the desired unit output
9375 :
9376 : Real64 PartLoadFrac; // compressor part load fraction
9377 : Real64 SpeedRatio; // compressor speed ratio
9378 : Real64 QTotUnitOut; // capacity output
9379 0 : auto &SpeedNum = state.dataFurnaces->SpeedNum;
9380 0 : auto &SupHeaterLoad = state.dataFurnaces->SupHeaterLoad;
9381 : HVAC::CompressorOp compressorOp; // compressor operation; 1=on, 0=off
9382 : Real64 QSensUnitOut; // sensible capacity output
9383 : Real64 QLatUnitOut; // latent capacity output
9384 : Real64 ActualSensibleOutput; // Actual furnace sensible capacity
9385 : Real64 QToHeatSetPt; // Load required to meet heating setpoint temp (>0 is a heating load)
9386 : Real64 NoCompOutput; // output when no active compressor [W]
9387 : bool EconoActive; // TRUE if Economizer is active
9388 :
9389 : // zero DX coils, and supplemental electric heater electricity consumption
9390 0 : state.dataHVACGlobal->DXElecHeatingPower = 0.0;
9391 0 : state.dataHVACGlobal->DXElecCoolingPower = 0.0;
9392 0 : state.dataFurnaces->SaveCompressorPLR = 0.0;
9393 0 : state.dataHVACGlobal->ElecHeatingCoilPower = 0.0;
9394 0 : state.dataHVACGlobal->SuppHeatingCoilPower = 0.0;
9395 0 : state.dataHVACGlobal->DefrostElecPower = 0.0;
9396 :
9397 0 : Real64 SystemSensibleLoad = QZnReq; // Positive value means heating required
9398 0 : Real64 TotalZoneSensibleLoad = QZnReq;
9399 0 : Real64 TotalZoneLatentLoad = QLatReq;
9400 0 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
9401 : // initialize local variables
9402 0 : bool UnitOn = true;
9403 0 : int OutletNode = thisFurnace.FurnaceOutletNodeNum;
9404 0 : int InletNode = thisFurnace.FurnaceInletNodeNum;
9405 0 : Real64 AirMassFlow = thisFurnace.DesignMassFlowRate;
9406 0 : HVAC::FanOp fanOp = thisFurnace.fanOp; // fan operating mode
9407 0 : int ZoneNum = thisFurnace.ControlZoneNum;
9408 :
9409 : // Set latent load for heating
9410 0 : if (state.dataFurnaces->HeatingLoad) {
9411 0 : thisFurnace.HeatCoolMode = Furnaces::ModeOfOperation::HeatingMode;
9412 : // Set latent load for cooling and no sensible load condition
9413 0 : } else if (state.dataFurnaces->CoolingLoad) {
9414 0 : thisFurnace.HeatCoolMode = Furnaces::ModeOfOperation::CoolingMode;
9415 : } else {
9416 0 : thisFurnace.HeatCoolMode = Furnaces::ModeOfOperation::NoCoolHeat;
9417 : }
9418 :
9419 : // set the on/off flags
9420 0 : if (thisFurnace.fanOp == HVAC::FanOp::Cycling) {
9421 : // cycling unit only runs if there is a cooling or heating load.
9422 0 : if (std::abs(QZnReq) < HVAC::SmallLoad || AirMassFlow < HVAC::SmallMassFlow ||
9423 0 : state.dataZoneEnergyDemand->CurDeadBandOrSetback(ZoneNum)) {
9424 0 : UnitOn = false;
9425 : }
9426 0 : } else if (thisFurnace.fanOp == HVAC::FanOp::Continuous) {
9427 : // continuous unit: fan runs if scheduled on; coil runs only if there is a cooling or heating load
9428 0 : if (AirMassFlow < HVAC::SmallMassFlow) {
9429 0 : UnitOn = false;
9430 : }
9431 : }
9432 :
9433 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
9434 0 : EconoActive = (AirLoopNum != 0) ? state.dataAirLoop->AirLoopControlInfo(AirLoopNum).EconoActive : false;
9435 :
9436 0 : Real64 SaveMassFlowRate = state.dataLoopNodes->Node(InletNode).MassFlowRate;
9437 : // decide current working mode for IHP
9438 0 : if ((FirstHVACIteration) && (thisFurnace.bIsIHP)) {
9439 0 : IntegratedHeatPump::DecideWorkMode(state, thisFurnace.CoolingCoilIndex, TotalZoneSensibleLoad, TotalZoneLatentLoad);
9440 : }
9441 :
9442 0 : if (!FirstHVACIteration && thisFurnace.fanOp == HVAC::FanOp::Cycling &&
9443 0 : (QZnReq < (-1.0 * HVAC::SmallLoad) || TotalZoneLatentLoad < (-HVAC::SmallLoad)) && EconoActive) {
9444 : // for cycling fan, cooling load, check whether furnace can meet load with compressor off
9445 0 : compressorOp = HVAC::CompressorOp::Off;
9446 0 : ControlVSHPOutput(state,
9447 : FurnaceNum,
9448 : FirstHVACIteration,
9449 : compressorOp,
9450 : fanOp,
9451 : TotalZoneSensibleLoad,
9452 : TotalZoneLatentLoad,
9453 : SpeedNum,
9454 : SpeedRatio,
9455 : PartLoadFrac,
9456 : OnOffAirFlowRatio,
9457 : SupHeaterLoad);
9458 :
9459 0 : TotalZoneSensibleLoad = QZnReq;
9460 0 : TotalZoneLatentLoad = QLatReq;
9461 :
9462 0 : if (SpeedNum == thisFurnace.NumOfSpeedCooling && SpeedRatio == 1.0) {
9463 : // compressor on (reset inlet air mass flow rate to starting value)
9464 0 : state.dataLoopNodes->Node(InletNode).MassFlowRate = SaveMassFlowRate;
9465 0 : compressorOp = HVAC::CompressorOp::On;
9466 0 : ControlVSHPOutput(state,
9467 : FurnaceNum,
9468 : FirstHVACIteration,
9469 : compressorOp,
9470 : fanOp,
9471 : TotalZoneSensibleLoad,
9472 : TotalZoneLatentLoad,
9473 : SpeedNum,
9474 : SpeedRatio,
9475 : PartLoadFrac,
9476 : OnOffAirFlowRatio,
9477 : SupHeaterLoad);
9478 : }
9479 : } else {
9480 : // compressor on
9481 0 : compressorOp = HVAC::CompressorOp::On;
9482 :
9483 0 : ControlVSHPOutput(state,
9484 : FurnaceNum,
9485 : FirstHVACIteration,
9486 : compressorOp,
9487 : fanOp,
9488 : TotalZoneSensibleLoad,
9489 : TotalZoneLatentLoad,
9490 : SpeedNum,
9491 : SpeedRatio,
9492 : PartLoadFrac,
9493 : OnOffAirFlowRatio,
9494 : SupHeaterLoad);
9495 : }
9496 :
9497 0 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool) {
9498 0 : state.dataFurnaces->SaveCompressorPLR = PartLoadFrac;
9499 : } else {
9500 0 : if (SpeedNum > 1) {
9501 0 : state.dataFurnaces->SaveCompressorPLR = 1.0;
9502 : }
9503 :
9504 0 : if (PartLoadFrac == 1.0 && state.dataFurnaces->SaveCompressorPLR < 1.0) {
9505 0 : PartLoadFrac = state.dataFurnaces->SaveCompressorPLR;
9506 : }
9507 : }
9508 :
9509 0 : Real64 ReheatCoilLoad = 0.0;
9510 0 : TotalZoneSensibleLoad = QZnReq;
9511 0 : TotalZoneLatentLoad = QLatReq;
9512 : // Calculate the reheat coil output
9513 0 : if ((thisFurnace.availSched->getCurrentVal() > 0.0) &&
9514 0 : (thisFurnace.Humidistat && thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat &&
9515 : (QLatReq < 0.0))) { // if a Humidistat is installed and dehumidification control type is CoolReheat
9516 0 : CalcVarSpeedHeatPump(state,
9517 : FurnaceNum,
9518 : FirstHVACIteration,
9519 : compressorOp,
9520 : SpeedNum,
9521 : SpeedRatio,
9522 : PartLoadFrac,
9523 : ActualSensibleOutput,
9524 : QLatUnitOut,
9525 : TotalZoneSensibleLoad,
9526 : TotalZoneLatentLoad,
9527 : OnOffAirFlowRatio,
9528 : ReheatCoilLoad);
9529 0 : if (thisFurnace.ZoneSequenceHeatingNum > 0) {
9530 0 : QToHeatSetPt = (state.dataZoneEnergyDemand->ZoneSysEnergyDemand(thisFurnace.ControlZoneNum)
9531 0 : .SequencedOutputRequiredToHeatingSP(thisFurnace.ZoneSequenceHeatingNum) /
9532 0 : thisFurnace.ControlZoneMassFlowFrac);
9533 : } else {
9534 0 : QToHeatSetPt = (state.dataZoneEnergyDemand->ZoneSysEnergyDemand(thisFurnace.ControlZoneNum).OutputRequiredToHeatingSP /
9535 0 : thisFurnace.ControlZoneMassFlowFrac);
9536 : }
9537 : // Cooling mode or floating condition and dehumidification is required
9538 0 : if (QToHeatSetPt < 0.0) {
9539 : // Calculate the reheat coil load wrt the heating setpoint temperature. Reheat coil picks up
9540 : // the entire excess sensible cooling (DX cooling coil and impact of outdoor air).
9541 0 : ReheatCoilLoad = max(0.0, (QToHeatSetPt - ActualSensibleOutput));
9542 0 : thisFurnace.DehumidInducedHeatingDemandRate = ReheatCoilLoad;
9543 : // Heating mode and dehumidification is required
9544 : } else {
9545 0 : ReheatCoilLoad = max(QToHeatSetPt, QToHeatSetPt - ActualSensibleOutput);
9546 0 : thisFurnace.DehumidInducedHeatingDemandRate = max(0.0, ActualSensibleOutput * (-1.0));
9547 : }
9548 :
9549 0 : SupHeaterLoad = 0.0;
9550 0 : CalcVarSpeedHeatPump(state,
9551 : FurnaceNum,
9552 : FirstHVACIteration,
9553 : compressorOp,
9554 : 1,
9555 : 0.0,
9556 : 0.0,
9557 : NoCompOutput,
9558 : QLatUnitOut,
9559 : 0.0,
9560 : 0.0,
9561 : OnOffAirFlowRatio,
9562 : SupHeaterLoad);
9563 :
9564 0 : if (NoCompOutput > SystemSensibleLoad && SystemSensibleLoad > 0.0 && ReheatCoilLoad > 0.0) {
9565 : // Reduce reheat coil load if you are controlling high humidity but outside air
9566 : // and/or the supply air fan is providing enough heat to meet the system sensible load.
9567 : // This will bring the zone temp closer to the heating setpoint temp.
9568 0 : ReheatCoilLoad = max(0.0, ReheatCoilLoad - (NoCompOutput - SystemSensibleLoad));
9569 : }
9570 : } else {
9571 : // No humidistat installed
9572 0 : ReheatCoilLoad = 0.0;
9573 : }
9574 :
9575 0 : TotalZoneSensibleLoad = QZnReq;
9576 0 : TotalZoneLatentLoad = QLatReq;
9577 0 : if (ReheatCoilLoad > 0.0) {
9578 0 : CalcVarSpeedHeatPump(state,
9579 : FurnaceNum,
9580 : FirstHVACIteration,
9581 : compressorOp,
9582 : SpeedNum,
9583 : SpeedRatio,
9584 : PartLoadFrac,
9585 : QSensUnitOut,
9586 : QLatUnitOut,
9587 : TotalZoneSensibleLoad,
9588 : TotalZoneLatentLoad,
9589 : OnOffAirFlowRatio,
9590 : ReheatCoilLoad);
9591 : } else {
9592 0 : CalcVarSpeedHeatPump(state,
9593 : FurnaceNum,
9594 : FirstHVACIteration,
9595 : compressorOp,
9596 : SpeedNum,
9597 : SpeedRatio,
9598 : PartLoadFrac,
9599 : QSensUnitOut,
9600 : QLatUnitOut,
9601 : TotalZoneSensibleLoad,
9602 : TotalZoneLatentLoad,
9603 : OnOffAirFlowRatio,
9604 : SupHeaterLoad);
9605 : }
9606 :
9607 : // calculate delivered capacity
9608 0 : AirMassFlow = state.dataLoopNodes->Node(InletNode).MassFlowRate;
9609 :
9610 0 : thisFurnace.MdotFurnace = AirMassFlow;
9611 :
9612 0 : QTotUnitOut =
9613 0 : AirMassFlow * (state.dataLoopNodes->Node(OutletNode).Enthalpy - state.dataLoopNodes->Node(thisFurnace.NodeNumOfControlledZone).Enthalpy);
9614 :
9615 0 : state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AirMassFlow;
9616 0 : state.dataLoopNodes->Node(OutletNode).MassFlowRateMaxAvail = AirMassFlow;
9617 :
9618 0 : if (!FirstHVACIteration && AirMassFlow > 0.0 && AirLoopNum > 0) {
9619 0 : int TotBranchNum = state.dataAirSystemsData->PrimaryAirSystems(AirLoopNum).NumOutletBranches;
9620 0 : if (TotBranchNum == 1) {
9621 0 : int ZoneSideNodeNum = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).ZoneEquipSupplyNodeNum(1);
9622 : // THE MASS FLOW PRECISION of the system solver is not enough for some small air flow rate iterations , BY DEBUGGING
9623 : // it may cause mass flow rate oscillations between airloop and zoneequip
9624 : // specify the air flow rate directly for one-to-one system, when the iteration deviation is closing the solver precision level
9625 : // 0.02 is 2 * HVACFlowRateToler, in order to accommodate the system solver precision level
9626 0 : if (std::abs(AirMassFlow - state.dataLoopNodes->Node(ZoneSideNodeNum).MassFlowRate) < 0.02) {
9627 0 : state.dataLoopNodes->Node(ZoneSideNodeNum).MassFlowRateMaxAvail = AirMassFlow;
9628 : }
9629 0 : state.dataLoopNodes->Node(ZoneSideNodeNum).MassFlowRate = AirMassFlow;
9630 : }
9631 :
9632 : // the below might be useful if more divergences occur
9633 : // Node(PrimaryAirSystem(AirLoopNumber)%Branch(1)%NodeNumIn)%MassFlowRateMaxAvail = AirMassFlow
9634 : // Node(PrimaryAirSystem(AirLoopNumber)%Branch(1)%NodeNumIn)%MassFlowRate = AirMassFlow
9635 : }
9636 :
9637 : // report variables
9638 0 : thisFurnace.DehumidInducedHeatingDemandRate = ReheatCoilLoad;
9639 0 : if (QZnReq > HVAC::SmallLoad) { // HEATING LOAD
9640 0 : thisFurnace.CoolingCoilSensDemand = 0.0;
9641 0 : thisFurnace.HeatingCoilSensDemand = QZnReq;
9642 : } else {
9643 0 : thisFurnace.CoolingCoilSensDemand = std::abs(QZnReq);
9644 0 : thisFurnace.HeatingCoilSensDemand = 0.0;
9645 : }
9646 :
9647 0 : thisFurnace.CompPartLoadRatio = state.dataFurnaces->SaveCompressorPLR;
9648 0 : if (thisFurnace.fanOp == HVAC::FanOp::Cycling) {
9649 0 : if (SupHeaterLoad > 0.0) {
9650 0 : thisFurnace.FanPartLoadRatio = 1.0;
9651 : } else {
9652 0 : if (SpeedNum < 2) {
9653 0 : thisFurnace.FanPartLoadRatio = PartLoadFrac;
9654 : } else {
9655 0 : thisFurnace.FanPartLoadRatio = 1.0;
9656 : }
9657 : }
9658 : } else {
9659 0 : if (UnitOn) {
9660 0 : thisFurnace.FanPartLoadRatio = 1.0;
9661 : } else {
9662 0 : if (SpeedNum < 2) {
9663 0 : thisFurnace.FanPartLoadRatio = PartLoadFrac;
9664 : } else {
9665 0 : thisFurnace.FanPartLoadRatio = 1.0;
9666 : }
9667 : }
9668 : }
9669 0 : }
9670 :
9671 : //******************************************************************************
9672 :
9673 0 : void ControlVSHPOutput(EnergyPlusData &state,
9674 : int const FurnaceNum, // Unit index of engine driven heat pump
9675 : bool const FirstHVACIteration, // flag for 1st HVAC iteration in the time step
9676 : HVAC::CompressorOp const compressorOp, // compressor operation; 1=on, 0=off
9677 : HVAC::FanOp const fanOp, // operating mode: FanOp::Cycling | FanOp::Continuous
9678 : Real64 &QZnReq, // cooling or heating output needed by zone [W]
9679 : Real64 QLatReq, // latent cooling output needed by zone [W]
9680 : int &SpeedNum, // Speed number
9681 : Real64 &SpeedRatio, // unit speed ratio for DX coils
9682 : Real64 &PartLoadFrac, // unit part load fraction
9683 : Real64 &OnOffAirFlowRatio, // ratio of compressor ON airflow to AVERAGE airflow over timestep
9684 : Real64 &SupHeaterLoad // Supplemental heater load [W]
9685 : )
9686 : {
9687 :
9688 : // SUBROUTINE INFORMATION:
9689 : // AUTHOR Bo Shen, based on HVACMultiSpeedHeatPump:ControlMSHPOutput
9690 : // DATE WRITTEN March, 2012
9691 :
9692 : // PURPOSE OF THIS SUBROUTINE:
9693 : // Determine the part load fraction at low speed, and speed ratio at high speed for this time step.
9694 :
9695 : // METHODOLOGY EMPLOYED:
9696 : // Use RegulaFalsi technique to iterate on part-load ratio until convergence is achieved.
9697 :
9698 : // SUBROUTINE PARAMETER DEFINITIONS:
9699 0 : int constexpr MaxIte(500); // maximum number of iterations
9700 :
9701 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
9702 : Real64 FullOutput; // unit full output when compressor is operating [W]
9703 : Real64 LowOutput; // unit full output at low speed [W]
9704 : Real64 TempOutput; // unit output when iteration limit exceeded [W]
9705 : Real64 NoCompOutput; // output when no active compressor [W]
9706 : int SolFla; // Flag of RegulaFalsi solver
9707 : Real64 QCoilActual; // coil load actually delivered returned to calling component
9708 : int i; // Speed index
9709 0 : IntegratedHeatPump::IHPOperationMode IHPMode(IntegratedHeatPump::IHPOperationMode::Idle);
9710 :
9711 0 : SupHeaterLoad = 0.0;
9712 0 : PartLoadFrac = 0.0;
9713 0 : SpeedRatio = 0.0;
9714 0 : SpeedNum = 1;
9715 0 : Real64 LatOutput = 0.0;
9716 0 : Real64 noLatOutput = 0.0;
9717 0 : Real64 ErrorToler = 0.001; // Error tolerance for convergence from input deck
9718 :
9719 0 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
9720 0 : if (thisFurnace.availSched->getCurrentVal() == 0.0) {
9721 0 : return;
9722 : }
9723 :
9724 : // Get result when DX coil is off
9725 0 : SupHeaterLoad = 0.0;
9726 0 : CalcVarSpeedHeatPump(state,
9727 : FurnaceNum,
9728 : FirstHVACIteration,
9729 : compressorOp,
9730 : SpeedNum,
9731 : SpeedRatio,
9732 : PartLoadFrac,
9733 : NoCompOutput,
9734 : noLatOutput,
9735 : 0.0,
9736 : 0.0,
9737 : OnOffAirFlowRatio,
9738 : SupHeaterLoad);
9739 :
9740 0 : if (thisFurnace.bIsIHP) {
9741 0 : IHPMode = IntegratedHeatPump::GetCurWorkMode(state, thisFurnace.CoolingCoilIndex);
9742 0 : if ((IntegratedHeatPump::IHPOperationMode::DedicatedWaterHtg == IHPMode) ||
9743 : (IntegratedHeatPump::IHPOperationMode::SCWHMatchWH == IHPMode)) { // cooling capacity is a resultant
9744 0 : return;
9745 : }
9746 : }
9747 :
9748 : // If cooling and NoCompOutput < QZnReq, the coil needs to be off
9749 : // If heating and NoCompOutput > QZnReq, the coil needs to be off
9750 : // If no cooling or heating and no latent load, the coil needs to be off
9751 0 : if (QZnReq < -HVAC::SmallLoad) {
9752 0 : if (NoCompOutput < QZnReq && QLatReq >= -HVAC::SmallLoad) {
9753 0 : return;
9754 : }
9755 0 : } else if (QZnReq > HVAC::SmallLoad) {
9756 0 : if (NoCompOutput > QZnReq && QLatReq >= -HVAC::SmallLoad) {
9757 0 : return;
9758 : }
9759 0 : if (QLatReq <= -HVAC::SmallLoad) {
9760 0 : QZnReq = 0.0; // Zero heating load to allow dehumidification
9761 : }
9762 : } else {
9763 0 : if (QLatReq >= -HVAC::SmallLoad) {
9764 0 : return;
9765 : }
9766 : }
9767 :
9768 : // Get full load result
9769 0 : PartLoadFrac = 1.0;
9770 0 : SpeedRatio = 1.0;
9771 0 : if (thisFurnace.HeatCoolMode == Furnaces::ModeOfOperation::HeatingMode) {
9772 0 : SpeedNum = thisFurnace.NumOfSpeedHeating;
9773 0 : } else if (thisFurnace.HeatCoolMode == Furnaces::ModeOfOperation::CoolingMode) {
9774 0 : SpeedNum = thisFurnace.NumOfSpeedCooling;
9775 0 : } else if (QLatReq < -HVAC::SmallLoad) {
9776 0 : SpeedNum = thisFurnace.NumOfSpeedCooling;
9777 : } else {
9778 0 : SpeedNum = 1;
9779 0 : PartLoadFrac = 0.0;
9780 : }
9781 :
9782 0 : if (thisFurnace.bIsIHP) {
9783 0 : SpeedNum = IntegratedHeatPump::GetMaxSpeedNumIHP(state, thisFurnace.CoolingCoilIndex);
9784 : }
9785 :
9786 0 : CalcVarSpeedHeatPump(state,
9787 : FurnaceNum,
9788 : FirstHVACIteration,
9789 : compressorOp,
9790 : SpeedNum,
9791 : SpeedRatio,
9792 : PartLoadFrac,
9793 : FullOutput,
9794 : LatOutput,
9795 : QZnReq,
9796 : QLatReq,
9797 : OnOffAirFlowRatio,
9798 : SupHeaterLoad);
9799 :
9800 0 : if (QLatReq < (-1.0 * HVAC::SmallLoad)) { // dehumidification mode
9801 0 : if (QLatReq <= LatOutput || (QZnReq < -HVAC::SmallLoad && QZnReq <= FullOutput) || (QZnReq > HVAC::SmallLoad && QZnReq >= FullOutput)) {
9802 0 : PartLoadFrac = 1.0;
9803 0 : SpeedRatio = 1.0;
9804 0 : thisFurnace.CompPartLoadRatio = PartLoadFrac;
9805 0 : thisFurnace.CompSpeedRatio = SpeedRatio;
9806 0 : thisFurnace.CompSpeedNum = SpeedNum;
9807 0 : return;
9808 : }
9809 0 : } else if (QZnReq < -HVAC::SmallLoad) {
9810 0 : if (QZnReq <= FullOutput) {
9811 0 : PartLoadFrac = 1.0;
9812 0 : SpeedRatio = 1.0;
9813 0 : thisFurnace.CompPartLoadRatio = PartLoadFrac;
9814 0 : thisFurnace.CompSpeedRatio = SpeedRatio;
9815 0 : thisFurnace.CompSpeedNum = SpeedNum;
9816 0 : return;
9817 : }
9818 : } else {
9819 0 : if (QZnReq >= FullOutput) {
9820 0 : PartLoadFrac = 1.0;
9821 0 : SpeedRatio = 1.0;
9822 : // may need supplemental heating so don't return in heating mode
9823 : }
9824 : }
9825 :
9826 0 : if ((QZnReq < -HVAC::SmallLoad && NoCompOutput - QZnReq > HVAC::SmallLoad) ||
9827 0 : (QZnReq > HVAC::SmallLoad && QZnReq - NoCompOutput > HVAC::SmallLoad)) {
9828 0 : if ((QZnReq > HVAC::SmallLoad && QZnReq < FullOutput) || (QZnReq < (-1.0 * HVAC::SmallLoad) && QZnReq > FullOutput)) {
9829 : // Check whether the low speed coil can meet the load or not
9830 0 : CalcVarSpeedHeatPump(state,
9831 : FurnaceNum,
9832 : FirstHVACIteration,
9833 : compressorOp,
9834 : 1,
9835 : 0.0,
9836 : 1.0,
9837 : LowOutput,
9838 : LatOutput,
9839 : QZnReq,
9840 : QLatReq,
9841 : OnOffAirFlowRatio,
9842 : SupHeaterLoad);
9843 0 : if ((QZnReq > HVAC::SmallLoad && QZnReq <= LowOutput) || (QZnReq < (-HVAC::SmallLoad) && QZnReq >= LowOutput)) {
9844 : // Calculate the part load fraction
9845 0 : SpeedRatio = 0.0;
9846 0 : SpeedNum = 1;
9847 : auto f = // (AUTO_OK_LAMBDA)
9848 0 : [&state, FurnaceNum, FirstHVACIteration, QZnReq, OnOffAirFlowRatio, SupHeaterLoad, compressorOp](Real64 const PartLoadFrac) {
9849 0 : return VSHPCyclingResidual(
9850 0 : state, PartLoadFrac, FurnaceNum, FirstHVACIteration, QZnReq, OnOffAirFlowRatio, SupHeaterLoad, compressorOp, 1.0);
9851 0 : };
9852 0 : General::SolveRoot(state, ErrorToler, MaxIte, SolFla, PartLoadFrac, f, 0.0, 1.0);
9853 0 : if (SolFla == -1) {
9854 0 : if (!state.dataGlobal->WarmupFlag) {
9855 0 : if (thisFurnace.ErrCountCyc == 0) {
9856 0 : ++thisFurnace.ErrCountCyc;
9857 0 : ShowWarningError(
9858 0 : state, format("Iteration limit exceeded calculating VS WSHP unit cycling ratio, for unit={}", thisFurnace.Name));
9859 0 : ShowContinueErrorTimeStamp(state, format("Cycling ratio returned={:.2R}", PartLoadFrac));
9860 : } else {
9861 0 : ShowRecurringWarningErrorAtEnd(
9862 : state,
9863 0 : thisFurnace.Name + "\": Iteration limit warning exceeding calculating DX unit cycling ratio continues...",
9864 0 : thisFurnace.ErrIndexCyc,
9865 : PartLoadFrac,
9866 : PartLoadFrac);
9867 : }
9868 : }
9869 0 : } else if (SolFla == -2) {
9870 0 : ShowFatalError(
9871 0 : state, format("VS WSHP unit cycling ratio calculation failed: cycling limits exceeded, for unit={}", thisFurnace.Name));
9872 : }
9873 0 : } else {
9874 : // Check to see which speed to meet the load
9875 0 : PartLoadFrac = 1.0;
9876 0 : SpeedRatio = 1.0;
9877 0 : if (QZnReq < -HVAC::SmallLoad) { // Cooling
9878 0 : for (i = 2; i <= thisFurnace.NumOfSpeedCooling; ++i) {
9879 0 : CalcVarSpeedHeatPump(state,
9880 : FurnaceNum,
9881 : FirstHVACIteration,
9882 : compressorOp,
9883 : i,
9884 : SpeedRatio,
9885 : PartLoadFrac,
9886 : TempOutput,
9887 : LatOutput,
9888 : QZnReq,
9889 : QLatReq,
9890 : OnOffAirFlowRatio,
9891 : SupHeaterLoad);
9892 :
9893 0 : if (QZnReq >= TempOutput) {
9894 0 : SpeedNum = i;
9895 0 : break;
9896 : }
9897 : }
9898 : } else {
9899 0 : for (i = 2; i <= thisFurnace.NumOfSpeedHeating; ++i) {
9900 0 : CalcVarSpeedHeatPump(state,
9901 : FurnaceNum,
9902 : FirstHVACIteration,
9903 : compressorOp,
9904 : i,
9905 : SpeedRatio,
9906 : PartLoadFrac,
9907 : TempOutput,
9908 : LatOutput,
9909 : QZnReq,
9910 : QLatReq,
9911 : OnOffAirFlowRatio,
9912 : SupHeaterLoad);
9913 0 : if (QZnReq <= TempOutput) {
9914 0 : SpeedNum = i;
9915 0 : break;
9916 : }
9917 : }
9918 : }
9919 0 : auto f = [&state, FurnaceNum, FirstHVACIteration, QZnReq, OnOffAirFlowRatio, SupHeaterLoad, SpeedNum, compressorOp](
9920 : Real64 const SpeedRatio) {
9921 0 : return VSHPSpeedResidual(
9922 0 : state, SpeedRatio, FurnaceNum, FirstHVACIteration, QZnReq, OnOffAirFlowRatio, SupHeaterLoad, SpeedNum, compressorOp, 1.0);
9923 0 : };
9924 0 : General::SolveRoot(state, ErrorToler, MaxIte, SolFla, SpeedRatio, f, 1.0e-10, 1.0);
9925 0 : if (SolFla == -1) {
9926 0 : if (!state.dataGlobal->WarmupFlag) {
9927 0 : if (thisFurnace.ErrCountVar == 0) {
9928 0 : ++thisFurnace.ErrCountVar;
9929 0 : ShowWarningError(
9930 0 : state, format("Iteration limit exceeded calculating VS WSHP unit speed ratio, for unit={}", thisFurnace.Name));
9931 0 : ShowContinueErrorTimeStamp(state, format("Speed ratio returned=[{:.2R}], Speed number ={}", SpeedRatio, SpeedNum));
9932 : } else {
9933 0 : ShowRecurringWarningErrorAtEnd(
9934 : state,
9935 0 : thisFurnace.Name + "\": Iteration limit warning exceeding calculating DX unit speed ratio continues...",
9936 0 : thisFurnace.ErrIndexVar,
9937 : SpeedRatio,
9938 : SpeedRatio);
9939 : }
9940 : }
9941 0 : } else if (SolFla == -2) {
9942 0 : ShowFatalError(
9943 0 : state, format("VS WSHP unit compressor speed calculation failed: speed limits exceeded, for unit={}", thisFurnace.Name));
9944 : }
9945 : }
9946 0 : } else {
9947 0 : LatOutput = noLatOutput; // reset full output if not needed for sensible load
9948 0 : SpeedNum = 1; // reset speed from full output test
9949 : }
9950 0 : } else {
9951 0 : LatOutput = noLatOutput; // reset full output if not needed for sensible load
9952 0 : SpeedNum = 1; // reset speed from full output test
9953 : }
9954 : // meet the latent load
9955 0 : if (QLatReq < -HVAC::SmallLoad && QLatReq < LatOutput) {
9956 0 : PartLoadFrac = 1.0;
9957 0 : SpeedRatio = 1.0;
9958 0 : for (i = SpeedNum; i <= thisFurnace.NumOfSpeedCooling; ++i) {
9959 0 : CalcVarSpeedHeatPump(state,
9960 : FurnaceNum,
9961 : FirstHVACIteration,
9962 : compressorOp,
9963 : i,
9964 : SpeedRatio,
9965 : PartLoadFrac,
9966 : TempOutput,
9967 : LatOutput,
9968 : QZnReq,
9969 : QLatReq,
9970 : OnOffAirFlowRatio,
9971 : SupHeaterLoad);
9972 :
9973 0 : if (QLatReq > LatOutput) {
9974 0 : SpeedNum = i;
9975 0 : break;
9976 : }
9977 : }
9978 0 : if (QLatReq - LatOutput > HVAC::SmallLoad) {
9979 0 : if (SpeedNum < 2) {
9980 : auto f = // (AUTO_OK_LAMBDA)
9981 0 : [&state, FurnaceNum, FirstHVACIteration, QLatReq, OnOffAirFlowRatio, SupHeaterLoad, compressorOp](Real64 const PartLoadFrac) {
9982 0 : return VSHPCyclingResidual(
9983 0 : state, PartLoadFrac, FurnaceNum, FirstHVACIteration, QLatReq, OnOffAirFlowRatio, SupHeaterLoad, compressorOp, 0.0);
9984 0 : };
9985 0 : General::SolveRoot(state, ErrorToler, MaxIte, SolFla, PartLoadFrac, f, 0.0, 1.0);
9986 : } else {
9987 0 : auto f = [&state, FurnaceNum, FirstHVACIteration, QLatReq, OnOffAirFlowRatio, SupHeaterLoad, SpeedNum, compressorOp](
9988 : Real64 const SpeedRatio) {
9989 0 : return VSHPSpeedResidual(state,
9990 : SpeedRatio,
9991 : FurnaceNum,
9992 : FirstHVACIteration,
9993 : QLatReq,
9994 : OnOffAirFlowRatio,
9995 : SupHeaterLoad,
9996 : SpeedNum,
9997 : compressorOp,
9998 0 : 0.0);
9999 0 : };
10000 0 : General::SolveRoot(state, ErrorToler, MaxIte, SolFla, SpeedRatio, f, 1.0e-10, 1.0);
10001 : }
10002 0 : if (SolFla == -1) {
10003 0 : if (!state.dataGlobal->WarmupFlag) {
10004 0 : if (thisFurnace.ErrCountVar2 == 0) {
10005 0 : ++thisFurnace.ErrCountVar2;
10006 0 : ShowWarningError(state,
10007 0 : format("Iteration limit exceeded calculating VS WSHP unit speed ratio, for unit={}", thisFurnace.Name));
10008 0 : ShowContinueErrorTimeStamp(state, format("Speed ratio returned=[{:.2R}], Speed number ={}", SpeedRatio, SpeedNum));
10009 : } else {
10010 0 : ShowRecurringWarningErrorAtEnd(state,
10011 0 : thisFurnace.Name +
10012 : "\": Iteration limit warning exceeding calculating DX unit speed ratio continues...",
10013 0 : thisFurnace.ErrIndexVar,
10014 : SpeedRatio,
10015 : SpeedRatio);
10016 : }
10017 : }
10018 0 : } else if (SolFla == -2) {
10019 0 : ShowFatalError(state,
10020 0 : format("VS WSHP unit compressor speed calculation failed: speed limits exceeded, for unit={}", thisFurnace.Name));
10021 : }
10022 : }
10023 : }
10024 : // end meet the latent load
10025 :
10026 : // if the heating coil cannot meet the load, trim with supplemental heater
10027 : // occurs with constant fan mode when compressor is on or off
10028 : // occurs with cycling fan mode when compressor PLR is equal to 1
10029 0 : if ((QZnReq > HVAC::SmallLoad && QZnReq > FullOutput) && (thisFurnace.SuppHeatCoilIndex != 0)) {
10030 0 : PartLoadFrac = 1.0;
10031 0 : SpeedRatio = 1.0;
10032 0 : if (thisFurnace.NumOfSpeedHeating > 0) {
10033 0 : SpeedNum = thisFurnace.NumOfSpeedHeating; // maximum heating speed, avoid zero for cooling only mode
10034 : }
10035 :
10036 0 : if (state.dataEnvrn->OutDryBulbTemp <= thisFurnace.MaxOATSuppHeat) {
10037 0 : SupHeaterLoad = QZnReq - FullOutput;
10038 : } else {
10039 0 : SupHeaterLoad = 0.0;
10040 : }
10041 0 : CalcVarSpeedHeatPump(state,
10042 : FurnaceNum,
10043 : FirstHVACIteration,
10044 : compressorOp,
10045 : SpeedNum,
10046 : SpeedRatio,
10047 : PartLoadFrac,
10048 : TempOutput,
10049 : LatOutput,
10050 : QZnReq,
10051 : QLatReq,
10052 : OnOffAirFlowRatio,
10053 : SupHeaterLoad);
10054 : }
10055 :
10056 : // check the outlet of the supplemental heater to be lower than the maximum supplemental heater supply air temperature
10057 0 : if (state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum).Temp > thisFurnace.DesignMaxOutletTemp && SupHeaterLoad > 0.0) {
10058 :
10059 : // If the supply air temperature is to high, turn off the supplemental heater to recalculate the outlet temperature
10060 0 : CalcNonDXHeatingCoils(state, FurnaceNum, true, FirstHVACIteration, 0.0, fanOp, QCoilActual);
10061 : // If the outlet temperature is below the maximum supplemental heater supply air temperature, reduce the load passed to
10062 : // the supplemental heater, otherwise leave the supplemental heater off. If the supplemental heater is to be turned on,
10063 : // use the outlet conditions when the supplemental heater was off (CALL above) as the inlet conditions for the calculation
10064 : // of supplemental heater load to just meet the maximum supply air temperature from the supplemental heater.
10065 0 : if (state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum).Temp < thisFurnace.DesignMaxOutletTemp) {
10066 0 : Real64 CpAir = Psychrometrics::PsyCpAirFnW(state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum).HumRat);
10067 0 : SupHeaterLoad = state.dataLoopNodes->Node(thisFurnace.FurnaceInletNodeNum).MassFlowRate * CpAir *
10068 0 : (thisFurnace.DesignMaxOutletTemp - state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum).Temp);
10069 :
10070 : } else {
10071 0 : SupHeaterLoad = 0.0;
10072 : }
10073 : }
10074 :
10075 : // prepare module level output
10076 0 : thisFurnace.CompPartLoadRatio = PartLoadFrac;
10077 0 : thisFurnace.CompSpeedRatio = SpeedRatio;
10078 0 : thisFurnace.CompSpeedNum = SpeedNum;
10079 0 : thisFurnace.CoolingCoilLatentDemand = std::abs(QLatReq);
10080 :
10081 0 : if (thisFurnace.fanOp == HVAC::FanOp::Continuous) {
10082 0 : thisFurnace.FanPartLoadRatio = 1.0;
10083 : } else {
10084 0 : thisFurnace.FanPartLoadRatio = PartLoadFrac;
10085 : }
10086 : }
10087 :
10088 : //******************************************************************************
10089 :
10090 0 : void CalcVarSpeedHeatPump(EnergyPlusData &state,
10091 : int const FurnaceNum, // Variable speed heat pump number
10092 : bool const FirstHVACIteration, // Flag for 1st HVAC iteration
10093 : HVAC::CompressorOp const compressorOp, // Compressor on/off; 1=on, 0=off
10094 : int const SpeedNum, // Speed number
10095 : Real64 const SpeedRatio, // Compressor speed ratio
10096 : Real64 const PartLoadFrac, // Compressor part load fraction
10097 : Real64 &SensibleLoadMet, // Sensible cooling load met (furnace outlet with respect to control zone temp)
10098 : Real64 &LatentLoadMet, // Latent cooling load met (furnace outlet with respect to control zone humidity ratio)
10099 : Real64 const QZnReq, // Zone load (W)
10100 : Real64 const QLatReq, // Zone latent load []
10101 : Real64 &OnOffAirFlowRatio, // Ratio of compressor ON airflow to AVERAGE airflow over timestep
10102 : Real64 const SupHeaterLoad // supplemental heater load (W)
10103 : )
10104 : {
10105 : // SUBROUTINE INFORMATION:
10106 : // AUTHOR: Bo Shen, based on HVACMultiSpeedHeatPump:CalcMSHeatPump
10107 : // DATE WRITTEN: March 2012
10108 :
10109 : // PURPOSE OF THIS SUBROUTINE:
10110 : // This routine will calculates MSHP performance based on given system load
10111 :
10112 0 : Real64 SavePartloadRatio = 0.0; // part-load ratio
10113 0 : Real64 SaveSpeedRatio = 0.0; // speed ratio
10114 0 : Real64 QCoilActual = 0.0; // coil load actually delivered returned to calling component
10115 0 : Real64 HeatCoilLoad = 0.0; // required heating coil load
10116 :
10117 0 : state.dataFurnaces->SaveCompressorPLR = 0.0;
10118 :
10119 : // Set inlet air mass flow rate based on PLR and compressor on/off air flow rates
10120 0 : SetVSHPAirFlow(state, FurnaceNum, PartLoadFrac, OnOffAirFlowRatio, SpeedNum, SpeedRatio);
10121 :
10122 0 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
10123 :
10124 0 : if ((SupHeaterLoad > 1.0e-10) && (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool) && (thisFurnace.SuppHeatCoilIndex == 0)) {
10125 : // ONLY HEATING COIL, NO SUPPLEMENTAL COIL, USED FOR REHEAT DURING DUHMI
10126 0 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity * PartLoadFrac; // REHEAT IN FAN ON TIME
10127 :
10128 0 : if (HeatCoilLoad > SupHeaterLoad) {
10129 0 : HeatCoilLoad = SupHeaterLoad; // HEATING COIL RUN TIME < FAN ON TIME
10130 : }
10131 :
10132 0 : } else if ((QZnReq > HVAC::SmallLoad) && (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool)) {
10133 0 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity * PartLoadFrac;
10134 : } else {
10135 0 : HeatCoilLoad = 0.0;
10136 : }
10137 :
10138 0 : Real64 AirMassFlow = state.dataLoopNodes->Node(thisFurnace.FurnaceInletNodeNum).MassFlowRate;
10139 : // if blow through, simulate fan then coils
10140 0 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
10141 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
10142 :
10143 0 : if ((!thisFurnace.CoolingCoilUpstream) && (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool)) {
10144 : // simulate thisFurnace heating coil
10145 0 : bool SuppHeatingCoilFlag = false; // if true simulates supplemental heating coil
10146 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, thisFurnace.fanOp, QCoilActual);
10147 : }
10148 :
10149 0 : if ((QZnReq < -HVAC::SmallLoad || (QLatReq < -HVAC::SmallLoad)) &&
10150 0 : (state.dataEnvrn->OutDryBulbTemp >= thisFurnace.MinOATCompressorCooling)) { // COOLING MODE or dehumidification mode
10151 :
10152 0 : if (thisFurnace.bIsIHP) {
10153 0 : IntegratedHeatPump::SimIHP(state,
10154 : BlankString,
10155 0 : thisFurnace.CoolingCoilIndex,
10156 : thisFurnace.fanOp,
10157 : compressorOp,
10158 : PartLoadFrac,
10159 : SpeedNum,
10160 : SpeedRatio,
10161 : QZnReq,
10162 : QLatReq,
10163 : false,
10164 : false,
10165 : OnOffAirFlowRatio);
10166 : } else {
10167 0 : VariableSpeedCoils::SimVariableSpeedCoils(state,
10168 : BlankString,
10169 0 : thisFurnace.CoolingCoilIndex,
10170 : thisFurnace.fanOp,
10171 : compressorOp,
10172 : PartLoadFrac,
10173 : SpeedNum,
10174 : SpeedRatio,
10175 : QZnReq,
10176 : QLatReq,
10177 : OnOffAirFlowRatio);
10178 : }
10179 :
10180 0 : SavePartloadRatio = PartLoadFrac;
10181 0 : SaveSpeedRatio = SpeedRatio;
10182 :
10183 0 : state.dataFurnaces->SaveCompressorPLR = state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.CoolingCoilIndex).PartLoadRatio;
10184 : } else {
10185 0 : if (thisFurnace.bIsIHP) {
10186 0 : IntegratedHeatPump::SimIHP(state,
10187 : BlankString,
10188 0 : thisFurnace.CoolingCoilIndex,
10189 : thisFurnace.fanOp,
10190 : compressorOp,
10191 : PartLoadFrac,
10192 : SpeedNum,
10193 : SpeedRatio,
10194 : QZnReq,
10195 : QLatReq,
10196 : false,
10197 : false,
10198 : OnOffAirFlowRatio);
10199 : } else {
10200 0 : VariableSpeedCoils::SimVariableSpeedCoils(
10201 0 : state, BlankString, thisFurnace.CoolingCoilIndex, thisFurnace.fanOp, compressorOp, 0.0, 1, 0.0, 0.0, 0.0, OnOffAirFlowRatio);
10202 : }
10203 : }
10204 :
10205 0 : if (thisFurnace.type != HVAC::UnitarySysType::Unitary_HeatCool) {
10206 0 : if ((QZnReq > HVAC::SmallLoad) && state.dataFurnaces->HeatingLoad) {
10207 0 : if (thisFurnace.bIsIHP) {
10208 0 : IntegratedHeatPump::SimIHP(state,
10209 : BlankString,
10210 0 : thisFurnace.HeatingCoilIndex,
10211 : thisFurnace.fanOp,
10212 : compressorOp,
10213 : PartLoadFrac,
10214 : SpeedNum,
10215 : SpeedRatio,
10216 : QZnReq,
10217 : QLatReq,
10218 : false,
10219 : false,
10220 : OnOffAirFlowRatio);
10221 : } else {
10222 0 : VariableSpeedCoils::SimVariableSpeedCoils(state,
10223 : BlankString,
10224 0 : thisFurnace.HeatingCoilIndex,
10225 : thisFurnace.fanOp,
10226 : compressorOp,
10227 : PartLoadFrac,
10228 : SpeedNum,
10229 : SpeedRatio,
10230 : QZnReq,
10231 : QLatReq,
10232 : OnOffAirFlowRatio);
10233 : }
10234 :
10235 0 : SavePartloadRatio = PartLoadFrac;
10236 0 : SaveSpeedRatio = SpeedRatio;
10237 :
10238 0 : state.dataFurnaces->SaveCompressorPLR = state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.HeatingCoilIndex).PartLoadRatio;
10239 : } else {
10240 0 : if (thisFurnace.bIsIHP) {
10241 0 : IntegratedHeatPump::SimIHP(state,
10242 : BlankString,
10243 0 : thisFurnace.CoolingCoilIndex,
10244 : thisFurnace.fanOp,
10245 : compressorOp,
10246 : PartLoadFrac,
10247 : SpeedNum,
10248 : SpeedRatio,
10249 : QZnReq,
10250 : QLatReq,
10251 : false,
10252 : false,
10253 : OnOffAirFlowRatio);
10254 : } else {
10255 0 : VariableSpeedCoils::SimVariableSpeedCoils(state,
10256 : BlankString,
10257 0 : thisFurnace.HeatingCoilIndex,
10258 : thisFurnace.fanOp,
10259 : compressorOp,
10260 : 0.0,
10261 : 1,
10262 : 0.0,
10263 : 0.0,
10264 : 0.0,
10265 : OnOffAirFlowRatio);
10266 : }
10267 : }
10268 0 : } else if (thisFurnace.CoolingCoilUpstream && (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool)) {
10269 : // simulate thisFurnace heating coil
10270 0 : bool SuppHeatingCoilFlag = false; // if true simulates supplemental heating coil
10271 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, thisFurnace.fanOp, QCoilActual);
10272 : }
10273 :
10274 : // Call twice to ensure the fan outlet conditions are updated
10275 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
10276 :
10277 0 : if ((!thisFurnace.CoolingCoilUpstream) && (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool)) {
10278 : // simulate thisFurnace heating coil
10279 0 : bool SuppHeatingCoilFlag = false; // if true simulates supplemental heating coil
10280 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, thisFurnace.fanOp, QCoilActual);
10281 : }
10282 :
10283 0 : if ((QZnReq < -HVAC::SmallLoad || (QLatReq < -HVAC::SmallLoad)) &&
10284 0 : (state.dataEnvrn->OutDryBulbTemp >= thisFurnace.MinOATCompressorCooling)) {
10285 :
10286 0 : if (thisFurnace.bIsIHP) {
10287 0 : IntegratedHeatPump::SimIHP(state,
10288 : BlankString,
10289 0 : thisFurnace.CoolingCoilIndex,
10290 : thisFurnace.fanOp,
10291 : compressorOp,
10292 : PartLoadFrac,
10293 : SpeedNum,
10294 : SpeedRatio,
10295 : QZnReq,
10296 : QLatReq,
10297 : false,
10298 : false,
10299 : OnOffAirFlowRatio);
10300 : } else {
10301 0 : VariableSpeedCoils::SimVariableSpeedCoils(state,
10302 : BlankString,
10303 0 : thisFurnace.CoolingCoilIndex,
10304 : thisFurnace.fanOp,
10305 : compressorOp,
10306 : PartLoadFrac,
10307 : SpeedNum,
10308 : SpeedRatio,
10309 : QZnReq,
10310 : QLatReq,
10311 : OnOffAirFlowRatio);
10312 : }
10313 :
10314 0 : SavePartloadRatio = PartLoadFrac;
10315 0 : SaveSpeedRatio = SpeedRatio;
10316 0 : state.dataFurnaces->SaveCompressorPLR = state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.CoolingCoilIndex).PartLoadRatio;
10317 : } else {
10318 :
10319 0 : if (thisFurnace.bIsIHP) {
10320 0 : IntegratedHeatPump::SimIHP(state,
10321 : BlankString,
10322 0 : thisFurnace.CoolingCoilIndex,
10323 : thisFurnace.fanOp,
10324 : compressorOp,
10325 : PartLoadFrac,
10326 : SpeedNum,
10327 : SpeedRatio,
10328 : QZnReq,
10329 : QLatReq,
10330 : false,
10331 : false,
10332 : OnOffAirFlowRatio);
10333 : } else {
10334 0 : VariableSpeedCoils::SimVariableSpeedCoils(
10335 0 : state, BlankString, thisFurnace.CoolingCoilIndex, thisFurnace.fanOp, compressorOp, 0.0, 1, 0.0, 0.0, 0.0, OnOffAirFlowRatio);
10336 : }
10337 : }
10338 :
10339 0 : if (thisFurnace.type != HVAC::UnitarySysType::Unitary_HeatCool) {
10340 0 : if ((QZnReq > HVAC::SmallLoad) && state.dataFurnaces->HeatingLoad) {
10341 0 : if (thisFurnace.bIsIHP) {
10342 0 : IntegratedHeatPump::SimIHP(state,
10343 : BlankString,
10344 0 : thisFurnace.HeatingCoilIndex,
10345 : thisFurnace.fanOp,
10346 : compressorOp,
10347 : PartLoadFrac,
10348 : SpeedNum,
10349 : SpeedRatio,
10350 : QZnReq,
10351 : QLatReq,
10352 : false,
10353 : false,
10354 : OnOffAirFlowRatio);
10355 : } else {
10356 0 : VariableSpeedCoils::SimVariableSpeedCoils(state,
10357 : BlankString,
10358 0 : thisFurnace.HeatingCoilIndex,
10359 : thisFurnace.fanOp,
10360 : compressorOp,
10361 : PartLoadFrac,
10362 : SpeedNum,
10363 : SpeedRatio,
10364 : QZnReq,
10365 : QLatReq,
10366 : OnOffAirFlowRatio);
10367 : }
10368 :
10369 0 : SavePartloadRatio = PartLoadFrac;
10370 0 : SaveSpeedRatio = SpeedRatio;
10371 0 : state.dataFurnaces->SaveCompressorPLR = state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.HeatingCoilIndex).PartLoadRatio;
10372 : } else {
10373 0 : if (thisFurnace.bIsIHP) {
10374 0 : IntegratedHeatPump::SimIHP(state,
10375 : BlankString,
10376 0 : thisFurnace.CoolingCoilIndex,
10377 : thisFurnace.fanOp,
10378 : compressorOp,
10379 : PartLoadFrac,
10380 : SpeedNum,
10381 : SpeedRatio,
10382 : QZnReq,
10383 : QLatReq,
10384 : false,
10385 : false,
10386 : OnOffAirFlowRatio);
10387 : } else {
10388 0 : VariableSpeedCoils::SimVariableSpeedCoils(state,
10389 : BlankString,
10390 0 : thisFurnace.HeatingCoilIndex,
10391 : thisFurnace.fanOp,
10392 : compressorOp,
10393 : 0.0,
10394 : 1,
10395 : 0.0,
10396 : 0.0,
10397 : 0.0,
10398 : OnOffAirFlowRatio);
10399 : }
10400 : }
10401 0 : } else if (thisFurnace.CoolingCoilUpstream && (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool)) {
10402 : // simulate thisFurnace heating coil
10403 0 : bool SuppHeatingCoilFlag = false; // if true simulates supplemental heating coil
10404 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, thisFurnace.fanOp, QCoilActual);
10405 : }
10406 :
10407 : // Simulate supplemental heating coil for blow through fan
10408 0 : if (thisFurnace.SuppHeatCoilIndex > 0) {
10409 0 : bool SuppHeatingCoilFlag = true; // if true simulates supplemental heating coil
10410 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, SupHeaterLoad, thisFurnace.fanOp, QCoilActual);
10411 : }
10412 : } else { // otherwise simulate DX coils then fan then supplemental heater
10413 :
10414 0 : if ((!thisFurnace.CoolingCoilUpstream) && (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool)) {
10415 : // simulate thisFurnace heating coil
10416 0 : bool SuppHeatingCoilFlag = false; // if true simulates supplemental heating coil
10417 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, thisFurnace.fanOp, QCoilActual);
10418 : }
10419 :
10420 0 : if ((QZnReq < -HVAC::SmallLoad || (QLatReq < -HVAC::SmallLoad)) &&
10421 0 : (state.dataEnvrn->OutDryBulbTemp >= thisFurnace.MinOATCompressorCooling)) {
10422 :
10423 0 : if (thisFurnace.bIsIHP) {
10424 0 : IntegratedHeatPump::SimIHP(state,
10425 : BlankString,
10426 0 : thisFurnace.CoolingCoilIndex,
10427 : thisFurnace.fanOp,
10428 : compressorOp,
10429 : PartLoadFrac,
10430 : SpeedNum,
10431 : SpeedRatio,
10432 : QZnReq,
10433 : QLatReq,
10434 : false,
10435 : false,
10436 : OnOffAirFlowRatio);
10437 : } else {
10438 0 : VariableSpeedCoils::SimVariableSpeedCoils(state,
10439 : BlankString,
10440 0 : thisFurnace.CoolingCoilIndex,
10441 : thisFurnace.fanOp,
10442 : compressorOp,
10443 : PartLoadFrac,
10444 : SpeedNum,
10445 : SpeedRatio,
10446 : QZnReq,
10447 : QLatReq,
10448 : OnOffAirFlowRatio);
10449 : }
10450 :
10451 0 : SavePartloadRatio = PartLoadFrac;
10452 0 : SaveSpeedRatio = SpeedRatio;
10453 :
10454 0 : state.dataFurnaces->SaveCompressorPLR = state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.CoolingCoilIndex).PartLoadRatio;
10455 : } else {
10456 0 : if (thisFurnace.bIsIHP) {
10457 0 : IntegratedHeatPump::SimIHP(state,
10458 : BlankString,
10459 0 : thisFurnace.CoolingCoilIndex,
10460 : thisFurnace.fanOp,
10461 : compressorOp,
10462 : PartLoadFrac,
10463 : SpeedNum,
10464 : SpeedRatio,
10465 : QZnReq,
10466 : QLatReq,
10467 : false,
10468 : false,
10469 : OnOffAirFlowRatio);
10470 : } else {
10471 0 : VariableSpeedCoils::SimVariableSpeedCoils(
10472 0 : state, BlankString, thisFurnace.CoolingCoilIndex, thisFurnace.fanOp, compressorOp, 0.0, 1, 0.0, 0.0, 0.0, OnOffAirFlowRatio);
10473 : }
10474 : }
10475 :
10476 0 : if (thisFurnace.type != HVAC::UnitarySysType::Unitary_HeatCool) {
10477 0 : if (QZnReq > HVAC::SmallLoad && (state.dataEnvrn->OutDryBulbTemp >= thisFurnace.MinOATCompressorCooling)) {
10478 :
10479 0 : if (thisFurnace.bIsIHP) {
10480 0 : IntegratedHeatPump::SimIHP(state,
10481 : BlankString,
10482 0 : thisFurnace.HeatingCoilIndex,
10483 : thisFurnace.fanOp,
10484 : compressorOp,
10485 : PartLoadFrac,
10486 : SpeedNum,
10487 : SpeedRatio,
10488 : QZnReq,
10489 : QLatReq,
10490 : false,
10491 : false,
10492 : OnOffAirFlowRatio);
10493 : } else {
10494 0 : VariableSpeedCoils::SimVariableSpeedCoils(state,
10495 : BlankString,
10496 0 : thisFurnace.HeatingCoilIndex,
10497 : thisFurnace.fanOp,
10498 : compressorOp,
10499 : PartLoadFrac,
10500 : SpeedNum,
10501 : SpeedRatio,
10502 : QZnReq,
10503 : QLatReq,
10504 : OnOffAirFlowRatio);
10505 : }
10506 :
10507 0 : SavePartloadRatio = PartLoadFrac;
10508 0 : SaveSpeedRatio = SpeedRatio;
10509 0 : state.dataFurnaces->SaveCompressorPLR = state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.HeatingCoilIndex).PartLoadRatio;
10510 : } else {
10511 0 : if (thisFurnace.bIsIHP) {
10512 0 : IntegratedHeatPump::SimIHP(state,
10513 : BlankString,
10514 0 : thisFurnace.CoolingCoilIndex,
10515 : thisFurnace.fanOp,
10516 : compressorOp,
10517 : PartLoadFrac,
10518 : SpeedNum,
10519 : SpeedRatio,
10520 : QZnReq,
10521 : QLatReq,
10522 : false,
10523 : false,
10524 : OnOffAirFlowRatio);
10525 : } else {
10526 0 : VariableSpeedCoils::SimVariableSpeedCoils(state,
10527 : BlankString,
10528 0 : thisFurnace.HeatingCoilIndex,
10529 : thisFurnace.fanOp,
10530 : compressorOp,
10531 : 0.0,
10532 : 1,
10533 : 0.0,
10534 : 0.0,
10535 : 0.0,
10536 : OnOffAirFlowRatio);
10537 : }
10538 : }
10539 0 : } else if (thisFurnace.CoolingCoilUpstream && (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool)) {
10540 : // simulate thisFurnace heating coil
10541 0 : bool SuppHeatingCoilFlag = false; // if true simulates supplemental heating coil
10542 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, thisFurnace.fanOp, QCoilActual);
10543 : }
10544 :
10545 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
10546 : // Simulate supplemental heating coil for draw through fan
10547 0 : if (thisFurnace.SuppHeatCoilIndex > 0) {
10548 0 : bool SuppHeatingCoilFlag = true; // if true simulates supplemental heating coil
10549 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, SupHeaterLoad, thisFurnace.fanOp, QCoilActual);
10550 : }
10551 : }
10552 :
10553 : // If the fan runs continually do not allow coils to set OnOffFanPartLoadRatio.
10554 0 : if (thisFurnace.fanOp == HVAC::FanOp::Continuous) {
10555 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
10556 : }
10557 :
10558 0 : auto &outNode = state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum);
10559 0 : auto &zoneNode = state.dataLoopNodes->Node(thisFurnace.NodeNumOfControlledZone);
10560 0 : Real64 zoneEnthalpy = Psychrometrics::PsyHFnTdbW(zoneNode.Temp, zoneNode.HumRat);
10561 0 : Real64 outletEnthalpy = Psychrometrics::PsyHFnTdbW(outNode.Temp, outNode.HumRat);
10562 0 : Real64 totalLoadMet = AirMassFlow * (outletEnthalpy - zoneEnthalpy);
10563 0 : SensibleLoadMet =
10564 0 : AirMassFlow * Psychrometrics::PsyDeltaHSenFnTdb2W2Tdb1W1(outNode.Temp, outNode.HumRat, zoneNode.Temp, zoneNode.HumRat); // sensible {W};
10565 0 : LatentLoadMet = totalLoadMet - SensibleLoadMet;
10566 0 : thisFurnace.LatentLoadMet = LatentLoadMet;
10567 0 : }
10568 :
10569 : //******************************************************************************
10570 :
10571 0 : Real64 VSHPCyclingResidual(EnergyPlusData &state,
10572 : Real64 const PartLoadFrac, // compressor cycling ratio (1.0 is continuous, 0.0 is off)
10573 : int FurnaceNum,
10574 : // int ZoneNum,
10575 : bool FirstHVACIteration,
10576 : // int fanOp,
10577 : Real64 LoadToBeMet,
10578 : Real64 OnOffAirFlowRatio,
10579 : Real64 SupHeaterLoad,
10580 : HVAC::CompressorOp compressorOp,
10581 : Real64 par9_SensLatFlag)
10582 : {
10583 : // FUNCTION INFORMATION:
10584 : // AUTHOR Bo Shen, based on HVACMultiSpeedHeatPump:MSHPCyclingResidual
10585 : // DATE WRITTEN March, 2012
10586 :
10587 : // PURPOSE OF THIS FUNCTION:
10588 : // Calculates residual function ((ActualOutput - QZnReq)/QZnReq)
10589 : // MSHP output depends on the part load ratio which is being varied to zero the residual.
10590 :
10591 : // METHODOLOGY EMPLOYED:
10592 : // Calls CalcMSHeatPump to get ActualOutput at the given part load ratio
10593 : // and calculates the residual as defined above
10594 :
10595 : // int FurnaceNum = int(Par[0]);
10596 : // int ZoneNum = int(Par[1]);
10597 : // bool FirstHVACIteration = (Par[2] == 1.0);
10598 : // int fanOp = int(Par[3]);
10599 : // Real64 LoadToBeMet = Par[4];
10600 : // Real64 OnOffAirFlowRatio = Par[5];
10601 : // Real64 SupHeaterLoad = Par[6];
10602 : // CompressorOperation CompressorOp = static_cast<CompressorOperation>(Par[8]);
10603 : // Real64 par9_SensLatFlag = Par[9];
10604 :
10605 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
10606 : Real64 ZoneSensLoadMet; // delivered sensible capacity of MSHP
10607 : Real64 ZoneLatLoadMet; // delivered latent capacity of MSHP
10608 :
10609 0 : Real64 QZnReq = 0.0;
10610 0 : Real64 QZnLat = 0.0;
10611 0 : if (par9_SensLatFlag == 1.0) {
10612 0 : QZnReq = LoadToBeMet;
10613 : } else {
10614 0 : QZnLat = LoadToBeMet;
10615 : }
10616 :
10617 0 : CalcVarSpeedHeatPump(state,
10618 : FurnaceNum,
10619 : FirstHVACIteration,
10620 : compressorOp,
10621 : 1,
10622 : 0.0,
10623 : PartLoadFrac,
10624 : ZoneSensLoadMet,
10625 : ZoneLatLoadMet,
10626 : QZnReq,
10627 : QZnLat,
10628 : OnOffAirFlowRatio,
10629 : SupHeaterLoad);
10630 :
10631 0 : Real64 ResScale = std::abs(LoadToBeMet);
10632 0 : if (ResScale < 100.0) {
10633 0 : ResScale = 100.0;
10634 : } else {
10635 0 : ResScale = LoadToBeMet;
10636 : }
10637 :
10638 : // Calculate residual based on output calculation flag
10639 0 : if (par9_SensLatFlag == 1.0) {
10640 0 : return (ZoneSensLoadMet - LoadToBeMet) / ResScale;
10641 : } else {
10642 0 : return (ZoneLatLoadMet - LoadToBeMet) / ResScale;
10643 : }
10644 : }
10645 :
10646 : //******************************************************************************
10647 :
10648 0 : Real64 VSHPSpeedResidual(EnergyPlusData &state,
10649 : Real64 const SpeedRatio, // compressor cycling ratio (1.0 is continuous, 0.0 is off)
10650 : int FurnaceNum,
10651 : // int ZoneNum,
10652 : bool FirstHVACIteration,
10653 : // int fanOp
10654 : Real64 LoadToBeMet,
10655 : Real64 OnOffAirFlowRatio,
10656 : Real64 SupHeaterLoad,
10657 : int SpeedNum,
10658 : HVAC::CompressorOp compressorOp,
10659 : Real64 par9_SensLatFlag)
10660 : {
10661 : // FUNCTION INFORMATION:
10662 : // AUTHOR Bo Shen, , based on HVACMultiSpeedHeatPump:MSHPVarSpeedgResidual
10663 : // DATE WRITTEN March, 2012
10664 :
10665 : // PURPOSE OF THIS FUNCTION:
10666 : // Calculates residual function ((ActualOutput - QZnReq)/QZnReq)
10667 : // MSHP output depends on the part load ratio which is being varied to zero the residual.
10668 :
10669 : // METHODOLOGY EMPLOYED:
10670 : // Calls CalcMSHeatPump to get ActualOutput at the given speed ratio (partload ratio for high speed)
10671 : // and calculates the residual as defined above
10672 :
10673 0 : Real64 QZnReq = 0.0;
10674 0 : Real64 QZnLat = 0.0;
10675 0 : if (par9_SensLatFlag == 1.0) {
10676 0 : QZnReq = LoadToBeMet;
10677 : } else {
10678 0 : QZnLat = LoadToBeMet;
10679 : }
10680 :
10681 : Real64 ZoneSensLoadMet; // delivered sensible capacity of MSHP
10682 : Real64 ZoneLatLoadMet; // delivered latent capacity of MSHP
10683 0 : CalcVarSpeedHeatPump(state,
10684 : FurnaceNum,
10685 : FirstHVACIteration,
10686 : compressorOp,
10687 : SpeedNum,
10688 : SpeedRatio,
10689 : 1.0,
10690 : ZoneSensLoadMet,
10691 : ZoneLatLoadMet,
10692 : QZnReq,
10693 : QZnLat,
10694 : OnOffAirFlowRatio,
10695 : SupHeaterLoad);
10696 :
10697 0 : Real64 ResScale = std::abs(LoadToBeMet);
10698 0 : if (ResScale < 100.0) {
10699 0 : ResScale = 100.0;
10700 : } else {
10701 0 : ResScale = LoadToBeMet;
10702 : }
10703 :
10704 : // Calculate residual based on output calculation flag
10705 0 : if (par9_SensLatFlag == 1.0) {
10706 0 : return (ZoneSensLoadMet - LoadToBeMet) / ResScale;
10707 : } else {
10708 0 : return (ZoneLatLoadMet - LoadToBeMet) / ResScale;
10709 : }
10710 : }
10711 :
10712 9 : void SetVSHPAirFlow(EnergyPlusData &state,
10713 : int const FurnaceNum, // Unit index
10714 : Real64 const PartLoadRatio, // unit part load ratio
10715 : Real64 &OnOffAirFlowRatio, // ratio of compressor ON airflow to average airflow over timestep
10716 : ObjexxFCL::Optional_int_const SpeedNum, // Speed number
10717 : ObjexxFCL::Optional<Real64 const> SpeedRatio // Speed ratio
10718 : )
10719 : {
10720 :
10721 : // SUBROUTINE INFORMATION:
10722 : // AUTHOR Bo Shen, based on HVACMultiSpeedHeatPump:SetAverageAirFlow
10723 : // DATE WRITTEN March, 2012
10724 :
10725 : // PURPOSE OF THIS SUBROUTINE:
10726 : // Set the average air mass flow rates using the part load fraction of the heat pump for this time step
10727 : // Set OnOffAirFlowRatio to be used by DX coils
10728 :
10729 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
10730 : Real64 AverageUnitMassFlow; // average supply air mass flow rate over time step
10731 :
10732 9 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
10733 :
10734 9 : state.dataHVACGlobal->MSHPMassFlowRateLow = 0.0; // Mass flow rate at low speed
10735 9 : state.dataHVACGlobal->MSHPMassFlowRateHigh = 0.0; // Mass flow rate at high speed
10736 :
10737 9 : if (thisFurnace.fanOp == HVAC::FanOp::Continuous) {
10738 1 : state.dataFurnaces->CompOffMassFlow = thisFurnace.IdleMassFlowRate;
10739 1 : state.dataFurnaces->CompOffFlowRatio = thisFurnace.IdleSpeedRatio;
10740 : } else {
10741 8 : state.dataFurnaces->CompOffMassFlow = 0.0;
10742 8 : state.dataFurnaces->CompOffFlowRatio = 0.0;
10743 : }
10744 :
10745 9 : if (state.dataFurnaces->CoolingLoad && (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool)) {
10746 3 : if (thisFurnace.NumOfSpeedCooling > 0) {
10747 3 : state.dataFurnaces->CompOnMassFlow = thisFurnace.CoolMassFlowRate(thisFurnace.NumOfSpeedCooling);
10748 3 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.MSCoolingSpeedRatio(thisFurnace.NumOfSpeedCooling);
10749 3 : state.dataHVACGlobal->MSHPMassFlowRateLow = thisFurnace.CoolMassFlowRate(thisFurnace.NumOfSpeedCooling);
10750 3 : state.dataHVACGlobal->MSHPMassFlowRateHigh = thisFurnace.CoolMassFlowRate(thisFurnace.NumOfSpeedCooling);
10751 : } else {
10752 0 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxCoolAirMassFlow;
10753 0 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.CoolingSpeedRatio;
10754 : }
10755 3 : AverageUnitMassFlow = (PartLoadRatio * state.dataFurnaces->CompOnMassFlow) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffMassFlow);
10756 3 : if (state.dataFurnaces->CompOffFlowRatio > 0.0) {
10757 0 : state.dataFurnaces->FanSpeedRatio =
10758 0 : (PartLoadRatio * state.dataFurnaces->CompOnFlowRatio) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffFlowRatio);
10759 : } else {
10760 3 : state.dataFurnaces->FanSpeedRatio = state.dataFurnaces->CompOnFlowRatio;
10761 : }
10762 6 : } else if (state.dataFurnaces->HeatingLoad && (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool)) {
10763 6 : if (thisFurnace.NumOfSpeedHeating > 0) {
10764 4 : state.dataFurnaces->CompOnMassFlow = thisFurnace.HeatMassFlowRate(thisFurnace.NumOfSpeedHeating);
10765 4 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.MSHeatingSpeedRatio(thisFurnace.NumOfSpeedHeating);
10766 4 : state.dataHVACGlobal->MSHPMassFlowRateLow = thisFurnace.HeatMassFlowRate(thisFurnace.NumOfSpeedHeating);
10767 4 : state.dataHVACGlobal->MSHPMassFlowRateHigh = thisFurnace.HeatMassFlowRate(thisFurnace.NumOfSpeedHeating);
10768 : } else {
10769 2 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxHeatAirMassFlow;
10770 2 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.HeatingSpeedRatio;
10771 : }
10772 6 : AverageUnitMassFlow = (PartLoadRatio * state.dataFurnaces->CompOnMassFlow) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffMassFlow);
10773 6 : if (state.dataFurnaces->CompOffFlowRatio > 0.0) {
10774 1 : state.dataFurnaces->FanSpeedRatio =
10775 1 : (PartLoadRatio * state.dataFurnaces->CompOnFlowRatio) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffFlowRatio);
10776 : } else {
10777 5 : state.dataFurnaces->FanSpeedRatio = state.dataFurnaces->CompOnFlowRatio;
10778 : }
10779 0 : } else if (thisFurnace.bIsIHP) {
10780 0 : if (!state.dataZoneEnergyDemand->CurDeadBandOrSetback(thisFurnace.ControlZoneNum) && present(SpeedNum)) {
10781 : // if(present(SpeedNum)) {
10782 0 : state.dataFurnaces->CompOnMassFlow =
10783 0 : IntegratedHeatPump::GetAirMassFlowRateIHP(state, thisFurnace.CoolingCoilIndex, SpeedNum, SpeedRatio, false);
10784 0 : state.dataFurnaces->CompOnFlowRatio =
10785 0 : state.dataFurnaces->CompOnMassFlow /
10786 0 : IntegratedHeatPump::GetAirMassFlowRateIHP(
10787 : state, thisFurnace.CoolingCoilIndex, IntegratedHeatPump::GetMaxSpeedNumIHP(state, thisFurnace.CoolingCoilIndex), 1.0, false);
10788 0 : state.dataHVACGlobal->MSHPMassFlowRateLow =
10789 0 : IntegratedHeatPump::GetAirMassFlowRateIHP(state, thisFurnace.CoolingCoilIndex, SpeedNum, 0.0, false);
10790 0 : state.dataHVACGlobal->MSHPMassFlowRateHigh =
10791 0 : IntegratedHeatPump::GetAirMassFlowRateIHP(state, thisFurnace.CoolingCoilIndex, SpeedNum, 1.0, false);
10792 : }
10793 :
10794 : // Set up fan flow rate during compressor off time
10795 0 : if (thisFurnace.fanOp == HVAC::FanOp::Continuous && present(SpeedNum)) {
10796 0 : if (thisFurnace.AirFlowControl == AirFlowControlConstFan::UseCompressorOnFlow && state.dataFurnaces->CompOnMassFlow > 0.0) {
10797 0 : state.dataFurnaces->CompOffMassFlow =
10798 0 : IntegratedHeatPump::GetAirMassFlowRateIHP(state, thisFurnace.CoolingCoilIndex, SpeedNum, 1.0, false);
10799 0 : state.dataFurnaces->CompOffFlowRatio =
10800 0 : state.dataFurnaces->CompOffMassFlow /
10801 0 : IntegratedHeatPump::GetAirMassFlowRateIHP(state,
10802 : thisFurnace.CoolingCoilIndex,
10803 : IntegratedHeatPump::GetMaxSpeedNumIHP(state, thisFurnace.CoolingCoilIndex),
10804 : 1.0,
10805 : false);
10806 : }
10807 : }
10808 :
10809 0 : if (present(SpeedNum)) {
10810 0 : if (SpeedNum > 1) {
10811 0 : AverageUnitMassFlow = state.dataFurnaces->CompOnMassFlow;
10812 0 : state.dataFurnaces->FanSpeedRatio = state.dataFurnaces->CompOnFlowRatio;
10813 : } else {
10814 0 : AverageUnitMassFlow =
10815 0 : (PartLoadRatio * state.dataFurnaces->CompOnMassFlow) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffMassFlow);
10816 0 : if (state.dataFurnaces->CompOffFlowRatio > 0.0) {
10817 0 : state.dataFurnaces->FanSpeedRatio =
10818 0 : (PartLoadRatio * state.dataFurnaces->CompOnFlowRatio) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffFlowRatio);
10819 : } else {
10820 0 : state.dataFurnaces->FanSpeedRatio = state.dataFurnaces->CompOnFlowRatio;
10821 : }
10822 : }
10823 : } else {
10824 0 : AverageUnitMassFlow =
10825 0 : (PartLoadRatio * state.dataFurnaces->CompOnMassFlow) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffMassFlow);
10826 0 : if (state.dataFurnaces->CompOffFlowRatio > 0.0) {
10827 0 : state.dataFurnaces->FanSpeedRatio =
10828 0 : (PartLoadRatio * state.dataFurnaces->CompOnFlowRatio) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffFlowRatio);
10829 : } else {
10830 0 : state.dataFurnaces->FanSpeedRatio = state.dataFurnaces->CompOnFlowRatio;
10831 : }
10832 : }
10833 :
10834 0 : if (IntegratedHeatPump::IHPOperationMode::SCWHMatchWH ==
10835 0 : state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).CurMode) {
10836 0 : state.dataFurnaces->CompOnMassFlow =
10837 0 : IntegratedHeatPump::GetAirMassFlowRateIHP(state, thisFurnace.CoolingCoilIndex, SpeedNum, SpeedRatio, false);
10838 0 : AverageUnitMassFlow = state.dataFurnaces->CompOnMassFlow;
10839 : }
10840 : } else {
10841 0 : if (!state.dataZoneEnergyDemand->CurDeadBandOrSetback(thisFurnace.ControlZoneNum) && present(SpeedNum)) {
10842 0 : if (thisFurnace.HeatCoolMode == Furnaces::ModeOfOperation::HeatingMode) {
10843 0 : if (SpeedNum == 1) {
10844 0 : state.dataFurnaces->CompOnMassFlow = thisFurnace.HeatMassFlowRate(SpeedNum);
10845 0 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.MSHeatingSpeedRatio(SpeedNum);
10846 0 : state.dataHVACGlobal->MSHPMassFlowRateLow = thisFurnace.HeatMassFlowRate(1);
10847 0 : state.dataHVACGlobal->MSHPMassFlowRateHigh = thisFurnace.HeatMassFlowRate(1);
10848 0 : } else if (SpeedNum > 1) {
10849 0 : state.dataFurnaces->CompOnMassFlow =
10850 0 : SpeedRatio * thisFurnace.HeatMassFlowRate(SpeedNum) + (1.0 - SpeedRatio) * thisFurnace.HeatMassFlowRate(SpeedNum - 1);
10851 0 : state.dataFurnaces->CompOnFlowRatio = SpeedRatio * thisFurnace.MSHeatingSpeedRatio(SpeedNum) +
10852 0 : (1.0 - SpeedRatio) * thisFurnace.MSHeatingSpeedRatio(SpeedNum - 1);
10853 0 : state.dataHVACGlobal->MSHPMassFlowRateLow = thisFurnace.HeatMassFlowRate(SpeedNum - 1);
10854 0 : state.dataHVACGlobal->MSHPMassFlowRateHigh = thisFurnace.HeatMassFlowRate(SpeedNum);
10855 : }
10856 0 : } else if (thisFurnace.HeatCoolMode == Furnaces::ModeOfOperation::CoolingMode) {
10857 0 : if (SpeedNum == 1) {
10858 0 : state.dataFurnaces->CompOnMassFlow = thisFurnace.CoolMassFlowRate(SpeedNum);
10859 0 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.MSCoolingSpeedRatio(SpeedNum);
10860 0 : state.dataHVACGlobal->MSHPMassFlowRateLow = thisFurnace.CoolMassFlowRate(1);
10861 0 : state.dataHVACGlobal->MSHPMassFlowRateHigh = thisFurnace.CoolMassFlowRate(1);
10862 0 : } else if (SpeedNum > 1) {
10863 0 : state.dataFurnaces->CompOnMassFlow =
10864 0 : SpeedRatio * thisFurnace.CoolMassFlowRate(SpeedNum) + (1.0 - SpeedRatio) * thisFurnace.CoolMassFlowRate(SpeedNum - 1);
10865 0 : state.dataFurnaces->CompOnFlowRatio = SpeedRatio * thisFurnace.MSCoolingSpeedRatio(SpeedNum) +
10866 0 : (1.0 - SpeedRatio) * thisFurnace.MSCoolingSpeedRatio(SpeedNum - 1);
10867 0 : state.dataHVACGlobal->MSHPMassFlowRateLow = thisFurnace.CoolMassFlowRate(SpeedNum - 1);
10868 0 : state.dataHVACGlobal->MSHPMassFlowRateHigh = thisFurnace.CoolMassFlowRate(SpeedNum);
10869 : }
10870 : }
10871 : }
10872 :
10873 : // Set up fan flow rate during compressor off time
10874 0 : if (thisFurnace.fanOp == HVAC::FanOp::Continuous && present(SpeedNum)) {
10875 0 : if (thisFurnace.AirFlowControl == AirFlowControlConstFan::UseCompressorOnFlow && state.dataFurnaces->CompOnMassFlow > 0.0) {
10876 0 : if (SpeedNum == 1) { // LOWEST SPEED USE IDLE FLOW
10877 0 : state.dataFurnaces->CompOffMassFlow = thisFurnace.IdleMassFlowRate;
10878 0 : state.dataFurnaces->CompOffFlowRatio = thisFurnace.IdleSpeedRatio;
10879 0 : } else if (thisFurnace.LastMode == Furnaces::ModeOfOperation::HeatingMode) {
10880 0 : state.dataFurnaces->CompOffMassFlow = thisFurnace.HeatMassFlowRate(SpeedNum);
10881 0 : state.dataFurnaces->CompOffFlowRatio = thisFurnace.MSHeatingSpeedRatio(SpeedNum);
10882 : } else {
10883 0 : state.dataFurnaces->CompOffMassFlow = thisFurnace.CoolMassFlowRate(SpeedNum);
10884 0 : state.dataFurnaces->CompOffFlowRatio = thisFurnace.MSCoolingSpeedRatio(SpeedNum);
10885 : }
10886 : }
10887 : }
10888 :
10889 0 : if (present(SpeedNum)) {
10890 0 : if (SpeedNum > 1) {
10891 0 : AverageUnitMassFlow = state.dataFurnaces->CompOnMassFlow;
10892 0 : state.dataFurnaces->FanSpeedRatio = state.dataFurnaces->CompOnFlowRatio;
10893 : } else {
10894 0 : AverageUnitMassFlow =
10895 0 : (PartLoadRatio * state.dataFurnaces->CompOnMassFlow) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffMassFlow);
10896 0 : if (state.dataFurnaces->CompOffFlowRatio > 0.0) {
10897 0 : state.dataFurnaces->FanSpeedRatio =
10898 0 : (PartLoadRatio * state.dataFurnaces->CompOnFlowRatio) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffFlowRatio);
10899 : } else {
10900 0 : state.dataFurnaces->FanSpeedRatio = state.dataFurnaces->CompOnFlowRatio;
10901 : }
10902 : }
10903 : } else {
10904 0 : AverageUnitMassFlow =
10905 0 : (PartLoadRatio * state.dataFurnaces->CompOnMassFlow) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffMassFlow);
10906 0 : if (state.dataFurnaces->CompOffFlowRatio > 0.0) {
10907 0 : state.dataFurnaces->FanSpeedRatio =
10908 0 : (PartLoadRatio * state.dataFurnaces->CompOnFlowRatio) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffFlowRatio);
10909 : } else {
10910 0 : state.dataFurnaces->FanSpeedRatio = state.dataFurnaces->CompOnFlowRatio;
10911 : }
10912 : }
10913 : }
10914 :
10915 17 : if ((thisFurnace.availSched->getCurrentVal() == 0.0) || state.dataHVACGlobal->TurnFansOff ||
10916 8 : (thisFurnace.fanAvailSched->getCurrentVal() == 0.0 && !state.dataHVACGlobal->TurnFansOn)) {
10917 1 : state.dataLoopNodes->Node(thisFurnace.FurnaceInletNodeNum).MassFlowRate = 0.0;
10918 1 : OnOffAirFlowRatio = 0.0;
10919 : } else {
10920 8 : state.dataLoopNodes->Node(thisFurnace.FurnaceInletNodeNum).MassFlowRate = AverageUnitMassFlow;
10921 8 : state.dataLoopNodes->Node(thisFurnace.FurnaceInletNodeNum).MassFlowRateMaxAvail = AverageUnitMassFlow;
10922 8 : if (AverageUnitMassFlow > 0.0) {
10923 8 : OnOffAirFlowRatio = state.dataFurnaces->CompOnMassFlow / AverageUnitMassFlow;
10924 : } else {
10925 0 : OnOffAirFlowRatio = 0.0;
10926 : }
10927 : }
10928 :
10929 9 : state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum).MassFlowRate =
10930 9 : state.dataLoopNodes->Node(thisFurnace.FurnaceInletNodeNum).MassFlowRate;
10931 9 : }
10932 :
10933 7 : void SetMinOATCompressor(EnergyPlusData &state,
10934 : int const FurnaceNum, // index to furnace
10935 : std::string const &cCurrentModuleObject, // type of furnace
10936 : bool &ErrorsFound // GetInput logical that errors were found
10937 : )
10938 : {
10939 7 : bool errFlag = false;
10940 7 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
10941 :
10942 : // Set minimum OAT for heat pump compressor operation in heating mode
10943 7 : if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingSingleSpeed) {
10944 5 : thisFurnace.MinOATCompressorCooling = DXCoils::GetMinOATCompressor(state, thisFurnace.CoolingCoilIndex, errFlag);
10945 2 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) {
10946 1 : std::string ChildCoolingCoilType = state.dataHVACAssistedCC->HXAssistedCoil(thisFurnace.CoolingCoilIndex).CoolingCoilType;
10947 1 : std::string ChildCoolingCoilName = state.dataHVACAssistedCC->HXAssistedCoil(thisFurnace.CoolingCoilIndex).CoolingCoilName;
10948 :
10949 1 : if (Util::SameString(ChildCoolingCoilType, "COIL:COOLING:DX")) {
10950 1 : int childCCIndex_DX = CoilCoolingDX::factory(state, ChildCoolingCoilName);
10951 1 : if (childCCIndex_DX < 0) {
10952 0 : ShowContinueError(state, format("Occurs in {} = {}", cCurrentModuleObject, thisFurnace.Name));
10953 0 : errFlag = true;
10954 0 : ErrorsFound = true;
10955 : }
10956 1 : auto const &newCoil = state.dataCoilCoolingDX->coilCoolingDXs[childCCIndex_DX];
10957 1 : thisFurnace.MinOATCompressorCooling = newCoil.performance.minOutdoorDrybulb;
10958 0 : } else if (Util::SameString(ChildCoolingCoilType, "Coil:Cooling:DX:VariableSpeed")) {
10959 0 : int childCCIndex_VS = state.dataHVACAssistedCC->HXAssistedCoil(thisFurnace.CoolingCoilIndex).CoolingCoilIndex;
10960 0 : thisFurnace.MinOATCompressorCooling = VariableSpeedCoils::GetVSCoilMinOATCompressor(state, childCCIndex_VS, errFlag);
10961 : } else { // Single speed
10962 0 : int childCCIndex_SP = state.dataHVACAssistedCC->HXAssistedCoil(thisFurnace.CoolingCoilIndex).CoolingCoilIndex;
10963 0 : thisFurnace.MinOATCompressorCooling = DXCoils::GetMinOATCompressor(state, childCCIndex_SP, errFlag);
10964 : }
10965 2 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) {
10966 1 : thisFurnace.MinOATCompressorCooling = VariableSpeedCoils::GetVSCoilMinOATCompressor(state, thisFurnace.CoolingCoilIndex, errFlag);
10967 : } else {
10968 0 : thisFurnace.MinOATCompressorCooling = -1000.0;
10969 : }
10970 7 : if (errFlag) {
10971 0 : ShowContinueError(state, format("...occurs in {} = {}", cCurrentModuleObject, thisFurnace.Name));
10972 0 : ErrorsFound = true;
10973 : }
10974 :
10975 : // Set minimum OAT for heat pump compressor operation in heating mode
10976 7 : errFlag = false;
10977 7 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed) {
10978 1 : thisFurnace.MinOATCompressorHeating = VariableSpeedCoils::GetVSCoilMinOATCompressor(state, thisFurnace.HeatingCoilIndex, errFlag);
10979 6 : } else if (thisFurnace.HeatingCoilType_Num == HVAC::CoilDX_HeatingEmpirical) {
10980 3 : thisFurnace.MinOATCompressorHeating = DXCoils::GetMinOATCompressor(state, thisFurnace.HeatingCoilIndex, errFlag);
10981 : } else {
10982 3 : thisFurnace.MinOATCompressorHeating = -1000.0;
10983 : }
10984 7 : if (errFlag) {
10985 0 : ShowContinueError(state, format("...occurs in {} = {}", cCurrentModuleObject, thisFurnace.Name));
10986 0 : ErrorsFound = true;
10987 : }
10988 7 : }
10989 :
10990 : } // namespace Furnaces
10991 :
10992 : } // namespace EnergyPlus
|