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 0 : SimVariableSpeedHP(state, FurnaceNum, FirstHVACIteration, AirLoopNum, ZoneLoad, MoistureLoad, OnOffAirFlowRatio);
320 : } else {
321 : // calculate the system flow rate
322 0 : if (!FirstHVACIteration && thisFurnace.fanOp == HVAC::FanOp::Cycling && state.dataFurnaces->CoolingLoad &&
323 0 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).EconoActive) {
324 : // for cycling fan, cooling load, check whether furnace can meet load with compressor off
325 0 : compressorOp = HVAC::CompressorOp::Off;
326 0 : CalcNewZoneHeatCoolFlowRates(state,
327 : FurnaceNum,
328 : FirstHVACIteration,
329 : compressorOp,
330 : ZoneLoad,
331 : MoistureLoad,
332 : HeatCoilLoad,
333 : ReheatCoilLoad,
334 : OnOffAirFlowRatio,
335 : HXUnitOn);
336 0 : if (thisFurnace.CoolPartLoadRatio >= 1.0 || thisFurnace.HeatPartLoadRatio >= 1.0 ||
337 0 : (thisFurnace.CoolPartLoadRatio <= 0.0 && thisFurnace.HeatPartLoadRatio <= 0.0)) {
338 : // compressor on (reset inlet air mass flow rate to starting value)
339 0 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = FurnaceSavMdot;
340 0 : compressorOp = HVAC::CompressorOp::On;
341 0 : CalcNewZoneHeatCoolFlowRates(state,
342 : FurnaceNum,
343 : FirstHVACIteration,
344 : compressorOp,
345 : ZoneLoad,
346 : MoistureLoad,
347 : HeatCoilLoad,
348 : ReheatCoilLoad,
349 : OnOffAirFlowRatio,
350 : HXUnitOn);
351 : }
352 : } else {
353 : // compressor on
354 0 : CalcNewZoneHeatCoolFlowRates(state,
355 : FurnaceNum,
356 : FirstHVACIteration,
357 : compressorOp,
358 : ZoneLoad,
359 : MoistureLoad,
360 : HeatCoilLoad,
361 : ReheatCoilLoad,
362 : OnOffAirFlowRatio,
363 : HXUnitOn);
364 : }
365 :
366 0 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
367 : // simulate fan
368 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
369 : }
370 :
371 0 : if (!thisFurnace.CoolingCoilUpstream) {
372 : // simulate furnace heating coil
373 0 : SuppHeatingCoilFlag = false; // if true simulates supplemental heating coil
374 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, fanOp, QActual);
375 : }
376 :
377 : // simulate furnace DX cooling coil
378 0 : if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) {
379 0 : HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(state,
380 : BlankString,
381 : FirstHVACIteration,
382 : compressorOp,
383 : thisFurnace.CoolPartLoadRatio,
384 0 : thisFurnace.CoolingCoilIndex,
385 : fanOp,
386 : HXUnitOn,
387 : OnOffAirFlowRatio,
388 0 : state.dataFurnaces->EconomizerFlag);
389 : } else {
390 0 : DXCoils::SimDXCoil(state,
391 : BlankString,
392 : compressorOp,
393 : FirstHVACIteration,
394 0 : thisFurnace.CoolingCoilIndex,
395 : fanOp,
396 0 : thisFurnace.CoolPartLoadRatio,
397 : OnOffAirFlowRatio,
398 0 : state.dataFurnaces->CoolHeatPLRRat);
399 : }
400 :
401 0 : if (thisFurnace.CoolingCoilUpstream) {
402 : // simulate furnace heating coil
403 0 : SuppHeatingCoilFlag = false; // if true simulates supplemental heating coil
404 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, fanOp, QActual);
405 : }
406 :
407 0 : if (thisFurnace.fanPlace == HVAC::FanPlace::DrawThru) {
408 : // simulate fan
409 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
410 : }
411 :
412 : // Simulate furnace reheat coil if a humidistat is used or if the reheat coil is present
413 0 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat || thisFurnace.SuppHeatCoilIndex > 0) {
414 0 : SuppHeatingCoilFlag = true; // if true simulates supplemental heating coil
415 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, ReheatCoilLoad, fanOp, QActual);
416 : }
417 : }
418 0 : } break;
419 : // Simulate air-to-air heat pumps:
420 15222 : case HVAC::UnitarySysType::Unitary_HeatPump_AirToAir: {
421 15222 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed) {
422 : // variable speed heat pump
423 0 : HeatCoilLoad = 0.0;
424 0 : if (thisFurnace.bIsIHP) {
425 0 : auto &integratedHP = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex);
426 0 : integratedHP.ControlledZoneTemp = state.dataLoopNodes->Node(thisFurnace.NodeNumOfControlledZone).Temp;
427 0 : integratedHP.IDFanID = thisFurnace.FanIndex; // why do this every time?
428 0 : integratedHP.IDFanName = BlankString;
429 0 : integratedHP.fanPlace = thisFurnace.fanPlace;
430 : }
431 :
432 0 : SimVariableSpeedHP(state, FurnaceNum, FirstHVACIteration, AirLoopNum, ZoneLoad, MoistureLoad, OnOffAirFlowRatio);
433 : } else {
434 : // Update the furnace flow rates
435 20283 : if (!FirstHVACIteration && thisFurnace.fanOp == HVAC::FanOp::Cycling && state.dataFurnaces->CoolingLoad &&
436 5061 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).EconoActive) {
437 : // for cycling fan, cooling load, check whether furnace can meet load with compressor off
438 0 : compressorOp = HVAC::CompressorOp::Off;
439 0 : CalcNewZoneHeatCoolFlowRates(state,
440 : FurnaceNum,
441 : FirstHVACIteration,
442 : compressorOp,
443 : ZoneLoad,
444 : MoistureLoad,
445 : HeatCoilLoad,
446 : ReheatCoilLoad,
447 : OnOffAirFlowRatio,
448 : HXUnitOn);
449 0 : if (thisFurnace.CoolPartLoadRatio >= 1.0 || thisFurnace.HeatPartLoadRatio >= 1.0 ||
450 0 : (thisFurnace.CoolPartLoadRatio <= 0.0 && thisFurnace.HeatPartLoadRatio <= 0.0)) {
451 : // compressor on (reset inlet air mass flow rate to starting value)
452 0 : compressorOp = HVAC::CompressorOp::On;
453 0 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = FurnaceSavMdot;
454 0 : CalcNewZoneHeatCoolFlowRates(state,
455 : FurnaceNum,
456 : FirstHVACIteration,
457 : compressorOp,
458 : ZoneLoad,
459 : MoistureLoad,
460 : HeatCoilLoad,
461 : ReheatCoilLoad,
462 : OnOffAirFlowRatio,
463 : HXUnitOn);
464 : }
465 : } else {
466 : // compressor on
467 15222 : CalcNewZoneHeatCoolFlowRates(state,
468 : FurnaceNum,
469 : FirstHVACIteration,
470 : compressorOp,
471 : ZoneLoad,
472 : MoistureLoad,
473 : HeatCoilLoad,
474 : ReheatCoilLoad,
475 : OnOffAirFlowRatio,
476 : HXUnitOn);
477 : }
478 :
479 15222 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
480 15222 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
481 : }
482 :
483 15222 : if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) {
484 0 : HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(state,
485 : BlankString,
486 : FirstHVACIteration,
487 : compressorOp,
488 : thisFurnace.CoolPartLoadRatio,
489 0 : thisFurnace.CoolingCoilIndex,
490 : fanOp,
491 : HXUnitOn,
492 : OnOffAirFlowRatio,
493 0 : state.dataFurnaces->EconomizerFlag);
494 : } else {
495 30444 : DXCoils::SimDXCoil(state,
496 : BlankString,
497 : compressorOp,
498 : FirstHVACIteration,
499 15222 : thisFurnace.CoolingCoilIndex,
500 : fanOp,
501 15222 : thisFurnace.CoolPartLoadRatio,
502 : OnOffAirFlowRatio);
503 : }
504 30444 : DXCoils::SimDXCoil(state,
505 : BlankString,
506 : compressorOp,
507 : FirstHVACIteration,
508 15222 : thisFurnace.HeatingCoilIndex,
509 : fanOp,
510 15222 : thisFurnace.HeatPartLoadRatio,
511 : OnOffAirFlowRatio);
512 15222 : if (thisFurnace.fanPlace == HVAC::FanPlace::DrawThru) {
513 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
514 : }
515 :
516 : // Simulate furnace reheat coil if a humidistat is present, the dehumidification type of coolreheat and
517 : // reheat coil load exists
518 15222 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat && ReheatCoilLoad > 0.0) {
519 0 : SuppHeatingCoilFlag = true; // if true simulates supplemental heating coil
520 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, ReheatCoilLoad, fanOp, QActual);
521 : } else {
522 15222 : SuppHeatingCoilFlag = true; // if true simulates supplemental heating coil
523 15222 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, fanOp, QActual);
524 : }
525 : }
526 15222 : } break;
527 : // Simulate water-to-air systems:
528 0 : case HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir: {
529 0 : if (thisFurnace.WatertoAirHPType == WAHPCoilType::Simple) {
530 : // Update the furnace flow rates
531 : // When CompressorOp logic is added to the child cooling coil (COIL:WaterToAirHP:EquationFit:Cooling), then this logic
532 : // needs to be reinstated... to align with Unitary/Furnace HeatCool and Unitary Air-to-Air Heat Pump (see above).
533 0 : if (!FirstHVACIteration && thisFurnace.fanOp == HVAC::FanOp::Cycling && state.dataFurnaces->CoolingLoad &&
534 0 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).EconoActive) {
535 : // for cycling fan, cooling load, check whether furnace can meet load with compressor off
536 0 : compressorOp = HVAC::CompressorOp::Off;
537 0 : CalcNewZoneHeatCoolFlowRates(state,
538 : FurnaceNum,
539 : FirstHVACIteration,
540 : compressorOp,
541 : ZoneLoad,
542 : MoistureLoad,
543 : HeatCoilLoad,
544 : ReheatCoilLoad,
545 : OnOffAirFlowRatio,
546 : HXUnitOn);
547 0 : if (thisFurnace.CoolPartLoadRatio >= 1.0 || thisFurnace.HeatPartLoadRatio >= 1.0 ||
548 0 : (thisFurnace.CoolPartLoadRatio <= 0.0 && thisFurnace.HeatPartLoadRatio <= 0.0)) {
549 : // compressor on (reset inlet air mass flow rate to starting value)
550 0 : compressorOp = HVAC::CompressorOp::On;
551 0 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = FurnaceSavMdot;
552 0 : CalcNewZoneHeatCoolFlowRates(state,
553 : FurnaceNum,
554 : FirstHVACIteration,
555 : compressorOp,
556 : ZoneLoad,
557 : MoistureLoad,
558 : HeatCoilLoad,
559 : ReheatCoilLoad,
560 : OnOffAirFlowRatio,
561 : HXUnitOn);
562 : }
563 : } else {
564 : // compressor on
565 0 : CalcNewZoneHeatCoolFlowRates(state,
566 : FurnaceNum,
567 : FirstHVACIteration,
568 : compressorOp,
569 : ZoneLoad,
570 : MoistureLoad,
571 : HeatCoilLoad,
572 : ReheatCoilLoad,
573 : OnOffAirFlowRatio,
574 : HXUnitOn);
575 : }
576 0 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
577 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
578 : }
579 :
580 0 : WaterToAirHeatPumpSimple::SimWatertoAirHPSimple(state,
581 : BlankString,
582 0 : thisFurnace.CoolingCoilIndex,
583 : thisFurnace.CoolingCoilSensDemand,
584 : thisFurnace.CoolingCoilLatentDemand,
585 : thisFurnace.fanOp,
586 : compressorOp,
587 : thisFurnace.CoolPartLoadRatio,
588 : FirstHVACIteration);
589 0 : WaterToAirHeatPumpSimple::SimWatertoAirHPSimple(state,
590 : BlankString,
591 0 : thisFurnace.HeatingCoilIndex,
592 : thisFurnace.HeatingCoilSensDemand,
593 : Dummy,
594 : thisFurnace.fanOp,
595 : compressorOp,
596 : thisFurnace.HeatPartLoadRatio,
597 : FirstHVACIteration);
598 :
599 0 : if (thisFurnace.fanPlace == HVAC::FanPlace::DrawThru) {
600 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
601 : }
602 0 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat && ReheatCoilLoad > 0.0) {
603 0 : SuppHeatingCoilFlag = true; // if true simulates supplemental heating coil
604 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, ReheatCoilLoad, fanOp, QActual);
605 : } else {
606 0 : SuppHeatingCoilFlag = true; // if true simulates supplemental heating coil
607 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, fanOp, QActual);
608 : }
609 0 : } else if (thisFurnace.WatertoAirHPType == WAHPCoilType::ParEst) {
610 :
611 : // simulate the heat pump
612 0 : HeatCoilLoad = 0.0;
613 0 : CalcWaterToAirHeatPump(state, FurnaceNum, FirstHVACIteration, compressorOp, ZoneLoad, MoistureLoad);
614 0 : } else if (thisFurnace.WatertoAirHPType == WAHPCoilType::VarSpeedEquationFit) {
615 : // simulate the heat pump
616 0 : HeatCoilLoad = 0.0;
617 0 : if (thisFurnace.bIsIHP)
618 0 : state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).ControlledZoneTemp =
619 0 : state.dataLoopNodes->Node(thisFurnace.NodeNumOfControlledZone).Temp;
620 0 : SimVariableSpeedHP(state, FurnaceNum, FirstHVACIteration, AirLoopNum, ZoneLoad, MoistureLoad, OnOffAirFlowRatio);
621 :
622 0 : } else if (thisFurnace.WatertoAirHPType == WAHPCoilType::VarSpeedLookupTable) {
623 0 : HeatCoilLoad = 0.0; // Added: Used below
624 : } else {
625 0 : assert(false); //? If all possible states covered by if conditions change to HeatCoilLoad = 0.0;
626 : }
627 0 : } break;
628 0 : default: {
629 : // will never get here, all system types are simulated above
630 0 : assert(false);
631 : } break;
632 : }
633 :
634 : // set the econo lockout flags
635 15222 : auto &airLoopControlInfo = state.dataAirLoop->AirLoopControlInfo(AirLoopNum);
636 15222 : if (thisFurnace.CompPartLoadRatio > 0.0 && airLoopControlInfo.CanLockoutEconoWithCompressor) {
637 0 : airLoopControlInfo.ReqstEconoLockoutWithCompressor = true;
638 : } else {
639 15222 : airLoopControlInfo.ReqstEconoLockoutWithCompressor = false;
640 : }
641 :
642 15222 : if ((HeatCoilLoad > 0.0 || thisFurnace.HeatPartLoadRatio > 0.0) &&
643 8361 : (airLoopControlInfo.CanLockoutEconoWithCompressor || airLoopControlInfo.CanLockoutEconoWithHeating)) {
644 0 : airLoopControlInfo.ReqstEconoLockoutWithHeating = true;
645 : } else {
646 15222 : airLoopControlInfo.ReqstEconoLockoutWithHeating = false;
647 : }
648 :
649 15222 : if (thisFurnace.fanOp == HVAC::FanOp::Cycling) {
650 15222 : state.dataAirLoop->AirLoopFlow(AirLoopNum).FanPLR = thisFurnace.FanPartLoadRatio;
651 : } else {
652 0 : state.dataAirLoop->AirLoopFlow(AirLoopNum).FanPLR = 1.0; // 1 means constant fan does not cycle.
653 : }
654 :
655 : // Report the current Furnace output
656 15222 : ReportFurnace(state, FurnaceNum, AirLoopNum);
657 :
658 : // Reset OnOffFanPartLoadFraction to 1 in case another on/off fan is called without a part-load curve
659 15222 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
660 :
661 15222 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRateMaxAvail = TempMassFlowRateMaxAvail;
662 15222 : }
663 :
664 : // Get Input Section of the Module
665 : //******************************************************************************
666 :
667 2 : void GetFurnaceInput(EnergyPlusData &state)
668 : {
669 :
670 : // SUBROUTINE INFORMATION:
671 : // AUTHOR Richard Liesen
672 : // DATE WRITTEN Feb 2001
673 : // MODIFIED Don Shirey and Rich Raustad, Mar/Oct 2001, Mar 2003
674 : // Bereket Nigusse, April 2010 - deprecated supply air flow fraction through
675 : // controlled zone from the input field.
676 : // Bo Shen, March 2012, add inputs for VS WSHP,
677 : // Bo Shen, ORNL, July 2012 - added variable-speed air source heat pump cooling and heating coils, using curve-fits
678 :
679 : // PURPOSE OF THIS SUBROUTINE:
680 : // Obtains input data for fans and coils and stores it in the Furnace data structures
681 :
682 : // METHODOLOGY EMPLOYED:
683 : // Uses "Get" routines to read in data.
684 :
685 : // SUBROUTINE PARAMETER DEFINITIONS:
686 2 : std::string_view constexpr getUnitaryHeatOnly("GetUnitaryHeatOnly");
687 2 : std::string_view constexpr getAirLoopHVACHeatCoolInput("GetAirLoopHVACHeatCoolInput");
688 2 : std::string_view constexpr routineName = "GetFurnaceInput";
689 :
690 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
691 : int FurnaceNum; // The Furnace that you are currently loading input into
692 : int GetObjectNum; // The index to each specific object name
693 : int NumFields; // Total number of fields in object
694 : int NumAlphas; // Total number of alpha fields in object
695 : int NumNumbers; // Total number of numeric fields in object
696 : int IOStatus; // Function call status
697 2 : Array1D<Real64> Numbers; // Numeric data
698 2 : Array1D_string Alphas; // Alpha data
699 2 : Array1D_string cAlphaFields; // Alpha field names
700 2 : Array1D_string cNumericFields; // Numeric field names
701 2 : Array1D_bool lAlphaBlanks; // Logical array, alpha field input BLANK = .TRUE.
702 2 : Array1D_bool lNumericBlanks; // Logical array, numeric field input BLANK = .TRUE.
703 2 : std::string CompSetFanInlet;
704 2 : std::string CompSetFanOutlet;
705 2 : std::string CompSetCoolInlet;
706 2 : std::string CompSetHeatInlet;
707 2 : std::string CompSetHeatOutlet;
708 2 : bool ErrorsFound(false); // If errors detected in input
709 : bool IsNotOK; // Flag to verify name
710 : bool AirNodeFound; // Used to determine if control zone is valid
711 : bool AirLoopFound; // Used to determine if control zone is served by furnace air loop
712 : int TstatZoneNum; // Used to determine if control zone has a thermostat object
713 : int HStatZoneNum; // Used to determine if control zone has a humidistat object
714 : bool errFlag; // Mining function error flag
715 : int FanInletNode; // Used for node checking warning messages
716 : int FanOutletNode; // Used for node checking warning messages
717 : int CoolingCoilInletNode; // Used for node checking warning messages
718 : int CoolingCoilOutletNode; // Used for node checking warning messages
719 : int HeatingCoilInletNode; // Used for node checking warning messages
720 : int HeatingCoilOutletNode; // Used for node checking warning messages
721 : int SupHeatCoilInletNode; // Used for node checking warning messages
722 : int SupHeatCoilOutletNode; // Used for node checking warning messages
723 2 : std::string CoolingCoilType; // Used in mining function CALLS
724 2 : std::string CoolingCoilName; // Used in mining function CALLS
725 2 : std::string HeatingCoilType; // Used in mining function CALLS
726 2 : std::string HeatingCoilName; // Used in mining function CALLS
727 2 : std::string ReheatingCoilType; // Used in mining function CALLS
728 2 : std::string ReheatingCoilName; // Used in mining function CALLS
729 2 : std::string SuppHeatCoilType; // Used in mining function CALLS
730 2 : std::string SuppHeatCoilName; // Used in mining function CALLS
731 2 : std::string FanName; // Used in mining function CALLS
732 : bool PrintMessage; // Used in mining function CALLS
733 : int HeatingCoilPLFCurveIndex; // index of heating coil PLF curve
734 : Real64 SteamDensity; // density of steam at 100C
735 : int DXCoilIndex; // Index to DX coil in HXAssited object
736 2 : std::string IHPCoilName; // IHP cooling coil name
737 2 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
738 : DataLoopNode::ConnectionObjectType currentModuleObjectType;
739 :
740 2 : state.dataFurnaces->GetFurnaceInputFlag = false;
741 2 : int MaxNumbers = 0;
742 2 : int MaxAlphas = 0;
743 :
744 2 : std::string_view CurrentModuleObject = "AirLoopHVAC:Unitary:Furnace:HeatOnly";
745 2 : int NumHeatOnly = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
746 2 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, NumFields, NumAlphas, NumNumbers);
747 2 : MaxNumbers = max(MaxNumbers, NumNumbers);
748 2 : MaxAlphas = max(MaxAlphas, NumAlphas);
749 :
750 2 : CurrentModuleObject = "AirLoopHVAC:Unitary:Furnace:HeatCool";
751 2 : int NumHeatCool = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
752 2 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, NumFields, NumAlphas, NumNumbers);
753 2 : MaxNumbers = max(MaxNumbers, NumNumbers);
754 2 : MaxAlphas = max(MaxAlphas, NumAlphas);
755 :
756 2 : CurrentModuleObject = "AirLoopHVAC:UnitaryHeatOnly";
757 2 : int NumUnitaryHeatOnly = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
758 2 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, NumFields, NumAlphas, NumNumbers);
759 2 : MaxNumbers = max(MaxNumbers, NumNumbers);
760 2 : MaxAlphas = max(MaxAlphas, NumAlphas);
761 :
762 2 : CurrentModuleObject = "AirLoopHVAC:UnitaryHeatCool";
763 2 : int NumUnitaryHeatCool = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
764 2 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, NumFields, NumAlphas, NumNumbers);
765 2 : MaxNumbers = max(MaxNumbers, NumNumbers);
766 2 : MaxAlphas = max(MaxAlphas, NumAlphas);
767 :
768 2 : CurrentModuleObject = "AirLoopHVAC:UnitaryHeatPump:AirToAir";
769 2 : int NumHeatPump = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
770 2 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, NumFields, NumAlphas, NumNumbers);
771 2 : MaxNumbers = max(MaxNumbers, NumNumbers);
772 2 : MaxAlphas = max(MaxAlphas, NumAlphas);
773 :
774 2 : CurrentModuleObject = "AirLoopHVAC:UnitaryHeatPump:WaterToAir";
775 2 : int NumWaterToAirHeatPump = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
776 2 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, NumFields, NumAlphas, NumNumbers);
777 2 : MaxNumbers = max(MaxNumbers, NumNumbers);
778 2 : MaxAlphas = max(MaxAlphas, NumAlphas);
779 :
780 2 : Alphas.allocate(MaxAlphas);
781 2 : Numbers.dimension(MaxNumbers, 0.0);
782 2 : cAlphaFields.allocate(MaxAlphas);
783 2 : cNumericFields.allocate(MaxNumbers);
784 2 : lAlphaBlanks.dimension(MaxAlphas, true);
785 2 : lNumericBlanks.dimension(MaxNumbers, true);
786 :
787 2 : state.dataFurnaces->NumFurnaces = NumHeatOnly + NumHeatCool + NumUnitaryHeatOnly + NumUnitaryHeatCool + NumHeatPump + NumWaterToAirHeatPump;
788 :
789 2 : if (state.dataFurnaces->NumFurnaces > 0) {
790 2 : state.dataFurnaces->Furnace.allocate(state.dataFurnaces->NumFurnaces);
791 2 : state.dataFurnaces->UniqueFurnaceNames.reserve(state.dataFurnaces->NumFurnaces);
792 : }
793 2 : state.dataFurnaces->CheckEquipName.dimension(state.dataFurnaces->NumFurnaces, true);
794 :
795 2 : int IHPCoilIndex = 0;
796 :
797 : // Get the data for the HeatOnly Furnace
798 2 : for (int HeatOnlyNum = 1; HeatOnlyNum <= NumHeatOnly + NumUnitaryHeatOnly; ++HeatOnlyNum) {
799 :
800 0 : FanInletNode = 0;
801 0 : FanOutletNode = 0;
802 0 : HeatingCoilInletNode = 0;
803 0 : HeatingCoilOutletNode = 0;
804 0 : CoolingCoilType = ' ';
805 0 : CoolingCoilName = ' ';
806 0 : HeatingCoilType = ' ';
807 0 : HeatingCoilName = ' ';
808 :
809 0 : FurnaceNum = HeatOnlyNum;
810 0 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
811 :
812 : // Furnace and UnitarySystem objects are both read in here.
813 : // Will still have 2 differently named objects for the user, but read in with 1 DO loop.
814 0 : if (HeatOnlyNum <= NumHeatOnly) {
815 0 : CurrentModuleObject = "AirLoopHVAC:Unitary:Furnace:HeatOnly";
816 0 : currentModuleObjectType = DataLoopNode::ConnectionObjectType::AirLoopHVACUnitaryFurnaceHeatOnly;
817 0 : thisFurnace.type = HVAC::UnitarySysType::Furnace_HeatOnly;
818 0 : GetObjectNum = HeatOnlyNum;
819 : } else {
820 0 : CurrentModuleObject = "AirLoopHVAC:UnitaryHeatOnly";
821 0 : currentModuleObjectType = DataLoopNode::ConnectionObjectType::AirLoopHVACUnitaryHeatOnly;
822 0 : thisFurnace.type = HVAC::UnitarySysType::Unitary_HeatOnly;
823 0 : GetObjectNum = HeatOnlyNum - NumHeatOnly;
824 : }
825 :
826 0 : thisFurnace.iterationMode.allocate(3);
827 :
828 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
829 : CurrentModuleObject,
830 : GetObjectNum,
831 : Alphas,
832 : NumAlphas,
833 : Numbers,
834 : NumNumbers,
835 : IOStatus,
836 : lNumericBlanks,
837 : lAlphaBlanks,
838 : cAlphaFields,
839 : cNumericFields);
840 :
841 0 : GlobalNames::VerifyUniqueInterObjectName(
842 0 : state, state.dataFurnaces->UniqueFurnaceNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
843 :
844 0 : thisFurnace.Name = Alphas(1);
845 0 : ErrorObjectHeader eoh{routineName, cAlphaFields(1), thisFurnace.Name};
846 :
847 0 : if (lAlphaBlanks(2)) {
848 0 : thisFurnace.availSched = Sched::GetScheduleAlwaysOn(state);
849 0 : } else if ((thisFurnace.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
850 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
851 0 : ErrorsFound = true;
852 : }
853 :
854 0 : thisFurnace.FurnaceInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
855 0 : Alphas(3),
856 : ErrorsFound,
857 : currentModuleObjectType,
858 0 : Alphas(1),
859 : DataLoopNode::NodeFluidType::Air,
860 : DataLoopNode::ConnectionType::Inlet,
861 : NodeInputManager::CompFluidStream::Primary,
862 : DataLoopNode::ObjectIsParent);
863 0 : thisFurnace.FurnaceOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
864 0 : Alphas(4),
865 : ErrorsFound,
866 : currentModuleObjectType,
867 0 : Alphas(1),
868 : DataLoopNode::NodeFluidType::Air,
869 : DataLoopNode::ConnectionType::Outlet,
870 : NodeInputManager::CompFluidStream::Primary,
871 : DataLoopNode::ObjectIsParent);
872 :
873 0 : BranchNodeConnections::TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(3), Alphas(4), "Air Nodes");
874 :
875 0 : if (lAlphaBlanks(5)) {
876 0 : thisFurnace.fanOp = HVAC::FanOp::Cycling;
877 0 : } else if ((thisFurnace.fanOpModeSched = Sched::GetSchedule(state, Alphas(5))) == nullptr) {
878 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(5), Alphas(5));
879 0 : ErrorsFound = true;
880 : }
881 :
882 : // Get the Controlling Zone or Location of the Furnace Thermostat
883 :
884 0 : thisFurnace.ControlZoneNum = Util::FindItemInList(Alphas(6), state.dataHeatBal->Zone);
885 0 : if (thisFurnace.ControlZoneNum == 0) {
886 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
887 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(6), Alphas(6)));
888 0 : ErrorsFound = true;
889 : }
890 :
891 : // Get the node number for the zone with the thermostat
892 0 : if (thisFurnace.ControlZoneNum > 0) {
893 0 : AirNodeFound = false;
894 0 : AirLoopFound = false;
895 0 : int ControlledZoneNum = thisFurnace.ControlZoneNum;
896 : // Find the controlled zone number for the specified thermostat location
897 0 : thisFurnace.NodeNumOfControlledZone = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneNode;
898 : // Determine if furnace is on air loop served by the thermostat location specified
899 0 : for (int zoneInNode = 1; zoneInNode <= state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumInletNodes; ++zoneInNode) {
900 0 : int AirLoopNumber = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNodeAirLoopNum(zoneInNode);
901 0 : if (AirLoopNumber > 0) {
902 0 : for (int BranchNum = 1; BranchNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).NumBranches; ++BranchNum) {
903 0 : for (int CompNum = 1;
904 0 : CompNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).TotalComponents;
905 : ++CompNum) {
906 0 : if (!Util::SameString(state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).Name,
907 0 : thisFurnace.Name) ||
908 0 : !Util::SameString(
909 0 : state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).TypeOf,
910 : CurrentModuleObject))
911 0 : continue;
912 0 : AirLoopFound = true;
913 0 : thisFurnace.ZoneInletNode = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNode(zoneInNode);
914 0 : break;
915 : }
916 0 : if (AirLoopFound) break;
917 : }
918 0 : for (TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumTempControlledZones; ++TstatZoneNum) {
919 0 : if (state.dataZoneCtrls->TempControlledZone(TstatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) continue;
920 0 : AirNodeFound = true;
921 : }
922 0 : for (TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumComfortControlledZones; ++TstatZoneNum) {
923 0 : if (state.dataZoneCtrls->ComfortControlledZone(TstatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) continue;
924 0 : AirNodeFound = true;
925 : }
926 : }
927 0 : if (AirLoopFound) break;
928 : }
929 0 : if (!AirNodeFound) {
930 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
931 0 : ShowContinueError(state, "Did not find Air Node (Zone with Thermostat).");
932 0 : ShowContinueError(state, format("Specified {} = {}", cAlphaFields(6), Alphas(6)));
933 0 : ShowContinueError(
934 : state, "Both a ZoneHVAC:EquipmentConnections object and a ZoneControl:Thermostat object must be specified for this zone.");
935 0 : ErrorsFound = true;
936 : }
937 0 : if (!AirLoopFound) {
938 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
939 0 : ShowContinueError(state, "Did not find correct Primary Air Loop.");
940 0 : ShowContinueError(state, format("Specified {} = {} is not served by this AirLoopHVAC equipment.", cAlphaFields(6), Alphas(6)));
941 0 : ErrorsFound = true;
942 : }
943 : }
944 :
945 : // Get fan data
946 0 : FanName = Alphas(8);
947 0 : errFlag = false;
948 :
949 0 : thisFurnace.fanType = static_cast<HVAC::FanType>(getEnumValue(HVAC::fanTypeNamesUC, Alphas(7)));
950 0 : if (thisFurnace.fanType != HVAC::FanType::OnOff && thisFurnace.fanType != HVAC::FanType::Constant) {
951 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
952 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(7), Alphas(7)));
953 0 : ErrorsFound = true;
954 :
955 0 : } else if ((thisFurnace.FanIndex = Fans::GetFanIndex(state, FanName)) == 0) {
956 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(8), FanName);
957 0 : ErrorsFound = true;
958 :
959 : } else {
960 0 : auto *fan = state.dataFans->fans(thisFurnace.FanIndex);
961 0 : thisFurnace.ActualFanVolFlowRate = fan->maxAirFlowRate;
962 0 : FanInletNode = fan->inletNodeNum;
963 0 : FanOutletNode = fan->outletNodeNum;
964 0 : thisFurnace.fanAvailSched = fan->availSched;
965 :
966 : // Check fan's schedule for cycling fan operation if constant volume fan is used
967 0 : if (thisFurnace.fanOpModeSched != nullptr && thisFurnace.fanType == HVAC::FanType::Constant) {
968 0 : if (!thisFurnace.fanOpModeSched->checkMinMaxVals(state, Clusive::Ex, 0.0, Clusive::In, 1.0)) {
969 0 : Sched::ShowSevereBadMinMax(
970 : state,
971 : eoh,
972 0 : cAlphaFields(5),
973 0 : Alphas(5),
974 : Clusive::Ex,
975 : 0.0,
976 : Clusive::In,
977 : 1.0,
978 0 : format("For {} = {}, Fan operating mode must be continuous (schedule values > 0)", cAlphaFields(7), Alphas(7)));
979 0 : ErrorsFound = true;
980 : }
981 0 : } else if (lAlphaBlanks(5) && thisFurnace.fanType != HVAC::FanType::OnOff) {
982 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisFurnace.Name));
983 0 : ShowContinueError(state, format("{} = {}", cAlphaFields(7), Alphas(7)));
984 0 : ShowContinueError(state, format("Fan type must be Fan:OnOff when {} = Blank.", cAlphaFields(5)));
985 0 : ErrorsFound = true;
986 : }
987 : }
988 :
989 0 : thisFurnace.fanPlace = static_cast<HVAC::FanPlace>(getEnumValue(HVAC::fanPlaceNamesUC, Alphas(9)));
990 0 : assert(thisFurnace.fanPlace != HVAC::FanPlace::Invalid);
991 :
992 : // Get coil data
993 0 : HeatingCoilType = Alphas(10);
994 0 : HeatingCoilName = Alphas(11);
995 0 : thisFurnace.HeatingCoilType = HeatingCoilType;
996 0 : thisFurnace.HeatingCoilName = HeatingCoilName;
997 0 : if (Util::SameString(HeatingCoilType, "Coil:Heating:Fuel") || Util::SameString(HeatingCoilType, "Coil:Heating:Electric")) {
998 0 : errFlag = false;
999 0 : thisFurnace.HeatingCoilType_Num = HeatingCoils::GetHeatingCoilTypeNum(state, HeatingCoilType, HeatingCoilName, errFlag);
1000 0 : if (errFlag) {
1001 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1002 0 : ErrorsFound = true;
1003 : } else {
1004 0 : ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject);
1005 0 : if (IsNotOK) {
1006 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1007 0 : ErrorsFound = true;
1008 :
1009 : } else { // mine data from heating coil object
1010 :
1011 : // Get index to Heating Coil
1012 0 : errFlag = false;
1013 0 : HeatingCoils::GetCoilIndex(state, HeatingCoilName, thisFurnace.HeatingCoilIndex, errFlag);
1014 0 : if (errFlag) {
1015 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1016 0 : ErrorsFound = true;
1017 : }
1018 :
1019 : // Get the furnace design capacity
1020 0 : errFlag = false;
1021 0 : thisFurnace.DesignHeatingCapacity = HeatingCoils::GetCoilCapacity(state, HeatingCoilType, HeatingCoilName, errFlag);
1022 0 : if (errFlag) {
1023 0 : ShowContinueError(state, format("...occurs in {} ={}", CurrentModuleObject, Alphas(1)));
1024 0 : ErrorsFound = true;
1025 : }
1026 :
1027 : // Get the Heating Coil Inlet Node
1028 0 : errFlag = false;
1029 0 : HeatingCoilInletNode = HeatingCoils::GetCoilInletNode(state, HeatingCoilType, HeatingCoilName, errFlag);
1030 0 : thisFurnace.HWCoilAirInletNode = HeatingCoilInletNode;
1031 0 : if (errFlag) {
1032 0 : ShowContinueError(state, format("...occurs in {} ={}", CurrentModuleObject, Alphas(1)));
1033 0 : ErrorsFound = true;
1034 : }
1035 :
1036 : // Get the Heating Coil Outlet Node
1037 0 : errFlag = false;
1038 0 : HeatingCoilOutletNode = HeatingCoils::GetCoilOutletNode(state, HeatingCoilType, HeatingCoilName, errFlag);
1039 0 : if (errFlag) {
1040 0 : ShowContinueError(state, format("...occurs in {} ={}", CurrentModuleObject, Alphas(1)));
1041 0 : ErrorsFound = true;
1042 : }
1043 :
1044 : } // IF (IsNotOK) THEN
1045 : }
1046 :
1047 0 : } else if (Util::SameString(HeatingCoilType, "Coil:Heating:Water")) {
1048 0 : thisFurnace.HeatingCoilType_Num = HVAC::Coil_HeatingWater;
1049 0 : ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject);
1050 0 : if (IsNotOK) {
1051 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1052 0 : ErrorsFound = true;
1053 : } else { // mine data from heating coil object
1054 :
1055 : // Get the Heating Coil water Inlet or control Node number
1056 0 : errFlag = false;
1057 0 : thisFurnace.CoilControlNode = WaterCoils::GetCoilWaterInletNode(state, "Coil:Heating:Water", HeatingCoilName, errFlag);
1058 0 : if (errFlag) {
1059 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1060 0 : ErrorsFound = true;
1061 : }
1062 :
1063 : // Get the Heating Coil hot water max volume flow rate
1064 0 : errFlag = false;
1065 0 : thisFurnace.MaxHeatCoilFluidFlow = WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", HeatingCoilName, errFlag);
1066 0 : if (errFlag) {
1067 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1068 0 : ErrorsFound = true;
1069 : }
1070 :
1071 : // Get the Heating Coil Inlet Node
1072 0 : errFlag = false;
1073 0 : HeatingCoilInletNode = WaterCoils::GetCoilInletNode(state, "Coil:Heating:Water", HeatingCoilName, errFlag);
1074 0 : thisFurnace.HWCoilAirInletNode = HeatingCoilInletNode;
1075 0 : if (errFlag) {
1076 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1077 0 : ErrorsFound = true;
1078 : }
1079 :
1080 : // Get the Heating Coil Outlet Node
1081 0 : errFlag = false;
1082 0 : HeatingCoilOutletNode = WaterCoils::GetCoilOutletNode(state, "Coil:Heating:Water", HeatingCoilName, errFlag);
1083 0 : thisFurnace.HWCoilAirOutletNode = HeatingCoilOutletNode;
1084 0 : if (errFlag) {
1085 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1086 0 : ErrorsFound = true;
1087 : }
1088 :
1089 : // check if user has also used a water coil controller, which they should not do
1090 0 : errFlag = false;
1091 0 : HVACControllers::CheckCoilWaterInletNode(state, thisFurnace.CoilControlNode, errFlag);
1092 0 : if (!errFlag) { // then did find a controller so that is bad
1093 0 : ShowSevereError(state,
1094 0 : format("{} = {} has a conflicting Controller:WaterCoil object", CurrentModuleObject, thisFurnace.Name));
1095 0 : ShowContinueError(state, "Hot water coils are controlled directly by unitary and furnace systems.");
1096 0 : ShowContinueError(state, "No water coil controller should be input for the coil.");
1097 0 : ErrorsFound = true;
1098 : }
1099 : }
1100 :
1101 0 : } else if (Util::SameString(HeatingCoilType, "Coil:Heating:Steam")) {
1102 0 : thisFurnace.HeatingCoilType_Num = HVAC::Coil_HeatingSteam;
1103 0 : ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject);
1104 0 : if (IsNotOK) {
1105 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1106 0 : ErrorsFound = true;
1107 : } else { // mine data from heating coil object
1108 :
1109 0 : errFlag = false;
1110 0 : thisFurnace.HeatingCoilIndex = SteamCoils::GetSteamCoilIndex(state, "COIL:HEATING:STEAM", HeatingCoilName, errFlag);
1111 0 : if (thisFurnace.HeatingCoilIndex == 0) {
1112 0 : ShowSevereError(state, format("{} illegal {} = {}", CurrentModuleObject, cAlphaFields(11), HeatingCoilName));
1113 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1114 0 : ErrorsFound = true;
1115 : }
1116 :
1117 : // Get the Heating Coil steam inlet node number
1118 0 : errFlag = false;
1119 0 : thisFurnace.CoilControlNode = SteamCoils::GetCoilSteamInletNode(state, "COIL:HEATING:STEAM", HeatingCoilName, errFlag);
1120 0 : if (errFlag) {
1121 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1122 0 : ErrorsFound = true;
1123 : }
1124 :
1125 : // Get the Heating Coil steam max volume flow rate
1126 0 : thisFurnace.MaxHeatCoilFluidFlow = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.HeatingCoilIndex, errFlag);
1127 0 : if (thisFurnace.MaxHeatCoilFluidFlow > 0.0) {
1128 0 : SteamDensity = Fluid::GetSteam(state)->getSatDensity(state, state.dataFurnaces->TempSteamIn, 1.0, getUnitaryHeatOnly);
1129 0 : thisFurnace.MaxHeatCoilFluidFlow *= SteamDensity;
1130 : }
1131 :
1132 : // Get the Heating Coil Inlet Node
1133 0 : errFlag = false;
1134 0 : HeatingCoilInletNode = SteamCoils::GetCoilAirInletNode(state, thisFurnace.HeatingCoilIndex, HeatingCoilName, errFlag);
1135 0 : thisFurnace.HWCoilAirInletNode = HeatingCoilInletNode;
1136 0 : if (errFlag) {
1137 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1138 0 : ErrorsFound = true;
1139 : }
1140 :
1141 : // Get the Heating Coil Outlet Node
1142 0 : errFlag = false;
1143 0 : HeatingCoilOutletNode = SteamCoils::GetCoilAirOutletNode(state, thisFurnace.HeatingCoilIndex, HeatingCoilName, errFlag);
1144 0 : thisFurnace.HWCoilAirOutletNode = HeatingCoilOutletNode;
1145 0 : if (errFlag) {
1146 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1147 0 : ErrorsFound = true;
1148 : }
1149 : }
1150 :
1151 : } else {
1152 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1153 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(11), Alphas(11)));
1154 0 : ErrorsFound = true;
1155 : } // IF (Furnace(FurnaceNum)%HeatingCoilType_Num == Coil_HeatingGasOrOtherFuel .OR. &, etc.
1156 :
1157 : // Add component sets array
1158 0 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
1159 0 : CompSetFanInlet = Alphas(3);
1160 0 : CompSetFanOutlet = state.dataLoopNodes->NodeID(FanOutletNode);
1161 0 : CompSetHeatInlet = state.dataLoopNodes->NodeID(FanOutletNode);
1162 0 : CompSetHeatOutlet = Alphas(4);
1163 : // Fan inlet node name must not be the same as the furnace inlet node name
1164 0 : if (FanInletNode != thisFurnace.FurnaceInletNodeNum) {
1165 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1166 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatOnly) {
1167 0 : ShowContinueError(
1168 : state, "When a blow through fan is specified, the fan inlet node name must be the same as the furnace inlet node name.");
1169 0 : ShowContinueError(state, format("...Fan inlet node name = {}", state.dataLoopNodes->NodeID(FanInletNode)));
1170 0 : ShowContinueError(state,
1171 0 : format("...Furnace inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
1172 : } else {
1173 0 : ShowContinueError(
1174 : state,
1175 : "When a blow through fan is specified, the fan inlet node name must be the same as the unitary system inlet node name.");
1176 0 : ShowContinueError(state, format("...Fan inlet node name = {}", state.dataLoopNodes->NodeID(FanInletNode)));
1177 0 : ShowContinueError(
1178 0 : state, format("...Unitary System inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
1179 : }
1180 0 : ErrorsFound = true;
1181 : }
1182 : // Fan outlet node name must be the same as the heating coil inlet node name
1183 0 : if (FanOutletNode != HeatingCoilInletNode) {
1184 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1185 0 : ShowContinueError(
1186 : state,
1187 : "When a blow through fan is specified, the fan outlet node name must be the same as the heating coil inlet node name.");
1188 0 : ShowContinueError(state, format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
1189 0 : ShowContinueError(state, format("...Heating coil inlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
1190 0 : ErrorsFound = true;
1191 : }
1192 : // Heating coil outlet node name must be the same as the furnace outlet node name
1193 0 : if (HeatingCoilOutletNode != thisFurnace.FurnaceOutletNodeNum) {
1194 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1195 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatOnly) {
1196 0 : ShowContinueError(state,
1197 : "When a blow through fan is specified, the heating coil outlet node name must be the same as the furnace "
1198 : "outlet node name.");
1199 0 : ShowContinueError(state, format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
1200 0 : ShowContinueError(
1201 0 : state, format("...Furnace outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
1202 : } else {
1203 0 : ShowContinueError(state,
1204 : "When a blow through fan is specified, the heating coil outlet node name must be the same as the unitary "
1205 : "system outlet node name.");
1206 0 : ShowContinueError(state,
1207 0 : format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
1208 0 : ShowContinueError(
1209 0 : state, format("...UnitarySystem outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
1210 : }
1211 0 : ErrorsFound = true;
1212 : }
1213 : } else { // draw through fan
1214 0 : CompSetHeatInlet = Alphas(3);
1215 0 : CompSetHeatOutlet = state.dataLoopNodes->NodeID(FanInletNode);
1216 0 : CompSetFanInlet = state.dataLoopNodes->NodeID(FanInletNode);
1217 0 : CompSetFanOutlet = Alphas(4);
1218 : // Heating coil inlet node name must not be the same as the furnace inlet node name
1219 0 : if (HeatingCoilInletNode != thisFurnace.FurnaceInletNodeNum) {
1220 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1221 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatOnly) {
1222 0 : ShowContinueError(state,
1223 : "When a draw through fan is specified, the heating coil inlet node name must be the same as the furnace "
1224 : "inlet node name.");
1225 0 : ShowContinueError(state, format("...Heating coil inlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
1226 0 : ShowContinueError(
1227 0 : state, format("...Furnace inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
1228 : } else {
1229 0 : ShowContinueError(state,
1230 : "When a draw through fan is specified, the heating coil inlet node name must be the same as the unitary "
1231 : "system inlet node name.");
1232 0 : ShowContinueError(state, format("...Heating coil inlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
1233 0 : ShowContinueError(
1234 0 : state, format("...UnitarySystem inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
1235 : }
1236 0 : ErrorsFound = true;
1237 : }
1238 : // Heating coil outlet node name must be the same as the fan inlet node name
1239 0 : if (HeatingCoilOutletNode != FanInletNode) {
1240 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1241 0 : ShowContinueError(
1242 : state,
1243 : "When a draw through fan is specified, the heating coil outlet node name must be the same as the fan inlet node name.");
1244 0 : ShowContinueError(state, format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
1245 0 : ShowContinueError(state, format("...Fan inlet node name = {}", state.dataLoopNodes->NodeID(FanInletNode)));
1246 0 : ErrorsFound = true;
1247 : }
1248 : // Fan coil outlet node name must be the same as the furnace outlet node name
1249 0 : if (FanOutletNode != thisFurnace.FurnaceOutletNodeNum) {
1250 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1251 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatOnly) {
1252 0 : ShowContinueError(
1253 : state,
1254 : "When a draw through fan is specified, the fan outlet node name must be the same as the furnace outlet node name.");
1255 0 : ShowContinueError(state, format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
1256 0 : ShowContinueError(state,
1257 0 : format("...Furnace outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
1258 : } else {
1259 0 : ShowContinueError(state,
1260 : "When a draw through fan is specified, the fan outlet node name must be the same as the unitary system "
1261 : "outlet node name.");
1262 0 : ShowContinueError(state, format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
1263 0 : ShowContinueError(
1264 0 : state, format("...UnitarySystem outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
1265 : }
1266 0 : ErrorsFound = true;
1267 : }
1268 : }
1269 :
1270 : // Add fan to component sets array
1271 0 : BranchNodeConnections::SetUpCompSets(
1272 0 : state, CurrentModuleObject, thisFurnace.Name, Alphas(7), Alphas(8), CompSetFanInlet, CompSetFanOutlet);
1273 : // Add heating coil to component sets array
1274 0 : BranchNodeConnections::SetUpCompSets(
1275 0 : state, CurrentModuleObject, thisFurnace.Name, Alphas(10), Alphas(11), CompSetHeatInlet, CompSetHeatOutlet);
1276 :
1277 : // Set the furnace max outlet temperature
1278 0 : thisFurnace.DesignMaxOutletTemp = Numbers(1);
1279 :
1280 : // Set the furnace design fan volumetric flow rate
1281 0 : thisFurnace.DesignFanVolFlowRate = Numbers(2);
1282 :
1283 : // Compare the flow rates.
1284 0 : if (thisFurnace.ActualFanVolFlowRate != DataSizing::AutoSize && thisFurnace.DesignFanVolFlowRate != DataSizing::AutoSize) {
1285 0 : if (thisFurnace.DesignFanVolFlowRate > thisFurnace.ActualFanVolFlowRate) {
1286 0 : ShowWarningError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1287 0 : ShowContinueError(
1288 0 : state, format("... The {} > Max Volume Flow Rate defined in the associated fan object, should be <=.", cNumericFields(2)));
1289 0 : ShowContinueError(state,
1290 0 : format("... Entered value = {:.4R}... Fan [{} = {}] Max Value = {:.4R}",
1291 0 : thisFurnace.DesignFanVolFlowRate,
1292 0 : HVAC::fanTypeNames[(int)thisFurnace.fanType],
1293 : FanName,
1294 0 : thisFurnace.ActualFanVolFlowRate));
1295 0 : ShowContinueError(state, " The HVAC system flow rate is reset to the fan flow rate and the simulation continues.");
1296 0 : thisFurnace.DesignFanVolFlowRate = thisFurnace.ActualFanVolFlowRate;
1297 : }
1298 : }
1299 0 : if (thisFurnace.DesignFanVolFlowRate != DataSizing::AutoSize) {
1300 0 : if (thisFurnace.DesignFanVolFlowRate <= 0.0) {
1301 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1302 0 : ShowContinueError(state, format("... The {} <= 0.0, it must be > 0.0.", cNumericFields(2)));
1303 0 : ShowContinueError(state, format("... Entered value = {:.2R}", thisFurnace.DesignFanVolFlowRate));
1304 0 : ErrorsFound = true;
1305 : }
1306 : }
1307 :
1308 : // HeatOnly furnace has only 1 flow rate, initialize other variables used in this module
1309 0 : thisFurnace.MaxHeatAirVolFlow = thisFurnace.DesignFanVolFlowRate;
1310 0 : thisFurnace.MaxCoolAirVolFlow = thisFurnace.DesignFanVolFlowRate;
1311 0 : thisFurnace.MaxNoCoolHeatAirVolFlow = thisFurnace.DesignFanVolFlowRate;
1312 0 : thisFurnace.AirFlowControl = AirFlowControlConstFan::UseCompressorOnFlow;
1313 :
1314 : // Set heating convergence tolerance
1315 0 : thisFurnace.HeatingConvergenceTolerance = 0.001;
1316 :
1317 : // set minimum outdoor temperature for compressor operation
1318 0 : SetMinOATCompressor(state, FurnaceNum, cCurrentModuleObject, ErrorsFound);
1319 :
1320 : } // End of the HeatOnly Furnace Loop
1321 :
1322 : // Get the data for the HeatCool Furnace or UnitarySystem
1323 2 : for (int HeatCoolNum = 1; HeatCoolNum <= NumHeatCool + NumUnitaryHeatCool; ++HeatCoolNum) {
1324 :
1325 0 : FanInletNode = 0;
1326 0 : FanOutletNode = 0;
1327 0 : CoolingCoilInletNode = 0;
1328 0 : CoolingCoilOutletNode = 0;
1329 0 : HeatingCoilInletNode = 0;
1330 0 : HeatingCoilOutletNode = 0;
1331 0 : int ReheatCoilInletNode = 0;
1332 0 : int ReheatCoilOutletNode = 0;
1333 0 : CoolingCoilType = ' ';
1334 0 : CoolingCoilName = ' ';
1335 0 : HeatingCoilType = ' ';
1336 0 : HeatingCoilName = ' ';
1337 :
1338 0 : FurnaceNum = HeatCoolNum + NumHeatOnly + NumUnitaryHeatOnly;
1339 0 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
1340 :
1341 : // Furnace and UnitarySystem objects are both read in here.
1342 : // Will still have 2 differently named objects for the user, but read in with 1 DO loop.
1343 0 : if (HeatCoolNum <= NumHeatCool) {
1344 0 : CurrentModuleObject = "AirLoopHVAC:Unitary:Furnace:HeatCool";
1345 0 : currentModuleObjectType = DataLoopNode::ConnectionObjectType::AirLoopHVACUnitaryFurnaceHeatCool;
1346 0 : thisFurnace.type = HVAC::UnitarySysType::Furnace_HeatCool;
1347 0 : GetObjectNum = HeatCoolNum;
1348 : } else {
1349 0 : CurrentModuleObject = "AirLoopHVAC:UnitaryHeatCool";
1350 0 : currentModuleObjectType = DataLoopNode::ConnectionObjectType::AirLoopHVACUnitaryHeatCool;
1351 0 : thisFurnace.type = HVAC::UnitarySysType::Unitary_HeatCool;
1352 0 : GetObjectNum = HeatCoolNum - NumHeatCool;
1353 : }
1354 :
1355 0 : thisFurnace.iterationMode.allocate(3);
1356 :
1357 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1358 : CurrentModuleObject,
1359 : GetObjectNum,
1360 : Alphas,
1361 : NumAlphas,
1362 : Numbers,
1363 : NumNumbers,
1364 : IOStatus,
1365 : lNumericBlanks,
1366 : lAlphaBlanks,
1367 : cAlphaFields,
1368 : cNumericFields);
1369 :
1370 0 : GlobalNames::VerifyUniqueInterObjectName(
1371 0 : state, state.dataFurnaces->UniqueFurnaceNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
1372 :
1373 0 : thisFurnace.Name = Alphas(1);
1374 :
1375 0 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, thisFurnace.Name};
1376 :
1377 0 : if (lAlphaBlanks(2)) {
1378 0 : thisFurnace.availSched = Sched::GetScheduleAlwaysOn(state);
1379 0 : } else if ((thisFurnace.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
1380 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
1381 0 : ErrorsFound = true;
1382 : }
1383 :
1384 0 : thisFurnace.FurnaceInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
1385 0 : Alphas(3),
1386 : ErrorsFound,
1387 : currentModuleObjectType,
1388 0 : Alphas(1),
1389 : DataLoopNode::NodeFluidType::Air,
1390 : DataLoopNode::ConnectionType::Inlet,
1391 : NodeInputManager::CompFluidStream::Primary,
1392 : DataLoopNode::ObjectIsParent);
1393 0 : thisFurnace.FurnaceOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
1394 0 : Alphas(4),
1395 : ErrorsFound,
1396 : currentModuleObjectType,
1397 0 : Alphas(1),
1398 : DataLoopNode::NodeFluidType::Air,
1399 : DataLoopNode::ConnectionType::Outlet,
1400 : NodeInputManager::CompFluidStream::Primary,
1401 : DataLoopNode::ObjectIsParent);
1402 :
1403 0 : BranchNodeConnections::TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(3), Alphas(4), "Air Nodes");
1404 :
1405 0 : if (lAlphaBlanks(5)) {
1406 0 : thisFurnace.fanOp = HVAC::FanOp::Cycling;
1407 0 : } else if ((thisFurnace.fanOpModeSched = Sched::GetSchedule(state, Alphas(5))) == nullptr) {
1408 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(5), Alphas(5));
1409 0 : ErrorsFound = true;
1410 : }
1411 :
1412 : // Get the Controlling Zone or Location of the Furnace Thermostat
1413 0 : thisFurnace.ControlZoneNum = Util::FindItemInList(Alphas(6), state.dataHeatBal->Zone);
1414 0 : if (thisFurnace.ControlZoneNum == 0) {
1415 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1416 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(6), Alphas(6)));
1417 0 : ErrorsFound = true;
1418 : }
1419 :
1420 : // Get the node number for the zone with the thermostat
1421 0 : if (thisFurnace.ControlZoneNum > 0) {
1422 0 : AirNodeFound = false;
1423 0 : AirLoopFound = false;
1424 0 : int ControlledZoneNum = thisFurnace.ControlZoneNum;
1425 : // Find the controlled zone number for the specified thermostat location
1426 0 : thisFurnace.NodeNumOfControlledZone = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneNode;
1427 : // Determine if system is on air loop served by the thermostat location specified
1428 0 : for (int zoneInNode = 1; zoneInNode <= state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumInletNodes; ++zoneInNode) {
1429 0 : int AirLoopNumber = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNodeAirLoopNum(zoneInNode);
1430 0 : if (AirLoopNumber > 0) {
1431 0 : for (int BranchNum = 1; BranchNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).NumBranches; ++BranchNum) {
1432 0 : for (int CompNum = 1;
1433 0 : CompNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).TotalComponents;
1434 : ++CompNum) {
1435 0 : if (!Util::SameString(state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).Name,
1436 0 : Alphas(1)) ||
1437 0 : !Util::SameString(
1438 0 : state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).TypeOf,
1439 : CurrentModuleObject))
1440 0 : continue;
1441 0 : AirLoopFound = true;
1442 0 : thisFurnace.ZoneInletNode = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNode(zoneInNode);
1443 0 : break;
1444 : }
1445 0 : if (AirLoopFound) break;
1446 : }
1447 0 : for (TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumTempControlledZones; ++TstatZoneNum) {
1448 0 : if (state.dataZoneCtrls->TempControlledZone(TstatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) continue;
1449 0 : AirNodeFound = true;
1450 : }
1451 0 : for (TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumComfortControlledZones; ++TstatZoneNum) {
1452 0 : if (state.dataZoneCtrls->ComfortControlledZone(TstatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) continue;
1453 0 : AirNodeFound = true;
1454 : }
1455 : }
1456 0 : if (AirLoopFound) break;
1457 : }
1458 0 : if (!AirNodeFound) {
1459 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1460 0 : ShowContinueError(state, "Did not find air node (zone with thermostat).");
1461 0 : ShowContinueError(state, format("Specified {} = {}", cAlphaFields(6), Alphas(6)));
1462 0 : ShowContinueError(
1463 : state, "Both a ZoneHVAC:EquipmentConnections object and a ZoneControl:Thermostat object must be specified for this zone.");
1464 0 : ErrorsFound = true;
1465 : }
1466 0 : if (!AirLoopFound) {
1467 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1468 0 : ShowContinueError(state, "Did not find correct AirLoopHVAC.");
1469 0 : ShowContinueError(state, format("Specified {} = {}", cAlphaFields(6), Alphas(6)));
1470 0 : ErrorsFound = true;
1471 : }
1472 : }
1473 :
1474 : // Get fan data
1475 0 : FanName = Alphas(8);
1476 :
1477 0 : thisFurnace.fanType = static_cast<HVAC::FanType>(getEnumValue(HVAC::fanTypeNamesUC, Alphas(7)));
1478 :
1479 0 : if (thisFurnace.fanType != HVAC::FanType::OnOff && thisFurnace.fanType != HVAC::FanType::Constant) {
1480 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1481 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(7), Alphas(7)));
1482 0 : ErrorsFound = true;
1483 :
1484 0 : } else if ((thisFurnace.FanIndex = Fans::GetFanIndex(state, FanName)) == 0) {
1485 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(8), FanName);
1486 0 : ErrorsFound = true;
1487 :
1488 : } else {
1489 0 : auto *fan = state.dataFans->fans(thisFurnace.FanIndex);
1490 0 : thisFurnace.ActualFanVolFlowRate = fan->maxAirFlowRate;
1491 0 : FanInletNode = fan->inletNodeNum;
1492 0 : FanOutletNode = fan->outletNodeNum;
1493 0 : thisFurnace.fanAvailSched = fan->availSched;
1494 :
1495 : // Check fan's schedule for cycling fan operation if constant volume fan is used
1496 0 : if (thisFurnace.fanOpModeSched != nullptr && thisFurnace.fanType == HVAC::FanType::Constant) {
1497 0 : if (!thisFurnace.fanOpModeSched->checkMinMaxVals(state, Clusive::Ex, 0.0, Clusive::In, 1.0)) {
1498 0 : Sched::ShowSevereBadMinMax(
1499 : state,
1500 : eoh,
1501 0 : cAlphaFields(5),
1502 0 : Alphas(5),
1503 : Clusive::In,
1504 : 0.0,
1505 : Clusive::In,
1506 : 1.0,
1507 0 : format("For {} = {}, fan operating mode must be continuous (schedule values > 0)", cAlphaFields(7), Alphas(7)));
1508 0 : ErrorsFound = true;
1509 : }
1510 0 : } else if (lAlphaBlanks(5) && thisFurnace.fanType != HVAC::FanType::OnOff) {
1511 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisFurnace.Name));
1512 0 : ShowContinueError(state, format("{} = {}", cAlphaFields(7), Alphas(7)));
1513 0 : ShowContinueError(state, format("Fan type must be Fan:OnOff when {} = Blank.", cAlphaFields(5)));
1514 0 : ErrorsFound = true;
1515 : }
1516 : }
1517 :
1518 0 : thisFurnace.fanPlace = static_cast<HVAC::FanPlace>(getEnumValue(HVAC::fanPlaceNamesUC, Alphas(9)));
1519 0 : assert(thisFurnace.fanPlace != HVAC::FanPlace::Invalid);
1520 :
1521 : // Get coil data
1522 0 : HeatingCoilType = Alphas(10);
1523 0 : HeatingCoilName = Alphas(11);
1524 0 : HeatingCoilPLFCurveIndex = 0;
1525 0 : thisFurnace.HeatingCoilType = HeatingCoilType;
1526 0 : thisFurnace.HeatingCoilName = HeatingCoilName;
1527 0 : if (Util::SameString(HeatingCoilType, "Coil:Heating:Fuel") || Util::SameString(HeatingCoilType, "Coil:Heating:Electric")) {
1528 0 : errFlag = false;
1529 0 : thisFurnace.HeatingCoilType_Num = HeatingCoils::GetHeatingCoilTypeNum(state, HeatingCoilType, HeatingCoilName, errFlag);
1530 0 : if (errFlag) {
1531 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1532 0 : ErrorsFound = true;
1533 : } else {
1534 :
1535 0 : ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject);
1536 0 : if (IsNotOK) {
1537 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1538 0 : ErrorsFound = true;
1539 :
1540 : } else { // mine data from heating coil
1541 :
1542 : // Get heating coil index
1543 0 : errFlag = false;
1544 0 : HeatingCoils::GetCoilIndex(state, HeatingCoilName, thisFurnace.HeatingCoilIndex, errFlag);
1545 0 : if (errFlag) {
1546 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1547 0 : ErrorsFound = true;
1548 : }
1549 :
1550 : // Get the design heating capacity
1551 0 : errFlag = false;
1552 0 : thisFurnace.DesignHeatingCapacity = HeatingCoils::GetCoilCapacity(state, HeatingCoilType, HeatingCoilName, errFlag);
1553 0 : if (errFlag) {
1554 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1555 0 : ErrorsFound = true;
1556 : }
1557 :
1558 : // Get the Heating Coil Inlet Node
1559 0 : errFlag = false;
1560 0 : HeatingCoilInletNode = HeatingCoils::GetCoilInletNode(state, HeatingCoilType, HeatingCoilName, errFlag);
1561 0 : if (errFlag) {
1562 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1563 0 : ErrorsFound = true;
1564 : }
1565 :
1566 : // Get the Heating Coil Outlet Node
1567 0 : errFlag = false;
1568 0 : HeatingCoilOutletNode = HeatingCoils::GetCoilOutletNode(state, HeatingCoilType, HeatingCoilName, errFlag);
1569 0 : if (errFlag) {
1570 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1571 0 : ErrorsFound = true;
1572 : }
1573 :
1574 : // Get the Heating Coil PLF Curve Index
1575 0 : errFlag = false;
1576 0 : HeatingCoilPLFCurveIndex = HeatingCoils::GetHeatingCoilPLFCurveIndex(state, HeatingCoilType, HeatingCoilName, errFlag);
1577 0 : if (errFlag) {
1578 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1579 0 : ErrorsFound = true;
1580 : }
1581 :
1582 : } // IF (IsNotOK) THEN
1583 : }
1584 :
1585 0 : } else if (Util::SameString(HeatingCoilType, "Coil:Heating:Water")) {
1586 0 : thisFurnace.HeatingCoilType_Num = HVAC::Coil_HeatingWater;
1587 0 : ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject);
1588 0 : if (IsNotOK) {
1589 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1590 0 : ErrorsFound = true;
1591 : } else { // mine data from heating coil object
1592 :
1593 : // Get the Heating Coil water Inlet or control Node number
1594 0 : errFlag = false;
1595 0 : thisFurnace.CoilControlNode = WaterCoils::GetCoilWaterInletNode(state, "Coil:Heating:Water", HeatingCoilName, errFlag);
1596 0 : if (errFlag) {
1597 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1598 0 : ErrorsFound = true;
1599 : }
1600 :
1601 : // Get the Heating Coil hot water max volume flow rate
1602 0 : errFlag = false;
1603 0 : thisFurnace.MaxHeatCoilFluidFlow = WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", HeatingCoilName, errFlag);
1604 0 : if (errFlag) {
1605 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1606 0 : ErrorsFound = true;
1607 : }
1608 :
1609 : // Get the Heating Coil Inlet Node
1610 0 : errFlag = false;
1611 0 : HeatingCoilInletNode = WaterCoils::GetCoilInletNode(state, "Coil:Heating:Water", HeatingCoilName, errFlag);
1612 0 : thisFurnace.HWCoilAirInletNode = HeatingCoilInletNode;
1613 0 : if (errFlag) {
1614 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1615 0 : ErrorsFound = true;
1616 : }
1617 :
1618 : // Get the Heating Coil Outlet Node
1619 0 : errFlag = false;
1620 0 : HeatingCoilOutletNode = WaterCoils::GetCoilOutletNode(state, "Coil:Heating:Water", HeatingCoilName, errFlag);
1621 0 : thisFurnace.HWCoilAirOutletNode = HeatingCoilOutletNode;
1622 0 : if (errFlag) {
1623 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1624 0 : ErrorsFound = true;
1625 : }
1626 :
1627 : // check if user has also used a water coil controller, which they should not do
1628 0 : errFlag = false;
1629 0 : HVACControllers::CheckCoilWaterInletNode(state, thisFurnace.CoilControlNode, errFlag);
1630 0 : if (!errFlag) { // then did find a controller so that is bad
1631 0 : ShowSevereError(state,
1632 0 : format("{} = {} has a conflicting Controller:WaterCoil object", CurrentModuleObject, thisFurnace.Name));
1633 0 : ShowContinueError(state, "Hot water coils are controlled directly by unitary and furnace systems.");
1634 0 : ShowContinueError(state, "No water coil controller should be input for the coil.");
1635 0 : ErrorsFound = true;
1636 : }
1637 : }
1638 :
1639 0 : } else if (Util::SameString(HeatingCoilType, "Coil:Heating:Steam")) {
1640 0 : thisFurnace.HeatingCoilType_Num = HVAC::Coil_HeatingSteam;
1641 0 : ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject);
1642 0 : if (IsNotOK) {
1643 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1644 0 : ErrorsFound = true;
1645 : } else { // mine data from heating coil object
1646 :
1647 0 : errFlag = false;
1648 0 : thisFurnace.HeatingCoilIndex = SteamCoils::GetSteamCoilIndex(state, "COIL:HEATING:STEAM", HeatingCoilName, errFlag);
1649 0 : if (thisFurnace.HeatingCoilIndex == 0) {
1650 0 : ShowSevereError(state, format("{} illegal {} = {}", CurrentModuleObject, cAlphaFields(11), HeatingCoilName));
1651 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1652 0 : ErrorsFound = true;
1653 : }
1654 :
1655 : // Get the Heating Coil steam inlet node number
1656 0 : errFlag = false;
1657 0 : thisFurnace.CoilControlNode = SteamCoils::GetCoilSteamInletNode(state, "Coil:Heating:Steam", HeatingCoilName, errFlag);
1658 0 : if (errFlag) {
1659 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1660 0 : ErrorsFound = true;
1661 : }
1662 :
1663 : // Get the Heating Coil steam max volume flow rate
1664 0 : thisFurnace.MaxHeatCoilFluidFlow = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.HeatingCoilIndex, errFlag);
1665 0 : if (thisFurnace.MaxHeatCoilFluidFlow > 0.0) {
1666 : SteamDensity =
1667 0 : Fluid::GetSteam(state)->getSatDensity(state, state.dataFurnaces->TempSteamIn, 1.0, getAirLoopHVACHeatCoolInput);
1668 0 : thisFurnace.MaxHeatCoilFluidFlow *= SteamDensity;
1669 : }
1670 :
1671 : // Get the Heating Coil Inlet Node
1672 0 : errFlag = false;
1673 0 : HeatingCoilInletNode = SteamCoils::GetCoilAirInletNode(state, thisFurnace.HeatingCoilIndex, HeatingCoilName, errFlag);
1674 0 : thisFurnace.HWCoilAirInletNode = HeatingCoilInletNode;
1675 0 : if (errFlag) {
1676 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1677 0 : ErrorsFound = true;
1678 : }
1679 :
1680 : // Get the Heating Coil Outlet Node
1681 0 : errFlag = false;
1682 0 : HeatingCoilOutletNode = SteamCoils::GetCoilAirOutletNode(state, thisFurnace.HeatingCoilIndex, HeatingCoilName, errFlag);
1683 0 : thisFurnace.HWCoilAirOutletNode = HeatingCoilOutletNode;
1684 0 : if (errFlag) {
1685 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1686 0 : ErrorsFound = true;
1687 : }
1688 : }
1689 :
1690 : } else {
1691 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1692 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(11), Alphas(11)));
1693 0 : ErrorsFound = true;
1694 : } // IF (Furnace(FurnaceNum)%HeatingCoilType_Num == Coil_HeatingGasOrOtherFuel .OR. &, etc.
1695 :
1696 : // Get Cooling Coil Information if available
1697 0 : CoolingCoilType = Alphas(12);
1698 0 : CoolingCoilName = Alphas(13);
1699 : // Find the type of coil. Do not print message since this may not be the correct coil type.
1700 0 : errFlag = false;
1701 0 : PrintMessage = false;
1702 :
1703 0 : if (Util::SameString(CoolingCoilType, "COIL:COOLING:DX:VARIABLESPEED") ||
1704 0 : Util::SameString(CoolingCoilType, "COILSYSTEM:INTEGRATEDHEATPUMP:AIRSOURCE")) {
1705 0 : thisFurnace.CoolingCoilType_Num = HVAC::Coil_CoolingAirToAirVariableSpeed;
1706 0 : if (Util::SameString(CoolingCoilType, "COILSYSTEM:INTEGRATEDHEATPUMP:AIRSOURCE")) thisFurnace.bIsIHP = true;
1707 : } else {
1708 0 : thisFurnace.CoolingCoilType_Num = DXCoils::GetCoilTypeNum(state, CoolingCoilType, CoolingCoilName, errFlag, PrintMessage);
1709 : }
1710 :
1711 : // If coil type not found, check to see if a HX assisted cooling coil is used.
1712 0 : if (thisFurnace.CoolingCoilType_Num == 0) {
1713 0 : errFlag = false;
1714 0 : thisFurnace.CoolingCoilType_Num =
1715 0 : HVACHXAssistedCoolingCoil::GetCoilGroupTypeNum(state, CoolingCoilType, CoolingCoilName, errFlag, PrintMessage);
1716 : }
1717 :
1718 0 : if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingSingleSpeed) {
1719 0 : ValidateComponent(state, CoolingCoilType, CoolingCoilName, IsNotOK, CurrentModuleObject);
1720 0 : if (IsNotOK) {
1721 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1722 0 : ErrorsFound = true;
1723 :
1724 : } else { // mine data from DX cooling coil
1725 :
1726 : // Get DX cooling coil index
1727 0 : DXCoils::GetDXCoilIndex(state, CoolingCoilName, thisFurnace.CoolingCoilIndex, IsNotOK);
1728 0 : if (IsNotOK) {
1729 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1730 0 : ErrorsFound = true;
1731 : }
1732 :
1733 : // Get DX cooling coil capacity
1734 0 : errFlag = false;
1735 0 : thisFurnace.DesignCoolingCapacity = DXCoils::GetCoilCapacity(state, CoolingCoilType, CoolingCoilName, errFlag);
1736 0 : if (errFlag) {
1737 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1738 0 : ErrorsFound = true;
1739 : }
1740 :
1741 : // Get the Cooling Coil Nodes
1742 0 : errFlag = false;
1743 0 : CoolingCoilInletNode = DXCoils::GetCoilInletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
1744 0 : CoolingCoilOutletNode = DXCoils::GetCoilOutletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
1745 0 : if (errFlag) {
1746 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1747 0 : ErrorsFound = true;
1748 : }
1749 :
1750 : // Get outdoor condenser node from DX coil object
1751 0 : errFlag = false;
1752 0 : if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) {
1753 0 : if (thisFurnace.bIsIHP) {
1754 0 : IHPCoilIndex = IntegratedHeatPump::GetCoilIndexIHP(state, CoolingCoilType, CoolingCoilName, errFlag);
1755 0 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(IHPCoilIndex).SCCoilName;
1756 0 : thisFurnace.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, IHPCoilName, errFlag);
1757 : } else {
1758 0 : thisFurnace.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, CoolingCoilName, errFlag);
1759 : }
1760 : } else {
1761 0 : thisFurnace.CondenserNodeNum = DXCoils::GetCoilCondenserInletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
1762 : }
1763 0 : if (errFlag) {
1764 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1765 0 : ErrorsFound = true;
1766 : }
1767 :
1768 : } // IF (IsNotOK) THEN
1769 :
1770 : // Push heating coil PLF curve index to DX coil
1771 0 : if (HeatingCoilPLFCurveIndex > 0) {
1772 0 : DXCoils::SetDXCoolingCoilData(state, thisFurnace.CoolingCoilIndex, ErrorsFound, HeatingCoilPLFCurveIndex);
1773 : }
1774 :
1775 0 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) {
1776 0 : ValidateComponent(state, CoolingCoilType, CoolingCoilName, IsNotOK, CurrentModuleObject);
1777 0 : if (IsNotOK) {
1778 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1779 0 : ErrorsFound = true;
1780 :
1781 : } else { // mine data from heat exchanger assisted cooling coil
1782 :
1783 : // Get DX heat exchanger assisted cooling coil index
1784 0 : HVACHXAssistedCoolingCoil::GetHXDXCoilIndex(state, CoolingCoilName, thisFurnace.CoolingCoilIndex, IsNotOK);
1785 0 : if (IsNotOK) {
1786 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1787 0 : ErrorsFound = true;
1788 : }
1789 :
1790 : // Get DX cooling coil capacity
1791 0 : errFlag = false;
1792 0 : thisFurnace.DesignCoolingCapacity = HVACHXAssistedCoolingCoil::GetCoilCapacity(state, CoolingCoilType, CoolingCoilName, errFlag);
1793 0 : if (errFlag) {
1794 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1795 0 : ErrorsFound = true;
1796 : }
1797 :
1798 : // Get the Cooling Coil Nodes
1799 0 : errFlag = false;
1800 0 : CoolingCoilInletNode = HVACHXAssistedCoolingCoil::GetCoilInletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
1801 0 : CoolingCoilOutletNode = HVACHXAssistedCoolingCoil::GetCoilOutletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
1802 0 : if (errFlag) {
1803 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1804 0 : ErrorsFound = true;
1805 : }
1806 :
1807 : // Get outdoor condenser node from heat exchanger assisted DX coil object
1808 0 : errFlag = false;
1809 0 : std::string ChildCoolingCoilName = HVACHXAssistedCoolingCoil::GetHXDXCoilName(state, CoolingCoilType, CoolingCoilName, IsNotOK);
1810 0 : std::string ChildCoolingCoilType = HVACHXAssistedCoolingCoil::GetHXDXCoilType(state, CoolingCoilType, CoolingCoilName, IsNotOK);
1811 0 : if (IsNotOK) {
1812 0 : ShowContinueError(state, format("Occurs in {} = {}", cCurrentModuleObject, Alphas(1)));
1813 0 : ErrorsFound = true;
1814 : }
1815 :
1816 : // if (thisFurnace.CoolingCoilType_Num == CoilDX_CoolingHXAssisted) {
1817 0 : if (Util::SameString(ChildCoolingCoilType, "COIL:COOLING:DX")) {
1818 :
1819 0 : int childCCIndex = CoilCoolingDX::factory(state, ChildCoolingCoilName);
1820 0 : if (childCCIndex < 0) {
1821 0 : ShowContinueError(state, format("Occurs in {} = {}", cCurrentModuleObject, Alphas(1)));
1822 0 : errFlag = true;
1823 0 : ErrorsFound = true;
1824 : }
1825 0 : auto const &newCoil = state.dataCoilCoolingDX->coilCoolingDXs[childCCIndex];
1826 :
1827 0 : thisFurnace.CondenserNodeNum = newCoil.condInletNodeIndex;
1828 :
1829 : }
1830 : // else if (thisFurnace.CoolingCoilType_Num == Coil_CoolingAirToAirVariableSpeed) {
1831 0 : else if (Util::SameString(ChildCoolingCoilType, "Coil:Cooling:DX:VariableSpeed")) {
1832 0 : if (thisFurnace.bIsIHP) {
1833 0 : IHPCoilIndex = IntegratedHeatPump::GetCoilIndexIHP(state, CoolingCoilType, CoolingCoilName, errFlag);
1834 0 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(IHPCoilIndex).SCCoilName;
1835 0 : thisFurnace.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, IHPCoilName, errFlag);
1836 : } else {
1837 0 : thisFurnace.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, CoolingCoilName, errFlag);
1838 : }
1839 : } else {
1840 0 : thisFurnace.CondenserNodeNum = DXCoils::GetCoilCondenserInletNode(
1841 : state,
1842 : "COIL:COOLING:DX:SINGLESPEED",
1843 0 : HVACHXAssistedCoolingCoil::GetHXDXCoilName(state, CoolingCoilType, CoolingCoilName, errFlag),
1844 : errFlag);
1845 : }
1846 :
1847 0 : if (errFlag) {
1848 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1849 0 : ErrorsFound = true;
1850 : }
1851 :
1852 : // Push heating coil PLF curve index to DX coil
1853 0 : if (HeatingCoilPLFCurveIndex > 0) {
1854 : // get the actual index to the DX cooling coil object
1855 0 : DXCoilIndex = HVACHXAssistedCoolingCoil::GetActualDXCoilIndex(state, CoolingCoilType, CoolingCoilName, ErrorsFound);
1856 0 : thisFurnace.ActualDXCoilIndexForHXAssisted = DXCoilIndex;
1857 : int ActualCoolCoilType =
1858 0 : HVACHXAssistedCoolingCoil::GetCoilObjectTypeNum(state, CoolingCoilType, CoolingCoilName, errFlag, true);
1859 0 : if (ActualCoolCoilType == HVAC::CoilDX_CoolingSingleSpeed) {
1860 0 : DXCoils::SetDXCoolingCoilData(state, DXCoilIndex, ErrorsFound, HeatingCoilPLFCurveIndex);
1861 : }
1862 : // what could we do for VS coil here? odd thing here
1863 : }
1864 :
1865 0 : } // IF (IsNotOK) THEN
1866 0 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) {
1867 : // BOS ADDED, AUG/2012, VARIIABLE SPEED DX COOLING COIL
1868 : // Furnace(FurnaceNum)%DXCoolCoilType = 'COIL:COOLING:DX:VARIABLESPEED'
1869 : // Furnace(FurnaceNum)%DXCoolCoilName = CoolingCoilName
1870 0 : if (Util::SameString(CoolingCoilType, "COILSYSTEM:INTEGRATEDHEATPUMP:AIRSOURCE")) thisFurnace.bIsIHP = true;
1871 0 : ValidateComponent(state, CoolingCoilType, CoolingCoilName, IsNotOK, CurrentModuleObject);
1872 :
1873 0 : if (IsNotOK) {
1874 0 : ShowContinueError(state, format("...specified in {}=\"{}\".", CurrentModuleObject, Alphas(1)));
1875 0 : ErrorsFound = true;
1876 : } else {
1877 0 : errFlag = false;
1878 0 : if (thisFurnace.bIsIHP) {
1879 0 : thisFurnace.CoolingCoilIndex = IntegratedHeatPump::GetCoilIndexIHP(state, CoolingCoilType, CoolingCoilName, errFlag);
1880 0 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SCCoilName;
1881 : } else {
1882 0 : thisFurnace.CoolingCoilIndex =
1883 0 : VariableSpeedCoils::GetCoilIndexVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
1884 0 : IHPCoilName = CoolingCoilName;
1885 : }
1886 :
1887 0 : if (errFlag) {
1888 0 : ShowContinueError(state, format("...specified in {}=\"{}\".", CurrentModuleObject, Alphas(1)));
1889 0 : ErrorsFound = true;
1890 : }
1891 :
1892 0 : if (thisFurnace.bIsIHP) {
1893 : CoolingCoilInletNode =
1894 0 : VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, "COIL:COOLING:DX:VARIABLESPEED", IHPCoilName, errFlag);
1895 : CoolingCoilOutletNode =
1896 0 : VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, "COIL:COOLING:DX:VARIABLESPEED", IHPCoilName, errFlag);
1897 0 : thisFurnace.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, IHPCoilName, errFlag);
1898 : } else {
1899 0 : CoolingCoilInletNode = VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
1900 0 : CoolingCoilOutletNode = VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
1901 0 : thisFurnace.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, CoolingCoilName, errFlag);
1902 : }
1903 :
1904 0 : if (errFlag) {
1905 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1906 0 : ErrorsFound = true;
1907 : }
1908 : }
1909 : } else {
1910 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1911 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(12), Alphas(12)));
1912 0 : ErrorsFound = true;
1913 : }
1914 :
1915 0 : if (Util::SameString(Alphas(14), "None") || Util::SameString(Alphas(14), "Multimode") || Util::SameString(Alphas(14), "CoolReheat")) {
1916 0 : AirNodeFound = false;
1917 0 : if (Util::SameString(Alphas(14), "Multimode")) {
1918 0 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::Multimode;
1919 0 : thisFurnace.Humidistat = true;
1920 0 : if (thisFurnace.CoolingCoilType_Num != HVAC::CoilDX_CoolingHXAssisted) {
1921 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1922 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(14), Alphas(14)));
1923 0 : ShowContinueError(state, "Multimode control must be used with a Heat Exchanger Assisted Cooling Coil.");
1924 0 : if (lAlphaBlanks(15)) {
1925 0 : ShowContinueError(state,
1926 : "Dehumidification control type is assumed to be None since a reheat coil has not been specified and "
1927 : "the simulation continues.");
1928 0 : thisFurnace.Humidistat = false;
1929 0 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::None;
1930 : } else {
1931 0 : ShowContinueError(state, "Dehumidification control type is assumed to be CoolReheat and the simulation continues.");
1932 0 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::CoolReheat;
1933 : }
1934 : }
1935 : }
1936 0 : if (Util::SameString(Alphas(14), "CoolReheat")) {
1937 0 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::CoolReheat;
1938 0 : thisFurnace.Humidistat = true;
1939 0 : if (lAlphaBlanks(15)) {
1940 0 : ShowWarningError(state, format("{} \"{}\"", CurrentModuleObject, Alphas(1)));
1941 0 : ShowContinueError(state,
1942 : "Dehumidification control type is assumed to be None since a reheat coil has not been specified and the "
1943 : "simulation continues.");
1944 0 : thisFurnace.Humidistat = false;
1945 0 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::None;
1946 : }
1947 : }
1948 0 : if (Util::SameString(Alphas(14), "None")) {
1949 0 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::None;
1950 0 : thisFurnace.Humidistat = false;
1951 : }
1952 0 : if (thisFurnace.Humidistat) {
1953 0 : for (HStatZoneNum = 1; HStatZoneNum <= state.dataZoneCtrls->NumHumidityControlZones; ++HStatZoneNum) {
1954 0 : if (state.dataZoneCtrls->HumidityControlZone(HStatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) continue;
1955 0 : AirNodeFound = true;
1956 : }
1957 0 : if (!AirNodeFound) {
1958 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1959 0 : ShowContinueError(state, "Did not find Air Node (Zone with Humidistat).");
1960 0 : ShowContinueError(state, format("Specified {} = {}", cAlphaFields(6), Alphas(6)));
1961 0 : ErrorsFound = true;
1962 : }
1963 : }
1964 : } else { // invalid input
1965 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1966 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(14), Alphas(14)));
1967 0 : thisFurnace.Humidistat = false;
1968 0 : ErrorsFound = true;
1969 : }
1970 :
1971 : // Check placement of cooling coil with respect to fan placement and dehumidification control type
1972 0 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
1973 0 : if (FanOutletNode == HeatingCoilInletNode && thisFurnace.DehumidControlType_Num != DehumidificationControlMode::CoolReheat) {
1974 0 : thisFurnace.CoolingCoilUpstream = false;
1975 : }
1976 : } else {
1977 0 : if (HeatingCoilOutletNode == CoolingCoilInletNode && thisFurnace.DehumidControlType_Num != DehumidificationControlMode::CoolReheat) {
1978 0 : thisFurnace.CoolingCoilUpstream = false;
1979 : }
1980 : }
1981 :
1982 : // Get reheat coil data if humidistat is used
1983 0 : ReheatingCoilType = Alphas(15);
1984 0 : ReheatingCoilName = Alphas(16);
1985 0 : thisFurnace.SuppHeatCoilType = ReheatingCoilType;
1986 0 : thisFurnace.SuppHeatCoilName = ReheatingCoilName;
1987 0 : errFlag = false;
1988 0 : if (!lAlphaBlanks(15)) {
1989 0 : if (Util::SameString(ReheatingCoilType, "Coil:Heating:Fuel") || Util::SameString(ReheatingCoilType, "Coil:Heating:Electric") ||
1990 0 : Util::SameString(ReheatingCoilType, "Coil:Heating:Desuperheater")) {
1991 :
1992 0 : thisFurnace.SuppHeatCoilType_Num = HeatingCoils::GetHeatingCoilTypeNum(state, ReheatingCoilType, ReheatingCoilName, errFlag);
1993 0 : if (errFlag) {
1994 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1995 0 : ErrorsFound = true;
1996 : } else {
1997 :
1998 0 : ValidateComponent(state, ReheatingCoilType, ReheatingCoilName, IsNotOK, CurrentModuleObject);
1999 0 : if (IsNotOK) {
2000 0 : ShowContinueError(state, format("In {} \"{}\"", CurrentModuleObject, Alphas(1)));
2001 0 : ErrorsFound = true;
2002 :
2003 : } else { // mine data from reheat coil
2004 :
2005 : // Get the heating coil index
2006 0 : HeatingCoils::GetCoilIndex(state, ReheatingCoilName, thisFurnace.SuppHeatCoilIndex, IsNotOK);
2007 0 : if (IsNotOK) {
2008 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2009 0 : ErrorsFound = true;
2010 : }
2011 :
2012 : // Get the design supplemental heating capacity
2013 0 : errFlag = false;
2014 0 : thisFurnace.DesignSuppHeatingCapacity =
2015 0 : HeatingCoils::GetCoilCapacity(state, ReheatingCoilType, ReheatingCoilName, errFlag);
2016 0 : if (errFlag) {
2017 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2018 0 : ErrorsFound = true;
2019 : }
2020 :
2021 : // Get the Reheat Coil Inlet Node
2022 0 : errFlag = false;
2023 0 : ReheatCoilInletNode = HeatingCoils::GetCoilInletNode(state, ReheatingCoilType, ReheatingCoilName, errFlag);
2024 0 : if (errFlag) {
2025 0 : ShowContinueError(state, format("...occurs in {} \"{}\"", CurrentModuleObject, Alphas(1)));
2026 0 : ErrorsFound = true;
2027 : }
2028 :
2029 : // Get the Reheat Coil Outlet Node
2030 0 : errFlag = false;
2031 0 : ReheatCoilOutletNode = HeatingCoils::GetCoilOutletNode(state, ReheatingCoilType, ReheatingCoilName, errFlag);
2032 0 : if (errFlag) {
2033 0 : ShowContinueError(state, format("...occurs in {} \"{}\"", CurrentModuleObject, Alphas(1)));
2034 0 : ErrorsFound = true;
2035 : }
2036 :
2037 : } // IF (IsNotOK) THEN
2038 : }
2039 :
2040 0 : } else if (Util::SameString(ReheatingCoilType, "Coil:Heating:Water")) {
2041 0 : thisFurnace.SuppHeatCoilType_Num = HVAC::Coil_HeatingWater;
2042 0 : ValidateComponent(state, ReheatingCoilType, ReheatingCoilName, IsNotOK, CurrentModuleObject);
2043 0 : if (IsNotOK) {
2044 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2045 0 : ErrorsFound = true;
2046 : } else { // mine data from heating coil object
2047 :
2048 : // Get the Heating Coil water Inlet or control Node number
2049 0 : errFlag = false;
2050 0 : thisFurnace.SuppCoilControlNode = WaterCoils::GetCoilWaterInletNode(state, "Coil:Heating:Water", ReheatingCoilName, errFlag);
2051 0 : if (errFlag) {
2052 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
2053 0 : ErrorsFound = true;
2054 : }
2055 :
2056 : // Get the ReHeat Coil hot water max volume flow rate
2057 0 : errFlag = false;
2058 0 : thisFurnace.MaxSuppCoilFluidFlow =
2059 0 : WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", ReheatingCoilName, errFlag);
2060 0 : if (errFlag) {
2061 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
2062 0 : ErrorsFound = true;
2063 : }
2064 :
2065 : // Get the ReHeat Coil Inlet Node
2066 0 : errFlag = false;
2067 0 : ReheatCoilInletNode = WaterCoils::GetCoilInletNode(state, "Coil:Heating:Water", ReheatingCoilName, errFlag);
2068 0 : thisFurnace.SuppCoilAirInletNode = ReheatCoilInletNode;
2069 0 : if (errFlag) {
2070 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
2071 0 : ErrorsFound = true;
2072 : }
2073 :
2074 : // Get the ReHeat Coil Outlet Node
2075 0 : errFlag = false;
2076 0 : ReheatCoilOutletNode = WaterCoils::GetCoilOutletNode(state, "Coil:Heating:Water", ReheatingCoilName, errFlag);
2077 0 : thisFurnace.SuppCoilAirOutletNode = ReheatCoilOutletNode;
2078 0 : if (errFlag) {
2079 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
2080 0 : ErrorsFound = true;
2081 : }
2082 :
2083 : // check if user has also used a water coil controller, which they should not do
2084 0 : errFlag = false;
2085 0 : HVACControllers::CheckCoilWaterInletNode(state, thisFurnace.CoilControlNode, errFlag);
2086 0 : if (!errFlag) { // then did find a controller so that is bad
2087 0 : ShowSevereError(state,
2088 0 : format("{} = {} has a conflicting Controller:WaterCoil object", CurrentModuleObject, thisFurnace.Name));
2089 0 : ShowContinueError(state, "Hot water coils are controlled directly by unitary and furnace systems.");
2090 0 : ShowContinueError(state, "No water coil controller should be input for the coil.");
2091 0 : ErrorsFound = true;
2092 : }
2093 : }
2094 :
2095 0 : } else if (Util::SameString(ReheatingCoilType, "Coil:Heating:Steam")) {
2096 0 : thisFurnace.SuppHeatCoilType_Num = HVAC::Coil_HeatingSteam;
2097 0 : ValidateComponent(state, ReheatingCoilType, ReheatingCoilName, IsNotOK, CurrentModuleObject);
2098 0 : if (IsNotOK) {
2099 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2100 0 : ErrorsFound = true;
2101 : } else { // mine data from heating coil object
2102 :
2103 0 : errFlag = false;
2104 0 : thisFurnace.SuppHeatCoilIndex = SteamCoils::GetSteamCoilIndex(state, "COIL:HEATING:STEAM", ReheatingCoilName, errFlag);
2105 0 : if (thisFurnace.SuppHeatCoilIndex == 0) {
2106 0 : ShowSevereError(state, format("{} illegal {} = {}", CurrentModuleObject, cAlphaFields(11), ReheatingCoilName));
2107 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
2108 0 : ErrorsFound = true;
2109 : }
2110 :
2111 : // Get the Heating Coil steam inlet node number
2112 0 : errFlag = false;
2113 0 : thisFurnace.SuppCoilControlNode = SteamCoils::GetCoilSteamInletNode(state, "Coil:Heating:Steam", ReheatingCoilName, errFlag);
2114 0 : if (errFlag) {
2115 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
2116 0 : ErrorsFound = true;
2117 : }
2118 :
2119 : // Get the Heating Coil steam max volume flow rate
2120 0 : thisFurnace.MaxSuppCoilFluidFlow = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.SuppHeatCoilIndex, errFlag);
2121 0 : if (thisFurnace.MaxSuppCoilFluidFlow > 0.0) {
2122 : SteamDensity =
2123 0 : Fluid::GetSteam(state)->getSatDensity(state, state.dataFurnaces->TempSteamIn, 1.0, getAirLoopHVACHeatCoolInput);
2124 0 : thisFurnace.MaxSuppCoilFluidFlow =
2125 0 : SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.SuppHeatCoilIndex, errFlag) * SteamDensity;
2126 : }
2127 :
2128 : // Get the Heating Coil Inlet Node
2129 0 : errFlag = false;
2130 0 : ReheatCoilInletNode = SteamCoils::GetCoilAirInletNode(state, thisFurnace.SuppHeatCoilIndex, ReheatingCoilName, errFlag);
2131 0 : thisFurnace.SuppCoilAirInletNode = ReheatCoilInletNode;
2132 0 : if (errFlag) {
2133 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
2134 0 : ErrorsFound = true;
2135 : }
2136 :
2137 : // Get the Heating Coil Outlet Node
2138 0 : errFlag = false;
2139 0 : ReheatCoilOutletNode = SteamCoils::GetCoilAirOutletNode(state, thisFurnace.SuppHeatCoilIndex, ReheatingCoilName, errFlag);
2140 0 : thisFurnace.SuppCoilAirOutletNode = ReheatCoilOutletNode;
2141 0 : if (errFlag) {
2142 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
2143 0 : ErrorsFound = true;
2144 : }
2145 : }
2146 :
2147 : } else { // Illegal heating coil
2148 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2149 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(15), Alphas(15)));
2150 0 : ErrorsFound = true;
2151 : } // IF (Furnace(FurnaceNum)%SuppHeatCoilType_Num == Coil_HeatingGasOrOtherFuel .OR. &, etc.
2152 :
2153 : } // IF(.NOT. lAlphaBlanks(15))THEN
2154 :
2155 0 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
2156 :
2157 0 : if (FanInletNode != thisFurnace.FurnaceInletNodeNum) {
2158 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2159 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatCool) {
2160 0 : ShowContinueError(
2161 : state, "When a blow through fan is specified, the fan inlet node name must be the same as the furnace inlet node name.");
2162 0 : ShowContinueError(state, format("...Fan inlet node name = {}", state.dataLoopNodes->NodeID(FanInletNode)));
2163 0 : ShowContinueError(state,
2164 0 : format("...Furnace inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
2165 : } else {
2166 0 : ShowContinueError(
2167 : state,
2168 : "When a blow through fan is specified, the fan inlet node name must be the same as the unitary system inlet node name.");
2169 0 : ShowContinueError(state, format("...Fan inlet node name = {}", state.dataLoopNodes->NodeID(FanInletNode)));
2170 0 : ShowContinueError(
2171 0 : state, format("...UnitarySystem inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
2172 : }
2173 0 : ErrorsFound = true;
2174 : }
2175 0 : if (thisFurnace.CoolingCoilUpstream) {
2176 0 : if (FanOutletNode != CoolingCoilInletNode) {
2177 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2178 0 : ShowContinueError(
2179 : state,
2180 : "When a blow through fan is specified, the fan outlet node name must be the same as the cooling coil inlet node name.");
2181 0 : ShowContinueError(state, format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
2182 0 : ShowContinueError(state, format("...Cooling coil inlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilInletNode)));
2183 0 : ErrorsFound = true;
2184 : }
2185 0 : if (CoolingCoilOutletNode != HeatingCoilInletNode) {
2186 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2187 0 : ShowContinueError(state, "The cooling coil outlet node name must be the same as the heating coil inlet node name.");
2188 0 : ShowContinueError(state, format("...Cooling coil outlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilOutletNode)));
2189 0 : ShowContinueError(state, format("...Heating coil inlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
2190 0 : ErrorsFound = true;
2191 : }
2192 0 : if ((thisFurnace.Humidistat && thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat) ||
2193 : ReheatCoilInletNode > 0) {
2194 0 : if (HeatingCoilOutletNode != ReheatCoilInletNode) {
2195 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2196 0 : ShowContinueError(state,
2197 : "When a blow through fan is specified, the heating coil outlet node name must be the same as the "
2198 : "reheat coil inlet node name.");
2199 0 : ShowContinueError(state,
2200 0 : format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
2201 0 : ShowContinueError(state,
2202 0 : format("...Reheat coil inlet node name = {}", state.dataLoopNodes->NodeID(ReheatCoilInletNode)));
2203 0 : ErrorsFound = true;
2204 : }
2205 0 : if (ReheatCoilOutletNode != thisFurnace.FurnaceOutletNodeNum) {
2206 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2207 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatCool) {
2208 0 : ShowContinueError(state, "The reheat coil outlet node name must be the same as the furnace outlet node name.");
2209 0 : ShowContinueError(state,
2210 0 : format("...Reheat coil outlet node name = {}", state.dataLoopNodes->NodeID(ReheatCoilOutletNode)));
2211 0 : ShowContinueError(
2212 : state,
2213 0 : format("...Furnace outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
2214 : } else {
2215 0 : ShowContinueError(state, "The reheat coil outlet node name must be the same as the unitary system outlet node name.");
2216 0 : ShowContinueError(
2217 0 : state, format("...Reheat coil outlet node name = {}", state.dataLoopNodes->NodeID(ReheatCoilOutletNode)));
2218 0 : ShowContinueError(
2219 : state,
2220 0 : format("...UnitarySystem outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
2221 : }
2222 0 : ErrorsFound = true;
2223 : }
2224 : } else { // IF((Furnace(FurnaceNum)%Humidistat ...
2225 : // Heating coil outlet node name must be the same as the furnace outlet node name
2226 0 : if (HeatingCoilOutletNode != thisFurnace.FurnaceOutletNodeNum) {
2227 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2228 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatOnly) {
2229 0 : ShowContinueError(state,
2230 : "When a blow through fan is specified, the heating coil outlet node name must be the same as the "
2231 : "furnace outlet node name.");
2232 0 : ShowContinueError(
2233 0 : state, format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
2234 0 : ShowContinueError(
2235 : state,
2236 0 : format("...Furnace outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
2237 : } else {
2238 0 : ShowContinueError(state,
2239 : "When a blow through fan is specified, the heating coil outlet node name must be the same as the "
2240 : "unitary system outlet node name.");
2241 0 : ShowContinueError(
2242 0 : state, format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
2243 0 : ShowContinueError(
2244 : state,
2245 0 : format("...UnitarySystem outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
2246 : }
2247 0 : ErrorsFound = true;
2248 : }
2249 : }
2250 : } else { // IF(Furnace(FurnaceNum)%CoolingCoilUpstream)THEN
2251 0 : if (FanOutletNode != HeatingCoilInletNode) {
2252 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2253 0 : ShowContinueError(
2254 : state,
2255 : "When a blow through fan is specified, the fan outlet node name must be the same as the heating coil inlet node name.");
2256 0 : ShowContinueError(state, format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
2257 0 : ShowContinueError(state, format("...Heating coil inlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
2258 0 : ErrorsFound = true;
2259 : }
2260 0 : if (HeatingCoilOutletNode != CoolingCoilInletNode) {
2261 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2262 0 : ShowContinueError(state, "The heating coil outlet node name must be the same as the cooling coil inlet node name.");
2263 0 : ShowContinueError(state, format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
2264 0 : ShowContinueError(state, format("...Cooling coil inlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilInletNode)));
2265 0 : ErrorsFound = true;
2266 : }
2267 0 : if (CoolingCoilOutletNode != thisFurnace.FurnaceOutletNodeNum) {
2268 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2269 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatCool) {
2270 0 : ShowContinueError(state,
2271 : "When a blow through fan is specified, the cooling coil outlet node name must be the same as the "
2272 : "furnace outlet node name.");
2273 0 : ShowContinueError(state,
2274 0 : format("...Cooling coil outlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilOutletNode)));
2275 0 : ShowContinueError(
2276 : state,
2277 0 : format("...Furnace outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
2278 : } else {
2279 0 : ShowContinueError(state,
2280 : "When a blow through fan is specified, the cooling coil outlet node name must be the same as the "
2281 : "unitary system outlet node name.");
2282 0 : ShowContinueError(state,
2283 0 : format("...Cooling coil outlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilOutletNode)));
2284 0 : ShowContinueError(
2285 : state,
2286 0 : format("...UnitarySystem outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
2287 : }
2288 0 : ErrorsFound = true;
2289 : }
2290 : }
2291 :
2292 : } else { // ELSE from IF(Furnace(FurnaceNum)%FanPlace .EQ. BlowThru)THEN
2293 :
2294 0 : if (thisFurnace.CoolingCoilUpstream) {
2295 0 : if (CoolingCoilInletNode != thisFurnace.FurnaceInletNodeNum) {
2296 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2297 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatCool) {
2298 0 : ShowContinueError(state,
2299 : "When a draw through fan is specified, the cooling coil inlet node name must be the same as the "
2300 : "furnace inlet node name.");
2301 0 : ShowContinueError(state,
2302 0 : format("...Cooling coil inlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilInletNode)));
2303 0 : ShowContinueError(
2304 0 : state, format("...Furnace inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
2305 : } else {
2306 0 : ShowContinueError(state,
2307 : "When a draw through fan is specified, the cooling coil inlet node name must be the same as the "
2308 : "unitary system inlet node name.");
2309 0 : ShowContinueError(state,
2310 0 : format("...Cooling coil inlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilInletNode)));
2311 0 : ShowContinueError(
2312 0 : state, format("...UnitarySystem inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
2313 : }
2314 0 : ErrorsFound = true;
2315 : }
2316 0 : if (CoolingCoilOutletNode != HeatingCoilInletNode) {
2317 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2318 0 : ShowContinueError(state, "The cooling coil outlet node name must be the same as the heating coil inlet node name.");
2319 0 : ShowContinueError(state, format("...Cooling coil outlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilOutletNode)));
2320 0 : ShowContinueError(state, format("...Heating coil inlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
2321 0 : ErrorsFound = true;
2322 : }
2323 0 : if (HeatingCoilOutletNode != FanInletNode) {
2324 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2325 0 : ShowContinueError(
2326 : state,
2327 : "When a draw through fan is specified, the heating coil outlet node name must be the same as the fan inlet node name.");
2328 0 : ShowContinueError(state, format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
2329 0 : ShowContinueError(state, format("...Fan inlet node name = {}", state.dataLoopNodes->NodeID(FanInletNode)));
2330 0 : ErrorsFound = true;
2331 : }
2332 0 : if ((thisFurnace.Humidistat && thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat) ||
2333 : ReheatCoilInletNode > 0) {
2334 0 : if (FanOutletNode != ReheatCoilInletNode) {
2335 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2336 0 : ShowContinueError(state,
2337 : "When a draw through fan is specified, the fan outlet node name must be the same as the reheat coil "
2338 : "inlet node name.");
2339 0 : ShowContinueError(state, format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
2340 0 : ShowContinueError(state, format("...Reheat coil inlet node name = {}", state.dataLoopNodes->NodeID(ReheatCoilInletNode)));
2341 0 : ErrorsFound = true;
2342 : }
2343 0 : if (ReheatCoilOutletNode != thisFurnace.FurnaceOutletNodeNum) {
2344 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2345 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatCool) {
2346 0 : ShowContinueError(state, "The reheat coil outlet node name must be the same as the furnace outlet node name.");
2347 0 : ShowContinueError(state,
2348 0 : format("...Reheat coil outlet node name = {}", state.dataLoopNodes->NodeID(ReheatCoilOutletNode)));
2349 0 : ShowContinueError(
2350 : state,
2351 0 : format("...Furnace outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
2352 : } else {
2353 0 : ShowContinueError(state, "The reheat coil outlet node name must be the same as the unitary system outlet node name.");
2354 0 : ShowContinueError(
2355 0 : state, format("...Reheat coil outlet node name = {}", state.dataLoopNodes->NodeID(ReheatCoilOutletNode)));
2356 0 : ShowContinueError(
2357 : state,
2358 0 : format("...UnitarySystem outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
2359 : }
2360 0 : ErrorsFound = true;
2361 : }
2362 : } else {
2363 0 : if (FanOutletNode != thisFurnace.FurnaceOutletNodeNum) {
2364 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2365 0 : ShowContinueError(state,
2366 : "When a draw through fan is specified, the fan outlet node name must be the same as the unitary system "
2367 : "outlet node name.");
2368 0 : ShowContinueError(state, format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
2369 0 : ShowContinueError(
2370 : state,
2371 0 : format("...Unitary system outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
2372 0 : ErrorsFound = true;
2373 : }
2374 : }
2375 : } else { // IF(Furnace(FurnaceNum)%CoolingCoilUpstream)THEN
2376 0 : if (HeatingCoilInletNode != thisFurnace.FurnaceInletNodeNum) {
2377 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2378 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatCool) {
2379 0 : ShowContinueError(state,
2380 : "When a draw through fan is specified, the heating coil inlet node name must be the same as the "
2381 : "furnace inlet node name.");
2382 0 : ShowContinueError(state,
2383 0 : format("...Heating coil inlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
2384 0 : ShowContinueError(
2385 0 : state, format("...Furnace inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
2386 : } else {
2387 0 : ShowContinueError(state,
2388 : "When a draw through fan is specified, the heating coil inlet node name must be the same as the "
2389 : "unitary system inlet node name.");
2390 0 : ShowContinueError(state,
2391 0 : format("...Heating coil inlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
2392 0 : ShowContinueError(
2393 0 : state, format("...UnitarySystem inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
2394 : }
2395 0 : ErrorsFound = true;
2396 : }
2397 0 : if (HeatingCoilOutletNode != CoolingCoilInletNode) {
2398 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2399 0 : ShowContinueError(state, "The heating coil outlet node name must be the same as the cooling coil inlet node name.");
2400 0 : ShowContinueError(state, format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
2401 0 : ShowContinueError(state, format("...Cooling coil inlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilInletNode)));
2402 0 : ErrorsFound = true;
2403 : }
2404 0 : if (CoolingCoilOutletNode != FanInletNode) {
2405 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2406 0 : ShowContinueError(
2407 : state,
2408 : "When a draw through fan is specified, the cooling coil outlet node name must be the same as the fan inlet node name.");
2409 0 : ShowContinueError(state, format("...Cooling coil outlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilOutletNode)));
2410 0 : ShowContinueError(state, format("...Fan inlet node name = {}", state.dataLoopNodes->NodeID(FanInletNode)));
2411 0 : ErrorsFound = true;
2412 : }
2413 0 : if (FanOutletNode != thisFurnace.FurnaceOutletNodeNum) {
2414 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2415 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatCool) {
2416 0 : ShowContinueError(
2417 : state,
2418 : "When a draw through fan is specified, the fan outlet node name must be the same as the furnace outlet node name.");
2419 0 : ShowContinueError(state, format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
2420 0 : ShowContinueError(
2421 0 : state, format("...Furnace outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
2422 : } else {
2423 0 : ShowContinueError(state,
2424 : "When a draw through fan is specified, the fan outlet node name must be the same as the unitary system "
2425 : "outlet node name.");
2426 0 : ShowContinueError(state, format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
2427 0 : ShowContinueError(
2428 : state,
2429 0 : format("...UnitarySystem outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
2430 : }
2431 0 : ErrorsFound = true;
2432 : }
2433 : }
2434 : } // ELSE from IF(Furnace(FurnaceNum)%FanPlace .EQ. BlowThru)THEN
2435 :
2436 : // Add fan to component sets array
2437 0 : BranchNodeConnections::SetUpCompSets(state,
2438 : CurrentModuleObject,
2439 0 : Alphas(1),
2440 0 : Alphas(7),
2441 0 : Alphas(8),
2442 0 : state.dataLoopNodes->NodeID(FanInletNode),
2443 0 : state.dataLoopNodes->NodeID(FanOutletNode));
2444 :
2445 : // Add DX cooling coil to component sets array
2446 0 : if (thisFurnace.bIsIHP) {
2447 0 : BranchNodeConnections::SetUpCompSets(state,
2448 : CurrentModuleObject,
2449 0 : Alphas(1),
2450 0 : Alphas(12),
2451 0 : Alphas(13) + " Cooling Coil",
2452 0 : state.dataLoopNodes->NodeID(CoolingCoilInletNode),
2453 0 : state.dataLoopNodes->NodeID(CoolingCoilOutletNode));
2454 : } else {
2455 0 : BranchNodeConnections::SetUpCompSets(state,
2456 : CurrentModuleObject,
2457 0 : Alphas(1),
2458 0 : Alphas(12),
2459 0 : Alphas(13),
2460 0 : state.dataLoopNodes->NodeID(CoolingCoilInletNode),
2461 0 : state.dataLoopNodes->NodeID(CoolingCoilOutletNode));
2462 : }
2463 :
2464 : // Add heating coil to component sets array
2465 0 : if (thisFurnace.bIsIHP) {
2466 0 : BranchNodeConnections::SetUpCompSets(state,
2467 : CurrentModuleObject,
2468 0 : Alphas(1),
2469 0 : Alphas(10),
2470 0 : Alphas(11) + " Heating Coil",
2471 0 : state.dataLoopNodes->NodeID(HeatingCoilInletNode),
2472 0 : state.dataLoopNodes->NodeID(HeatingCoilOutletNode));
2473 : } else {
2474 0 : BranchNodeConnections::SetUpCompSets(state,
2475 : CurrentModuleObject,
2476 0 : Alphas(1),
2477 0 : Alphas(10),
2478 0 : Alphas(11),
2479 0 : state.dataLoopNodes->NodeID(HeatingCoilInletNode),
2480 0 : state.dataLoopNodes->NodeID(HeatingCoilOutletNode));
2481 : }
2482 :
2483 0 : if (ReheatCoilInletNode > 0) {
2484 :
2485 : // Add reheating coil to component sets array
2486 0 : BranchNodeConnections::SetUpCompSets(state,
2487 : CurrentModuleObject,
2488 0 : Alphas(1),
2489 0 : Alphas(15),
2490 0 : Alphas(16),
2491 0 : state.dataLoopNodes->NodeID(ReheatCoilInletNode),
2492 0 : state.dataLoopNodes->NodeID(ReheatCoilOutletNode));
2493 : }
2494 :
2495 : // Set the furnace max outlet temperature
2496 0 : thisFurnace.DesignMaxOutletTemp = Numbers(1);
2497 :
2498 0 : thisFurnace.MaxCoolAirVolFlow = Numbers(2);
2499 0 : if (thisFurnace.MaxCoolAirVolFlow <= 0 && thisFurnace.MaxCoolAirVolFlow != DataSizing::AutoSize) {
2500 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2501 0 : ShowContinueError(state, format("Illegal {} = {:.7T}", cNumericFields(2), Numbers(2)));
2502 0 : ErrorsFound = true;
2503 : }
2504 :
2505 0 : thisFurnace.MaxHeatAirVolFlow = Numbers(3);
2506 0 : if (thisFurnace.MaxHeatAirVolFlow <= 0 && thisFurnace.MaxHeatAirVolFlow != DataSizing::AutoSize) {
2507 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2508 0 : ShowContinueError(state, format("Illegal {} = {:.7T}", cNumericFields(3), Numbers(3)));
2509 0 : ErrorsFound = true;
2510 : }
2511 :
2512 0 : thisFurnace.MaxNoCoolHeatAirVolFlow = Numbers(4);
2513 0 : if (thisFurnace.MaxNoCoolHeatAirVolFlow < 0 && thisFurnace.MaxNoCoolHeatAirVolFlow != DataSizing::AutoSize) {
2514 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2515 0 : ShowContinueError(state, format("Illegal {} = {:.7T}", cNumericFields(4), Numbers(4)));
2516 0 : ErrorsFound = true;
2517 : }
2518 :
2519 0 : if (Numbers(2) != DataSizing::AutoSize && Numbers(3) != DataSizing::AutoSize && Numbers(4) != DataSizing::AutoSize) {
2520 0 : thisFurnace.DesignFanVolFlowRate = max(Numbers(2), Numbers(3), Numbers(4));
2521 : } else {
2522 0 : thisFurnace.DesignFanVolFlowRate = DataSizing::AutoSize;
2523 : }
2524 :
2525 0 : if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) {
2526 0 : errFlag = false;
2527 0 : if (thisFurnace.bIsIHP) {
2528 0 : thisFurnace.CoolingCoilIndex = IntegratedHeatPump::GetCoilIndexIHP(state, CoolingCoilType, CoolingCoilName, errFlag);
2529 0 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SCCoilName;
2530 0 : thisFurnace.MaxCoolAirVolFlow =
2531 0 : VariableSpeedCoils::GetCoilAirFlowRateVariableSpeed(state, "COIL:COOLING:DX:VARIABLESPEED", IHPCoilName, errFlag);
2532 : } else {
2533 0 : thisFurnace.MaxCoolAirVolFlow =
2534 0 : VariableSpeedCoils::GetCoilAirFlowRateVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
2535 : }
2536 :
2537 0 : if (errFlag) {
2538 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2539 0 : ErrorsFound = true;
2540 : }
2541 :
2542 0 : thisFurnace.MaxNoCoolHeatAirVolFlow = min(thisFurnace.MaxHeatAirVolFlow, thisFurnace.MaxCoolAirVolFlow);
2543 0 : if (thisFurnace.MaxHeatAirVolFlow != DataSizing::AutoSize && thisFurnace.MaxCoolAirVolFlow != DataSizing::AutoSize) {
2544 0 : thisFurnace.DesignFanVolFlowRate = max(thisFurnace.MaxHeatAirVolFlow, thisFurnace.MaxCoolAirVolFlow);
2545 : } else {
2546 0 : thisFurnace.DesignFanVolFlowRate = DataSizing::AutoSize;
2547 : }
2548 : }
2549 :
2550 0 : if (thisFurnace.ActualFanVolFlowRate != DataSizing::AutoSize) {
2551 0 : if (thisFurnace.ActualFanVolFlowRate < thisFurnace.MaxCoolAirVolFlow && thisFurnace.MaxCoolAirVolFlow != DataSizing::AutoSize) {
2552 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2553 0 : ShowContinueError(
2554 : state,
2555 0 : format("... air flow rate = {:.7T} in fan object {} is less than the maximum HVAC system air flow rate in cooling mode.",
2556 0 : thisFurnace.ActualFanVolFlowRate,
2557 : FanName));
2558 0 : ShowContinueError(state, format(" The {} is reset to the fan flow rate and the simulation continues.", cNumericFields(2)));
2559 0 : thisFurnace.MaxCoolAirVolFlow = thisFurnace.ActualFanVolFlowRate;
2560 0 : thisFurnace.DesignFanVolFlowRate = thisFurnace.ActualFanVolFlowRate;
2561 : }
2562 0 : if (thisFurnace.ActualFanVolFlowRate < thisFurnace.MaxHeatAirVolFlow && thisFurnace.MaxHeatAirVolFlow != DataSizing::AutoSize) {
2563 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2564 0 : ShowContinueError(
2565 : state,
2566 0 : format("... air flow rate = {:.7T} in fan object {} is less than the maximum HVAC system air flow rate in heating mode.",
2567 0 : thisFurnace.ActualFanVolFlowRate,
2568 : FanName));
2569 0 : ShowContinueError(state, format(" The {} is reset to the fan flow rate and the simulation continues.", cNumericFields(3)));
2570 0 : thisFurnace.MaxHeatAirVolFlow = thisFurnace.ActualFanVolFlowRate;
2571 0 : thisFurnace.DesignFanVolFlowRate = thisFurnace.ActualFanVolFlowRate;
2572 : }
2573 : }
2574 :
2575 0 : if (thisFurnace.fanOpModeSched != nullptr) {
2576 : // Is this correct? 0.0 for max also?
2577 0 : if (!thisFurnace.fanOpModeSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 0.0)) {
2578 : // set air flow control mode:
2579 : // UseCompressorOnFlow = operate at last cooling or heating air flow requested when compressor is off
2580 : // UseCompressorOffFlow = operate at value specified by user
2581 : // AirFlowControl only valid if fan opmode = ContFanCycComp
2582 0 : if (thisFurnace.MaxNoCoolHeatAirVolFlow == 0.0) {
2583 0 : thisFurnace.AirFlowControl = AirFlowControlConstFan::UseCompressorOnFlow;
2584 : } else {
2585 0 : thisFurnace.AirFlowControl = AirFlowControlConstFan::UseCompressorOffFlow;
2586 : }
2587 : }
2588 : }
2589 :
2590 0 : if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) {
2591 0 : errFlag = false;
2592 0 : if (thisFurnace.bIsIHP) {
2593 0 : thisFurnace.CoolingCoilIndex = IntegratedHeatPump::GetCoilIndexIHP(state, CoolingCoilType, CoolingCoilName, errFlag);
2594 0 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SCCoilName;
2595 0 : thisFurnace.DesignCoolingCapacity =
2596 0 : VariableSpeedCoils::GetCoilCapacityVariableSpeed(state, "COIL:COOLING:DX:VARIABLESPEED", IHPCoilName, errFlag);
2597 : } else {
2598 0 : thisFurnace.DesignCoolingCapacity =
2599 0 : VariableSpeedCoils::GetCoilCapacityVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
2600 : }
2601 :
2602 0 : if (errFlag) {
2603 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2604 0 : ErrorsFound = true;
2605 : }
2606 : }
2607 :
2608 : // Set heating convergence tolerance
2609 0 : thisFurnace.HeatingConvergenceTolerance = 0.001;
2610 :
2611 : // Set cooling convergence tolerance
2612 0 : thisFurnace.CoolingConvergenceTolerance = 0.001;
2613 :
2614 : // set minimum outdoor temperature for compressor operation
2615 0 : SetMinOATCompressor(state, FurnaceNum, cCurrentModuleObject, ErrorsFound);
2616 :
2617 : } // End of the HeatCool Furnace Loop
2618 :
2619 : // Get the data for the Unitary System HeatPump AirToAir (UnitarySystem:HeatPump:AirToAir)
2620 4 : for (int HeatPumpNum = 1; HeatPumpNum <= NumHeatPump; ++HeatPumpNum) {
2621 :
2622 2 : CurrentModuleObject = "AirLoopHVAC:UnitaryHeatPump:AirToAir";
2623 2 : FanInletNode = 0;
2624 2 : FanOutletNode = 0;
2625 2 : CoolingCoilInletNode = 0;
2626 2 : CoolingCoilOutletNode = 0;
2627 2 : HeatingCoilInletNode = 0;
2628 2 : HeatingCoilOutletNode = 0;
2629 2 : SupHeatCoilInletNode = 0;
2630 2 : SupHeatCoilOutletNode = 0;
2631 2 : CoolingCoilType = ' ';
2632 2 : CoolingCoilName = ' ';
2633 2 : HeatingCoilType = ' ';
2634 2 : HeatingCoilName = ' ';
2635 :
2636 2 : FurnaceNum = NumHeatOnly + NumHeatCool + NumUnitaryHeatOnly + NumUnitaryHeatCool + HeatPumpNum;
2637 2 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
2638 2 : thisFurnace.iterationMode.allocate(3);
2639 :
2640 2 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
2641 : CurrentModuleObject,
2642 : HeatPumpNum,
2643 : Alphas,
2644 : NumAlphas,
2645 : Numbers,
2646 : NumNumbers,
2647 : IOStatus,
2648 : lNumericBlanks,
2649 : lAlphaBlanks,
2650 : cAlphaFields,
2651 : cNumericFields);
2652 :
2653 4 : GlobalNames::VerifyUniqueInterObjectName(
2654 2 : state, state.dataFurnaces->UniqueFurnaceNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
2655 :
2656 2 : thisFurnace.type = HVAC::UnitarySysType::Unitary_HeatPump_AirToAir;
2657 2 : thisFurnace.Name = Alphas(1);
2658 :
2659 2 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, thisFurnace.Name};
2660 :
2661 2 : if (lAlphaBlanks(2)) {
2662 0 : thisFurnace.availSched = Sched::GetScheduleAlwaysOn(state);
2663 2 : } else if ((thisFurnace.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
2664 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
2665 0 : ErrorsFound = true;
2666 : }
2667 :
2668 2 : thisFurnace.FurnaceInletNodeNum =
2669 2 : NodeInputManager::GetOnlySingleNode(state,
2670 2 : Alphas(3),
2671 : ErrorsFound,
2672 : DataLoopNode::ConnectionObjectType::AirLoopHVACUnitaryHeatPumpAirToAir,
2673 2 : Alphas(1),
2674 : DataLoopNode::NodeFluidType::Air,
2675 : DataLoopNode::ConnectionType::Inlet,
2676 : NodeInputManager::CompFluidStream::Primary,
2677 : DataLoopNode::ObjectIsParent);
2678 :
2679 2 : thisFurnace.FurnaceOutletNodeNum =
2680 4 : NodeInputManager::GetOnlySingleNode(state,
2681 2 : Alphas(4),
2682 : ErrorsFound,
2683 : DataLoopNode::ConnectionObjectType::AirLoopHVACUnitaryHeatPumpAirToAir,
2684 2 : Alphas(1),
2685 : DataLoopNode::NodeFluidType::Air,
2686 : DataLoopNode::ConnectionType::Outlet,
2687 : NodeInputManager::CompFluidStream::Primary,
2688 : DataLoopNode::ObjectIsParent);
2689 :
2690 2 : BranchNodeConnections::TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(3), Alphas(4), "Air Nodes");
2691 :
2692 : // Get the Controlling Zone or Location of the Furnace Thermostat
2693 2 : thisFurnace.ControlZoneNum = Util::FindItemInList(Alphas(5), state.dataHeatBal->Zone);
2694 2 : if (thisFurnace.ControlZoneNum == 0) {
2695 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2696 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(5), Alphas(5)));
2697 0 : ErrorsFound = true;
2698 : }
2699 :
2700 : // Get the node number for the zone with the thermostat
2701 2 : if (thisFurnace.ControlZoneNum > 0) {
2702 2 : AirNodeFound = false;
2703 2 : AirLoopFound = false;
2704 2 : int ControlledZoneNum = thisFurnace.ControlZoneNum;
2705 : // Find the controlled zone number for the specified thermostat location
2706 2 : thisFurnace.NodeNumOfControlledZone = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneNode;
2707 : // Determine if furnace is on air loop served by the thermostat location specified
2708 3 : for (int zoneInNode = 1; zoneInNode <= state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumInletNodes; ++zoneInNode) {
2709 3 : int AirLoopNumber = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNodeAirLoopNum(zoneInNode);
2710 3 : if (AirLoopNumber > 0) {
2711 2 : for (int BranchNum = 1; BranchNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).NumBranches; ++BranchNum) {
2712 3 : for (int CompNum = 1;
2713 3 : CompNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).TotalComponents;
2714 : ++CompNum) {
2715 3 : if (!Util::SameString(state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).Name,
2716 8 : Alphas(1)) ||
2717 2 : !Util::SameString(
2718 2 : state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).TypeOf,
2719 : CurrentModuleObject))
2720 1 : continue;
2721 2 : AirLoopFound = true;
2722 2 : thisFurnace.ZoneInletNode = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNode(zoneInNode);
2723 2 : break;
2724 : }
2725 2 : if (AirLoopFound) break;
2726 : }
2727 4 : for (TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumTempControlledZones; ++TstatZoneNum) {
2728 2 : if (state.dataZoneCtrls->TempControlledZone(TstatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) continue;
2729 2 : AirNodeFound = true;
2730 : }
2731 2 : for (TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumComfortControlledZones; ++TstatZoneNum) {
2732 0 : if (state.dataZoneCtrls->ComfortControlledZone(TstatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) continue;
2733 0 : AirNodeFound = true;
2734 : }
2735 : }
2736 3 : if (AirLoopFound) break;
2737 : }
2738 2 : if (!AirNodeFound) {
2739 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2740 0 : ShowContinueError(state, "Did not find air node (zone with thermostat).");
2741 0 : ShowContinueError(state, format("Specified {} = {}", cAlphaFields(5), Alphas(5)));
2742 0 : ShowContinueError(
2743 : state, "Both a ZoneHVAC:EquipmentConnections object and a ZoneControl:Thermostat object must be specified for this zone.");
2744 0 : ErrorsFound = true;
2745 : }
2746 2 : if (!AirLoopFound) {
2747 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2748 0 : ShowContinueError(state, "Did not find correct AirLoopHVAC.");
2749 0 : ShowContinueError(state, format("Specified {} = {}", cAlphaFields(5), Alphas(5)));
2750 0 : ErrorsFound = true;
2751 : }
2752 : }
2753 :
2754 : // Get fan data
2755 2 : FanName = Alphas(7);
2756 :
2757 2 : thisFurnace.fanType = static_cast<HVAC::FanType>(getEnumValue(HVAC::fanTypeNamesUC, Alphas(6)));
2758 :
2759 2 : if (thisFurnace.fanType == HVAC::FanType::OnOff || thisFurnace.fanType == HVAC::FanType::Constant) {
2760 :
2761 2 : if ((thisFurnace.FanIndex = Fans::GetFanIndex(state, FanName)) == 0) {
2762 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(7), FanName);
2763 0 : ErrorsFound = true;
2764 : } else {
2765 2 : auto *fan = state.dataFans->fans(thisFurnace.FanIndex);
2766 2 : FanInletNode = fan->inletNodeNum;
2767 2 : FanOutletNode = fan->outletNodeNum;
2768 2 : thisFurnace.fanAvailSched = fan->availSched;
2769 2 : thisFurnace.ActualFanVolFlowRate = fan->maxAirFlowRate;
2770 : }
2771 : }
2772 :
2773 : // Get heating coil type and name data
2774 2 : HeatingCoilType = Alphas(8);
2775 2 : HeatingCoilName = Alphas(9);
2776 :
2777 2 : errFlag = false;
2778 :
2779 4 : if (Util::SameString(HeatingCoilType, "COIL:HEATING:DX:VARIABLESPEED") ||
2780 4 : Util::SameString(HeatingCoilType, "COILSYSTEM:INTEGRATEDHEATPUMP:AIRSOURCE")) {
2781 0 : thisFurnace.HeatingCoilType_Num = HVAC::Coil_HeatingAirToAirVariableSpeed;
2782 0 : if (Util::SameString(HeatingCoilType, "COILSYSTEM:INTEGRATEDHEATPUMP:AIRSOURCE")) thisFurnace.bIsIHP = true;
2783 : } else {
2784 2 : thisFurnace.HeatingCoilType_Num = DXCoils::GetCoilTypeNum(state, HeatingCoilType, HeatingCoilName, errFlag);
2785 : }
2786 :
2787 2 : if (errFlag) {
2788 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2789 0 : ErrorsFound = true;
2790 : }
2791 :
2792 2 : if (thisFurnace.HeatingCoilType_Num == HVAC::CoilDX_HeatingEmpirical) {
2793 2 : ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject);
2794 2 : if (IsNotOK) {
2795 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2796 0 : ErrorsFound = true;
2797 :
2798 : } else { // mine data from DX heating coil
2799 :
2800 2 : DXCoils::GetDXCoilIndex(state, HeatingCoilName, thisFurnace.HeatingCoilIndex, IsNotOK);
2801 2 : if (IsNotOK) {
2802 0 : ShowContinueError(state, format("...occurs {} = {}", CurrentModuleObject, Alphas(1)));
2803 0 : ErrorsFound = true;
2804 : }
2805 :
2806 : // Get the Heating Coil Node Names
2807 2 : errFlag = false;
2808 2 : HeatingCoilInletNode = DXCoils::GetCoilInletNode(state, HeatingCoilType, HeatingCoilName, errFlag);
2809 2 : HeatingCoilOutletNode = DXCoils::GetCoilOutletNode(state, HeatingCoilType, HeatingCoilName, errFlag);
2810 2 : if (errFlag) {
2811 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2812 0 : ErrorsFound = true;
2813 : }
2814 :
2815 : // Get the design heating capacity
2816 2 : errFlag = false;
2817 2 : thisFurnace.DesignHeatingCapacity = DXCoils::GetCoilCapacity(state, HeatingCoilType, HeatingCoilName, errFlag);
2818 2 : if (errFlag) {
2819 0 : ShowContinueError(state, format("...occurs in {} ={}", CurrentModuleObject, Alphas(1)));
2820 0 : ErrorsFound = true;
2821 : }
2822 :
2823 : } // IF (IsNotOK) THEN
2824 0 : } else if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed) {
2825 0 : ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject);
2826 0 : if (IsNotOK) {
2827 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2828 0 : ErrorsFound = true;
2829 : } else {
2830 0 : if (thisFurnace.bIsIHP) {
2831 0 : thisFurnace.HeatingCoilIndex = IntegratedHeatPump::GetCoilIndexIHP(state, HeatingCoilType, HeatingCoilName, errFlag);
2832 0 : IHPCoilIndex = thisFurnace.HeatingCoilIndex;
2833 0 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(IHPCoilIndex).SHCoilName;
2834 : HeatingCoilInletNode =
2835 0 : VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, "COIL:HEATING:DX:VARIABLESPEED", IHPCoilName, errFlag);
2836 : HeatingCoilOutletNode =
2837 0 : VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, "COIL:HEATING:DX:VARIABLESPEED", IHPCoilName, errFlag);
2838 : } else {
2839 0 : thisFurnace.HeatingCoilIndex =
2840 0 : VariableSpeedCoils::GetCoilIndexVariableSpeed(state, HeatingCoilType, HeatingCoilName, errFlag);
2841 0 : HeatingCoilInletNode = VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, HeatingCoilType, HeatingCoilName, errFlag);
2842 0 : HeatingCoilOutletNode = VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, HeatingCoilType, HeatingCoilName, errFlag);
2843 : }
2844 : }
2845 : } else {
2846 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2847 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(8), Alphas(8)));
2848 0 : ErrorsFound = true;
2849 : }
2850 :
2851 : // Get Cooling Coil Information if available
2852 2 : CoolingCoilType = Alphas(10);
2853 2 : CoolingCoilName = Alphas(11);
2854 :
2855 4 : if (Util::SameString(CoolingCoilType, "COIL:COOLING:DX:VARIABLESPEED") ||
2856 4 : Util::SameString(CoolingCoilType, "COILSYSTEM:INTEGRATEDHEATPUMP:AIRSOURCE")) {
2857 0 : thisFurnace.CoolingCoilType_Num = HVAC::Coil_CoolingAirToAirVariableSpeed;
2858 0 : if (Util::SameString(CoolingCoilType, "COILSYSTEM:INTEGRATEDHEATPUMP:AIRSOURCE")) thisFurnace.bIsIHP = true;
2859 : }
2860 :
2861 2 : ValidateComponent(state, CoolingCoilType, CoolingCoilName, IsNotOK, CurrentModuleObject);
2862 :
2863 2 : if (IsNotOK) {
2864 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2865 0 : ErrorsFound = true;
2866 :
2867 : } else { // mine data from DX cooling coil
2868 :
2869 2 : errFlag = false;
2870 2 : PrintMessage = false;
2871 :
2872 2 : if (thisFurnace.CoolingCoilType_Num != HVAC::Coil_CoolingAirToAirVariableSpeed) {
2873 2 : thisFurnace.CoolingCoilType_Num = DXCoils::GetCoilTypeNum(state, CoolingCoilType, CoolingCoilName, errFlag, PrintMessage);
2874 : }
2875 :
2876 : // If coil type not found, check to see if a HX assisted cooling coil is used.
2877 2 : if (thisFurnace.CoolingCoilType_Num == 0) {
2878 0 : errFlag = false;
2879 0 : PrintMessage = false;
2880 0 : thisFurnace.CoolingCoilType_Num =
2881 0 : HVACHXAssistedCoolingCoil::GetCoilGroupTypeNum(state, CoolingCoilType, CoolingCoilName, errFlag, PrintMessage);
2882 : }
2883 :
2884 2 : if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingSingleSpeed) {
2885 :
2886 : // Get the cooling coil node numbers
2887 2 : errFlag = false;
2888 2 : DXCoils::GetDXCoilIndex(state, CoolingCoilName, thisFurnace.CoolingCoilIndex, errFlag);
2889 2 : CoolingCoilInletNode = DXCoils::GetCoilInletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
2890 2 : CoolingCoilOutletNode = DXCoils::GetCoilOutletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
2891 2 : if (errFlag) {
2892 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2893 0 : ErrorsFound = true;
2894 : }
2895 :
2896 : // Get the DX cooling coil design capacity
2897 2 : errFlag = false;
2898 2 : thisFurnace.DesignCoolingCapacity = DXCoils::GetCoilCapacity(state, CoolingCoilType, CoolingCoilName, errFlag);
2899 2 : if (errFlag) {
2900 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2901 0 : ErrorsFound = true;
2902 : }
2903 :
2904 0 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) {
2905 :
2906 : // Get the cooling coil node numbers
2907 0 : errFlag = false;
2908 0 : HVACHXAssistedCoolingCoil::GetHXDXCoilIndex(state, CoolingCoilName, thisFurnace.CoolingCoilIndex, errFlag);
2909 0 : CoolingCoilInletNode = HVACHXAssistedCoolingCoil::GetCoilInletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
2910 0 : CoolingCoilOutletNode = HVACHXAssistedCoolingCoil::GetCoilOutletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
2911 0 : if (errFlag) {
2912 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2913 0 : ErrorsFound = true;
2914 : }
2915 :
2916 : // Get the heat exchanger assisted cooling coil design capacity
2917 0 : errFlag = false;
2918 0 : thisFurnace.DesignCoolingCapacity = HVACHXAssistedCoolingCoil::GetCoilCapacity(state, CoolingCoilType, CoolingCoilName, errFlag);
2919 0 : if (errFlag) {
2920 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2921 0 : ErrorsFound = true;
2922 : }
2923 :
2924 : // get the actual index to the DX cooling coil object
2925 0 : DXCoilIndex = HVACHXAssistedCoolingCoil::GetActualDXCoilIndex(state, CoolingCoilType, CoolingCoilName, ErrorsFound);
2926 0 : thisFurnace.ActualDXCoilIndexForHXAssisted = DXCoilIndex;
2927 :
2928 0 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) {
2929 : // BOS ADDED, AUG/2012, VARIIABLE SPEED DX COOLING COIL
2930 : // Furnace(FurnaceNum)%DXCoolCoilType = 'COIL:COOLING:DX:VARIABLESPEED'
2931 : // Furnace(FurnaceNum)%DXCoolCoilName = CoolingCoilName
2932 0 : ValidateComponent(state, CoolingCoilType, CoolingCoilName, IsNotOK, CurrentModuleObject);
2933 0 : if (IsNotOK) {
2934 0 : ShowContinueError(state, format("...specified in {}=\"{}\".", CurrentModuleObject, Alphas(1)));
2935 0 : ErrorsFound = true;
2936 : } else {
2937 0 : errFlag = false;
2938 0 : if (thisFurnace.bIsIHP) {
2939 0 : thisFurnace.CoolingCoilIndex = IntegratedHeatPump::GetCoilIndexIHP(state, CoolingCoilType, CoolingCoilName, errFlag);
2940 0 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SCCoilName;
2941 : } else {
2942 0 : thisFurnace.CoolingCoilIndex =
2943 0 : VariableSpeedCoils::GetCoilIndexVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
2944 0 : IHPCoilName = CoolingCoilName;
2945 : }
2946 :
2947 0 : if (errFlag) {
2948 0 : ShowContinueError(state, format("...specified in {}=\"{}\".", CurrentModuleObject, Alphas(1)));
2949 0 : ErrorsFound = true;
2950 : }
2951 :
2952 0 : if (thisFurnace.bIsIHP) {
2953 : CoolingCoilInletNode =
2954 0 : VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, "COIL:COOLING:DX:VARIABLESPEED", IHPCoilName, errFlag);
2955 : CoolingCoilOutletNode =
2956 0 : VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, "COIL:COOLING:DX:VARIABLESPEED", IHPCoilName, errFlag);
2957 0 : thisFurnace.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, IHPCoilName, errFlag);
2958 : } else {
2959 : CoolingCoilInletNode =
2960 0 : VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
2961 : CoolingCoilOutletNode =
2962 0 : VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
2963 0 : thisFurnace.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, CoolingCoilName, errFlag);
2964 : }
2965 :
2966 0 : if (errFlag) {
2967 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2968 0 : ErrorsFound = true;
2969 : }
2970 : }
2971 : } else {
2972 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2973 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(10), Alphas(10)));
2974 0 : ErrorsFound = true;
2975 : }
2976 : }
2977 :
2978 2 : if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed &&
2979 0 : thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed) {
2980 : // Furnace(FurnaceNum)%WatertoAirHPType = WatertoAir_VarSpeedEquationFit
2981 0 : if (thisFurnace.bIsIHP) {
2982 0 : VariableSpeedCoils::SetVarSpeedCoilData(state,
2983 0 : state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SCCoilIndex,
2984 : ErrorsFound,
2985 : _,
2986 0 : state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SHCoilIndex);
2987 : } else {
2988 0 : VariableSpeedCoils::SetVarSpeedCoilData(state, thisFurnace.CoolingCoilIndex, ErrorsFound, _, thisFurnace.HeatingCoilIndex);
2989 : }
2990 : }
2991 :
2992 : // Get supplemental heating coil information
2993 2 : SuppHeatCoilType = Alphas(12);
2994 2 : SuppHeatCoilName = Alphas(13);
2995 2 : thisFurnace.SuppHeatCoilType = SuppHeatCoilType;
2996 2 : thisFurnace.SuppHeatCoilName = SuppHeatCoilName;
2997 2 : errFlag = false;
2998 2 : if (Util::SameString(SuppHeatCoilType, "Coil:Heating:Fuel") || Util::SameString(SuppHeatCoilType, "Coil:Heating:Electric")) {
2999 :
3000 2 : thisFurnace.SuppHeatCoilType_Num = HeatingCoils::GetHeatingCoilTypeNum(state, SuppHeatCoilType, SuppHeatCoilName, errFlag);
3001 2 : if (errFlag) {
3002 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3003 0 : ErrorsFound = true;
3004 : } else {
3005 2 : IsNotOK = false;
3006 2 : ValidateComponent(state, SuppHeatCoilType, SuppHeatCoilName, IsNotOK, CurrentModuleObject);
3007 2 : if (IsNotOK) {
3008 0 : ShowContinueError(state, format("In {} \"{}\"", CurrentModuleObject, Alphas(1)));
3009 0 : ErrorsFound = true;
3010 :
3011 : } else { // mine data from the supplemental heating coil
3012 :
3013 2 : HeatingCoils::GetCoilIndex(state, SuppHeatCoilName, thisFurnace.SuppHeatCoilIndex, IsNotOK);
3014 2 : if (IsNotOK) {
3015 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3016 0 : ErrorsFound = true;
3017 : }
3018 :
3019 : // Get the Supplemental Heating Coil Inlet Node Number
3020 2 : errFlag = false;
3021 2 : SupHeatCoilInletNode = HeatingCoils::GetCoilInletNode(state, SuppHeatCoilType, SuppHeatCoilName, errFlag);
3022 2 : if (errFlag) {
3023 0 : ShowContinueError(state, format("...occurs in {} \"{}\"", CurrentModuleObject, Alphas(1)));
3024 0 : ErrorsFound = true;
3025 : }
3026 :
3027 : // Get the Supplemental Heating Coil Outlet Node Number
3028 2 : errFlag = false;
3029 2 : SupHeatCoilOutletNode = HeatingCoils::GetCoilOutletNode(state, SuppHeatCoilType, SuppHeatCoilName, errFlag);
3030 :
3031 2 : if (errFlag) {
3032 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3033 0 : ErrorsFound = true;
3034 : }
3035 :
3036 : // Get the supplemental heating coil design capacity
3037 2 : errFlag = false;
3038 2 : thisFurnace.DesignSuppHeatingCapacity = HeatingCoils::GetCoilCapacity(state, SuppHeatCoilType, SuppHeatCoilName, errFlag);
3039 2 : if (errFlag) {
3040 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3041 0 : ErrorsFound = true;
3042 : }
3043 :
3044 : } // IF (IsNotOK) THEN
3045 : }
3046 0 : } else if (Util::SameString(SuppHeatCoilType, "Coil:Heating:Water")) {
3047 0 : thisFurnace.SuppHeatCoilType_Num = HVAC::Coil_HeatingWater;
3048 0 : ValidateComponent(state, SuppHeatCoilType, SuppHeatCoilName, IsNotOK, CurrentModuleObject);
3049 0 : if (IsNotOK) {
3050 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3051 0 : ErrorsFound = true;
3052 : } else { // mine data from heating coil object
3053 :
3054 : // Get the Heating Coil water Inlet or control Node number
3055 0 : errFlag = false;
3056 0 : thisFurnace.SuppCoilControlNode = WaterCoils::GetCoilWaterInletNode(state, "Coil:Heating:Water", SuppHeatCoilName, errFlag);
3057 0 : if (errFlag) {
3058 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3059 0 : ErrorsFound = true;
3060 : }
3061 :
3062 : // Get the ReHeat Coil hot water max volume flow rate
3063 0 : errFlag = false;
3064 0 : thisFurnace.MaxSuppCoilFluidFlow = WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", SuppHeatCoilName, errFlag);
3065 0 : if (errFlag) {
3066 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3067 0 : ErrorsFound = true;
3068 : }
3069 :
3070 : // Get the ReHeat Coil Inlet Node
3071 0 : errFlag = false;
3072 0 : SupHeatCoilInletNode = WaterCoils::GetCoilInletNode(state, "Coil:Heating:Water", SuppHeatCoilName, errFlag);
3073 0 : thisFurnace.SuppCoilAirInletNode = SupHeatCoilInletNode;
3074 0 : if (errFlag) {
3075 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3076 0 : ErrorsFound = true;
3077 : }
3078 :
3079 : // Get the ReHeat Coil Outlet Node
3080 0 : errFlag = false;
3081 0 : SupHeatCoilOutletNode = WaterCoils::GetCoilOutletNode(state, "Coil:Heating:Water", SuppHeatCoilName, errFlag);
3082 0 : thisFurnace.SuppCoilAirOutletNode = SupHeatCoilOutletNode;
3083 0 : if (errFlag) {
3084 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3085 0 : ErrorsFound = true;
3086 : }
3087 0 : errFlag = false;
3088 0 : HVACControllers::CheckCoilWaterInletNode(state, thisFurnace.CoilControlNode, errFlag);
3089 0 : if (!errFlag) { // then did find a controller so that is bad
3090 0 : ShowSevereError(state,
3091 0 : format("{} = {} has a conflicting Controller:WaterCoil object", CurrentModuleObject, thisFurnace.Name));
3092 0 : ShowContinueError(state, "Hot water coils are controlled directly by unitary and furnace systems.");
3093 0 : ShowContinueError(state, "No water coil controller should be input for the coil.");
3094 0 : ErrorsFound = true;
3095 : }
3096 : }
3097 :
3098 0 : } else if (Util::SameString(SuppHeatCoilType, "Coil:Heating:Steam")) {
3099 0 : thisFurnace.SuppHeatCoilType_Num = HVAC::Coil_HeatingSteam;
3100 0 : ValidateComponent(state, SuppHeatCoilType, SuppHeatCoilName, IsNotOK, CurrentModuleObject);
3101 0 : if (IsNotOK) {
3102 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3103 0 : ErrorsFound = true;
3104 : } else { // mine data from heating coil object
3105 :
3106 0 : errFlag = false;
3107 0 : thisFurnace.SuppHeatCoilIndex = SteamCoils::GetSteamCoilIndex(state, "COIL:HEATING:STEAM", SuppHeatCoilName, errFlag);
3108 0 : if (thisFurnace.SuppHeatCoilIndex == 0) {
3109 0 : ShowSevereError(state, format("{} illegal {} = {}", CurrentModuleObject, cAlphaFields(12), SuppHeatCoilName));
3110 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3111 0 : ErrorsFound = true;
3112 : }
3113 :
3114 : // Get the Heating Coil steam inlet node number
3115 0 : errFlag = false;
3116 0 : thisFurnace.SuppCoilControlNode = SteamCoils::GetCoilSteamInletNode(state, "Coil:Heating:Steam", SuppHeatCoilName, errFlag);
3117 0 : if (errFlag) {
3118 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3119 0 : ErrorsFound = true;
3120 : }
3121 :
3122 : // Get the Heating Coil steam max volume flow rate
3123 0 : thisFurnace.MaxSuppCoilFluidFlow = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.SuppHeatCoilIndex, errFlag);
3124 0 : if (thisFurnace.MaxSuppCoilFluidFlow > 0.0) {
3125 : SteamDensity =
3126 0 : Fluid::GetSteam(state)->getSatDensity(state, state.dataFurnaces->TempSteamIn, 1.0, getAirLoopHVACHeatCoolInput);
3127 0 : thisFurnace.MaxSuppCoilFluidFlow =
3128 0 : SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.SuppHeatCoilIndex, errFlag) * SteamDensity;
3129 : }
3130 :
3131 : // Get the Heating Coil Inlet Node
3132 0 : errFlag = false;
3133 0 : SupHeatCoilInletNode = SteamCoils::GetCoilAirInletNode(state, thisFurnace.SuppHeatCoilIndex, SuppHeatCoilName, errFlag);
3134 0 : thisFurnace.SuppCoilAirInletNode = SupHeatCoilInletNode;
3135 0 : if (errFlag) {
3136 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3137 0 : ErrorsFound = true;
3138 : }
3139 :
3140 : // Get the Heating Coil Outlet Node
3141 0 : errFlag = false;
3142 0 : SupHeatCoilOutletNode = SteamCoils::GetCoilAirOutletNode(state, thisFurnace.SuppHeatCoilIndex, SuppHeatCoilName, errFlag);
3143 0 : thisFurnace.SuppCoilAirOutletNode = SupHeatCoilOutletNode;
3144 0 : if (errFlag) {
3145 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3146 0 : ErrorsFound = true;
3147 : }
3148 : }
3149 :
3150 : } else {
3151 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3152 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(12), Alphas(12)));
3153 0 : ErrorsFound = true;
3154 : } // IF (Furnace(FurnaceNum)%HeatingCoilType_Num == Coil_HeatingGasOrOtherFuel .OR. &, etc.
3155 :
3156 2 : thisFurnace.fanPlace = static_cast<HVAC::FanPlace>(getEnumValue(HVAC::fanPlaceNamesUC, Alphas(14)));
3157 2 : assert(thisFurnace.fanPlace != HVAC::FanPlace::Invalid);
3158 :
3159 2 : if (lAlphaBlanks(15)) {
3160 0 : thisFurnace.fanOp = HVAC::FanOp::Cycling;
3161 0 : if (thisFurnace.fanType != HVAC::FanType::OnOff) {
3162 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisFurnace.Name));
3163 0 : ShowContinueError(state, format("{} = {}", cAlphaFields(6), Alphas(6)));
3164 0 : ShowContinueError(state, format("Fan type must be Fan:OnOff when {} = Blank.", cAlphaFields(15)));
3165 0 : ErrorsFound = true;
3166 : }
3167 2 : } else if ((thisFurnace.fanOpModeSched = Sched::GetSchedule(state, Alphas(15))) == nullptr) {
3168 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(15), Alphas(15));
3169 0 : ErrorsFound = true;
3170 : }
3171 :
3172 2 : if (thisFurnace.fanType == HVAC::FanType::Constant && thisFurnace.fanOpModeSched != nullptr &&
3173 0 : !thisFurnace.fanOpModeSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 1.0)) {
3174 0 : Sched::ShowSevereBadMinMax(
3175 : state,
3176 : eoh,
3177 0 : cAlphaFields(15),
3178 0 : Alphas(15),
3179 : Clusive::In,
3180 : 0.0,
3181 : Clusive::In,
3182 : 1.0,
3183 0 : format("For {} = {}, fan operating mode must be continuous (schedule values > 0)", cAlphaFields(7), Alphas(7)));
3184 0 : ErrorsFound = true;
3185 : }
3186 :
3187 : // Dehumidification Control Type
3188 2 : if (Util::SameString(Alphas(16), "None") || Util::SameString(Alphas(16), "Multimode") || Util::SameString(Alphas(16), "CoolReheat")) {
3189 2 : AirNodeFound = false;
3190 2 : if (Util::SameString(Alphas(16), "Multimode")) {
3191 0 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::Multimode;
3192 0 : thisFurnace.Humidistat = true;
3193 0 : if (thisFurnace.CoolingCoilType_Num != HVAC::CoilDX_CoolingHXAssisted) {
3194 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3195 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(16), Alphas(16)));
3196 0 : ShowContinueError(state, "Multimode control must be used with a Heat Exchanger Assisted Cooling Coil.");
3197 0 : ErrorsFound = true;
3198 : }
3199 : }
3200 2 : if (Util::SameString(Alphas(16), "CoolReheat")) {
3201 0 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::CoolReheat;
3202 0 : thisFurnace.Humidistat = true;
3203 : }
3204 2 : if (Util::SameString(Alphas(16), "None")) {
3205 2 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::None;
3206 2 : thisFurnace.Humidistat = false;
3207 : }
3208 2 : if (thisFurnace.Humidistat) {
3209 0 : for (HStatZoneNum = 1; HStatZoneNum <= state.dataZoneCtrls->NumHumidityControlZones; ++HStatZoneNum) {
3210 0 : if (state.dataZoneCtrls->HumidityControlZone(HStatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) continue;
3211 0 : AirNodeFound = true;
3212 : }
3213 0 : if (!AirNodeFound) {
3214 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3215 0 : ShowContinueError(state, "Did not find Air Node (Zone with Humidistat).");
3216 0 : ShowContinueError(state, format("Specified {} = {}", cAlphaFields(5), Alphas(5)));
3217 0 : ErrorsFound = true;
3218 : }
3219 : }
3220 : } else { // invalid input or blank
3221 0 : if (!lAlphaBlanks(16)) {
3222 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3223 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(16), Alphas(16)));
3224 0 : ErrorsFound = true;
3225 : } else {
3226 0 : thisFurnace.Humidistat = false;
3227 0 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::None;
3228 : }
3229 : }
3230 :
3231 : // Check node names for child components
3232 2 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
3233 2 : if (FanInletNode != thisFurnace.FurnaceInletNodeNum) {
3234 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, Alphas(1)));
3235 0 : ShowContinueError(
3236 : state,
3237 : "When a blow through fan is specified, the fan inlet node name must be the same as the unitary system inlet node name.");
3238 0 : ShowContinueError(state, format("...Fan inlet node name = {}", state.dataLoopNodes->NodeID(FanInletNode)));
3239 0 : ShowContinueError(state,
3240 0 : format("...Unitary system inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
3241 0 : ErrorsFound = true;
3242 : }
3243 2 : if (FanOutletNode != CoolingCoilInletNode) {
3244 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, Alphas(1)));
3245 0 : ShowContinueError(
3246 : state,
3247 : "When a blow through fan is specified, the fan outlet node name must be the same as the cooling coil inlet node name.");
3248 0 : ShowContinueError(state, format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
3249 0 : ShowContinueError(state, format("...Cooling coil inlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilInletNode)));
3250 0 : ErrorsFound = true;
3251 : }
3252 2 : if (CoolingCoilOutletNode != HeatingCoilInletNode) {
3253 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, Alphas(1)));
3254 0 : ShowContinueError(state, "The cooling coil outlet node name must be the same as the heating coil inlet node name.");
3255 0 : ShowContinueError(state, format("...Cooling coil outlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilOutletNode)));
3256 0 : ShowContinueError(state, format("...Heating coil inlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
3257 0 : ErrorsFound = true;
3258 : }
3259 2 : if (HeatingCoilOutletNode != SupHeatCoilInletNode) {
3260 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, Alphas(1)));
3261 0 : ShowContinueError(state,
3262 : "When a blow through fan is specified, the heating coil outlet node name must be the same as the supplemental "
3263 : "heating coil inlet node name.");
3264 0 : ShowContinueError(
3265 0 : state, format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
3266 0 : ShowContinueError(
3267 0 : state, format("...Supplemental heating coil inlet node name = {}", state.dataLoopNodes->NodeID(SupHeatCoilInletNode)));
3268 0 : ErrorsFound = true;
3269 : }
3270 2 : if (SupHeatCoilOutletNode != thisFurnace.FurnaceOutletNodeNum) {
3271 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, Alphas(1)));
3272 0 : ShowContinueError(state,
3273 : "The supplemental heating coil outlet node name must be the same as the unitary system outlet node name.");
3274 0 : ShowContinueError(
3275 0 : state, format("...Supplemental heating coil outlet node name = {}", state.dataLoopNodes->NodeID(SupHeatCoilOutletNode)));
3276 0 : ShowContinueError(
3277 : state,
3278 0 : format("...Unitary system outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
3279 0 : ErrorsFound = true;
3280 : }
3281 : } else {
3282 0 : if (CoolingCoilInletNode != thisFurnace.FurnaceInletNodeNum) {
3283 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, Alphas(1)));
3284 0 : ShowContinueError(state,
3285 : "When a draw through fan is specified, the cooling coil inlet node name must be the same as the unitary system "
3286 : "inlet node name.");
3287 0 : ShowContinueError(state, format("...Cooling coil inlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilInletNode)));
3288 0 : ShowContinueError(state,
3289 0 : format("...Unitary system inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
3290 0 : ErrorsFound = true;
3291 : }
3292 0 : if (CoolingCoilOutletNode != HeatingCoilInletNode) {
3293 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, Alphas(1)));
3294 0 : ShowContinueError(state, "The cooling coil outlet node name must be the same as the heating coil inlet node name.");
3295 0 : ShowContinueError(state, format("...Cooling coil outlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilOutletNode)));
3296 0 : ShowContinueError(state, format("...Heating coil inlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
3297 0 : ErrorsFound = true;
3298 : }
3299 0 : if (HeatingCoilOutletNode != FanInletNode) {
3300 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, Alphas(1)));
3301 0 : ShowContinueError(
3302 : state,
3303 : "When a draw through fan is specified, the heating coil outlet node name must be the same as the fan inlet node name.");
3304 0 : ShowContinueError(state, format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
3305 0 : ShowContinueError(state, format("...Fan inlet node name = {}", state.dataLoopNodes->NodeID(FanInletNode)));
3306 0 : ErrorsFound = true;
3307 : }
3308 0 : if (FanOutletNode != SupHeatCoilInletNode) {
3309 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, Alphas(1)));
3310 0 : ShowContinueError(state,
3311 : "When a draw through fan is specified, the fan outlet node name must be the same as the supplemental heating "
3312 : "coil inlet node name.");
3313 0 : ShowContinueError(state,
3314 0 : format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
3315 0 : ShowContinueError(
3316 0 : state, format("...Supplemental heating coil inlet node name = {}", state.dataLoopNodes->NodeID(SupHeatCoilInletNode)));
3317 0 : ErrorsFound = true;
3318 : }
3319 0 : if (SupHeatCoilOutletNode != thisFurnace.FurnaceOutletNodeNum) {
3320 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, Alphas(1)));
3321 0 : ShowContinueError(state,
3322 : "The supplemental heating coil outlet node name must be the same as the unitary system outlet node name.");
3323 0 : ShowContinueError(
3324 0 : state, format("...Supplemental heating coil outlet node name = {}", state.dataLoopNodes->NodeID(SupHeatCoilOutletNode)));
3325 0 : ShowContinueError(
3326 : state,
3327 0 : format("...Unitary system outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
3328 0 : ErrorsFound = true;
3329 : }
3330 : }
3331 :
3332 : // Add component sets array
3333 2 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
3334 2 : CompSetFanInlet = Alphas(3);
3335 2 : CompSetCoolInlet = "UNDEFINED";
3336 : } else {
3337 0 : CompSetFanInlet = "UNDEFINED";
3338 0 : CompSetCoolInlet = Alphas(3);
3339 : }
3340 2 : BranchNodeConnections::SetUpCompSets(state, CurrentModuleObject, Alphas(1), Alphas(6), Alphas(7), CompSetFanInlet, "UNDEFINED");
3341 :
3342 : // Add DX cooling coil to component sets array
3343 2 : if (thisFurnace.bIsIHP) {
3344 0 : BranchNodeConnections::SetUpCompSets(
3345 0 : state, CurrentModuleObject, Alphas(1), Alphas(10), Alphas(11) + " Cooling Coil", CompSetCoolInlet, "UNDEFINED");
3346 : } else {
3347 2 : BranchNodeConnections::SetUpCompSets(state, CurrentModuleObject, Alphas(1), Alphas(10), Alphas(11), CompSetCoolInlet, "UNDEFINED");
3348 : }
3349 : // Add DX heating coil to component sets array
3350 2 : if (thisFurnace.bIsIHP) {
3351 0 : BranchNodeConnections::SetUpCompSets(
3352 0 : state, CurrentModuleObject, Alphas(1), Alphas(8), Alphas(9) + " Heating Coil", "UNDEFINED", "UNDEFINED");
3353 : } else {
3354 2 : BranchNodeConnections::SetUpCompSets(state, CurrentModuleObject, Alphas(1), Alphas(8), Alphas(9), "UNDEFINED", "UNDEFINED");
3355 : }
3356 :
3357 : // Add supplemental heating coil to component sets array
3358 2 : BranchNodeConnections::SetUpCompSets(state, CurrentModuleObject, Alphas(1), Alphas(12), Alphas(13), "UNDEFINED", Alphas(4));
3359 :
3360 2 : thisFurnace.MaxCoolAirVolFlow = Numbers(1);
3361 2 : if (thisFurnace.MaxCoolAirVolFlow <= 0 && thisFurnace.MaxCoolAirVolFlow != DataSizing::AutoSize) {
3362 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3363 0 : ShowContinueError(state, format("Illegal {} = {:.7T}", cNumericFields(1), Numbers(1)));
3364 0 : ErrorsFound = true;
3365 : }
3366 :
3367 2 : thisFurnace.MaxHeatAirVolFlow = Numbers(2);
3368 2 : if (thisFurnace.MaxHeatAirVolFlow <= 0 && thisFurnace.MaxHeatAirVolFlow != DataSizing::AutoSize) {
3369 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3370 0 : ShowContinueError(state, format("Illegal {} = {:.7T}", cNumericFields(2), Numbers(2)));
3371 0 : ErrorsFound = true;
3372 : }
3373 :
3374 2 : thisFurnace.MaxNoCoolHeatAirVolFlow = Numbers(3);
3375 2 : if (thisFurnace.MaxNoCoolHeatAirVolFlow < 0 && thisFurnace.MaxNoCoolHeatAirVolFlow != DataSizing::AutoSize) {
3376 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3377 0 : ShowContinueError(state, format("Illegal {} = {:.7T}", cNumericFields(3), Numbers(3)));
3378 0 : ErrorsFound = true;
3379 : }
3380 :
3381 2 : if (thisFurnace.fanOpModeSched != nullptr) {
3382 2 : if (!thisFurnace.fanOpModeSched->checkMinMaxVals(state, Clusive::In, 0.0, Clusive::In, 0.0)) { // Autodesk:Note Range is 0 to 0?
3383 : // set air flow control mode:
3384 : // UseCompressorOnFlow = operate at last cooling or heating air flow requested when compressor is off
3385 : // UseCompressorOffFlow = operate at value specified by user
3386 : // AirFlowControl only valid if fan opmode = ContFanCycComp
3387 0 : if (thisFurnace.MaxNoCoolHeatAirVolFlow == 0.0) {
3388 0 : thisFurnace.AirFlowControl = AirFlowControlConstFan::UseCompressorOnFlow;
3389 : } else {
3390 0 : thisFurnace.AirFlowControl = AirFlowControlConstFan::UseCompressorOffFlow;
3391 : }
3392 : }
3393 : }
3394 :
3395 2 : if (Numbers(1) != DataSizing::AutoSize && Numbers(2) != DataSizing::AutoSize && Numbers(3) != DataSizing::AutoSize) {
3396 0 : thisFurnace.DesignFanVolFlowRate = max(Numbers(1), Numbers(2), Numbers(3));
3397 : } else {
3398 2 : thisFurnace.DesignFanVolFlowRate = DataSizing::AutoSize;
3399 : }
3400 :
3401 2 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed) {
3402 0 : errFlag = false;
3403 :
3404 0 : if (thisFurnace.bIsIHP) {
3405 0 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SHCoilName;
3406 0 : thisFurnace.MaxHeatAirVolFlow =
3407 0 : VariableSpeedCoils::GetCoilAirFlowRateVariableSpeed(state, "COIL:HEATING:DX:VARIABLESPEED", IHPCoilName, errFlag);
3408 0 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SCCoilName;
3409 0 : thisFurnace.MaxCoolAirVolFlow =
3410 0 : VariableSpeedCoils::GetCoilAirFlowRateVariableSpeed(state, "COIL:COOLING:DX:VARIABLESPEED", IHPCoilName, errFlag);
3411 : } else {
3412 0 : thisFurnace.MaxHeatAirVolFlow =
3413 0 : VariableSpeedCoils::GetCoilAirFlowRateVariableSpeed(state, HeatingCoilType, HeatingCoilName, errFlag);
3414 0 : thisFurnace.MaxCoolAirVolFlow =
3415 0 : VariableSpeedCoils::GetCoilAirFlowRateVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
3416 : }
3417 :
3418 0 : if (errFlag) {
3419 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3420 0 : ErrorsFound = true;
3421 : }
3422 :
3423 0 : thisFurnace.MaxNoCoolHeatAirVolFlow = min(thisFurnace.MaxHeatAirVolFlow, thisFurnace.MaxCoolAirVolFlow);
3424 0 : if (thisFurnace.MaxHeatAirVolFlow != DataSizing::AutoSize && thisFurnace.MaxCoolAirVolFlow != DataSizing::AutoSize) {
3425 0 : thisFurnace.DesignFanVolFlowRate = max(thisFurnace.MaxHeatAirVolFlow, thisFurnace.MaxCoolAirVolFlow);
3426 : } else {
3427 0 : thisFurnace.DesignFanVolFlowRate = DataSizing::AutoSize;
3428 : }
3429 : }
3430 :
3431 2 : if (thisFurnace.ActualFanVolFlowRate != DataSizing::AutoSize) {
3432 0 : if (thisFurnace.ActualFanVolFlowRate < thisFurnace.MaxCoolAirVolFlow && thisFurnace.MaxCoolAirVolFlow != DataSizing::AutoSize) {
3433 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3434 0 : ShowContinueError(
3435 : state,
3436 0 : format("... air flow rate = {:.7T} in fan object {} is less than the maximum HVAC system air flow rate in cooling mode.",
3437 0 : thisFurnace.ActualFanVolFlowRate,
3438 : FanName));
3439 0 : ShowContinueError(state, format(" The {} is reset to the fan flow rate and the simulation continues.", cNumericFields(1)));
3440 0 : thisFurnace.MaxCoolAirVolFlow = thisFurnace.ActualFanVolFlowRate;
3441 0 : thisFurnace.DesignFanVolFlowRate = thisFurnace.ActualFanVolFlowRate;
3442 : }
3443 0 : if (thisFurnace.ActualFanVolFlowRate < thisFurnace.MaxHeatAirVolFlow && thisFurnace.MaxHeatAirVolFlow != DataSizing::AutoSize) {
3444 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3445 0 : ShowContinueError(
3446 : state,
3447 0 : format("... air flow rate = {:.7T} in fan object {} is less than the maximum HVAC system air flow rate in heating mode.",
3448 0 : thisFurnace.ActualFanVolFlowRate,
3449 : FanName));
3450 0 : ShowContinueError(state, format(" The {} is reset to the fan flow rate and the simulation continues.", cNumericFields(2)));
3451 0 : thisFurnace.MaxHeatAirVolFlow = thisFurnace.ActualFanVolFlowRate;
3452 0 : thisFurnace.DesignFanVolFlowRate = thisFurnace.ActualFanVolFlowRate;
3453 : }
3454 : }
3455 :
3456 : // Set heating convergence tolerance
3457 2 : thisFurnace.HeatingConvergenceTolerance = 0.001;
3458 :
3459 : // Mine heatpump outdoor condenser node from DX coil object
3460 2 : errFlag = false;
3461 2 : if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingSingleSpeed) {
3462 2 : thisFurnace.CondenserNodeNum = DXCoils::GetCoilCondenserInletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
3463 0 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) {
3464 0 : if (thisFurnace.bIsIHP) {
3465 0 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SCCoilName;
3466 0 : thisFurnace.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, IHPCoilName, errFlag);
3467 : } else {
3468 0 : thisFurnace.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, CoolingCoilName, errFlag);
3469 : }
3470 : } else {
3471 0 : thisFurnace.CondenserNodeNum =
3472 0 : DXCoils::GetCoilCondenserInletNode(state,
3473 : "Coil:Cooling:DX:SingleSpeed",
3474 0 : HVACHXAssistedCoolingCoil::GetHXDXCoilName(state, CoolingCoilType, CoolingCoilName, errFlag),
3475 : errFlag);
3476 : }
3477 2 : if (errFlag) {
3478 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3479 0 : ErrorsFound = true;
3480 : }
3481 :
3482 2 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed) {
3483 0 : errFlag = false;
3484 0 : if (thisFurnace.bIsIHP) {
3485 0 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SHCoilName;
3486 0 : thisFurnace.DesignHeatingCapacity =
3487 0 : VariableSpeedCoils::GetCoilCapacityVariableSpeed(state, "Coil:Heating:DX:VariableSpeed", IHPCoilName, errFlag);
3488 : } else {
3489 0 : thisFurnace.DesignHeatingCapacity =
3490 0 : VariableSpeedCoils::GetCoilCapacityVariableSpeed(state, HeatingCoilType, HeatingCoilName, errFlag);
3491 : }
3492 :
3493 0 : if (errFlag) {
3494 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3495 0 : ErrorsFound = true;
3496 : }
3497 : }
3498 :
3499 2 : if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) {
3500 0 : errFlag = false;
3501 0 : if (thisFurnace.bIsIHP) {
3502 0 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SCCoilName;
3503 0 : thisFurnace.DesignCoolingCapacity =
3504 0 : VariableSpeedCoils::GetCoilCapacityVariableSpeed(state, "COIL:COOLING:DX:VARIABLESPEED", IHPCoilName, errFlag);
3505 : } else {
3506 0 : thisFurnace.DesignCoolingCapacity =
3507 0 : VariableSpeedCoils::GetCoilCapacityVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
3508 : }
3509 :
3510 0 : if (errFlag) {
3511 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3512 0 : ErrorsFound = true;
3513 : }
3514 : }
3515 :
3516 : // Set cooling convergence tolerance
3517 2 : thisFurnace.CoolingConvergenceTolerance = 0.001;
3518 :
3519 : // Set the furnace max outlet temperature
3520 2 : thisFurnace.DesignMaxOutletTemp = Numbers(4);
3521 :
3522 : // Set maximum supply air temperature for supplemental heating coil
3523 2 : thisFurnace.MaxOATSuppHeat = Numbers(5);
3524 4 : OutputReportPredefined::PreDefTableEntry(
3525 2 : state, state.dataOutRptPredefined->pdchDXHeatCoilSuppHiT, HeatingCoilName, thisFurnace.MaxOATSuppHeat);
3526 :
3527 : // set minimum outdoor temperature for compressor operation
3528 2 : SetMinOATCompressor(state, FurnaceNum, cCurrentModuleObject, ErrorsFound);
3529 :
3530 : } // End of the Unitary System HeatPump Loop
3531 :
3532 : // Get the Input for the Water to Air Heat Pump (UnitarySystem:HeatPump:WaterToAir)
3533 2 : for (int HeatPumpNum = 1; HeatPumpNum <= NumWaterToAirHeatPump; ++HeatPumpNum) {
3534 :
3535 0 : CurrentModuleObject = "AirLoopHVAC:UnitaryHeatPump:WaterToAir";
3536 0 : FanInletNode = 0;
3537 0 : FanOutletNode = 0;
3538 0 : CoolingCoilInletNode = 0;
3539 0 : CoolingCoilOutletNode = 0;
3540 0 : HeatingCoilInletNode = 0;
3541 0 : HeatingCoilOutletNode = 0;
3542 0 : SupHeatCoilInletNode = 0;
3543 0 : SupHeatCoilOutletNode = 0;
3544 0 : CoolingCoilType = ' ';
3545 0 : CoolingCoilName = ' ';
3546 0 : HeatingCoilType = ' ';
3547 0 : HeatingCoilName = ' ';
3548 :
3549 0 : FurnaceNum = NumHeatOnly + NumHeatCool + NumUnitaryHeatOnly + NumUnitaryHeatCool + NumHeatPump + HeatPumpNum;
3550 0 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
3551 0 : thisFurnace.iterationMode.allocate(3);
3552 :
3553 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
3554 : CurrentModuleObject,
3555 : HeatPumpNum,
3556 : Alphas,
3557 : NumAlphas,
3558 : Numbers,
3559 : NumNumbers,
3560 : IOStatus,
3561 : lNumericBlanks,
3562 : lAlphaBlanks,
3563 : cAlphaFields,
3564 : cNumericFields);
3565 :
3566 0 : GlobalNames::VerifyUniqueInterObjectName(
3567 0 : state, state.dataFurnaces->UniqueFurnaceNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
3568 :
3569 0 : thisFurnace.type = HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir;
3570 0 : thisFurnace.Name = Alphas(1);
3571 :
3572 0 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, thisFurnace.Name};
3573 :
3574 0 : if (lAlphaBlanks(2)) {
3575 0 : thisFurnace.availSched = Sched::GetScheduleAlwaysOn(state);
3576 0 : } else if ((thisFurnace.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
3577 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
3578 0 : ErrorsFound = true;
3579 : }
3580 :
3581 0 : thisFurnace.FurnaceInletNodeNum =
3582 0 : NodeInputManager::GetOnlySingleNode(state,
3583 0 : Alphas(3),
3584 : ErrorsFound,
3585 : DataLoopNode::ConnectionObjectType::AirLoopHVACUnitaryHeatPumpWaterToAir,
3586 0 : Alphas(1),
3587 : DataLoopNode::NodeFluidType::Air,
3588 : DataLoopNode::ConnectionType::Inlet,
3589 : NodeInputManager::CompFluidStream::Primary,
3590 : DataLoopNode::ObjectIsParent);
3591 :
3592 0 : thisFurnace.FurnaceOutletNodeNum =
3593 0 : NodeInputManager::GetOnlySingleNode(state,
3594 0 : Alphas(4),
3595 : ErrorsFound,
3596 : DataLoopNode::ConnectionObjectType::AirLoopHVACUnitaryHeatPumpWaterToAir,
3597 0 : Alphas(1),
3598 : DataLoopNode::NodeFluidType::Air,
3599 : DataLoopNode::ConnectionType::Outlet,
3600 : NodeInputManager::CompFluidStream::Primary,
3601 : DataLoopNode::ObjectIsParent);
3602 :
3603 0 : BranchNodeConnections::TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(3), Alphas(4), "Air Nodes");
3604 :
3605 : // Get the Controlling Zone or Location of the Furnace Thermostat
3606 0 : thisFurnace.ControlZoneNum = Util::FindItemInList(Alphas(5), state.dataHeatBal->Zone);
3607 0 : if (thisFurnace.ControlZoneNum == 0) {
3608 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3609 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(5), Alphas(5)));
3610 0 : ErrorsFound = true;
3611 : }
3612 :
3613 : // Get the node number for the zone with the thermostat
3614 0 : if (thisFurnace.ControlZoneNum > 0) {
3615 0 : AirNodeFound = false;
3616 0 : AirLoopFound = false;
3617 0 : int ControlledZoneNum = thisFurnace.ControlZoneNum;
3618 : // Find the controlled zone number for the specified thermostat location
3619 0 : thisFurnace.NodeNumOfControlledZone = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneNode;
3620 : // Determine if furnace is on air loop served by the thermostat location specified
3621 0 : for (int zoneInNode = 1; zoneInNode <= state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumInletNodes; ++zoneInNode) {
3622 0 : int AirLoopNumber = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNodeAirLoopNum(zoneInNode);
3623 0 : if (AirLoopNumber > 0) {
3624 0 : for (int BranchNum = 1; BranchNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).NumBranches; ++BranchNum) {
3625 0 : for (int CompNum = 1;
3626 0 : CompNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).TotalComponents;
3627 : ++CompNum) {
3628 0 : if (!Util::SameString(state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).Name,
3629 0 : Alphas(1)) ||
3630 0 : !Util::SameString(
3631 0 : state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).TypeOf,
3632 : CurrentModuleObject))
3633 0 : continue;
3634 0 : AirLoopFound = true;
3635 0 : thisFurnace.ZoneInletNode = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNode(zoneInNode);
3636 0 : break;
3637 : }
3638 0 : if (AirLoopFound) break;
3639 : }
3640 0 : for (TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumTempControlledZones; ++TstatZoneNum) {
3641 0 : if (state.dataZoneCtrls->TempControlledZone(TstatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) continue;
3642 0 : AirNodeFound = true;
3643 : }
3644 0 : for (TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumComfortControlledZones; ++TstatZoneNum) {
3645 0 : if (state.dataZoneCtrls->ComfortControlledZone(TstatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) continue;
3646 0 : AirNodeFound = true;
3647 : }
3648 : }
3649 0 : if (AirLoopFound) break;
3650 : }
3651 0 : if (!AirNodeFound) {
3652 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3653 0 : ShowContinueError(state, "Did not find air node (zone with thermostat).");
3654 0 : ShowContinueError(state, format("Specified {} = {}", cAlphaFields(5), Alphas(5)));
3655 0 : ShowContinueError(
3656 : state, "Both a ZoneHVAC:EquipmentConnections object and a ZoneControl:Thermostat object must be specified for this zone.");
3657 0 : ErrorsFound = true;
3658 : }
3659 0 : if (!AirLoopFound) {
3660 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3661 0 : ShowContinueError(state, "Did not find correct AirLoopHVAC.");
3662 0 : ShowContinueError(state, format("Specified {} = {}", cAlphaFields(5), Alphas(5)));
3663 0 : ErrorsFound = true;
3664 : }
3665 : }
3666 :
3667 : // Get fan data
3668 0 : FanName = Alphas(7);
3669 0 : errFlag = false;
3670 0 : thisFurnace.fanType = static_cast<HVAC::FanType>(getEnumValue(HVAC::fanTypeNamesUC, Alphas(6)));
3671 :
3672 0 : if (thisFurnace.fanType != HVAC::FanType::OnOff) {
3673 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3674 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(6), Alphas(6)));
3675 0 : ErrorsFound = true;
3676 :
3677 0 : } else if ((thisFurnace.FanIndex = Fans::GetFanIndex(state, FanName)) == 0) {
3678 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(7), FanName);
3679 0 : ErrorsFound = true;
3680 :
3681 : } else {
3682 0 : auto *fan = state.dataFans->fans(thisFurnace.FanIndex);
3683 0 : FanInletNode = fan->inletNodeNum;
3684 0 : FanOutletNode = fan->outletNodeNum;
3685 0 : thisFurnace.fanAvailSched = fan->availSched;
3686 : }
3687 :
3688 : // Get heating coil type and name data
3689 0 : if (Alphas(8) == "COIL:HEATING:WATERTOAIRHEATPUMP:PARAMETERESTIMATION") {
3690 0 : HeatingCoilType = Alphas(8);
3691 0 : thisFurnace.HeatingCoilType_Num = HVAC::Coil_HeatingWaterToAirHP;
3692 0 : HeatingCoilName = Alphas(9);
3693 0 : ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject);
3694 0 : if (IsNotOK) {
3695 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3696 0 : ErrorsFound = true;
3697 : } else {
3698 0 : thisFurnace.HeatingCoilIndex = WaterToAirHeatPump::GetCoilIndex(state, HeatingCoilType, HeatingCoilName, errFlag);
3699 0 : HeatingCoilInletNode = WaterToAirHeatPump::GetCoilInletNode(state, HeatingCoilType, HeatingCoilName, errFlag);
3700 0 : HeatingCoilOutletNode = WaterToAirHeatPump::GetCoilOutletNode(state, HeatingCoilType, HeatingCoilName, errFlag);
3701 : }
3702 0 : } else if (Alphas(8) == "COIL:HEATING:WATERTOAIRHEATPUMP:EQUATIONFIT") {
3703 0 : HeatingCoilType = Alphas(8);
3704 0 : thisFurnace.HeatingCoilType_Num = HVAC::Coil_HeatingWaterToAirHPSimple;
3705 0 : HeatingCoilName = Alphas(9);
3706 0 : ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject);
3707 0 : if (IsNotOK) {
3708 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3709 0 : ErrorsFound = true;
3710 : } else {
3711 0 : thisFurnace.HeatingCoilIndex = WaterToAirHeatPumpSimple::GetCoilIndex(state, HeatingCoilType, HeatingCoilName, errFlag);
3712 0 : HeatingCoilInletNode = WaterToAirHeatPumpSimple::GetCoilInletNode(state, HeatingCoilType, HeatingCoilName, errFlag);
3713 0 : HeatingCoilOutletNode = WaterToAirHeatPumpSimple::GetCoilOutletNode(state, HeatingCoilType, HeatingCoilName, errFlag);
3714 : }
3715 0 : } else if (Alphas(8) == "COIL:HEATING:WATERTOAIRHEATPUMP:VARIABLESPEEDEQUATIONFIT") {
3716 0 : HeatingCoilType = Alphas(8);
3717 0 : thisFurnace.HeatingCoilType_Num = HVAC::Coil_HeatingWaterToAirHPVSEquationFit;
3718 0 : HeatingCoilName = Alphas(9);
3719 0 : ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject);
3720 0 : if (IsNotOK) {
3721 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3722 0 : ErrorsFound = true;
3723 : } else {
3724 0 : thisFurnace.HeatingCoilIndex = VariableSpeedCoils::GetCoilIndexVariableSpeed(state, HeatingCoilType, HeatingCoilName, errFlag);
3725 0 : HeatingCoilInletNode = VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, HeatingCoilType, HeatingCoilName, errFlag);
3726 0 : HeatingCoilOutletNode = VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, HeatingCoilType, HeatingCoilName, errFlag);
3727 : }
3728 : } else {
3729 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3730 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(8), Alphas(8)));
3731 0 : ErrorsFound = true;
3732 : }
3733 :
3734 : // Get Cooling Coil Information if available
3735 0 : if (Alphas(10) == "COIL:COOLING:WATERTOAIRHEATPUMP:PARAMETERESTIMATION") {
3736 0 : CoolingCoilType = Alphas(10);
3737 0 : thisFurnace.CoolingCoilType_Num = HVAC::Coil_CoolingWaterToAirHP;
3738 0 : CoolingCoilName = Alphas(11);
3739 0 : ValidateComponent(state, CoolingCoilType, CoolingCoilName, IsNotOK, CurrentModuleObject);
3740 0 : if (IsNotOK) {
3741 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3742 0 : ErrorsFound = true;
3743 : } else {
3744 0 : thisFurnace.CoolingCoilIndex = WaterToAirHeatPump::GetCoilIndex(state, CoolingCoilType, CoolingCoilName, errFlag);
3745 0 : CoolingCoilInletNode = WaterToAirHeatPump::GetCoilInletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
3746 0 : CoolingCoilOutletNode = WaterToAirHeatPump::GetCoilOutletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
3747 : }
3748 0 : } else if (Alphas(10) == "COIL:COOLING:WATERTOAIRHEATPUMP:EQUATIONFIT") {
3749 0 : CoolingCoilType = Alphas(10);
3750 0 : thisFurnace.CoolingCoilType_Num = HVAC::Coil_CoolingWaterToAirHPSimple;
3751 0 : CoolingCoilName = Alphas(11);
3752 0 : ValidateComponent(state, CoolingCoilType, CoolingCoilName, IsNotOK, CurrentModuleObject);
3753 0 : if (IsNotOK) {
3754 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3755 0 : ErrorsFound = true;
3756 : } else {
3757 0 : thisFurnace.CoolingCoilIndex = WaterToAirHeatPumpSimple::GetCoilIndex(state, CoolingCoilType, CoolingCoilName, errFlag);
3758 0 : CoolingCoilInletNode = WaterToAirHeatPumpSimple::GetCoilInletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
3759 0 : CoolingCoilOutletNode = WaterToAirHeatPumpSimple::GetCoilOutletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
3760 : }
3761 0 : } else if (Alphas(10) == "COIL:COOLING:WATERTOAIRHEATPUMP:VARIABLESPEEDEQUATIONFIT") {
3762 0 : CoolingCoilType = Alphas(10);
3763 0 : thisFurnace.CoolingCoilType_Num = HVAC::Coil_CoolingWaterToAirHPVSEquationFit;
3764 0 : CoolingCoilName = Alphas(11);
3765 0 : ValidateComponent(state, CoolingCoilType, CoolingCoilName, IsNotOK, CurrentModuleObject);
3766 0 : if (IsNotOK) {
3767 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3768 0 : ErrorsFound = true;
3769 : } else {
3770 0 : thisFurnace.CoolingCoilIndex = VariableSpeedCoils::GetCoilIndexVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
3771 0 : CoolingCoilInletNode = VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
3772 0 : CoolingCoilOutletNode = VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
3773 : }
3774 : } else {
3775 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3776 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(10), Alphas(10)));
3777 0 : ErrorsFound = true;
3778 : }
3779 :
3780 0 : thisFurnace.WaterCyclingMode = (NumAlphas < 18 || lAlphaBlanks(18))
3781 0 : ? HVAC::WaterFlow::Cycling
3782 0 : : static_cast<HVAC::WaterFlow>(getEnumValue(HVAC::waterFlowNamesUC, Alphas(18)));
3783 :
3784 : // end get water flow mode info
3785 0 : if (Alphas(8) == "COIL:HEATING:WATERTOAIRHEATPUMP:EQUATIONFIT" && Alphas(10) == "COIL:COOLING:WATERTOAIRHEATPUMP:EQUATIONFIT") {
3786 0 : thisFurnace.WatertoAirHPType = WAHPCoilType::Simple;
3787 0 : WaterToAirHeatPumpSimple::SetSimpleWSHPData(
3788 0 : state, thisFurnace.CoolingCoilIndex, ErrorsFound, thisFurnace.WaterCyclingMode, _, thisFurnace.HeatingCoilIndex);
3789 0 : } else if (Alphas(8) == "COIL:HEATING:WATERTOAIRHEATPUMP:PARAMETERESTIMATION" &&
3790 0 : Alphas(10) == "COIL:COOLING:WATERTOAIRHEATPUMP:PARAMETERESTIMATION") {
3791 0 : thisFurnace.WatertoAirHPType = WAHPCoilType::ParEst;
3792 0 : } else if (Alphas(8) == "COIL:HEATING:WATERTOAIRHEATPUMP:VARIABLESPEEDEQUATIONFIT" &&
3793 0 : Alphas(10) == "COIL:COOLING:WATERTOAIRHEATPUMP:VARIABLESPEEDEQUATIONFIT") {
3794 0 : thisFurnace.WatertoAirHPType = WAHPCoilType::VarSpeedEquationFit;
3795 0 : VariableSpeedCoils::SetVarSpeedCoilData(state, thisFurnace.CoolingCoilIndex, ErrorsFound, _, thisFurnace.HeatingCoilIndex);
3796 : } else {
3797 0 : ShowContinueError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
3798 0 : ShowContinueError(state, "Cooling coil and heating coil should be of same general type");
3799 0 : ErrorsFound = true;
3800 : }
3801 :
3802 : // Get supplemental heating coil information
3803 :
3804 0 : SuppHeatCoilType = Alphas(12);
3805 0 : SuppHeatCoilName = Alphas(13);
3806 0 : thisFurnace.SuppHeatCoilType = SuppHeatCoilType;
3807 0 : thisFurnace.SuppHeatCoilName = SuppHeatCoilName;
3808 0 : errFlag = false;
3809 0 : if (Util::SameString(SuppHeatCoilType, "Coil:Heating:Fuel") || Util::SameString(SuppHeatCoilType, "Coil:Heating:Electric")) {
3810 :
3811 0 : thisFurnace.SuppHeatCoilType_Num = HeatingCoils::GetHeatingCoilTypeNum(state, SuppHeatCoilType, SuppHeatCoilName, errFlag);
3812 0 : if (errFlag) {
3813 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3814 0 : ErrorsFound = true;
3815 : } else {
3816 0 : IsNotOK = false;
3817 0 : ValidateComponent(state, SuppHeatCoilType, SuppHeatCoilName, IsNotOK, CurrentModuleObject);
3818 0 : if (IsNotOK) {
3819 0 : ShowContinueError(state, format("In {} \"{}\"", CurrentModuleObject, Alphas(1)));
3820 0 : ErrorsFound = true;
3821 :
3822 : } else { // mine data from the supplemental heating coil
3823 :
3824 0 : HeatingCoils::GetCoilIndex(state, SuppHeatCoilName, thisFurnace.SuppHeatCoilIndex, IsNotOK);
3825 0 : if (IsNotOK) {
3826 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3827 0 : ErrorsFound = true;
3828 : }
3829 :
3830 : // Get the Supplemental Heating Coil Inlet Node Number
3831 0 : errFlag = false;
3832 0 : SupHeatCoilInletNode = HeatingCoils::GetCoilInletNode(state, SuppHeatCoilType, SuppHeatCoilName, errFlag);
3833 0 : if (errFlag) {
3834 0 : ShowContinueError(state, format("...occurs in {} \"{}\"", CurrentModuleObject, Alphas(1)));
3835 0 : ErrorsFound = true;
3836 : }
3837 :
3838 : // Get the Supplemental Heating Coil Outlet Node Number
3839 0 : errFlag = false;
3840 0 : SupHeatCoilOutletNode = HeatingCoils::GetCoilOutletNode(state, SuppHeatCoilType, SuppHeatCoilName, errFlag);
3841 0 : if (errFlag) {
3842 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3843 0 : ErrorsFound = true;
3844 : }
3845 :
3846 : // Get the supplemental heating coil design capacity
3847 0 : errFlag = false;
3848 0 : thisFurnace.DesignSuppHeatingCapacity = HeatingCoils::GetCoilCapacity(state, SuppHeatCoilType, SuppHeatCoilName, errFlag);
3849 0 : if (errFlag) {
3850 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3851 0 : ErrorsFound = true;
3852 : }
3853 :
3854 : } // IF (IsNotOK) THEN
3855 : }
3856 0 : } else if (Util::SameString(SuppHeatCoilType, "Coil:Heating:Water")) {
3857 0 : thisFurnace.SuppHeatCoilType_Num = HVAC::Coil_HeatingWater;
3858 0 : ValidateComponent(state, SuppHeatCoilType, SuppHeatCoilName, IsNotOK, CurrentModuleObject);
3859 0 : if (IsNotOK) {
3860 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3861 0 : ErrorsFound = true;
3862 : } else { // mine data from heating coil object
3863 :
3864 : // Get the Heating Coil water Inlet or control Node number
3865 0 : errFlag = false;
3866 0 : thisFurnace.SuppCoilControlNode = WaterCoils::GetCoilWaterInletNode(state, "Coil:Heating:Water", SuppHeatCoilName, errFlag);
3867 0 : if (errFlag) {
3868 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3869 0 : ErrorsFound = true;
3870 : }
3871 :
3872 : // Get the ReHeat Coil hot water max volume flow rate
3873 0 : errFlag = false;
3874 0 : thisFurnace.MaxSuppCoilFluidFlow = WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", SuppHeatCoilName, errFlag);
3875 0 : if (errFlag) {
3876 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3877 0 : ErrorsFound = true;
3878 : }
3879 :
3880 : // Get the ReHeat Coil Inlet Node
3881 0 : errFlag = false;
3882 0 : SupHeatCoilInletNode = WaterCoils::GetCoilInletNode(state, "Coil:Heating:Water", SuppHeatCoilName, errFlag);
3883 0 : thisFurnace.SuppCoilAirInletNode = SupHeatCoilInletNode;
3884 0 : if (errFlag) {
3885 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3886 0 : ErrorsFound = true;
3887 : }
3888 :
3889 : // Get the ReHeat Coil Outlet Node
3890 0 : errFlag = false;
3891 0 : SupHeatCoilOutletNode = WaterCoils::GetCoilOutletNode(state, "Coil:Heating:Water", SuppHeatCoilName, errFlag);
3892 0 : thisFurnace.SuppCoilAirOutletNode = SupHeatCoilOutletNode;
3893 0 : if (errFlag) {
3894 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3895 0 : ErrorsFound = true;
3896 : }
3897 :
3898 0 : errFlag = false;
3899 0 : HVACControllers::CheckCoilWaterInletNode(state, thisFurnace.CoilControlNode, errFlag);
3900 0 : if (!errFlag) { // then did find a controller so that is bad
3901 0 : ShowSevereError(state,
3902 0 : format("{} = {} has a conflicting Controller:WaterCoil object", CurrentModuleObject, thisFurnace.Name));
3903 0 : ShowContinueError(state, "Hot water coils are controlled directly by unitary and furnace systems.");
3904 0 : ShowContinueError(state, "No water coil controller should be input for the coil.");
3905 0 : ErrorsFound = true;
3906 : }
3907 : }
3908 :
3909 0 : } else if (Util::SameString(SuppHeatCoilType, "Coil:Heating:Steam")) {
3910 0 : thisFurnace.SuppHeatCoilType_Num = HVAC::Coil_HeatingSteam;
3911 0 : ValidateComponent(state, SuppHeatCoilType, SuppHeatCoilName, IsNotOK, CurrentModuleObject);
3912 0 : if (IsNotOK) {
3913 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3914 0 : ErrorsFound = true;
3915 : } else { // mine data from heating coil object
3916 :
3917 0 : errFlag = false;
3918 0 : thisFurnace.SuppHeatCoilIndex = SteamCoils::GetSteamCoilIndex(state, SuppHeatCoilType, SuppHeatCoilName, errFlag);
3919 0 : if (thisFurnace.SuppHeatCoilIndex == 0) {
3920 0 : ShowSevereError(state, format("{} illegal {} = {}", CurrentModuleObject, cAlphaFields(12), SuppHeatCoilName));
3921 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3922 0 : ErrorsFound = true;
3923 : }
3924 :
3925 : // Get the Heating Coil steam inlet node number
3926 0 : errFlag = false;
3927 0 : thisFurnace.SuppCoilControlNode = SteamCoils::GetCoilSteamInletNode(state, "Coil:Heating:Steam", SuppHeatCoilName, errFlag);
3928 0 : if (errFlag) {
3929 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3930 0 : ErrorsFound = true;
3931 : }
3932 :
3933 : // Get the Heating Coil steam max volume flow rate
3934 0 : thisFurnace.MaxSuppCoilFluidFlow = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.SuppHeatCoilIndex, errFlag);
3935 0 : if (thisFurnace.MaxSuppCoilFluidFlow > 0.0) {
3936 : SteamDensity =
3937 0 : Fluid::GetSteam(state)->getSatDensity(state, state.dataFurnaces->TempSteamIn, 1.0, getAirLoopHVACHeatCoolInput);
3938 0 : thisFurnace.MaxSuppCoilFluidFlow =
3939 0 : SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.SuppHeatCoilIndex, errFlag) * SteamDensity;
3940 : }
3941 :
3942 : // Get the Heating Coil Inlet Node
3943 0 : errFlag = false;
3944 0 : SupHeatCoilInletNode = SteamCoils::GetCoilAirInletNode(state, thisFurnace.SuppHeatCoilIndex, SuppHeatCoilName, errFlag);
3945 0 : thisFurnace.SuppCoilAirInletNode = SupHeatCoilInletNode;
3946 0 : if (errFlag) {
3947 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3948 0 : ErrorsFound = true;
3949 : }
3950 :
3951 : // Get the Heating Coil Outlet Node
3952 0 : errFlag = false;
3953 0 : SupHeatCoilOutletNode = SteamCoils::GetCoilAirOutletNode(state, thisFurnace.SuppHeatCoilIndex, SuppHeatCoilName, errFlag);
3954 0 : thisFurnace.SuppCoilAirOutletNode = SupHeatCoilOutletNode;
3955 0 : if (errFlag) {
3956 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3957 0 : ErrorsFound = true;
3958 : }
3959 : }
3960 :
3961 : } else {
3962 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3963 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(12), Alphas(12)));
3964 0 : ErrorsFound = true;
3965 : } // IF (Furnace(FurnaceNum)%HeatingCoilType_Num == Coil_HeatingGasOrOtherFuel .OR. &, etc.
3966 :
3967 0 : if (lAlphaBlanks(14)) {
3968 0 : thisFurnace.CondenserNodeNum = 0;
3969 : } else {
3970 0 : thisFurnace.CondenserNodeNum =
3971 0 : NodeInputManager::GetOnlySingleNode(state,
3972 0 : Alphas(14),
3973 : ErrorsFound,
3974 : DataLoopNode::ConnectionObjectType::AirLoopHVACUnitaryHeatPumpWaterToAir,
3975 0 : Alphas(1),
3976 : DataLoopNode::NodeFluidType::Air,
3977 : DataLoopNode::ConnectionType::OutsideAirReference,
3978 : NodeInputManager::CompFluidStream::Primary,
3979 : DataLoopNode::ObjectIsNotParent);
3980 : // need better verification.
3981 0 : if (!OutAirNodeManager::CheckOutAirNodeNumber(state, thisFurnace.CondenserNodeNum)) {
3982 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
3983 0 : ShowContinueError(state, format(" Node name of outdoor dry-bulb temperature sensor not valid outdoor air node= {}", Alphas(14)));
3984 0 : ShowContinueError(state, "...does not appear in an OutdoorAir:NodeList or as an OutdoorAir:Node.");
3985 0 : ErrorsFound = true;
3986 : }
3987 : }
3988 :
3989 0 : thisFurnace.fanPlace = static_cast<HVAC::FanPlace>(getEnumValue(HVAC::fanPlaceNamesUC, Alphas(15)));
3990 0 : assert(thisFurnace.fanPlace != HVAC::FanPlace::Invalid);
3991 :
3992 0 : if (lAlphaBlanks(16)) {
3993 0 : thisFurnace.fanOp = HVAC::FanOp::Cycling;
3994 0 : if (thisFurnace.fanType != HVAC::FanType::OnOff) {
3995 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisFurnace.Name));
3996 0 : ShowContinueError(state, format("{} = {}", cAlphaFields(6), Alphas(6)));
3997 0 : ShowContinueError(state, format("Fan type must be Fan:OnOff when {} = Blank.", cAlphaFields(16)));
3998 0 : ErrorsFound = true;
3999 : }
4000 0 : } else if ((thisFurnace.fanOpModeSched = Sched::GetSchedule(state, Alphas(16))) == nullptr) {
4001 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(16), Alphas(16));
4002 0 : ErrorsFound = true;
4003 : }
4004 :
4005 : // add the Dehumidification Type
4006 0 : if (Util::SameString(Alphas(17), "None") || Util::SameString(Alphas(17), "CoolReheat")) {
4007 0 : AirNodeFound = false;
4008 0 : if (Util::SameString(Alphas(17), "CoolReheat")) {
4009 0 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::CoolReheat;
4010 0 : thisFurnace.Humidistat = true;
4011 0 : if (lAlphaBlanks(17)) {
4012 0 : ShowWarningError(state, format("{} \"{}\"", CurrentModuleObject, Alphas(1)));
4013 0 : ShowContinueError(state,
4014 : "Dehumidification control type is assumed to be None since a supplemental reheat coil has not been "
4015 : "specified and the simulation continues.");
4016 0 : thisFurnace.Humidistat = false;
4017 0 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::None;
4018 : }
4019 : }
4020 0 : if (Util::SameString(Alphas(17), "None")) {
4021 0 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::None;
4022 0 : thisFurnace.Humidistat = false;
4023 : }
4024 0 : if (thisFurnace.Humidistat) {
4025 0 : for (HStatZoneNum = 1; HStatZoneNum <= state.dataZoneCtrls->NumHumidityControlZones; ++HStatZoneNum) {
4026 0 : if (state.dataZoneCtrls->HumidityControlZone(HStatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) continue;
4027 0 : AirNodeFound = true;
4028 : }
4029 0 : if (!AirNodeFound) {
4030 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
4031 0 : ShowContinueError(state, "Did not find Air Node (Zone with Humidistat).");
4032 0 : ShowContinueError(state, format("Specified {} = {}", cAlphaFields(5), Alphas(5)));
4033 0 : ErrorsFound = true;
4034 : }
4035 : }
4036 : } else { // invalid input or blank
4037 0 : if (!lAlphaBlanks(17)) {
4038 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
4039 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(17), Alphas(17)));
4040 0 : ErrorsFound = true;
4041 : } else {
4042 0 : thisFurnace.Humidistat = false;
4043 0 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::None;
4044 : }
4045 : }
4046 :
4047 : // Add fan to component sets array
4048 :
4049 0 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
4050 0 : CompSetFanInlet = Alphas(3);
4051 0 : CompSetCoolInlet = "UNDEFINED";
4052 0 : if (FanInletNode != thisFurnace.FurnaceInletNodeNum) {
4053 0 : ShowSevereError(
4054 0 : state, format("For {} = {}, Mismatch between unitary system inlet node and fan inlet node.", CurrentModuleObject, Alphas(1)));
4055 0 : ShowContinueError(state, "..For \"BlowThrough\" fan, the inlet node name for the HeatPump should match the fan inlet node name.");
4056 0 : ShowContinueError(state, format("..HeatPump Inlet Node = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
4057 0 : ShowContinueError(state, format("..Fan Inlet Node = {}", state.dataLoopNodes->NodeID(FanInletNode)));
4058 0 : ErrorsFound = true;
4059 : }
4060 0 : if (FanOutletNode != CoolingCoilInletNode) {
4061 0 : ShowSevereError(
4062 0 : state, format("For {} = {}, Mismatch between fan outlet node and cooling coil inlet node.", CurrentModuleObject, Alphas(1)));
4063 0 : ShowContinueError(state, "..For \"BlowThrough\" fan, the fan outlet node name must match the cooling coil inlet node name.");
4064 0 : ShowContinueError(state, format("..Fan outlet node = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
4065 0 : ShowContinueError(state, format("..Cooling coil inlet node = {}", state.dataLoopNodes->NodeID(CoolingCoilInletNode)));
4066 0 : ErrorsFound = true;
4067 : }
4068 0 : if (CoolingCoilOutletNode != HeatingCoilInletNode) {
4069 0 : ShowSevereError(state,
4070 0 : format("For {} = {}, Mismatch between cooling coil outlet node and heating coil inlet node.",
4071 : CurrentModuleObject,
4072 : Alphas(1)));
4073 0 : ShowContinueError(state, "..The cooling coil outlet node name must match the heating coil inlet node name.");
4074 0 : ShowContinueError(state, format("..Cooling coil outlet node = {}", state.dataLoopNodes->NodeID(CoolingCoilOutletNode)));
4075 0 : ShowContinueError(state, format("..Heating coil inlet node = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
4076 0 : ErrorsFound = true;
4077 : }
4078 0 : if (HeatingCoilOutletNode != SupHeatCoilInletNode) {
4079 0 : ShowSevereError(state,
4080 0 : format("For {} = {}, Mismatch between heating coil outlet node and supplemental heating coil inlet node.",
4081 : CurrentModuleObject,
4082 : Alphas(1)));
4083 0 : ShowContinueError(
4084 : state,
4085 : "..For \"BlowThrough\" fan, the heating coil outlet node name must match the supplemental heating coil inlet node name.");
4086 0 : ShowContinueError(state,
4087 0 : format("..Heating coil outlet node = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
4088 0 : ShowContinueError(state,
4089 0 : format("..Supplemental heating coil inlet node = {}", state.dataLoopNodes->NodeID(SupHeatCoilInletNode)));
4090 0 : ErrorsFound = true;
4091 : }
4092 0 : if (SupHeatCoilOutletNode != thisFurnace.FurnaceOutletNodeNum) {
4093 0 : ShowSevereError(state,
4094 0 : format("For {} = {}, Mismatch between supplemental heating coil outlet node and HeatPump outlet node.",
4095 : CurrentModuleObject,
4096 : Alphas(1)));
4097 0 : ShowContinueError(state, "..The supplemental heating coil outlet node name must match the HeatPump outlet node name.");
4098 0 : ShowContinueError(state,
4099 0 : format("..Supplemental heating coil outlet node = {}", state.dataLoopNodes->NodeID(SupHeatCoilOutletNode)));
4100 0 : ShowContinueError(
4101 0 : state, format("..HeatPump outlet node = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
4102 0 : ErrorsFound = true;
4103 : }
4104 : } else {
4105 0 : CompSetFanInlet = "UNDEFINED";
4106 0 : CompSetCoolInlet = Alphas(3);
4107 0 : if (CoolingCoilInletNode != thisFurnace.FurnaceInletNodeNum) {
4108 0 : ShowSevereError(state,
4109 0 : format("For {} = {}, Mismatch between unitary system inlet node and cooling coil inlet node.",
4110 : CurrentModuleObject,
4111 : Alphas(1)));
4112 0 : ShowContinueError(
4113 : state, "..For \"DrawThrough\" fan, the inlet node name for the HeatPump should match the cooling coil inlet node name.");
4114 0 : ShowContinueError(state, format("..HeatPump inlet node = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
4115 0 : ShowContinueError(state, format("..Cooling coil inlet node = {}", state.dataLoopNodes->NodeID(CoolingCoilInletNode)));
4116 0 : ErrorsFound = true;
4117 : }
4118 0 : if (CoolingCoilOutletNode != HeatingCoilInletNode) {
4119 0 : ShowSevereError(state,
4120 0 : format("For {} = {}, Mismatch between cooling coil outlet node and heating coil inlet node.",
4121 : CurrentModuleObject,
4122 : Alphas(1)));
4123 0 : ShowContinueError(state, "..The outlet node name for the cooling coil should match the heating coil inlet node name.");
4124 0 : ShowContinueError(state, format("..Cooling coil outlet node = {}", state.dataLoopNodes->NodeID(CoolingCoilOutletNode)));
4125 0 : ShowContinueError(state, format("..Heating coil inlet node = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
4126 0 : ErrorsFound = true;
4127 : }
4128 0 : if (HeatingCoilOutletNode != FanInletNode) {
4129 0 : ShowSevereError(
4130 0 : state, format("For {} = {}, Mismatch between heating coil outlet node and fan inlet node.", CurrentModuleObject, Alphas(1)));
4131 0 : ShowContinueError(state,
4132 : "..For \"DrawThrough\" fan, the outlet node name for the heating coil should match the fan inlet node name.");
4133 0 : ShowContinueError(state, format("..Heating coil outlet node = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
4134 0 : ShowContinueError(state, format("..Fan inlet node = {}", state.dataLoopNodes->NodeID(FanInletNode)));
4135 0 : ErrorsFound = true;
4136 : }
4137 0 : if (FanOutletNode != SupHeatCoilInletNode) {
4138 0 : ShowSevereError(state,
4139 0 : format("For {} = {}, Mismatch between fan outlet node and supplemental heating coil inlet node.",
4140 : CurrentModuleObject,
4141 : Alphas(1)));
4142 0 : ShowContinueError(
4143 : state,
4144 : "..For \"DrawThrough\" fan, the outlet node name for the fan should match the supplemental heating coil inlet node name.");
4145 0 : ShowContinueError(state, format("..Fan outlet node = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
4146 0 : ShowContinueError(state,
4147 0 : format("..Supplemental heating coil inlet node = {}", state.dataLoopNodes->NodeID(SupHeatCoilInletNode)));
4148 0 : ErrorsFound = true;
4149 : }
4150 0 : if (SupHeatCoilOutletNode != thisFurnace.FurnaceOutletNodeNum) {
4151 0 : ShowSevereError(state,
4152 0 : format("For {} = {}, Mismatch between supplemental heating coil outlet node and HeatPump outlet node.",
4153 : CurrentModuleObject,
4154 : Alphas(1)));
4155 0 : ShowContinueError(state, "..The supplemental heating coil outlet node name must match the HeatPump outlet node name.");
4156 0 : ShowContinueError(state,
4157 0 : format("..Supplemental heating coil outlet node = {}", state.dataLoopNodes->NodeID(SupHeatCoilOutletNode)));
4158 0 : ShowContinueError(
4159 0 : state, format("..HeatPump outlet node = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
4160 0 : ErrorsFound = true;
4161 : }
4162 : }
4163 : // (Set up validation here for the fan or cooling coil inlet?)
4164 0 : BranchNodeConnections::SetUpCompSets(state, CurrentModuleObject, Alphas(1), Alphas(6), Alphas(7), CompSetFanInlet, "UNDEFINED");
4165 :
4166 : // Add DX heating coil to component sets array
4167 0 : BranchNodeConnections::SetUpCompSets(state, CurrentModuleObject, Alphas(1), Alphas(8), Alphas(9), "UNDEFINED", "UNDEFINED");
4168 :
4169 : // Add DX cooling coil to component sets array
4170 0 : BranchNodeConnections::SetUpCompSets(state, CurrentModuleObject, Alphas(1), Alphas(10), Alphas(11), CompSetCoolInlet, "UNDEFINED");
4171 :
4172 : // Add supplemental heating coil to component sets array
4173 0 : BranchNodeConnections::SetUpCompSets(state, CurrentModuleObject, Alphas(1), Alphas(12), Alphas(13), "UNDEFINED", Alphas(4));
4174 :
4175 : // Set the Design Fan Volume Flow Rate
4176 0 : thisFurnace.ActualFanVolFlowRate = state.dataFans->fans(thisFurnace.FanIndex)->maxAirFlowRate;
4177 :
4178 : // CR8094 - simple water to air heat pump MUST operate at the same flow rate specified in the coil objects
4179 : // Furnace(FurnaceNum)%DesignFanVolFlowRate = Numbers(1)
4180 : // Furnace(FurnaceNum)%MaxHeatAirVolFlow = Furnace(FurnaceNum)%DesignFanVolFlowRate
4181 : // Furnace(FurnaceNum)%MaxCoolAirVolFlow = Furnace(FurnaceNum)%DesignFanVolFlowRate
4182 :
4183 : // parameter estimate model only specifies air flow rate in parent object
4184 0 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHP) {
4185 0 : thisFurnace.MaxHeatAirVolFlow = Numbers(1);
4186 0 : thisFurnace.MaxCoolAirVolFlow = Numbers(1);
4187 : // simple HP model specifies air flow rate in both the parent and child coils. Use coil air flow rates.
4188 : // simple HP model air flow rate input will not be used.
4189 0 : } else if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPSimple) {
4190 0 : errFlag = false;
4191 0 : thisFurnace.MaxHeatAirVolFlow = WaterToAirHeatPumpSimple::GetCoilAirFlowRate(state, HeatingCoilType, HeatingCoilName, errFlag);
4192 0 : thisFurnace.MaxCoolAirVolFlow = WaterToAirHeatPumpSimple::GetCoilAirFlowRate(state, CoolingCoilType, CoolingCoilName, errFlag);
4193 0 : if (errFlag) {
4194 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
4195 0 : ErrorsFound = true;
4196 : }
4197 0 : } else if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPVSEquationFit) {
4198 0 : errFlag = false;
4199 0 : thisFurnace.MaxHeatAirVolFlow = VariableSpeedCoils::GetCoilAirFlowRateVariableSpeed(state, HeatingCoilType, HeatingCoilName, errFlag);
4200 0 : thisFurnace.MaxCoolAirVolFlow = VariableSpeedCoils::GetCoilAirFlowRateVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
4201 0 : if (errFlag) {
4202 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
4203 0 : ErrorsFound = true;
4204 : }
4205 : }
4206 :
4207 0 : thisFurnace.MaxNoCoolHeatAirVolFlow = min(thisFurnace.MaxHeatAirVolFlow, thisFurnace.MaxCoolAirVolFlow);
4208 0 : if (thisFurnace.MaxHeatAirVolFlow != DataSizing::AutoSize && thisFurnace.MaxCoolAirVolFlow != DataSizing::AutoSize) {
4209 0 : thisFurnace.DesignFanVolFlowRate = max(thisFurnace.MaxHeatAirVolFlow, thisFurnace.MaxCoolAirVolFlow);
4210 : } else {
4211 0 : thisFurnace.DesignFanVolFlowRate = DataSizing::AutoSize;
4212 : }
4213 :
4214 0 : thisFurnace.AirFlowControl = AirFlowControlConstFan::UseCompressorOnFlow;
4215 :
4216 0 : if (thisFurnace.ActualFanVolFlowRate != DataSizing::AutoSize && thisFurnace.DesignFanVolFlowRate != DataSizing::AutoSize) {
4217 0 : if (thisFurnace.DesignFanVolFlowRate > thisFurnace.ActualFanVolFlowRate) {
4218 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
4219 0 : ShowContinueError(state, "... has a Cooling or Heating Air Flow Rate > Max Fan Volume Flow Rate, should be <=.");
4220 0 : ShowContinueError(state,
4221 0 : format("... Entered value={:.2R}... Fan [{}:{}] Max Value={:.2R}",
4222 0 : thisFurnace.DesignFanVolFlowRate,
4223 0 : HVAC::fanTypeNames[(int)thisFurnace.fanType],
4224 : FanName,
4225 0 : thisFurnace.ActualFanVolFlowRate));
4226 : }
4227 : }
4228 0 : if (thisFurnace.ActualFanVolFlowRate != DataSizing::AutoSize && thisFurnace.DesignFanVolFlowRate != DataSizing::AutoSize) {
4229 0 : if (thisFurnace.DesignFanVolFlowRate <= 0.0) {
4230 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
4231 0 : ShowContinueError(state, "... has a Design Fan Flow Rate <= 0.0, it must be >0.0");
4232 0 : ShowContinueError(state, format("... Entered value={:.2R}", thisFurnace.DesignFanVolFlowRate));
4233 0 : ErrorsFound = true;
4234 : }
4235 : }
4236 :
4237 : // Set the heat pump heating coil capacity
4238 : // Get from coil module.
4239 0 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHP) {
4240 0 : errFlag = false;
4241 0 : thisFurnace.DesignHeatingCapacity = WaterToAirHeatPump::GetCoilCapacity(state, HeatingCoilType, HeatingCoilName, errFlag);
4242 0 : if (errFlag) {
4243 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
4244 0 : ErrorsFound = true;
4245 : }
4246 0 : } else if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPSimple) {
4247 0 : errFlag = false;
4248 0 : thisFurnace.DesignHeatingCapacity = WaterToAirHeatPumpSimple::GetCoilCapacity(state, HeatingCoilType, HeatingCoilName, errFlag);
4249 0 : if (errFlag) {
4250 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
4251 0 : ErrorsFound = true;
4252 : }
4253 0 : } else if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPVSEquationFit) {
4254 0 : errFlag = false;
4255 0 : thisFurnace.DesignHeatingCapacity =
4256 0 : VariableSpeedCoils::GetCoilCapacityVariableSpeed(state, HeatingCoilType, HeatingCoilName, errFlag);
4257 0 : if (errFlag) {
4258 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
4259 0 : ErrorsFound = true;
4260 : }
4261 : }
4262 : // Set the heat pump heating coil convergence
4263 0 : thisFurnace.HeatingConvergenceTolerance = Numbers(2);
4264 : // Set the heat pump cooling coil capacity (Total capacity)
4265 : // Get from coil module.
4266 0 : if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingWaterToAirHP) {
4267 0 : errFlag = false;
4268 0 : thisFurnace.DesignCoolingCapacity = WaterToAirHeatPump::GetCoilCapacity(state, CoolingCoilType, CoolingCoilName, errFlag);
4269 0 : if (errFlag) {
4270 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
4271 0 : ErrorsFound = true;
4272 : }
4273 0 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingWaterToAirHPSimple) {
4274 0 : errFlag = false;
4275 0 : thisFurnace.DesignCoolingCapacity = WaterToAirHeatPumpSimple::GetCoilCapacity(state, CoolingCoilType, CoolingCoilName, errFlag);
4276 0 : if (errFlag) {
4277 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
4278 0 : ErrorsFound = true;
4279 : }
4280 0 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingWaterToAirHPVSEquationFit) {
4281 0 : errFlag = false;
4282 0 : thisFurnace.DesignCoolingCapacity =
4283 0 : VariableSpeedCoils::GetCoilCapacityVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
4284 0 : if (errFlag) {
4285 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
4286 0 : ErrorsFound = true;
4287 : }
4288 : }
4289 : // Set the heat pump cooling coil convergence
4290 0 : thisFurnace.CoolingConvergenceTolerance = Numbers(3);
4291 :
4292 : // Set the heatpump design supplemental heating capacity
4293 : // Get from coil module.
4294 :
4295 : // Set the heatpump max outlet temperature
4296 0 : thisFurnace.DesignMaxOutletTemp = Numbers(4);
4297 :
4298 : // Set maximum supply air temperature for supplemental heating coil
4299 0 : thisFurnace.MaxOATSuppHeat = Numbers(5);
4300 0 : OutputReportPredefined::PreDefTableEntry(
4301 0 : state, state.dataOutRptPredefined->pdchDXHeatCoilSuppHiT, HeatingCoilName, thisFurnace.MaxOATSuppHeat);
4302 :
4303 : // set minimum outdoor temperature for compressor operation
4304 0 : SetMinOATCompressor(state, FurnaceNum, cCurrentModuleObject, ErrorsFound);
4305 :
4306 : } // End of the Unitary System WaterToAirHeatPump Loop
4307 :
4308 2 : Alphas.deallocate();
4309 2 : Numbers.deallocate();
4310 :
4311 2 : if (ErrorsFound) {
4312 0 : ShowFatalError(state, "Errors found in getting Furnace or Unitary System input.");
4313 : }
4314 :
4315 2 : for (int HeatOnlyNum = 1; HeatOnlyNum <= NumHeatOnly; ++HeatOnlyNum) {
4316 0 : FurnaceNum = HeatOnlyNum;
4317 0 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
4318 : // Setup Report variables for the Furnace that are not reported in the components themselves
4319 0 : SetupOutputVariable(state,
4320 : "Unitary System Fan Part Load Ratio",
4321 : Constant::Units::None,
4322 0 : thisFurnace.FanPartLoadRatio,
4323 : OutputProcessor::TimeStepType::System,
4324 : OutputProcessor::StoreType::Average,
4325 0 : thisFurnace.Name);
4326 0 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
4327 0 : SetupEMSActuator(state,
4328 : "AirLoopHVAC:Unitary:Furnace:HeatOnly",
4329 : thisFurnace.Name,
4330 : "Autosized Supply Air Flow Rate",
4331 : "[m3/s]",
4332 0 : thisFurnace.DesignFanVolFlowRateEMSOverrideOn,
4333 0 : thisFurnace.DesignFanVolFlowRateEMSOverrideValue);
4334 : }
4335 : }
4336 :
4337 2 : for (int UnitaryHeatOnlyNum = NumHeatOnly + 1; UnitaryHeatOnlyNum <= NumHeatOnly + NumUnitaryHeatOnly; ++UnitaryHeatOnlyNum) {
4338 0 : FurnaceNum = UnitaryHeatOnlyNum;
4339 0 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
4340 : // Setup Report variables for Unitary System that are not reported in the components themselves
4341 0 : SetupOutputVariable(state,
4342 : "Unitary System Fan Part Load Ratio",
4343 : Constant::Units::None,
4344 0 : thisFurnace.FanPartLoadRatio,
4345 : OutputProcessor::TimeStepType::System,
4346 : OutputProcessor::StoreType::Average,
4347 0 : thisFurnace.Name);
4348 0 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
4349 0 : SetupEMSActuator(state,
4350 : "AirLoopHVAC:UnitaryHeatOnly",
4351 : thisFurnace.Name,
4352 : "Autosized Supply Air Flow Rate",
4353 : "[m3/s]",
4354 0 : thisFurnace.DesignFanVolFlowRateEMSOverrideOn,
4355 0 : thisFurnace.DesignFanVolFlowRateEMSOverrideValue);
4356 : }
4357 : }
4358 :
4359 2 : for (int HeatCoolNum = NumHeatOnly + NumUnitaryHeatOnly + 1; HeatCoolNum <= NumHeatOnly + NumUnitaryHeatOnly + NumHeatCool; ++HeatCoolNum) {
4360 0 : FurnaceNum = HeatCoolNum;
4361 0 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
4362 : // Setup Report variables for the Furnace that are not reported in the components themselves
4363 0 : SetupOutputVariable(state,
4364 : "Unitary System Fan Part Load Ratio",
4365 : Constant::Units::None,
4366 0 : thisFurnace.FanPartLoadRatio,
4367 : OutputProcessor::TimeStepType::System,
4368 : OutputProcessor::StoreType::Average,
4369 0 : thisFurnace.Name);
4370 0 : SetupOutputVariable(state,
4371 : "Unitary System Compressor Part Load Ratio",
4372 : Constant::Units::None,
4373 0 : thisFurnace.CompPartLoadRatio,
4374 : OutputProcessor::TimeStepType::System,
4375 : OutputProcessor::StoreType::Average,
4376 0 : thisFurnace.Name);
4377 :
4378 0 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
4379 0 : SetupEMSActuator(state,
4380 : "AirLoopHVAC:Unitary:Furnace:HeatCool",
4381 : thisFurnace.Name,
4382 : "Autosized Supply Air Flow Rate",
4383 : "[m3/s]",
4384 0 : thisFurnace.DesignFanVolFlowRateEMSOverrideOn,
4385 0 : thisFurnace.DesignFanVolFlowRateEMSOverrideValue);
4386 0 : SetupEMSActuator(state,
4387 : "AirLoopHVAC:Unitary:Furnace:HeatCool",
4388 : thisFurnace.Name,
4389 : "Autosized Supply Air Flow Rate During Cooling Operation",
4390 : "[m3/s]",
4391 0 : thisFurnace.MaxCoolAirVolFlowEMSOverrideOn,
4392 0 : thisFurnace.MaxCoolAirVolFlowEMSOverrideValue);
4393 0 : SetupEMSActuator(state,
4394 : "AirLoopHVAC:Unitary:Furnace:HeatCool",
4395 : thisFurnace.Name,
4396 : "Autosized Supply Air Flow Rate During Heating Operation",
4397 : "[m3/s]",
4398 0 : thisFurnace.MaxHeatAirVolFlowEMSOverrideOn,
4399 0 : thisFurnace.MaxHeatAirVolFlowEMSOverrideValue);
4400 0 : SetupEMSActuator(state,
4401 : "AirLoopHVAC:Unitary:Furnace:HeatCool",
4402 : thisFurnace.Name,
4403 : "Autosized Supply Air Flow Rate During No Heating or Cooling Operation",
4404 : "[m3/s]",
4405 0 : thisFurnace.MaxNoCoolHeatAirVolFlowEMSOverrideOn,
4406 0 : thisFurnace.MaxNoCoolHeatAirVolFlowEMSOverrideValue);
4407 : }
4408 : }
4409 :
4410 2 : for (int UnitaryHeatCoolNum = NumHeatOnly + NumHeatCool + NumUnitaryHeatOnly + 1;
4411 2 : UnitaryHeatCoolNum <= NumHeatOnly + NumHeatCool + NumUnitaryHeatOnly + NumUnitaryHeatCool;
4412 : ++UnitaryHeatCoolNum) {
4413 0 : FurnaceNum = UnitaryHeatCoolNum;
4414 0 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
4415 : // Setup Report variables for Unitary System that are not reported in the components themselves
4416 0 : SetupOutputVariable(state,
4417 : "Unitary System Fan Part Load Ratio",
4418 : Constant::Units::None,
4419 0 : thisFurnace.FanPartLoadRatio,
4420 : OutputProcessor::TimeStepType::System,
4421 : OutputProcessor::StoreType::Average,
4422 0 : thisFurnace.Name);
4423 0 : SetupOutputVariable(state,
4424 : "Unitary System Compressor Part Load Ratio",
4425 : Constant::Units::None,
4426 0 : thisFurnace.CompPartLoadRatio,
4427 : OutputProcessor::TimeStepType::System,
4428 : OutputProcessor::StoreType::Average,
4429 0 : thisFurnace.Name);
4430 0 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
4431 0 : SetupEMSActuator(state,
4432 : "AirLoopHVAC:UnitaryHeatCool",
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:UnitaryHeatCool",
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:UnitaryHeatCool",
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:UnitaryHeatCool",
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 4 : for (int HeatPumpNum = NumHeatOnly + NumHeatCool + NumUnitaryHeatOnly + NumUnitaryHeatCool + 1;
4463 4 : HeatPumpNum <= state.dataFurnaces->NumFurnaces - NumWaterToAirHeatPump;
4464 : ++HeatPumpNum) {
4465 2 : FurnaceNum = HeatPumpNum;
4466 2 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
4467 : // Setup Report variables for Unitary System that are not reported in the components themselves
4468 4 : SetupOutputVariable(state,
4469 : "Unitary System Fan Part Load Ratio",
4470 : Constant::Units::None,
4471 2 : thisFurnace.FanPartLoadRatio,
4472 : OutputProcessor::TimeStepType::System,
4473 : OutputProcessor::StoreType::Average,
4474 2 : thisFurnace.Name);
4475 4 : SetupOutputVariable(state,
4476 : "Unitary System Compressor Part Load Ratio",
4477 : Constant::Units::None,
4478 2 : thisFurnace.CompPartLoadRatio,
4479 : OutputProcessor::TimeStepType::System,
4480 : OutputProcessor::StoreType::Average,
4481 2 : thisFurnace.Name);
4482 4 : SetupOutputVariable(state,
4483 : "Unitary System Dehumidification Induced Heating Demand Rate",
4484 : Constant::Units::W,
4485 2 : thisFurnace.DehumidInducedHeatingDemandRate,
4486 : OutputProcessor::TimeStepType::System,
4487 : OutputProcessor::StoreType::Average,
4488 2 : thisFurnace.Name);
4489 :
4490 2 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
4491 0 : SetupEMSActuator(state,
4492 : "AirLoopHVAC:UnitaryHeatPump:AirToAir",
4493 : thisFurnace.Name,
4494 : "Autosized Supply Air Flow Rate",
4495 : "[m3/s]",
4496 0 : thisFurnace.DesignFanVolFlowRateEMSOverrideOn,
4497 0 : thisFurnace.DesignFanVolFlowRateEMSOverrideValue);
4498 : }
4499 : }
4500 :
4501 2 : for (int HeatPumpNum = NumHeatOnly + NumHeatCool + NumUnitaryHeatOnly + NumUnitaryHeatCool + NumHeatPump + 1;
4502 2 : HeatPumpNum <= state.dataFurnaces->NumFurnaces;
4503 : ++HeatPumpNum) {
4504 0 : FurnaceNum = HeatPumpNum;
4505 0 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
4506 : // Setup Report variables for Unitary System that are not reported in the components themselves
4507 0 : SetupOutputVariable(state,
4508 : "Unitary System Fan Part Load Ratio",
4509 : Constant::Units::None,
4510 0 : thisFurnace.FanPartLoadRatio,
4511 : OutputProcessor::TimeStepType::System,
4512 : OutputProcessor::StoreType::Average,
4513 0 : thisFurnace.Name);
4514 0 : SetupOutputVariable(state,
4515 : "Unitary System Compressor Part Load Ratio",
4516 : Constant::Units::None,
4517 0 : thisFurnace.CompPartLoadRatio,
4518 : OutputProcessor::TimeStepType::System,
4519 : OutputProcessor::StoreType::Average,
4520 0 : thisFurnace.Name);
4521 0 : SetupOutputVariable(state,
4522 : "Unitary System Requested Sensible Cooling Rate",
4523 : Constant::Units::W,
4524 0 : thisFurnace.CoolingCoilSensDemand,
4525 : OutputProcessor::TimeStepType::System,
4526 : OutputProcessor::StoreType::Average,
4527 0 : thisFurnace.Name);
4528 0 : SetupOutputVariable(state,
4529 : "Unitary System Requested Latent Cooling Rate",
4530 : Constant::Units::W,
4531 0 : thisFurnace.CoolingCoilLatentDemand,
4532 : OutputProcessor::TimeStepType::System,
4533 : OutputProcessor::StoreType::Average,
4534 0 : thisFurnace.Name);
4535 0 : SetupOutputVariable(state,
4536 : "Unitary System Requested Heating Rate",
4537 : Constant::Units::W,
4538 0 : thisFurnace.HeatingCoilSensDemand,
4539 : OutputProcessor::TimeStepType::System,
4540 : OutputProcessor::StoreType::Average,
4541 0 : thisFurnace.Name);
4542 0 : SetupOutputVariable(state,
4543 : "Unitary System Dehumidification Induced Heating Demand Rate",
4544 : Constant::Units::W,
4545 0 : thisFurnace.DehumidInducedHeatingDemandRate,
4546 : OutputProcessor::TimeStepType::System,
4547 : OutputProcessor::StoreType::Average,
4548 0 : thisFurnace.Name);
4549 :
4550 0 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
4551 0 : SetupEMSActuator(state,
4552 : "AirLoopHVAC:UnitaryHeatPump:WaterToAir",
4553 : thisFurnace.Name,
4554 : "Autosized Supply Air Flow Rate",
4555 : "[m3/s]",
4556 0 : thisFurnace.DesignFanVolFlowRateEMSOverrideOn,
4557 0 : thisFurnace.DesignFanVolFlowRateEMSOverrideValue);
4558 : }
4559 : }
4560 :
4561 2 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
4562 0 : for (FurnaceNum = 1; FurnaceNum <= state.dataFurnaces->NumFurnaces; ++FurnaceNum) {
4563 0 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
4564 0 : SetupEMSInternalVariable(state, "Unitary HVAC Design Heating Capacity", thisFurnace.Name, "[W]", thisFurnace.DesignHeatingCapacity);
4565 0 : SetupEMSInternalVariable(state, "Unitary HVAC Design Cooling Capacity", thisFurnace.Name, "[W]", thisFurnace.DesignCoolingCapacity);
4566 0 : SetupEMSActuator(state,
4567 : "Unitary HVAC",
4568 : thisFurnace.Name,
4569 : "Sensible Load Request",
4570 : "[W]",
4571 0 : thisFurnace.EMSOverrideSensZoneLoadRequest,
4572 0 : thisFurnace.EMSSensibleZoneLoadValue);
4573 0 : SetupEMSActuator(state,
4574 : "Unitary HVAC",
4575 : thisFurnace.Name,
4576 : "Moisture Load Request",
4577 : "[W]",
4578 0 : thisFurnace.EMSOverrideMoistZoneLoadRequest,
4579 0 : thisFurnace.EMSMoistureZoneLoadValue);
4580 : }
4581 : }
4582 : bool anyRan;
4583 2 : EMSManager::ManageEMS(state, EMSManager::EMSCallFrom::ComponentGetInput, anyRan, ObjexxFCL::Optional_int_const());
4584 2 : }
4585 :
4586 : // End of Get Input subroutines for this Module
4587 : //******************************************************************************
4588 :
4589 : // Beginning Initialization Section of the Module
4590 : //******************************************************************************
4591 :
4592 15222 : void InitFurnace(EnergyPlusData &state,
4593 : int const FurnaceNum, // index to Furnace
4594 : int const AirLoopNum, // index to air loop
4595 : Real64 &OnOffAirFlowRatio, // ratio of on to off air mass flow rate
4596 : HVAC::FanOp &fanOp, // fan operating mode
4597 : Real64 &ZoneLoad, // zone sensible load to be met (modified here as needed) (W)
4598 : Real64 &MoistureLoad, // zone moisture load (W)
4599 : bool const FirstHVACIteration // TRUE if first HVAC iteration
4600 : )
4601 : {
4602 :
4603 : // SUBROUTINE INFORMATION:
4604 : // AUTHOR Richard J. Liesen
4605 : // DATE WRITTEN Feb 2001
4606 : // MODIFIED Oct 2001, Richard Raustad
4607 : // Sep 2008, R. Raustad - revised logic to determine load to be met
4608 : // Bereket Nigusse, June 2010 - added a procedure to calculate supply air flow fraction
4609 : // through controlled zone
4610 : // Bo Shen, March 2012 - for VS WSHP
4611 : // Bo Shen, ORNL, July 2012 - added variable-speed air source heat pump cooling and heating coils, using curve-fits
4612 :
4613 : // PURPOSE OF THIS SUBROUTINE:
4614 : // This subroutine is for initializations of the Furnace Components.
4615 :
4616 : // METHODOLOGY EMPLOYED:
4617 : // Uses the status flags to trigger initializations.
4618 : // The HeatCool furnace/unitarysystem and air-to-air heat pump may have alternate air flow rates
4619 : // in cooling, heating, and when no cooling or heating is needed. Set up the coil (comp) ON and OFF
4620 : // air flow rates during InitFurnace. Use these flow rates during the Calc routines to set the
4621 : // average mass flow rates based on PLR.
4622 :
4623 : // SUBROUTINE PARAMETER DEFINITIONS:
4624 15222 : Real64 constexpr Small5WLoad(5.0);
4625 15222 : std::string_view constexpr RoutineName("InitFurnace");
4626 :
4627 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4628 : bool errFlag; // error flag for mining functions
4629 : Real64 QZnReq; // furnace load based on control zone frac (W)
4630 : Real64 PartLoadRatio; // furnace part-load ratio
4631 : Real64 SensibleOutput; // no load sensible output (coils off) (W)
4632 : Real64 LatentOutput; // no load latent output (coils off) (W)
4633 : Real64 QToCoolSetPt; // sensible load to cooling setpoint (W)
4634 : Real64 QToHeatSetPt; // sensible load to heating setpoint (W)
4635 : // calculation (kg/kg)
4636 : Real64 DeltaMassRate; // Difference of mass flow rate between
4637 : // inlet node and system outlet node
4638 : Real64 MassFlowRate; // mass flow rate to calculate loss
4639 :
4640 15222 : Real64 SumOfMassFlowRateMax(0.0); // the sum of mass flow rates at inlet to zones in an airloop
4641 15222 : Real64 CntrlZoneTerminalUnitMassFlowRateMax(0.0); // Maximum mass flow rate through controlled zone terminal unit
4642 :
4643 15222 : bool ErrorsFound(false); // flag returned from mining call
4644 15222 : Real64 mdot(0.0); // local temporary for mass flow rate (kg/s)
4645 15222 : Real64 rho(0.0); // local for fluid density
4646 15222 : Real64 SteamDensity(0.0); // density of steam at 100C, used for steam heating coils
4647 15222 : Real64 CoilMaxVolFlowRate(0.0); // coil fluid maximum volume flow rate
4648 15222 : Real64 QActual(0.0); // coil actual capacity
4649 15222 : Real64 SUPHEATERLOAD(0.0); // SUPPLEMENTAL HEATER LOAD
4650 : Real64 RhoAir; // Air density at InNode
4651 : Furnaces::ModeOfOperation OperatingMode; // track cooling, heating, and no cooling or heating modes
4652 : Furnaces::ModeOfOperation OperatingModeMinusOne;
4653 : Furnaces::ModeOfOperation OperatingModeMinusTwo;
4654 : bool Oscillate; // detection of oscillating operating modes
4655 :
4656 15222 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
4657 15222 : int InNode = thisFurnace.FurnaceInletNodeNum;
4658 15222 : int OutNode = thisFurnace.FurnaceOutletNodeNum;
4659 :
4660 15222 : if (state.dataFurnaces->InitFurnaceMyOneTimeFlag) {
4661 : // initialize the environment and sizing flags
4662 2 : state.dataFurnaces->MyEnvrnFlag.allocate(state.dataFurnaces->NumFurnaces);
4663 2 : state.dataFurnaces->MySizeFlag.allocate(state.dataFurnaces->NumFurnaces);
4664 2 : state.dataFurnaces->MySecondOneTimeFlag.allocate(state.dataFurnaces->NumFurnaces);
4665 2 : state.dataFurnaces->MyFanFlag.allocate(state.dataFurnaces->NumFurnaces);
4666 2 : state.dataFurnaces->MyCheckFlag.allocate(state.dataFurnaces->NumFurnaces);
4667 2 : state.dataFurnaces->MyFlowFracFlag.allocate(state.dataFurnaces->NumFurnaces);
4668 2 : state.dataFurnaces->MyPlantScanFlag.allocate(state.dataFurnaces->NumFurnaces);
4669 2 : state.dataFurnaces->MySuppCoilPlantScanFlag.allocate(state.dataFurnaces->NumFurnaces);
4670 2 : state.dataFurnaces->MyEnvrnFlag = true;
4671 2 : state.dataFurnaces->MySizeFlag = true;
4672 2 : state.dataFurnaces->MySecondOneTimeFlag = true;
4673 2 : state.dataFurnaces->MyFanFlag = true;
4674 2 : state.dataFurnaces->MyCheckFlag = true;
4675 2 : state.dataFurnaces->MyFlowFracFlag = true;
4676 2 : state.dataFurnaces->InitFurnaceMyOneTimeFlag = false;
4677 2 : state.dataFurnaces->MyPlantScanFlag = true;
4678 2 : state.dataFurnaces->MySuppCoilPlantScanFlag = true;
4679 : }
4680 :
4681 15222 : if (state.dataGlobal->BeginEnvrnFlag && state.dataFurnaces->MyAirLoopPass) {
4682 6 : state.dataFurnaces->AirLoopPass = 0;
4683 6 : state.dataFurnaces->MyAirLoopPass = false;
4684 : }
4685 15222 : if (!state.dataGlobal->BeginEnvrnFlag) {
4686 15136 : state.dataFurnaces->MyAirLoopPass = true;
4687 : }
4688 :
4689 15222 : ++state.dataFurnaces->AirLoopPass;
4690 15222 : if (state.dataFurnaces->AirLoopPass > 2) state.dataFurnaces->AirLoopPass = 1;
4691 :
4692 15222 : if (!state.dataGlobal->SysSizingCalc && state.dataFurnaces->MySizeFlag(FurnaceNum)) {
4693 : // for each furnace, do the sizing once.
4694 2 : SizeFurnace(state, FurnaceNum, FirstHVACIteration);
4695 2 : thisFurnace.ControlZoneMassFlowFrac = 1.0;
4696 :
4697 2 : state.dataFurnaces->MySizeFlag(FurnaceNum) = false;
4698 : // Pass the fan cycling schedule index up to the air loop. Set the air loop unitary system flag.
4699 2 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).cycFanSched = thisFurnace.fanOpModeSched;
4700 2 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).UnitarySys = true;
4701 : // RR this is wrong, Op mode needs to be updated each time atep
4702 2 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).fanOp = thisFurnace.fanOp;
4703 :
4704 : // Check that heat pump heating capacity is within 20% of cooling capacity
4705 2 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir) {
4706 2 : if (std::abs(thisFurnace.DesignCoolingCapacity - thisFurnace.DesignHeatingCapacity) / thisFurnace.DesignCoolingCapacity > 0.2) {
4707 0 : ShowWarningError(state,
4708 0 : format("{} \"{}\" heating capacity is disproportionate (> 20% different) to total cooling capacity",
4709 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
4710 0 : thisFurnace.Name));
4711 : }
4712 : }
4713 : }
4714 :
4715 15222 : if (!state.dataGlobal->DoingSizing && state.dataFurnaces->MySecondOneTimeFlag(FurnaceNum)) {
4716 : // sizing all done. check fan air flow rates
4717 4 : thisFurnace.ActualFanVolFlowRate = state.dataFans->fans(thisFurnace.FanIndex)->maxAirFlowRate;
4718 4 : if (thisFurnace.ActualFanVolFlowRate != DataSizing::AutoSize) {
4719 2 : if (thisFurnace.DesignFanVolFlowRate > thisFurnace.ActualFanVolFlowRate) {
4720 0 : ShowWarningError(state,
4721 0 : format("{}={} has a Design Fan Volume Flow Rate > Max Fan Volume Flow Rate, should be <=",
4722 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
4723 0 : thisFurnace.Name));
4724 0 : ShowContinueError(state,
4725 0 : format("... Entered value={:.2R}... Fan [{}] Max Value={:.2R}",
4726 0 : thisFurnace.DesignFanVolFlowRate,
4727 0 : HVAC::fanTypeNames[(int)thisFurnace.fanType],
4728 0 : thisFurnace.ActualFanVolFlowRate));
4729 : }
4730 2 : if (thisFurnace.DesignFanVolFlowRate <= 0.0) {
4731 0 : ShowSevereError(state,
4732 0 : format("{}={} has a Design Fan Volume Flow Rate <= 0.0, it must be >0.0",
4733 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
4734 0 : thisFurnace.Name));
4735 0 : ShowContinueError(state, format("... Entered value={:.2R}", thisFurnace.DesignFanVolFlowRate));
4736 : }
4737 :
4738 2 : state.dataFurnaces->MySecondOneTimeFlag(FurnaceNum) = false;
4739 : }
4740 : }
4741 :
4742 : // Scan hot water and steam heating coil plant components for one time initializations
4743 15222 : if (state.dataFurnaces->MyPlantScanFlag(FurnaceNum) && allocated(state.dataPlnt->PlantLoop)) {
4744 2 : if ((thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWater) || (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingSteam)) {
4745 :
4746 0 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWater) {
4747 :
4748 0 : errFlag = false;
4749 0 : PlantUtilities::ScanPlantLoopsForObject(state,
4750 : thisFurnace.HeatingCoilName,
4751 : DataPlant::PlantEquipmentType::CoilWaterSimpleHeating,
4752 0 : thisFurnace.plantLoc,
4753 : errFlag,
4754 : _,
4755 : _,
4756 : _,
4757 : _,
4758 : _);
4759 0 : if (errFlag) {
4760 0 : ShowFatalError(state, "InitFurnace: Program terminated for previous conditions.");
4761 : }
4762 0 : thisFurnace.MaxHeatCoilFluidFlow =
4763 0 : WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", thisFurnace.HeatingCoilName, ErrorsFound);
4764 0 : if (thisFurnace.MaxHeatCoilFluidFlow > 0.0) {
4765 : rho =
4766 0 : state.dataPlnt->PlantLoop(thisFurnace.plantLoc.loopNum).glycol->getDensity(state, Constant::HWInitConvTemp, RoutineName);
4767 0 : thisFurnace.MaxHeatCoilFluidFlow *= rho;
4768 : }
4769 0 : } else if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingSteam) {
4770 :
4771 0 : errFlag = false;
4772 0 : PlantUtilities::ScanPlantLoopsForObject(state,
4773 : thisFurnace.HeatingCoilName,
4774 : DataPlant::PlantEquipmentType::CoilSteamAirHeating,
4775 0 : thisFurnace.plantLoc,
4776 : errFlag,
4777 : _,
4778 : _,
4779 : _,
4780 : _,
4781 : _);
4782 0 : if (errFlag) {
4783 0 : ShowFatalError(state, "InitFurnace: Program terminated for previous conditions.");
4784 : }
4785 0 : thisFurnace.MaxHeatCoilFluidFlow = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.HeatingCoilIndex, ErrorsFound);
4786 0 : if (thisFurnace.MaxHeatCoilFluidFlow > 0.0) {
4787 0 : SteamDensity = Fluid::GetSteam(state)->getSatDensity(state, state.dataFurnaces->TempSteamIn, 1.0, RoutineName);
4788 0 : thisFurnace.MaxHeatCoilFluidFlow *= SteamDensity;
4789 : }
4790 : }
4791 : // fill outlet node for coil
4792 0 : thisFurnace.CoilOutletNode = DataPlant::CompData::getPlantComponent(state, thisFurnace.plantLoc).NodeNumOut;
4793 0 : state.dataFurnaces->MyPlantScanFlag(FurnaceNum) = false;
4794 : } else { // pthp not connected to plant
4795 2 : state.dataFurnaces->MyPlantScanFlag(FurnaceNum) = false;
4796 : }
4797 15220 : } else if (state.dataFurnaces->MyPlantScanFlag(FurnaceNum) && !state.dataGlobal->AnyPlantInModel) {
4798 0 : state.dataFurnaces->MyPlantScanFlag(FurnaceNum) = false;
4799 : }
4800 :
4801 : // Scan Supplemental hot water and steam heating coil plant components for one time initializations
4802 15222 : if (state.dataFurnaces->MySuppCoilPlantScanFlag(FurnaceNum) && allocated(state.dataPlnt->PlantLoop)) {
4803 2 : if ((thisFurnace.SuppHeatCoilType_Num == HVAC::Coil_HeatingWater) || (thisFurnace.SuppHeatCoilType_Num == HVAC::Coil_HeatingSteam)) {
4804 :
4805 0 : if (thisFurnace.SuppHeatCoilType_Num == HVAC::Coil_HeatingWater) {
4806 0 : errFlag = false;
4807 0 : PlantUtilities::ScanPlantLoopsForObject(state,
4808 : thisFurnace.SuppHeatCoilName,
4809 : DataPlant::PlantEquipmentType::CoilWaterSimpleHeating,
4810 0 : thisFurnace.SuppPlantLoc,
4811 : errFlag,
4812 : _,
4813 : _,
4814 : _,
4815 : _,
4816 : _);
4817 0 : if (errFlag) {
4818 0 : ShowFatalError(state, "InitFurnace: Program terminated for previous conditions.");
4819 : }
4820 0 : thisFurnace.MaxSuppCoilFluidFlow =
4821 0 : WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", thisFurnace.SuppHeatCoilName, ErrorsFound);
4822 0 : if (thisFurnace.MaxSuppCoilFluidFlow > 0.0) {
4823 0 : rho = state.dataPlnt->PlantLoop(thisFurnace.SuppPlantLoc.loopNum)
4824 0 : .glycol->getDensity(state, Constant::HWInitConvTemp, RoutineName);
4825 0 : thisFurnace.MaxSuppCoilFluidFlow *= rho;
4826 : }
4827 0 : } else if (thisFurnace.SuppHeatCoilType_Num == HVAC::Coil_HeatingSteam) {
4828 0 : errFlag = false;
4829 0 : PlantUtilities::ScanPlantLoopsForObject(state,
4830 : thisFurnace.SuppHeatCoilName,
4831 : DataPlant::PlantEquipmentType::CoilSteamAirHeating,
4832 0 : thisFurnace.SuppPlantLoc,
4833 : errFlag,
4834 : _,
4835 : _,
4836 : _,
4837 : _,
4838 : _);
4839 0 : if (errFlag) {
4840 0 : ShowFatalError(state, "InitFurnace: Program terminated for previous conditions.");
4841 : }
4842 0 : thisFurnace.MaxSuppCoilFluidFlow = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.SuppHeatCoilIndex, ErrorsFound);
4843 0 : if (thisFurnace.MaxSuppCoilFluidFlow > 0.0) {
4844 0 : SteamDensity = Fluid::GetSteam(state)->getSatDensity(state, state.dataFurnaces->TempSteamIn, 1.0, RoutineName);
4845 0 : thisFurnace.MaxSuppCoilFluidFlow *= SteamDensity;
4846 : }
4847 : }
4848 : // fill outlet node for coil
4849 0 : thisFurnace.SuppCoilOutletNode = DataPlant::CompData::getPlantComponent(state, thisFurnace.SuppPlantLoc).NodeNumOut;
4850 0 : state.dataFurnaces->MySuppCoilPlantScanFlag(FurnaceNum) = false;
4851 : } else { // pthp not connected to plant
4852 2 : state.dataFurnaces->MySuppCoilPlantScanFlag(FurnaceNum) = false;
4853 : }
4854 :
4855 15220 : } else if (state.dataFurnaces->MySuppCoilPlantScanFlag(FurnaceNum) && !state.dataGlobal->AnyPlantInModel) {
4856 0 : state.dataFurnaces->MySuppCoilPlantScanFlag(FurnaceNum) = false;
4857 : }
4858 :
4859 : // Do the Begin Environment initializations
4860 15222 : if (state.dataGlobal->BeginEnvrnFlag && state.dataFurnaces->MyEnvrnFlag(FurnaceNum)) {
4861 : // Change the Volume Flow Rates to Mass Flow Rates
4862 6 : thisFurnace.DesignMassFlowRate = thisFurnace.DesignFanVolFlowRate * state.dataEnvrn->StdRhoAir;
4863 6 : thisFurnace.MaxCoolAirMassFlow = thisFurnace.MaxCoolAirVolFlow * state.dataEnvrn->StdRhoAir;
4864 6 : thisFurnace.MaxHeatAirMassFlow = thisFurnace.MaxHeatAirVolFlow * state.dataEnvrn->StdRhoAir;
4865 6 : thisFurnace.MaxNoCoolHeatAirMassFlow = thisFurnace.MaxNoCoolHeatAirVolFlow * state.dataEnvrn->StdRhoAir;
4866 6 : thisFurnace.CompPartLoadRatio = 0.0;
4867 6 : thisFurnace.CoolingCoilSensDemand = 0.0;
4868 6 : thisFurnace.CoolingCoilLatentDemand = 0.0;
4869 6 : thisFurnace.HeatingCoilSensDemand = 0.0;
4870 :
4871 6 : thisFurnace.SenLoadLoss = 0.0;
4872 6 : if (thisFurnace.Humidistat) {
4873 0 : thisFurnace.LatLoadLoss = 0.0;
4874 : }
4875 :
4876 : // set fluid-side hardware limits
4877 6 : if (thisFurnace.CoilControlNode > 0) {
4878 :
4879 0 : if (thisFurnace.MaxHeatCoilFluidFlow == DataSizing::AutoSize) {
4880 : // If water coil max water flow rate is autosized, simulate once in order to mine max flow rate
4881 0 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWater) {
4882 0 : WaterCoils::SimulateWaterCoilComponents(state, thisFurnace.HeatingCoilName, FirstHVACIteration, thisFurnace.HeatingCoilIndex);
4883 : CoilMaxVolFlowRate =
4884 0 : WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", thisFurnace.HeatingCoilName, ErrorsFound);
4885 0 : if (CoilMaxVolFlowRate != DataSizing::AutoSize) {
4886 0 : rho = state.dataPlnt->PlantLoop(thisFurnace.plantLoc.loopNum)
4887 0 : .glycol->getDensity(state, Constant::HWInitConvTemp, RoutineName);
4888 0 : thisFurnace.MaxHeatCoilFluidFlow = CoilMaxVolFlowRate * rho;
4889 : }
4890 : }
4891 : // If steam coil max steam flow rate is autosized, simulate once in order to mine max flow rate
4892 0 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingSteam) {
4893 0 : SteamCoils::SimulateSteamCoilComponents(state,
4894 : thisFurnace.HeatingCoilName,
4895 : FirstHVACIteration,
4896 0 : thisFurnace.HeatingCoilIndex,
4897 0 : 1.0,
4898 : QActual); // QCoilReq, simulate any load > 0 to get max capacity
4899 0 : CoilMaxVolFlowRate = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.HeatingCoilIndex, ErrorsFound);
4900 0 : if (CoilMaxVolFlowRate != DataSizing::AutoSize) {
4901 0 : SteamDensity = Fluid::GetSteam(state)->getSatDensity(state, state.dataFurnaces->TempSteamIn, 1.0, RoutineName);
4902 0 : thisFurnace.MaxHeatCoilFluidFlow = CoilMaxVolFlowRate * SteamDensity;
4903 : }
4904 : }
4905 : }
4906 :
4907 0 : PlantUtilities::InitComponentNodes(
4908 : state, 0.0, thisFurnace.MaxHeatCoilFluidFlow, thisFurnace.CoilControlNode, thisFurnace.CoilOutletNode);
4909 : }
4910 6 : if (thisFurnace.SuppCoilControlNode > 0) {
4911 0 : if (thisFurnace.MaxSuppCoilFluidFlow == DataSizing::AutoSize) {
4912 0 : if (thisFurnace.SuppHeatCoilType_Num == HVAC::Coil_HeatingWater) {
4913 : // If water coil max water flow rate is autosized, simulate once in order to mine max flow rate
4914 0 : WaterCoils::SimulateWaterCoilComponents(
4915 0 : state, thisFurnace.SuppHeatCoilName, FirstHVACIteration, thisFurnace.SuppHeatCoilIndex);
4916 : CoilMaxVolFlowRate =
4917 0 : WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", thisFurnace.SuppHeatCoilName, ErrorsFound);
4918 0 : if (CoilMaxVolFlowRate != DataSizing::AutoSize) {
4919 0 : rho = state.dataPlnt->PlantLoop(thisFurnace.SuppPlantLoc.loopNum)
4920 0 : .glycol->getDensity(state, Constant::HWInitConvTemp, RoutineName);
4921 0 : thisFurnace.MaxSuppCoilFluidFlow = CoilMaxVolFlowRate * rho;
4922 : }
4923 : }
4924 0 : if (thisFurnace.SuppHeatCoilType_Num == HVAC::Coil_HeatingSteam) {
4925 0 : SteamCoils::SimulateSteamCoilComponents(state,
4926 : thisFurnace.SuppHeatCoilName,
4927 : FirstHVACIteration,
4928 0 : thisFurnace.SuppHeatCoilIndex,
4929 0 : 1.0,
4930 : QActual); // QCoilReq, simulate any load > 0 to get max capacity
4931 0 : CoilMaxVolFlowRate = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.SuppHeatCoilIndex, ErrorsFound);
4932 0 : if (CoilMaxVolFlowRate != DataSizing::AutoSize) {
4933 0 : SteamDensity = Fluid::GetSteam(state)->getSatDensity(state, state.dataFurnaces->TempSteamIn, 1.0, RoutineName);
4934 0 : thisFurnace.MaxSuppCoilFluidFlow = CoilMaxVolFlowRate * SteamDensity;
4935 : }
4936 : }
4937 0 : PlantUtilities::InitComponentNodes(
4938 : state, 0.0, thisFurnace.MaxSuppCoilFluidFlow, thisFurnace.SuppCoilControlNode, thisFurnace.SuppCoilOutletNode);
4939 : }
4940 : }
4941 6 : state.dataFurnaces->MyEnvrnFlag(FurnaceNum) = false;
4942 : }
4943 :
4944 15222 : if (!state.dataGlobal->BeginEnvrnFlag) {
4945 15136 : state.dataFurnaces->MyEnvrnFlag(FurnaceNum) = true;
4946 : }
4947 :
4948 15222 : if (state.dataFurnaces->MyFanFlag(FurnaceNum)) {
4949 4 : if (thisFurnace.ActualFanVolFlowRate != DataSizing::AutoSize) {
4950 2 : if (thisFurnace.ActualFanVolFlowRate > 0.0) {
4951 2 : thisFurnace.HeatingSpeedRatio = thisFurnace.MaxHeatAirVolFlow / thisFurnace.ActualFanVolFlowRate;
4952 2 : thisFurnace.CoolingSpeedRatio = thisFurnace.MaxCoolAirVolFlow / thisFurnace.ActualFanVolFlowRate;
4953 2 : thisFurnace.NoHeatCoolSpeedRatio = thisFurnace.MaxNoCoolHeatAirVolFlow / thisFurnace.ActualFanVolFlowRate;
4954 : }
4955 2 : if (dynamic_cast<Fans::FanComponent *>(state.dataFans->fans(thisFurnace.FanIndex))->powerRatioAtSpeedRatioCurveNum > 0) {
4956 0 : if (thisFurnace.ActualFanVolFlowRate == thisFurnace.MaxHeatAirVolFlow &&
4957 0 : thisFurnace.ActualFanVolFlowRate == thisFurnace.MaxCoolAirVolFlow &&
4958 0 : thisFurnace.ActualFanVolFlowRate == thisFurnace.MaxNoCoolHeatAirVolFlow) {
4959 0 : std::string FanName = state.dataFans->fans(thisFurnace.FanIndex)->Name;
4960 0 : ShowWarningError(state, format("{} \"{}\"", HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name));
4961 0 : ShowContinueError(state,
4962 0 : format("...For fan type and name = {} \"{}\"", HVAC::fanTypeNames[(int)thisFurnace.fanType], FanName));
4963 0 : ShowContinueError(state,
4964 : "...Fan power ratio function of speed ratio curve has no impact if fan volumetric flow rate is the same as "
4965 : "the unitary system volumetric flow rate.");
4966 0 : ShowContinueError(state, format("...Fan volumetric flow rate = {:.5R} m3/s.", thisFurnace.ActualFanVolFlowRate));
4967 0 : ShowContinueError(state, format("...Unitary system volumetric flow rate = {:.5R} m3/s.", thisFurnace.MaxHeatAirVolFlow));
4968 0 : }
4969 : }
4970 2 : state.dataFurnaces->MyFanFlag(FurnaceNum) = false;
4971 : } else {
4972 2 : thisFurnace.ActualFanVolFlowRate = state.dataFans->fans(thisFurnace.FanIndex)->maxAirFlowRate;
4973 : }
4974 : }
4975 :
4976 15222 : if (allocated(state.dataZoneEquip->ZoneEquipConfig) && state.dataFurnaces->MyCheckFlag(FurnaceNum)) {
4977 2 : int zoneNum = thisFurnace.ControlZoneNum;
4978 2 : int zoneInlet = thisFurnace.ZoneInletNode;
4979 : // setup furnace zone equipment sequence information based on finding matching air terminal
4980 2 : if (state.dataZoneEquip->ZoneEquipConfig(zoneNum).EquipListIndex > 0) {
4981 2 : int coolingPriority = 0;
4982 2 : int heatingPriority = 0;
4983 2 : state.dataZoneEquip->ZoneEquipList(state.dataZoneEquip->ZoneEquipConfig(zoneNum).EquipListIndex)
4984 2 : .getPrioritiesForInletNode(state, zoneInlet, coolingPriority, heatingPriority);
4985 2 : thisFurnace.ZoneSequenceCoolingNum = coolingPriority;
4986 2 : thisFurnace.ZoneSequenceHeatingNum = heatingPriority;
4987 : }
4988 2 : state.dataFurnaces->MyCheckFlag(FurnaceNum) = false;
4989 2 : if (thisFurnace.ZoneSequenceCoolingNum == 0 || thisFurnace.ZoneSequenceHeatingNum == 0) {
4990 0 : ShowSevereError(state,
4991 0 : format("{} \"{}\": Airloop air terminal in the zone equipment list for zone = {} not found or is not allowed Zone "
4992 : "Equipment Cooling or Heating Sequence = 0.",
4993 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
4994 0 : thisFurnace.Name,
4995 0 : state.dataHeatBal->Zone(thisFurnace.ControlZoneNum).Name));
4996 0 : ShowFatalError(state,
4997 0 : format("Subroutine InitFurnace: Errors found in getting {} input. Preceding condition(s) causes termination.",
4998 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type]));
4999 : }
5000 : }
5001 :
5002 : // Find the number of zones (zone Inlet Nodes) attached to an air loop from the air loop number
5003 : int NumAirLoopZones =
5004 15222 : state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesCooled + state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesHeated;
5005 15222 : if (allocated(state.dataAirLoop->AirToZoneNodeInfo) && state.dataFurnaces->MyFlowFracFlag(FurnaceNum)) {
5006 2 : state.dataFurnaces->FlowFracFlagReady = true;
5007 4 : for (int ZoneInSysIndex = 1; ZoneInSysIndex <= NumAirLoopZones; ++ZoneInSysIndex) {
5008 : // zone inlet nodes for cooling
5009 2 : if (state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesCooled > 0) {
5010 2 : if (state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolInletNodes(ZoneInSysIndex) == -999) {
5011 : // the data structure for the zones inlet nodes has not been filled
5012 0 : state.dataFurnaces->FlowFracFlagReady = false;
5013 : }
5014 : }
5015 : // zone inlet nodes for heating
5016 2 : if (state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesHeated > 0) {
5017 0 : if (state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitHeatInletNodes(ZoneInSysIndex) == -999) {
5018 : // the data structure for the zones inlet nodes has not been filled
5019 0 : state.dataFurnaces->FlowFracFlagReady = false;
5020 : }
5021 : }
5022 : }
5023 : }
5024 :
5025 15222 : if (state.dataFurnaces->MyFlowFracFlag(FurnaceNum)) {
5026 2 : if (allocated(state.dataAirLoop->AirToZoneNodeInfo) && state.dataFurnaces->FlowFracFlagReady) {
5027 2 : SumOfMassFlowRateMax = 0.0; // initialize the sum of the maximum flows
5028 4 : for (int ZoneInSysIndex = 1; ZoneInSysIndex <= NumAirLoopZones; ++ZoneInSysIndex) {
5029 2 : int ZoneInletNodeNum = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolInletNodes(ZoneInSysIndex);
5030 2 : SumOfMassFlowRateMax += state.dataLoopNodes->Node(ZoneInletNodeNum).MassFlowRateMax;
5031 2 : if (state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).CoolCtrlZoneNums(ZoneInSysIndex) == thisFurnace.ControlZoneNum) {
5032 2 : CntrlZoneTerminalUnitMassFlowRateMax = state.dataLoopNodes->Node(ZoneInletNodeNum).MassFlowRateMax;
5033 : }
5034 : }
5035 2 : if (SumOfMassFlowRateMax != 0.0) {
5036 2 : if (CntrlZoneTerminalUnitMassFlowRateMax >= HVAC::SmallAirVolFlow) {
5037 2 : thisFurnace.ControlZoneMassFlowFrac = CntrlZoneTerminalUnitMassFlowRateMax / SumOfMassFlowRateMax;
5038 : } else {
5039 0 : ShowSevereError(state, format("{} = {}", HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name));
5040 0 : ShowContinueError(state, " The Fraction of Supply Air Flow That Goes Through the Controlling Zone is set to 1.");
5041 : }
5042 4 : BaseSizer::reportSizerOutput(state,
5043 2 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
5044 : thisFurnace.Name,
5045 : "Fraction of Supply Air Flow That Goes Through the Controlling Zone",
5046 : thisFurnace.ControlZoneMassFlowFrac);
5047 2 : state.dataFurnaces->MyFlowFracFlag(FurnaceNum) = false;
5048 : }
5049 : }
5050 : }
5051 :
5052 : // Calculate air distribution losses
5053 15222 : if (!FirstHVACIteration && state.dataFurnaces->AirLoopPass == 1) {
5054 3778 : int ZoneInNode = thisFurnace.ZoneInletNode;
5055 3778 : MassFlowRate = state.dataLoopNodes->Node(ZoneInNode).MassFlowRate / thisFurnace.ControlZoneMassFlowFrac;
5056 3778 : if (state.afn->distribution_simulated) {
5057 2764 : DeltaMassRate = state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum).MassFlowRate -
5058 2764 : state.dataLoopNodes->Node(ZoneInNode).MassFlowRate / thisFurnace.ControlZoneMassFlowFrac;
5059 2764 : if (DeltaMassRate < 0.0) DeltaMassRate = 0.0;
5060 : } else {
5061 1014 : MassFlowRate = state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum).MassFlowRate;
5062 1014 : DeltaMassRate = 0.0;
5063 : }
5064 3778 : Real64 TotalOutput(0.0); // total output rate, {W}
5065 3778 : Real64 SensibleOutputDelta(0.0); // delta sensible output rate, {W}
5066 3778 : Real64 LatentOutputDelta(0.0); // delta latent output rate, {W}
5067 3778 : Real64 TotalOutputDelta(0.0); // delta total output rate, {W}
5068 15112 : CalcZoneSensibleLatentOutput(MassFlowRate,
5069 3778 : state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum).Temp,
5070 3778 : state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum).HumRat,
5071 3778 : state.dataLoopNodes->Node(ZoneInNode).Temp,
5072 3778 : state.dataLoopNodes->Node(ZoneInNode).HumRat,
5073 3778 : thisFurnace.SenLoadLoss,
5074 3778 : thisFurnace.LatLoadLoss,
5075 : TotalOutput);
5076 15112 : CalcZoneSensibleLatentOutput(DeltaMassRate,
5077 3778 : state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum).Temp,
5078 3778 : state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum).HumRat,
5079 3778 : state.dataLoopNodes->Node(thisFurnace.NodeNumOfControlledZone).Temp,
5080 3778 : state.dataLoopNodes->Node(thisFurnace.NodeNumOfControlledZone).HumRat,
5081 : SensibleOutputDelta,
5082 : LatentOutputDelta,
5083 : TotalOutputDelta);
5084 3778 : thisFurnace.SenLoadLoss = thisFurnace.SenLoadLoss + SensibleOutputDelta;
5085 3778 : if (std::abs(thisFurnace.SensibleLoadMet) > 0.0) {
5086 3777 : if (std::abs(thisFurnace.SenLoadLoss / thisFurnace.SensibleLoadMet) < 0.001) thisFurnace.SenLoadLoss = 0.0;
5087 : }
5088 3778 : if (thisFurnace.Humidistat) {
5089 0 : thisFurnace.LatLoadLoss = thisFurnace.LatLoadLoss + LatentOutputDelta;
5090 0 : if (std::abs(thisFurnace.LatentLoadMet) > 0.0) {
5091 0 : if (std::abs(thisFurnace.LatLoadLoss / thisFurnace.LatentLoadMet) < 0.001) thisFurnace.LatLoadLoss = 0.0;
5092 : }
5093 : }
5094 : }
5095 :
5096 15222 : if (thisFurnace.fanOpModeSched != nullptr) {
5097 15222 : thisFurnace.fanOp = (thisFurnace.fanOpModeSched->getCurrentVal() == 0.0) ? HVAC::FanOp::Cycling : HVAC::FanOp::Continuous;
5098 15222 : if (AirLoopNum > 0) {
5099 15222 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).fanOp = thisFurnace.fanOp;
5100 : }
5101 : }
5102 :
5103 15222 : fanOp = thisFurnace.fanOp;
5104 15222 : state.dataFurnaces->EconomizerFlag = state.dataAirLoop->AirLoopControlInfo(AirLoopNum).EconoActive;
5105 :
5106 15222 : if (thisFurnace.ControlZoneMassFlowFrac > 0.0) {
5107 15222 : QZnReq = ZoneLoad / thisFurnace.ControlZoneMassFlowFrac;
5108 15222 : MoistureLoad /= thisFurnace.ControlZoneMassFlowFrac;
5109 15222 : ZoneLoad = QZnReq;
5110 : } else {
5111 0 : QZnReq = ZoneLoad;
5112 : }
5113 :
5114 : // Original thermostat control logic (works only for cycling fan systems)
5115 23584 : if (QZnReq > HVAC::SmallLoad && QZnReq > (Small5WLoad / thisFurnace.ControlZoneMassFlowFrac) &&
5116 8362 : !state.dataZoneEnergyDemand->CurDeadBandOrSetback(thisFurnace.ControlZoneNum)) {
5117 8362 : state.dataFurnaces->HeatingLoad = true;
5118 8362 : state.dataFurnaces->CoolingLoad = false;
5119 13608 : } else if (QZnReq < -HVAC::SmallLoad && std::abs(QZnReq) > (Small5WLoad / thisFurnace.ControlZoneMassFlowFrac) &&
5120 6748 : !state.dataZoneEnergyDemand->CurDeadBandOrSetback(thisFurnace.ControlZoneNum)) {
5121 6748 : state.dataFurnaces->HeatingLoad = false;
5122 6748 : state.dataFurnaces->CoolingLoad = true;
5123 : } else {
5124 112 : state.dataFurnaces->HeatingLoad = false;
5125 112 : state.dataFurnaces->CoolingLoad = false;
5126 : }
5127 :
5128 15222 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir ||
5129 0 : (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir &&
5130 0 : (thisFurnace.WatertoAirHPType == WAHPCoilType::Simple || thisFurnace.WatertoAirHPType == WAHPCoilType::VarSpeedEquationFit))) {
5131 15222 : if (MoistureLoad < 0.0 && thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat) {
5132 0 : state.dataFurnaces->HPDehumidificationLoadFlag = true;
5133 0 : state.dataFurnaces->HeatingLoad = false;
5134 0 : state.dataFurnaces->CoolingLoad = true;
5135 : } else {
5136 15222 : state.dataFurnaces->HPDehumidificationLoadFlag = false;
5137 : }
5138 : }
5139 :
5140 : // Check for heat only furnace
5141 15222 : if (thisFurnace.type != HVAC::UnitarySysType::Furnace_HeatOnly && thisFurnace.type != HVAC::UnitarySysType::Unitary_HeatOnly) {
5142 :
5143 30444 : if (thisFurnace.availSched->getCurrentVal() > 0.0) {
5144 15222 : if ((state.dataFurnaces->HeatingLoad || state.dataFurnaces->CoolingLoad) || (thisFurnace.Humidistat && MoistureLoad < 0.0)) {
5145 15110 : PartLoadRatio = 1.0;
5146 : } else {
5147 112 : PartLoadRatio = 0.0;
5148 : }
5149 : } else {
5150 0 : PartLoadRatio = 0.0;
5151 : }
5152 : } else {
5153 0 : PartLoadRatio = 1.0;
5154 : }
5155 :
5156 : // get current time step operating capacity of water and steam coils
5157 : // (dependent on entering water and steam temperature)
5158 15222 : if (FirstHVACIteration) {
5159 4846 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWater) {
5160 : // set water-side mass flow rates
5161 0 : state.dataLoopNodes->Node(thisFurnace.HWCoilAirInletNode).MassFlowRate = state.dataFurnaces->CompOnMassFlow;
5162 0 : mdot = thisFurnace.MaxHeatCoilFluidFlow;
5163 0 : PlantUtilities::SetComponentFlowRate(state, mdot, thisFurnace.CoilControlNode, thisFurnace.CoilOutletNode, thisFurnace.plantLoc);
5164 : // simulate water coil to find operating capacity
5165 0 : WaterCoils::SimulateWaterCoilComponents(
5166 0 : state, thisFurnace.HeatingCoilName, FirstHVACIteration, thisFurnace.HeatingCoilIndex, QActual);
5167 0 : thisFurnace.DesignHeatingCapacity = QActual;
5168 :
5169 : } // from IF(furnace%HeatingCoilType_Num == Coil_HeatingWater) THEN
5170 :
5171 4846 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingSteam) {
5172 : // set air-side and steam-side mass flow rates
5173 0 : state.dataLoopNodes->Node(thisFurnace.HWCoilAirInletNode).MassFlowRate = state.dataFurnaces->CompOnMassFlow;
5174 0 : mdot = thisFurnace.MaxHeatCoilFluidFlow;
5175 0 : PlantUtilities::SetComponentFlowRate(state, mdot, thisFurnace.CoilControlNode, thisFurnace.CoilOutletNode, thisFurnace.plantLoc);
5176 :
5177 : // simulate steam coil to find operating capacity
5178 0 : SteamCoils::SimulateSteamCoilComponents(state,
5179 : thisFurnace.HeatingCoilName,
5180 : FirstHVACIteration,
5181 0 : thisFurnace.HeatingCoilIndex,
5182 0 : 1.0,
5183 : QActual); // QCoilReq, simulate any load > 0 to get max capacity of steam coil
5184 0 : thisFurnace.DesignHeatingCapacity =
5185 0 : SteamCoils::GetCoilCapacity(state, thisFurnace.HeatingCoilType, thisFurnace.HeatingCoilName, ErrorsFound);
5186 :
5187 : } // from IF(Furnace(FurnaceNum)%HeatingCoilType_Num == Coil_HeatingSteam) THEN
5188 :
5189 4846 : if (thisFurnace.SuppHeatCoilType_Num == HVAC::Coil_HeatingWater) {
5190 :
5191 : // set air-side and steam-side mass flow rates
5192 0 : state.dataLoopNodes->Node(thisFurnace.SuppCoilAirInletNode).MassFlowRate = state.dataFurnaces->CompOnMassFlow;
5193 0 : mdot = thisFurnace.MaxSuppCoilFluidFlow;
5194 0 : PlantUtilities::SetComponentFlowRate(
5195 0 : state, mdot, thisFurnace.SuppCoilControlNode, thisFurnace.SuppCoilOutletNode, thisFurnace.SuppPlantLoc);
5196 :
5197 : // simulate water coil to find operating capacity
5198 0 : WaterCoils::SimulateWaterCoilComponents(
5199 0 : state, thisFurnace.SuppHeatCoilName, FirstHVACIteration, thisFurnace.SuppHeatCoilIndex, QActual);
5200 0 : thisFurnace.DesignSuppHeatingCapacity = QActual;
5201 :
5202 : } // from IF(Furnace(FurnaceNum)%SuppHeatCoilType_Num == Coil_HeatingWater) THEN
5203 4846 : if (thisFurnace.SuppHeatCoilType_Num == HVAC::Coil_HeatingSteam) {
5204 : // set air-side and steam-side mass flow rates
5205 0 : state.dataLoopNodes->Node(thisFurnace.SuppCoilAirInletNode).MassFlowRate = state.dataFurnaces->CompOnMassFlow;
5206 0 : mdot = thisFurnace.MaxSuppCoilFluidFlow;
5207 0 : PlantUtilities::SetComponentFlowRate(
5208 0 : state, mdot, thisFurnace.SuppCoilControlNode, thisFurnace.SuppCoilOutletNode, thisFurnace.SuppPlantLoc);
5209 :
5210 : // simulate steam coil to find operating capacity
5211 0 : SteamCoils::SimulateSteamCoilComponents(state,
5212 : thisFurnace.SuppHeatCoilName,
5213 : FirstHVACIteration,
5214 0 : thisFurnace.SuppHeatCoilIndex,
5215 0 : 1.0,
5216 : QActual); // QCoilReq, simulate any load > 0 to get max capacity of steam coil
5217 0 : thisFurnace.DesignSuppHeatingCapacity =
5218 0 : SteamCoils::GetCoilCapacity(state, thisFurnace.SuppHeatCoilType, thisFurnace.SuppHeatCoilName, ErrorsFound);
5219 :
5220 : } // from IF(Furnace(FurnaceNum)%SuppHeatCoilType_Num == Coil_HeatingSteam) THEN
5221 : } // from IF( FirstHVACIteration ) THEN
5222 :
5223 15222 : if (thisFurnace.NumOfSpeedCooling > 0) { // BoS, variable-speed water source hp
5224 : // Furnace(FurnaceNum)%IdleMassFlowRate = RhoAir*Furnace(FurnaceNum)%IdleVolumeAirRate
5225 0 : int NumOfSpeedCooling = thisFurnace.NumOfSpeedCooling;
5226 0 : int NumOfSpeedHeating = thisFurnace.NumOfSpeedHeating;
5227 : // IF MSHP system was not autosized and the fan is autosized, check that fan volumetric flow rate is greater than MSHP flow rates
5228 0 : if (thisFurnace.CheckFanFlow) {
5229 0 : state.dataFurnaces->CurrentModuleObject = "AirLoopHVAC:UnitaryHeatPump:VariableSpeed";
5230 0 : thisFurnace.FanVolFlow = state.dataFans->fans(thisFurnace.FanIndex)->maxAirFlowRate;
5231 :
5232 0 : if (thisFurnace.FanVolFlow != DataSizing::AutoSize) {
5233 : // Check fan versus system supply air flow rates
5234 0 : if (thisFurnace.FanVolFlow + 1e-10 < thisFurnace.CoolVolumeFlowRate(NumOfSpeedCooling)) {
5235 0 : ShowWarningError(state,
5236 0 : format("{} - air flow rate = {:.7T} in fan object is less than the MSHP system air flow rate when cooling "
5237 : "is required ({:.7T}).",
5238 0 : state.dataFurnaces->CurrentModuleObject,
5239 0 : thisFurnace.FanVolFlow,
5240 : thisFurnace.CoolVolumeFlowRate(NumOfSpeedCooling)));
5241 0 : ShowContinueError(
5242 : state, " The MSHP system flow rate when cooling is required is reset to the fan flow rate and the simulation continues.");
5243 0 : ShowContinueError(state, format(" Occurs in {} = {}", state.dataFurnaces->CurrentModuleObject, thisFurnace.Name));
5244 0 : thisFurnace.CoolVolumeFlowRate(NumOfSpeedCooling) = thisFurnace.FanVolFlow;
5245 :
5246 0 : if (thisFurnace.bIsIHP) // set max fan flow rate to the IHP collection
5247 : {
5248 0 : state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).MaxCoolAirVolFlow = thisFurnace.FanVolFlow;
5249 0 : state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).MaxCoolAirMassFlow =
5250 0 : thisFurnace.FanVolFlow * state.dataEnvrn->StdRhoAir;
5251 : }
5252 :
5253 : // Check flow rates in other speeds and ensure flow rates are not above the max flow rate
5254 0 : for (int i = NumOfSpeedCooling - 1; i >= 1; --i) {
5255 0 : if (thisFurnace.CoolVolumeFlowRate(i) > thisFurnace.CoolVolumeFlowRate(i + 1)) {
5256 0 : ShowContinueError(state,
5257 0 : format(" The MSHP system flow rate when cooling is required is reset to the flow rate at higher "
5258 : "speed and the simulation continues at Speed{}.",
5259 : i));
5260 0 : ShowContinueError(state, format(" Occurs in {} = {}", state.dataFurnaces->CurrentModuleObject, thisFurnace.Name));
5261 0 : thisFurnace.CoolVolumeFlowRate(i) = thisFurnace.CoolVolumeFlowRate(i + 1);
5262 : }
5263 : }
5264 : }
5265 0 : if (NumOfSpeedHeating > 0) {
5266 0 : if (thisFurnace.FanVolFlow + 1e-10 < thisFurnace.HeatVolumeFlowRate(NumOfSpeedHeating)) {
5267 0 : ShowWarningError(state,
5268 0 : format("{} - air flow rate = {:.7T} in fan object is less than the MSHP system air flow rate when "
5269 : "heating is required ({:.7T}).",
5270 0 : state.dataFurnaces->CurrentModuleObject,
5271 0 : thisFurnace.FanVolFlow,
5272 : thisFurnace.HeatVolumeFlowRate(NumOfSpeedHeating)));
5273 0 : ShowContinueError(
5274 : state,
5275 : " The MSHP system flow rate when heating is required is reset to the fan flow rate and the simulation continues.");
5276 0 : ShowContinueError(state, format(" Occurs in {} = {}", state.dataFurnaces->CurrentModuleObject, thisFurnace.Name));
5277 0 : thisFurnace.HeatVolumeFlowRate(NumOfSpeedHeating) = thisFurnace.FanVolFlow;
5278 :
5279 0 : if (thisFurnace.bIsIHP) // set max fan flow rate to the IHP collection
5280 : {
5281 0 : state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).MaxHeatAirVolFlow = thisFurnace.FanVolFlow;
5282 0 : state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).MaxHeatAirMassFlow =
5283 0 : thisFurnace.FanVolFlow * state.dataEnvrn->StdRhoAir;
5284 : }
5285 :
5286 0 : for (int i = NumOfSpeedHeating - 1; i >= 1; --i) {
5287 0 : if (thisFurnace.HeatVolumeFlowRate(i) > thisFurnace.HeatVolumeFlowRate(i + 1)) {
5288 0 : ShowContinueError(state,
5289 0 : format(" The MSHP system flow rate when heating is required is reset to the flow rate at "
5290 : "higher speed and the simulation continues at Speed{}.",
5291 : i));
5292 0 : ShowContinueError(state,
5293 0 : format(" Occurs in {} system = {}", state.dataFurnaces->CurrentModuleObject, thisFurnace.Name));
5294 0 : thisFurnace.HeatVolumeFlowRate(i) = thisFurnace.HeatVolumeFlowRate(i + 1);
5295 : }
5296 : }
5297 : }
5298 : }
5299 0 : if (thisFurnace.FanVolFlow < thisFurnace.IdleVolumeAirRate && thisFurnace.IdleVolumeAirRate != 0.0) {
5300 0 : ShowWarningError(state,
5301 0 : format("{} - air flow rate = {:.7T} in fan object is less than the MSHP system air flow rate when no "
5302 : "heating or cooling is needed ({:.7T}).",
5303 0 : state.dataFurnaces->CurrentModuleObject,
5304 0 : thisFurnace.FanVolFlow,
5305 0 : thisFurnace.IdleVolumeAirRate));
5306 0 : ShowContinueError(state,
5307 : " The MSHP system flow rate when no heating or cooling is needed is reset to the fan flow rate and the "
5308 : "simulation continues.");
5309 0 : ShowContinueError(state, format(" Occurs in {} = {}", state.dataFurnaces->CurrentModuleObject, thisFurnace.Name));
5310 0 : thisFurnace.IdleVolumeAirRate = thisFurnace.FanVolFlow;
5311 : }
5312 0 : RhoAir = state.dataEnvrn->StdRhoAir;
5313 : // set the mass flow rates from the reset volume flow rates
5314 0 : for (int i = 1; i <= NumOfSpeedCooling; ++i) {
5315 0 : thisFurnace.CoolMassFlowRate(i) = RhoAir * thisFurnace.CoolVolumeFlowRate(i);
5316 0 : if (thisFurnace.FanVolFlow > 0.0) {
5317 0 : thisFurnace.MSCoolingSpeedRatio(i) = thisFurnace.CoolVolumeFlowRate(i) / thisFurnace.FanVolFlow;
5318 : }
5319 : }
5320 0 : for (int i = 1; i <= NumOfSpeedHeating; ++i) {
5321 0 : thisFurnace.HeatMassFlowRate(i) = RhoAir * thisFurnace.HeatVolumeFlowRate(i);
5322 0 : if (thisFurnace.FanVolFlow > 0.0) {
5323 0 : thisFurnace.MSHeatingSpeedRatio(i) = thisFurnace.HeatVolumeFlowRate(i) / thisFurnace.FanVolFlow;
5324 : }
5325 : }
5326 0 : thisFurnace.IdleMassFlowRate = RhoAir * thisFurnace.IdleVolumeAirRate;
5327 0 : if (thisFurnace.FanVolFlow > 0.0) {
5328 0 : thisFurnace.IdleSpeedRatio = thisFurnace.IdleVolumeAirRate / thisFurnace.FanVolFlow;
5329 : }
5330 : // set the node max and min mass flow rates based on reset volume flow rates
5331 0 : if (NumOfSpeedCooling > 0 && NumOfSpeedHeating == 0) {
5332 0 : state.dataLoopNodes->Node(InNode).MassFlowRateMax =
5333 0 : max(thisFurnace.CoolMassFlowRate(NumOfSpeedCooling), thisFurnace.MaxHeatAirMassFlow);
5334 0 : state.dataLoopNodes->Node(InNode).MassFlowRateMaxAvail =
5335 0 : max(thisFurnace.CoolMassFlowRate(NumOfSpeedCooling), thisFurnace.MaxHeatAirMassFlow);
5336 0 : } else if (NumOfSpeedCooling == 0 && NumOfSpeedHeating > 0) {
5337 0 : state.dataLoopNodes->Node(InNode).MassFlowRateMax =
5338 0 : max(thisFurnace.MaxCoolAirMassFlow, thisFurnace.HeatMassFlowRate(NumOfSpeedHeating));
5339 0 : state.dataLoopNodes->Node(InNode).MassFlowRateMaxAvail =
5340 0 : max(thisFurnace.MaxCoolAirMassFlow, thisFurnace.HeatMassFlowRate(NumOfSpeedHeating));
5341 : } else {
5342 0 : state.dataLoopNodes->Node(InNode).MassFlowRateMax =
5343 0 : max(thisFurnace.CoolMassFlowRate(NumOfSpeedCooling), thisFurnace.HeatMassFlowRate(NumOfSpeedHeating));
5344 0 : state.dataLoopNodes->Node(InNode).MassFlowRateMaxAvail =
5345 0 : max(thisFurnace.CoolMassFlowRate(NumOfSpeedCooling), thisFurnace.HeatMassFlowRate(NumOfSpeedHeating));
5346 : }
5347 0 : state.dataLoopNodes->Node(InNode).MassFlowRateMin = 0.0;
5348 0 : state.dataLoopNodes->Node(InNode).MassFlowRateMinAvail = 0.0;
5349 0 : state.dataLoopNodes->Node(OutNode) = state.dataLoopNodes->Node(InNode);
5350 : }
5351 : }
5352 :
5353 0 : thisFurnace.CheckFanFlow = false;
5354 : }
5355 15222 : SetOnOffMassFlowRate(state, FurnaceNum, AirLoopNum, OnOffAirFlowRatio, fanOp, QZnReq, MoistureLoad, PartLoadRatio);
5356 :
5357 : // Check ventilation/fan load for constant fan systems to see if load to be met changes
5358 : // Same IF logic used in Subroutine SetAverageAirFlow to determine if unit is ON or OFF
5359 :
5360 15222 : QToCoolSetPt = 0.0;
5361 15222 : QToHeatSetPt = 0.0;
5362 15222 : if (fanOp == HVAC::FanOp::Continuous && thisFurnace.availSched->getCurrentVal() > 0.0 &&
5363 0 : ((thisFurnace.fanAvailSched->getCurrentVal() > 0.0 || state.dataHVACGlobal->TurnFansOn) && !state.dataHVACGlobal->TurnFansOff)) {
5364 :
5365 0 : if (thisFurnace.NumOfSpeedCooling > 0) {
5366 0 : CalcVarSpeedHeatPump(state,
5367 : FurnaceNum,
5368 : false,
5369 : HVAC::CompressorOp::Off,
5370 : 1,
5371 : 0.0,
5372 : 0.0,
5373 : SensibleOutput,
5374 : LatentOutput,
5375 : 0.0,
5376 : 0.0,
5377 : OnOffAirFlowRatio,
5378 : SUPHEATERLOAD);
5379 : } else {
5380 0 : CalcFurnaceOutput(state,
5381 : FurnaceNum,
5382 : false,
5383 : HVAC::FanOp::Invalid, // Looks like Invalid is used to mean that the fan is off here?
5384 : HVAC::CompressorOp::Off,
5385 : 0.0,
5386 : 0.0,
5387 : 0.0,
5388 : 0.0,
5389 : SensibleOutput,
5390 : LatentOutput,
5391 : OnOffAirFlowRatio,
5392 : false);
5393 : }
5394 :
5395 0 : if (thisFurnace.ControlZoneMassFlowFrac > 0.0) {
5396 0 : if (thisFurnace.ZoneSequenceCoolingNum > 0 && thisFurnace.ZoneSequenceHeatingNum > 0) {
5397 0 : QToCoolSetPt = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(thisFurnace.ControlZoneNum)
5398 0 : .SequencedOutputRequiredToCoolingSP(thisFurnace.ZoneSequenceCoolingNum) /
5399 0 : thisFurnace.ControlZoneMassFlowFrac;
5400 0 : QToHeatSetPt = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(thisFurnace.ControlZoneNum)
5401 0 : .SequencedOutputRequiredToHeatingSP(thisFurnace.ZoneSequenceHeatingNum) /
5402 0 : thisFurnace.ControlZoneMassFlowFrac;
5403 : } else {
5404 0 : QToCoolSetPt = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(thisFurnace.ControlZoneNum).OutputRequiredToCoolingSP /
5405 0 : thisFurnace.ControlZoneMassFlowFrac;
5406 0 : QToHeatSetPt = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(thisFurnace.ControlZoneNum).OutputRequiredToHeatingSP /
5407 0 : thisFurnace.ControlZoneMassFlowFrac;
5408 : }
5409 : // If the furnace has a net cooling capacity (SensibleOutput < 0) and
5410 : // the zone temp is above the Tstat heating setpoint (QToHeatSetPt < 0) and
5411 : // the net cooling capacity does not just offset the cooling load
5412 0 : if (SensibleOutput < 0.0 && QToHeatSetPt < 0.0 &&
5413 0 : std::abs(QToCoolSetPt - SensibleOutput) > (Small5WLoad / thisFurnace.ControlZoneMassFlowFrac)) {
5414 : // Only switch modes when humidistat is not used or no moisture load exists, otherwise let
5415 : // reheat coil pick up load
5416 : // IF((SensibleOutput .LT. QToHeatSetPt .AND. .NOT. Furnace(FurnaceNum)%Humidistat) .OR. &
5417 : // (SensibleOutput .LT. QToHeatSetPt .AND. Furnace(FurnaceNum)%Humidistat .AND. MoistureLoad .GE. 0.0))THEN
5418 0 : if ((SensibleOutput < QToHeatSetPt && !thisFurnace.Humidistat) ||
5419 0 : (SensibleOutput < QToHeatSetPt && thisFurnace.Humidistat && MoistureLoad >= 0.0)) {
5420 0 : QZnReq = QToHeatSetPt;
5421 0 : state.dataFurnaces->CoolingLoad = false;
5422 : // Don't set mode TRUE unless mode is allowed. Also check for floating zone.
5423 0 : if (state.dataHeatBalFanSys->TempControlType(thisFurnace.ControlZoneNum) == HVAC::SetptType::SingleCool ||
5424 0 : state.dataHeatBalFanSys->TempControlType(thisFurnace.ControlZoneNum) == HVAC::SetptType::Uncontrolled) {
5425 0 : state.dataFurnaces->HeatingLoad = false;
5426 : } else {
5427 0 : state.dataFurnaces->HeatingLoad = true;
5428 : }
5429 :
5430 0 : SetOnOffMassFlowRate(state, FurnaceNum, AirLoopNum, OnOffAirFlowRatio, fanOp, QZnReq, MoistureLoad, PartLoadRatio);
5431 0 : if (thisFurnace.NumOfSpeedCooling > 0) {
5432 0 : CalcVarSpeedHeatPump(state,
5433 : FurnaceNum,
5434 : false,
5435 : HVAC::CompressorOp::Off,
5436 : 1,
5437 : 0.0,
5438 : 0.0,
5439 : SensibleOutput,
5440 : LatentOutput,
5441 : 0.0,
5442 : 0.0,
5443 : OnOffAirFlowRatio,
5444 : SUPHEATERLOAD);
5445 : } else {
5446 0 : CalcFurnaceOutput(state,
5447 : FurnaceNum,
5448 : false,
5449 : HVAC::FanOp::Invalid,
5450 : HVAC::CompressorOp::Off,
5451 : 0.0,
5452 : 0.0,
5453 : 0.0,
5454 : 0.0,
5455 : SensibleOutput,
5456 : LatentOutput,
5457 : OnOffAirFlowRatio,
5458 : false);
5459 : }
5460 0 : if (SensibleOutput > QToHeatSetPt) {
5461 : // If changing operating mode (flow rates) does not overshoot heating setpoint, turn off heating
5462 0 : QZnReq = 0.0;
5463 0 : state.dataFurnaces->HeatingLoad = false;
5464 0 : SetOnOffMassFlowRate(state, FurnaceNum, AirLoopNum, OnOffAirFlowRatio, fanOp, QZnReq, MoistureLoad, PartLoadRatio);
5465 : }
5466 0 : } else if (SensibleOutput < QZnReq) {
5467 : // If the net cooling capacity meets the zone cooling load but does not overshoot heating setpoint, turn off cooling
5468 : // (dehumidification may still occur)
5469 0 : QZnReq = 0.0;
5470 0 : state.dataFurnaces->CoolingLoad = false;
5471 0 : if (state.dataFurnaces->HPDehumidificationLoadFlag) {
5472 0 : state.dataFurnaces->CoolingLoad = true;
5473 0 : state.dataFurnaces->HeatingLoad = false;
5474 : }
5475 0 : SetOnOffMassFlowRate(state, FurnaceNum, AirLoopNum, OnOffAirFlowRatio, fanOp, QZnReq, MoistureLoad, PartLoadRatio);
5476 : }
5477 : // the net cooling capacity just offsets the cooling load, turn off cooling
5478 0 : } else if (SensibleOutput < 0.0 && QToCoolSetPt < 0.0 &&
5479 0 : std::abs(QToCoolSetPt - SensibleOutput) < (Small5WLoad / thisFurnace.ControlZoneMassFlowFrac)) {
5480 0 : state.dataFurnaces->CoolingLoad = false;
5481 0 : if (state.dataFurnaces->HPDehumidificationLoadFlag) {
5482 0 : state.dataFurnaces->CoolingLoad = true;
5483 0 : state.dataFurnaces->HeatingLoad = false;
5484 : }
5485 : } // SensibleOutput .LT. 0.0d0 .AND. QToHeatSetPt .LT. 0.0d0
5486 :
5487 : // If the furnace has a net heating capacity and the zone temp is below the Tstat cooling setpoint and
5488 : // the net heating capacity does not just offset the heating load
5489 0 : if (SensibleOutput > 0.0 && QToCoolSetPt > 0.0 &&
5490 0 : std::abs(SensibleOutput - QToHeatSetPt) > (Small5WLoad / thisFurnace.ControlZoneMassFlowFrac)) {
5491 0 : if (SensibleOutput > QToCoolSetPt) {
5492 0 : QZnReq = QToCoolSetPt;
5493 : // Don't set mode TRUE unless mode is allowed. Also check for floating zone.
5494 0 : if (state.dataHeatBalFanSys->TempControlType(thisFurnace.ControlZoneNum) == HVAC::SetptType::SingleHeat ||
5495 0 : state.dataHeatBalFanSys->TempControlType(thisFurnace.ControlZoneNum) == HVAC::SetptType::Uncontrolled) {
5496 0 : state.dataFurnaces->CoolingLoad = false;
5497 : } else {
5498 0 : state.dataFurnaces->CoolingLoad = true;
5499 : }
5500 0 : state.dataFurnaces->HeatingLoad = false;
5501 :
5502 0 : SetOnOffMassFlowRate(state, FurnaceNum, AirLoopNum, OnOffAirFlowRatio, fanOp, QZnReq, MoistureLoad, PartLoadRatio);
5503 0 : if (thisFurnace.NumOfSpeedCooling > 0) {
5504 0 : CalcVarSpeedHeatPump(state,
5505 : FurnaceNum,
5506 : false,
5507 : HVAC::CompressorOp::Off,
5508 : 1,
5509 : 0.0,
5510 : 0.0,
5511 : SensibleOutput,
5512 : LatentOutput,
5513 : 0.0,
5514 : 0.0,
5515 : OnOffAirFlowRatio,
5516 : SUPHEATERLOAD);
5517 : } else {
5518 0 : CalcFurnaceOutput(state,
5519 : FurnaceNum,
5520 : false,
5521 : HVAC::FanOp::Invalid,
5522 : HVAC::CompressorOp::Off,
5523 : 0.0,
5524 : 0.0,
5525 : 0.0,
5526 : 0.0,
5527 : SensibleOutput,
5528 : LatentOutput,
5529 : OnOffAirFlowRatio,
5530 : false);
5531 : }
5532 0 : if (SensibleOutput < QToCoolSetPt) {
5533 : // If changing operating mode (flow rates) does not overshoot cooling setpoint, turn off cooling
5534 0 : if (state.dataFurnaces->HPDehumidificationLoadFlag) {
5535 0 : state.dataFurnaces->CoolingLoad = true;
5536 0 : state.dataFurnaces->HeatingLoad = false;
5537 : } else {
5538 0 : QZnReq = 0.0;
5539 0 : state.dataFurnaces->CoolingLoad = false;
5540 : }
5541 0 : SetOnOffMassFlowRate(state, FurnaceNum, AirLoopNum, OnOffAirFlowRatio, fanOp, QZnReq, MoistureLoad, PartLoadRatio);
5542 : }
5543 0 : } else if (SensibleOutput > QZnReq) {
5544 : // If the net heating capacity meets the zone heating load but does not overshoot, turn off heating
5545 0 : QZnReq = 0.0;
5546 0 : state.dataFurnaces->HeatingLoad = false;
5547 0 : SetOnOffMassFlowRate(state, FurnaceNum, AirLoopNum, OnOffAirFlowRatio, fanOp, QZnReq, MoistureLoad, PartLoadRatio);
5548 : }
5549 : // the net heating capacity just offsets the heating load, turn off heating
5550 0 : } else if (SensibleOutput > 0.0 && QToHeatSetPt > 0.0 &&
5551 0 : std::abs(SensibleOutput - QToHeatSetPt) < (Small5WLoad / thisFurnace.ControlZoneMassFlowFrac)) {
5552 0 : state.dataFurnaces->HeatingLoad = false;
5553 : } // SensibleOutput .GT. 0.0d0 .AND. QToCoolSetPt .GT. 0.0d0
5554 : } // Furnace(FurnaceNum)%ControlZoneMassFlowFrac .GT. 0.0d0
5555 0 : ZoneLoad = QZnReq;
5556 : } // fanOp .EQ. FanOp::Continuous
5557 :
5558 15222 : if (FirstHVACIteration) {
5559 4846 : thisFurnace.iterationCounter = 0;
5560 4846 : thisFurnace.iterationMode = Furnaces::ModeOfOperation::NoCoolHeat;
5561 : }
5562 15222 : thisFurnace.iterationCounter += 1;
5563 :
5564 : // push iteration mode stack and set current mode
5565 15222 : thisFurnace.iterationMode(3) = thisFurnace.iterationMode(2);
5566 15222 : thisFurnace.iterationMode(2) = thisFurnace.iterationMode(1);
5567 15222 : if (state.dataFurnaces->CoolingLoad) {
5568 6748 : thisFurnace.iterationMode(1) = Furnaces::ModeOfOperation::CoolingMode;
5569 8474 : } else if (state.dataFurnaces->HeatingLoad) {
5570 8362 : thisFurnace.iterationMode(1) = Furnaces::ModeOfOperation::HeatingMode;
5571 : } else {
5572 112 : thisFurnace.iterationMode(1) = Furnaces::ModeOfOperation::NoCoolHeat;
5573 : }
5574 :
5575 : // IF small loads to meet or not converging, just shut down unit
5576 15222 : if (std::abs(ZoneLoad) < Small5WLoad) {
5577 112 : ZoneLoad = 0.0;
5578 112 : state.dataFurnaces->CoolingLoad = false;
5579 112 : state.dataFurnaces->HeatingLoad = false;
5580 15110 : } else if (thisFurnace.iterationCounter > (state.dataHVACGlobal->MinAirLoopIterationsAfterFirst + 4)) {
5581 : // attempt to lock output (air flow) if oscillations are detected
5582 0 : OperatingMode = thisFurnace.iterationMode(1);
5583 0 : OperatingModeMinusOne = thisFurnace.iterationMode(2);
5584 0 : OperatingModeMinusTwo = thisFurnace.iterationMode(3);
5585 0 : Oscillate = true;
5586 0 : if (OperatingMode == OperatingModeMinusOne && OperatingMode == OperatingModeMinusTwo) Oscillate = false;
5587 0 : if (Oscillate) {
5588 0 : if (QToCoolSetPt < 0.0) {
5589 0 : state.dataFurnaces->HeatingLoad = false;
5590 0 : state.dataFurnaces->CoolingLoad = true;
5591 0 : ZoneLoad = QToCoolSetPt;
5592 0 : } else if (QToHeatSetPt > 0.0) {
5593 0 : state.dataFurnaces->HeatingLoad = true;
5594 0 : state.dataFurnaces->CoolingLoad = false;
5595 0 : ZoneLoad = QToHeatSetPt;
5596 : } else {
5597 0 : state.dataFurnaces->HeatingLoad = false;
5598 0 : state.dataFurnaces->CoolingLoad = false;
5599 0 : ZoneLoad = 0.0;
5600 : }
5601 : }
5602 : }
5603 :
5604 : // EMS override point
5605 15222 : if (thisFurnace.EMSOverrideSensZoneLoadRequest) ZoneLoad = thisFurnace.EMSSensibleZoneLoadValue;
5606 15222 : if (thisFurnace.EMSOverrideMoistZoneLoadRequest) MoistureLoad = thisFurnace.EMSMoistureZoneLoadValue;
5607 15222 : if (thisFurnace.EMSOverrideSensZoneLoadRequest || thisFurnace.EMSOverrideMoistZoneLoadRequest) {
5608 0 : if ((ZoneLoad != 0.0) && (thisFurnace.EMSOverrideSensZoneLoadRequest)) {
5609 0 : PartLoadRatio = 1.0;
5610 0 : } else if ((MoistureLoad != 0.0) && (thisFurnace.EMSOverrideMoistZoneLoadRequest)) {
5611 0 : PartLoadRatio = 1.0;
5612 : } else {
5613 0 : PartLoadRatio = 0.0;
5614 : }
5615 0 : if (thisFurnace.NumOfSpeedCooling > 0) {
5616 0 : SetOnOffMassFlowRate(state, FurnaceNum, AirLoopNum, OnOffAirFlowRatio, fanOp, QZnReq, MoistureLoad, PartLoadRatio);
5617 : } else {
5618 : // This line is suspicious - all other calls to SetOnOffMassFlowRate pass in QZnReq, not ZoneLoad
5619 : // either way, it seems these two should be using the same parameters.
5620 0 : SetOnOffMassFlowRate(state, FurnaceNum, AirLoopNum, OnOffAirFlowRatio, fanOp, ZoneLoad, MoistureLoad, PartLoadRatio);
5621 : }
5622 : }
5623 :
5624 : // AirflowNetwork global variable
5625 15222 : if (state.afn->distribution_simulated) {
5626 11168 : state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).AFNLoopHeatingCoilMaxRTF = 0.0;
5627 : }
5628 15222 : }
5629 :
5630 15222 : void SetOnOffMassFlowRate(EnergyPlusData &state,
5631 : int const FurnaceNum, // index to furnace
5632 : [[maybe_unused]] int const AirLoopNum, // index to air loop !unused1208
5633 : Real64 &OnOffAirFlowRatio, // ratio of coil on to coil off air flow rate
5634 : HVAC::FanOp const fanOp, // fan operating mode
5635 : [[maybe_unused]] Real64 const ZoneLoad, // sensible load to be met (W) !unused1208
5636 : Real64 const MoistureLoad, // moisture load to be met (W)
5637 : Real64 const PartLoadRatio // coil part-load ratio
5638 : )
5639 : {
5640 :
5641 : // SUBROUTINE INFORMATION:
5642 : // AUTHOR Richard Raustad
5643 : // DATE WRITTEN Sep 2008
5644 :
5645 : // PURPOSE OF THIS SUBROUTINE:
5646 : // This subroutine is for initializations of the Furnace Components.
5647 :
5648 : // METHODOLOGY EMPLOYED:
5649 : // The HeatCool furnace/unitarysystem and air-to-air heat pump may have alternate air flow rates
5650 : // in cooling, heating, and when no cooling or heating is needed. Set up the coil (comp) ON and OFF
5651 : // air flow rates. Use these flow rates during the Calc routines to set the average mass flow rates
5652 : // based on PLR.
5653 :
5654 15222 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
5655 : // Check for heat only furnace
5656 15222 : if (thisFurnace.type != HVAC::UnitarySysType::Furnace_HeatOnly && thisFurnace.type != HVAC::UnitarySysType::Unitary_HeatOnly) {
5657 :
5658 : // Set the system mass flow rates
5659 15222 : if (fanOp == HVAC::FanOp::Continuous) {
5660 : // Set the compressor or coil ON mass flow rate
5661 : // constant fan mode
5662 0 : if (state.dataFurnaces->HeatingLoad) {
5663 : // IF a heating and moisture load exists, operate at the cooling mass flow rate ELSE operate at the heating flow rate
5664 0 : if (MoistureLoad < 0.0 && thisFurnace.Humidistat &&
5665 0 : thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat) {
5666 0 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxCoolAirMassFlow;
5667 0 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.CoolingSpeedRatio;
5668 : } else {
5669 0 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxHeatAirMassFlow;
5670 0 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.HeatingSpeedRatio;
5671 : }
5672 0 : thisFurnace.LastMode = Furnaces::ModeOfOperation::HeatingMode;
5673 : // IF a cooling load exists, operate at the cooling mass flow rate
5674 0 : } else if (state.dataFurnaces->CoolingLoad) {
5675 0 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxCoolAirMassFlow;
5676 0 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.CoolingSpeedRatio;
5677 0 : thisFurnace.LastMode = Furnaces::ModeOfOperation::CoolingMode;
5678 : // If no load exists, set the compressor on mass flow rate.
5679 : // Set equal the mass flow rate when no heating or cooling is needed if no moisture load exists.
5680 : // If the user has set the off mass flow rate to 0, set according to the last operating mode.
5681 : } else {
5682 0 : if (MoistureLoad < 0.0 && thisFurnace.Humidistat &&
5683 0 : thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat) {
5684 0 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxCoolAirMassFlow;
5685 0 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.CoolingSpeedRatio;
5686 : } else {
5687 0 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxNoCoolHeatAirMassFlow;
5688 0 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.HeatingSpeedRatio;
5689 : // User may have entered a 0 for MaxNoCoolHeatAirMassFlow
5690 0 : if (state.dataFurnaces->CompOnMassFlow == 0.0) {
5691 0 : if (thisFurnace.LastMode == Furnaces::ModeOfOperation::HeatingMode) {
5692 0 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxHeatAirMassFlow;
5693 0 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.HeatingSpeedRatio;
5694 : } else {
5695 0 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxCoolAirMassFlow;
5696 0 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.CoolingSpeedRatio;
5697 : }
5698 : }
5699 : }
5700 : }
5701 :
5702 : // Set the compressor or coil OFF mass flow rate based on LOGICAL flag
5703 : // UseCompressorOnFlow is used when the user does not enter a value for no cooling or heating flow rate
5704 0 : if (thisFurnace.AirFlowControl == AirFlowControlConstFan::UseCompressorOnFlow) {
5705 0 : if (thisFurnace.LastMode == Furnaces::ModeOfOperation::HeatingMode) {
5706 0 : if (MoistureLoad < 0.0 && thisFurnace.Humidistat &&
5707 0 : thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat) {
5708 0 : state.dataFurnaces->CompOffMassFlow = thisFurnace.MaxCoolAirMassFlow;
5709 0 : state.dataFurnaces->CompOffFlowRatio = thisFurnace.CoolingSpeedRatio;
5710 : } else {
5711 0 : state.dataFurnaces->CompOffMassFlow = thisFurnace.MaxHeatAirMassFlow;
5712 0 : state.dataFurnaces->CompOffFlowRatio = thisFurnace.HeatingSpeedRatio;
5713 : }
5714 : } else {
5715 0 : state.dataFurnaces->CompOffMassFlow = thisFurnace.MaxCoolAirMassFlow;
5716 0 : state.dataFurnaces->CompOffFlowRatio = thisFurnace.CoolingSpeedRatio;
5717 : }
5718 : // ELSE use the user specified value
5719 : } else {
5720 0 : state.dataFurnaces->CompOffMassFlow = thisFurnace.MaxNoCoolHeatAirMassFlow;
5721 0 : state.dataFurnaces->CompOffFlowRatio = thisFurnace.NoHeatCoolSpeedRatio;
5722 : }
5723 : } else {
5724 : // cycling fan mode
5725 22082 : if (state.dataFurnaces->HeatingLoad ||
5726 6860 : (thisFurnace.Humidistat && MoistureLoad < 0.0 && thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat)) {
5727 :
5728 8362 : if (thisFurnace.Humidistat && MoistureLoad < 0.0 &&
5729 0 : thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat) {
5730 0 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxCoolAirMassFlow;
5731 0 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.CoolingSpeedRatio;
5732 0 : thisFurnace.LastMode = Furnaces::ModeOfOperation::CoolingMode;
5733 : } else {
5734 8362 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxHeatAirMassFlow;
5735 8362 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.HeatingSpeedRatio;
5736 8362 : thisFurnace.LastMode = Furnaces::ModeOfOperation::HeatingMode;
5737 : }
5738 6860 : } else if (state.dataFurnaces->CoolingLoad) {
5739 6748 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxCoolAirMassFlow;
5740 6748 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.CoolingSpeedRatio;
5741 : } else {
5742 112 : state.dataFurnaces->CompOnMassFlow = 0.0;
5743 112 : state.dataFurnaces->CompOnFlowRatio = 0.0;
5744 : }
5745 15222 : state.dataFurnaces->CompOffMassFlow = 0.0;
5746 15222 : state.dataFurnaces->CompOffFlowRatio = 0.0;
5747 : }
5748 : } else { // Is a HeatOnly furnace
5749 :
5750 0 : state.dataFurnaces->CompOnMassFlow = thisFurnace.DesignMassFlowRate;
5751 0 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.HeatingSpeedRatio;
5752 0 : if (fanOp == HVAC::FanOp::Continuous) {
5753 0 : state.dataFurnaces->CompOffMassFlow = thisFurnace.MaxNoCoolHeatAirMassFlow;
5754 0 : state.dataFurnaces->CompOffFlowRatio = thisFurnace.HeatingSpeedRatio;
5755 : } else {
5756 0 : state.dataFurnaces->CompOffMassFlow = 0.0;
5757 0 : state.dataFurnaces->CompOffFlowRatio = 0.0;
5758 : }
5759 :
5760 : } // End check for heat only furnace or water-to-air heat pump
5761 :
5762 : // Set the system mass flow rates
5763 15222 : SetAverageAirFlow(state, FurnaceNum, PartLoadRatio, OnOffAirFlowRatio);
5764 15222 : }
5765 :
5766 2 : void SizeFurnace(EnergyPlusData &state, int const FurnaceNum, bool const FirstHVACIteration)
5767 : {
5768 :
5769 : // SUBROUTINE INFORMATION:
5770 : // AUTHOR Fred Buhl
5771 : // DATE WRITTEN January 2002
5772 : // MODIFIED Bereket Nigusse, May 2010, removed the autosize option for the input field supply air
5773 : // flow fraction through controlled zone.
5774 : // Bo Shen, March 2012, size the air flow rates at individual speed levels for VS WSHP
5775 : // Bo Shen, ORNL, July 2012 - added variable-speed air source heat pump cooling and heating coils, using curve-fits
5776 :
5777 : // PURPOSE OF THIS SUBROUTINE:
5778 : // This subroutine is for sizing Furnace Components for which nominal capacities
5779 : // and flow rates have not been specified in the input
5780 :
5781 : // METHODOLOGY EMPLOYED:
5782 : // Obtains heating capacities and flow rates from the zone or system sizing arrays.
5783 : // NOTE: In UNITARYSYSTEM:HEATPUMP:AIRTOAIR we are sizing the heating capacity to be
5784 : // equal to the cooling capacity. Thus the cooling and
5785 : // and heating capacities of a DX heat pump system will be identical. In real life the ARI
5786 : // heating and cooling capacities are close but not identical.
5787 :
5788 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5789 : int Iter; // iteration count
5790 : Real64 MulSpeedFlowScale; // variable speed air flow scaling factor
5791 : int IHPCoilIndex; // refer to cooling or heating coil in IHP
5792 2 : Real64 dummy(0.0);
5793 : bool anyRan;
5794 2 : EMSManager::ManageEMS(state, EMSManager::EMSCallFrom::UnitarySystemSizing, anyRan, ObjexxFCL::Optional_int_const()); // calling point
5795 :
5796 2 : state.dataSize->DXCoolCap = 0.0;
5797 2 : state.dataSize->UnitaryHeatCap = 0.0;
5798 2 : state.dataSize->SuppHeatCap = 0.0;
5799 2 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
5800 :
5801 2 : state.dataAirSystemsData->PrimaryAirSystems(state.dataSize->CurSysNum).supFanNum = thisFurnace.FanIndex;
5802 2 : state.dataAirSystemsData->PrimaryAirSystems(state.dataSize->CurSysNum).supFanType = thisFurnace.fanType;
5803 2 : state.dataSize->DataFanType = thisFurnace.fanType;
5804 2 : state.dataSize->DataFanIndex = thisFurnace.FanIndex;
5805 :
5806 2 : state.dataAirSystemsData->PrimaryAirSystems(state.dataSize->CurSysNum).supFanPlace = thisFurnace.fanPlace;
5807 :
5808 2 : if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingSingleSpeed) {
5809 2 : DXCoils::SimDXCoil(state, BlankString, HVAC::CompressorOp::On, true, thisFurnace.CoolingCoilIndex, HVAC::FanOp::Cycling, 0.0);
5810 0 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) {
5811 0 : int HXCC_Index = thisFurnace.CoolingCoilIndex;
5812 0 : int childCCType_Num = state.dataHVACAssistedCC->HXAssistedCoil(HXCC_Index).CoolingCoilType_Num;
5813 0 : if (childCCType_Num == HVAC::CoilDX_Cooling) {
5814 0 : int childCCIndex = state.dataHVACAssistedCC->HXAssistedCoil(HXCC_Index).CoolingCoilIndex;
5815 0 : if (childCCIndex < 0) {
5816 0 : ShowContinueError(state, "Occurs in sizing HeatExchangerAssistedCoolingCoil.");
5817 : }
5818 0 : auto &newCoil = state.dataCoilCoolingDX->coilCoolingDXs[childCCIndex];
5819 0 : newCoil.size(state);
5820 : }
5821 0 : HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(
5822 0 : state, BlankString, true, HVAC::CompressorOp::On, 0.0, thisFurnace.CoolingCoilIndex, HVAC::FanOp::Cycling, false, 1.0, false);
5823 0 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingWaterToAirHPSimple) {
5824 0 : WaterToAirHeatPumpSimple::SimWatertoAirHPSimple(state,
5825 : BlankString,
5826 0 : thisFurnace.CoolingCoilIndex,
5827 : thisFurnace.CoolingCoilSensDemand,
5828 : thisFurnace.CoolingCoilLatentDemand,
5829 : HVAC::FanOp::Invalid, // Using invalid to mean off?
5830 : HVAC::CompressorOp::Off,
5831 : 0.0,
5832 : FirstHVACIteration); // CoolPartLoadRatio
5833 0 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPSimple) {
5834 0 : WaterToAirHeatPumpSimple::SimWatertoAirHPSimple(state,
5835 : BlankString,
5836 0 : thisFurnace.HeatingCoilIndex,
5837 : thisFurnace.HeatingCoilSensDemand,
5838 : dummy,
5839 : HVAC::FanOp::Invalid, // using Invalid to mean off?
5840 : HVAC::CompressorOp::Off,
5841 : 0.0,
5842 : FirstHVACIteration);
5843 : }
5844 0 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingWaterToAirHPVSEquationFit ||
5845 0 : thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) {
5846 0 : if (thisFurnace.bIsIHP) {
5847 0 : IntegratedHeatPump::SizeIHP(state, thisFurnace.CoolingCoilIndex);
5848 0 : IHPCoilIndex = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SCCoilIndex;
5849 0 : thisFurnace.NumOfSpeedCooling = state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).NumOfSpeeds;
5850 0 : MulSpeedFlowScale = state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).RatedAirVolFlowRate /
5851 0 : state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex)
5852 0 : .MSRatedAirVolFlowRate(state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).NormSpedLevel);
5853 0 : state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).CoolVolFlowScale = MulSpeedFlowScale;
5854 : } else {
5855 0 : VariableSpeedCoils::SimVariableSpeedCoils(state,
5856 : BlankString,
5857 0 : thisFurnace.CoolingCoilIndex,
5858 : HVAC::FanOp::Invalid, // USing Invalid for off?
5859 : HVAC::CompressorOp::Off,
5860 : 0.0,
5861 : 1,
5862 : 0.0,
5863 : 0.0,
5864 : 0.0,
5865 : 0.0); // conduct the sizing operation in the VS WSHP
5866 0 : thisFurnace.NumOfSpeedCooling = state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.CoolingCoilIndex).NumOfSpeeds;
5867 0 : MulSpeedFlowScale =
5868 0 : state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.CoolingCoilIndex).RatedAirVolFlowRate /
5869 0 : state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.CoolingCoilIndex)
5870 0 : .MSRatedAirVolFlowRate(state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.CoolingCoilIndex).NormSpedLevel);
5871 0 : IHPCoilIndex = thisFurnace.CoolingCoilIndex;
5872 : }
5873 :
5874 0 : for (Iter = 1; Iter <= thisFurnace.NumOfSpeedCooling; ++Iter) {
5875 0 : thisFurnace.CoolVolumeFlowRate(Iter) =
5876 0 : state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).MSRatedAirVolFlowRate(Iter) * MulSpeedFlowScale;
5877 0 : thisFurnace.CoolMassFlowRate(Iter) =
5878 0 : state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).MSRatedAirMassFlowRate(Iter) * MulSpeedFlowScale;
5879 0 : thisFurnace.MSCoolingSpeedRatio(Iter) =
5880 0 : state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).MSRatedAirVolFlowRate(Iter) /
5881 0 : state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).MSRatedAirVolFlowRate(thisFurnace.NumOfSpeedCooling);
5882 : }
5883 :
5884 0 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPVSEquationFit ||
5885 0 : thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed) {
5886 :
5887 0 : if (thisFurnace.bIsIHP) {
5888 0 : IntegratedHeatPump::SizeIHP(state, thisFurnace.CoolingCoilIndex);
5889 0 : IHPCoilIndex = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SHCoilIndex;
5890 0 : thisFurnace.NumOfSpeedHeating = state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).NumOfSpeeds;
5891 0 : MulSpeedFlowScale = state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).RatedAirVolFlowRate /
5892 0 : state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex)
5893 0 : .MSRatedAirVolFlowRate(state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).NormSpedLevel);
5894 0 : state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).HeatVolFlowScale = MulSpeedFlowScale;
5895 : } else {
5896 0 : VariableSpeedCoils::SimVariableSpeedCoils(state,
5897 : BlankString,
5898 0 : thisFurnace.HeatingCoilIndex,
5899 : HVAC::FanOp::Invalid, // Invalid for off?
5900 : HVAC::CompressorOp::Off,
5901 : 0.0,
5902 : 1,
5903 : 0.0,
5904 : 0.0,
5905 : 0.0,
5906 : 0.0); // conduct the sizing operation in the VS WSHP
5907 0 : thisFurnace.NumOfSpeedHeating = state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.HeatingCoilIndex).NumOfSpeeds;
5908 0 : MulSpeedFlowScale =
5909 0 : state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.HeatingCoilIndex).RatedAirVolFlowRate /
5910 0 : state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.HeatingCoilIndex)
5911 0 : .MSRatedAirVolFlowRate(state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.HeatingCoilIndex).NormSpedLevel);
5912 0 : IHPCoilIndex = thisFurnace.HeatingCoilIndex;
5913 : }
5914 :
5915 0 : for (Iter = 1; Iter <= thisFurnace.NumOfSpeedHeating; ++Iter) {
5916 0 : thisFurnace.HeatVolumeFlowRate(Iter) =
5917 0 : state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).MSRatedAirVolFlowRate(Iter) * MulSpeedFlowScale;
5918 0 : thisFurnace.HeatMassFlowRate(Iter) =
5919 0 : state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).MSRatedAirMassFlowRate(Iter) * MulSpeedFlowScale;
5920 0 : thisFurnace.MSHeatingSpeedRatio(Iter) =
5921 0 : state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).MSRatedAirVolFlowRate(Iter) /
5922 0 : state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).MSRatedAirVolFlowRate(thisFurnace.NumOfSpeedHeating);
5923 : }
5924 : }
5925 :
5926 0 : if (thisFurnace.NumOfSpeedHeating > 0) {
5927 0 : thisFurnace.IdleMassFlowRate = min(thisFurnace.HeatMassFlowRate(1), thisFurnace.CoolMassFlowRate(1));
5928 0 : thisFurnace.IdleSpeedRatio = min(thisFurnace.MSHeatingSpeedRatio(1), thisFurnace.MSCoolingSpeedRatio(1));
5929 0 : thisFurnace.IdleVolumeAirRate = min(thisFurnace.HeatVolumeFlowRate(1), thisFurnace.CoolVolumeFlowRate(1));
5930 : } else {
5931 0 : thisFurnace.IdleMassFlowRate = thisFurnace.CoolMassFlowRate(1);
5932 0 : thisFurnace.IdleSpeedRatio = thisFurnace.MSCoolingSpeedRatio(1);
5933 0 : thisFurnace.IdleVolumeAirRate = thisFurnace.CoolVolumeFlowRate(1);
5934 : }
5935 :
5936 0 : if (thisFurnace.fanOp == HVAC::FanOp::Continuous) {
5937 0 : thisFurnace.MaxNoCoolHeatAirVolFlow = thisFurnace.IdleVolumeAirRate;
5938 0 : thisFurnace.MaxNoCoolHeatAirMassFlow = thisFurnace.IdleMassFlowRate;
5939 0 : thisFurnace.NoHeatCoolSpeedRatio = thisFurnace.IdleSpeedRatio;
5940 : }
5941 : }
5942 :
5943 2 : if (thisFurnace.DesignFanVolFlowRate == DataSizing::AutoSize) {
5944 :
5945 2 : if (state.dataSize->CurSysNum > 0) {
5946 :
5947 2 : CheckSysSizing(state, HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name);
5948 2 : if (state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesMainVolFlow >= HVAC::SmallAirVolFlow) {
5949 2 : thisFurnace.DesignFanVolFlowRate = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesMainVolFlow;
5950 : } else {
5951 0 : thisFurnace.DesignFanVolFlowRate = 0.0;
5952 : }
5953 :
5954 2 : if (thisFurnace.DesignFanVolFlowRateEMSOverrideOn) {
5955 0 : thisFurnace.DesignFanVolFlowRate = thisFurnace.DesignFanVolFlowRateEMSOverrideValue;
5956 : }
5957 :
5958 4 : BaseSizer::reportSizerOutput(state,
5959 2 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
5960 : thisFurnace.Name,
5961 : "Supply Air Flow Rate [m3/s]",
5962 : thisFurnace.DesignFanVolFlowRate);
5963 : }
5964 : }
5965 :
5966 2 : if (thisFurnace.MaxHeatAirVolFlow == DataSizing::AutoSize) {
5967 :
5968 2 : if (state.dataSize->CurSysNum > 0) {
5969 :
5970 2 : CheckSysSizing(state, HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name);
5971 2 : if (state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesMainVolFlow >= HVAC::SmallAirVolFlow) {
5972 2 : thisFurnace.MaxHeatAirVolFlow = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesMainVolFlow;
5973 : } else {
5974 0 : thisFurnace.MaxHeatAirVolFlow = 0.0;
5975 : }
5976 :
5977 2 : if (thisFurnace.MaxHeatAirVolFlowEMSOverrideOn) {
5978 0 : thisFurnace.MaxHeatAirVolFlow = thisFurnace.MaxHeatAirVolFlowEMSOverrideValue;
5979 : }
5980 4 : BaseSizer::reportSizerOutput(state,
5981 2 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
5982 : thisFurnace.Name,
5983 : "Supply Air Flow Rate During Heating Operation [m3/s]",
5984 : thisFurnace.MaxHeatAirVolFlow);
5985 : }
5986 : }
5987 :
5988 2 : if (thisFurnace.MaxCoolAirVolFlow == DataSizing::AutoSize) {
5989 :
5990 2 : if (state.dataSize->CurSysNum > 0) {
5991 :
5992 2 : CheckSysSizing(state, HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name);
5993 2 : if (state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesMainVolFlow >= HVAC::SmallAirVolFlow) {
5994 2 : thisFurnace.MaxCoolAirVolFlow = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesMainVolFlow;
5995 : } else {
5996 0 : thisFurnace.MaxCoolAirVolFlow = 0.0;
5997 : }
5998 :
5999 2 : if (thisFurnace.MaxCoolAirVolFlowEMSOverrideOn) {
6000 0 : thisFurnace.MaxCoolAirVolFlow = thisFurnace.MaxCoolAirVolFlowEMSOverrideValue;
6001 : }
6002 :
6003 4 : BaseSizer::reportSizerOutput(state,
6004 2 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6005 : thisFurnace.Name,
6006 : "Supply Air Flow Rate During Cooling Operation [m3/s]",
6007 : thisFurnace.MaxCoolAirVolFlow);
6008 : }
6009 : }
6010 :
6011 2 : if (thisFurnace.MaxNoCoolHeatAirVolFlow == DataSizing::AutoSize) {
6012 :
6013 1 : if (state.dataSize->CurSysNum > 0) {
6014 :
6015 1 : CheckSysSizing(state, HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name);
6016 1 : if (state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesMainVolFlow >= HVAC::SmallAirVolFlow) {
6017 1 : thisFurnace.MaxNoCoolHeatAirVolFlow = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesMainVolFlow;
6018 : } else {
6019 0 : thisFurnace.MaxNoCoolHeatAirVolFlow = 0.0;
6020 : }
6021 :
6022 1 : if (thisFurnace.MaxNoCoolHeatAirVolFlowEMSOverrideOn) {
6023 0 : thisFurnace.MaxNoCoolHeatAirVolFlow = thisFurnace.MaxNoCoolHeatAirVolFlowEMSOverrideValue;
6024 : }
6025 :
6026 2 : BaseSizer::reportSizerOutput(state,
6027 1 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6028 : thisFurnace.Name,
6029 : "Supply Air Flow Rate When No Cooling or Heating is Needed [m3/s]",
6030 : thisFurnace.MaxNoCoolHeatAirVolFlow);
6031 : }
6032 : }
6033 :
6034 2 : if (thisFurnace.DesignHeatingCapacity == DataSizing::AutoSize) {
6035 :
6036 2 : if (state.dataSize->CurSysNum > 0) {
6037 :
6038 2 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir ||
6039 0 : thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir) {
6040 :
6041 2 : CheckSysSizing(state, HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name);
6042 :
6043 2 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPSimple) {
6044 0 : thisFurnace.DesignHeatingCapacity =
6045 0 : state.dataWaterToAirHeatPumpSimple->SimpleWatertoAirHP(thisFurnace.HeatingCoilIndex).RatedCapHeat;
6046 : } else {
6047 2 : thisFurnace.DesignHeatingCapacity = state.dataSize->DXCoolCap;
6048 : }
6049 :
6050 : } else {
6051 :
6052 0 : CheckSysSizing(state, HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name);
6053 :
6054 0 : thisFurnace.DesignHeatingCapacity = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).HeatCap;
6055 : }
6056 :
6057 2 : if (thisFurnace.DesignHeatingCapacity < HVAC::SmallLoad) {
6058 0 : thisFurnace.DesignHeatingCapacity = 0.0;
6059 : }
6060 :
6061 4 : BaseSizer::reportSizerOutput(state,
6062 2 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6063 : thisFurnace.Name,
6064 : "Nominal Heating Capacity [W]",
6065 : thisFurnace.DesignHeatingCapacity);
6066 : }
6067 : }
6068 :
6069 2 : if (thisFurnace.DesignCoolingCapacity == DataSizing::AutoSize) {
6070 :
6071 2 : if (state.dataSize->CurSysNum > 0) {
6072 :
6073 2 : CheckSysSizing(state, HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name);
6074 2 : if (state.dataSize->DXCoolCap >= HVAC::SmallLoad) {
6075 2 : thisFurnace.DesignCoolingCapacity = state.dataSize->DXCoolCap;
6076 : } else {
6077 0 : thisFurnace.DesignCoolingCapacity = 0.0;
6078 : }
6079 4 : BaseSizer::reportSizerOutput(state,
6080 2 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6081 : thisFurnace.Name,
6082 : "Nominal Cooling Capacity [W]",
6083 : thisFurnace.DesignCoolingCapacity);
6084 : }
6085 : }
6086 :
6087 2 : if (thisFurnace.DesignMaxOutletTemp == DataSizing::AutoSize) {
6088 :
6089 1 : if (state.dataSize->CurSysNum > 0) {
6090 :
6091 1 : CheckSysSizing(state, HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name);
6092 1 : thisFurnace.DesignMaxOutletTemp = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).HeatSupTemp;
6093 2 : BaseSizer::reportSizerOutput(state,
6094 1 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6095 : thisFurnace.Name,
6096 : "Maximum Supply Air Temperature from Supplemental Heater [C]",
6097 : thisFurnace.DesignMaxOutletTemp);
6098 : }
6099 : }
6100 :
6101 2 : if (thisFurnace.DesignSuppHeatingCapacity == DataSizing::AutoSize) {
6102 :
6103 1 : if (state.dataSize->CurSysNum > 0) {
6104 :
6105 1 : CheckSysSizing(state, HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name);
6106 1 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir ||
6107 0 : thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir) {
6108 : // set the supplemental heating capacity to the actual heating load
6109 1 : thisFurnace.DesignSuppHeatingCapacity = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).HeatCap;
6110 : // if reheat needed for humidity control, make sure supplemental heating is at least as big
6111 : // as the cooling capacity
6112 1 : if (thisFurnace.Humidistat && thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat) {
6113 0 : thisFurnace.DesignSuppHeatingCapacity = max(thisFurnace.DesignSuppHeatingCapacity, thisFurnace.DesignCoolingCapacity);
6114 0 : if (thisFurnace.DesignSuppHeatingCapacity < HVAC::SmallLoad) {
6115 0 : thisFurnace.DesignSuppHeatingCapacity = 0.0;
6116 : }
6117 : }
6118 :
6119 : } else {
6120 :
6121 0 : if (thisFurnace.Humidistat && thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat) {
6122 0 : thisFurnace.DesignSuppHeatingCapacity = thisFurnace.DesignCoolingCapacity;
6123 : } else {
6124 0 : thisFurnace.DesignSuppHeatingCapacity = 0.0;
6125 : }
6126 : }
6127 :
6128 2 : BaseSizer::reportSizerOutput(state,
6129 1 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6130 : thisFurnace.Name,
6131 : "Supplemental Heating Coil Nominal Capacity [W]",
6132 : thisFurnace.DesignSuppHeatingCapacity);
6133 : }
6134 : }
6135 :
6136 2 : state.dataSize->UnitaryHeatCap = thisFurnace.DesignHeatingCapacity;
6137 2 : state.dataSize->SuppHeatCap = thisFurnace.DesignSuppHeatingCapacity;
6138 2 : }
6139 :
6140 : // End Initialization Section of the Module
6141 : //******************************************************************************
6142 :
6143 : // Beginning of Update subroutines for the Furnace Module
6144 : // *****************************************************************************
6145 :
6146 0 : void CalcNewZoneHeatOnlyFlowRates(EnergyPlusData &state,
6147 : int const FurnaceNum, // Index to furnace
6148 : bool const FirstHVACIteration, // Iteration flag
6149 : Real64 const ZoneLoad, // load to be met by furnace (W)
6150 : Real64 &HeatCoilLoad, // actual load passed to heating coil (W)
6151 : Real64 &OnOffAirFlowRatio // ratio of coil on to coil off air flow rate
6152 : )
6153 : {
6154 : // SUBROUTINE INFORMATION:
6155 : // AUTHOR Richard Liesen
6156 : // DATE WRITTEN Feb 2001
6157 : // MODIFIED Don Shirey and R. Raustad, Mar 2001 & Mar 2003
6158 :
6159 : // PURPOSE OF THIS SUBROUTINE:
6160 : // This subroutine updates the coil outlet nodes by simulating a heat-only
6161 : // furnace or unitary system.
6162 :
6163 : // METHODOLOGY EMPLOYED:
6164 : // Determine the operating PLR to meet the zone sensible load.
6165 :
6166 : // SUBROUTINE PARAMETER DEFINITIONS:
6167 0 : int constexpr MaxIter(15); // maximum number of iterations
6168 0 : Real64 constexpr MinPLR(0.0); // minimum part load ratio allowed
6169 :
6170 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
6171 0 : Real64 Error(1.0);
6172 : Real64 SystemSensibleLoad; // Sensible load to be met by furnace (W)
6173 : Real64 FullSensibleOutput; // Full sensible output of furnace (W)
6174 : Real64 FullLatentOutput; // Full latent output of furnace = 0 (W)
6175 : Real64 NoSensibleOutput; // Sensible output of furnace with no heating allowed (W)
6176 : Real64 NoLatentOutput; // Latent output of furnace = 0 (W)
6177 : Real64 PartLoadRatio; // Part load ratio of furnace
6178 : Real64 HeatErrorToler; // Error tolerance in heating mode
6179 : Real64 IterRelax; // Relaxation factor for iterations
6180 : Real64 ActualSensibleOutput; // Actual furnace sensible capacity
6181 : Real64 ActualLatentOutput; // Actual furnace latent capacity = 0
6182 : Real64 deltaT; // Heater outlet temp minus design heater outlet temp
6183 :
6184 0 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
6185 : // Retrieve the load on the controlled zone
6186 0 : auto &furnaceInNode = state.dataLoopNodes->Node(thisFurnace.FurnaceInletNodeNum);
6187 0 : auto const &furnaceOutNode = state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum);
6188 0 : int ControlZoneNode = thisFurnace.NodeNumOfControlledZone;
6189 0 : HVAC::FanOp fanOp = thisFurnace.fanOp; // fan operating mode
6190 0 : thisFurnace.MdotFurnace = thisFurnace.DesignMassFlowRate;
6191 0 : thisFurnace.CoolPartLoadRatio = 0.0;
6192 :
6193 : // Calculate the Cp Air of zone
6194 0 : Real64 cpair = Psychrometrics::PsyCpAirFnW(state.dataLoopNodes->Node(ControlZoneNode).HumRat);
6195 :
6196 0 : if (FirstHVACIteration) {
6197 0 : HeatCoilLoad = ZoneLoad;
6198 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
6199 : } else {
6200 : // If Furnace runs then set HeatCoilLoad on Heating Coil and the Mass Flow
6201 0 : if ((thisFurnace.availSched->getCurrentVal() > 0.0) && (furnaceInNode.MassFlowRate > 0.0) && (state.dataFurnaces->HeatingLoad)) {
6202 :
6203 0 : furnaceInNode.MassFlowRate = thisFurnace.MdotFurnace;
6204 0 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity;
6205 0 : SystemSensibleLoad = ZoneLoad;
6206 :
6207 : // Get no load result
6208 0 : if (fanOp == HVAC::FanOp::Cycling) {
6209 0 : furnaceInNode.MassFlowRate = 0.0;
6210 : }
6211 0 : if (fanOp == HVAC::FanOp::Continuous) {
6212 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0; // The on/off fan will not cycle, so set part-load fraction = 1
6213 : }
6214 :
6215 : // Set the inlet mass flow rate based on user specified coil OFF flow rate
6216 0 : PartLoadRatio = 0.0;
6217 0 : SetAverageAirFlow(state, FurnaceNum, PartLoadRatio, OnOffAirFlowRatio);
6218 :
6219 0 : CalcFurnaceOutput(state,
6220 : FurnaceNum,
6221 : FirstHVACIteration,
6222 : fanOp,
6223 : HVAC::CompressorOp::On,
6224 : 0.0,
6225 : 0.0,
6226 : 0.0,
6227 : 0.0,
6228 : NoSensibleOutput,
6229 : NoLatentOutput,
6230 : OnOffAirFlowRatio,
6231 : false);
6232 :
6233 0 : furnaceInNode.MassFlowRate = thisFurnace.MdotFurnace;
6234 :
6235 : // Set fan part-load fraction equal to 1 while getting full load result
6236 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
6237 0 : OnOffAirFlowRatio = 1.0;
6238 :
6239 : // Get full load result
6240 0 : CalcFurnaceOutput(state,
6241 : FurnaceNum,
6242 : FirstHVACIteration,
6243 : fanOp,
6244 : HVAC::CompressorOp::On,
6245 : 0.0,
6246 : 1.0,
6247 : HeatCoilLoad,
6248 : 0.0,
6249 : FullSensibleOutput,
6250 : FullLatentOutput,
6251 : OnOffAirFlowRatio,
6252 : false);
6253 :
6254 : // Since we are heating, we expect FullSensibleOutput to be > 0 and FullSensibleOutput > NoSensibleOutput
6255 : // Check that this is the case; if not set PartLoadRatio = 0.0d0 (off) and return
6256 :
6257 0 : if (FullSensibleOutput > NoSensibleOutput) {
6258 : PartLoadRatio =
6259 0 : max(MinPLR, min(1.0, std::abs(SystemSensibleLoad - NoSensibleOutput) / std::abs(FullSensibleOutput - NoSensibleOutput)));
6260 0 : if (fanOp == HVAC::FanOp::Cycling) {
6261 0 : furnaceInNode.MassFlowRate = thisFurnace.MdotFurnace * PartLoadRatio;
6262 0 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity * PartLoadRatio;
6263 : } else { // FanOp::Continuous
6264 0 : if (furnaceOutNode.Temp > thisFurnace.DesignMaxOutletTemp) {
6265 0 : deltaT = furnaceOutNode.Temp - thisFurnace.DesignMaxOutletTemp;
6266 0 : if (HeatCoilLoad > thisFurnace.DesignHeatingCapacity) HeatCoilLoad = thisFurnace.DesignHeatingCapacity;
6267 0 : HeatCoilLoad -= furnaceInNode.MassFlowRate * cpair * deltaT;
6268 : } else {
6269 0 : HeatCoilLoad = SystemSensibleLoad - NoSensibleOutput;
6270 : }
6271 : }
6272 :
6273 : // Calculate the part load ratio through iteration
6274 0 : HeatErrorToler = thisFurnace.HeatingConvergenceTolerance; // Error tolerance for convergence from input deck
6275 0 : Error = 1.0; // initialize error value for comparison against tolerance
6276 0 : state.dataFurnaces->Iter = 0; // initialize iteration counter
6277 0 : IterRelax = 0.9; // relaxation factor for iterations
6278 0 : while (state.dataFurnaces->Iter <= MaxIter) {
6279 :
6280 0 : if (fanOp == HVAC::FanOp::Cycling) furnaceInNode.MassFlowRate = thisFurnace.MdotFurnace * PartLoadRatio;
6281 0 : CalcFurnaceOutput(state,
6282 : FurnaceNum,
6283 : FirstHVACIteration,
6284 : fanOp,
6285 : HVAC::CompressorOp::On,
6286 : 0.0,
6287 : PartLoadRatio,
6288 : HeatCoilLoad,
6289 : 0.0,
6290 : ActualSensibleOutput,
6291 : ActualLatentOutput,
6292 : OnOffAirFlowRatio,
6293 : false);
6294 :
6295 0 : if (SystemSensibleLoad != 0.0) Error = (SystemSensibleLoad - ActualSensibleOutput) / (SystemSensibleLoad);
6296 0 : if (std::abs(Error) <= HeatErrorToler) break;
6297 0 : PartLoadRatio = max(
6298 : MinPLR,
6299 : min(1.0,
6300 0 : PartLoadRatio + IterRelax * (SystemSensibleLoad - ActualSensibleOutput) / (FullSensibleOutput - NoSensibleOutput)));
6301 :
6302 : // limit the heating coil outlet air temperature to DesignMaxOutletTemp
6303 0 : if (furnaceOutNode.Temp > thisFurnace.DesignMaxOutletTemp) {
6304 0 : deltaT = furnaceOutNode.Temp - thisFurnace.DesignMaxOutletTemp;
6305 0 : if (HeatCoilLoad > thisFurnace.DesignHeatingCapacity) HeatCoilLoad = thisFurnace.DesignHeatingCapacity;
6306 0 : HeatCoilLoad -= furnaceInNode.MassFlowRate * cpair * deltaT;
6307 0 : CalcFurnaceOutput(state,
6308 : FurnaceNum,
6309 : FirstHVACIteration,
6310 : fanOp,
6311 : HVAC::CompressorOp::On,
6312 : 0.0,
6313 : PartLoadRatio,
6314 : HeatCoilLoad,
6315 : 0.0,
6316 : ActualSensibleOutput,
6317 : ActualLatentOutput,
6318 : OnOffAirFlowRatio,
6319 : false);
6320 :
6321 0 : if (SystemSensibleLoad != 0.0) Error = (SystemSensibleLoad - ActualSensibleOutput) / (SystemSensibleLoad);
6322 0 : PartLoadRatio = max(MinPLR,
6323 : min(1.0,
6324 0 : PartLoadRatio + IterRelax * (SystemSensibleLoad - ActualSensibleOutput) /
6325 0 : (FullSensibleOutput - NoSensibleOutput)));
6326 : } else {
6327 0 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity * PartLoadRatio;
6328 : }
6329 :
6330 0 : if (PartLoadRatio == MinPLR) break;
6331 0 : if (PartLoadRatio == 1.0) break;
6332 0 : ++state.dataFurnaces->Iter;
6333 0 : if (state.dataFurnaces->Iter == 7) IterRelax = 0.7;
6334 0 : if (state.dataFurnaces->Iter == 15) IterRelax = 0.4;
6335 : }
6336 :
6337 0 : if (state.dataFurnaces->Iter > MaxIter) {
6338 0 : if (thisFurnace.HeatingMaxIterIndex2 == 0) {
6339 0 : ShowWarningMessage(state,
6340 0 : format("{} \"{}\" -- Exceeded max heating iterations ({}) while adjusting furnace runtime.",
6341 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6342 0 : thisFurnace.Name,
6343 : MaxIter));
6344 0 : ShowContinueErrorTimeStamp(state, "");
6345 : }
6346 0 : ShowRecurringWarningErrorAtEnd(state,
6347 0 : format("{} \"{}\" -- Exceeded max heating iterations error continues...",
6348 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6349 0 : thisFurnace.Name),
6350 0 : thisFurnace.HeatingMaxIterIndex2);
6351 : }
6352 :
6353 : } else { // ELSE from IF(FullSensibleOutput.GT.NoSensibleOutput)THEN above
6354 : // Set part load ratio to 1 and run heater at design heating capacity
6355 0 : PartLoadRatio = 1.0;
6356 0 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity;
6357 : }
6358 : // Set the final results
6359 : // IF (fanOp .EQ. FanOp::Cycling) THEN
6360 : // Furnace(FurnaceNum)%MdotFurnace = Furnace(FurnaceNum)%MdotFurnace * PartLoadRatio
6361 : // END IF
6362 0 : thisFurnace.MdotFurnace = furnaceInNode.MassFlowRate;
6363 :
6364 0 : } else if ((thisFurnace.availSched->getCurrentVal() > 0.0) && (furnaceInNode.MassFlowRate > 0.0) && (fanOp == HVAC::FanOp::Continuous)) {
6365 0 : HeatCoilLoad = 0.0;
6366 : } else { // no heating and no flow
6367 0 : thisFurnace.MdotFurnace = 0.0;
6368 0 : HeatCoilLoad = 0.0;
6369 : } // End of the Scheduled Furnace If block
6370 :
6371 : } // End of the FirstHVACIteration control of the mass flow If block
6372 :
6373 : // Set the fan inlet node flow rates
6374 0 : furnaceInNode.MassFlowRateMaxAvail = thisFurnace.MdotFurnace;
6375 0 : furnaceInNode.MassFlowRate = thisFurnace.MdotFurnace;
6376 0 : }
6377 :
6378 15225 : void CalcNewZoneHeatCoolFlowRates(EnergyPlusData &state,
6379 : int const FurnaceNum,
6380 : bool const FirstHVACIteration,
6381 : HVAC::CompressorOp const compressorOp, // compressor operation flag (1=On, 0=Off)
6382 : Real64 const ZoneLoad, // the control zone load (watts)
6383 : Real64 const MoistureLoad, // the control zone latent load (watts)
6384 : Real64 &HeatCoilLoad, // Heating load to be met by heating coil ( excluding heat pump DX coil)
6385 : Real64 &ReheatCoilLoad, // Heating load to be met by reheat coil using hstat (excluding HP DX coil)
6386 : Real64 &OnOffAirFlowRatio, // Ratio of compressor ON air flow to AVERAGE air flow over time step
6387 : bool &HXUnitOn // flag to control HX based on zone moisture load
6388 : )
6389 : {
6390 : // SUBROUTINE INFORMATION:
6391 : // AUTHOR Richard Liesen
6392 : // DATE WRITTEN Feb 2001
6393 : // MODIFIED R. Raustad and D. Shirey, Feb/Mar/Sept/Oct/Dec 2001, Jan/Oct 2002
6394 : // RE-ENGINEERED R. Raustad, Feb. 2005 (added RegulaFalsi for iteration technique)
6395 :
6396 : // PURPOSE OF THIS SUBROUTINE:
6397 : // This subroutine updates the coil outlet nodes.
6398 :
6399 : // METHODOLOGY EMPLOYED:
6400 : // Determine the operating PLR to meet the zone sensible load. If a humidistat is specified, determine
6401 : // the operating PLR (greater of the sensible and latent PLR) to meet the zone SENSIBLE load
6402 : // (Multimode dehumidification control) or zone LATENT load (CoolReheat dehumidification control).
6403 : // For dehumidification control type COOLREHEAT, both a sensible and latent PLR may exist for a
6404 : // single time step (heating and dehumidification can occur). For all other system types,
6405 : // only a single PLR is allowed for any given time step.
6406 : // Order of simulation depends on dehumidification control option as described below.
6407 : // Dehumidification control options:
6408 : // Dehumidification Control NONE: Cooling performance is simulated first and then heating performance. If a HX
6409 : // assisted cooling coil is selected, the HX is always active.
6410 : // Dehumidification Control COOLREHEAT: Continuous Fan Operation:
6411 : // For cooling operation, the sensible and latent capacities are calculated to
6412 : // meet the thermostat setpoint. If a HX assisted cooling coil is selected,
6413 : // the HX is always active. If the latent load is not met by operating the
6414 : // system at the sensible PLR, a new PLR is calculated to meet the humidistat
6415 : // setpoint. The reheat coil load is then calculated to meet the HEATING
6416 : // setpoint temperature.
6417 : // Cycling Fan Operation:
6418 : // The heating part-load ratio is calculated first. Since the fan will be
6419 : // controlled at the higher of the heating or cooling PLR's, a ratio of the
6420 : // cooling to heating PLR is used to pass to the cooling coil (MAX=1). This allows
6421 : // the cooling coil to operate at the heating PLR when the heating PLR is
6422 : // higher than the cooling PLR. The sensible and latent capacities are then
6423 : // calculated to meet the thermostat setpoint.
6424 : // If a HX assisted cooling coil is selected, the HX is always active.
6425 : // If the latent load is not met by operating the system at the sensible PLR,
6426 : // a new PLR is calculated to meet the humidistat setpoint.
6427 : // The reheat coil load is then calculated to meet the HEATING setpoint temperature.
6428 : // Dehumidification Control MULTIMODE: For cooling operation, the sensible and latent capacities are calculated to
6429 : // meet the thermostat setpoint. If a HX assisted cooling coil is selected,
6430 : // the HX is off for this calculation. If the latent load is not met by operating
6431 : // the system at the sensible PLR, a new PLR is calculated with the HX operating
6432 : // and the target is the thermostat setpoint. Humidity is not controlled in this
6433 : // mode. No reheat coil is used in this configuration.
6434 : // Note: A supplemental heater augments the heating capacity for air-to-air heat pumps.
6435 : // A reheat coil is used for the HeatCool furnace/unitarysystem to offset the sensible cooling when the
6436 : // dehumidification control type is COOLREHEAT. Both the supplemental and reheat heating coil load is calculated
6437 : // in the Calc routines. The actual simulation of these coils is performed in the SimFurnace routine (i.e. the
6438 : // supplemental and reheat coil loads are passed as 0 to CalcFurnaceOutput).
6439 :
6440 : // SUBROUTINE PARAMETER DEFINITIONS:
6441 15225 : int constexpr MaxIter(100); // maximum number of iterations
6442 15225 : Real64 constexpr MinPLR(0.0); // minimum part load ratio allowed
6443 :
6444 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
6445 : Real64 SystemMoistureLoad; // Total latent load to be removed by furnace/unitary system
6446 : Real64 deltaT; // Temperature rise across heating coil (C)
6447 : Real64 TempOutHeatingCoil; // Temperature leaving heating coil (C)
6448 : Real64 FullSensibleOutput; // Full sensible output of AC (W)
6449 : Real64 FullLatentOutput; // Full latent output of AC (W)
6450 : Real64 NoCoolOutput; // Sensible output of AC with no cooling allowed (W)
6451 : Real64 NoHeatOutput; // Sensible output of heater with no heating allowed (W)
6452 : Real64 NoLatentOutput; // Latent output of AC with no cooling allowed (W)
6453 : Real64 CoolErrorToler; // Error tolerance in cooling mode
6454 : Real64 HeatErrorToler; // Error tolerance in heating mode
6455 : Real64 ActualSensibleOutput; // Actual furnace sensible capacity
6456 : Real64 ActualLatentOutput; // Actual furnace latent capacity
6457 : Real64 PartLoadRatio; // Part load ratio (greater of sensible or latent part load ratio for cooling,
6458 : // or heating PLR)
6459 : Real64 LatentPartLoadRatio; // Part load ratio to meet dehumidification load
6460 : Real64 TempCoolOutput; // Temporary Sensible output of AC while iterating on PLR (W)
6461 : Real64 TempHeatOutput; // Temporary Sensible output of heating coil while iterating on PLR (W)
6462 : Real64 TempLatentOutput; // Temporary Latent output of AC at increasing PLR (W)
6463 : // ! (Temp variables are used to find min PLR for positive latent removal)
6464 : Real64 TempMinPLR; // Temporary min latent PLR when hum control is required and iter is exceeded
6465 : Real64 TempMinPLR2; // Temporary min latent PLR when cyc fan hum control is required and iter is exceeded
6466 : Real64 TempMaxPLR; // Temporary max latent PLR when hum control is required and iter is exceeded
6467 : Real64 QToHeatSetPt; // Load required to meet heating setpoint temp (>0 is a heating load)
6468 : Real64 CoolingHeatingPLRRatio; // ratio of cooling to heating PLR (MAX=1). Used in heating mode.
6469 : Real64 HeatingSensibleOutput;
6470 : Real64 HeatingLatentOutput;
6471 : Real64 OutdoorDryBulbTemp; // secondary coil (condenser) entering dry bulb temperature
6472 :
6473 15225 : Real64 &SystemSensibleLoad = state.dataFurnaces->SystemSensibleLoad;
6474 15225 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
6475 : // Set local variables
6476 15225 : int FurnaceOutletNode = thisFurnace.FurnaceOutletNodeNum;
6477 15225 : int FurnaceInletNode = thisFurnace.FurnaceInletNodeNum;
6478 15225 : int ControlZoneNode = thisFurnace.NodeNumOfControlledZone;
6479 15225 : HVAC::FanOp fanOp = thisFurnace.fanOp; // fan operating mode
6480 15225 : bool HumControl = false;
6481 : // Calculate the Cp Air of zone
6482 15225 : Real64 cpair = Psychrometrics::PsyCpAirFnW(state.dataLoopNodes->Node(ControlZoneNode).HumRat);
6483 15225 : NoHeatOutput = 0.0;
6484 15225 : SystemSensibleLoad = 0.0;
6485 15225 : ReheatCoilLoad = 0.0;
6486 15225 : HeatCoilLoad = 0.0;
6487 15225 : ReheatCoilLoad = 0.0;
6488 15225 : PartLoadRatio = 0.0;
6489 :
6490 15225 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir) {
6491 15222 : if (state.dataDXCoils->DXCoil(thisFurnace.HeatingCoilIndex)
6492 15222 : .IsSecondaryDXCoilInZone) { // assumes compressor is in same location as secondary coil
6493 0 : OutdoorDryBulbTemp =
6494 0 : state.dataZoneTempPredictorCorrector->zoneHeatBalance(state.dataDXCoils->DXCoil(thisFurnace.HeatingCoilIndex).SecZonePtr).ZT;
6495 15222 : } else if (state.dataDXCoils->DXCoil(thisFurnace.CoolingCoilIndex).IsSecondaryDXCoilInZone) {
6496 0 : OutdoorDryBulbTemp =
6497 0 : state.dataZoneTempPredictorCorrector->zoneHeatBalance(state.dataDXCoils->DXCoil(thisFurnace.CoolingCoilIndex).SecZonePtr).ZT;
6498 : } else {
6499 15222 : if (thisFurnace.CondenserNodeNum > 0) {
6500 0 : OutdoorDryBulbTemp = state.dataLoopNodes->Node(thisFurnace.CondenserNodeNum).Temp;
6501 : } else {
6502 15222 : OutdoorDryBulbTemp = state.dataEnvrn->OutDryBulbTemp;
6503 : }
6504 : }
6505 : } else {
6506 3 : OutdoorDryBulbTemp = state.dataEnvrn->OutDryBulbTemp;
6507 : }
6508 15225 : if (FirstHVACIteration) {
6509 : // Set selected values during first HVAC iteration
6510 :
6511 : // Init for heating
6512 4847 : if (state.dataFurnaces->HeatingLoad) {
6513 3103 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir ||
6514 0 : (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir && thisFurnace.WatertoAirHPType == WAHPCoilType::Simple)) {
6515 3103 : thisFurnace.HeatPartLoadRatio = 1.0;
6516 3103 : HeatCoilLoad = 0.0;
6517 3103 : thisFurnace.HeatingCoilSensDemand = 0.0;
6518 3103 : thisFurnace.CoolingCoilSensDemand = 0.0;
6519 3103 : thisFurnace.CoolingCoilLatentDemand = 0.0;
6520 : } else { // for furnaces
6521 0 : thisFurnace.HeatPartLoadRatio = 0.0;
6522 0 : HeatCoilLoad = ZoneLoad;
6523 0 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.MdotFurnace;
6524 0 : thisFurnace.HeatingCoilSensDemand = 0.0;
6525 0 : thisFurnace.CoolingCoilSensDemand = 0.0;
6526 0 : thisFurnace.CoolingCoilLatentDemand = 0.0;
6527 : }
6528 3103 : ReheatCoilLoad = 0.0;
6529 3103 : thisFurnace.CoolPartLoadRatio = 0.0;
6530 :
6531 : // Init for cooling
6532 1744 : } else if (state.dataFurnaces->CoolingLoad) {
6533 : // air to air heat pumps
6534 1687 : thisFurnace.CoolPartLoadRatio = 1.0;
6535 1687 : thisFurnace.HeatPartLoadRatio = 0.0;
6536 1687 : HeatCoilLoad = 0.0;
6537 1687 : ReheatCoilLoad = 0.0;
6538 :
6539 : // Init for moisture load only
6540 : } else {
6541 57 : thisFurnace.CoolPartLoadRatio = 0.0;
6542 57 : thisFurnace.HeatPartLoadRatio = 0.0;
6543 57 : HeatCoilLoad = 0.0;
6544 57 : ReheatCoilLoad = 0.0;
6545 57 : thisFurnace.HeatingCoilSensDemand = 0.0;
6546 57 : thisFurnace.CoolingCoilSensDemand = 0.0;
6547 57 : thisFurnace.CoolingCoilLatentDemand = 0.0;
6548 : }
6549 :
6550 4847 : SetAverageAirFlow(state, FurnaceNum, max(thisFurnace.HeatPartLoadRatio, thisFurnace.CoolPartLoadRatio), OnOffAirFlowRatio);
6551 : // if dehumidification load exists (for heat pumps) turn on the supplemental heater
6552 4847 : if (state.dataFurnaces->HPDehumidificationLoadFlag) HumControl = true;
6553 : } else { // not FirstHVACIteration
6554 : // Init for heating
6555 10378 : Real64 &CoolCoilLoad = state.dataFurnaces->CoolCoilLoad;
6556 10378 : if (state.dataFurnaces->HeatingLoad) {
6557 5260 : CoolCoilLoad = 0.0;
6558 5260 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir ||
6559 1 : (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir && thisFurnace.WatertoAirHPType == WAHPCoilType::Simple)) {
6560 5260 : SystemSensibleLoad = ZoneLoad;
6561 5260 : SystemMoistureLoad = 0.0;
6562 5260 : HeatCoilLoad = 0.0;
6563 5260 : thisFurnace.HeatingCoilSensDemand = SystemSensibleLoad;
6564 5260 : thisFurnace.CoolingCoilSensDemand = 0.0;
6565 5260 : thisFurnace.CoolingCoilLatentDemand = 0.0;
6566 : } else {
6567 0 : SystemMoistureLoad = MoistureLoad;
6568 0 : HeatCoilLoad = ZoneLoad;
6569 : }
6570 :
6571 : // Init for cooling
6572 5118 : } else if (state.dataFurnaces->CoolingLoad) {
6573 5061 : CoolCoilLoad = ZoneLoad;
6574 5061 : SystemMoistureLoad = MoistureLoad;
6575 5061 : HeatCoilLoad = 0.0;
6576 5061 : thisFurnace.CoolingCoilSensDemand = std::abs(CoolCoilLoad);
6577 5061 : thisFurnace.CoolingCoilLatentDemand = std::abs(SystemMoistureLoad);
6578 5061 : thisFurnace.HeatingCoilSensDemand = 0.0;
6579 :
6580 : // Init for latent
6581 : } else {
6582 57 : SystemMoistureLoad = MoistureLoad;
6583 57 : CoolCoilLoad = 0.0;
6584 57 : HeatCoilLoad = 0.0;
6585 : // set report variables
6586 57 : thisFurnace.CoolingCoilSensDemand = 0.0;
6587 57 : thisFurnace.CoolingCoilLatentDemand = SystemMoistureLoad;
6588 57 : thisFurnace.HeatingCoilSensDemand = 0.0;
6589 : }
6590 10378 : HeatingSensibleOutput = 0.0;
6591 10378 : HeatingLatentOutput = 0.0;
6592 10378 : ReheatCoilLoad = 0.0;
6593 10378 : thisFurnace.CoolPartLoadRatio = 0.0;
6594 10378 : thisFurnace.HeatPartLoadRatio = 0.0;
6595 10378 : thisFurnace.CompPartLoadRatio = 0.0;
6596 10378 : thisFurnace.DehumidInducedHeatingDemandRate = 0.0;
6597 :
6598 : // When humidity control is used with cycling fan control and a heating load exists, if a moisture load
6599 : // also exists, the heating PLR must be available for the cooling coil calculations.
6600 : //*********** Heating Section ************
6601 : // If Furnace runs with a heating load then set HeatCoilLoad on Heating Coil and the Mass Flow
6602 : // (Node(FurnaceInletNode)%MassFlowRate .gt. 0.0d0) .and. &
6603 10378 : if ((thisFurnace.availSched->getCurrentVal() > 0.0) && (state.dataFurnaces->HeatingLoad)) {
6604 :
6605 : // Heat pumps only calculate a single PLR each time step (i.e. only cooling or heating allowed in a single time step)
6606 5260 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir ||
6607 1 : (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir && thisFurnace.WatertoAirHPType == WAHPCoilType::Simple)) {
6608 :
6609 5260 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.MdotFurnace;
6610 :
6611 : // Get no load result
6612 5260 : if (fanOp == HVAC::FanOp::Cycling) {
6613 5259 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = 0.0;
6614 : }
6615 :
6616 : // Set the inlet mass flow rate based on user specified coil OFF flow rate
6617 5260 : PartLoadRatio = 0.0;
6618 :
6619 5260 : SetAverageAirFlow(state, FurnaceNum, PartLoadRatio, OnOffAirFlowRatio);
6620 :
6621 : // Set the input parameters for CalcFurnaceOutput
6622 5260 : thisFurnace.CompPartLoadRatio = 0.0; // compressor off
6623 :
6624 5260 : CalcFurnaceOutput(state,
6625 : FurnaceNum,
6626 : FirstHVACIteration,
6627 : fanOp,
6628 : compressorOp,
6629 : 0.0,
6630 : MinPLR,
6631 : 0.0,
6632 : 0.0,
6633 : NoHeatOutput,
6634 : NoLatentOutput,
6635 : OnOffAirFlowRatio,
6636 : false);
6637 :
6638 5260 : PartLoadRatio = 1.0;
6639 5260 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.MdotFurnace;
6640 :
6641 5260 : thisFurnace.CompPartLoadRatio = 1.0; // compressor ON
6642 :
6643 : // Set fan part-load fraction equal to 1 while getting full load result
6644 5260 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
6645 5260 : OnOffAirFlowRatio = 1.0;
6646 :
6647 : // Get full load result
6648 5260 : CalcFurnaceOutput(state,
6649 : FurnaceNum,
6650 : FirstHVACIteration,
6651 : fanOp,
6652 : compressorOp,
6653 : 0.0,
6654 : PartLoadRatio,
6655 : 0.0,
6656 : 0.0,
6657 : FullSensibleOutput,
6658 : FullLatentOutput,
6659 : OnOffAirFlowRatio,
6660 : false);
6661 :
6662 : // Check that SystemSensibleLoad is between FullSensibleOutput and NoHeatOutput
6663 : // If so then calculate PartLoadRatio for the DX Heating coil
6664 5260 : if (SystemSensibleLoad < FullSensibleOutput && SystemSensibleLoad > NoHeatOutput) {
6665 :
6666 : // Calculate the part load ratio through iteration
6667 8 : HeatErrorToler = thisFurnace.HeatingConvergenceTolerance; // Error tolerance for convergence from input deck
6668 :
6669 8 : int SolFlag = 0; // # of iterations if positive, -1 means failed to converge, -2 means bounds are incorrect
6670 : // HeatErrorToler is in fraction of load, MaxIter = 30, SolFalg = # of iterations or error as appropriate
6671 32 : auto f = [&state, FurnaceNum, FirstHVACIteration, fanOp, compressorOp, SystemSensibleLoad](Real64 const PartLoadRatio) {
6672 24 : return CalcFurnaceResidual(state,
6673 : PartLoadRatio,
6674 : FurnaceNum,
6675 : FirstHVACIteration,
6676 : fanOp,
6677 : compressorOp,
6678 : SystemSensibleLoad,
6679 : 0.0, // par6_loadFlag,
6680 : 1.0, // par7_sensLatentFlag,
6681 : 0.0, // par9_HXOnFlag,
6682 24 : 0.0); // par10_HeatingCoilPLR);
6683 8 : };
6684 8 : General::SolveRoot(state, HeatErrorToler, MaxIter, SolFlag, PartLoadRatio, f, 0.0, 1.0);
6685 : // OnOffAirFlowRatio is updated during the above iteration. Reset to correct value based on PLR.
6686 8 : OnOffAirFlowRatio = state.dataFurnaces->OnOffAirFlowRatioSave;
6687 8 : if (SolFlag < 0) {
6688 0 : if (SolFlag == -1) {
6689 0 : CalcFurnaceOutput(state,
6690 : FurnaceNum,
6691 : FirstHVACIteration,
6692 : fanOp,
6693 : compressorOp,
6694 : 0.0,
6695 : PartLoadRatio,
6696 : 0.0,
6697 : 0.0,
6698 : TempHeatOutput,
6699 : TempLatentOutput,
6700 : OnOffAirFlowRatio,
6701 : false);
6702 0 : if (std::abs(SystemSensibleLoad - TempHeatOutput) > HVAC::SmallLoad) {
6703 0 : if (thisFurnace.DXHeatingMaxIterIndex == 0) {
6704 0 : ShowWarningMessage(state,
6705 0 : format("Heating coil control failed to converge for {}:{}",
6706 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6707 0 : thisFurnace.Name));
6708 0 : ShowContinueError(state,
6709 : " Iteration limit exceeded in calculating DX heating coil sensible part-load ratio.");
6710 0 : ShowContinueErrorTimeStamp(
6711 : state,
6712 0 : format("Sensible load to be met by DX heating coil = {:.2T} (watts), sensible output of DX heating "
6713 : "coil = {:.2T} (watts), and the simulation continues.",
6714 : SystemSensibleLoad,
6715 : TempHeatOutput));
6716 : }
6717 0 : ShowRecurringWarningErrorAtEnd(state,
6718 0 : format("{} \"{}\" - Iteration limit exceeded in calculating DX sensible heating "
6719 : "part-load ratio error continues. "
6720 : "Sensible load statistics:",
6721 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6722 0 : thisFurnace.Name),
6723 0 : thisFurnace.DXHeatingMaxIterIndex,
6724 : SystemSensibleLoad,
6725 : SystemSensibleLoad);
6726 : }
6727 0 : } else if (SolFlag == -2) {
6728 0 : if (thisFurnace.DXHeatingRegulaFalsiFailedIndex == 0) {
6729 0 : ShowWarningMessage(state,
6730 0 : format("Heating coil control failed for {}:{}",
6731 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6732 0 : thisFurnace.Name));
6733 0 : ShowContinueError(state, " DX sensible heating part-load ratio determined to be outside the range of 0-1.");
6734 0 : ShowContinueErrorTimeStamp(
6735 : state,
6736 0 : format("Sensible load to be met by DX heating coil = {:.2T} (watts), and the simulation continues.",
6737 : SystemSensibleLoad));
6738 : }
6739 0 : ShowRecurringWarningErrorAtEnd(
6740 : state,
6741 0 : format("{} \"{}\" - DX sensible heating part-load ratio out of range error continues. Sensible load statistics:",
6742 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6743 0 : thisFurnace.Name),
6744 0 : thisFurnace.DXHeatingRegulaFalsiFailedIndex,
6745 : SystemSensibleLoad,
6746 : SystemSensibleLoad);
6747 : }
6748 : }
6749 :
6750 8 : thisFurnace.HeatPartLoadRatio = PartLoadRatio;
6751 : // Check if Heat Pump compressor is allowed to run based on outdoor temperature
6752 8 : if (OutdoorDryBulbTemp > thisFurnace.MinOATCompressorHeating) {
6753 0 : thisFurnace.CompPartLoadRatio = PartLoadRatio;
6754 : } else {
6755 8 : thisFurnace.CompPartLoadRatio = 0.0;
6756 : }
6757 5260 : } else if (SystemSensibleLoad > FullSensibleOutput) {
6758 : // SystemSensibleLoad is greater than full DX Heating coil output so heat pump runs entire
6759 : // timestep and additional supplemental heating is required
6760 5252 : thisFurnace.HeatPartLoadRatio = 1.0;
6761 5252 : if (OutdoorDryBulbTemp > thisFurnace.MinOATCompressorHeating) {
6762 : // Check to see if Heat Pump compressor was allowed to run based on outdoor temperature
6763 1 : thisFurnace.CompPartLoadRatio = 1.0;
6764 : } else {
6765 5251 : thisFurnace.CompPartLoadRatio = 0.0;
6766 : }
6767 0 : } else if (SystemSensibleLoad < NoHeatOutput) {
6768 : // SystemSensibleLoad is less than minimum DX Heating coil output so heat pump does not run and
6769 : // the load will be met by the supplemental heater
6770 0 : thisFurnace.CompPartLoadRatio = 0.0;
6771 0 : thisFurnace.HeatPartLoadRatio = 1.0;
6772 : }
6773 5260 : if (thisFurnace.HeatPartLoadRatio == 1.0) {
6774 : // Determine the load on the supplemental heating coil
6775 5252 : if ((SystemSensibleLoad - FullSensibleOutput) > thisFurnace.DesignSuppHeatingCapacity) {
6776 1 : HeatCoilLoad = thisFurnace.DesignSuppHeatingCapacity;
6777 1 : TempOutHeatingCoil = state.dataLoopNodes->Node(FurnaceOutletNode).Temp + HeatCoilLoad / (cpair * thisFurnace.MdotFurnace);
6778 5251 : } else if (SystemSensibleLoad < NoHeatOutput) {
6779 0 : HeatCoilLoad = max(0.0, SystemSensibleLoad); // BG 10/22/2008 need a case for when its all suppl heat
6780 0 : TempOutHeatingCoil = state.dataLoopNodes->Node(FurnaceInletNode).Temp + HeatCoilLoad / (cpair * thisFurnace.MdotFurnace);
6781 : } else {
6782 5251 : HeatCoilLoad = max(0.0, (SystemSensibleLoad - FullSensibleOutput));
6783 5251 : TempOutHeatingCoil = state.dataLoopNodes->Node(FurnaceOutletNode).Temp + HeatCoilLoad / (cpair * thisFurnace.MdotFurnace);
6784 : }
6785 5252 : if (OutdoorDryBulbTemp > thisFurnace.MaxOATSuppHeat) {
6786 1 : HeatCoilLoad = 0.0;
6787 1 : if (SystemSensibleLoad < NoHeatOutput) {
6788 0 : TempOutHeatingCoil = state.dataLoopNodes->Node(FurnaceInletNode).Temp;
6789 : } else {
6790 1 : TempOutHeatingCoil = state.dataLoopNodes->Node(FurnaceOutletNode).Temp;
6791 : }
6792 : }
6793 5252 : if ((TempOutHeatingCoil > thisFurnace.DesignMaxOutletTemp) && (HeatCoilLoad > 0.0)) {
6794 : // deltaT = Furnace(FurnaceNum)%DesignMaxOutletTemp - Node(FurnaceOutletNode)%Temp
6795 : // BG 10/22/2008 above made no sense if DX heat is off and its all supplemental,
6796 : // because Node(FurnaceOutletNode)%Temp will have been calc'd with full DX heat in last faux call to CalcFurnaceOutput
6797 :
6798 1584 : Real64 cpairSupply = Psychrometrics::PsyCpAirFnW(state.dataLoopNodes->Node(FurnaceInletNode).HumRat);
6799 1584 : deltaT = (thisFurnace.DesignMaxOutletTemp - TempOutHeatingCoil);
6800 1584 : HeatCoilLoad += (state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate * cpairSupply * deltaT);
6801 1584 : HeatCoilLoad = max(0.0, HeatCoilLoad);
6802 : }
6803 : } else {
6804 8 : HeatCoilLoad = 0.0;
6805 : }
6806 5260 : PartLoadRatio = 0.0;
6807 :
6808 : // HeatCool systems can have both a sensible and latent PLR in a single time step
6809 : // (i.e. both cooling and heating can occur in a single time step)
6810 5260 : } else { // else not a heatpump DX coil ** non-HP heating coils are not DX so testing if OutdoorDryBulbTemp < MinOATCompressorHeating
6811 : // is not necessary **
6812 :
6813 0 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.MdotFurnace;
6814 0 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity;
6815 0 : SystemSensibleLoad = ZoneLoad;
6816 :
6817 : // Get no load result
6818 0 : if (fanOp == HVAC::FanOp::Cycling) {
6819 0 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = 0.0;
6820 : }
6821 0 : if (fanOp == HVAC::FanOp::Continuous) {
6822 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0; // The on/off fan will not cycle, so set part-load fraction = 1
6823 : }
6824 :
6825 : // Set the inlet mass flow rate based on user specified coil OFF flow rate
6826 0 : PartLoadRatio = 0.0;
6827 0 : SetAverageAirFlow(state, FurnaceNum, PartLoadRatio, OnOffAirFlowRatio);
6828 :
6829 0 : CalcFurnaceOutput(state,
6830 : FurnaceNum,
6831 : FirstHVACIteration,
6832 : fanOp,
6833 : compressorOp,
6834 : 0.0,
6835 : MinPLR,
6836 : 0.0,
6837 : 0.0,
6838 : NoHeatOutput,
6839 : NoLatentOutput,
6840 : OnOffAirFlowRatio,
6841 : false);
6842 :
6843 0 : if (NoHeatOutput < SystemSensibleLoad) {
6844 0 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.MdotFurnace;
6845 :
6846 : // Set fan part-load fraction equal to 1 while getting full load result
6847 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
6848 0 : OnOffAirFlowRatio = 1.0;
6849 :
6850 : // Get full load result
6851 0 : CalcFurnaceOutput(state,
6852 : FurnaceNum,
6853 : FirstHVACIteration,
6854 : fanOp,
6855 : compressorOp,
6856 : 0.0,
6857 : 1.0,
6858 : HeatCoilLoad,
6859 : 0.0,
6860 : FullSensibleOutput,
6861 : FullLatentOutput,
6862 : OnOffAirFlowRatio,
6863 : false);
6864 : } else {
6865 0 : FullSensibleOutput = NoHeatOutput + 0.000000001;
6866 : }
6867 :
6868 : // Since we are heating, we expect FullSensibleOutput to be > 0 and FullSensibleOutput > NoSensibleOutput
6869 : // Check that this is the case; if not set PartLoadRatio = 0.0 (off) and return
6870 :
6871 0 : if (FullSensibleOutput > NoHeatOutput) {
6872 :
6873 : // check bounds on sensible output prior to iteration using RegulaFalsi
6874 0 : if (FullSensibleOutput <= SystemSensibleLoad) {
6875 0 : PartLoadRatio = 1.0;
6876 : // save modified HeatCoilLoad in case it was reset because outlet temp > DesignMaxOutletTemp
6877 0 : if (state.dataFurnaces->ModifiedHeatCoilLoad > 0.0) {
6878 0 : HeatCoilLoad = state.dataFurnaces->ModifiedHeatCoilLoad;
6879 : } else {
6880 0 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity;
6881 : }
6882 0 : } else if (NoHeatOutput >= SystemSensibleLoad) {
6883 0 : PartLoadRatio = 0.0;
6884 0 : HeatCoilLoad = 0.0;
6885 : } else {
6886 :
6887 : // Calculate the part load ratio through iteration
6888 0 : HeatErrorToler = thisFurnace.HeatingConvergenceTolerance; // Error tolerance for convergence from input deck
6889 :
6890 0 : int SolFlag = 0; // # of iterations if positive, -1 means failed to converge, -2 means bounds are incorrect
6891 : // HeatErrorToler is in fraction load, MaxIter = 30, SolFalg = # of iterations or error as appropriate
6892 0 : auto f = [&state, FurnaceNum, FirstHVACIteration, fanOp, compressorOp, SystemSensibleLoad](Real64 const PartLoadRatio) {
6893 0 : return CalcFurnaceResidual(state,
6894 : PartLoadRatio,
6895 : FurnaceNum,
6896 : FirstHVACIteration,
6897 : fanOp,
6898 : compressorOp,
6899 : SystemSensibleLoad,
6900 : 0.0, // par6_loadFlag,
6901 : 1.0, // par7_sensLatentFlag,
6902 : 0.0, // par9_HXOnFlag,
6903 0 : 0.0); // par10_HeatingCoilPLR);
6904 0 : };
6905 0 : General::SolveRoot(state, HeatErrorToler, MaxIter, SolFlag, PartLoadRatio, f, 0.0, 1.0);
6906 : // OnOffAirFlowRatio is updated during the above iteration. Reset to correct value based on PLR.
6907 0 : OnOffAirFlowRatio = state.dataFurnaces->OnOffAirFlowRatioSave;
6908 : // Reset HeatCoilLoad calculated in CalcFurnaceResidual (in case it was reset because output temp >
6909 : // DesignMaxOutletTemp)
6910 0 : if (state.dataFurnaces->ModifiedHeatCoilLoad > 0.0) {
6911 0 : HeatCoilLoad = state.dataFurnaces->ModifiedHeatCoilLoad;
6912 : } else {
6913 0 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity * PartLoadRatio;
6914 : }
6915 0 : if (SolFlag == -1) {
6916 :
6917 : // RegulaFalsi may not find heating PLR when the maximum supply air temperature is exceeded.
6918 : // If iteration limit is exceeded, find tighter boundary of solution and repeat RegulaFalsi
6919 0 : TempMaxPLR = -0.1;
6920 0 : TempHeatOutput = NoHeatOutput;
6921 0 : while ((TempHeatOutput - SystemSensibleLoad) < 0.0 && TempMaxPLR < 1.0) {
6922 : // find upper limit of HeatingPLR
6923 0 : TempMaxPLR += 0.1;
6924 0 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity * TempMaxPLR;
6925 0 : CalcFurnaceOutput(state,
6926 : FurnaceNum,
6927 : FirstHVACIteration,
6928 : fanOp,
6929 : compressorOp,
6930 : 0.0,
6931 : TempMaxPLR,
6932 : HeatCoilLoad,
6933 : 0.0,
6934 : TempHeatOutput,
6935 : TempLatentOutput,
6936 : OnOffAirFlowRatio,
6937 : false);
6938 : }
6939 0 : TempMinPLR = TempMaxPLR;
6940 0 : while ((TempHeatOutput - SystemSensibleLoad) > 0.0 && TempMinPLR > 0.0) {
6941 : // pull upper limit of HeatingPLR down to last valid limit (i.e. heat output still exceeds
6942 : // SystemSensibleLoad)
6943 0 : TempMaxPLR = TempMinPLR;
6944 : // find minimum limit of HeatingPLR
6945 0 : TempMinPLR -= 0.01;
6946 :
6947 0 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity * TempMinPLR;
6948 0 : CalcFurnaceOutput(state,
6949 : FurnaceNum,
6950 : FirstHVACIteration,
6951 : fanOp,
6952 : compressorOp,
6953 : 0.0,
6954 : TempMinPLR,
6955 : HeatCoilLoad,
6956 : 0.0,
6957 : TempHeatOutput,
6958 : TempLatentOutput,
6959 : OnOffAirFlowRatio,
6960 : false);
6961 : }
6962 : // Now solve again with tighter PLR limits
6963 : auto f2 = // (AUTO_OK_LAMBDA)
6964 0 : [&state, FurnaceNum, FirstHVACIteration, fanOp, compressorOp, SystemSensibleLoad](Real64 const PartLoadRatio) {
6965 0 : return CalcFurnaceResidual(state,
6966 : PartLoadRatio,
6967 : FurnaceNum,
6968 : FirstHVACIteration,
6969 : fanOp,
6970 : compressorOp,
6971 : SystemSensibleLoad,
6972 : 0.0, // par6_loadFlag,
6973 : 1.0, // par7_sensLatentFlag,
6974 : 0.0, // par9_HXOnFlag,
6975 0 : 0.0); // par10_HeatingCoilPLR);
6976 0 : };
6977 0 : General::SolveRoot(state, HeatErrorToler, MaxIter, SolFlag, PartLoadRatio, f2, TempMinPLR, TempMaxPLR);
6978 0 : if (state.dataFurnaces->ModifiedHeatCoilLoad > 0.0) {
6979 0 : HeatCoilLoad = state.dataFurnaces->ModifiedHeatCoilLoad;
6980 : } else {
6981 0 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity * PartLoadRatio;
6982 : }
6983 0 : CalcFurnaceOutput(state,
6984 : FurnaceNum,
6985 : FirstHVACIteration,
6986 : fanOp,
6987 : compressorOp,
6988 : 0.0,
6989 : PartLoadRatio,
6990 : HeatCoilLoad,
6991 : 0.0,
6992 : TempHeatOutput,
6993 : TempLatentOutput,
6994 : OnOffAirFlowRatio,
6995 : false);
6996 :
6997 : // After iterating with tighter boundaries, if still out of tolerance, show warning.
6998 0 : if (SolFlag == -1 && std::abs(SystemSensibleLoad - TempHeatOutput) > HVAC::SmallLoad) {
6999 0 : if (thisFurnace.HeatingMaxIterIndex == 0) {
7000 0 : ShowWarningMessage(state,
7001 0 : format("Heating coil control failed to converge for {}:{}",
7002 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7003 0 : thisFurnace.Name));
7004 0 : ShowContinueError(state, " Iteration limit exceeded in calculating heating coil sensible part-load ratio.");
7005 0 : ShowContinueErrorTimeStamp(state,
7006 0 : format("Sensible load to be met by heating coil = {:.2T} (watts), sensible output "
7007 : "of heating coil = {:.2T} (watts), and the simulation continues.",
7008 : SystemSensibleLoad,
7009 : TempHeatOutput));
7010 : }
7011 0 : ShowRecurringWarningErrorAtEnd(
7012 : state,
7013 0 : format("{} \"{}\" - Iteration limit exceeded in calculating sensible heating part-load "
7014 : "ratio error continues. Sensible load statistics:",
7015 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7016 0 : thisFurnace.Name),
7017 0 : thisFurnace.HeatingMaxIterIndex,
7018 : SystemSensibleLoad,
7019 : SystemSensibleLoad);
7020 : }
7021 0 : } else if (SolFlag == -2) {
7022 0 : if (thisFurnace.HeatingRegulaFalsiFailedIndex == 0) {
7023 0 : ShowWarningMessage(state,
7024 0 : format("Heating coil control failed for {}:{}",
7025 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7026 0 : thisFurnace.Name));
7027 0 : ShowContinueError(state, " Sensible heating part-load ratio determined to be outside the range of 0-1.");
7028 0 : ShowContinueErrorTimeStamp(
7029 : state,
7030 0 : format("Sensible load to be met by heating coil = {:.2T} (watts), and the simulation continues.",
7031 : SystemSensibleLoad));
7032 : }
7033 0 : ShowRecurringWarningErrorAtEnd(
7034 : state,
7035 0 : format("{} \"{}\" - Sensible heating part-load ratio out of range error continues. Sensible load statistics:",
7036 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7037 0 : thisFurnace.Name),
7038 0 : thisFurnace.HeatingRegulaFalsiFailedIndex,
7039 : SystemSensibleLoad,
7040 : SystemSensibleLoad);
7041 : }
7042 : }
7043 :
7044 : } else { // ELSE from IF(FullSensibleOutput.GT.NoSensibleOutput)THEN above
7045 : // Set part load ratio to 1 and run heater at design heating capacity
7046 0 : PartLoadRatio = 1.0;
7047 0 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity;
7048 : }
7049 :
7050 : } // End of IF HeatPump
7051 :
7052 : } // End of IF for heating
7053 :
7054 : // Non-heat pump systems do not set a heating PLR, set it here for use with the DX cooling coil calculations.
7055 : // Set this variable back to 0 for non-heat pump systems at the end of this routine.
7056 10378 : thisFurnace.HeatPartLoadRatio = max(PartLoadRatio, thisFurnace.HeatPartLoadRatio);
7057 10378 : CalcFurnaceOutput(state,
7058 : FurnaceNum,
7059 : FirstHVACIteration,
7060 : fanOp,
7061 : compressorOp,
7062 : 0.0,
7063 : thisFurnace.HeatPartLoadRatio,
7064 : HeatCoilLoad,
7065 : 0.0,
7066 : HeatingSensibleOutput,
7067 : HeatingLatentOutput,
7068 : OnOffAirFlowRatio,
7069 : false);
7070 :
7071 10380 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir ||
7072 2 : (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir && thisFurnace.WatertoAirHPType == WAHPCoilType::Simple &&
7073 2 : state.dataFurnaces->CoolingLoad)) {
7074 10376 : HeatingSensibleOutput = 0.0;
7075 10376 : HeatingLatentOutput = 0.0;
7076 : }
7077 : //***********Cooling Section*****************
7078 : // Simulate if scheduled ON and cooling load or if a moisture load exists when using a humidistat
7079 : // Check of HeatingLatentOutput is used to reduce overshoot during simultaneous heating and cooling
7080 : // Setback flag is used to avoid continued RH control when Tstat is setback (RH should float down)
7081 15695 : if ((thisFurnace.availSched->getCurrentVal() > 0.0 && state.dataFurnaces->CoolingLoad) ||
7082 5317 : (thisFurnace.Humidistat && thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat &&
7083 0 : (SystemMoistureLoad < 0.0 || (SystemMoistureLoad >= 0.0 && HeatingLatentOutput > SystemMoistureLoad &&
7084 0 : !state.dataZoneEnergyDemand->Setback(thisFurnace.ControlZoneNum))))) {
7085 :
7086 : // For cooling operation, the first step is to set the HX operation flag in case a HX assisted coil is used.
7087 : // (if a HX assisted coil is not used, this flag is not used. It's only used in the CALL to SimHXAssistedCoolingCoil)
7088 : // Check the dehumidification control type:
7089 : // For dehumidification control options CoolReheat and None, the HX is always active (locked ON).
7090 : // For dehumidification control option Multimode, the system is operated first with the HX off.
7091 : // If the moisture load is not met, the HX will then be turned on and the system is re-simulated.
7092 :
7093 5061 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat ||
7094 5061 : thisFurnace.DehumidControlType_Num == DehumidificationControlMode::None) {
7095 5061 : HXUnitOn = true;
7096 : } else {
7097 0 : HXUnitOn = false;
7098 : }
7099 :
7100 : // The next step is to determine the system output at no load (PLR=0) and full load (PLR=1)
7101 :
7102 : // Set the inlet mass flow rate based on user specified coil OFF flow rate
7103 5061 : PartLoadRatio = 0.0;
7104 :
7105 5061 : thisFurnace.CompPartLoadRatio = 0.0; // compressor off
7106 :
7107 : // SetAverageAirFlow calculates the operating mass flow rate based on PLR and the user specified inputs
7108 : // for MaxCoolAirMassFlow and MaxNoCoolHeatAirMassFlow.
7109 : // Air flow rate is set according to max of cooling and heating PLR if heating and latent load exists.
7110 5061 : if (fanOp == HVAC::FanOp::Cycling && thisFurnace.HeatPartLoadRatio > 0.0 && thisFurnace.Humidistat &&
7111 10122 : thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat &&
7112 0 : (SystemMoistureLoad < 0.0 || (SystemMoistureLoad >= 0.0 && HeatingLatentOutput > SystemMoistureLoad &&
7113 0 : !state.dataZoneEnergyDemand->Setback(thisFurnace.ControlZoneNum)))) {
7114 0 : CoolingHeatingPLRRatio = min(1.0, PartLoadRatio / thisFurnace.HeatPartLoadRatio);
7115 0 : SetAverageAirFlow(state, FurnaceNum, max(PartLoadRatio, thisFurnace.HeatPartLoadRatio), OnOffAirFlowRatio);
7116 :
7117 : } else {
7118 5061 : CoolingHeatingPLRRatio = 1.0;
7119 5061 : SetAverageAirFlow(state, FurnaceNum, PartLoadRatio, OnOffAirFlowRatio);
7120 : }
7121 :
7122 : // Get no load result (coils simulated OFF)
7123 5061 : CalcFurnaceOutput(state,
7124 : FurnaceNum,
7125 : FirstHVACIteration,
7126 : fanOp,
7127 : compressorOp,
7128 : MinPLR,
7129 : PartLoadRatio,
7130 : 0.0,
7131 : 0.0,
7132 : NoCoolOutput,
7133 : NoLatentOutput,
7134 : OnOffAirFlowRatio,
7135 5061 : HXUnitOn,
7136 : CoolingHeatingPLRRatio);
7137 :
7138 : // Don't calculate full load output if no load output can meet sensible load
7139 5061 : if (NoCoolOutput >= CoolCoilLoad && (CoolCoilLoad != 0.0 || state.dataFurnaces->HPDehumidificationLoadFlag)) {
7140 : // Set full mass flow rate for full load calculation
7141 5061 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.MdotFurnace;
7142 :
7143 : // Set fan part-load fraction equal to 1 while getting full load result
7144 5061 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
7145 5061 : OnOffAirFlowRatio = 1.0;
7146 5061 : PartLoadRatio = 1.0;
7147 5061 : thisFurnace.CompPartLoadRatio = 1.0; // compressor ON
7148 :
7149 : // Get full load result (coils simulated full ON)
7150 5061 : CalcFurnaceOutput(state,
7151 : FurnaceNum,
7152 : FirstHVACIteration,
7153 : fanOp,
7154 : compressorOp,
7155 : PartLoadRatio,
7156 : 0.0,
7157 : 0.0,
7158 : 0.0,
7159 : FullSensibleOutput,
7160 : FullLatentOutput,
7161 : OnOffAirFlowRatio,
7162 5061 : HXUnitOn);
7163 : } else {
7164 0 : FullSensibleOutput = NoCoolOutput - 0.00000001;
7165 : }
7166 :
7167 : // The next step is to compare the results of the full load and no load results
7168 : // 1) Since we are cooling, we expect FullSensibleOutput < NoCoolOutput
7169 : // Check that this is the case; if not set PartLoadRatio = 0.0 (off)
7170 : // 2) Verify that the load to be met is within the range of available output
7171 : // (i.e. between FullSensibleOutput and NoCoolOutput)
7172 : // 3) Set PLR if load is out of range or RegulaFalsi on PLR if system can meet the load
7173 5061 : if (FullSensibleOutput < NoCoolOutput) {
7174 5061 : if (CoolCoilLoad != 0.0 || state.dataFurnaces->HPDehumidificationLoadFlag) {
7175 :
7176 : // check bounds on sensible output prior to iteration using RegulaFalsi
7177 : // Negative value represents cooling load, IF FullSensibleOutput .GT. CoolCoilLoad, load is greater than capacity
7178 5061 : if (FullSensibleOutput >= CoolCoilLoad) {
7179 0 : PartLoadRatio = 1.0;
7180 : // Likewise IF NoCoolOutput .LT. CoolCoilLoad, then load can be met using only the fan (constant fan mode only)
7181 5061 : } else if (NoCoolOutput <= CoolCoilLoad) {
7182 0 : PartLoadRatio = 0.0;
7183 : // ELSE load is between NoCoolOutput and FullSensibleOuput, find PLR required to meet load
7184 : } else {
7185 :
7186 : // Calculate the sensible part load ratio through iteration
7187 5061 : CoolErrorToler = thisFurnace.CoolingConvergenceTolerance; // Error tolerance for convergence from input deck
7188 5061 : int SolFlag = 0; // # of iterations if positive, -1 means failed to converge, -2 means bounds are incorrect
7189 5061 : Real64 par8_HXFlag = HXUnitOn ? 1.0 : 0.0;
7190 : // CoolErrorToler is in fraction of load, MaxIter = 30, SolFalg = # of iterations or error as appropriate
7191 : auto f =
7192 25305 : [&state, FurnaceNum, FirstHVACIteration, fanOp, compressorOp, CoolCoilLoad, par8_HXFlag](Real64 const PartLoadRatio) {
7193 20244 : return CalcFurnaceResidual(state,
7194 : PartLoadRatio,
7195 : FurnaceNum,
7196 : FirstHVACIteration,
7197 : fanOp,
7198 : compressorOp,
7199 : CoolCoilLoad,
7200 : 1.0, // par6_loadFlag,
7201 : 1.0, // par7_sensLatentFlag,
7202 : par8_HXFlag, // par9_HXOnFlag,
7203 20244 : 0.0); // par10_HeatingCoilPLR);
7204 5061 : };
7205 5061 : General::SolveRoot(state, CoolErrorToler, MaxIter, SolFlag, PartLoadRatio, f, 0.0, 1.0);
7206 : // OnOffAirFlowRatio is updated during the above iteration. Reset to correct value based on PLR.
7207 5061 : OnOffAirFlowRatio = state.dataFurnaces->OnOffAirFlowRatioSave;
7208 5061 : if (SolFlag < 0) {
7209 0 : if (SolFlag == -1) {
7210 0 : CalcFurnaceOutput(state,
7211 : FurnaceNum,
7212 : FirstHVACIteration,
7213 : fanOp,
7214 : compressorOp,
7215 : PartLoadRatio,
7216 : 0.0,
7217 : 0.0,
7218 : 0.0,
7219 : TempCoolOutput,
7220 : TempLatentOutput,
7221 : OnOffAirFlowRatio,
7222 0 : HXUnitOn);
7223 0 : if (!state.dataGlobal->WarmupFlag) {
7224 0 : if (std::abs(CoolCoilLoad - TempCoolOutput) > HVAC::SmallLoad) {
7225 0 : if (thisFurnace.SensibleMaxIterIndex == 0) {
7226 0 : ShowWarningMessage(state,
7227 0 : format("Cooling coil control failed to converge for {}:{}",
7228 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7229 0 : thisFurnace.Name));
7230 0 : ShowContinueError(
7231 : state, " Iteration limit exceeded in calculating DX cooling coil sensible part-load ratio.");
7232 0 : ShowContinueErrorTimeStamp(state,
7233 0 : format("Sensible load to be met by DX coil = {:.2T} (watts), sensible "
7234 : "output of DX coil = {:.2T} (watts), and the simulation continues.",
7235 : CoolCoilLoad,
7236 : TempCoolOutput));
7237 : }
7238 0 : ShowRecurringWarningErrorAtEnd(
7239 : state,
7240 0 : format("{} \"{}\" - Iteration limit exceeded in calculating sensible cooling "
7241 : "part-load ratio error continues. Sensible load statistics:",
7242 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7243 0 : thisFurnace.Name),
7244 0 : thisFurnace.SensibleMaxIterIndex,
7245 : CoolCoilLoad,
7246 : CoolCoilLoad);
7247 : }
7248 : }
7249 0 : } else if (SolFlag == -2) {
7250 0 : if (!state.dataGlobal->WarmupFlag) {
7251 0 : if (thisFurnace.SensibleRegulaFalsiFailedIndex == 0) {
7252 0 : ShowWarningMessage(state,
7253 0 : format("Cooling coil control failed for {}:{}",
7254 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7255 0 : thisFurnace.Name));
7256 0 : ShowContinueError(state, " Cooling sensible part-load ratio determined to be outside the range of 0-1.");
7257 0 : ShowContinueErrorTimeStamp(state, format(" Cooling sensible load = {:.2T}", CoolCoilLoad));
7258 : }
7259 0 : ShowRecurringWarningErrorAtEnd(
7260 : state,
7261 0 : format("{} \"{}\" - Cooling sensible part-load ratio out of range error continues. Sensible cooling load "
7262 : "statistics:",
7263 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7264 0 : thisFurnace.Name),
7265 0 : thisFurnace.SensibleRegulaFalsiFailedIndex,
7266 : CoolCoilLoad,
7267 : CoolCoilLoad);
7268 : }
7269 : }
7270 : }
7271 : }
7272 :
7273 : } else {
7274 0 : PartLoadRatio = 0.0;
7275 : } // EndIf for IF(CoolCoilLoad.NE.0.0)
7276 :
7277 : // Calculate the delivered capacity from the PLR calculated above
7278 5061 : CalcFurnaceOutput(state,
7279 : FurnaceNum,
7280 : FirstHVACIteration,
7281 : fanOp,
7282 : compressorOp,
7283 : PartLoadRatio,
7284 : thisFurnace.HeatPartLoadRatio,
7285 : 0.0,
7286 : 0.0,
7287 : TempCoolOutput,
7288 : TempLatentOutput,
7289 : OnOffAirFlowRatio,
7290 5061 : HXUnitOn);
7291 :
7292 : // Calculate the latent part load ratio through iteration
7293 : // Negative SystemMoistureLoad means dehumidification load is present
7294 : // IF this furnace uses MultiMode control AND there is a moisture load AND the moisture load met by the furnace in
7295 : // cooling only mode above is sufficient to meet the moisture demand OR there is no sensible load (PLR=0 from above)
7296 : // then set LatentPartLoadRatio to 0 (no additional dehumidification is required).
7297 5061 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::Multimode &&
7298 0 : ((SystemMoistureLoad < 0.0 && TempLatentOutput < SystemMoistureLoad) || PartLoadRatio == 0.0)) {
7299 0 : LatentPartLoadRatio = 0.0;
7300 : // ELSE calculate a new PLR for valid dehumidification control types if a moisture load exists.
7301 5061 : } else if (thisFurnace.DehumidControlType_Num != DehumidificationControlMode::None &&
7302 0 : (SystemMoistureLoad < 0.0 || (SystemMoistureLoad >= 0.0 && TempLatentOutput > SystemMoistureLoad &&
7303 0 : !state.dataZoneEnergyDemand->Setback(thisFurnace.ControlZoneNum)))) {
7304 :
7305 : // IF the furnace uses dehumidification control MultiMode, turn on the HX and calculate the latent output with
7306 : // the HX ON to compare to the moisture load predicted by the humidistat.
7307 0 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::Multimode) {
7308 0 : HXUnitOn = true;
7309 0 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.MdotFurnace;
7310 : // Set fan part-load fraction equal to 1 while getting full load result
7311 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
7312 0 : OnOffAirFlowRatio = 1.0;
7313 : // Get full load result
7314 0 : CalcFurnaceOutput(state,
7315 : FurnaceNum,
7316 : FirstHVACIteration,
7317 : fanOp,
7318 : compressorOp,
7319 : 1.0,
7320 : 0.0,
7321 : 0.0,
7322 : 0.0,
7323 : TempCoolOutput,
7324 : TempLatentOutput,
7325 : OnOffAirFlowRatio,
7326 0 : HXUnitOn);
7327 : }
7328 :
7329 : // Set the global cooling to heating PLR ratio. CoolHeatPLRRat = MIN(1,CoolingPLR/HeatingPLR)
7330 0 : state.dataFurnaces->CoolHeatPLRRat = 1.0; // means cooling dominated operation (applies to cycling fan mode)
7331 :
7332 0 : if (TempLatentOutput > SystemMoistureLoad) {
7333 : // Set full mass flow rate for full load calculation
7334 0 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.MdotFurnace;
7335 :
7336 : // Set fan part-load fraction equal to 1 while getting full load result
7337 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
7338 0 : OnOffAirFlowRatio = 1.0;
7339 0 : thisFurnace.CompPartLoadRatio = 1.0; // compressor ON
7340 :
7341 : // Get full load result (coils simulated full ON)
7342 0 : CalcFurnaceOutput(state,
7343 : FurnaceNum,
7344 : FirstHVACIteration,
7345 : fanOp,
7346 : compressorOp,
7347 : 1.0,
7348 : 0.0,
7349 : 0.0,
7350 : 0.0,
7351 : TempCoolOutput,
7352 : TempLatentOutput,
7353 : OnOffAirFlowRatio,
7354 0 : HXUnitOn);
7355 : }
7356 :
7357 : // check bounds on latent output prior to iteration using RegulaFalsi
7358 0 : if (TempLatentOutput > SystemMoistureLoad ||
7359 0 : (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::Multimode && TempCoolOutput > CoolCoilLoad)) {
7360 0 : LatentPartLoadRatio = 1.0;
7361 0 : } else if (NoLatentOutput < SystemMoistureLoad || HeatingLatentOutput < SystemMoistureLoad) {
7362 0 : LatentPartLoadRatio = 0.0;
7363 : } else {
7364 :
7365 0 : CoolErrorToler = thisFurnace.CoolingConvergenceTolerance; // Error tolerance for convergence
7366 :
7367 0 : int SolFlag = 0; // # of iterations if positive, -1 means failed to converge, -2 means bounds are incorrect
7368 : // Multimode always controls to meet the SENSIBLE load (however, HXUnitOn is now TRUE)
7369 : Real64 par4_load;
7370 0 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::Multimode) {
7371 0 : par4_load = CoolCoilLoad;
7372 : } else {
7373 0 : par4_load = SystemMoistureLoad;
7374 : }
7375 : // Multimode always controls to meet the SENSIBLE load (however, HXUnitOn is now TRUE)
7376 : Real64 par6_LatentSens;
7377 0 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::Multimode) {
7378 0 : par6_LatentSens = 1.0;
7379 : } else {
7380 0 : par6_LatentSens = 0.0;
7381 : }
7382 0 : Real64 par8_HXUnit = HXUnitOn ? 1.0 : 0.0;
7383 : Real64 par9_HtgCoilPLR;
7384 0 : if (fanOp == HVAC::FanOp::Cycling && thisFurnace.HeatPartLoadRatio > 0.0 && par6_LatentSens == 0.0) {
7385 0 : par9_HtgCoilPLR = thisFurnace.HeatPartLoadRatio;
7386 : } else {
7387 0 : par9_HtgCoilPLR = 0.0;
7388 : }
7389 0 : auto f = [&state,
7390 : FurnaceNum,
7391 : FirstHVACIteration,
7392 : fanOp,
7393 : compressorOp,
7394 : par4_load,
7395 : par6_LatentSens,
7396 : par8_HXUnit,
7397 : par9_HtgCoilPLR](Real64 const PartLoadRatio) {
7398 0 : return CalcFurnaceResidual(state,
7399 : PartLoadRatio,
7400 : FurnaceNum,
7401 : FirstHVACIteration,
7402 : fanOp,
7403 : compressorOp,
7404 : par4_load,
7405 : 1.0, // par6_loadFlag,
7406 : par6_LatentSens, // par7_sensLatentFlag,
7407 : par8_HXUnit, // par9_HXOnFlag,
7408 0 : par9_HtgCoilPLR); // par10_HeatingCoilPLR);
7409 0 : };
7410 : // CoolErrorToler is in fraction of load, MaxIter = 30, SolFalg = # of iterations or error as appropriate
7411 0 : General::SolveRoot(state, CoolErrorToler, MaxIter, SolFlag, LatentPartLoadRatio, f, 0.0, 1.0);
7412 : // OnOffAirFlowRatio is updated during the above iteration. Reset to correct value based on PLR.
7413 0 : OnOffAirFlowRatio = state.dataFurnaces->OnOffAirFlowRatioSave;
7414 0 : if (SolFlag == -1) {
7415 : // RegulaFalsi may not find latent PLR when the latent degradation model is used.
7416 : // If iteration limit is exceeded, find tighter boundary of solution and repeat RegulaFalsi
7417 0 : TempMaxPLR = -0.1;
7418 0 : TempLatentOutput = NoLatentOutput;
7419 0 : while ((TempLatentOutput - SystemMoistureLoad) > 0.0 && TempMaxPLR < 1.0) {
7420 : // find upper limit of LatentPLR
7421 0 : TempMaxPLR += 0.1;
7422 :
7423 : // Same calculation as is done in Function CalcFurnaceResidual for latent PLR calculation.
7424 : // Set cooling to heating PLR for use with Subroutine CalcFurnaceOutput. IF Par(10) = 0,
7425 : // heating PLR = 0 so set the CoolingHeatingPLRRatio to 1 so the cooling PLR is used in the
7426 : // DX cooling coil calculations.
7427 0 : if (par9_HtgCoilPLR > 0.0) {
7428 : // Par(10) = Furnace(FurnaceNum)%HeatPartLoadRatio
7429 : // fanOp = CycFan and Furnace(FurnaceNum)%HeatPartLoadRatio must be > 0 for Part(10) to be
7430 : // greater than 0
7431 0 : CoolingHeatingPLRRatio = min(1.0, TempMaxPLR / thisFurnace.HeatPartLoadRatio);
7432 : } else {
7433 0 : CoolingHeatingPLRRatio = 1.0;
7434 : }
7435 :
7436 0 : CalcFurnaceOutput(state,
7437 : FurnaceNum,
7438 : FirstHVACIteration,
7439 : fanOp,
7440 : compressorOp,
7441 : TempMaxPLR,
7442 : 0.0,
7443 : 0.0,
7444 : 0.0,
7445 : TempCoolOutput,
7446 : TempLatentOutput,
7447 : OnOffAirFlowRatio,
7448 0 : HXUnitOn,
7449 : CoolingHeatingPLRRatio);
7450 : }
7451 0 : TempMinPLR = TempMaxPLR;
7452 0 : while ((TempLatentOutput - SystemMoistureLoad) < 0.0 && TempMinPLR > 0.0) {
7453 : // pull upper limit of LatentPLR down to last valid limit (i.e. latent output still exceeds
7454 : // SystemMoisuterLoad) CR7558 - relax final limits to allow HX assisted coils to converge
7455 0 : TempMaxPLR = TempMinPLR + 0.001;
7456 : // find minimum limit of Latent PLR
7457 0 : TempMinPLR -= 0.001;
7458 :
7459 : // Set cooling to heating PLR for use with Subroutine CalcFurnaceOutput.
7460 0 : if (par9_HtgCoilPLR > 0.0) {
7461 : // Par(10) = Furnace(FurnaceNum)%HeatPartLoadRatio
7462 : // fanOp = CycFan and Furnace(FurnaceNum)%HeatPartLoadRatio must be > 0 for Part(10) to be
7463 : // greater than 0 Since the latent output of cycling fan systems is 0 at PLR=0, do not allow
7464 : // the PLR to be 0, otherwise RegulaFalsi can fail when a heating and moisture load exists and
7465 : // heating PLR > latent PLR.
7466 0 : TempMinPLR2 = max(0.0000000001, TempMinPLR);
7467 0 : CoolingHeatingPLRRatio = min(1.0, TempMinPLR2 / thisFurnace.HeatPartLoadRatio);
7468 : } else {
7469 0 : TempMinPLR2 = TempMinPLR;
7470 0 : CoolingHeatingPLRRatio = 1.0;
7471 : }
7472 :
7473 0 : CalcFurnaceOutput(state,
7474 : FurnaceNum,
7475 : FirstHVACIteration,
7476 : fanOp,
7477 : compressorOp,
7478 : TempMinPLR2,
7479 : 0.0,
7480 : 0.0,
7481 : 0.0,
7482 : TempCoolOutput,
7483 : TempLatentOutput,
7484 : OnOffAirFlowRatio,
7485 0 : HXUnitOn,
7486 : CoolingHeatingPLRRatio);
7487 : }
7488 : // tighter boundary of solution has been found, call RegulaFalsi a second time
7489 0 : auto f2 = [&state,
7490 : FurnaceNum,
7491 : FirstHVACIteration,
7492 : fanOp,
7493 : compressorOp,
7494 : par4_load,
7495 : par6_LatentSens,
7496 : par8_HXUnit,
7497 : par9_HtgCoilPLR](Real64 const PartLoadRatio) {
7498 0 : return CalcFurnaceResidual(state,
7499 : PartLoadRatio,
7500 : FurnaceNum,
7501 : FirstHVACIteration,
7502 : fanOp,
7503 : compressorOp,
7504 : par4_load,
7505 : 1.0, // par6_loadFlag,
7506 : par6_LatentSens, // par7_sensLatentFlag,
7507 : par8_HXUnit, // par9_HXOnFlag,
7508 0 : par9_HtgCoilPLR); // par10_HeatingCoilPLR);
7509 0 : };
7510 0 : General::SolveRoot(state, CoolErrorToler, MaxIter, SolFlag, LatentPartLoadRatio, f2, TempMinPLR2, TempMaxPLR);
7511 : // OnOffAirFlowRatio is updated during the above iteration. Reset to correct value based on PLR.
7512 0 : OnOffAirFlowRatio = state.dataFurnaces->OnOffAirFlowRatioSave;
7513 0 : if (SolFlag == -1) {
7514 :
7515 : // Set cooling to heating PLR for use with Subroutine CalcFurnaceOutput.
7516 0 : if (par9_HtgCoilPLR > 0.0) {
7517 : // Par(10) = Furnace(FurnaceNum)%HeatPartLoadRatio
7518 : // fanOp = CycFan and Furnace(FurnaceNum)%HeatPartLoadRatio must be > 0 for Part(10) to be
7519 : // greater than 0
7520 0 : CoolingHeatingPLRRatio = min(1.0, LatentPartLoadRatio / thisFurnace.HeatPartLoadRatio);
7521 : } else {
7522 0 : CoolingHeatingPLRRatio = 1.0;
7523 : }
7524 :
7525 0 : CalcFurnaceOutput(state,
7526 : FurnaceNum,
7527 : FirstHVACIteration,
7528 : fanOp,
7529 : compressorOp,
7530 : LatentPartLoadRatio,
7531 : 0.0,
7532 : 0.0,
7533 : 0.0,
7534 : TempCoolOutput,
7535 : TempLatentOutput,
7536 : OnOffAirFlowRatio,
7537 0 : HXUnitOn,
7538 : CoolingHeatingPLRRatio);
7539 0 : if (std::abs((SystemMoistureLoad - TempLatentOutput) / SystemMoistureLoad) > CoolErrorToler &&
7540 0 : std::abs(SystemMoistureLoad - TempLatentOutput) > 10.0) {
7541 0 : if (!state.dataGlobal->WarmupFlag) {
7542 0 : if (thisFurnace.LatentMaxIterIndex == 0) {
7543 0 : ShowWarningMessage(state,
7544 0 : format("Cooling coil control failed to converge for {}:{}",
7545 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7546 0 : thisFurnace.Name));
7547 0 : ShowContinueError(state,
7548 : " Iteration limit exceeded in calculating cooling coil latent part-load ratio.");
7549 0 : ShowContinueError(
7550 : state,
7551 0 : format(" Latent load convergence error (percent) = {:.2T}",
7552 0 : 100.0 * std::abs((SystemMoistureLoad - TempLatentOutput) / SystemMoistureLoad)));
7553 0 : ShowContinueErrorTimeStamp(state,
7554 0 : format("Moisture load to be met by DX coil = {:.2T} (watts), Latent "
7555 : "output of DX coil = {:.2T} (watts), and the simulation continues.",
7556 : SystemMoistureLoad,
7557 : TempLatentOutput));
7558 : }
7559 0 : ShowRecurringWarningErrorAtEnd(
7560 : state,
7561 0 : format("{} \"{}\" - Iteration limit exceeded in calculating latent part-load ratio error continues. "
7562 : "Latent "
7563 : "load convergence error (percent) statistics follow.",
7564 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7565 0 : thisFurnace.Name),
7566 0 : thisFurnace.LatentMaxIterIndex,
7567 0 : 100.0 * std::abs((SystemMoistureLoad - TempLatentOutput) / SystemMoistureLoad),
7568 0 : 100.0 * std::abs((SystemMoistureLoad - TempLatentOutput) / SystemMoistureLoad));
7569 : }
7570 : }
7571 0 : } else if (SolFlag == -2) {
7572 0 : if (thisFurnace.LatentRegulaFalsiFailedIndex2 == 0) {
7573 0 : ShowWarningMessage(state,
7574 0 : format("Cooling coil control failed for {}:{}",
7575 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7576 0 : thisFurnace.Name));
7577 0 : ShowContinueError(state,
7578 0 : format(" Latent part-load ratio determined to be outside the range of {:.3T} to {:.3T}.",
7579 : TempMinPLR,
7580 : TempMaxPLR));
7581 0 : ShowContinueErrorTimeStamp(state,
7582 0 : format("A PLR of {:.3T} will be used and the simulation continues.", TempMinPLR));
7583 : }
7584 0 : ShowRecurringWarningErrorAtEnd(state,
7585 0 : format("{} \"{}\" - Cooling sensible part-load ratio out of range error "
7586 : "continues. System moisture load statistics:",
7587 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7588 0 : thisFurnace.Name),
7589 0 : thisFurnace.LatentRegulaFalsiFailedIndex2,
7590 : SystemMoistureLoad,
7591 : SystemMoistureLoad);
7592 0 : LatentPartLoadRatio = TempMinPLR;
7593 : }
7594 0 : } else if (SolFlag == -2) {
7595 0 : if (thisFurnace.LatentRegulaFalsiFailedIndex == 0) {
7596 0 : ShowWarningMessage(state,
7597 0 : format("Cooling coil control failed for {}:{}",
7598 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7599 0 : thisFurnace.Name));
7600 0 : ShowContinueError(state, " Latent part-load ratio determined to be outside the range of 0-1.");
7601 0 : ShowContinueErrorTimeStamp(state, "A PLR of 0 will be used and the simulation continues.");
7602 : }
7603 0 : ShowRecurringWarningErrorAtEnd(
7604 : state,
7605 0 : format("{} \"{}\" - Latent part-load ratio out of range or 0-1 error continues. System moisture load statistics:",
7606 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7607 0 : thisFurnace.Name),
7608 0 : thisFurnace.LatentRegulaFalsiFailedIndex,
7609 : SystemMoistureLoad,
7610 : SystemMoistureLoad);
7611 0 : LatentPartLoadRatio = 0.0;
7612 : }
7613 : }
7614 :
7615 : // Cooling to heating PLR ratio is now known as CoolHeatPLRRat (Module level global set in CalcFurnaceOutput
7616 : // This same variable is use in Subroutine SimFurnace for final calculations.
7617 : // Get the actual output in case reheat needs to be calculated (HumControl=TRUE [latent PLR > sensible PLR])
7618 0 : CalcFurnaceOutput(state,
7619 : FurnaceNum,
7620 : FirstHVACIteration,
7621 : fanOp,
7622 : compressorOp,
7623 : LatentPartLoadRatio,
7624 : 0.0,
7625 : 0.0,
7626 : 0.0,
7627 : ActualSensibleOutput,
7628 : ActualLatentOutput,
7629 : OnOffAirFlowRatio,
7630 0 : HXUnitOn,
7631 0 : state.dataFurnaces->CoolHeatPLRRat);
7632 :
7633 : } else {
7634 5061 : LatentPartLoadRatio = 0.0;
7635 : } // ENDIF for valid dehumidification control types
7636 :
7637 : // IF a humidistat is used and there is a moisture load, check if the latent PLR is greater than the (sensible) PLR
7638 : // IF(LatentPartLoadRatio .GT. PartLoadRatio .and. SystemMoistureLoad .lt. 0.0 .and. Furnace(FurnaceNum)%Humidistat) THEN
7639 5061 : if (LatentPartLoadRatio > PartLoadRatio && thisFurnace.Humidistat) {
7640 : // For dehumidification mode CoolReheat, compare the Sensible and Latent PLR values, if latentPLR is greater
7641 : // than PLR (sensible), then overcooling is required and reheat will be activated using the HumControl flag.
7642 0 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat) {
7643 0 : PartLoadRatio = LatentPartLoadRatio;
7644 0 : HumControl = true;
7645 : }
7646 : // For dehumidification mode MultiMode, compare the Sensible and Latent PLR values, if latentPLR is
7647 : // greater than PLR (sensible), then use the latent PLR to control the unit.
7648 : // For MultiMode control, the latent PLR is found by enabling the HX and calculating a PLR required to meet the
7649 : // sensible load. Overcooling is not required, and reheat will not be activated using the HumControl flag.
7650 0 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::Multimode) {
7651 0 : PartLoadRatio = LatentPartLoadRatio;
7652 : }
7653 : }
7654 :
7655 5061 : thisFurnace.CoolPartLoadRatio = PartLoadRatio;
7656 5061 : if (compressorOp == HVAC::CompressorOp::Off) {
7657 0 : thisFurnace.CompPartLoadRatio = 0.0;
7658 : } else {
7659 5061 : thisFurnace.CompPartLoadRatio = PartLoadRatio;
7660 : }
7661 :
7662 : } else { // ELSE from IF(FullSensibleOutput.LT.NoCoolOutput)THEN above
7663 : // CR8679 - Unitary Heat Cool control problem, will not run to meeting cooling load
7664 : // underlying problem is that FullSensibleOutput is greater than 0 due to very high inlet temp, so the system should be on
7665 : // NoCoolOutput was 0 since the defect file is a cycling fan system and the system was turned off
7666 :
7667 : // if FullSensibleOutput > NoCoolOutput, it means the system cannot meet the load and will run full out
7668 : // this same logic for WSHP does not seem to work (only the Unitary Heat Pump Compressor Part-Load Ratio report
7669 : // variable was affected in the HeatPumpWaterToAirRHControl.idf file while other variables showed very small diffs).
7670 : // The defect files meter.csv showed 2% diffs so this IF test is used to keep the results the same in that file.
7671 : // Additional logic is used here to make sure the coil actually turned on, e.g., if DX coil PLR > 0 then set to 1,
7672 : // otherwise 0 (to make sure coil is actually ON and not off due to schedule, OAT, or other reason).
7673 : // The global variable DXCoilPartLoadRatio(DXCoilNum) is not yet used for the WSHP to make the same check.
7674 0 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir) {
7675 0 : thisFurnace.CoolPartLoadRatio = 0.0;
7676 0 : thisFurnace.CompPartLoadRatio = 0.0;
7677 : } else {
7678 0 : if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) {
7679 :
7680 : // VS coil issue here...
7681 0 : if (state.dataDXCoils->DXCoilPartLoadRatio(thisFurnace.ActualDXCoilIndexForHXAssisted) > 0.0) {
7682 0 : thisFurnace.CoolPartLoadRatio = 1.0;
7683 0 : thisFurnace.CompPartLoadRatio = 1.0;
7684 : } else {
7685 0 : thisFurnace.CoolPartLoadRatio = 0.0;
7686 0 : thisFurnace.CompPartLoadRatio = 0.0;
7687 : }
7688 : } else {
7689 0 : if (state.dataDXCoils->DXCoilPartLoadRatio(thisFurnace.CoolingCoilIndex) > 0.0) {
7690 0 : thisFurnace.CoolPartLoadRatio = 1.0;
7691 0 : thisFurnace.CompPartLoadRatio = 1.0;
7692 : } else {
7693 0 : thisFurnace.CoolPartLoadRatio = 0.0;
7694 0 : thisFurnace.CompPartLoadRatio = 0.0;
7695 : }
7696 : }
7697 : }
7698 : }
7699 :
7700 : // Calculate the reheat coil output
7701 5061 : if (HumControl) { // HumControl = .TRUE. if a Humidistat is installed and dehumidification control type is CoolReheat
7702 0 : if (thisFurnace.ZoneSequenceHeatingNum > 0) {
7703 0 : QToHeatSetPt = (state.dataZoneEnergyDemand->ZoneSysEnergyDemand(thisFurnace.ControlZoneNum)
7704 0 : .SequencedOutputRequiredToHeatingSP(thisFurnace.ZoneSequenceHeatingNum) /
7705 0 : thisFurnace.ControlZoneMassFlowFrac);
7706 : } else {
7707 0 : QToHeatSetPt = (state.dataZoneEnergyDemand->ZoneSysEnergyDemand(thisFurnace.ControlZoneNum).OutputRequiredToHeatingSP /
7708 0 : thisFurnace.ControlZoneMassFlowFrac);
7709 : }
7710 : // Cooling mode or floating condition and dehumidification is required
7711 0 : if (QToHeatSetPt < 0.0) {
7712 : // Calculate the reheat coil load wrt the heating setpoint temperature. Reheat coil picks up
7713 : // the entire excess sensible cooling (DX cooling coil and impact of outdoor air).
7714 0 : ReheatCoilLoad = max(0.0, (QToHeatSetPt - ActualSensibleOutput));
7715 0 : thisFurnace.DehumidInducedHeatingDemandRate = ReheatCoilLoad;
7716 : // Heating mode and dehumidification is required
7717 : } else {
7718 : // Calculate the reheat coil load as the sensible capacity of the DX cooling coil only. Let
7719 : // the heating coil pick up the load due to outdoor air.
7720 0 : ReheatCoilLoad = max(0.0, (ActualSensibleOutput - NoCoolOutput) * (-1.0));
7721 : // Dehumidification is not required
7722 0 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir ||
7723 0 : (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir &&
7724 0 : thisFurnace.WatertoAirHPType == WAHPCoilType::Simple)) {
7725 0 : ReheatCoilLoad = max(QToHeatSetPt, QToHeatSetPt - ActualSensibleOutput);
7726 : }
7727 0 : thisFurnace.DehumidInducedHeatingDemandRate = max(0.0, ActualSensibleOutput * (-1.0));
7728 : }
7729 : } else {
7730 : // No humidistat installed
7731 5061 : ReheatCoilLoad = 0.0;
7732 : }
7733 : } // End of cooling section IF statement
7734 :
7735 10378 : if (NoHeatOutput > SystemSensibleLoad && ReheatCoilLoad > 0.0) {
7736 : // Reduce reheat coil load if you are controlling high humidity but outside air
7737 : // and/or the supply air fan is providing enough heat to meet the system sensible load.
7738 : // This will bring the zone temp closer to the heating setpoint temp.
7739 0 : ReheatCoilLoad = max(0.0, ReheatCoilLoad - (NoHeatOutput - SystemSensibleLoad));
7740 : }
7741 :
7742 : // Set the final air flow. MdotFurnace will be used to set the fan part-load ratio in ReportFurnace
7743 10378 : if (HumControl && SystemMoistureLoad < 0.0) {
7744 0 : if (fanOp == HVAC::FanOp::Cycling) {
7745 : // set the flow rate at the maximum of the cooling and heating PLR's
7746 0 : SetAverageAirFlow(state, FurnaceNum, max(thisFurnace.CoolPartLoadRatio, thisFurnace.HeatPartLoadRatio), OnOffAirFlowRatio);
7747 : } else {
7748 : // ELSE set the flow rate at the cooling PLR
7749 0 : SetAverageAirFlow(state, FurnaceNum, thisFurnace.CoolPartLoadRatio, OnOffAirFlowRatio);
7750 : }
7751 : } else {
7752 10378 : SetAverageAirFlow(state, FurnaceNum, max(thisFurnace.CoolPartLoadRatio, thisFurnace.HeatPartLoadRatio), OnOffAirFlowRatio);
7753 : }
7754 10378 : thisFurnace.MdotFurnace = state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate;
7755 :
7756 10378 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir ||
7757 2 : (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir && thisFurnace.WatertoAirHPType == WAHPCoilType::Simple)) {
7758 : } else {
7759 : // Non-HeatPump (non-DX) heating coils do not set PLR, reset to 0 here. This variable was set for non-DX
7760 : // coils to allow the SetAverageAirFlow CALL above to set the correct air mass flow rate. See this
7761 : // IF block above in heating section. HeatPLR is not set in the ELSE part of the IF (only HeatCoilLoad is set).
7762 0 : thisFurnace.HeatPartLoadRatio = 0.0;
7763 : }
7764 :
7765 : //*********HVAC Scheduled OFF*************
7766 : // No heating or cooling or dehumidification
7767 : //!!LKL discrepancy with < 0?
7768 10378 : if (thisFurnace.availSched->getCurrentVal() == 0.0 || state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate == 0.0) {
7769 57 : thisFurnace.MdotFurnace = 0.0;
7770 57 : CoolCoilLoad = 0.0;
7771 57 : HeatCoilLoad = 0.0;
7772 57 : ReheatCoilLoad = 0.0;
7773 57 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0; // System off, so set on/off fan part-load fraction = 1
7774 57 : thisFurnace.CoolPartLoadRatio = 0.0;
7775 57 : thisFurnace.HeatPartLoadRatio = 0.0;
7776 57 : thisFurnace.CompPartLoadRatio = 0.0;
7777 : // set report variables
7778 57 : thisFurnace.CoolingCoilSensDemand = 0.0;
7779 57 : thisFurnace.CoolingCoilLatentDemand = 0.0;
7780 57 : thisFurnace.HeatingCoilSensDemand = 0.0;
7781 : }
7782 :
7783 : } // End of the FirstHVACIteration control of the mass flow If block
7784 :
7785 : // Set the fan inlet node flow rates
7786 15225 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRateMaxAvail = thisFurnace.MdotFurnace;
7787 15225 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.MdotFurnace;
7788 15225 : }
7789 :
7790 0 : void CalcWaterToAirHeatPump(EnergyPlusData &state,
7791 : int const FurnaceNum, // index to Furnace
7792 : bool const FirstHVACIteration, // TRUE on first HVAC iteration
7793 : HVAC::CompressorOp const compressorOp, // compressor operation flag (1=On, 0=Off)
7794 : Real64 const ZoneLoad, // the control zone load (watts)
7795 : Real64 const MoistureLoad // the control zone latent load (watts)
7796 : )
7797 : {
7798 :
7799 : // SUBROUTINE INFORMATION:
7800 : // AUTHOR Dan Fisher
7801 : // DATE WRITTEN Feb 2004
7802 : // MODIFIED R. Raustad (Oct 2006) Revised iteration technique
7803 :
7804 : // PURPOSE OF THIS SUBROUTINE:
7805 : // This subroutine manages the heat pump simulation
7806 :
7807 : // METHODOLOGY EMPLOYED:
7808 : // Calculate the part-load ratio required to meet the zone sensible load.
7809 :
7810 : // SUBROUTINE PARAMETER DEFINITIONS:
7811 0 : int constexpr MaxIter(600); // maximum number of iterations
7812 0 : Real64 constexpr MinPLR(0.0); // minimum part load ratio allowed
7813 :
7814 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
7815 : Real64 ZoneSensLoadMet; // Actual zone sensible load met by heat pump (W)
7816 : Real64 ZoneLatLoadMet; // Actual zone latent load met by heat pump (W)
7817 : Real64 ZoneSensLoadMetFanONCompON; // Max Zone sensible load heat pump can meet (W)
7818 : Real64 ZoneLatLoadMetFanONCompON; // Max Zone latent load heat pump can meet (W)
7819 : Real64 ZoneSensLoadMetFanONCompOFF; // control zone sensible load met using only outside air
7820 : // and fan heat (no coil output) (W)
7821 : Real64 ZoneLatLoadMetFanONCompOFF; // control zone Latent load met using only outside air
7822 : // and fan heat (no coil output) (W)
7823 : Real64 HPCoilSensDemand; // Heat pump sensible demand
7824 : Real64 HPCoilSensCapacity; // Heat pump sensible capacity
7825 :
7826 : Real64 SuppHeatCoilLoad; // Load passed to supplemental heater (W)
7827 : Real64 CoolErrorToler; // convergence tolerance used in cooling mode
7828 : Real64 HeatErrorToler; // convergence tolerance used in heating mode
7829 : int SolFlag; // flag returned from iteration routine to denote problems
7830 :
7831 0 : Real64 &TotalZoneLatentLoad = state.dataFurnaces->TotalZoneLatentLoad;
7832 0 : Real64 &TotalZoneSensLoad = state.dataFurnaces->TotalZoneSensLoad;
7833 0 : Real64 &CoolPartLoadRatio = state.dataFurnaces->CoolPartLoadRatio;
7834 0 : Real64 &HeatPartLoadRatio = state.dataFurnaces->HeatPartLoadRatio;
7835 0 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
7836 :
7837 : // Set local variables
7838 0 : Real64 Dummy2 = 0.0; // used as dummy heat and reheat coil load
7839 0 : Real64 OnOffAirFlowRatio = 1.0; // Ratio of compressor ON air mass flow to AVERAGE air mass flow over time step
7840 0 : int FurnaceInletNode = thisFurnace.FurnaceInletNodeNum;
7841 0 : HVAC::FanOp fanOp = thisFurnace.fanOp; // fan operating mode
7842 0 : thisFurnace.MdotFurnace = thisFurnace.DesignMassFlowRate;
7843 :
7844 : //*********INITIAL CALCULATIONS****************
7845 : // set the fan part load fraction
7846 : // Note: OnOffFanPartLoadFraction is passed to the
7847 : // fan module by DataHVACGlobals. It should be
7848 : // set =1 for all cases except cycling fan/cycling
7849 : // coil. For this case it is set to the part load
7850 : // factor. In SimOnOffFan, the part load ratio is
7851 : // divided by the part load factor (OnOffFanPartLoadFraction)
7852 : // in order to match the run time fraction of the cycling
7853 : // fan with the run time fraction of the cycling compressor
7854 0 : if (FirstHVACIteration) state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
7855 :
7856 : // Calc Zone sensible loads for heating (+) and cooling (-)
7857 0 : TotalZoneSensLoad = ZoneLoad;
7858 :
7859 0 : if (state.dataFurnaces->HeatingLoad) {
7860 0 : TotalZoneLatentLoad = 0.0; // Set latent load for heating
7861 : } else {
7862 0 : TotalZoneLatentLoad = MoistureLoad; // Set latent load for cooling and no sensible load condition
7863 : }
7864 :
7865 : //*********COOLING CALCULATIONS****************
7866 : // IF scheduled on...
7867 : // AND air flow rate is greater than zero...
7868 : // AND the air system has a cooling load and is not set back or in the deadband...
7869 : // OR the system is controlled by a humidistat and there is a latent load
7870 0 : if ((thisFurnace.availSched->getCurrentVal() > 0.0 && state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate > 0.0) &&
7871 0 : ((state.dataFurnaces->CoolingLoad) || (thisFurnace.Humidistat && thisFurnace.CoolingCoilLatentDemand < 0.0))) {
7872 :
7873 : // Set the air flow rate to the design flow rate and set the fan operation fraction to 1 (continuous operation)
7874 0 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.DesignMassFlowRate;
7875 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0; // see 'Note' under INITIAL CALCULATIONS
7876 :
7877 : // !Set the operation flag to run the fan continuously
7878 : // fanOp = FanOp::Continuous
7879 :
7880 : // Set the input parameters for CalcFurnaceOutput
7881 0 : thisFurnace.HeatingCoilSensDemand = 0.0;
7882 0 : thisFurnace.CoolingCoilLatentDemand = 0.0;
7883 0 : thisFurnace.CoolingCoilSensDemand = 0.0;
7884 0 : thisFurnace.CompPartLoadRatio = 0.0; // compressor off
7885 0 : thisFurnace.InitHeatPump = true; // initialization call to Calc Furnace
7886 0 : CoolPartLoadRatio = 0.0;
7887 :
7888 : // Get no load result in order to calculate the effect of the fan and the mixed air equipment
7889 0 : CalcFurnaceOutput(state,
7890 : FurnaceNum,
7891 : FirstHVACIteration,
7892 : fanOp,
7893 : compressorOp,
7894 : CoolPartLoadRatio,
7895 : HeatPartLoadRatio,
7896 : Dummy2,
7897 : Dummy2,
7898 : ZoneSensLoadMetFanONCompOFF,
7899 : ZoneLatLoadMetFanONCompOFF,
7900 : OnOffAirFlowRatio,
7901 : false);
7902 :
7903 : // Set the input parameters for CalcFurnaceOutput
7904 0 : thisFurnace.CoolingCoilSensDemand = 1.0;
7905 0 : thisFurnace.CompPartLoadRatio = 1.0; // compressor ON
7906 0 : CoolPartLoadRatio = 1.0;
7907 :
7908 : // Get full load result in order to estimate the operating part load ratio for continuous fan operation
7909 0 : CalcFurnaceOutput(state,
7910 : FurnaceNum,
7911 : FirstHVACIteration,
7912 : fanOp,
7913 : compressorOp,
7914 : CoolPartLoadRatio,
7915 : HeatPartLoadRatio,
7916 : Dummy2,
7917 : Dummy2,
7918 : ZoneSensLoadMetFanONCompON,
7919 : ZoneLatLoadMetFanONCompON,
7920 : OnOffAirFlowRatio,
7921 : false);
7922 :
7923 : // Calculate the heating coil demand for continuous fan operation as:
7924 : // (the zone sensible load - the zone sensible load met by fan heat and mixed air)
7925 : // Note; The sensible zone load met by fan heat and mixed air is calculated as:
7926 : // mdotsys(control zone inlet enthalpy - control zone outlet enthalpy)
7927 : // This accounts for the negative sign in the equation.
7928 0 : HPCoilSensDemand = TotalZoneSensLoad - ZoneSensLoadMetFanONCompOFF;
7929 :
7930 : // Calculate the heating coil capacity for continuous fan operation as:
7931 : // (the zone sensible load met by fan heat and mixed air and coil
7932 : // - the zone sensible load met by fan heat and mixed air)
7933 0 : HPCoilSensCapacity = ZoneSensLoadMetFanONCompON - ZoneSensLoadMetFanONCompOFF;
7934 :
7935 : // Calculate the part load ratio for continuous fan operation with cycling coil
7936 0 : if (HPCoilSensCapacity == 0.0) {
7937 0 : CoolPartLoadRatio = 0.0;
7938 : } else {
7939 0 : CoolPartLoadRatio = max(MinPLR, min(1.0, std::abs(HPCoilSensDemand) / std::abs(HPCoilSensCapacity)));
7940 : }
7941 :
7942 0 : thisFurnace.InitHeatPump = false;
7943 :
7944 : // check bounds on sensible output prior to iteration using RegulaFalsi
7945 0 : if (ZoneSensLoadMetFanONCompON > TotalZoneSensLoad) {
7946 0 : CoolPartLoadRatio = 1.0;
7947 0 : HPCoilSensDemand = std::abs(ZoneSensLoadMetFanONCompON - ZoneSensLoadMetFanONCompOFF);
7948 0 : thisFurnace.CoolingCoilSensDemand = HPCoilSensDemand;
7949 0 : } else if (ZoneSensLoadMetFanONCompOFF < TotalZoneSensLoad) {
7950 0 : CoolPartLoadRatio = 0.0;
7951 0 : thisFurnace.CompPartLoadRatio = 0.0; // compressor OFF
7952 0 : thisFurnace.CoolingCoilSensDemand = 0.0;
7953 0 : CalcFurnaceOutput(state,
7954 : FurnaceNum,
7955 : FirstHVACIteration,
7956 : fanOp,
7957 : compressorOp,
7958 : CoolPartLoadRatio,
7959 : HeatPartLoadRatio,
7960 : Dummy2,
7961 : Dummy2,
7962 : ZoneSensLoadMetFanONCompOFF,
7963 : ZoneLatLoadMetFanONCompOFF,
7964 : OnOffAirFlowRatio,
7965 : false);
7966 : } else {
7967 : // Calculate the sensible part load ratio through iteration
7968 0 : CoolErrorToler = thisFurnace.CoolingConvergenceTolerance;
7969 0 : SolFlag = 0; // # of iterations if positive, -1 means failed to converge, -2 means bounds are incorrect
7970 : // CoolErrorToler is in fraction of load, MaxIter = 600, SolFalg = # of iterations or error as appropriate
7971 0 : auto f = [&state, FurnaceNum, FirstHVACIteration, fanOp, compressorOp, TotalZoneSensLoad, ZoneSensLoadMetFanONCompOFF](
7972 : Real64 const PartLoadRatio) {
7973 0 : return CalcWaterToAirResidual(state,
7974 : PartLoadRatio,
7975 : FurnaceNum,
7976 : FirstHVACIteration,
7977 : fanOp,
7978 : compressorOp,
7979 : TotalZoneSensLoad,
7980 : 1.0,
7981 : 1.0,
7982 : ZoneSensLoadMetFanONCompOFF,
7983 0 : 0.0);
7984 0 : };
7985 0 : General::SolveRoot(state, CoolErrorToler, MaxIter, SolFlag, CoolPartLoadRatio, f, 0.0, 1.0);
7986 0 : if (SolFlag == -1 && !state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
7987 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = state.dataFurnaces->OnOffFanPartLoadFractionSave;
7988 0 : CalcFurnaceOutput(state,
7989 : FurnaceNum,
7990 : FirstHVACIteration,
7991 : fanOp,
7992 : compressorOp,
7993 : CoolPartLoadRatio,
7994 : 0.0,
7995 : 0.0,
7996 : 0.0,
7997 : ZoneSensLoadMet,
7998 : ZoneLatLoadMet,
7999 : OnOffAirFlowRatio,
8000 : false);
8001 0 : if (std::abs(ZoneSensLoadMet - TotalZoneSensLoad) / TotalZoneSensLoad > CoolErrorToler) {
8002 0 : if (thisFurnace.SensibleMaxIterIndex == 0) {
8003 0 : ShowWarningMessage(state,
8004 0 : format("Cooling coil control failed to converge for {}:{}",
8005 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
8006 0 : thisFurnace.Name));
8007 0 : ShowContinueError(state, " Iteration limit exceeded in calculating DX cooling coil sensible part-load ratio.");
8008 0 : ShowContinueErrorTimeStamp(state,
8009 0 : format("Sensible load to be met by DX coil = {:.2T} (watts), sensible output of DX coil = "
8010 : "{:.2T} (watts), and the simulation continues.",
8011 : TotalZoneSensLoad,
8012 : ZoneSensLoadMet));
8013 : }
8014 0 : ShowRecurringWarningErrorAtEnd(
8015 : state,
8016 0 : format("{} \"{}\" - Iteration limit exceeded in calculating sensible cooling part-load ratio error "
8017 : "continues. Sensible load statistics:",
8018 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
8019 0 : thisFurnace.Name),
8020 0 : thisFurnace.SensibleMaxIterIndex,
8021 : TotalZoneSensLoad,
8022 : TotalZoneSensLoad);
8023 : }
8024 0 : } else if (SolFlag == -2 && !state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
8025 0 : CoolPartLoadRatio = max(MinPLR, min(1.0, std::abs(HPCoilSensDemand) / std::abs(HPCoilSensCapacity)));
8026 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
8027 0 : CalcFurnaceOutput(state,
8028 : FurnaceNum,
8029 : FirstHVACIteration,
8030 : fanOp,
8031 : compressorOp,
8032 : CoolPartLoadRatio,
8033 : 0.0,
8034 : 0.0,
8035 : 0.0,
8036 : ZoneSensLoadMet,
8037 : ZoneLatLoadMet,
8038 : OnOffAirFlowRatio,
8039 : false);
8040 0 : if ((ZoneSensLoadMet - TotalZoneSensLoad) / TotalZoneSensLoad > CoolErrorToler) {
8041 0 : if (thisFurnace.SensibleRegulaFalsiFailedIndex == 0) {
8042 0 : ShowWarningMessage(
8043 : state,
8044 0 : format("Cooling coil control failed for {}:{}", HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name));
8045 0 : ShowContinueError(state, " Cooling sensible part-load ratio determined to be outside the range of 0-1.");
8046 0 : ShowContinueError(
8047 : state,
8048 0 : format(" An estimated part-load ratio = {:.2T} will be used and the simulation continues.", CoolPartLoadRatio));
8049 0 : ShowContinueError(
8050 0 : state, format(" The estimated part-load ratio provides a cooling sensible capacity = {:.2T}", ZoneSensLoadMet));
8051 0 : ShowContinueErrorTimeStamp(state, format(" Cooling sensible load required = {:.2T}", TotalZoneSensLoad));
8052 : }
8053 0 : ShowRecurringWarningErrorAtEnd(
8054 : state,
8055 0 : format("{} \"{}\" - Cooling sensible part-load ratio out of range error continues. Sensible cooling load statistics:",
8056 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
8057 0 : thisFurnace.Name),
8058 0 : thisFurnace.SensibleRegulaFalsiFailedIndex,
8059 : TotalZoneSensLoad,
8060 : TotalZoneSensLoad);
8061 : }
8062 : }
8063 : }
8064 :
8065 0 : if (fanOp == HVAC::FanOp::Cycling) {
8066 0 : thisFurnace.MdotFurnace *= CoolPartLoadRatio;
8067 : }
8068 :
8069 : //*********HEATING CALCULATIONS****************
8070 : // If Furnace runs with a heating load then set HeatCoilLoad on Heating Coil and the Mass Flow
8071 0 : } else if ((thisFurnace.availSched->getCurrentVal() > 0.0) && (state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate > 0.0) &&
8072 0 : state.dataFurnaces->HeatingLoad) {
8073 :
8074 : // Set the air flow rate to the design flow rate and set the fan operation fraction to 1 (continuous operation)
8075 0 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.DesignMassFlowRate;
8076 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0; // see 'Note' under INITIAL CALCULATIONS
8077 :
8078 : // !Set the operation flag to run the fan continuously
8079 : // fanOp = FanOp::Continuous
8080 :
8081 : // Set the input parameters for CalcFurnaceOutput
8082 0 : thisFurnace.HeatingCoilSensDemand = 0.0;
8083 0 : thisFurnace.CoolingCoilLatentDemand = 0.0;
8084 0 : thisFurnace.CoolingCoilSensDemand = 0.0;
8085 0 : thisFurnace.CompPartLoadRatio = 0.0; // compressor off
8086 0 : thisFurnace.InitHeatPump = true; // initialization call to Calc Furnace
8087 0 : HeatPartLoadRatio = 0.0;
8088 :
8089 : // Get no load result in order to calculate the effect of the fan and the mixed air equipment
8090 0 : CalcFurnaceOutput(state,
8091 : FurnaceNum,
8092 : FirstHVACIteration,
8093 : fanOp,
8094 : compressorOp,
8095 : CoolPartLoadRatio,
8096 : HeatPartLoadRatio,
8097 : Dummy2,
8098 : Dummy2,
8099 : ZoneSensLoadMetFanONCompOFF,
8100 : ZoneLatLoadMetFanONCompOFF,
8101 : OnOffAirFlowRatio,
8102 : false);
8103 :
8104 : // Set the input parameters for CalcFurnaceOutput
8105 0 : thisFurnace.HeatingCoilSensDemand = 1.0;
8106 0 : thisFurnace.CompPartLoadRatio = 1.0; // compressor ON
8107 0 : HeatPartLoadRatio = 1.0;
8108 :
8109 : // Get full load result in order to estimate the operating part load ratio for continuous fan operation
8110 :
8111 0 : CalcFurnaceOutput(state,
8112 : FurnaceNum,
8113 : FirstHVACIteration,
8114 : fanOp,
8115 : compressorOp,
8116 : CoolPartLoadRatio,
8117 : HeatPartLoadRatio,
8118 : Dummy2,
8119 : Dummy2,
8120 : ZoneSensLoadMetFanONCompON,
8121 : ZoneLatLoadMetFanONCompON,
8122 : OnOffAirFlowRatio,
8123 : false);
8124 :
8125 : // Calculate the heating coil demand for continuous fan operation as:
8126 : // (the zone sensible load - the zone sensible load met by fan heat and mixed air)
8127 : // Note; The sensible zone load met by fan heat and mixed air is calculated as:
8128 : // mdotsys(control zone inlet enthalpy - control zone outlet enthalpy)
8129 : // This accounts for the negative sign in the equation.
8130 0 : HPCoilSensDemand = TotalZoneSensLoad - ZoneSensLoadMetFanONCompOFF;
8131 :
8132 : // Calculate the heating coil capacity for continuous fan operation as:
8133 : // (the zone sensible load met by fan heat and mixed air and coil
8134 : // - the zone sensible load met by fan heat and mixed air)
8135 0 : HPCoilSensCapacity = ZoneSensLoadMetFanONCompON - ZoneSensLoadMetFanONCompOFF;
8136 :
8137 : // Calculate the part load ratio for continuous fan operation with cycling coil
8138 0 : if (HPCoilSensCapacity == 0.0) {
8139 0 : HeatPartLoadRatio = 0.0;
8140 : } else {
8141 0 : HeatPartLoadRatio = max(MinPLR, min(1.0, std::abs(HPCoilSensDemand) / std::abs(HPCoilSensCapacity)));
8142 : }
8143 :
8144 0 : thisFurnace.InitHeatPump = false;
8145 :
8146 : // check bounds on sensible output prior to iteration using RegulaFalsi
8147 0 : if (ZoneSensLoadMetFanONCompON < TotalZoneSensLoad) {
8148 0 : HeatPartLoadRatio = 1.0;
8149 0 : ZoneSensLoadMet = ZoneSensLoadMetFanONCompON;
8150 0 : HPCoilSensDemand = std::abs(ZoneSensLoadMetFanONCompON - ZoneSensLoadMetFanONCompOFF);
8151 0 : thisFurnace.HeatingCoilSensDemand = HPCoilSensDemand;
8152 0 : } else if (ZoneSensLoadMetFanONCompOFF > TotalZoneSensLoad) {
8153 0 : HeatPartLoadRatio = 0.0;
8154 0 : ZoneSensLoadMet = ZoneSensLoadMetFanONCompOFF;
8155 0 : thisFurnace.CompPartLoadRatio = 0.0; // compressor ON
8156 0 : CalcFurnaceOutput(state,
8157 : FurnaceNum,
8158 : FirstHVACIteration,
8159 : fanOp,
8160 : compressorOp,
8161 : CoolPartLoadRatio,
8162 : HeatPartLoadRatio,
8163 : Dummy2,
8164 : Dummy2,
8165 : ZoneSensLoadMet,
8166 : ZoneLatLoadMet,
8167 : OnOffAirFlowRatio,
8168 : false);
8169 : } else {
8170 : // Calculate the sensible part load ratio through iteration
8171 0 : HeatErrorToler = thisFurnace.HeatingConvergenceTolerance;
8172 0 : SolFlag = 0; // # of iterations if positive, -1 means failed to converge, -2 means bounds are incorrect
8173 : // HeatErrorToler is in fraction of load, MaxIter = 600, SolFalg = # of iterations or error as appropriate
8174 0 : auto f = [&state, FurnaceNum, FirstHVACIteration, fanOp, compressorOp, TotalZoneSensLoad, ZoneSensLoadMetFanONCompOFF](
8175 : Real64 const PartLoadRatio) {
8176 0 : return CalcWaterToAirResidual(state,
8177 : PartLoadRatio,
8178 : FurnaceNum,
8179 : FirstHVACIteration,
8180 : fanOp,
8181 : compressorOp,
8182 : TotalZoneSensLoad,
8183 : 0.0,
8184 : 1.0,
8185 : ZoneSensLoadMetFanONCompOFF,
8186 0 : 0.0);
8187 0 : };
8188 0 : General::SolveRoot(state, HeatErrorToler, MaxIter, SolFlag, HeatPartLoadRatio, f, 0.0, 1.0);
8189 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = state.dataFurnaces->OnOffFanPartLoadFractionSave;
8190 0 : CalcFurnaceOutput(state,
8191 : FurnaceNum,
8192 : FirstHVACIteration,
8193 : fanOp,
8194 : compressorOp,
8195 : CoolPartLoadRatio,
8196 : HeatPartLoadRatio,
8197 : Dummy2,
8198 : Dummy2,
8199 : ZoneSensLoadMet,
8200 : ZoneLatLoadMet,
8201 : OnOffAirFlowRatio,
8202 : false);
8203 0 : if (SolFlag == -1 && !state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
8204 0 : if (std::abs(ZoneSensLoadMet - TotalZoneSensLoad) / TotalZoneSensLoad > HeatErrorToler) {
8205 0 : if (thisFurnace.WSHPHeatMaxIterIndex == 0) {
8206 0 : ShowWarningMessage(state,
8207 0 : format("Heating coil control failed to converge for {}:{}",
8208 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
8209 0 : thisFurnace.Name));
8210 0 : ShowContinueError(state, " Iteration limit exceeded in calculating DX heating coil sensible part-load ratio.");
8211 0 : ShowContinueErrorTimeStamp(state,
8212 0 : format("Sensible load to be met by DX coil = {:.2T} (watts), sensible output of DX coil = "
8213 : "{:.2T} (watts), and the simulation continues.",
8214 : TotalZoneSensLoad,
8215 : ZoneSensLoadMet));
8216 : }
8217 0 : ShowRecurringWarningErrorAtEnd(
8218 : state,
8219 0 : format("{} \"{}\" - Iteration limit exceeded in calculating sensible heating part-load ratio error continues.",
8220 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
8221 0 : thisFurnace.Name),
8222 0 : thisFurnace.WSHPHeatMaxIterIndex,
8223 : TotalZoneSensLoad,
8224 : TotalZoneSensLoad);
8225 : }
8226 0 : } else if (SolFlag == -2) {
8227 0 : HeatPartLoadRatio = max(MinPLR, min(1.0, std::abs(HPCoilSensDemand) / std::abs(HPCoilSensCapacity)));
8228 0 : CalcFurnaceOutput(state,
8229 : FurnaceNum,
8230 : FirstHVACIteration,
8231 : fanOp,
8232 : compressorOp,
8233 : 0.0,
8234 : HeatPartLoadRatio,
8235 : 0.0,
8236 : 0.0,
8237 : ZoneSensLoadMet,
8238 : ZoneLatLoadMet,
8239 : OnOffAirFlowRatio,
8240 : false);
8241 0 : if ((ZoneSensLoadMet - TotalZoneSensLoad) / TotalZoneSensLoad > HeatErrorToler) {
8242 0 : if (thisFurnace.WSHPHeatRegulaFalsiFailedIndex == 0) {
8243 0 : ShowWarningError(
8244 : state,
8245 0 : format("Heating coil control failed for {}:{}", HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name));
8246 0 : ShowContinueError(state, " Heating sensible part-load ratio determined to be outside the range of 0-1.");
8247 0 : ShowContinueError(
8248 : state,
8249 0 : format(" An estimated part-load ratio = {:.2T} will be used and the simulation continues.", HeatPartLoadRatio));
8250 0 : ShowContinueError(
8251 0 : state, format(" The estimated part-load ratio provides a heating sensible capacity = {:.2T}", ZoneSensLoadMet));
8252 0 : ShowContinueErrorTimeStamp(state, format(" Heating sensible load required = {:.2T}", TotalZoneSensLoad));
8253 : }
8254 0 : ShowRecurringWarningErrorAtEnd(state,
8255 0 : format("{} \"{}\" - Heating sensible part-load ratio out of range error continues.",
8256 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
8257 0 : thisFurnace.Name),
8258 0 : thisFurnace.WSHPHeatRegulaFalsiFailedIndex,
8259 : TotalZoneSensLoad,
8260 : TotalZoneSensLoad);
8261 : }
8262 : }
8263 : }
8264 :
8265 : // CALL supplemental heater if required
8266 0 : if ((TotalZoneSensLoad - ZoneSensLoadMet) > HVAC::SmallLoad && HeatPartLoadRatio >= 1.0) {
8267 0 : SuppHeatCoilLoad = TotalZoneSensLoad - ZoneSensLoadMet;
8268 0 : CalcFurnaceOutput(state,
8269 : FurnaceNum,
8270 : FirstHVACIteration,
8271 : fanOp,
8272 : compressorOp,
8273 : CoolPartLoadRatio,
8274 : HeatPartLoadRatio,
8275 : SuppHeatCoilLoad,
8276 : Dummy2,
8277 : ZoneSensLoadMet,
8278 : ZoneLatLoadMet,
8279 : OnOffAirFlowRatio,
8280 : false);
8281 : }
8282 :
8283 0 : if (fanOp == HVAC::FanOp::Cycling) {
8284 0 : thisFurnace.MdotFurnace *= HeatPartLoadRatio;
8285 : }
8286 :
8287 : //**********HVAC Scheduled ON, but no cooling, dehumidification or heating load*********
8288 0 : } else if (thisFurnace.availSched->getCurrentVal() > 0.0) {
8289 0 : thisFurnace.InitHeatPump = true; // initialization call to Calc Furnace
8290 0 : HeatPartLoadRatio = 0.0;
8291 0 : CoolPartLoadRatio = 0.0;
8292 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0; //! see 'Note' under INITIAL CALCULATIONS
8293 : // set report variables
8294 0 : thisFurnace.CompPartLoadRatio = 0.0;
8295 0 : thisFurnace.CoolingCoilSensDemand = 0.0;
8296 0 : thisFurnace.CoolingCoilLatentDemand = 0.0;
8297 0 : thisFurnace.HeatingCoilSensDemand = 0.0;
8298 0 : if (fanOp == HVAC::FanOp::Cycling) {
8299 0 : thisFurnace.MdotFurnace = 0.0;
8300 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0; // see 'Note' under INITIAL CALCULATIONS
8301 0 : CalcFurnaceOutput(state,
8302 : FurnaceNum,
8303 : FirstHVACIteration,
8304 : fanOp,
8305 : compressorOp,
8306 : CoolPartLoadRatio,
8307 : HeatPartLoadRatio,
8308 : Dummy2,
8309 : Dummy2,
8310 : ZoneSensLoadMet,
8311 : ZoneLatLoadMet,
8312 : OnOffAirFlowRatio,
8313 : false);
8314 0 : thisFurnace.MdotFurnace = 0.0;
8315 : } else { // continuous fan, cycling coil
8316 0 : CalcFurnaceOutput(state,
8317 : FurnaceNum,
8318 : FirstHVACIteration,
8319 : fanOp,
8320 : compressorOp,
8321 : CoolPartLoadRatio,
8322 : HeatPartLoadRatio,
8323 : Dummy2,
8324 : Dummy2,
8325 : ZoneSensLoadMet,
8326 : ZoneLatLoadMet,
8327 : OnOffAirFlowRatio,
8328 : false);
8329 : }
8330 : //*********No heating or cooling or dehumidification*********
8331 : } else {
8332 0 : thisFurnace.InitHeatPump = true; // initialization call to Calc Furnace
8333 0 : thisFurnace.MdotFurnace = 0.0;
8334 0 : HeatPartLoadRatio = 0.0;
8335 0 : CoolPartLoadRatio = 0.0;
8336 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0; // see 'Note' under INITIAL CALCULATIONS
8337 0 : thisFurnace.CompPartLoadRatio = 0.0;
8338 0 : thisFurnace.CoolingCoilSensDemand = 0.0;
8339 0 : thisFurnace.CoolingCoilLatentDemand = 0.0;
8340 0 : thisFurnace.HeatingCoilSensDemand = 0.0;
8341 0 : CalcFurnaceOutput(state,
8342 : FurnaceNum,
8343 : FirstHVACIteration,
8344 : fanOp,
8345 : compressorOp,
8346 : CoolPartLoadRatio,
8347 : HeatPartLoadRatio,
8348 : Dummy2,
8349 : Dummy2,
8350 : ZoneSensLoadMet,
8351 : ZoneLatLoadMet,
8352 : OnOffAirFlowRatio,
8353 : false);
8354 0 : thisFurnace.MdotFurnace = 0.0;
8355 : }
8356 :
8357 : // Set the fan inlet node flow rates
8358 0 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRateMaxAvail = thisFurnace.MdotFurnace;
8359 0 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.MdotFurnace;
8360 0 : }
8361 :
8362 56349 : void CalcFurnaceOutput(EnergyPlusData &state,
8363 : int const FurnaceNum,
8364 : bool const FirstHVACIteration,
8365 : HVAC::FanOp const fanOp, // Cycling fan or constant fan
8366 : HVAC::CompressorOp const compressorOp, // Compressor on/off; 1=on, 0=off
8367 : Real64 const CoolPartLoadRatio, // DX cooling coil part load ratio
8368 : Real64 const HeatPartLoadRatio, // DX heating coil part load ratio (0 for other heating coil types)
8369 : Real64 const HeatCoilLoad, // Heating coil load for gas heater
8370 : Real64 const ReheatCoilLoad, // Reheating coil load for gas heater
8371 : Real64 &SensibleLoadMet, // Sensible cooling load met (furnace outlet with respect to control zone temp)
8372 : Real64 &LatentLoadMet, // Latent cooling load met (furnace outlet with respect to control zone humidity ratio)
8373 : Real64 &OnOffAirFlowRatio, // Ratio of compressor ON mass flow rate to AVERAGE
8374 : bool const HXUnitOn, // flag to enable HX based on zone moisture load
8375 : Real64 const CoolingHeatingPLRRatio // cooling PLR to heating PLR ratio, used for cycling fan RH control
8376 : )
8377 : {
8378 :
8379 : // SUBROUTINE INFORMATION:
8380 : // AUTHOR Richard Raustad
8381 : // DATE WRITTEN Sept 2001
8382 : // MODIFIED Dec 2001
8383 :
8384 : // PURPOSE OF THIS SUBROUTINE:
8385 : // This subroutine calculates to sensible and latent loads met by the DX coils
8386 : // specified. Load met is the outlet node with respect to the control zone's
8387 : // temperature and humidity ratio.
8388 :
8389 : // METHODOLOGY EMPLOYED:
8390 : // Simulate each child object in the correct order for each system type. This routine is used in the
8391 : // RegulaFalsi function CALL. Air mass flow rate is set each iteration based on PLR.
8392 :
8393 56349 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
8394 56349 : auto &inletNode = state.dataLoopNodes->Node(thisFurnace.FurnaceInletNodeNum);
8395 56349 : int CoolingCoilType_Num = thisFurnace.CoolingCoilType_Num;
8396 56349 : Real64 QActual = 0.0; // heating coil load met or delivered
8397 56349 : state.dataFurnaces->ModifiedHeatCoilLoad = 0.0;
8398 :
8399 56349 : state.dataFurnaces->CoolHeatPLRRat = CoolingHeatingPLRRatio;
8400 :
8401 : // Cooling to Heating PLR Ratio (CoolHeatPLRRat) is used to track the air mass flow rate of both the heating
8402 : // and cooling coils when RH control is used and the heating coil operates longer than the cooling coil.
8403 : // When CoolPartLoadRatio/CoolHeatPLRRat is used, the PLR calculated is actually the PLR for the heating
8404 : // coil (heating PLR is greater than cooling PLR), it is this PLR that determines the air mass flow rate.
8405 : // When MAX(HeatPartLoadRatio,CoolPartLoadRatio) is used, only one of these values is non-zero.
8406 56349 : if (fanOp == HVAC::FanOp::Cycling) {
8407 56345 : if (state.dataFurnaces->CoolHeatPLRRat < 1.0) {
8408 0 : if (state.dataFurnaces->CoolHeatPLRRat > 0.0) {
8409 0 : inletNode.MassFlowRate = state.dataFurnaces->CompOnMassFlow * CoolPartLoadRatio / state.dataFurnaces->CoolHeatPLRRat;
8410 0 : if (thisFurnace.type != HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir) {
8411 0 : SetAverageAirFlow(state, FurnaceNum, CoolPartLoadRatio / state.dataFurnaces->CoolHeatPLRRat, OnOffAirFlowRatio);
8412 : }
8413 : } else {
8414 0 : inletNode.MassFlowRate = state.dataFurnaces->CompOnMassFlow * CoolPartLoadRatio;
8415 0 : if (thisFurnace.type != HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir) {
8416 0 : SetAverageAirFlow(state, FurnaceNum, max(HeatPartLoadRatio, CoolPartLoadRatio), OnOffAirFlowRatio);
8417 : }
8418 : }
8419 : } else {
8420 56345 : inletNode.MassFlowRate = state.dataFurnaces->CompOnMassFlow * max(HeatPartLoadRatio, CoolPartLoadRatio);
8421 56345 : if (thisFurnace.type != HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir) {
8422 56345 : SetAverageAirFlow(state, FurnaceNum, max(HeatPartLoadRatio, CoolPartLoadRatio), OnOffAirFlowRatio);
8423 : }
8424 : }
8425 : } else {
8426 4 : if (thisFurnace.type != HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir) {
8427 0 : SetAverageAirFlow(state, FurnaceNum, max(HeatPartLoadRatio, CoolPartLoadRatio), OnOffAirFlowRatio);
8428 : }
8429 : }
8430 :
8431 56349 : inletNode.MassFlowRateMaxAvail = inletNode.MassFlowRate;
8432 :
8433 : // Simulate the air-to-air heat pump
8434 56349 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir) {
8435 : // Simulate blow-thru fan and non-linear coils twice to update PLF used by the ONOFF Fan
8436 56345 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
8437 56345 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
8438 56345 : if (CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) {
8439 0 : HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(state,
8440 : BlankString,
8441 : FirstHVACIteration,
8442 : compressorOp,
8443 : CoolPartLoadRatio,
8444 0 : thisFurnace.CoolingCoilIndex,
8445 : fanOp,
8446 : HXUnitOn,
8447 : OnOffAirFlowRatio,
8448 0 : state.dataFurnaces->EconomizerFlag);
8449 : } else {
8450 112690 : DXCoils::SimDXCoil(state,
8451 : BlankString,
8452 : compressorOp,
8453 : FirstHVACIteration,
8454 56345 : thisFurnace.CoolingCoilIndex,
8455 : fanOp,
8456 : CoolPartLoadRatio,
8457 : OnOffAirFlowRatio);
8458 : }
8459 112690 : DXCoils::SimDXCoil(
8460 56345 : state, BlankString, compressorOp, FirstHVACIteration, thisFurnace.HeatingCoilIndex, fanOp, HeatPartLoadRatio, OnOffAirFlowRatio);
8461 56345 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
8462 : }
8463 : // Simulate cooling and heating coils
8464 56345 : if (CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) {
8465 0 : HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(state,
8466 : BlankString,
8467 : FirstHVACIteration,
8468 : compressorOp,
8469 : CoolPartLoadRatio,
8470 0 : thisFurnace.CoolingCoilIndex,
8471 : fanOp,
8472 : HXUnitOn,
8473 : OnOffAirFlowRatio,
8474 0 : state.dataFurnaces->EconomizerFlag);
8475 : } else {
8476 112690 : DXCoils::SimDXCoil(
8477 56345 : state, BlankString, compressorOp, FirstHVACIteration, thisFurnace.CoolingCoilIndex, fanOp, CoolPartLoadRatio, OnOffAirFlowRatio);
8478 : }
8479 112690 : DXCoils::SimDXCoil(
8480 56345 : state, BlankString, compressorOp, FirstHVACIteration, thisFurnace.HeatingCoilIndex, fanOp, HeatPartLoadRatio, OnOffAirFlowRatio);
8481 : // Simulate the draw-thru fan
8482 56345 : if (thisFurnace.fanPlace == HVAC::FanPlace::DrawThru) {
8483 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
8484 : }
8485 : // Simulate the supplemental heating coil
8486 56345 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat && ReheatCoilLoad > 0.0) {
8487 0 : bool SuppHeatingCoilFlag = true;
8488 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, ReheatCoilLoad, fanOp, QActual);
8489 0 : } else {
8490 : // equivalent to QCoilReq=0.0d0 or ReHeatCoilLoad = 0.0d0
8491 56345 : bool SuppHeatingCoilFlag = true;
8492 56345 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, ReheatCoilLoad, fanOp, QActual);
8493 : }
8494 : // Simulate the parameter estimate water-to-air heat pump
8495 4 : } else if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir && thisFurnace.WatertoAirHPType == WAHPCoilType::Simple) {
8496 : // Simulate blow-thru fan and non-linear coils twice to update PLF used by the ONOFF Fan
8497 4 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
8498 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
8499 : // COIL:WATERTOAIRHPSIMPLE:COOLING
8500 0 : WaterToAirHeatPumpSimple::SimWatertoAirHPSimple(state,
8501 : BlankString,
8502 0 : thisFurnace.CoolingCoilIndex,
8503 : thisFurnace.CoolingCoilSensDemand,
8504 : thisFurnace.CoolingCoilLatentDemand,
8505 : fanOp,
8506 : compressorOp,
8507 : CoolPartLoadRatio,
8508 : FirstHVACIteration); // CoolPartLoadRatio
8509 0 : Real64 Dummy = 0.0;
8510 : // COIL:WATERTOAIRHPSIMPLE:HEATING
8511 0 : WaterToAirHeatPumpSimple::SimWatertoAirHPSimple(state,
8512 : BlankString,
8513 0 : thisFurnace.HeatingCoilIndex,
8514 : thisFurnace.HeatingCoilSensDemand,
8515 : Dummy,
8516 : fanOp,
8517 : compressorOp,
8518 : HeatPartLoadRatio,
8519 : FirstHVACIteration); // HeatPartLoadRatio
8520 : // Simulate the whole thing a second time so that the correct PLF required by the coils is used by the Fan. *******
8521 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
8522 : }
8523 : // Simulate the cooling and heating coils
8524 : // COIL:WATERTOAIRHPSIMPLE:COOLING
8525 4 : WaterToAirHeatPumpSimple::SimWatertoAirHPSimple(state,
8526 : BlankString,
8527 4 : thisFurnace.CoolingCoilIndex,
8528 : thisFurnace.CoolingCoilSensDemand,
8529 : thisFurnace.CoolingCoilLatentDemand,
8530 : fanOp,
8531 : compressorOp,
8532 : CoolPartLoadRatio,
8533 : FirstHVACIteration); // CoolPartLoadRatio
8534 4 : Real64 Dummy = 0.0;
8535 : // COIL:WATERTOAIRHPSIMPLE:HEATING
8536 4 : WaterToAirHeatPumpSimple::SimWatertoAirHPSimple(state,
8537 : BlankString,
8538 4 : thisFurnace.HeatingCoilIndex,
8539 : thisFurnace.HeatingCoilSensDemand,
8540 : Dummy,
8541 : fanOp,
8542 : compressorOp,
8543 : HeatPartLoadRatio,
8544 : FirstHVACIteration); // HeatPartLoadRatio
8545 : // Simulate the draw-thru fan
8546 4 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
8547 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
8548 : }
8549 : // Simulate the supplemental heating coil
8550 4 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat && ReheatCoilLoad > 0.0) {
8551 0 : bool SuppHeatingCoilFlag = true; // if true simulates supplemental heating coil
8552 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, ReheatCoilLoad, fanOp, QActual);
8553 0 : } else {
8554 4 : bool SuppHeatingCoilFlag = true; // if true simulates supplemental heating coil
8555 4 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, fanOp, QActual);
8556 : }
8557 : // Simulate the detailed water-to-air heat pump
8558 4 : } else if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir && thisFurnace.WatertoAirHPType == WAHPCoilType::ParEst) {
8559 : // Simulate the draw-thru fan
8560 0 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
8561 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
8562 : }
8563 : // Simulate the cooling and heating coils
8564 0 : WaterToAirHeatPump::SimWatertoAirHP(state,
8565 : BlankString,
8566 0 : thisFurnace.CoolingCoilIndex,
8567 : thisFurnace.DesignMassFlowRate,
8568 : fanOp,
8569 : FirstHVACIteration,
8570 0 : thisFurnace.InitHeatPump,
8571 : thisFurnace.CoolingCoilSensDemand,
8572 : thisFurnace.CoolingCoilLatentDemand,
8573 : compressorOp,
8574 : CoolPartLoadRatio);
8575 0 : Real64 Dummy = 0.0;
8576 0 : WaterToAirHeatPump::SimWatertoAirHP(state,
8577 : BlankString,
8578 0 : thisFurnace.HeatingCoilIndex,
8579 : thisFurnace.DesignMassFlowRate,
8580 : fanOp,
8581 : FirstHVACIteration,
8582 0 : thisFurnace.InitHeatPump,
8583 : thisFurnace.HeatingCoilSensDemand,
8584 : Dummy,
8585 : compressorOp,
8586 : HeatPartLoadRatio);
8587 : // Simulate the draw-thru fan
8588 0 : if (thisFurnace.fanPlace == HVAC::FanPlace::DrawThru) {
8589 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
8590 : }
8591 : // Simulate the supplemental heating coil
8592 0 : HeatingCoils::SimulateHeatingCoilComponents(
8593 0 : state, BlankString, FirstHVACIteration, HeatCoilLoad, thisFurnace.SuppHeatCoilIndex, _, true, fanOp);
8594 :
8595 0 : } else { // ELSE it's not a heat pump
8596 : // Simulate blow-thru fan
8597 0 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
8598 :
8599 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
8600 :
8601 : // For non-linear coils, simulate coil to update PLF used by the ONOFF Fan
8602 0 : if (thisFurnace.fanType == HVAC::FanType::OnOff) {
8603 0 : if (thisFurnace.type != HVAC::UnitarySysType::Unitary_HeatOnly && thisFurnace.type != HVAC::UnitarySysType::Furnace_HeatOnly) {
8604 :
8605 0 : if (!thisFurnace.CoolingCoilUpstream) {
8606 0 : bool SuppHeatingCoilFlag = false; // if false simulates heating coil
8607 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, fanOp, QActual);
8608 : }
8609 :
8610 0 : if (CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) {
8611 0 : HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(state,
8612 : BlankString,
8613 : FirstHVACIteration,
8614 : compressorOp,
8615 : CoolPartLoadRatio,
8616 0 : thisFurnace.CoolingCoilIndex,
8617 : fanOp,
8618 : HXUnitOn,
8619 : OnOffAirFlowRatio,
8620 0 : state.dataFurnaces->EconomizerFlag);
8621 : } else {
8622 0 : DXCoils::SimDXCoil(state,
8623 : BlankString,
8624 : compressorOp,
8625 : FirstHVACIteration,
8626 0 : thisFurnace.CoolingCoilIndex,
8627 : fanOp,
8628 : CoolPartLoadRatio,
8629 : OnOffAirFlowRatio,
8630 0 : state.dataFurnaces->CoolHeatPLRRat);
8631 : }
8632 : }
8633 :
8634 0 : if (thisFurnace.CoolingCoilUpstream) {
8635 0 : bool SuppHeatingCoilFlag = false; // if false simulates heating coil
8636 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, fanOp, QActual);
8637 : }
8638 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
8639 : } // Simple OnOff fan
8640 :
8641 : } // Blow thru fan
8642 :
8643 : // Simulate the cooling and heating coils
8644 0 : if (thisFurnace.type != HVAC::UnitarySysType::Unitary_HeatOnly && thisFurnace.type != HVAC::UnitarySysType::Furnace_HeatOnly) {
8645 :
8646 0 : if (!thisFurnace.CoolingCoilUpstream) {
8647 0 : bool SuppHeatingCoilFlag = false; // if false simulates heating coil
8648 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, fanOp, QActual);
8649 : }
8650 :
8651 0 : if (CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) {
8652 0 : HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(state,
8653 : BlankString,
8654 : FirstHVACIteration,
8655 : compressorOp,
8656 : CoolPartLoadRatio,
8657 0 : thisFurnace.CoolingCoilIndex,
8658 : fanOp,
8659 : HXUnitOn,
8660 : OnOffAirFlowRatio,
8661 0 : state.dataFurnaces->EconomizerFlag);
8662 : } else {
8663 0 : DXCoils::SimDXCoil(state,
8664 : BlankString,
8665 : compressorOp,
8666 : FirstHVACIteration,
8667 0 : thisFurnace.CoolingCoilIndex,
8668 : fanOp,
8669 : CoolPartLoadRatio,
8670 : OnOffAirFlowRatio,
8671 0 : state.dataFurnaces->CoolHeatPLRRat);
8672 : }
8673 : }
8674 :
8675 0 : if (thisFurnace.CoolingCoilUpstream) {
8676 0 : bool SuppHeatingCoilFlag = false; // if false simulates heating coil
8677 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, fanOp, QActual);
8678 : }
8679 : // Simulate the draw-thru fan
8680 0 : if (thisFurnace.fanPlace == HVAC::FanPlace::DrawThru) {
8681 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
8682 : }
8683 0 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat || thisFurnace.SuppHeatCoilIndex > 0) {
8684 0 : bool SuppHeatingCoilFlag = true; // if true simulates supplemental heating coil
8685 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, ReheatCoilLoad, fanOp, QActual);
8686 : }
8687 : } // IF(Furnace(FurnaceNum)%type == UnitarySys_HeatPump_AirToAir)THEN
8688 :
8689 : // Get mass flow rate after components are simulated
8690 56349 : auto &outletNode = state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum);
8691 56349 : Real64 AirMassFlow = inletNode.MassFlowRate; // this should be outlet node as in 9897?
8692 :
8693 : // check the DesignMaxOutletTemp and reset if necessary (for Coil:Gas:Heating or Coil:Electric:Heating only)
8694 56349 : if (outletNode.Temp > thisFurnace.DesignMaxOutletTemp) {
8695 0 : Real64 Wout = outletNode.HumRat;
8696 0 : Real64 Tout = thisFurnace.DesignMaxOutletTemp;
8697 0 : state.dataFurnaces->ModifiedHeatCoilLoad = HeatCoilLoad - (AirMassFlow * Psychrometrics::PsyCpAirFnW(Wout) * (outletNode.Temp - Tout));
8698 0 : outletNode.Temp = Tout;
8699 : }
8700 :
8701 : // If the fan runs continually do not allow coils to set OnOffFanPartLoadRatio.
8702 56349 : if (fanOp == HVAC::FanOp::Continuous) state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
8703 :
8704 56349 : Real64 SensibleOutput = 0.0; // sensible output rate, {W}
8705 56349 : Real64 LatentOutput = 0.0; // latent output rate, {W}
8706 56349 : Real64 TotalOutput = 0.0; // total output rate, {W}
8707 112698 : CalcZoneSensibleLatentOutput(AirMassFlow,
8708 : outletNode.Temp,
8709 : outletNode.HumRat,
8710 56349 : state.dataLoopNodes->Node(thisFurnace.NodeNumOfControlledZone).Temp,
8711 56349 : state.dataLoopNodes->Node(thisFurnace.NodeNumOfControlledZone).HumRat,
8712 : SensibleOutput,
8713 : LatentOutput,
8714 : TotalOutput);
8715 56349 : SensibleLoadMet = SensibleOutput - thisFurnace.SenLoadLoss;
8716 56349 : thisFurnace.SensibleLoadMet = SensibleLoadMet;
8717 :
8718 56349 : if (thisFurnace.Humidistat) {
8719 0 : LatentLoadMet = LatentOutput - thisFurnace.LatLoadLoss;
8720 : } else {
8721 56349 : LatentLoadMet = 0.0;
8722 : }
8723 56349 : thisFurnace.LatentLoadMet = LatentLoadMet;
8724 56349 : }
8725 :
8726 : // End of Update subroutines for the Furnace Module
8727 : // *****************************************************************************
8728 :
8729 20268 : Real64 CalcFurnaceResidual(EnergyPlusData &state,
8730 : Real64 const PartLoadRatio, // DX cooling coil part load ratio
8731 : int FurnaceNum,
8732 : bool FirstHVACIteration,
8733 : HVAC::FanOp const fanOp,
8734 : HVAC::CompressorOp compressorOp,
8735 : Real64 LoadToBeMet,
8736 : Real64 par6_loadFlag,
8737 : Real64 par7_sensLatentFlag,
8738 : Real64 par9_HXOnFlag,
8739 : Real64 par10_HeatingCoilPLR)
8740 : {
8741 :
8742 : // FUNCTION INFORMATION:
8743 : // AUTHOR Richard Raustad
8744 : // DATE WRITTEN Feb 2005
8745 :
8746 : // PURPOSE OF THIS SUBROUTINE:
8747 : // To calculate the part-load ratio for cooling and heating coils
8748 :
8749 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
8750 : Real64 CoolPartLoadRatio; // DX cooling coil part load ratio
8751 : Real64 HeatPartLoadRatio; // DX heating coil part load ratio (0 for other heating coil types)
8752 : Real64 HeatCoilLoad; // Heating coil load for gas heater
8753 : Real64 SensibleLoadMet; // Sensible cooling load met (furnace outlet with respect to control zone temp)
8754 : Real64 LatentLoadMet; // Latent cooling load met (furnace outlet with respect to control zone humidity ratio)
8755 : Real64 OnOffAirFlowRatio; // Ratio of compressor ON air mass flow to AVERAGE air mass flow over time step
8756 : Real64 CoolingHeatingPLRRatio; // ratio of cooling PLR to heating PLR, used for cycling fan RH control
8757 : bool HXUnitOn; // flag to enable HX based on zone moisture load
8758 :
8759 : // // Convert parameters to usable variables
8760 : // int FurnaceNum = int(Par(1));
8761 : // bool FirstHVACIteration = Par(2) == 1.0;
8762 : // int FanfanOp = int(Par(3));
8763 : // CompressorOperation CompressorOp = static_cast<CompressorOperation>(Par(4));
8764 : // Real64 LoadToBeMet = Par(5);
8765 : // Real64 par6_loadFlag = Par(6);
8766 : // Real64 par7_sensLatentFlag = Par(7);
8767 : // Real64 par9_HXOnFlag = Par(9);
8768 : // Real64 par10_HeatingCoilPLR = Par(10);
8769 :
8770 20268 : if (par6_loadFlag == 1.0) {
8771 20244 : CoolPartLoadRatio = PartLoadRatio;
8772 20244 : HeatPartLoadRatio = 0.0;
8773 20244 : HeatCoilLoad = 0.0;
8774 : } else {
8775 24 : CoolPartLoadRatio = 0.0;
8776 24 : HeatPartLoadRatio = PartLoadRatio;
8777 :
8778 24 : int const HeatingCoilType_Num(state.dataFurnaces->Furnace(FurnaceNum).HeatingCoilType_Num);
8779 24 : if (HeatingCoilType_Num == HVAC::Coil_HeatingGasOrOtherFuel || HeatingCoilType_Num == HVAC::Coil_HeatingElectric ||
8780 24 : HeatingCoilType_Num == HVAC::Coil_HeatingWater || HeatingCoilType_Num == HVAC::Coil_HeatingSteam) {
8781 0 : HeatCoilLoad = state.dataFurnaces->Furnace(FurnaceNum).DesignHeatingCapacity * PartLoadRatio;
8782 : } else {
8783 24 : HeatCoilLoad = 0.0;
8784 : }
8785 : }
8786 :
8787 : // OnOffAirFlowRatio = Par(8)
8788 20268 : if (state.dataFurnaces->Furnace(FurnaceNum).type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir) {
8789 0 : state.dataFurnaces->Furnace(FurnaceNum).CompPartLoadRatio = PartLoadRatio;
8790 : }
8791 :
8792 20268 : if (par9_HXOnFlag == 1.0) {
8793 20244 : HXUnitOn = true;
8794 : } else {
8795 24 : HXUnitOn = false;
8796 : }
8797 :
8798 20268 : if (par10_HeatingCoilPLR > 0.0) {
8799 : // Par(10) = Furnace(FurnaceNum)%HeatPartLoadRatio
8800 : // FanOp = CycFan and Furnace(FurnaceNum)%HeatPartLoadRatio must be > 0 for Part(10) to be greater than 0
8801 : // This variable used when in heating mode and dehumidification (cooling) is required.
8802 0 : CoolingHeatingPLRRatio = min(1.0, CoolPartLoadRatio / state.dataFurnaces->Furnace(FurnaceNum).HeatPartLoadRatio);
8803 : } else {
8804 20268 : CoolingHeatingPLRRatio = 1.0;
8805 : }
8806 :
8807 : // Subroutine arguments
8808 20268 : CalcFurnaceOutput(state,
8809 : FurnaceNum,
8810 : FirstHVACIteration,
8811 : fanOp,
8812 : compressorOp,
8813 : CoolPartLoadRatio,
8814 : HeatPartLoadRatio,
8815 : HeatCoilLoad,
8816 : 0.0,
8817 : SensibleLoadMet,
8818 : LatentLoadMet,
8819 : OnOffAirFlowRatio,
8820 : HXUnitOn,
8821 : CoolingHeatingPLRRatio);
8822 :
8823 : // Calculate residual based on output calculation flag
8824 20268 : if (par7_sensLatentFlag == 1.0) {
8825 20268 : if (LoadToBeMet == 0.0) {
8826 0 : return (SensibleLoadMet - LoadToBeMet) / 100.0;
8827 : } else {
8828 20268 : return (SensibleLoadMet - LoadToBeMet) / LoadToBeMet;
8829 : }
8830 : } else {
8831 0 : if (LoadToBeMet == 0.0) {
8832 0 : return (LatentLoadMet - LoadToBeMet) / 100.0;
8833 : } else {
8834 0 : return (LatentLoadMet - LoadToBeMet) / LoadToBeMet;
8835 : }
8836 : }
8837 : }
8838 :
8839 0 : Real64 CalcWaterToAirResidual(EnergyPlusData &state,
8840 : Real64 const PartLoadRatio, // DX cooling coil part load ratio
8841 : int FurnaceNum,
8842 : bool FirstHVACIteration,
8843 : HVAC::FanOp const fanOp,
8844 : HVAC::CompressorOp compressorOp,
8845 : Real64 LoadToBeMet,
8846 : Real64 par6_loadTypeFlag,
8847 : Real64 par7_latentOrSensible,
8848 : Real64 ZoneSensLoadMetFanONCompOFF,
8849 : Real64 par9_HXUnitOne)
8850 : {
8851 :
8852 : // FUNCTION INFORMATION:
8853 : // AUTHOR Richard Raustad
8854 : // DATE WRITTEN October 2006
8855 :
8856 : // PURPOSE OF THIS SUBROUTINE:
8857 : // To calculate the part-load ratio for water to air HP's
8858 : // this is used for parameter estimation WAHPs but not equation fit WAHPs
8859 :
8860 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
8861 : Real64 CoolPartLoadRatio; // DX cooling coil part load ratio
8862 : Real64 HeatPartLoadRatio; // DX heating coil part load ratio (0 for other heating coil types)
8863 : Real64 HeatCoilLoad; // Heating coil load for gas heater
8864 : Real64 ZoneSensLoadMet; // Sensible cooling load met (furnace outlet with respect to control zone temp)
8865 : Real64 ZoneLatLoadMet; // Latent cooling load met (furnace outlet with respect to control zone humidity ratio)
8866 : Real64 Dummy;
8867 : Real64 HPCoilSensDemand;
8868 : Real64 OnOffAirFlowRatio;
8869 : bool HXUnitOn; // flag to enable HX based on zone moisture load (not valid for water-to-air HP's
8870 :
8871 : // Convert parameters to usable variables
8872 : // int FurnaceNum = int(Par[0]);
8873 : // bool FirstHVACIteration = Par[1] == 1.0;
8874 : // int FanOp = int(Par[2]);
8875 : // CompressorOperation CompressorOp = static_cast<CompressorOperation>(Par[3]);
8876 : // Real64 LoadToBeMet = Par[4];
8877 : // Real64 par6_loadTypeFlag = Par[5];
8878 : // Real64 par7_latentOrSensible = Par[6];
8879 : // Real64 ZoneSensLoadMetFanONCompOFF = Par[7];
8880 : // Real64 par9_HXUnitOne = Par[8];
8881 :
8882 : int CoilIndex;
8883 0 : if (par6_loadTypeFlag == 1.0) {
8884 0 : CoolPartLoadRatio = PartLoadRatio;
8885 0 : HeatPartLoadRatio = 0.0;
8886 0 : HeatCoilLoad = 0.0;
8887 0 : CoilIndex = state.dataFurnaces->Furnace(FurnaceNum).CoolingCoilIndex;
8888 : } else {
8889 0 : CoolPartLoadRatio = 0.0;
8890 0 : HeatPartLoadRatio = PartLoadRatio;
8891 0 : CoilIndex = state.dataFurnaces->Furnace(FurnaceNum).HeatingCoilIndex;
8892 : }
8893 :
8894 : // Get child component RuntimeFrac
8895 : Real64 RuntimeFrac;
8896 0 : switch (state.dataFurnaces->Furnace(FurnaceNum).WatertoAirHPType) {
8897 0 : case WAHPCoilType::Simple: {
8898 0 : RuntimeFrac = state.dataWaterToAirHeatPumpSimple->SimpleWatertoAirHP(CoilIndex).RunFrac;
8899 0 : break;
8900 : }
8901 0 : case WAHPCoilType::ParEst: {
8902 0 : RuntimeFrac = state.dataWaterToAirHeatPump->WatertoAirHP(CoilIndex).RunFrac;
8903 0 : break;
8904 : }
8905 0 : case WAHPCoilType::VarSpeedEquationFit: {
8906 0 : RuntimeFrac = state.dataVariableSpeedCoils->VarSpeedCoil(CoilIndex).RunFrac;
8907 0 : break;
8908 : }
8909 0 : default:
8910 0 : RuntimeFrac = 1.0; // Programming error. Assert failure?
8911 : }
8912 :
8913 0 : state.dataFurnaces->OnOffFanPartLoadFractionSave = state.dataHVACGlobal->OnOffFanPartLoadFraction;
8914 : // update fan and compressor run times
8915 0 : state.dataFurnaces->Furnace(FurnaceNum).CompPartLoadRatio = PartLoadRatio;
8916 :
8917 : // Calculate the heating coil demand as (the zone sensible load - load met by fan heat and mixed air)
8918 : // Note; The load met by fan heat and mixed air is calculated as mdot(zoneinletenthalpy-zoneoutletenthalpy)
8919 : // This accounts for the negative sign in the equation.
8920 :
8921 : // Calculate the heat coil sensible capacity as the load met by the system with the fan and compressor on less
8922 : // the load met by the system with the compressor off.
8923 : // HPCoilSensCapacity = ZoneSensLoadMetFanONCompON - ZoneSensLoadMetFanONCompOFF
8924 :
8925 : // Set input parameters for heat pump coil model
8926 0 : HPCoilSensDemand = LoadToBeMet - RuntimeFrac * ZoneSensLoadMetFanONCompOFF;
8927 : // HPCoilSensDemand = LoadToBeMet - PartLoadRatio*ZoneSensLoadMetFanONCompOFF
8928 0 : if (par6_loadTypeFlag == 1.0) {
8929 0 : state.dataFurnaces->Furnace(FurnaceNum).HeatingCoilSensDemand = 0.0;
8930 0 : state.dataFurnaces->Furnace(FurnaceNum).CoolingCoilSensDemand = std::abs(HPCoilSensDemand);
8931 : } else {
8932 0 : state.dataFurnaces->Furnace(FurnaceNum).HeatingCoilSensDemand = HPCoilSensDemand;
8933 0 : state.dataFurnaces->Furnace(FurnaceNum).CoolingCoilSensDemand = 0.0;
8934 : }
8935 0 : state.dataFurnaces->Furnace(FurnaceNum).InitHeatPump = false; // initialization call to Calc Furnace
8936 :
8937 : // Calculate the zone loads met and the new part load ratio and for the specified run time
8938 0 : Dummy = 0.0;
8939 0 : OnOffAirFlowRatio = 1.0;
8940 0 : if (par9_HXUnitOne == 1.0) {
8941 0 : HXUnitOn = true;
8942 : } else {
8943 0 : HXUnitOn = false;
8944 : }
8945 :
8946 : // Subroutine arguments
8947 : // CALL CalcFurnaceOutput(FurnaceNum,FirstHVACIteration,FanOp,compressorOp,CoolPartLoadRatio,&
8948 : // HeatPartLoadRatio, HeatCoilLoad, ReHeatCoilLoad, SensibleLoadMet, LatentLoadMet, HXUnitOn)
8949 0 : CalcFurnaceOutput(state,
8950 : FurnaceNum,
8951 : FirstHVACIteration,
8952 : fanOp,
8953 : compressorOp,
8954 : CoolPartLoadRatio,
8955 : HeatPartLoadRatio,
8956 : Dummy,
8957 : Dummy,
8958 : ZoneSensLoadMet,
8959 : ZoneLatLoadMet,
8960 : OnOffAirFlowRatio,
8961 : HXUnitOn);
8962 :
8963 : // Calculate residual based on output calculation flag
8964 0 : if (par7_latentOrSensible == 1.0) {
8965 0 : return (ZoneSensLoadMet - LoadToBeMet) / LoadToBeMet;
8966 : } else {
8967 0 : return (ZoneLatLoadMet - LoadToBeMet) / LoadToBeMet;
8968 : }
8969 : }
8970 :
8971 97113 : void SetAverageAirFlow(EnergyPlusData &state,
8972 : int const FurnaceNum, // Unit index
8973 : Real64 const PartLoadRatio, // unit part load ratio
8974 : Real64 &OnOffAirFlowRatio // ratio of compressor ON airflow to AVERAGE airflow over timestep
8975 : )
8976 : {
8977 :
8978 : // SUBROUTINE INFORMATION:
8979 : // AUTHOR Richard Raustad
8980 : // DATE WRITTEN July 2005
8981 :
8982 : // PURPOSE OF THIS SUBROUTINE:
8983 : // Set the average air mass flow rates using the part-load fraction of the HVAC system for this time step
8984 : // Set OnOffAirFlowRatio to be used by DX coils
8985 :
8986 : // METHODOLOGY EMPLOYED:
8987 : // The air flow rate in cooling, heating, and no cooling or heating can be different.
8988 : // Calculate the air flow rate based on initializations made in InitFurnace.
8989 :
8990 97113 : int InletNode = state.dataFurnaces->Furnace(FurnaceNum).FurnaceInletNodeNum;
8991 : Real64 AverageUnitMassFlow =
8992 97113 : (PartLoadRatio * state.dataFurnaces->CompOnMassFlow) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffMassFlow);
8993 97113 : if (state.dataFurnaces->CompOffFlowRatio > 0.0) {
8994 4 : state.dataFurnaces->FanSpeedRatio =
8995 4 : (PartLoadRatio * state.dataFurnaces->CompOnFlowRatio) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffFlowRatio);
8996 : } else {
8997 97109 : state.dataFurnaces->FanSpeedRatio = state.dataFurnaces->CompOnFlowRatio;
8998 : }
8999 :
9000 : // IF the furnace is scheduled on or nightime cycle overrides fan schedule. Uses same logic as fan.
9001 291339 : if (state.dataFurnaces->Furnace(FurnaceNum).availSched->getCurrentVal() > 0.0 &&
9002 97113 : ((state.dataFurnaces->Furnace(FurnaceNum).fanAvailSched->getCurrentVal() > 0.0 || state.dataHVACGlobal->TurnFansOn) &&
9003 97113 : !state.dataHVACGlobal->TurnFansOff)) {
9004 97107 : state.dataLoopNodes->Node(InletNode).MassFlowRate = AverageUnitMassFlow;
9005 97107 : state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AverageUnitMassFlow;
9006 97107 : if (AverageUnitMassFlow > 0.0) {
9007 66059 : OnOffAirFlowRatio = state.dataFurnaces->CompOnMassFlow / AverageUnitMassFlow;
9008 : } else {
9009 31048 : OnOffAirFlowRatio = 0.0;
9010 : }
9011 : } else {
9012 6 : state.dataLoopNodes->Node(InletNode).MassFlowRate = 0.0;
9013 6 : OnOffAirFlowRatio = 1.0;
9014 : }
9015 :
9016 97113 : state.dataFurnaces->Furnace(FurnaceNum).MdotFurnace = state.dataFurnaces->CompOnMassFlow;
9017 97113 : state.dataFurnaces->OnOffAirFlowRatioSave = OnOffAirFlowRatio;
9018 97113 : }
9019 :
9020 : // Beginning of Reporting subroutines for the Furnace Module
9021 : // *****************************************************************************
9022 :
9023 15224 : void ReportFurnace(EnergyPlusData &state, int const FurnaceNum, int const AirLoopNum)
9024 : {
9025 :
9026 : // SUBROUTINE INFORMATION:
9027 : // AUTHOR Richard Liesen
9028 : // DATE WRITTEN Feb 2001
9029 :
9030 : // PURPOSE OF THIS SUBROUTINE:
9031 : // This subroutine updates the report variable for the coils.
9032 :
9033 : // METHODOLOGY EMPLOYED:
9034 : // Update fan part-load ratio based on mass flow rate ratio.
9035 : // Update global variables used by AirflowNetwork module.
9036 :
9037 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
9038 : Real64 ratio;
9039 : Real64 OnOffRatio;
9040 15224 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
9041 :
9042 : // Report the Furnace Fan Part Load Ratio
9043 15224 : if (thisFurnace.NumOfSpeedCooling < 1) {
9044 15224 : if (thisFurnace.DesignMassFlowRate > 0.0) {
9045 15224 : thisFurnace.FanPartLoadRatio = thisFurnace.MdotFurnace / thisFurnace.DesignMassFlowRate;
9046 : } else {
9047 0 : thisFurnace.FanPartLoadRatio = 0.0;
9048 : }
9049 : }
9050 :
9051 : // Set mass flow rates during on and off cycle using an OnOff fan
9052 15224 : if (state.afn->distribution_simulated) {
9053 11170 : state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopSystemOnMassFlowrate = state.dataFurnaces->CompOnMassFlow;
9054 11170 : state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopSystemOffMassFlowrate = state.dataFurnaces->CompOffMassFlow;
9055 11170 : state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopFanOperationMode = thisFurnace.fanOp;
9056 11170 : state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopOnOffFanPartLoadRatio = thisFurnace.FanPartLoadRatio;
9057 11170 : OnOffRatio = state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopOnOffFanPartLoadRatio;
9058 11170 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir) {
9059 11169 : state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopOnOffFanPartLoadRatio =
9060 11169 : max(thisFurnace.FanPartLoadRatio, thisFurnace.HeatPartLoadRatio, thisFurnace.CoolPartLoadRatio);
9061 11169 : state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopOnOffFanPartLoadRatio =
9062 11169 : min(1.0, state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopOnOffFanPartLoadRatio);
9063 : }
9064 11170 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool) {
9065 1 : if (thisFurnace.HeatPartLoadRatio == 0.0 && thisFurnace.CoolPartLoadRatio == 0.0 && thisFurnace.FanPartLoadRatio > 0.0) {
9066 2 : if (state.dataFurnaces->CompOnMassFlow < max(thisFurnace.MaxCoolAirMassFlow, thisFurnace.MaxHeatAirMassFlow) &&
9067 1 : state.dataFurnaces->CompOnMassFlow > 0.0) {
9068 1 : ratio = max(thisFurnace.MaxCoolAirMassFlow, thisFurnace.MaxHeatAirMassFlow) / state.dataFurnaces->CompOnMassFlow;
9069 1 : state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopOnOffFanPartLoadRatio =
9070 1 : state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopOnOffFanPartLoadRatio * ratio;
9071 : }
9072 : }
9073 : }
9074 : }
9075 15224 : if (thisFurnace.FirstPass) {
9076 3 : if (!state.dataGlobal->SysSizingCalc) {
9077 3 : DataSizing::resetHVACSizingGlobals(state, 0, state.dataSize->CurSysNum, thisFurnace.FirstPass);
9078 : }
9079 : }
9080 15224 : state.dataHVACGlobal->OnOffFanPartLoadFraction =
9081 : 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)
9082 15224 : }
9083 :
9084 71571 : void CalcNonDXHeatingCoils(EnergyPlusData &state,
9085 : int const FurnaceNum, // Furnace Index
9086 : bool const SuppHeatingCoilFlag, // .TRUE. if supplemental heating coil
9087 : bool const FirstHVACIteration, // flag for first HVAC iteration in the time step
9088 : Real64 const QCoilLoad, // load met by unit (watts)
9089 : HVAC::FanOp const fanOp, // fan operation mode
9090 : Real64 &HeatCoilLoadmet // Heating Load Met
9091 : )
9092 : {
9093 : // SUBROUTINE INFORMATION:
9094 : // AUTHOR Bereket Nigusse, FSEC/UCF
9095 : // DATE WRITTEN January 2012
9096 :
9097 : // PURPOSE OF THIS SUBROUTINE:
9098 : // This subroutine simulates the four non dx heating coil types: Gas, Electric, hot water and steam.
9099 :
9100 : // METHODOLOGY EMPLOYED:
9101 : // Simply calls the different heating coil component. The hot water flow rate matching the coil load
9102 : // is calculated iteratively.
9103 :
9104 : // SUBROUTINE PARAMETER DEFINITIONS:
9105 71571 : Real64 constexpr ErrTolerance(0.001); // convergence limit for hotwater coil
9106 71571 : int constexpr SolveMaxIter(50);
9107 :
9108 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
9109 : Real64 mdot; // heating coil steam or hot water mass flow rate
9110 : Real64 MinWaterFlow; // coil minimum hot water mass flow rate, kg/s
9111 : Real64 MaxHotWaterFlow; // coil maximum hot water mass flow rate, kg/s
9112 : Real64 HotWaterMdot; // actual hot water mass flow rate
9113 71571 : int CoilTypeNum(0); // heating coil type number
9114 71571 : int HeatingCoilIndex(0); // heating coil index
9115 71571 : int CoilControlNode(0); // control node for hot water and steam heating coils
9116 71571 : int CoilOutletNode(0); // air outlet node of the heating coils
9117 71571 : PlantLocation plantLoc{}; // plant loop location
9118 :
9119 71571 : Real64 QActual = 0.0; // actual heating load
9120 71571 : std::string &HeatingCoilName = state.dataFurnaces->HeatingCoilName; // name of heating coil
9121 71571 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
9122 :
9123 71571 : if (SuppHeatingCoilFlag) {
9124 71571 : HeatingCoilName = thisFurnace.SuppHeatCoilName;
9125 71571 : HeatingCoilIndex = thisFurnace.SuppHeatCoilIndex;
9126 71571 : CoilControlNode = thisFurnace.SuppCoilControlNode;
9127 71571 : CoilOutletNode = thisFurnace.SuppCoilOutletNode;
9128 71571 : CoilTypeNum = thisFurnace.SuppHeatCoilType_Num;
9129 71571 : plantLoc = thisFurnace.SuppPlantLoc;
9130 71571 : MaxHotWaterFlow = thisFurnace.MaxSuppCoilFluidFlow;
9131 : } else {
9132 0 : HeatingCoilName = thisFurnace.HeatingCoilName;
9133 0 : HeatingCoilIndex = thisFurnace.HeatingCoilIndex;
9134 0 : CoilControlNode = thisFurnace.CoilControlNode;
9135 0 : CoilOutletNode = thisFurnace.CoilOutletNode;
9136 0 : CoilTypeNum = thisFurnace.HeatingCoilType_Num;
9137 0 : plantLoc = thisFurnace.plantLoc;
9138 0 : MaxHotWaterFlow = thisFurnace.MaxHeatCoilFluidFlow;
9139 : }
9140 :
9141 71571 : switch (CoilTypeNum) {
9142 71567 : case HVAC::Coil_HeatingGasOrOtherFuel:
9143 : case HVAC::Coil_HeatingElectric:
9144 : case HVAC::Coil_HeatingDesuperheater: {
9145 71567 : HeatingCoils::SimulateHeatingCoilComponents(
9146 : state, HeatingCoilName, FirstHVACIteration, QCoilLoad, HeatingCoilIndex, QActual, SuppHeatingCoilFlag, fanOp);
9147 71567 : } break;
9148 0 : case HVAC::Coil_HeatingWater: {
9149 0 : if (QCoilLoad > HVAC::SmallLoad) {
9150 0 : PlantUtilities::SetComponentFlowRate(state, MaxHotWaterFlow, CoilControlNode, CoilOutletNode, plantLoc);
9151 0 : WaterCoils::SimulateWaterCoilComponents(state, HeatingCoilName, FirstHVACIteration, HeatingCoilIndex, QActual, fanOp);
9152 :
9153 0 : if (QActual > (QCoilLoad + HVAC::SmallLoad)) {
9154 : // control water flow to obtain output matching QCoilLoad
9155 0 : MinWaterFlow = 0.0;
9156 0 : auto f = [&state, FurnaceNum, FirstHVACIteration, QCoilLoad, SuppHeatingCoilFlag](Real64 const HWFlow) {
9157 0 : Real64 QCoilRequested = QCoilLoad;
9158 :
9159 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
9160 : Real64 QCoilActual; // delivered coil load, W
9161 0 : Real64 mdot = HWFlow; // to get non-const argument
9162 0 : QCoilActual = QCoilRequested;
9163 0 : if (!SuppHeatingCoilFlag) {
9164 0 : PlantUtilities::SetComponentFlowRate(state,
9165 : mdot,
9166 0 : state.dataFurnaces->Furnace(FurnaceNum).CoilControlNode,
9167 0 : state.dataFurnaces->Furnace(FurnaceNum).CoilOutletNode,
9168 0 : state.dataFurnaces->Furnace(FurnaceNum).plantLoc);
9169 0 : WaterCoils::SimulateWaterCoilComponents(state,
9170 0 : state.dataFurnaces->Furnace(FurnaceNum).HeatingCoilName,
9171 : FirstHVACIteration,
9172 0 : state.dataFurnaces->Furnace(FurnaceNum).HeatingCoilIndex,
9173 : QCoilActual,
9174 0 : state.dataFurnaces->Furnace(FurnaceNum).fanOp);
9175 : } else {
9176 : // supplemental coil
9177 0 : PlantUtilities::SetComponentFlowRate(state,
9178 : mdot,
9179 0 : state.dataFurnaces->Furnace(FurnaceNum).SuppCoilControlNode,
9180 0 : state.dataFurnaces->Furnace(FurnaceNum).SuppCoilOutletNode,
9181 0 : state.dataFurnaces->Furnace(FurnaceNum).SuppPlantLoc);
9182 : // simulate the hot water supplemental heating coil
9183 0 : WaterCoils::SimulateWaterCoilComponents(state,
9184 0 : state.dataFurnaces->Furnace(FurnaceNum).SuppHeatCoilName,
9185 : FirstHVACIteration,
9186 0 : state.dataFurnaces->Furnace(FurnaceNum).SuppHeatCoilIndex,
9187 : QCoilActual,
9188 0 : state.dataFurnaces->Furnace(FurnaceNum).fanOp);
9189 : }
9190 0 : return QCoilRequested != 0.0 ? (QCoilActual - QCoilRequested) / QCoilRequested : 0.0;
9191 0 : };
9192 0 : int SolFlag = 0;
9193 0 : General::SolveRoot(state, ErrTolerance, SolveMaxIter, SolFlag, HotWaterMdot, f, MinWaterFlow, MaxHotWaterFlow);
9194 0 : if (SolFlag == -1) {
9195 0 : if (thisFurnace.HotWaterCoilMaxIterIndex == 0) {
9196 0 : ShowWarningMessage(state,
9197 0 : format("CalcNonDXHeatingCoils: Hot water coil control failed for {}=\"{}\"",
9198 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
9199 0 : thisFurnace.Name));
9200 0 : ShowContinueErrorTimeStamp(state, "");
9201 0 : ShowContinueError(state, format(" Iteration limit [{}] exceeded in calculating hot water mass flow rate", SolveMaxIter));
9202 : }
9203 0 : ShowRecurringWarningErrorAtEnd(
9204 : state,
9205 0 : format("CalcNonDXHeatingCoils: Hot water coil control failed (iteration limit [{}]) for {}=\"{}",
9206 : SolveMaxIter,
9207 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
9208 0 : thisFurnace.Name),
9209 0 : thisFurnace.HotWaterCoilMaxIterIndex);
9210 0 : } else if (SolFlag == -2) {
9211 0 : if (thisFurnace.HotWaterCoilMaxIterIndex2 == 0) {
9212 0 : ShowWarningMessage(state,
9213 0 : format("CalcNonDXHeatingCoils: Hot water coil control failed (maximum flow limits) for {}=\"{}\"",
9214 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
9215 0 : thisFurnace.Name));
9216 0 : ShowContinueErrorTimeStamp(state, "");
9217 0 : ShowContinueError(state, "...Bad hot water maximum flow rate limits");
9218 0 : ShowContinueError(state, format("...Given minimum water flow rate={:.3R} kg/s", MinWaterFlow));
9219 0 : ShowContinueError(state, format("...Given maximum water flow rate={:.3R} kg/s", MaxHotWaterFlow));
9220 : }
9221 0 : ShowRecurringWarningErrorAtEnd(state,
9222 0 : format("CalcNonDXHeatingCoils: Hot water coil control failed (flow limits) for {}=\"{}\"",
9223 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
9224 0 : thisFurnace.Name),
9225 0 : thisFurnace.HotWaterCoilMaxIterIndex2,
9226 : MaxHotWaterFlow,
9227 : MinWaterFlow,
9228 : _,
9229 : "[kg/s]",
9230 : "[kg/s]");
9231 : }
9232 : }
9233 : } else {
9234 0 : mdot = 0.0;
9235 0 : PlantUtilities::SetComponentFlowRate(state, mdot, CoilControlNode, CoilOutletNode, plantLoc);
9236 : }
9237 : // simulate the hot water heating coil
9238 0 : WaterCoils::SimulateWaterCoilComponents(state, HeatingCoilName, FirstHVACIteration, HeatingCoilIndex, QActual, fanOp);
9239 0 : } break;
9240 0 : case HVAC::Coil_HeatingSteam: {
9241 0 : if (QCoilLoad > HVAC::SmallLoad) {
9242 0 : PlantUtilities::SetComponentFlowRate(state, MaxHotWaterFlow, CoilControlNode, CoilOutletNode, plantLoc);
9243 : // simulate the steam heating coil
9244 0 : SteamCoils::SimulateSteamCoilComponents(state, HeatingCoilName, FirstHVACIteration, HeatingCoilIndex, QCoilLoad, QActual, fanOp);
9245 : } else {
9246 0 : mdot = 0.0;
9247 0 : PlantUtilities::SetComponentFlowRate(state, mdot, CoilControlNode, CoilOutletNode, plantLoc);
9248 : // simulate the steam heating coil
9249 0 : SteamCoils::SimulateSteamCoilComponents(state, HeatingCoilName, FirstHVACIteration, HeatingCoilIndex, QCoilLoad, QActual, fanOp);
9250 : }
9251 0 : } break;
9252 4 : default:
9253 4 : break;
9254 : }
9255 :
9256 71571 : HeatCoilLoadmet = QActual;
9257 71571 : }
9258 :
9259 : // End of Reporting subroutines for the Furnace Module
9260 :
9261 : //******************************************************************************
9262 :
9263 0 : void SimVariableSpeedHP(EnergyPlusData &state,
9264 : int const FurnaceNum, // number of the current engine driven Heat Pump being simulated
9265 : bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
9266 : int const AirLoopNum, // index to air loop
9267 : Real64 const QZnReq, // required zone load
9268 : Real64 const QLatReq, // required latent load
9269 : Real64 &OnOffAirFlowRatio // ratio of compressor ON airflow to AVERAGE airflow over timestep
9270 : )
9271 : {
9272 :
9273 : // SUBROUTINE INFORMATION:
9274 : // AUTHOR Bo Shen, based on HVACMultiSpeedHeatPump:CalcMSHeatPump
9275 : // DATE WRITTEN March, 2012
9276 :
9277 : // PURPOSE OF THIS SUBROUTINE:
9278 : // Simulate a multispeed heat pump; adjust its output to match the
9279 : // required system load.
9280 :
9281 : // METHODOLOGY EMPLOYED:
9282 : // Calls ControlMSHPOutput to obtain the desired unit output
9283 :
9284 : Real64 PartLoadFrac; // compressor part load fraction
9285 : Real64 SpeedRatio; // compressor speed ratio
9286 : Real64 QTotUnitOut; // capacity output
9287 0 : auto &SpeedNum = state.dataFurnaces->SpeedNum;
9288 0 : auto &SupHeaterLoad = state.dataFurnaces->SupHeaterLoad;
9289 : HVAC::CompressorOp compressorOp; // compressor operation; 1=on, 0=off
9290 : Real64 QSensUnitOut; // sensible capacity output
9291 : Real64 QLatUnitOut; // latent capacity output
9292 : Real64 ActualSensibleOutput; // Actual furnace sensible capacity
9293 : Real64 QToHeatSetPt; // Load required to meet heating setpoint temp (>0 is a heating load)
9294 : Real64 NoCompOutput; // output when no active compressor [W]
9295 : bool EconoActive; // TRUE if Economizer is active
9296 :
9297 : // zero DX coils, and supplemental electric heater electricity consumption
9298 0 : state.dataHVACGlobal->DXElecHeatingPower = 0.0;
9299 0 : state.dataHVACGlobal->DXElecCoolingPower = 0.0;
9300 0 : state.dataFurnaces->SaveCompressorPLR = 0.0;
9301 0 : state.dataHVACGlobal->ElecHeatingCoilPower = 0.0;
9302 0 : state.dataHVACGlobal->SuppHeatingCoilPower = 0.0;
9303 0 : state.dataHVACGlobal->DefrostElecPower = 0.0;
9304 :
9305 0 : Real64 SystemSensibleLoad = QZnReq; // Positive value means heating required
9306 0 : Real64 TotalZoneSensibleLoad = QZnReq;
9307 0 : Real64 TotalZoneLatentLoad = QLatReq;
9308 0 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
9309 : // initialize local variables
9310 0 : bool UnitOn = true;
9311 0 : int OutletNode = thisFurnace.FurnaceOutletNodeNum;
9312 0 : int InletNode = thisFurnace.FurnaceInletNodeNum;
9313 0 : Real64 AirMassFlow = thisFurnace.DesignMassFlowRate;
9314 0 : HVAC::FanOp fanOp = thisFurnace.fanOp; // fan operating mode
9315 0 : int ZoneNum = thisFurnace.ControlZoneNum;
9316 :
9317 : // Set latent load for heating
9318 0 : if (state.dataFurnaces->HeatingLoad) {
9319 0 : thisFurnace.HeatCoolMode = Furnaces::ModeOfOperation::HeatingMode;
9320 : // Set latent load for cooling and no sensible load condition
9321 0 : } else if (state.dataFurnaces->CoolingLoad) {
9322 0 : thisFurnace.HeatCoolMode = Furnaces::ModeOfOperation::CoolingMode;
9323 : } else {
9324 0 : thisFurnace.HeatCoolMode = Furnaces::ModeOfOperation::NoCoolHeat;
9325 : }
9326 :
9327 : // set the on/off flags
9328 0 : if (thisFurnace.fanOp == HVAC::FanOp::Cycling) {
9329 : // cycling unit only runs if there is a cooling or heating load.
9330 0 : if (std::abs(QZnReq) < HVAC::SmallLoad || AirMassFlow < HVAC::SmallMassFlow ||
9331 0 : state.dataZoneEnergyDemand->CurDeadBandOrSetback(ZoneNum)) {
9332 0 : UnitOn = false;
9333 : }
9334 0 : } else if (thisFurnace.fanOp == HVAC::FanOp::Continuous) {
9335 : // continuous unit: fan runs if scheduled on; coil runs only if there is a cooling or heating load
9336 0 : if (AirMassFlow < HVAC::SmallMassFlow) {
9337 0 : UnitOn = false;
9338 : }
9339 : }
9340 :
9341 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
9342 0 : EconoActive = (AirLoopNum != 0) ? state.dataAirLoop->AirLoopControlInfo(AirLoopNum).EconoActive : false;
9343 :
9344 0 : Real64 SaveMassFlowRate = state.dataLoopNodes->Node(InletNode).MassFlowRate;
9345 : // decide current working mode for IHP
9346 0 : if ((FirstHVACIteration) && (thisFurnace.bIsIHP))
9347 0 : IntegratedHeatPump::DecideWorkMode(state, thisFurnace.CoolingCoilIndex, TotalZoneSensibleLoad, TotalZoneLatentLoad);
9348 :
9349 0 : if (!FirstHVACIteration && thisFurnace.fanOp == HVAC::FanOp::Cycling &&
9350 0 : (QZnReq < (-1.0 * HVAC::SmallLoad) || TotalZoneLatentLoad < (-HVAC::SmallLoad)) && EconoActive) {
9351 : // for cycling fan, cooling load, check whether furnace can meet load with compressor off
9352 0 : compressorOp = HVAC::CompressorOp::Off;
9353 0 : ControlVSHPOutput(state,
9354 : FurnaceNum,
9355 : FirstHVACIteration,
9356 : compressorOp,
9357 : fanOp,
9358 : TotalZoneSensibleLoad,
9359 : TotalZoneLatentLoad,
9360 : SpeedNum,
9361 : SpeedRatio,
9362 : PartLoadFrac,
9363 : OnOffAirFlowRatio,
9364 : SupHeaterLoad);
9365 :
9366 0 : TotalZoneSensibleLoad = QZnReq;
9367 0 : TotalZoneLatentLoad = QLatReq;
9368 :
9369 0 : if (SpeedNum == thisFurnace.NumOfSpeedCooling && SpeedRatio == 1.0) {
9370 : // compressor on (reset inlet air mass flow rate to starting value)
9371 0 : state.dataLoopNodes->Node(InletNode).MassFlowRate = SaveMassFlowRate;
9372 0 : compressorOp = HVAC::CompressorOp::On;
9373 0 : ControlVSHPOutput(state,
9374 : FurnaceNum,
9375 : FirstHVACIteration,
9376 : compressorOp,
9377 : fanOp,
9378 : TotalZoneSensibleLoad,
9379 : TotalZoneLatentLoad,
9380 : SpeedNum,
9381 : SpeedRatio,
9382 : PartLoadFrac,
9383 : OnOffAirFlowRatio,
9384 : SupHeaterLoad);
9385 : }
9386 : } else {
9387 : // compressor on
9388 0 : compressorOp = HVAC::CompressorOp::On;
9389 :
9390 0 : ControlVSHPOutput(state,
9391 : FurnaceNum,
9392 : FirstHVACIteration,
9393 : compressorOp,
9394 : fanOp,
9395 : TotalZoneSensibleLoad,
9396 : TotalZoneLatentLoad,
9397 : SpeedNum,
9398 : SpeedRatio,
9399 : PartLoadFrac,
9400 : OnOffAirFlowRatio,
9401 : SupHeaterLoad);
9402 : }
9403 :
9404 0 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool) {
9405 0 : state.dataFurnaces->SaveCompressorPLR = PartLoadFrac;
9406 : } else {
9407 0 : if (SpeedNum > 1) {
9408 0 : state.dataFurnaces->SaveCompressorPLR = 1.0;
9409 : }
9410 :
9411 0 : if (PartLoadFrac == 1.0 && state.dataFurnaces->SaveCompressorPLR < 1.0) {
9412 0 : PartLoadFrac = state.dataFurnaces->SaveCompressorPLR;
9413 : }
9414 : }
9415 :
9416 0 : Real64 ReheatCoilLoad = 0.0;
9417 0 : TotalZoneSensibleLoad = QZnReq;
9418 0 : TotalZoneLatentLoad = QLatReq;
9419 : // Calculate the reheat coil output
9420 0 : if ((thisFurnace.availSched->getCurrentVal() > 0.0) &&
9421 0 : (thisFurnace.Humidistat && thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat &&
9422 : (QLatReq < 0.0))) { // if a Humidistat is installed and dehumidification control type is CoolReheat
9423 0 : CalcVarSpeedHeatPump(state,
9424 : FurnaceNum,
9425 : FirstHVACIteration,
9426 : compressorOp,
9427 : SpeedNum,
9428 : SpeedRatio,
9429 : PartLoadFrac,
9430 : ActualSensibleOutput,
9431 : QLatUnitOut,
9432 : TotalZoneSensibleLoad,
9433 : TotalZoneLatentLoad,
9434 : OnOffAirFlowRatio,
9435 : ReheatCoilLoad);
9436 0 : if (thisFurnace.ZoneSequenceHeatingNum > 0) {
9437 0 : QToHeatSetPt = (state.dataZoneEnergyDemand->ZoneSysEnergyDemand(thisFurnace.ControlZoneNum)
9438 0 : .SequencedOutputRequiredToHeatingSP(thisFurnace.ZoneSequenceHeatingNum) /
9439 0 : thisFurnace.ControlZoneMassFlowFrac);
9440 : } else {
9441 0 : QToHeatSetPt = (state.dataZoneEnergyDemand->ZoneSysEnergyDemand(thisFurnace.ControlZoneNum).OutputRequiredToHeatingSP /
9442 0 : thisFurnace.ControlZoneMassFlowFrac);
9443 : }
9444 : // Cooling mode or floating condition and dehumidification is required
9445 0 : if (QToHeatSetPt < 0.0) {
9446 : // Calculate the reheat coil load wrt the heating setpoint temperature. Reheat coil picks up
9447 : // the entire excess sensible cooling (DX cooling coil and impact of outdoor air).
9448 0 : ReheatCoilLoad = max(0.0, (QToHeatSetPt - ActualSensibleOutput));
9449 0 : thisFurnace.DehumidInducedHeatingDemandRate = ReheatCoilLoad;
9450 : // Heating mode and dehumidification is required
9451 : } else {
9452 0 : ReheatCoilLoad = max(QToHeatSetPt, QToHeatSetPt - ActualSensibleOutput);
9453 0 : thisFurnace.DehumidInducedHeatingDemandRate = max(0.0, ActualSensibleOutput * (-1.0));
9454 : }
9455 :
9456 0 : SupHeaterLoad = 0.0;
9457 0 : CalcVarSpeedHeatPump(state,
9458 : FurnaceNum,
9459 : FirstHVACIteration,
9460 : compressorOp,
9461 : 1,
9462 : 0.0,
9463 : 0.0,
9464 : NoCompOutput,
9465 : QLatUnitOut,
9466 : 0.0,
9467 : 0.0,
9468 : OnOffAirFlowRatio,
9469 : SupHeaterLoad);
9470 :
9471 0 : if (NoCompOutput > SystemSensibleLoad && SystemSensibleLoad > 0.0 && ReheatCoilLoad > 0.0) {
9472 : // Reduce reheat coil load if you are controlling high humidity but outside air
9473 : // and/or the supply air fan is providing enough heat to meet the system sensible load.
9474 : // This will bring the zone temp closer to the heating setpoint temp.
9475 0 : ReheatCoilLoad = max(0.0, ReheatCoilLoad - (NoCompOutput - SystemSensibleLoad));
9476 : }
9477 : } else {
9478 : // No humidistat installed
9479 0 : ReheatCoilLoad = 0.0;
9480 : }
9481 :
9482 0 : TotalZoneSensibleLoad = QZnReq;
9483 0 : TotalZoneLatentLoad = QLatReq;
9484 0 : if (ReheatCoilLoad > 0.0) {
9485 0 : CalcVarSpeedHeatPump(state,
9486 : FurnaceNum,
9487 : FirstHVACIteration,
9488 : compressorOp,
9489 : SpeedNum,
9490 : SpeedRatio,
9491 : PartLoadFrac,
9492 : QSensUnitOut,
9493 : QLatUnitOut,
9494 : TotalZoneSensibleLoad,
9495 : TotalZoneLatentLoad,
9496 : OnOffAirFlowRatio,
9497 : ReheatCoilLoad);
9498 : } else {
9499 0 : CalcVarSpeedHeatPump(state,
9500 : FurnaceNum,
9501 : FirstHVACIteration,
9502 : compressorOp,
9503 : SpeedNum,
9504 : SpeedRatio,
9505 : PartLoadFrac,
9506 : QSensUnitOut,
9507 : QLatUnitOut,
9508 : TotalZoneSensibleLoad,
9509 : TotalZoneLatentLoad,
9510 : OnOffAirFlowRatio,
9511 : SupHeaterLoad);
9512 : }
9513 :
9514 : // calculate delivered capacity
9515 0 : AirMassFlow = state.dataLoopNodes->Node(InletNode).MassFlowRate;
9516 :
9517 0 : thisFurnace.MdotFurnace = AirMassFlow;
9518 :
9519 0 : QTotUnitOut =
9520 0 : AirMassFlow * (state.dataLoopNodes->Node(OutletNode).Enthalpy - state.dataLoopNodes->Node(thisFurnace.NodeNumOfControlledZone).Enthalpy);
9521 :
9522 0 : state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AirMassFlow;
9523 0 : state.dataLoopNodes->Node(OutletNode).MassFlowRateMaxAvail = AirMassFlow;
9524 :
9525 0 : if (!FirstHVACIteration && AirMassFlow > 0.0 && AirLoopNum > 0) {
9526 0 : int TotBranchNum = state.dataAirSystemsData->PrimaryAirSystems(AirLoopNum).NumOutletBranches;
9527 0 : if (TotBranchNum == 1) {
9528 0 : int ZoneSideNodeNum = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).ZoneEquipSupplyNodeNum(1);
9529 : // THE MASS FLOW PRECISION of the system solver is not enough for some small air flow rate iterations , BY DEBUGGING
9530 : // it may cause mass flow rate oscillations between airloop and zoneequip
9531 : // specify the air flow rate directly for one-to-one system, when the iteration deviation is closing the solver precision level
9532 : // 0.02 is 2 * HVACFlowRateToler, in order to accommodate the system solver precision level
9533 0 : if (std::abs(AirMassFlow - state.dataLoopNodes->Node(ZoneSideNodeNum).MassFlowRate) < 0.02)
9534 0 : state.dataLoopNodes->Node(ZoneSideNodeNum).MassFlowRateMaxAvail = AirMassFlow;
9535 0 : state.dataLoopNodes->Node(ZoneSideNodeNum).MassFlowRate = AirMassFlow;
9536 : }
9537 :
9538 : // the below might be useful if more divergences occur
9539 : // Node(PrimaryAirSystem(AirLoopNumber)%Branch(1)%NodeNumIn)%MassFlowRateMaxAvail = AirMassFlow
9540 : // Node(PrimaryAirSystem(AirLoopNumber)%Branch(1)%NodeNumIn)%MassFlowRate = AirMassFlow
9541 : }
9542 :
9543 : // report variables
9544 0 : thisFurnace.DehumidInducedHeatingDemandRate = ReheatCoilLoad;
9545 0 : if (QZnReq > HVAC::SmallLoad) { // HEATING LOAD
9546 0 : thisFurnace.CoolingCoilSensDemand = 0.0;
9547 0 : thisFurnace.HeatingCoilSensDemand = QZnReq;
9548 : } else {
9549 0 : thisFurnace.CoolingCoilSensDemand = std::abs(QZnReq);
9550 0 : thisFurnace.HeatingCoilSensDemand = 0.0;
9551 : }
9552 :
9553 0 : thisFurnace.CompPartLoadRatio = state.dataFurnaces->SaveCompressorPLR;
9554 0 : if (thisFurnace.fanOp == HVAC::FanOp::Cycling) {
9555 0 : if (SupHeaterLoad > 0.0) {
9556 0 : thisFurnace.FanPartLoadRatio = 1.0;
9557 : } else {
9558 0 : if (SpeedNum < 2) {
9559 0 : thisFurnace.FanPartLoadRatio = PartLoadFrac;
9560 : } else {
9561 0 : thisFurnace.FanPartLoadRatio = 1.0;
9562 : }
9563 : }
9564 : } else {
9565 0 : if (UnitOn) {
9566 0 : thisFurnace.FanPartLoadRatio = 1.0;
9567 : } else {
9568 0 : if (SpeedNum < 2) {
9569 0 : thisFurnace.FanPartLoadRatio = PartLoadFrac;
9570 : } else {
9571 0 : thisFurnace.FanPartLoadRatio = 1.0;
9572 : }
9573 : }
9574 : }
9575 0 : }
9576 :
9577 : //******************************************************************************
9578 :
9579 0 : void ControlVSHPOutput(EnergyPlusData &state,
9580 : int const FurnaceNum, // Unit index of engine driven heat pump
9581 : bool const FirstHVACIteration, // flag for 1st HVAC iteration in the time step
9582 : HVAC::CompressorOp const compressorOp, // compressor operation; 1=on, 0=off
9583 : HVAC::FanOp const fanOp, // operating mode: FanOp::Cycling | FanOp::Continuous
9584 : Real64 &QZnReq, // cooling or heating output needed by zone [W]
9585 : Real64 QLatReq, // latent cooling output needed by zone [W]
9586 : int &SpeedNum, // Speed number
9587 : Real64 &SpeedRatio, // unit speed ratio for DX coils
9588 : Real64 &PartLoadFrac, // unit part load fraction
9589 : Real64 &OnOffAirFlowRatio, // ratio of compressor ON airflow to AVERAGE airflow over timestep
9590 : Real64 &SupHeaterLoad // Supplemental heater load [W]
9591 : )
9592 : {
9593 :
9594 : // SUBROUTINE INFORMATION:
9595 : // AUTHOR Bo Shen, based on HVACMultiSpeedHeatPump:ControlMSHPOutput
9596 : // DATE WRITTEN March, 2012
9597 :
9598 : // PURPOSE OF THIS SUBROUTINE:
9599 : // Determine the part load fraction at low speed, and speed ratio at high speed for this time step.
9600 :
9601 : // METHODOLOGY EMPLOYED:
9602 : // Use RegulaFalsi technique to iterate on part-load ratio until convergence is achieved.
9603 :
9604 : // SUBROUTINE PARAMETER DEFINITIONS:
9605 0 : int constexpr MaxIte(500); // maximum number of iterations
9606 :
9607 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
9608 : Real64 FullOutput; // unit full output when compressor is operating [W]
9609 : Real64 LowOutput; // unit full output at low speed [W]
9610 : Real64 TempOutput; // unit output when iteration limit exceeded [W]
9611 : Real64 NoCompOutput; // output when no active compressor [W]
9612 : int SolFla; // Flag of RegulaFalsi solver
9613 : Real64 QCoilActual; // coil load actually delivered returned to calling component
9614 : int i; // Speed index
9615 0 : IntegratedHeatPump::IHPOperationMode IHPMode(IntegratedHeatPump::IHPOperationMode::Idle);
9616 :
9617 0 : SupHeaterLoad = 0.0;
9618 0 : PartLoadFrac = 0.0;
9619 0 : SpeedRatio = 0.0;
9620 0 : SpeedNum = 1;
9621 0 : Real64 LatOutput = 0.0;
9622 0 : Real64 noLatOutput = 0.0;
9623 0 : Real64 ErrorToler = 0.001; // Error tolerance for convergence from input deck
9624 :
9625 0 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
9626 0 : if (thisFurnace.availSched->getCurrentVal() == 0.0) return;
9627 :
9628 : // Get result when DX coil is off
9629 0 : SupHeaterLoad = 0.0;
9630 0 : CalcVarSpeedHeatPump(state,
9631 : FurnaceNum,
9632 : FirstHVACIteration,
9633 : compressorOp,
9634 : SpeedNum,
9635 : SpeedRatio,
9636 : PartLoadFrac,
9637 : NoCompOutput,
9638 : noLatOutput,
9639 : 0.0,
9640 : 0.0,
9641 : OnOffAirFlowRatio,
9642 : SupHeaterLoad);
9643 :
9644 0 : if (thisFurnace.bIsIHP) {
9645 0 : IHPMode = IntegratedHeatPump::GetCurWorkMode(state, thisFurnace.CoolingCoilIndex);
9646 0 : if ((IntegratedHeatPump::IHPOperationMode::DedicatedWaterHtg == IHPMode) ||
9647 : (IntegratedHeatPump::IHPOperationMode::SCWHMatchWH == IHPMode)) { // cooling capacity is a resultant
9648 0 : return;
9649 : }
9650 : }
9651 :
9652 : // If cooling and NoCompOutput < QZnReq, the coil needs to be off
9653 : // If heating and NoCompOutput > QZnReq, the coil needs to be off
9654 : // If no cooling or heating and no latent load, the coil needs to be off
9655 0 : if (QZnReq < -HVAC::SmallLoad) {
9656 0 : if (NoCompOutput < QZnReq && QLatReq >= -HVAC::SmallLoad) return;
9657 0 : } else if (QZnReq > HVAC::SmallLoad) {
9658 0 : if (NoCompOutput > QZnReq && QLatReq >= -HVAC::SmallLoad) return;
9659 0 : if (QLatReq <= -HVAC::SmallLoad) QZnReq = 0.0; // Zero heating load to allow dehumidification
9660 : } else {
9661 0 : if (QLatReq >= -HVAC::SmallLoad) return;
9662 : }
9663 :
9664 : // Get full load result
9665 0 : PartLoadFrac = 1.0;
9666 0 : SpeedRatio = 1.0;
9667 0 : if (thisFurnace.HeatCoolMode == Furnaces::ModeOfOperation::HeatingMode) {
9668 0 : SpeedNum = thisFurnace.NumOfSpeedHeating;
9669 0 : } else if (thisFurnace.HeatCoolMode == Furnaces::ModeOfOperation::CoolingMode) {
9670 0 : SpeedNum = thisFurnace.NumOfSpeedCooling;
9671 0 : } else if (QLatReq < -HVAC::SmallLoad) {
9672 0 : SpeedNum = thisFurnace.NumOfSpeedCooling;
9673 : } else {
9674 0 : SpeedNum = 1;
9675 0 : PartLoadFrac = 0.0;
9676 : }
9677 :
9678 0 : if (thisFurnace.bIsIHP) SpeedNum = IntegratedHeatPump::GetMaxSpeedNumIHP(state, thisFurnace.CoolingCoilIndex);
9679 :
9680 0 : CalcVarSpeedHeatPump(state,
9681 : FurnaceNum,
9682 : FirstHVACIteration,
9683 : compressorOp,
9684 : SpeedNum,
9685 : SpeedRatio,
9686 : PartLoadFrac,
9687 : FullOutput,
9688 : LatOutput,
9689 : QZnReq,
9690 : QLatReq,
9691 : OnOffAirFlowRatio,
9692 : SupHeaterLoad);
9693 :
9694 0 : if (QLatReq < (-1.0 * HVAC::SmallLoad)) { // dehumidification mode
9695 0 : if (QLatReq <= LatOutput || (QZnReq < -HVAC::SmallLoad && QZnReq <= FullOutput) || (QZnReq > HVAC::SmallLoad && QZnReq >= FullOutput)) {
9696 0 : PartLoadFrac = 1.0;
9697 0 : SpeedRatio = 1.0;
9698 0 : thisFurnace.CompPartLoadRatio = PartLoadFrac;
9699 0 : thisFurnace.CompSpeedRatio = SpeedRatio;
9700 0 : thisFurnace.CompSpeedNum = SpeedNum;
9701 0 : return;
9702 : }
9703 0 : } else if (QZnReq < -HVAC::SmallLoad) {
9704 0 : if (QZnReq <= FullOutput) {
9705 0 : PartLoadFrac = 1.0;
9706 0 : SpeedRatio = 1.0;
9707 0 : thisFurnace.CompPartLoadRatio = PartLoadFrac;
9708 0 : thisFurnace.CompSpeedRatio = SpeedRatio;
9709 0 : thisFurnace.CompSpeedNum = SpeedNum;
9710 0 : return;
9711 : }
9712 : } else {
9713 0 : if (QZnReq >= FullOutput) {
9714 0 : PartLoadFrac = 1.0;
9715 0 : SpeedRatio = 1.0;
9716 : // may need supplemental heating so don't return in heating mode
9717 : }
9718 : }
9719 :
9720 0 : if ((QZnReq < -HVAC::SmallLoad && NoCompOutput - QZnReq > HVAC::SmallLoad) ||
9721 0 : (QZnReq > HVAC::SmallLoad && QZnReq - NoCompOutput > HVAC::SmallLoad)) {
9722 0 : if ((QZnReq > HVAC::SmallLoad && QZnReq < FullOutput) || (QZnReq < (-1.0 * HVAC::SmallLoad) && QZnReq > FullOutput)) {
9723 : // Check whether the low speed coil can meet the load or not
9724 0 : CalcVarSpeedHeatPump(state,
9725 : FurnaceNum,
9726 : FirstHVACIteration,
9727 : compressorOp,
9728 : 1,
9729 : 0.0,
9730 : 1.0,
9731 : LowOutput,
9732 : LatOutput,
9733 : QZnReq,
9734 : QLatReq,
9735 : OnOffAirFlowRatio,
9736 : SupHeaterLoad);
9737 0 : if ((QZnReq > HVAC::SmallLoad && QZnReq <= LowOutput) || (QZnReq < (-HVAC::SmallLoad) && QZnReq >= LowOutput)) {
9738 : // Calculate the part load fraction
9739 0 : SpeedRatio = 0.0;
9740 0 : SpeedNum = 1;
9741 : auto f = // (AUTO_OK_LAMBDA)
9742 0 : [&state, FurnaceNum, FirstHVACIteration, QZnReq, OnOffAirFlowRatio, SupHeaterLoad, compressorOp](Real64 const PartLoadFrac) {
9743 0 : return VSHPCyclingResidual(
9744 0 : state, PartLoadFrac, FurnaceNum, FirstHVACIteration, QZnReq, OnOffAirFlowRatio, SupHeaterLoad, compressorOp, 1.0);
9745 0 : };
9746 0 : General::SolveRoot(state, ErrorToler, MaxIte, SolFla, PartLoadFrac, f, 0.0, 1.0);
9747 0 : if (SolFla == -1) {
9748 0 : if (!state.dataGlobal->WarmupFlag) {
9749 0 : if (thisFurnace.ErrCountCyc == 0) {
9750 0 : ++thisFurnace.ErrCountCyc;
9751 0 : ShowWarningError(
9752 0 : state, format("Iteration limit exceeded calculating VS WSHP unit cycling ratio, for unit={}", thisFurnace.Name));
9753 0 : ShowContinueErrorTimeStamp(state, format("Cycling ratio returned={:.2R}", PartLoadFrac));
9754 : } else {
9755 0 : ShowRecurringWarningErrorAtEnd(
9756 : state,
9757 0 : thisFurnace.Name + "\": Iteration limit warning exceeding calculating DX unit cycling ratio continues...",
9758 0 : thisFurnace.ErrIndexCyc,
9759 : PartLoadFrac,
9760 : PartLoadFrac);
9761 : }
9762 : }
9763 0 : } else if (SolFla == -2) {
9764 0 : ShowFatalError(
9765 0 : state, format("VS WSHP unit cycling ratio calculation failed: cycling limits exceeded, for unit={}", thisFurnace.Name));
9766 : }
9767 0 : } else {
9768 : // Check to see which speed to meet the load
9769 0 : PartLoadFrac = 1.0;
9770 0 : SpeedRatio = 1.0;
9771 0 : if (QZnReq < -HVAC::SmallLoad) { // Cooling
9772 0 : for (i = 2; i <= thisFurnace.NumOfSpeedCooling; ++i) {
9773 0 : CalcVarSpeedHeatPump(state,
9774 : FurnaceNum,
9775 : FirstHVACIteration,
9776 : compressorOp,
9777 : i,
9778 : SpeedRatio,
9779 : PartLoadFrac,
9780 : TempOutput,
9781 : LatOutput,
9782 : QZnReq,
9783 : QLatReq,
9784 : OnOffAirFlowRatio,
9785 : SupHeaterLoad);
9786 :
9787 0 : if (QZnReq >= TempOutput) {
9788 0 : SpeedNum = i;
9789 0 : break;
9790 : }
9791 : }
9792 : } else {
9793 0 : for (i = 2; i <= thisFurnace.NumOfSpeedHeating; ++i) {
9794 0 : CalcVarSpeedHeatPump(state,
9795 : FurnaceNum,
9796 : FirstHVACIteration,
9797 : compressorOp,
9798 : i,
9799 : SpeedRatio,
9800 : PartLoadFrac,
9801 : TempOutput,
9802 : LatOutput,
9803 : QZnReq,
9804 : QLatReq,
9805 : OnOffAirFlowRatio,
9806 : SupHeaterLoad);
9807 0 : if (QZnReq <= TempOutput) {
9808 0 : SpeedNum = i;
9809 0 : break;
9810 : }
9811 : }
9812 : }
9813 0 : auto f = [&state, FurnaceNum, FirstHVACIteration, QZnReq, OnOffAirFlowRatio, SupHeaterLoad, SpeedNum, compressorOp](
9814 : Real64 const SpeedRatio) {
9815 0 : return VSHPSpeedResidual(
9816 0 : state, SpeedRatio, FurnaceNum, FirstHVACIteration, QZnReq, OnOffAirFlowRatio, SupHeaterLoad, SpeedNum, compressorOp, 1.0);
9817 0 : };
9818 0 : General::SolveRoot(state, ErrorToler, MaxIte, SolFla, SpeedRatio, f, 1.0e-10, 1.0);
9819 0 : if (SolFla == -1) {
9820 0 : if (!state.dataGlobal->WarmupFlag) {
9821 0 : if (thisFurnace.ErrCountVar == 0) {
9822 0 : ++thisFurnace.ErrCountVar;
9823 0 : ShowWarningError(
9824 0 : state, format("Iteration limit exceeded calculating VS WSHP unit speed ratio, for unit={}", thisFurnace.Name));
9825 0 : ShowContinueErrorTimeStamp(state, format("Speed ratio returned=[{:.2R}], Speed number ={}", SpeedRatio, SpeedNum));
9826 : } else {
9827 0 : ShowRecurringWarningErrorAtEnd(
9828 : state,
9829 0 : thisFurnace.Name + "\": Iteration limit warning exceeding calculating DX unit speed ratio continues...",
9830 0 : thisFurnace.ErrIndexVar,
9831 : SpeedRatio,
9832 : SpeedRatio);
9833 : }
9834 : }
9835 0 : } else if (SolFla == -2) {
9836 0 : ShowFatalError(
9837 0 : state, format("VS WSHP unit compressor speed calculation failed: speed limits exceeded, for unit={}", thisFurnace.Name));
9838 : }
9839 : }
9840 0 : } else {
9841 0 : LatOutput = noLatOutput; // reset full output if not needed for sensible load
9842 0 : SpeedNum = 1; // reset speed from full output test
9843 : }
9844 0 : } else {
9845 0 : LatOutput = noLatOutput; // reset full output if not needed for sensible load
9846 0 : SpeedNum = 1; // reset speed from full output test
9847 : }
9848 : // meet the latent load
9849 0 : if (QLatReq < -HVAC::SmallLoad && QLatReq < LatOutput) {
9850 0 : PartLoadFrac = 1.0;
9851 0 : SpeedRatio = 1.0;
9852 0 : for (i = SpeedNum; i <= thisFurnace.NumOfSpeedCooling; ++i) {
9853 0 : CalcVarSpeedHeatPump(state,
9854 : FurnaceNum,
9855 : FirstHVACIteration,
9856 : compressorOp,
9857 : i,
9858 : SpeedRatio,
9859 : PartLoadFrac,
9860 : TempOutput,
9861 : LatOutput,
9862 : QZnReq,
9863 : QLatReq,
9864 : OnOffAirFlowRatio,
9865 : SupHeaterLoad);
9866 :
9867 0 : if (QLatReq > LatOutput) {
9868 0 : SpeedNum = i;
9869 0 : break;
9870 : }
9871 : }
9872 0 : if (QLatReq - LatOutput > HVAC::SmallLoad) {
9873 0 : if (SpeedNum < 2) {
9874 : auto f = // (AUTO_OK_LAMBDA)
9875 0 : [&state, FurnaceNum, FirstHVACIteration, QLatReq, OnOffAirFlowRatio, SupHeaterLoad, compressorOp](Real64 const PartLoadFrac) {
9876 0 : return VSHPCyclingResidual(
9877 0 : state, PartLoadFrac, FurnaceNum, FirstHVACIteration, QLatReq, OnOffAirFlowRatio, SupHeaterLoad, compressorOp, 0.0);
9878 0 : };
9879 0 : General::SolveRoot(state, ErrorToler, MaxIte, SolFla, PartLoadFrac, f, 0.0, 1.0);
9880 : } else {
9881 0 : auto f = [&state, FurnaceNum, FirstHVACIteration, QLatReq, OnOffAirFlowRatio, SupHeaterLoad, SpeedNum, compressorOp](
9882 : Real64 const SpeedRatio) {
9883 0 : return VSHPSpeedResidual(state,
9884 : SpeedRatio,
9885 : FurnaceNum,
9886 : FirstHVACIteration,
9887 : QLatReq,
9888 : OnOffAirFlowRatio,
9889 : SupHeaterLoad,
9890 : SpeedNum,
9891 : compressorOp,
9892 0 : 0.0);
9893 0 : };
9894 0 : General::SolveRoot(state, ErrorToler, MaxIte, SolFla, SpeedRatio, f, 1.0e-10, 1.0);
9895 : }
9896 0 : if (SolFla == -1) {
9897 0 : if (!state.dataGlobal->WarmupFlag) {
9898 0 : if (thisFurnace.ErrCountVar2 == 0) {
9899 0 : ++thisFurnace.ErrCountVar2;
9900 0 : ShowWarningError(state,
9901 0 : format("Iteration limit exceeded calculating VS WSHP unit speed ratio, for unit={}", thisFurnace.Name));
9902 0 : ShowContinueErrorTimeStamp(state, format("Speed ratio returned=[{:.2R}], Speed number ={}", SpeedRatio, SpeedNum));
9903 : } else {
9904 0 : ShowRecurringWarningErrorAtEnd(state,
9905 0 : thisFurnace.Name +
9906 : "\": Iteration limit warning exceeding calculating DX unit speed ratio continues...",
9907 0 : thisFurnace.ErrIndexVar,
9908 : SpeedRatio,
9909 : SpeedRatio);
9910 : }
9911 : }
9912 0 : } else if (SolFla == -2) {
9913 0 : ShowFatalError(state,
9914 0 : format("VS WSHP unit compressor speed calculation failed: speed limits exceeded, for unit={}", thisFurnace.Name));
9915 : }
9916 : }
9917 : }
9918 : // end meet the latent load
9919 :
9920 : // if the heating coil cannot meet the load, trim with supplemental heater
9921 : // occurs with constant fan mode when compressor is on or off
9922 : // occurs with cycling fan mode when compressor PLR is equal to 1
9923 0 : if ((QZnReq > HVAC::SmallLoad && QZnReq > FullOutput) && (thisFurnace.SuppHeatCoilIndex != 0)) {
9924 0 : PartLoadFrac = 1.0;
9925 0 : SpeedRatio = 1.0;
9926 0 : if (thisFurnace.NumOfSpeedHeating > 0)
9927 0 : SpeedNum = thisFurnace.NumOfSpeedHeating; // maximum heating speed, avoid zero for cooling only mode
9928 :
9929 0 : if (state.dataEnvrn->OutDryBulbTemp <= thisFurnace.MaxOATSuppHeat) {
9930 0 : SupHeaterLoad = QZnReq - FullOutput;
9931 : } else {
9932 0 : SupHeaterLoad = 0.0;
9933 : }
9934 0 : CalcVarSpeedHeatPump(state,
9935 : FurnaceNum,
9936 : FirstHVACIteration,
9937 : compressorOp,
9938 : SpeedNum,
9939 : SpeedRatio,
9940 : PartLoadFrac,
9941 : TempOutput,
9942 : LatOutput,
9943 : QZnReq,
9944 : QLatReq,
9945 : OnOffAirFlowRatio,
9946 : SupHeaterLoad);
9947 : }
9948 :
9949 : // check the outlet of the supplemental heater to be lower than the maximum supplemental heater supply air temperature
9950 0 : if (state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum).Temp > thisFurnace.DesignMaxOutletTemp && SupHeaterLoad > 0.0) {
9951 :
9952 : // If the supply air temperature is to high, turn off the supplemental heater to recalculate the outlet temperature
9953 0 : CalcNonDXHeatingCoils(state, FurnaceNum, true, FirstHVACIteration, 0.0, fanOp, QCoilActual);
9954 : // If the outlet temperature is below the maximum supplemental heater supply air temperature, reduce the load passed to
9955 : // the supplemental heater, otherwise leave the supplemental heater off. If the supplemental heater is to be turned on,
9956 : // use the outlet conditions when the supplemental heater was off (CALL above) as the inlet conditions for the calculation
9957 : // of supplemental heater load to just meet the maximum supply air temperature from the supplemental heater.
9958 0 : if (state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum).Temp < thisFurnace.DesignMaxOutletTemp) {
9959 0 : Real64 CpAir = Psychrometrics::PsyCpAirFnW(state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum).HumRat);
9960 0 : SupHeaterLoad = state.dataLoopNodes->Node(thisFurnace.FurnaceInletNodeNum).MassFlowRate * CpAir *
9961 0 : (thisFurnace.DesignMaxOutletTemp - state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum).Temp);
9962 :
9963 : } else {
9964 0 : SupHeaterLoad = 0.0;
9965 : }
9966 : }
9967 :
9968 : // prepare module level output
9969 0 : thisFurnace.CompPartLoadRatio = PartLoadFrac;
9970 0 : thisFurnace.CompSpeedRatio = SpeedRatio;
9971 0 : thisFurnace.CompSpeedNum = SpeedNum;
9972 0 : thisFurnace.CoolingCoilLatentDemand = std::abs(QLatReq);
9973 :
9974 0 : if (thisFurnace.fanOp == HVAC::FanOp::Continuous) {
9975 0 : thisFurnace.FanPartLoadRatio = 1.0;
9976 : } else {
9977 0 : thisFurnace.FanPartLoadRatio = PartLoadFrac;
9978 : }
9979 : }
9980 :
9981 : //******************************************************************************
9982 :
9983 0 : void CalcVarSpeedHeatPump(EnergyPlusData &state,
9984 : int const FurnaceNum, // Variable speed heat pump number
9985 : bool const FirstHVACIteration, // Flag for 1st HVAC iteration
9986 : HVAC::CompressorOp const compressorOp, // Compressor on/off; 1=on, 0=off
9987 : int const SpeedNum, // Speed number
9988 : Real64 const SpeedRatio, // Compressor speed ratio
9989 : Real64 const PartLoadFrac, // Compressor part load fraction
9990 : Real64 &SensibleLoadMet, // Sensible cooling load met (furnace outlet with respect to control zone temp)
9991 : Real64 &LatentLoadMet, // Latent cooling load met (furnace outlet with respect to control zone humidity ratio)
9992 : Real64 const QZnReq, // Zone load (W)
9993 : Real64 const QLatReq, // Zone latent load []
9994 : Real64 &OnOffAirFlowRatio, // Ratio of compressor ON airflow to AVERAGE airflow over timestep
9995 : Real64 const SupHeaterLoad // supplemental heater load (W)
9996 : )
9997 : {
9998 : // SUBROUTINE INFORMATION:
9999 : // AUTHOR: Bo Shen, based on HVACMultiSpeedHeatPump:CalcMSHeatPump
10000 : // DATE WRITTEN: March 2012
10001 :
10002 : // PURPOSE OF THIS SUBROUTINE:
10003 : // This routine will calculates MSHP performance based on given system load
10004 :
10005 0 : Real64 SavePartloadRatio = 0.0; // part-load ratio
10006 0 : Real64 SaveSpeedRatio = 0.0; // speed ratio
10007 0 : Real64 QCoilActual = 0.0; // coil load actually delivered returned to calling component
10008 0 : Real64 HeatCoilLoad = 0.0; // required heating coil load
10009 :
10010 0 : state.dataFurnaces->SaveCompressorPLR = 0.0;
10011 :
10012 : // Set inlet air mass flow rate based on PLR and compressor on/off air flow rates
10013 0 : SetVSHPAirFlow(state, FurnaceNum, PartLoadFrac, OnOffAirFlowRatio, SpeedNum, SpeedRatio);
10014 :
10015 0 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
10016 :
10017 0 : if ((SupHeaterLoad > 1.0e-10) && (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool) && (thisFurnace.SuppHeatCoilIndex == 0)) {
10018 : // ONLY HEATING COIL, NO SUPPLEMENTAL COIL, USED FOR REHEAT DURING DUHMI
10019 0 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity * PartLoadFrac; // REHEAT IN FAN ON TIME
10020 :
10021 0 : if (HeatCoilLoad > SupHeaterLoad) HeatCoilLoad = SupHeaterLoad; // HEATING COIL RUN TIME < FAN ON TIME
10022 :
10023 0 : } else if ((QZnReq > HVAC::SmallLoad) && (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool)) {
10024 0 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity * PartLoadFrac;
10025 : } else {
10026 0 : HeatCoilLoad = 0.0;
10027 : }
10028 :
10029 0 : Real64 AirMassFlow = state.dataLoopNodes->Node(thisFurnace.FurnaceInletNodeNum).MassFlowRate;
10030 : // if blow through, simulate fan then coils
10031 0 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
10032 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
10033 :
10034 0 : if ((!thisFurnace.CoolingCoilUpstream) && (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool)) {
10035 : // simulate thisFurnace heating coil
10036 0 : bool SuppHeatingCoilFlag = false; // if true simulates supplemental heating coil
10037 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, thisFurnace.fanOp, QCoilActual);
10038 : }
10039 :
10040 0 : if ((QZnReq < -HVAC::SmallLoad || (QLatReq < -HVAC::SmallLoad)) &&
10041 0 : (state.dataEnvrn->OutDryBulbTemp >= thisFurnace.MinOATCompressorCooling)) { // COOLING MODE or dehumidification mode
10042 :
10043 0 : if (thisFurnace.bIsIHP) {
10044 0 : IntegratedHeatPump::SimIHP(state,
10045 : BlankString,
10046 0 : thisFurnace.CoolingCoilIndex,
10047 : thisFurnace.fanOp,
10048 : compressorOp,
10049 : PartLoadFrac,
10050 : SpeedNum,
10051 : SpeedRatio,
10052 : QZnReq,
10053 : QLatReq,
10054 : false,
10055 : false,
10056 : OnOffAirFlowRatio);
10057 : } else {
10058 0 : VariableSpeedCoils::SimVariableSpeedCoils(state,
10059 : BlankString,
10060 0 : thisFurnace.CoolingCoilIndex,
10061 : thisFurnace.fanOp,
10062 : compressorOp,
10063 : PartLoadFrac,
10064 : SpeedNum,
10065 : SpeedRatio,
10066 : QZnReq,
10067 : QLatReq,
10068 : OnOffAirFlowRatio);
10069 : }
10070 :
10071 0 : SavePartloadRatio = PartLoadFrac;
10072 0 : SaveSpeedRatio = SpeedRatio;
10073 :
10074 0 : state.dataFurnaces->SaveCompressorPLR = state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.CoolingCoilIndex).PartLoadRatio;
10075 : } else {
10076 0 : if (thisFurnace.bIsIHP) {
10077 0 : IntegratedHeatPump::SimIHP(state,
10078 : BlankString,
10079 0 : thisFurnace.CoolingCoilIndex,
10080 : thisFurnace.fanOp,
10081 : compressorOp,
10082 : PartLoadFrac,
10083 : SpeedNum,
10084 : SpeedRatio,
10085 : QZnReq,
10086 : QLatReq,
10087 : false,
10088 : false,
10089 : OnOffAirFlowRatio);
10090 : } else {
10091 0 : VariableSpeedCoils::SimVariableSpeedCoils(
10092 0 : state, BlankString, thisFurnace.CoolingCoilIndex, thisFurnace.fanOp, compressorOp, 0.0, 1, 0.0, 0.0, 0.0, OnOffAirFlowRatio);
10093 : }
10094 : }
10095 :
10096 0 : if (thisFurnace.type != HVAC::UnitarySysType::Unitary_HeatCool) {
10097 0 : if ((QZnReq > HVAC::SmallLoad) && state.dataFurnaces->HeatingLoad) {
10098 0 : if (thisFurnace.bIsIHP) {
10099 0 : IntegratedHeatPump::SimIHP(state,
10100 : BlankString,
10101 0 : thisFurnace.HeatingCoilIndex,
10102 : thisFurnace.fanOp,
10103 : compressorOp,
10104 : PartLoadFrac,
10105 : SpeedNum,
10106 : SpeedRatio,
10107 : QZnReq,
10108 : QLatReq,
10109 : false,
10110 : false,
10111 : OnOffAirFlowRatio);
10112 : } else {
10113 0 : VariableSpeedCoils::SimVariableSpeedCoils(state,
10114 : BlankString,
10115 0 : thisFurnace.HeatingCoilIndex,
10116 : thisFurnace.fanOp,
10117 : compressorOp,
10118 : PartLoadFrac,
10119 : SpeedNum,
10120 : SpeedRatio,
10121 : QZnReq,
10122 : QLatReq,
10123 : OnOffAirFlowRatio);
10124 : }
10125 :
10126 0 : SavePartloadRatio = PartLoadFrac;
10127 0 : SaveSpeedRatio = SpeedRatio;
10128 :
10129 0 : state.dataFurnaces->SaveCompressorPLR = state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.HeatingCoilIndex).PartLoadRatio;
10130 : } else {
10131 0 : if (thisFurnace.bIsIHP) {
10132 0 : IntegratedHeatPump::SimIHP(state,
10133 : BlankString,
10134 0 : thisFurnace.CoolingCoilIndex,
10135 : thisFurnace.fanOp,
10136 : compressorOp,
10137 : PartLoadFrac,
10138 : SpeedNum,
10139 : SpeedRatio,
10140 : QZnReq,
10141 : QLatReq,
10142 : false,
10143 : false,
10144 : OnOffAirFlowRatio);
10145 : } else {
10146 0 : VariableSpeedCoils::SimVariableSpeedCoils(state,
10147 : BlankString,
10148 0 : thisFurnace.HeatingCoilIndex,
10149 : thisFurnace.fanOp,
10150 : compressorOp,
10151 : 0.0,
10152 : 1,
10153 : 0.0,
10154 : 0.0,
10155 : 0.0,
10156 : OnOffAirFlowRatio);
10157 : }
10158 : }
10159 0 : } else if (thisFurnace.CoolingCoilUpstream && (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool)) {
10160 : // simulate thisFurnace heating coil
10161 0 : bool SuppHeatingCoilFlag = false; // if true simulates supplemental heating coil
10162 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, thisFurnace.fanOp, QCoilActual);
10163 : }
10164 :
10165 : // Call twice to ensure the fan outlet conditions are updated
10166 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
10167 :
10168 0 : if ((!thisFurnace.CoolingCoilUpstream) && (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool)) {
10169 : // simulate thisFurnace heating coil
10170 0 : bool SuppHeatingCoilFlag = false; // if true simulates supplemental heating coil
10171 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, thisFurnace.fanOp, QCoilActual);
10172 : }
10173 :
10174 0 : if ((QZnReq < -HVAC::SmallLoad || (QLatReq < -HVAC::SmallLoad)) &&
10175 0 : (state.dataEnvrn->OutDryBulbTemp >= thisFurnace.MinOATCompressorCooling)) {
10176 :
10177 0 : if (thisFurnace.bIsIHP) {
10178 0 : IntegratedHeatPump::SimIHP(state,
10179 : BlankString,
10180 0 : thisFurnace.CoolingCoilIndex,
10181 : thisFurnace.fanOp,
10182 : compressorOp,
10183 : PartLoadFrac,
10184 : SpeedNum,
10185 : SpeedRatio,
10186 : QZnReq,
10187 : QLatReq,
10188 : false,
10189 : false,
10190 : OnOffAirFlowRatio);
10191 : } else {
10192 0 : VariableSpeedCoils::SimVariableSpeedCoils(state,
10193 : BlankString,
10194 0 : thisFurnace.CoolingCoilIndex,
10195 : thisFurnace.fanOp,
10196 : compressorOp,
10197 : PartLoadFrac,
10198 : SpeedNum,
10199 : SpeedRatio,
10200 : QZnReq,
10201 : QLatReq,
10202 : OnOffAirFlowRatio);
10203 : }
10204 :
10205 0 : SavePartloadRatio = PartLoadFrac;
10206 0 : SaveSpeedRatio = SpeedRatio;
10207 0 : state.dataFurnaces->SaveCompressorPLR = state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.CoolingCoilIndex).PartLoadRatio;
10208 : } else {
10209 :
10210 0 : if (thisFurnace.bIsIHP) {
10211 0 : IntegratedHeatPump::SimIHP(state,
10212 : BlankString,
10213 0 : thisFurnace.CoolingCoilIndex,
10214 : thisFurnace.fanOp,
10215 : compressorOp,
10216 : PartLoadFrac,
10217 : SpeedNum,
10218 : SpeedRatio,
10219 : QZnReq,
10220 : QLatReq,
10221 : false,
10222 : false,
10223 : OnOffAirFlowRatio);
10224 : } else {
10225 0 : VariableSpeedCoils::SimVariableSpeedCoils(
10226 0 : state, BlankString, thisFurnace.CoolingCoilIndex, thisFurnace.fanOp, compressorOp, 0.0, 1, 0.0, 0.0, 0.0, OnOffAirFlowRatio);
10227 : }
10228 : }
10229 :
10230 0 : if (thisFurnace.type != HVAC::UnitarySysType::Unitary_HeatCool) {
10231 0 : if ((QZnReq > HVAC::SmallLoad) && state.dataFurnaces->HeatingLoad) {
10232 0 : if (thisFurnace.bIsIHP) {
10233 0 : IntegratedHeatPump::SimIHP(state,
10234 : BlankString,
10235 0 : thisFurnace.HeatingCoilIndex,
10236 : thisFurnace.fanOp,
10237 : compressorOp,
10238 : PartLoadFrac,
10239 : SpeedNum,
10240 : SpeedRatio,
10241 : QZnReq,
10242 : QLatReq,
10243 : false,
10244 : false,
10245 : OnOffAirFlowRatio);
10246 : } else {
10247 0 : VariableSpeedCoils::SimVariableSpeedCoils(state,
10248 : BlankString,
10249 0 : thisFurnace.HeatingCoilIndex,
10250 : thisFurnace.fanOp,
10251 : compressorOp,
10252 : PartLoadFrac,
10253 : SpeedNum,
10254 : SpeedRatio,
10255 : QZnReq,
10256 : QLatReq,
10257 : OnOffAirFlowRatio);
10258 : }
10259 :
10260 0 : SavePartloadRatio = PartLoadFrac;
10261 0 : SaveSpeedRatio = SpeedRatio;
10262 0 : state.dataFurnaces->SaveCompressorPLR = state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.HeatingCoilIndex).PartLoadRatio;
10263 : } else {
10264 0 : if (thisFurnace.bIsIHP) {
10265 0 : IntegratedHeatPump::SimIHP(state,
10266 : BlankString,
10267 0 : thisFurnace.CoolingCoilIndex,
10268 : thisFurnace.fanOp,
10269 : compressorOp,
10270 : PartLoadFrac,
10271 : SpeedNum,
10272 : SpeedRatio,
10273 : QZnReq,
10274 : QLatReq,
10275 : false,
10276 : false,
10277 : OnOffAirFlowRatio);
10278 : } else {
10279 0 : VariableSpeedCoils::SimVariableSpeedCoils(state,
10280 : BlankString,
10281 0 : thisFurnace.HeatingCoilIndex,
10282 : thisFurnace.fanOp,
10283 : compressorOp,
10284 : 0.0,
10285 : 1,
10286 : 0.0,
10287 : 0.0,
10288 : 0.0,
10289 : OnOffAirFlowRatio);
10290 : }
10291 : }
10292 0 : } else if (thisFurnace.CoolingCoilUpstream && (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool)) {
10293 : // simulate thisFurnace heating coil
10294 0 : bool SuppHeatingCoilFlag = false; // if true simulates supplemental heating coil
10295 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, thisFurnace.fanOp, QCoilActual);
10296 : }
10297 :
10298 : // Simulate supplemental heating coil for blow through fan
10299 0 : if (thisFurnace.SuppHeatCoilIndex > 0) {
10300 0 : bool SuppHeatingCoilFlag = true; // if true simulates supplemental heating coil
10301 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, SupHeaterLoad, thisFurnace.fanOp, QCoilActual);
10302 : }
10303 : } else { // otherwise simulate DX coils then fan then supplemental heater
10304 :
10305 0 : if ((!thisFurnace.CoolingCoilUpstream) && (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool)) {
10306 : // simulate thisFurnace heating coil
10307 0 : bool SuppHeatingCoilFlag = false; // if true simulates supplemental heating coil
10308 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, thisFurnace.fanOp, QCoilActual);
10309 : }
10310 :
10311 0 : if ((QZnReq < -HVAC::SmallLoad || (QLatReq < -HVAC::SmallLoad)) &&
10312 0 : (state.dataEnvrn->OutDryBulbTemp >= thisFurnace.MinOATCompressorCooling)) {
10313 :
10314 0 : if (thisFurnace.bIsIHP) {
10315 0 : IntegratedHeatPump::SimIHP(state,
10316 : BlankString,
10317 0 : thisFurnace.CoolingCoilIndex,
10318 : thisFurnace.fanOp,
10319 : compressorOp,
10320 : PartLoadFrac,
10321 : SpeedNum,
10322 : SpeedRatio,
10323 : QZnReq,
10324 : QLatReq,
10325 : false,
10326 : false,
10327 : OnOffAirFlowRatio);
10328 : } else {
10329 0 : VariableSpeedCoils::SimVariableSpeedCoils(state,
10330 : BlankString,
10331 0 : thisFurnace.CoolingCoilIndex,
10332 : thisFurnace.fanOp,
10333 : compressorOp,
10334 : PartLoadFrac,
10335 : SpeedNum,
10336 : SpeedRatio,
10337 : QZnReq,
10338 : QLatReq,
10339 : OnOffAirFlowRatio);
10340 : }
10341 :
10342 0 : SavePartloadRatio = PartLoadFrac;
10343 0 : SaveSpeedRatio = SpeedRatio;
10344 :
10345 0 : state.dataFurnaces->SaveCompressorPLR = state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.CoolingCoilIndex).PartLoadRatio;
10346 : } else {
10347 0 : if (thisFurnace.bIsIHP) {
10348 0 : IntegratedHeatPump::SimIHP(state,
10349 : BlankString,
10350 0 : thisFurnace.CoolingCoilIndex,
10351 : thisFurnace.fanOp,
10352 : compressorOp,
10353 : PartLoadFrac,
10354 : SpeedNum,
10355 : SpeedRatio,
10356 : QZnReq,
10357 : QLatReq,
10358 : false,
10359 : false,
10360 : OnOffAirFlowRatio);
10361 : } else {
10362 0 : VariableSpeedCoils::SimVariableSpeedCoils(
10363 0 : state, BlankString, thisFurnace.CoolingCoilIndex, thisFurnace.fanOp, compressorOp, 0.0, 1, 0.0, 0.0, 0.0, OnOffAirFlowRatio);
10364 : }
10365 : }
10366 :
10367 0 : if (thisFurnace.type != HVAC::UnitarySysType::Unitary_HeatCool) {
10368 0 : if (QZnReq > HVAC::SmallLoad && (state.dataEnvrn->OutDryBulbTemp >= thisFurnace.MinOATCompressorCooling)) {
10369 :
10370 0 : if (thisFurnace.bIsIHP) {
10371 0 : IntegratedHeatPump::SimIHP(state,
10372 : BlankString,
10373 0 : thisFurnace.HeatingCoilIndex,
10374 : thisFurnace.fanOp,
10375 : compressorOp,
10376 : PartLoadFrac,
10377 : SpeedNum,
10378 : SpeedRatio,
10379 : QZnReq,
10380 : QLatReq,
10381 : false,
10382 : false,
10383 : OnOffAirFlowRatio);
10384 : } else {
10385 0 : VariableSpeedCoils::SimVariableSpeedCoils(state,
10386 : BlankString,
10387 0 : thisFurnace.HeatingCoilIndex,
10388 : thisFurnace.fanOp,
10389 : compressorOp,
10390 : PartLoadFrac,
10391 : SpeedNum,
10392 : SpeedRatio,
10393 : QZnReq,
10394 : QLatReq,
10395 : OnOffAirFlowRatio);
10396 : }
10397 :
10398 0 : SavePartloadRatio = PartLoadFrac;
10399 0 : SaveSpeedRatio = SpeedRatio;
10400 0 : state.dataFurnaces->SaveCompressorPLR = state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.HeatingCoilIndex).PartLoadRatio;
10401 : } else {
10402 0 : if (thisFurnace.bIsIHP) {
10403 0 : IntegratedHeatPump::SimIHP(state,
10404 : BlankString,
10405 0 : thisFurnace.CoolingCoilIndex,
10406 : thisFurnace.fanOp,
10407 : compressorOp,
10408 : PartLoadFrac,
10409 : SpeedNum,
10410 : SpeedRatio,
10411 : QZnReq,
10412 : QLatReq,
10413 : false,
10414 : false,
10415 : OnOffAirFlowRatio);
10416 : } else {
10417 0 : VariableSpeedCoils::SimVariableSpeedCoils(state,
10418 : BlankString,
10419 0 : thisFurnace.HeatingCoilIndex,
10420 : thisFurnace.fanOp,
10421 : compressorOp,
10422 : 0.0,
10423 : 1,
10424 : 0.0,
10425 : 0.0,
10426 : 0.0,
10427 : OnOffAirFlowRatio);
10428 : }
10429 : }
10430 0 : } else if (thisFurnace.CoolingCoilUpstream && (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool)) {
10431 : // simulate thisFurnace heating coil
10432 0 : bool SuppHeatingCoilFlag = false; // if true simulates supplemental heating coil
10433 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, thisFurnace.fanOp, QCoilActual);
10434 : }
10435 :
10436 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
10437 : // Simulate supplemental heating coil for draw through fan
10438 0 : if (thisFurnace.SuppHeatCoilIndex > 0) {
10439 0 : bool SuppHeatingCoilFlag = true; // if true simulates supplemental heating coil
10440 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, SupHeaterLoad, thisFurnace.fanOp, QCoilActual);
10441 : }
10442 : }
10443 :
10444 : // If the fan runs continually do not allow coils to set OnOffFanPartLoadRatio.
10445 0 : if (thisFurnace.fanOp == HVAC::FanOp::Continuous) state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
10446 :
10447 0 : auto &outNode = state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum);
10448 0 : auto &zoneNode = state.dataLoopNodes->Node(thisFurnace.NodeNumOfControlledZone);
10449 0 : Real64 zoneEnthalpy = Psychrometrics::PsyHFnTdbW(zoneNode.Temp, zoneNode.HumRat);
10450 0 : Real64 outletEnthalpy = Psychrometrics::PsyHFnTdbW(outNode.Temp, outNode.HumRat);
10451 0 : Real64 totalLoadMet = AirMassFlow * (outletEnthalpy - zoneEnthalpy);
10452 0 : SensibleLoadMet =
10453 0 : AirMassFlow * Psychrometrics::PsyDeltaHSenFnTdb2W2Tdb1W1(outNode.Temp, outNode.HumRat, zoneNode.Temp, zoneNode.HumRat); // sensible {W};
10454 0 : LatentLoadMet = totalLoadMet - SensibleLoadMet;
10455 0 : thisFurnace.LatentLoadMet = LatentLoadMet;
10456 0 : }
10457 :
10458 : //******************************************************************************
10459 :
10460 0 : Real64 VSHPCyclingResidual(EnergyPlusData &state,
10461 : Real64 const PartLoadFrac, // compressor cycling ratio (1.0 is continuous, 0.0 is off)
10462 : int FurnaceNum,
10463 : // int ZoneNum,
10464 : bool FirstHVACIteration,
10465 : // int fanOp,
10466 : Real64 LoadToBeMet,
10467 : Real64 OnOffAirFlowRatio,
10468 : Real64 SupHeaterLoad,
10469 : HVAC::CompressorOp compressorOp,
10470 : Real64 par9_SensLatFlag)
10471 : {
10472 : // FUNCTION INFORMATION:
10473 : // AUTHOR Bo Shen, based on HVACMultiSpeedHeatPump:MSHPCyclingResidual
10474 : // DATE WRITTEN March, 2012
10475 :
10476 : // PURPOSE OF THIS FUNCTION:
10477 : // Calculates residual function ((ActualOutput - QZnReq)/QZnReq)
10478 : // MSHP output depends on the part load ratio which is being varied to zero the residual.
10479 :
10480 : // METHODOLOGY EMPLOYED:
10481 : // Calls CalcMSHeatPump to get ActualOutput at the given part load ratio
10482 : // and calculates the residual as defined above
10483 :
10484 : // int FurnaceNum = int(Par[0]);
10485 : // int ZoneNum = int(Par[1]);
10486 : // bool FirstHVACIteration = (Par[2] == 1.0);
10487 : // int fanOp = int(Par[3]);
10488 : // Real64 LoadToBeMet = Par[4];
10489 : // Real64 OnOffAirFlowRatio = Par[5];
10490 : // Real64 SupHeaterLoad = Par[6];
10491 : // CompressorOperation CompressorOp = static_cast<CompressorOperation>(Par[8]);
10492 : // Real64 par9_SensLatFlag = Par[9];
10493 :
10494 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
10495 : Real64 ZoneSensLoadMet; // delivered sensible capacity of MSHP
10496 : Real64 ZoneLatLoadMet; // delivered latent capacity of MSHP
10497 :
10498 0 : Real64 QZnReq = 0.0;
10499 0 : Real64 QZnLat = 0.0;
10500 0 : if (par9_SensLatFlag == 1.0) {
10501 0 : QZnReq = LoadToBeMet;
10502 : } else {
10503 0 : QZnLat = LoadToBeMet;
10504 : }
10505 :
10506 0 : CalcVarSpeedHeatPump(state,
10507 : FurnaceNum,
10508 : FirstHVACIteration,
10509 : compressorOp,
10510 : 1,
10511 : 0.0,
10512 : PartLoadFrac,
10513 : ZoneSensLoadMet,
10514 : ZoneLatLoadMet,
10515 : QZnReq,
10516 : QZnLat,
10517 : OnOffAirFlowRatio,
10518 : SupHeaterLoad);
10519 :
10520 0 : Real64 ResScale = std::abs(LoadToBeMet);
10521 0 : if (ResScale < 100.0) {
10522 0 : ResScale = 100.0;
10523 : } else {
10524 0 : ResScale = LoadToBeMet;
10525 : }
10526 :
10527 : // Calculate residual based on output calculation flag
10528 0 : if (par9_SensLatFlag == 1.0) {
10529 0 : return (ZoneSensLoadMet - LoadToBeMet) / ResScale;
10530 : } else {
10531 0 : return (ZoneLatLoadMet - LoadToBeMet) / ResScale;
10532 : }
10533 : }
10534 :
10535 : //******************************************************************************
10536 :
10537 0 : Real64 VSHPSpeedResidual(EnergyPlusData &state,
10538 : Real64 const SpeedRatio, // compressor cycling ratio (1.0 is continuous, 0.0 is off)
10539 : int FurnaceNum,
10540 : // int ZoneNum,
10541 : bool FirstHVACIteration,
10542 : // int fanOp
10543 : Real64 LoadToBeMet,
10544 : Real64 OnOffAirFlowRatio,
10545 : Real64 SupHeaterLoad,
10546 : int SpeedNum,
10547 : HVAC::CompressorOp compressorOp,
10548 : Real64 par9_SensLatFlag)
10549 : {
10550 : // FUNCTION INFORMATION:
10551 : // AUTHOR Bo Shen, , based on HVACMultiSpeedHeatPump:MSHPVarSpeedgResidual
10552 : // DATE WRITTEN March, 2012
10553 :
10554 : // PURPOSE OF THIS FUNCTION:
10555 : // Calculates residual function ((ActualOutput - QZnReq)/QZnReq)
10556 : // MSHP output depends on the part load ratio which is being varied to zero the residual.
10557 :
10558 : // METHODOLOGY EMPLOYED:
10559 : // Calls CalcMSHeatPump to get ActualOutput at the given speed ratio (partload ratio for high speed)
10560 : // and calculates the residual as defined above
10561 :
10562 0 : Real64 QZnReq = 0.0;
10563 0 : Real64 QZnLat = 0.0;
10564 0 : if (par9_SensLatFlag == 1.0) {
10565 0 : QZnReq = LoadToBeMet;
10566 : } else {
10567 0 : QZnLat = LoadToBeMet;
10568 : }
10569 :
10570 : Real64 ZoneSensLoadMet; // delivered sensible capacity of MSHP
10571 : Real64 ZoneLatLoadMet; // delivered latent capacity of MSHP
10572 0 : CalcVarSpeedHeatPump(state,
10573 : FurnaceNum,
10574 : FirstHVACIteration,
10575 : compressorOp,
10576 : SpeedNum,
10577 : SpeedRatio,
10578 : 1.0,
10579 : ZoneSensLoadMet,
10580 : ZoneLatLoadMet,
10581 : QZnReq,
10582 : QZnLat,
10583 : OnOffAirFlowRatio,
10584 : SupHeaterLoad);
10585 :
10586 0 : Real64 ResScale = std::abs(LoadToBeMet);
10587 0 : if (ResScale < 100.0) {
10588 0 : ResScale = 100.0;
10589 : } else {
10590 0 : ResScale = LoadToBeMet;
10591 : }
10592 :
10593 : // Calculate residual based on output calculation flag
10594 0 : if (par9_SensLatFlag == 1.0) {
10595 0 : return (ZoneSensLoadMet - LoadToBeMet) / ResScale;
10596 : } else {
10597 0 : return (ZoneLatLoadMet - LoadToBeMet) / ResScale;
10598 : }
10599 : }
10600 :
10601 9 : void SetVSHPAirFlow(EnergyPlusData &state,
10602 : int const FurnaceNum, // Unit index
10603 : Real64 const PartLoadRatio, // unit part load ratio
10604 : Real64 &OnOffAirFlowRatio, // ratio of compressor ON airflow to average airflow over timestep
10605 : ObjexxFCL::Optional_int_const SpeedNum, // Speed number
10606 : ObjexxFCL::Optional<Real64 const> SpeedRatio // Speed ratio
10607 : )
10608 : {
10609 :
10610 : // SUBROUTINE INFORMATION:
10611 : // AUTHOR Bo Shen, based on HVACMultiSpeedHeatPump:SetAverageAirFlow
10612 : // DATE WRITTEN March, 2012
10613 :
10614 : // PURPOSE OF THIS SUBROUTINE:
10615 : // Set the average air mass flow rates using the part load fraction of the heat pump for this time step
10616 : // Set OnOffAirFlowRatio to be used by DX coils
10617 :
10618 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
10619 : Real64 AverageUnitMassFlow; // average supply air mass flow rate over time step
10620 :
10621 9 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
10622 :
10623 9 : state.dataHVACGlobal->MSHPMassFlowRateLow = 0.0; // Mass flow rate at low speed
10624 9 : state.dataHVACGlobal->MSHPMassFlowRateHigh = 0.0; // Mass flow rate at high speed
10625 :
10626 9 : if (thisFurnace.fanOp == HVAC::FanOp::Continuous) {
10627 1 : state.dataFurnaces->CompOffMassFlow = thisFurnace.IdleMassFlowRate;
10628 1 : state.dataFurnaces->CompOffFlowRatio = thisFurnace.IdleSpeedRatio;
10629 : } else {
10630 8 : state.dataFurnaces->CompOffMassFlow = 0.0;
10631 8 : state.dataFurnaces->CompOffFlowRatio = 0.0;
10632 : }
10633 :
10634 9 : if (state.dataFurnaces->CoolingLoad && (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool)) {
10635 3 : if (thisFurnace.NumOfSpeedCooling > 0) {
10636 3 : state.dataFurnaces->CompOnMassFlow = thisFurnace.CoolMassFlowRate(thisFurnace.NumOfSpeedCooling);
10637 3 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.MSCoolingSpeedRatio(thisFurnace.NumOfSpeedCooling);
10638 3 : state.dataHVACGlobal->MSHPMassFlowRateLow = thisFurnace.CoolMassFlowRate(thisFurnace.NumOfSpeedCooling);
10639 3 : state.dataHVACGlobal->MSHPMassFlowRateHigh = thisFurnace.CoolMassFlowRate(thisFurnace.NumOfSpeedCooling);
10640 : } else {
10641 0 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxCoolAirMassFlow;
10642 0 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.CoolingSpeedRatio;
10643 : }
10644 3 : AverageUnitMassFlow = (PartLoadRatio * state.dataFurnaces->CompOnMassFlow) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffMassFlow);
10645 3 : if (state.dataFurnaces->CompOffFlowRatio > 0.0) {
10646 0 : state.dataFurnaces->FanSpeedRatio =
10647 0 : (PartLoadRatio * state.dataFurnaces->CompOnFlowRatio) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffFlowRatio);
10648 : } else {
10649 3 : state.dataFurnaces->FanSpeedRatio = state.dataFurnaces->CompOnFlowRatio;
10650 : }
10651 6 : } else if (state.dataFurnaces->HeatingLoad && (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool)) {
10652 6 : if (thisFurnace.NumOfSpeedHeating > 0) {
10653 4 : state.dataFurnaces->CompOnMassFlow = thisFurnace.HeatMassFlowRate(thisFurnace.NumOfSpeedHeating);
10654 4 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.MSHeatingSpeedRatio(thisFurnace.NumOfSpeedHeating);
10655 4 : state.dataHVACGlobal->MSHPMassFlowRateLow = thisFurnace.HeatMassFlowRate(thisFurnace.NumOfSpeedHeating);
10656 4 : state.dataHVACGlobal->MSHPMassFlowRateHigh = thisFurnace.HeatMassFlowRate(thisFurnace.NumOfSpeedHeating);
10657 : } else {
10658 2 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxHeatAirMassFlow;
10659 2 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.HeatingSpeedRatio;
10660 : }
10661 6 : AverageUnitMassFlow = (PartLoadRatio * state.dataFurnaces->CompOnMassFlow) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffMassFlow);
10662 6 : if (state.dataFurnaces->CompOffFlowRatio > 0.0) {
10663 1 : state.dataFurnaces->FanSpeedRatio =
10664 1 : (PartLoadRatio * state.dataFurnaces->CompOnFlowRatio) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffFlowRatio);
10665 : } else {
10666 5 : state.dataFurnaces->FanSpeedRatio = state.dataFurnaces->CompOnFlowRatio;
10667 : }
10668 0 : } else if (thisFurnace.bIsIHP) {
10669 0 : if (!state.dataZoneEnergyDemand->CurDeadBandOrSetback(thisFurnace.ControlZoneNum) && present(SpeedNum)) {
10670 : // if(present(SpeedNum)) {
10671 0 : state.dataFurnaces->CompOnMassFlow =
10672 0 : IntegratedHeatPump::GetAirMassFlowRateIHP(state, thisFurnace.CoolingCoilIndex, SpeedNum, SpeedRatio, false);
10673 0 : state.dataFurnaces->CompOnFlowRatio =
10674 0 : state.dataFurnaces->CompOnMassFlow /
10675 0 : IntegratedHeatPump::GetAirMassFlowRateIHP(
10676 : state, thisFurnace.CoolingCoilIndex, IntegratedHeatPump::GetMaxSpeedNumIHP(state, thisFurnace.CoolingCoilIndex), 1.0, false);
10677 0 : state.dataHVACGlobal->MSHPMassFlowRateLow =
10678 0 : IntegratedHeatPump::GetAirMassFlowRateIHP(state, thisFurnace.CoolingCoilIndex, SpeedNum, 0.0, false);
10679 0 : state.dataHVACGlobal->MSHPMassFlowRateHigh =
10680 0 : IntegratedHeatPump::GetAirMassFlowRateIHP(state, thisFurnace.CoolingCoilIndex, SpeedNum, 1.0, false);
10681 : }
10682 :
10683 : // Set up fan flow rate during compressor off time
10684 0 : if (thisFurnace.fanOp == HVAC::FanOp::Continuous && present(SpeedNum)) {
10685 0 : if (thisFurnace.AirFlowControl == AirFlowControlConstFan::UseCompressorOnFlow && state.dataFurnaces->CompOnMassFlow > 0.0) {
10686 0 : state.dataFurnaces->CompOffMassFlow =
10687 0 : IntegratedHeatPump::GetAirMassFlowRateIHP(state, thisFurnace.CoolingCoilIndex, SpeedNum, 1.0, false);
10688 0 : state.dataFurnaces->CompOffFlowRatio =
10689 0 : state.dataFurnaces->CompOffMassFlow /
10690 0 : IntegratedHeatPump::GetAirMassFlowRateIHP(state,
10691 : thisFurnace.CoolingCoilIndex,
10692 : IntegratedHeatPump::GetMaxSpeedNumIHP(state, thisFurnace.CoolingCoilIndex),
10693 : 1.0,
10694 : false);
10695 : }
10696 : }
10697 :
10698 0 : if (present(SpeedNum)) {
10699 0 : if (SpeedNum > 1) {
10700 0 : AverageUnitMassFlow = state.dataFurnaces->CompOnMassFlow;
10701 0 : state.dataFurnaces->FanSpeedRatio = state.dataFurnaces->CompOnFlowRatio;
10702 : } else {
10703 0 : AverageUnitMassFlow =
10704 0 : (PartLoadRatio * state.dataFurnaces->CompOnMassFlow) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffMassFlow);
10705 0 : if (state.dataFurnaces->CompOffFlowRatio > 0.0) {
10706 0 : state.dataFurnaces->FanSpeedRatio =
10707 0 : (PartLoadRatio * state.dataFurnaces->CompOnFlowRatio) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffFlowRatio);
10708 : } else {
10709 0 : state.dataFurnaces->FanSpeedRatio = state.dataFurnaces->CompOnFlowRatio;
10710 : }
10711 : }
10712 : } else {
10713 0 : AverageUnitMassFlow =
10714 0 : (PartLoadRatio * state.dataFurnaces->CompOnMassFlow) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffMassFlow);
10715 0 : if (state.dataFurnaces->CompOffFlowRatio > 0.0) {
10716 0 : state.dataFurnaces->FanSpeedRatio =
10717 0 : (PartLoadRatio * state.dataFurnaces->CompOnFlowRatio) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffFlowRatio);
10718 : } else {
10719 0 : state.dataFurnaces->FanSpeedRatio = state.dataFurnaces->CompOnFlowRatio;
10720 : }
10721 : }
10722 :
10723 0 : if (IntegratedHeatPump::IHPOperationMode::SCWHMatchWH ==
10724 0 : state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).CurMode) {
10725 0 : state.dataFurnaces->CompOnMassFlow =
10726 0 : IntegratedHeatPump::GetAirMassFlowRateIHP(state, thisFurnace.CoolingCoilIndex, SpeedNum, SpeedRatio, false);
10727 0 : AverageUnitMassFlow = state.dataFurnaces->CompOnMassFlow;
10728 : }
10729 : } else {
10730 0 : if (!state.dataZoneEnergyDemand->CurDeadBandOrSetback(thisFurnace.ControlZoneNum) && present(SpeedNum)) {
10731 0 : if (thisFurnace.HeatCoolMode == Furnaces::ModeOfOperation::HeatingMode) {
10732 0 : if (SpeedNum == 1) {
10733 0 : state.dataFurnaces->CompOnMassFlow = thisFurnace.HeatMassFlowRate(SpeedNum);
10734 0 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.MSHeatingSpeedRatio(SpeedNum);
10735 0 : state.dataHVACGlobal->MSHPMassFlowRateLow = thisFurnace.HeatMassFlowRate(1);
10736 0 : state.dataHVACGlobal->MSHPMassFlowRateHigh = thisFurnace.HeatMassFlowRate(1);
10737 0 : } else if (SpeedNum > 1) {
10738 0 : state.dataFurnaces->CompOnMassFlow =
10739 0 : SpeedRatio * thisFurnace.HeatMassFlowRate(SpeedNum) + (1.0 - SpeedRatio) * thisFurnace.HeatMassFlowRate(SpeedNum - 1);
10740 0 : state.dataFurnaces->CompOnFlowRatio = SpeedRatio * thisFurnace.MSHeatingSpeedRatio(SpeedNum) +
10741 0 : (1.0 - SpeedRatio) * thisFurnace.MSHeatingSpeedRatio(SpeedNum - 1);
10742 0 : state.dataHVACGlobal->MSHPMassFlowRateLow = thisFurnace.HeatMassFlowRate(SpeedNum - 1);
10743 0 : state.dataHVACGlobal->MSHPMassFlowRateHigh = thisFurnace.HeatMassFlowRate(SpeedNum);
10744 : }
10745 0 : } else if (thisFurnace.HeatCoolMode == Furnaces::ModeOfOperation::CoolingMode) {
10746 0 : if (SpeedNum == 1) {
10747 0 : state.dataFurnaces->CompOnMassFlow = thisFurnace.CoolMassFlowRate(SpeedNum);
10748 0 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.MSCoolingSpeedRatio(SpeedNum);
10749 0 : state.dataHVACGlobal->MSHPMassFlowRateLow = thisFurnace.CoolMassFlowRate(1);
10750 0 : state.dataHVACGlobal->MSHPMassFlowRateHigh = thisFurnace.CoolMassFlowRate(1);
10751 0 : } else if (SpeedNum > 1) {
10752 0 : state.dataFurnaces->CompOnMassFlow =
10753 0 : SpeedRatio * thisFurnace.CoolMassFlowRate(SpeedNum) + (1.0 - SpeedRatio) * thisFurnace.CoolMassFlowRate(SpeedNum - 1);
10754 0 : state.dataFurnaces->CompOnFlowRatio = SpeedRatio * thisFurnace.MSCoolingSpeedRatio(SpeedNum) +
10755 0 : (1.0 - SpeedRatio) * thisFurnace.MSCoolingSpeedRatio(SpeedNum - 1);
10756 0 : state.dataHVACGlobal->MSHPMassFlowRateLow = thisFurnace.CoolMassFlowRate(SpeedNum - 1);
10757 0 : state.dataHVACGlobal->MSHPMassFlowRateHigh = thisFurnace.CoolMassFlowRate(SpeedNum);
10758 : }
10759 : }
10760 : }
10761 :
10762 : // Set up fan flow rate during compressor off time
10763 0 : if (thisFurnace.fanOp == HVAC::FanOp::Continuous && present(SpeedNum)) {
10764 0 : if (thisFurnace.AirFlowControl == AirFlowControlConstFan::UseCompressorOnFlow && state.dataFurnaces->CompOnMassFlow > 0.0) {
10765 0 : if (SpeedNum == 1) { // LOWEST SPEED USE IDLE FLOW
10766 0 : state.dataFurnaces->CompOffMassFlow = thisFurnace.IdleMassFlowRate;
10767 0 : state.dataFurnaces->CompOffFlowRatio = thisFurnace.IdleSpeedRatio;
10768 0 : } else if (thisFurnace.LastMode == Furnaces::ModeOfOperation::HeatingMode) {
10769 0 : state.dataFurnaces->CompOffMassFlow = thisFurnace.HeatMassFlowRate(SpeedNum);
10770 0 : state.dataFurnaces->CompOffFlowRatio = thisFurnace.MSHeatingSpeedRatio(SpeedNum);
10771 : } else {
10772 0 : state.dataFurnaces->CompOffMassFlow = thisFurnace.CoolMassFlowRate(SpeedNum);
10773 0 : state.dataFurnaces->CompOffFlowRatio = thisFurnace.MSCoolingSpeedRatio(SpeedNum);
10774 : }
10775 : }
10776 : }
10777 :
10778 0 : if (present(SpeedNum)) {
10779 0 : if (SpeedNum > 1) {
10780 0 : AverageUnitMassFlow = state.dataFurnaces->CompOnMassFlow;
10781 0 : state.dataFurnaces->FanSpeedRatio = state.dataFurnaces->CompOnFlowRatio;
10782 : } else {
10783 0 : AverageUnitMassFlow =
10784 0 : (PartLoadRatio * state.dataFurnaces->CompOnMassFlow) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffMassFlow);
10785 0 : if (state.dataFurnaces->CompOffFlowRatio > 0.0) {
10786 0 : state.dataFurnaces->FanSpeedRatio =
10787 0 : (PartLoadRatio * state.dataFurnaces->CompOnFlowRatio) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffFlowRatio);
10788 : } else {
10789 0 : state.dataFurnaces->FanSpeedRatio = state.dataFurnaces->CompOnFlowRatio;
10790 : }
10791 : }
10792 : } else {
10793 0 : AverageUnitMassFlow =
10794 0 : (PartLoadRatio * state.dataFurnaces->CompOnMassFlow) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffMassFlow);
10795 0 : if (state.dataFurnaces->CompOffFlowRatio > 0.0) {
10796 0 : state.dataFurnaces->FanSpeedRatio =
10797 0 : (PartLoadRatio * state.dataFurnaces->CompOnFlowRatio) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffFlowRatio);
10798 : } else {
10799 0 : state.dataFurnaces->FanSpeedRatio = state.dataFurnaces->CompOnFlowRatio;
10800 : }
10801 : }
10802 : }
10803 :
10804 17 : if ((thisFurnace.availSched->getCurrentVal() == 0.0) || state.dataHVACGlobal->TurnFansOff ||
10805 8 : (thisFurnace.fanAvailSched->getCurrentVal() == 0.0 && !state.dataHVACGlobal->TurnFansOn)) {
10806 1 : state.dataLoopNodes->Node(thisFurnace.FurnaceInletNodeNum).MassFlowRate = 0.0;
10807 1 : OnOffAirFlowRatio = 0.0;
10808 : } else {
10809 8 : state.dataLoopNodes->Node(thisFurnace.FurnaceInletNodeNum).MassFlowRate = AverageUnitMassFlow;
10810 8 : state.dataLoopNodes->Node(thisFurnace.FurnaceInletNodeNum).MassFlowRateMaxAvail = AverageUnitMassFlow;
10811 8 : if (AverageUnitMassFlow > 0.0) {
10812 8 : OnOffAirFlowRatio = state.dataFurnaces->CompOnMassFlow / AverageUnitMassFlow;
10813 : } else {
10814 0 : OnOffAirFlowRatio = 0.0;
10815 : }
10816 : }
10817 :
10818 9 : state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum).MassFlowRate =
10819 9 : state.dataLoopNodes->Node(thisFurnace.FurnaceInletNodeNum).MassFlowRate;
10820 9 : }
10821 :
10822 7 : void SetMinOATCompressor(EnergyPlusData &state,
10823 : int const FurnaceNum, // index to furnace
10824 : std::string const &cCurrentModuleObject, // type of furnace
10825 : bool &ErrorsFound // GetInput logical that errors were found
10826 : )
10827 : {
10828 7 : bool errFlag = false;
10829 7 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
10830 :
10831 : // Set minimum OAT for heat pump compressor operation in heating mode
10832 7 : if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingSingleSpeed) {
10833 5 : thisFurnace.MinOATCompressorCooling = DXCoils::GetMinOATCompressor(state, thisFurnace.CoolingCoilIndex, errFlag);
10834 2 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) {
10835 1 : std::string ChildCoolingCoilType = state.dataHVACAssistedCC->HXAssistedCoil(thisFurnace.CoolingCoilIndex).CoolingCoilType;
10836 1 : std::string ChildCoolingCoilName = state.dataHVACAssistedCC->HXAssistedCoil(thisFurnace.CoolingCoilIndex).CoolingCoilName;
10837 :
10838 1 : if (Util::SameString(ChildCoolingCoilType, "COIL:COOLING:DX")) {
10839 1 : int childCCIndex_DX = CoilCoolingDX::factory(state, ChildCoolingCoilName);
10840 1 : if (childCCIndex_DX < 0) {
10841 0 : ShowContinueError(state, format("Occurs in {} = {}", cCurrentModuleObject, thisFurnace.Name));
10842 0 : errFlag = true;
10843 0 : ErrorsFound = true;
10844 : }
10845 1 : auto const &newCoil = state.dataCoilCoolingDX->coilCoolingDXs[childCCIndex_DX];
10846 1 : thisFurnace.MinOATCompressorCooling = newCoil.performance.minOutdoorDrybulb;
10847 0 : } else if (Util::SameString(ChildCoolingCoilType, "Coil:Cooling:DX:VariableSpeed")) {
10848 0 : int childCCIndex_VS = state.dataHVACAssistedCC->HXAssistedCoil(thisFurnace.CoolingCoilIndex).CoolingCoilIndex;
10849 0 : thisFurnace.MinOATCompressorCooling = VariableSpeedCoils::GetVSCoilMinOATCompressor(state, childCCIndex_VS, errFlag);
10850 : } else { // Single speed
10851 0 : int childCCIndex_SP = state.dataHVACAssistedCC->HXAssistedCoil(thisFurnace.CoolingCoilIndex).CoolingCoilIndex;
10852 0 : thisFurnace.MinOATCompressorCooling = DXCoils::GetMinOATCompressor(state, childCCIndex_SP, errFlag);
10853 : }
10854 2 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) {
10855 1 : thisFurnace.MinOATCompressorCooling = VariableSpeedCoils::GetVSCoilMinOATCompressor(state, thisFurnace.CoolingCoilIndex, errFlag);
10856 : } else {
10857 0 : thisFurnace.MinOATCompressorCooling = -1000.0;
10858 : }
10859 7 : if (errFlag) {
10860 0 : ShowContinueError(state, format("...occurs in {} = {}", cCurrentModuleObject, thisFurnace.Name));
10861 0 : ErrorsFound = true;
10862 : }
10863 :
10864 : // Set minimum OAT for heat pump compressor operation in heating mode
10865 7 : errFlag = false;
10866 7 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed) {
10867 1 : thisFurnace.MinOATCompressorHeating = VariableSpeedCoils::GetVSCoilMinOATCompressor(state, thisFurnace.HeatingCoilIndex, errFlag);
10868 6 : } else if (thisFurnace.HeatingCoilType_Num == HVAC::CoilDX_HeatingEmpirical) {
10869 3 : thisFurnace.MinOATCompressorHeating = DXCoils::GetMinOATCompressor(state, thisFurnace.HeatingCoilIndex, errFlag);
10870 : } else {
10871 3 : thisFurnace.MinOATCompressorHeating = -1000.0;
10872 : }
10873 7 : if (errFlag) {
10874 0 : ShowContinueError(state, format("...occurs in {} = {}", cCurrentModuleObject, thisFurnace.Name));
10875 0 : ErrorsFound = true;
10876 : }
10877 7 : }
10878 :
10879 : } // namespace Furnaces
10880 :
10881 : } // namespace EnergyPlus
|