Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2024, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // C++ Headers
49 : #include <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 dehumidificaiton 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 dehumidificaiton 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 : // Dehumidificaiton 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 : constexpr std::string_view fluidNameSteam("STEAM");
169 :
170 : // Functions
171 :
172 6243009 : void SimFurnace(EnergyPlusData &state,
173 : std::string_view FurnaceName,
174 : bool const FirstHVACIteration,
175 : int const AirLoopNum, // Primary air loop number
176 : int &CompIndex // Pointer to which furnace
177 : )
178 : {
179 :
180 : // SUBROUTINE INFORMATION:
181 : // AUTHOR Dan Fisher
182 : // DATE WRITTEN Jan 2001
183 : // MODIFIED Richard Liesen, Oct 2001 - Richard Raustad; Bo Shen, March 2012, for VS WSHP
184 : // RE-ENGINEERED Feb 2001
185 :
186 : // PURPOSE OF THIS SUBROUTINE:
187 : // This subroutine manages Furnace component simulation.
188 :
189 : // METHODOLOGY EMPLOYED:
190 : // Call the calc routine to determine an operating PLR. Resimulate child components at this PLR.
191 : // A supplemental heater augments the heating capacity for both air-to-air and water-to-air heat pump systems.
192 : // A reheat coil is used for the HeatCool furnace/unitarysystem to offset the sensible cooling when the
193 : // dehumidification control type is COOLREHEAT. Both the supplemental and reheat heating coil load is calculated
194 : // in the Calc routines and returned here through subroutine arguments. The actual simulation of these coils is
195 : // performed here (i.e. the supplemental and reheat coil loads are passed as 0 to CalcFurnaceOutput).
196 :
197 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
198 : int FurnaceNum; // Furnace number
199 6243009 : Real64 HeatCoilLoad(0.0); // Zone heating coil load
200 : Real64 ReheatCoilLoad; // Load to be met by the reheat coil (if high humidity control)
201 : Real64 MoistureLoad; // Control zone latent load
202 6243009 : Real64 Dummy(0.0);
203 6243009 : HVAC::FanOp fanOp = HVAC::FanOp::Invalid; // Fan operating mode (1=FanOp::Cycling, 2=FanOp::Continuous)
204 :
205 : Real64 QActual; // actual heating coil output (W)
206 : bool SuppHeatingCoilFlag; // true if supplemental heating coil
207 :
208 : // Obtains and Allocates Furnace related parameters from input file
209 6243009 : if (state.dataFurnaces->GetFurnaceInputFlag) { // First time subroutine has been entered
210 : // Get the furnace input
211 97 : GetFurnaceInput(state);
212 97 : state.dataFurnaces->GetFurnaceInputFlag = false;
213 : }
214 :
215 : // Find the correct Furnace
216 6243009 : if (CompIndex == 0) {
217 359 : FurnaceNum = Util::FindItemInList(FurnaceName, state.dataFurnaces->Furnace);
218 359 : if (FurnaceNum == 0) {
219 0 : ShowFatalError(state, format("SimFurnace: Unit not found={}", FurnaceName));
220 : }
221 359 : CompIndex = FurnaceNum;
222 : } else {
223 6242650 : FurnaceNum = CompIndex;
224 6242650 : if (FurnaceNum > state.dataFurnaces->NumFurnaces || FurnaceNum < 1) {
225 0 : ShowFatalError(state,
226 0 : format("SimFurnace: Invalid CompIndex passed={}, Number of Units={}, Entered Unit name={}",
227 : FurnaceNum,
228 0 : state.dataFurnaces->NumFurnaces,
229 : FurnaceName));
230 : }
231 6242650 : if (state.dataFurnaces->CheckEquipName(FurnaceNum)) {
232 359 : if (FurnaceName != state.dataFurnaces->Furnace(FurnaceNum).Name) {
233 0 : ShowFatalError(state,
234 0 : format("SimFurnace: Invalid CompIndex passed={}, Unit name={}, stored Unit Name for that index={}",
235 : FurnaceNum,
236 : FurnaceName,
237 0 : state.dataFurnaces->Furnace(FurnaceNum).Name));
238 : }
239 359 : state.dataFurnaces->CheckEquipName(FurnaceNum) = false;
240 : }
241 : }
242 :
243 6243009 : bool HXUnitOn = false; // flag to control HX assisted cooling coil
244 6243009 : Real64 OnOffAirFlowRatio = 0.0; // Ratio of compressor ON air flow to AVERAGE air flow over time step
245 : // here we need to deal with sequenced zone equip sensible load in control zone
246 6243009 : Real64 ZoneLoad = 0.0;
247 :
248 6243009 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
249 6243009 : auto &zoneSysEnergyDemand = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(thisFurnace.ControlZoneNum);
250 6243009 : if (thisFurnace.ZoneSequenceCoolingNum > 0 && thisFurnace.ZoneSequenceHeatingNum > 0) {
251 6242650 : Real64 ZoneLoadToCoolSPSequenced = zoneSysEnergyDemand.SequencedOutputRequiredToCoolingSP(thisFurnace.ZoneSequenceCoolingNum);
252 6242650 : Real64 ZoneLoadToHeatSPSequenced = zoneSysEnergyDemand.SequencedOutputRequiredToHeatingSP(thisFurnace.ZoneSequenceHeatingNum);
253 6242650 : auto const &tempControlType = state.dataHeatBalFanSys->TempControlType(thisFurnace.ControlZoneNum);
254 6242650 : if (ZoneLoadToHeatSPSequenced > 0.0 && ZoneLoadToCoolSPSequenced > 0.0 && tempControlType != HVAC::ThermostatType::SingleCooling) {
255 2027000 : ZoneLoad = ZoneLoadToHeatSPSequenced;
256 4215650 : } else if (ZoneLoadToHeatSPSequenced > 0.0 && ZoneLoadToCoolSPSequenced > 0.0 && tempControlType == HVAC::ThermostatType::SingleCooling) {
257 66828 : ZoneLoad = 0.0;
258 4148822 : } else if (ZoneLoadToHeatSPSequenced < 0.0 && ZoneLoadToCoolSPSequenced < 0.0 && tempControlType != HVAC::ThermostatType::SingleHeating) {
259 3045034 : ZoneLoad = ZoneLoadToCoolSPSequenced;
260 1103788 : } else if (ZoneLoadToHeatSPSequenced < 0.0 && ZoneLoadToCoolSPSequenced < 0.0 && tempControlType == HVAC::ThermostatType::SingleHeating) {
261 25175 : ZoneLoad = 0.0;
262 1078613 : } else if (ZoneLoadToHeatSPSequenced <= 0.0 && ZoneLoadToCoolSPSequenced >= 0.0) {
263 1078613 : ZoneLoad = 0.0;
264 : }
265 6242650 : MoistureLoad = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(thisFurnace.ControlZoneNum)
266 6242650 : .SequencedOutputRequiredToDehumidSP(thisFurnace.ZoneSequenceCoolingNum);
267 6242650 : } else {
268 359 : ZoneLoad = zoneSysEnergyDemand.RemainingOutputRequired;
269 359 : MoistureLoad = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(thisFurnace.ControlZoneNum).OutputRequiredToDehumidifyingSP;
270 : }
271 :
272 : // H2OHtOfVap
273 6243009 : MoistureLoad *= Psychrometrics::PsyHfgAirFnWTdb(state.dataLoopNodes->Node(thisFurnace.NodeNumOfControlledZone).HumRat,
274 6243009 : state.dataLoopNodes->Node(thisFurnace.NodeNumOfControlledZone).Temp);
275 :
276 : // Initialize Furnace Flows
277 6243009 : InitFurnace(state, FurnaceNum, AirLoopNum, OnOffAirFlowRatio, fanOp, ZoneLoad, MoistureLoad, FirstHVACIteration);
278 :
279 6243009 : int FurnaceInletNode = thisFurnace.FurnaceInletNodeNum;
280 :
281 : // MassFlowRateMaxAvail issues are impeding non-VAV air loop equipment by limiting air flow
282 : // temporarily open up flow limits while simulating, and then set this same value at the INLET after this parent has simulated
283 6243009 : Real64 TempMassFlowRateMaxAvail = state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRateMaxAvail;
284 6243009 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRateMaxAvail = thisFurnace.DesignMassFlowRate;
285 :
286 6243009 : Real64 FurnaceSavMdot = state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate;
287 6243009 : HVAC::CompressorOp compressorOp = HVAC::CompressorOp::On;
288 6243009 : state.dataFurnaces->CoolHeatPLRRat = 1.0;
289 :
290 : // Simulate correct system type (1 of 4 choices)
291 6243009 : switch (thisFurnace.type) {
292 : // Simulate HeatOnly systems:
293 24444 : case HVAC::UnitarySysType::Furnace_HeatOnly:
294 : case HVAC::UnitarySysType::Unitary_HeatOnly: {
295 : // Update the furnace flow rates
296 24444 : CalcNewZoneHeatOnlyFlowRates(state, FurnaceNum, FirstHVACIteration, ZoneLoad, HeatCoilLoad, OnOffAirFlowRatio);
297 :
298 24444 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
299 : // simulate fan
300 24444 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
301 : }
302 :
303 : // simulate furnace heating coil
304 24444 : SuppHeatingCoilFlag = false; // if true simulates supplemental heating coil
305 24444 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, fanOp, QActual);
306 :
307 24444 : if (thisFurnace.fanPlace == HVAC::FanPlace::DrawThru) {
308 : // simulate fan
309 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
310 : }
311 24444 : } break;
312 : // Simulate HeatCool sytems:
313 3738201 : case HVAC::UnitarySysType::Furnace_HeatCool:
314 : case HVAC::UnitarySysType::Unitary_HeatCool: {
315 3738201 : if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) {
316 : // variable speed cooling coil
317 1247320 : HeatCoilLoad = 0.0;
318 1247320 : if (thisFurnace.bIsIHP)
319 0 : state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).ControlledZoneTemp =
320 0 : state.dataLoopNodes->Node(thisFurnace.NodeNumOfControlledZone).Temp;
321 1247320 : SimVariableSpeedHP(state, FurnaceNum, FirstHVACIteration, AirLoopNum, ZoneLoad, MoistureLoad, OnOffAirFlowRatio);
322 : } else {
323 : // calculate the system flow rate
324 2743943 : if (!FirstHVACIteration && thisFurnace.fanOp == HVAC::FanOp::Cycling && state.dataFurnaces->CoolingLoad &&
325 253062 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).EconoActive) {
326 : // for cycling fan, cooling load, check whether furnace can meet load with compressor off
327 5692 : compressorOp = HVAC::CompressorOp::Off;
328 5692 : CalcNewZoneHeatCoolFlowRates(state,
329 : FurnaceNum,
330 : FirstHVACIteration,
331 : compressorOp,
332 : ZoneLoad,
333 : MoistureLoad,
334 : HeatCoilLoad,
335 : ReheatCoilLoad,
336 : OnOffAirFlowRatio,
337 : HXUnitOn);
338 5692 : if (thisFurnace.CoolPartLoadRatio >= 1.0 || thisFurnace.HeatPartLoadRatio >= 1.0 ||
339 2160 : (thisFurnace.CoolPartLoadRatio <= 0.0 && thisFurnace.HeatPartLoadRatio <= 0.0)) {
340 : // compressor on (reset inlet air mass flow rate to starting value)
341 5672 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = FurnaceSavMdot;
342 5672 : compressorOp = HVAC::CompressorOp::On;
343 5672 : CalcNewZoneHeatCoolFlowRates(state,
344 : FurnaceNum,
345 : FirstHVACIteration,
346 : compressorOp,
347 : ZoneLoad,
348 : MoistureLoad,
349 : HeatCoilLoad,
350 : ReheatCoilLoad,
351 : OnOffAirFlowRatio,
352 : HXUnitOn);
353 : }
354 : } else {
355 : // compressor on
356 2485189 : CalcNewZoneHeatCoolFlowRates(state,
357 : FurnaceNum,
358 : FirstHVACIteration,
359 : compressorOp,
360 : ZoneLoad,
361 : MoistureLoad,
362 : HeatCoilLoad,
363 : ReheatCoilLoad,
364 : OnOffAirFlowRatio,
365 : HXUnitOn);
366 : }
367 :
368 2490881 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
369 : // simulate fan
370 2451427 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
371 : }
372 :
373 2490881 : if (!thisFurnace.CoolingCoilUpstream) {
374 : // simulate furnace heating coil
375 1128522 : SuppHeatingCoilFlag = false; // if true simulates supplemental heating coil
376 1128522 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, fanOp, QActual);
377 : }
378 :
379 : // simulate furnace DX cooling coil
380 2490881 : if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) {
381 151317 : HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(state,
382 : BlankString,
383 : FirstHVACIteration,
384 : compressorOp,
385 : thisFurnace.CoolPartLoadRatio,
386 50439 : thisFurnace.CoolingCoilIndex,
387 : fanOp,
388 : HXUnitOn,
389 : OnOffAirFlowRatio,
390 50439 : state.dataFurnaces->EconomizerFlag);
391 : } else {
392 7321326 : DXCoils::SimDXCoil(state,
393 : BlankString,
394 : compressorOp,
395 : FirstHVACIteration,
396 2440442 : thisFurnace.CoolingCoilIndex,
397 : fanOp,
398 2440442 : thisFurnace.CoolPartLoadRatio,
399 : OnOffAirFlowRatio,
400 2440442 : state.dataFurnaces->CoolHeatPLRRat);
401 : }
402 :
403 2490881 : if (thisFurnace.CoolingCoilUpstream) {
404 : // simulate furnace heating coil
405 1362359 : SuppHeatingCoilFlag = false; // if true simulates supplemental heating coil
406 1362359 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, fanOp, QActual);
407 : }
408 :
409 2490881 : if (thisFurnace.fanPlace == HVAC::FanPlace::DrawThru) {
410 : // simulate fan
411 39454 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
412 : }
413 :
414 : // Simulate furnace reheat coil if a humidistat is used or if the reheat coil is present
415 2490881 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat || thisFurnace.SuppHeatCoilIndex > 0) {
416 837862 : SuppHeatingCoilFlag = true; // if truee simulates supplemental heating coil
417 837862 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, ReheatCoilLoad, fanOp, QActual);
418 : }
419 : }
420 3738201 : } break;
421 : // Simulate air-to-air heat pumps:
422 421792 : case HVAC::UnitarySysType::Unitary_HeatPump_AirToAir: {
423 421792 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed) {
424 : // variable speed heat pump
425 30262 : HeatCoilLoad = 0.0;
426 30262 : if (thisFurnace.bIsIHP) {
427 10106 : auto &integratedHP = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex);
428 10106 : integratedHP.ControlledZoneTemp = state.dataLoopNodes->Node(thisFurnace.NodeNumOfControlledZone).Temp;
429 10106 : integratedHP.IDFanID = thisFurnace.FanIndex; // why do this every time?
430 10106 : integratedHP.IDFanName = BlankString;
431 10106 : integratedHP.fanPlace = thisFurnace.fanPlace;
432 : }
433 :
434 30262 : SimVariableSpeedHP(state, FurnaceNum, FirstHVACIteration, AirLoopNum, ZoneLoad, MoistureLoad, OnOffAirFlowRatio);
435 : } else {
436 : // Update the furnace flow rates
437 496877 : if (!FirstHVACIteration && thisFurnace.fanOp == HVAC::FanOp::Cycling && state.dataFurnaces->CoolingLoad &&
438 105347 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).EconoActive) {
439 : // for cycling fan, cooling load, check whether furnace can meet load with compressor off
440 538 : compressorOp = HVAC::CompressorOp::Off;
441 538 : CalcNewZoneHeatCoolFlowRates(state,
442 : FurnaceNum,
443 : FirstHVACIteration,
444 : compressorOp,
445 : ZoneLoad,
446 : MoistureLoad,
447 : HeatCoilLoad,
448 : ReheatCoilLoad,
449 : OnOffAirFlowRatio,
450 : HXUnitOn);
451 538 : if (thisFurnace.CoolPartLoadRatio >= 1.0 || thisFurnace.HeatPartLoadRatio >= 1.0 ||
452 406 : (thisFurnace.CoolPartLoadRatio <= 0.0 && thisFurnace.HeatPartLoadRatio <= 0.0)) {
453 : // compressor on (reset inlet air mass flow rate to starting value)
454 132 : compressorOp = HVAC::CompressorOp::On;
455 132 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = FurnaceSavMdot;
456 132 : CalcNewZoneHeatCoolFlowRates(state,
457 : FurnaceNum,
458 : FirstHVACIteration,
459 : compressorOp,
460 : ZoneLoad,
461 : MoistureLoad,
462 : HeatCoilLoad,
463 : ReheatCoilLoad,
464 : OnOffAirFlowRatio,
465 : HXUnitOn);
466 : }
467 : } else {
468 : // compressor on
469 390992 : CalcNewZoneHeatCoolFlowRates(state,
470 : FurnaceNum,
471 : FirstHVACIteration,
472 : compressorOp,
473 : ZoneLoad,
474 : MoistureLoad,
475 : HeatCoilLoad,
476 : ReheatCoilLoad,
477 : OnOffAirFlowRatio,
478 : HXUnitOn);
479 : }
480 :
481 391530 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
482 391530 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
483 : }
484 :
485 391530 : if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) {
486 0 : HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(state,
487 : BlankString,
488 : FirstHVACIteration,
489 : compressorOp,
490 : thisFurnace.CoolPartLoadRatio,
491 0 : thisFurnace.CoolingCoilIndex,
492 : fanOp,
493 : HXUnitOn,
494 : OnOffAirFlowRatio,
495 0 : state.dataFurnaces->EconomizerFlag);
496 : } else {
497 783060 : DXCoils::SimDXCoil(state,
498 : BlankString,
499 : compressorOp,
500 : FirstHVACIteration,
501 391530 : thisFurnace.CoolingCoilIndex,
502 : fanOp,
503 391530 : thisFurnace.CoolPartLoadRatio,
504 : OnOffAirFlowRatio);
505 : }
506 783060 : DXCoils::SimDXCoil(state,
507 : BlankString,
508 : compressorOp,
509 : FirstHVACIteration,
510 391530 : thisFurnace.HeatingCoilIndex,
511 : fanOp,
512 391530 : thisFurnace.HeatPartLoadRatio,
513 : OnOffAirFlowRatio);
514 391530 : if (thisFurnace.fanPlace == HVAC::FanPlace::DrawThru) {
515 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
516 : }
517 :
518 : // Simulate furnace reheat coil if a humidistat is present, the dehumidification type of coolreheat and
519 : // reheat coil load exists
520 391530 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat && ReheatCoilLoad > 0.0) {
521 6194 : SuppHeatingCoilFlag = true; // if truee simulates supplemental heating coil
522 6194 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, ReheatCoilLoad, fanOp, QActual);
523 : } else {
524 385336 : SuppHeatingCoilFlag = true; // if true simulates supplemental heating coil
525 385336 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, fanOp, QActual);
526 : }
527 : }
528 421792 : } break;
529 : // Simulate water-to-air systems:
530 2058572 : case HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir: {
531 2058572 : if (thisFurnace.WatertoAirHPType == WAHPCoilType::Simple) {
532 : // Update the furnace flow rates
533 : // When CompressorOp logic is added to the child cooling coil (COIL:WaterToAirHP:EquationFit:Cooling), then this logic
534 : // needs to be reinstated... to align with Unitary/Furnace HeatCool and Unitary Air-to-Air Heat Pump (see above).
535 2138290 : if (!FirstHVACIteration && thisFurnace.fanOp == HVAC::FanOp::Cycling && state.dataFurnaces->CoolingLoad &&
536 429030 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).EconoActive) {
537 : // for cycling fan, cooling load, check whether furnace can meet load with compressor off
538 0 : compressorOp = HVAC::CompressorOp::Off;
539 0 : CalcNewZoneHeatCoolFlowRates(state,
540 : FurnaceNum,
541 : FirstHVACIteration,
542 : compressorOp,
543 : ZoneLoad,
544 : MoistureLoad,
545 : HeatCoilLoad,
546 : ReheatCoilLoad,
547 : OnOffAirFlowRatio,
548 : HXUnitOn);
549 0 : if (thisFurnace.CoolPartLoadRatio >= 1.0 || thisFurnace.HeatPartLoadRatio >= 1.0 ||
550 0 : (thisFurnace.CoolPartLoadRatio <= 0.0 && thisFurnace.HeatPartLoadRatio <= 0.0)) {
551 : // compressor on (reset inlet air mass flow rate to starting value)
552 0 : compressorOp = HVAC::CompressorOp::On;
553 0 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = FurnaceSavMdot;
554 0 : CalcNewZoneHeatCoolFlowRates(state,
555 : FurnaceNum,
556 : FirstHVACIteration,
557 : compressorOp,
558 : ZoneLoad,
559 : MoistureLoad,
560 : HeatCoilLoad,
561 : ReheatCoilLoad,
562 : OnOffAirFlowRatio,
563 : HXUnitOn);
564 : }
565 : } else {
566 : // compressor on
567 1709260 : CalcNewZoneHeatCoolFlowRates(state,
568 : FurnaceNum,
569 : FirstHVACIteration,
570 : compressorOp,
571 : ZoneLoad,
572 : MoistureLoad,
573 : HeatCoilLoad,
574 : ReheatCoilLoad,
575 : OnOffAirFlowRatio,
576 : HXUnitOn);
577 : }
578 1709260 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
579 1709260 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
580 : }
581 :
582 1709260 : WaterToAirHeatPumpSimple::SimWatertoAirHPSimple(state,
583 : BlankString,
584 1709260 : thisFurnace.CoolingCoilIndex,
585 : thisFurnace.CoolingCoilSensDemand,
586 : thisFurnace.CoolingCoilLatentDemand,
587 : thisFurnace.fanOp,
588 : compressorOp,
589 : thisFurnace.CoolPartLoadRatio,
590 : FirstHVACIteration);
591 1709260 : WaterToAirHeatPumpSimple::SimWatertoAirHPSimple(state,
592 : BlankString,
593 1709260 : thisFurnace.HeatingCoilIndex,
594 : thisFurnace.HeatingCoilSensDemand,
595 : Dummy,
596 : thisFurnace.fanOp,
597 : compressorOp,
598 : thisFurnace.HeatPartLoadRatio,
599 : FirstHVACIteration);
600 :
601 1709260 : if (thisFurnace.fanPlace == HVAC::FanPlace::DrawThru) {
602 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
603 : }
604 1709260 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat && ReheatCoilLoad > 0.0) {
605 15850 : SuppHeatingCoilFlag = true; // if true simulates supplemental heating coil
606 15850 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, ReheatCoilLoad, fanOp, QActual);
607 : } else {
608 1693410 : SuppHeatingCoilFlag = true; // if true simulates supplemental heating coil
609 1693410 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, fanOp, QActual);
610 : }
611 349312 : } else if (thisFurnace.WatertoAirHPType == WAHPCoilType::ParEst) {
612 :
613 : // simulate the heat pump
614 119270 : HeatCoilLoad = 0.0;
615 119270 : CalcWaterToAirHeatPump(state, FurnaceNum, FirstHVACIteration, compressorOp, ZoneLoad, MoistureLoad);
616 230042 : } else if (thisFurnace.WatertoAirHPType == WAHPCoilType::VarSpeedEquationFit) {
617 : // simulate the heat pump
618 230042 : HeatCoilLoad = 0.0;
619 230042 : if (thisFurnace.bIsIHP)
620 0 : state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).ControlledZoneTemp =
621 0 : state.dataLoopNodes->Node(thisFurnace.NodeNumOfControlledZone).Temp;
622 230042 : SimVariableSpeedHP(state, FurnaceNum, FirstHVACIteration, AirLoopNum, ZoneLoad, MoistureLoad, OnOffAirFlowRatio);
623 :
624 0 : } else if (thisFurnace.WatertoAirHPType == WAHPCoilType::VarSpeedLookupTable) {
625 0 : HeatCoilLoad = 0.0; // Added: Used below
626 : } else {
627 0 : assert(false); //? If all possible states covered by if conditions change to HeatCoilLoad = 0.0;
628 : }
629 2058572 : } break;
630 0 : default: {
631 : // will never get here, all system types are simulated above
632 0 : assert(false);
633 : } break;
634 : }
635 :
636 : // set the econo lockout flags
637 6243009 : auto &airLoopControlInfo = state.dataAirLoop->AirLoopControlInfo(AirLoopNum);
638 6243009 : if (thisFurnace.CompPartLoadRatio > 0.0 && airLoopControlInfo.CanLockoutEconoWithCompressor) {
639 278181 : airLoopControlInfo.ReqstEconoLockoutWithCompressor = true;
640 : } else {
641 5964828 : airLoopControlInfo.ReqstEconoLockoutWithCompressor = false;
642 : }
643 :
644 6243009 : if ((HeatCoilLoad > 0.0 || thisFurnace.HeatPartLoadRatio > 0.0) &&
645 1744246 : (airLoopControlInfo.CanLockoutEconoWithCompressor || airLoopControlInfo.CanLockoutEconoWithHeating)) {
646 905744 : airLoopControlInfo.ReqstEconoLockoutWithHeating = true;
647 : } else {
648 5337265 : airLoopControlInfo.ReqstEconoLockoutWithHeating = false;
649 : }
650 :
651 6243009 : if (thisFurnace.fanOp == HVAC::FanOp::Cycling) {
652 2858974 : state.dataAirLoop->AirLoopFlow(AirLoopNum).FanPLR = thisFurnace.FanPartLoadRatio;
653 : } else {
654 3384035 : state.dataAirLoop->AirLoopFlow(AirLoopNum).FanPLR = 1.0; // 1 means constant fan does not cycle.
655 : }
656 :
657 : // Report the current Furnace output
658 6243009 : ReportFurnace(state, FurnaceNum, AirLoopNum);
659 :
660 : // Reset OnOffFanPartLoadFraction to 1 in case another on/off fan is called without a part-load curve
661 6243009 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
662 :
663 6243009 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRateMaxAvail = TempMassFlowRateMaxAvail;
664 6243009 : }
665 :
666 : // Get Input Section of the Module
667 : //******************************************************************************
668 :
669 97 : void GetFurnaceInput(EnergyPlusData &state)
670 : {
671 :
672 : // SUBROUTINE INFORMATION:
673 : // AUTHOR Richard Liesen
674 : // DATE WRITTEN Feb 2001
675 : // MODIFIED Don Shirey and Rich Raustad, Mar/Oct 2001, Mar 2003
676 : // Bereket Nigusse, April 2010 - deprecated supply air flow fraction through
677 : // controlled zone from the input field.
678 : // Bo Shen, March 2012, add inputs for VS WSHP,
679 : // Bo Shen, ORNL, July 2012 - added variable-speed air source heat pump cooling and heating coils, using curve-fits
680 :
681 : // PURPOSE OF THIS SUBROUTINE:
682 : // Obtains input data for fans and coils and stores it in the Furnace data structures
683 :
684 : // METHODOLOGY EMPLOYED:
685 : // Uses "Get" routines to read in data.
686 :
687 : // SUBROUTINE PARAMETER DEFINITIONS:
688 97 : std::string_view constexpr getUnitaryHeatOnly("GetUnitaryHeatOnly");
689 97 : std::string_view constexpr getAirLoopHVACHeatCoolInput("GetAirLoopHVACHeatCoolInput");
690 97 : std::string_view constexpr routineName = "GetFurnaceInput";
691 :
692 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
693 : int FurnaceNum; // The Furnace that you are currently loading input into
694 : int GetObjectNum; // The index to each specific object name
695 : int NumFields; // Total number of fields in object
696 : int NumAlphas; // Total number of alpha fields in object
697 : int NumNumbers; // Total number of numeric fields in object
698 : int IOStatus; // Function call status
699 97 : Array1D<Real64> Numbers; // Numeric data
700 97 : Array1D_string Alphas; // Alpha data
701 97 : Array1D_string cAlphaFields; // Alpha field names
702 97 : Array1D_string cNumericFields; // Numeric field names
703 97 : Array1D_bool lAlphaBlanks; // Logical array, alpha field input BLANK = .TRUE.
704 97 : Array1D_bool lNumericBlanks; // Logical array, numeric field input BLANK = .TRUE.
705 97 : std::string CompSetFanInlet;
706 97 : std::string CompSetFanOutlet;
707 97 : std::string CompSetCoolInlet;
708 97 : std::string CompSetHeatInlet;
709 97 : std::string CompSetHeatOutlet;
710 97 : bool ErrorsFound(false); // If errors detected in input
711 : bool IsNotOK; // Flag to verify name
712 : bool AirNodeFound; // Used to determine if control zone is valid
713 : bool AirLoopFound; // Used to determine if control zone is served by furnace air loop
714 : int TstatZoneNum; // Used to determine if control zone has a thermostat object
715 : int HStatZoneNum; // Used to determine if control zone has a humidistat object
716 : bool errFlag; // Mining function error flag
717 : int FanInletNode; // Used for node checking warning messages
718 : int FanOutletNode; // Used for node checking warning messages
719 : int CoolingCoilInletNode; // Used for node checking warning messages
720 : int CoolingCoilOutletNode; // Used for node checking warning messages
721 : int HeatingCoilInletNode; // Used for node checking warning messages
722 : int HeatingCoilOutletNode; // Used for node checking warning messages
723 : int SupHeatCoilInletNode; // Used for node checking warning messages
724 : int SupHeatCoilOutletNode; // Used for node checking warning messages
725 97 : std::string CoolingCoilType; // Used in mining function CALLS
726 97 : std::string CoolingCoilName; // Used in mining function CALLS
727 97 : std::string HeatingCoilType; // Used in mining function CALLS
728 97 : std::string HeatingCoilName; // Used in mining function CALLS
729 97 : std::string ReheatingCoilType; // Used in mining function CALLS
730 97 : std::string ReheatingCoilName; // Used in mining function CALLS
731 97 : std::string SuppHeatCoilType; // Used in mining function CALLS
732 97 : std::string SuppHeatCoilName; // Used in mining function CALLS
733 97 : std::string FanName; // Used in mining function CALLS
734 : bool PrintMessage; // Used in mining function CALLS
735 : int HeatingCoilPLFCurveIndex; // index of heating coil PLF curve
736 : int SteamIndex; // steam coil index
737 : Real64 SteamDensity; // density of steam at 100C
738 : int DXCoilIndex; // Index to DX coil in HXAssited object
739 97 : std::string IHPCoilName; // IHP cooling coil name
740 97 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
741 : DataLoopNode::ConnectionObjectType currentModuleObjectType;
742 :
743 97 : state.dataFurnaces->GetFurnaceInputFlag = false;
744 97 : int MaxNumbers = 0;
745 97 : int MaxAlphas = 0;
746 :
747 97 : std::string_view CurrentModuleObject = "AirLoopHVAC:Unitary:Furnace:HeatOnly";
748 97 : int NumHeatOnly = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
749 97 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, NumFields, NumAlphas, NumNumbers);
750 97 : MaxNumbers = max(MaxNumbers, NumNumbers);
751 97 : MaxAlphas = max(MaxAlphas, NumAlphas);
752 :
753 97 : CurrentModuleObject = "AirLoopHVAC:Unitary:Furnace:HeatCool";
754 97 : int NumHeatCool = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
755 97 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, NumFields, NumAlphas, NumNumbers);
756 97 : MaxNumbers = max(MaxNumbers, NumNumbers);
757 97 : MaxAlphas = max(MaxAlphas, NumAlphas);
758 :
759 97 : CurrentModuleObject = "AirLoopHVAC:UnitaryHeatOnly";
760 97 : int NumUnitaryHeatOnly = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
761 97 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, NumFields, NumAlphas, NumNumbers);
762 97 : MaxNumbers = max(MaxNumbers, NumNumbers);
763 97 : MaxAlphas = max(MaxAlphas, NumAlphas);
764 :
765 97 : CurrentModuleObject = "AirLoopHVAC:UnitaryHeatCool";
766 97 : int NumUnitaryHeatCool = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
767 97 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, NumFields, NumAlphas, NumNumbers);
768 97 : MaxNumbers = max(MaxNumbers, NumNumbers);
769 97 : MaxAlphas = max(MaxAlphas, NumAlphas);
770 :
771 97 : CurrentModuleObject = "AirLoopHVAC:UnitaryHeatPump:AirToAir";
772 97 : int NumHeatPump = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
773 97 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, NumFields, NumAlphas, NumNumbers);
774 97 : MaxNumbers = max(MaxNumbers, NumNumbers);
775 97 : MaxAlphas = max(MaxAlphas, NumAlphas);
776 :
777 97 : CurrentModuleObject = "AirLoopHVAC:UnitaryHeatPump:WaterToAir";
778 97 : int NumWaterToAirHeatPump = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
779 97 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, NumFields, NumAlphas, NumNumbers);
780 97 : MaxNumbers = max(MaxNumbers, NumNumbers);
781 97 : MaxAlphas = max(MaxAlphas, NumAlphas);
782 :
783 97 : Alphas.allocate(MaxAlphas);
784 97 : Numbers.dimension(MaxNumbers, 0.0);
785 97 : cAlphaFields.allocate(MaxAlphas);
786 97 : cNumericFields.allocate(MaxNumbers);
787 97 : lAlphaBlanks.dimension(MaxAlphas, true);
788 97 : lNumericBlanks.dimension(MaxNumbers, true);
789 :
790 97 : state.dataFurnaces->NumFurnaces = NumHeatOnly + NumHeatCool + NumUnitaryHeatOnly + NumUnitaryHeatCool + NumHeatPump + NumWaterToAirHeatPump;
791 :
792 97 : if (state.dataFurnaces->NumFurnaces > 0) {
793 97 : state.dataFurnaces->Furnace.allocate(state.dataFurnaces->NumFurnaces);
794 97 : state.dataFurnaces->UniqueFurnaceNames.reserve(state.dataFurnaces->NumFurnaces);
795 : }
796 97 : state.dataFurnaces->CheckEquipName.dimension(state.dataFurnaces->NumFurnaces, true);
797 :
798 97 : int IHPCoilIndex = 0;
799 :
800 : // Get the data for the HeatOnly Furnace
801 101 : for (int HeatOnlyNum = 1; HeatOnlyNum <= NumHeatOnly + NumUnitaryHeatOnly; ++HeatOnlyNum) {
802 :
803 4 : FanInletNode = 0;
804 4 : FanOutletNode = 0;
805 4 : HeatingCoilInletNode = 0;
806 4 : HeatingCoilOutletNode = 0;
807 4 : CoolingCoilType = ' ';
808 4 : CoolingCoilName = ' ';
809 4 : HeatingCoilType = ' ';
810 4 : HeatingCoilName = ' ';
811 :
812 4 : FurnaceNum = HeatOnlyNum;
813 4 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
814 :
815 : // Furnace and UnitarySystem objects are both read in here.
816 : // Will still have 2 differently named objects for the user, but read in with 1 DO loop.
817 4 : if (HeatOnlyNum <= NumHeatOnly) {
818 3 : CurrentModuleObject = "AirLoopHVAC:Unitary:Furnace:HeatOnly";
819 3 : currentModuleObjectType = DataLoopNode::ConnectionObjectType::AirLoopHVACUnitaryFurnaceHeatOnly;
820 3 : thisFurnace.type = HVAC::UnitarySysType::Furnace_HeatOnly;
821 3 : GetObjectNum = HeatOnlyNum;
822 : } else {
823 1 : CurrentModuleObject = "AirLoopHVAC:UnitaryHeatOnly";
824 1 : currentModuleObjectType = DataLoopNode::ConnectionObjectType::AirLoopHVACUnitaryHeatOnly;
825 1 : thisFurnace.type = HVAC::UnitarySysType::Unitary_HeatOnly;
826 1 : GetObjectNum = HeatOnlyNum - NumHeatOnly;
827 : }
828 :
829 4 : thisFurnace.iterationMode.allocate(3);
830 :
831 4 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
832 : CurrentModuleObject,
833 : GetObjectNum,
834 : Alphas,
835 : NumAlphas,
836 : Numbers,
837 : NumNumbers,
838 : IOStatus,
839 : lNumericBlanks,
840 : lAlphaBlanks,
841 : cAlphaFields,
842 : cNumericFields);
843 :
844 8 : GlobalNames::VerifyUniqueInterObjectName(
845 4 : state, state.dataFurnaces->UniqueFurnaceNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
846 :
847 4 : thisFurnace.Name = Alphas(1);
848 4 : ErrorObjectHeader eoh{routineName, cAlphaFields(1), thisFurnace.Name};
849 :
850 4 : if (lAlphaBlanks(2)) {
851 0 : thisFurnace.SchedPtr = ScheduleManager::ScheduleAlwaysOn;
852 : } else {
853 4 : thisFurnace.SchedPtr = ScheduleManager::GetScheduleIndex(state, Alphas(2));
854 4 : if (thisFurnace.SchedPtr == 0) {
855 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
856 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(2), Alphas(2)));
857 0 : ErrorsFound = true;
858 : }
859 : }
860 :
861 4 : thisFurnace.FurnaceInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
862 4 : Alphas(3),
863 : ErrorsFound,
864 : currentModuleObjectType,
865 4 : Alphas(1),
866 : DataLoopNode::NodeFluidType::Air,
867 : DataLoopNode::ConnectionType::Inlet,
868 : NodeInputManager::CompFluidStream::Primary,
869 : DataLoopNode::ObjectIsParent);
870 4 : thisFurnace.FurnaceOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
871 4 : Alphas(4),
872 : ErrorsFound,
873 : currentModuleObjectType,
874 4 : Alphas(1),
875 : DataLoopNode::NodeFluidType::Air,
876 : DataLoopNode::ConnectionType::Outlet,
877 : NodeInputManager::CompFluidStream::Primary,
878 : DataLoopNode::ObjectIsParent);
879 :
880 4 : BranchNodeConnections::TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(3), Alphas(4), "Air Nodes");
881 :
882 4 : thisFurnace.FanSchedPtr = ScheduleManager::GetScheduleIndex(state, Alphas(5));
883 4 : if (!lAlphaBlanks(5) && thisFurnace.FanSchedPtr == 0) {
884 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
885 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(5), Alphas(5)));
886 0 : ErrorsFound = true;
887 4 : } else if (lAlphaBlanks(5)) {
888 0 : thisFurnace.fanOp = HVAC::FanOp::Cycling;
889 : }
890 :
891 : // Get the Controlling Zone or Location of the Furnace Thermostat
892 :
893 4 : thisFurnace.ControlZoneNum = Util::FindItemInList(Alphas(6), state.dataHeatBal->Zone);
894 4 : if (thisFurnace.ControlZoneNum == 0) {
895 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
896 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(6), Alphas(6)));
897 0 : ErrorsFound = true;
898 : }
899 :
900 : // Get the node number for the zone with the thermostat
901 4 : if (thisFurnace.ControlZoneNum > 0) {
902 4 : AirNodeFound = false;
903 4 : AirLoopFound = false;
904 4 : int ControlledZoneNum = thisFurnace.ControlZoneNum;
905 : // Find the controlled zone number for the specified thermostat location
906 4 : thisFurnace.NodeNumOfControlledZone = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneNode;
907 : // Determine if furnace is on air loop served by the thermostat location specified
908 4 : for (int zoneInNode = 1; zoneInNode <= state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumInletNodes; ++zoneInNode) {
909 4 : int AirLoopNumber = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNodeAirLoopNum(zoneInNode);
910 4 : if (AirLoopNumber > 0) {
911 4 : for (int BranchNum = 1; BranchNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).NumBranches; ++BranchNum) {
912 4 : for (int CompNum = 1;
913 4 : CompNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).TotalComponents;
914 : ++CompNum) {
915 4 : if (!Util::SameString(state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).Name,
916 8 : thisFurnace.Name) ||
917 4 : !Util::SameString(
918 4 : state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).TypeOf,
919 : CurrentModuleObject))
920 0 : continue;
921 4 : AirLoopFound = true;
922 4 : thisFurnace.ZoneInletNode = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNode(zoneInNode);
923 4 : break;
924 : }
925 4 : if (AirLoopFound) break;
926 : }
927 10 : for (TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumTempControlledZones; ++TstatZoneNum) {
928 6 : if (state.dataZoneCtrls->TempControlledZone(TstatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) continue;
929 4 : AirNodeFound = true;
930 : }
931 4 : for (TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumComfortControlledZones; ++TstatZoneNum) {
932 0 : if (state.dataZoneCtrls->ComfortControlledZone(TstatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) continue;
933 0 : AirNodeFound = true;
934 : }
935 : }
936 4 : if (AirLoopFound) break;
937 : }
938 4 : if (!AirNodeFound) {
939 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
940 0 : ShowContinueError(state, "Did not find Air Node (Zone with Thermostat).");
941 0 : ShowContinueError(state, format("Specified {} = {}", cAlphaFields(6), Alphas(6)));
942 0 : ShowContinueError(
943 : state, "Both a ZoneHVAC:EquipmentConnections object and a ZoneControl:Thermostat object must be specified for this zone.");
944 0 : ErrorsFound = true;
945 : }
946 4 : if (!AirLoopFound) {
947 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
948 0 : ShowContinueError(state, "Did not find correct Primary Air Loop.");
949 0 : ShowContinueError(state, format("Specified {} = {} is not served by this AirLoopHVAC equipment.", cAlphaFields(6), Alphas(6)));
950 0 : ErrorsFound = true;
951 : }
952 : }
953 :
954 : // Get fan data
955 4 : FanName = Alphas(8);
956 4 : errFlag = false;
957 :
958 4 : thisFurnace.fanType = static_cast<HVAC::FanType>(getEnumValue(HVAC::fanTypeNamesUC, Alphas(7)));
959 4 : if (thisFurnace.fanType != HVAC::FanType::OnOff && thisFurnace.fanType != HVAC::FanType::Constant) {
960 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
961 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(7), Alphas(7)));
962 0 : ErrorsFound = true;
963 :
964 4 : } else if ((thisFurnace.FanIndex = Fans::GetFanIndex(state, FanName)) == 0) {
965 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(8), FanName);
966 0 : ErrorsFound = true;
967 :
968 : } else {
969 4 : auto *fan = state.dataFans->fans(thisFurnace.FanIndex);
970 4 : thisFurnace.ActualFanVolFlowRate = fan->maxAirFlowRate;
971 4 : FanInletNode = fan->inletNodeNum;
972 4 : FanOutletNode = fan->outletNodeNum;
973 4 : thisFurnace.FanAvailSchedPtr = fan->availSchedNum;
974 :
975 : // Check fan's schedule for cycling fan operation if constant volume fan is used
976 4 : if (thisFurnace.FanSchedPtr > 0 && thisFurnace.fanType == HVAC::FanType::Constant) {
977 0 : if (!ScheduleManager::CheckScheduleValueMinMax(
978 : state, thisFurnace.FanSchedPtr, ScheduleManager::Clusivity::Exclusive, 0.0, ScheduleManager::Clusivity::Inclusive, 1.0)) {
979 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
980 0 : ShowContinueError(state, format("For {} = {}", cAlphaFields(7), Alphas(7)));
981 0 : ShowContinueError(state, "Fan operating mode must be continuous (fan operating mode schedule values > 0).");
982 0 : ShowContinueError(state, format("Error found in {} = {}", cAlphaFields(5), Alphas(5)));
983 0 : ShowContinueError(state, "...schedule values must be (>0., <=1.)");
984 0 : ErrorsFound = true;
985 : }
986 4 : } else if (lAlphaBlanks(5) && thisFurnace.fanType != HVAC::FanType::OnOff) {
987 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisFurnace.Name));
988 0 : ShowContinueError(state, format("{} = {}", cAlphaFields(7), Alphas(7)));
989 0 : ShowContinueError(state, format("Fan type must be Fan:OnOff when {} = Blank.", cAlphaFields(5)));
990 0 : ErrorsFound = true;
991 : }
992 : }
993 :
994 4 : thisFurnace.fanPlace = static_cast<HVAC::FanPlace>(getEnumValue(HVAC::fanPlaceNamesUC, Alphas(9)));
995 4 : assert(thisFurnace.fanPlace != HVAC::FanPlace::Invalid);
996 :
997 : // Get coil data
998 4 : HeatingCoilType = Alphas(10);
999 4 : HeatingCoilName = Alphas(11);
1000 4 : thisFurnace.HeatingCoilType = HeatingCoilType;
1001 4 : thisFurnace.HeatingCoilName = HeatingCoilName;
1002 4 : if (Util::SameString(HeatingCoilType, "Coil:Heating:Fuel") || Util::SameString(HeatingCoilType, "Coil:Heating:Electric")) {
1003 4 : errFlag = false;
1004 4 : thisFurnace.HeatingCoilType_Num = HeatingCoils::GetHeatingCoilTypeNum(state, HeatingCoilType, HeatingCoilName, errFlag);
1005 4 : if (errFlag) {
1006 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1007 0 : ErrorsFound = true;
1008 : } else {
1009 4 : ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject);
1010 4 : if (IsNotOK) {
1011 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1012 0 : ErrorsFound = true;
1013 :
1014 : } else { // mine data from heating coil object
1015 :
1016 : // Get index to Heating Coil
1017 4 : errFlag = false;
1018 4 : HeatingCoils::GetCoilIndex(state, HeatingCoilName, thisFurnace.HeatingCoilIndex, errFlag);
1019 4 : if (errFlag) {
1020 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1021 0 : ErrorsFound = true;
1022 : }
1023 :
1024 : // Get the furnace design capacity
1025 4 : errFlag = false;
1026 4 : thisFurnace.DesignHeatingCapacity = HeatingCoils::GetCoilCapacity(state, HeatingCoilType, HeatingCoilName, errFlag);
1027 4 : if (errFlag) {
1028 0 : ShowContinueError(state, format("...occurs in {} ={}", CurrentModuleObject, Alphas(1)));
1029 0 : ErrorsFound = true;
1030 : }
1031 :
1032 : // Get the Heating Coil Inlet Node
1033 4 : errFlag = false;
1034 4 : HeatingCoilInletNode = HeatingCoils::GetCoilInletNode(state, HeatingCoilType, HeatingCoilName, errFlag);
1035 4 : thisFurnace.HWCoilAirInletNode = HeatingCoilInletNode;
1036 4 : if (errFlag) {
1037 0 : ShowContinueError(state, format("...occurs in {} ={}", CurrentModuleObject, Alphas(1)));
1038 0 : ErrorsFound = true;
1039 : }
1040 :
1041 : // Get the Heating Coil Outlet Node
1042 4 : errFlag = false;
1043 4 : HeatingCoilOutletNode = HeatingCoils::GetCoilOutletNode(state, HeatingCoilType, HeatingCoilName, errFlag);
1044 4 : if (errFlag) {
1045 0 : ShowContinueError(state, format("...occurs in {} ={}", CurrentModuleObject, Alphas(1)));
1046 0 : ErrorsFound = true;
1047 : }
1048 :
1049 : } // IF (IsNotOK) THEN
1050 : }
1051 :
1052 0 : } else if (Util::SameString(HeatingCoilType, "Coil:Heating:Water")) {
1053 0 : thisFurnace.HeatingCoilType_Num = HVAC::Coil_HeatingWater;
1054 0 : ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject);
1055 0 : if (IsNotOK) {
1056 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1057 0 : ErrorsFound = true;
1058 : } else { // mine data from heating coil object
1059 :
1060 : // Get the Heating Coil water Inlet or control Node number
1061 0 : errFlag = false;
1062 0 : thisFurnace.CoilControlNode = WaterCoils::GetCoilWaterInletNode(state, "Coil:Heating:Water", HeatingCoilName, errFlag);
1063 0 : if (errFlag) {
1064 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1065 0 : ErrorsFound = true;
1066 : }
1067 :
1068 : // Get the Heating Coil hot water max volume flow rate
1069 0 : errFlag = false;
1070 0 : thisFurnace.MaxHeatCoilFluidFlow = WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", HeatingCoilName, errFlag);
1071 0 : if (errFlag) {
1072 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1073 0 : ErrorsFound = true;
1074 : }
1075 :
1076 : // Get the Heating Coil Inlet Node
1077 0 : errFlag = false;
1078 0 : HeatingCoilInletNode = WaterCoils::GetCoilInletNode(state, "Coil:Heating:Water", HeatingCoilName, errFlag);
1079 0 : thisFurnace.HWCoilAirInletNode = HeatingCoilInletNode;
1080 0 : if (errFlag) {
1081 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1082 0 : ErrorsFound = true;
1083 : }
1084 :
1085 : // Get the Heating Coil Outlet Node
1086 0 : errFlag = false;
1087 0 : HeatingCoilOutletNode = WaterCoils::GetCoilOutletNode(state, "Coil:Heating:Water", HeatingCoilName, errFlag);
1088 0 : thisFurnace.HWCoilAirOutletNode = HeatingCoilOutletNode;
1089 0 : if (errFlag) {
1090 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1091 0 : ErrorsFound = true;
1092 : }
1093 :
1094 : // check if user has also used a water coil controller, which they should not do
1095 0 : errFlag = false;
1096 0 : HVACControllers::CheckCoilWaterInletNode(state, thisFurnace.CoilControlNode, errFlag);
1097 0 : if (!errFlag) { // then did find a controller so that is bad
1098 0 : ShowSevereError(state,
1099 0 : format("{} = {} has a conflicting Controller:WaterCoil object", CurrentModuleObject, thisFurnace.Name));
1100 0 : ShowContinueError(state, "Hot water coils are controlled directly by unitary and furnace systems.");
1101 0 : ShowContinueError(state, "No water coil controller should be input for the coil.");
1102 0 : ErrorsFound = true;
1103 : }
1104 : }
1105 :
1106 0 : } else if (Util::SameString(HeatingCoilType, "Coil:Heating:Steam")) {
1107 0 : thisFurnace.HeatingCoilType_Num = HVAC::Coil_HeatingSteam;
1108 0 : ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject);
1109 0 : if (IsNotOK) {
1110 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1111 0 : ErrorsFound = true;
1112 : } else { // mine data from heating coil object
1113 :
1114 0 : errFlag = false;
1115 0 : thisFurnace.HeatingCoilIndex = SteamCoils::GetSteamCoilIndex(state, "COIL:HEATING:STEAM", HeatingCoilName, errFlag);
1116 0 : if (thisFurnace.HeatingCoilIndex == 0) {
1117 0 : ShowSevereError(state, format("{} illegal {} = {}", CurrentModuleObject, cAlphaFields(11), HeatingCoilName));
1118 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1119 0 : ErrorsFound = true;
1120 : }
1121 :
1122 : // Get the Heating Coil steam inlet node number
1123 0 : errFlag = false;
1124 0 : thisFurnace.CoilControlNode = SteamCoils::GetCoilSteamInletNode(state, "COIL:HEATING:STEAM", HeatingCoilName, errFlag);
1125 0 : if (errFlag) {
1126 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1127 0 : ErrorsFound = true;
1128 : }
1129 :
1130 : // Get the Heating Coil steam max volume flow rate
1131 0 : thisFurnace.MaxHeatCoilFluidFlow = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.HeatingCoilIndex, errFlag);
1132 0 : if (thisFurnace.MaxHeatCoilFluidFlow > 0.0) {
1133 0 : SteamIndex = 0; // Function GetSatDensityRefrig will look up steam index if 0 is passed
1134 0 : SteamDensity = FluidProperties::GetSatDensityRefrig(
1135 0 : state, fluidNameSteam, state.dataFurnaces->TempSteamIn, 1.0, SteamIndex, getUnitaryHeatOnly);
1136 0 : thisFurnace.MaxHeatCoilFluidFlow *= SteamDensity;
1137 : }
1138 :
1139 : // Get the Heating Coil Inlet Node
1140 0 : errFlag = false;
1141 0 : HeatingCoilInletNode = SteamCoils::GetCoilAirInletNode(state, thisFurnace.HeatingCoilIndex, HeatingCoilName, errFlag);
1142 0 : thisFurnace.HWCoilAirInletNode = HeatingCoilInletNode;
1143 0 : if (errFlag) {
1144 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1145 0 : ErrorsFound = true;
1146 : }
1147 :
1148 : // Get the Heating Coil Outlet Node
1149 0 : errFlag = false;
1150 0 : HeatingCoilOutletNode = SteamCoils::GetCoilAirOutletNode(state, thisFurnace.HeatingCoilIndex, HeatingCoilName, errFlag);
1151 0 : thisFurnace.HWCoilAirOutletNode = HeatingCoilOutletNode;
1152 0 : if (errFlag) {
1153 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1154 0 : ErrorsFound = true;
1155 : }
1156 : }
1157 :
1158 : } else {
1159 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1160 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(11), Alphas(11)));
1161 0 : ErrorsFound = true;
1162 : } // IF (Furnace(FurnaceNum)%HeatingCoilType_Num == Coil_HeatingGasOrOtherFuel .OR. &, etc.
1163 :
1164 : // Add component sets array
1165 4 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
1166 4 : CompSetFanInlet = Alphas(3);
1167 4 : CompSetFanOutlet = state.dataLoopNodes->NodeID(FanOutletNode);
1168 4 : CompSetHeatInlet = state.dataLoopNodes->NodeID(FanOutletNode);
1169 4 : CompSetHeatOutlet = Alphas(4);
1170 : // Fan inlet node name must not be the same as the furnace inlet node name
1171 4 : if (FanInletNode != thisFurnace.FurnaceInletNodeNum) {
1172 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1173 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatOnly) {
1174 0 : ShowContinueError(
1175 : state, "When a blow through fan is specified, the fan inlet node name must be the same as the furnace inlet node name.");
1176 0 : ShowContinueError(state, format("...Fan inlet node name = {}", state.dataLoopNodes->NodeID(FanInletNode)));
1177 0 : ShowContinueError(state,
1178 0 : format("...Furnace inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
1179 : } else {
1180 0 : ShowContinueError(
1181 : state,
1182 : "When a blow through fan is specified, the fan inlet node name must be the same as the unitary system inlet node name.");
1183 0 : ShowContinueError(state, format("...Fan inlet node name = {}", state.dataLoopNodes->NodeID(FanInletNode)));
1184 0 : ShowContinueError(
1185 0 : state, format("...Unitary System inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
1186 : }
1187 0 : ErrorsFound = true;
1188 : }
1189 : // Fan outlet node name must be the same as the heating coil inlet node name
1190 4 : if (FanOutletNode != HeatingCoilInletNode) {
1191 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1192 0 : ShowContinueError(
1193 : state,
1194 : "When a blow through fan is specified, the fan outlet node name must be the same as the heating coil inlet node name.");
1195 0 : ShowContinueError(state, format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
1196 0 : ShowContinueError(state, format("...Heating coil inlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
1197 0 : ErrorsFound = true;
1198 : }
1199 : // Heating coil outlet node name must be the same as the furnace outlet node name
1200 4 : if (HeatingCoilOutletNode != thisFurnace.FurnaceOutletNodeNum) {
1201 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1202 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatOnly) {
1203 0 : ShowContinueError(state,
1204 : "When a blow through fan is specified, the heating coil outlet node name must be the same as the furnace "
1205 : "outlet node name.");
1206 0 : ShowContinueError(state, format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
1207 0 : ShowContinueError(
1208 0 : state, format("...Furnace outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
1209 : } else {
1210 0 : ShowContinueError(state,
1211 : "When a blow through fan is specified, the heating coil outlet node name must be the same as the unitary "
1212 : "system outlet node name.");
1213 0 : ShowContinueError(state,
1214 0 : format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
1215 0 : ShowContinueError(
1216 0 : state, format("...UnitarySystem outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
1217 : }
1218 0 : ErrorsFound = true;
1219 : }
1220 : } else { // draw through fan
1221 0 : CompSetHeatInlet = Alphas(3);
1222 0 : CompSetHeatOutlet = state.dataLoopNodes->NodeID(FanInletNode);
1223 0 : CompSetFanInlet = state.dataLoopNodes->NodeID(FanInletNode);
1224 0 : CompSetFanOutlet = Alphas(4);
1225 : // Heating coil inlet node name must not be the same as the furnace inlet node name
1226 0 : if (HeatingCoilInletNode != thisFurnace.FurnaceInletNodeNum) {
1227 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1228 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatOnly) {
1229 0 : ShowContinueError(state,
1230 : "When a draw through fan is specified, the heating coil inlet node name must be the same as the furnace "
1231 : "inlet node name.");
1232 0 : ShowContinueError(state, format("...Heating coil inlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
1233 0 : ShowContinueError(
1234 0 : state, format("...Furnace inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
1235 : } else {
1236 0 : ShowContinueError(state,
1237 : "When a draw through fan is specified, the heating coil inlet node name must be the same as the unitary "
1238 : "system inlet node name.");
1239 0 : ShowContinueError(state, format("...Heating coil inlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
1240 0 : ShowContinueError(
1241 0 : state, format("...UnitarySystem inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
1242 : }
1243 0 : ErrorsFound = true;
1244 : }
1245 : // Heating coil outlet node name must be the same as the fan inlet node name
1246 0 : if (HeatingCoilOutletNode != FanInletNode) {
1247 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1248 0 : ShowContinueError(
1249 : state,
1250 : "When a draw through fan is specified, the heating coil outlet node name must be the same as the fan inlet node name.");
1251 0 : ShowContinueError(state, format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
1252 0 : ShowContinueError(state, format("...Fan inlet node name = {}", state.dataLoopNodes->NodeID(FanInletNode)));
1253 0 : ErrorsFound = true;
1254 : }
1255 : // Fan coil outlet node name must be the same as the furnace outlet node name
1256 0 : if (FanOutletNode != thisFurnace.FurnaceOutletNodeNum) {
1257 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1258 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatOnly) {
1259 0 : ShowContinueError(
1260 : state,
1261 : "When a draw through fan is specified, the fan outlet node name must be the same as the furnace outlet node name.");
1262 0 : ShowContinueError(state, format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
1263 0 : ShowContinueError(state,
1264 0 : format("...Furnace outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
1265 : } else {
1266 0 : ShowContinueError(state,
1267 : "When a draw through fan is specified, the fan outlet node name must be the same as the unitary system "
1268 : "outlet node name.");
1269 0 : ShowContinueError(state, format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
1270 0 : ShowContinueError(
1271 0 : state, format("...UnitarySystem outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
1272 : }
1273 0 : ErrorsFound = true;
1274 : }
1275 : }
1276 :
1277 : // Add fan to component sets array
1278 8 : BranchNodeConnections::SetUpCompSets(
1279 4 : state, CurrentModuleObject, thisFurnace.Name, Alphas(7), Alphas(8), CompSetFanInlet, CompSetFanOutlet);
1280 : // Add heating coil to component sets array
1281 8 : BranchNodeConnections::SetUpCompSets(
1282 4 : state, CurrentModuleObject, thisFurnace.Name, Alphas(10), Alphas(11), CompSetHeatInlet, CompSetHeatOutlet);
1283 :
1284 : // Set the furnace max outlet temperature
1285 4 : thisFurnace.DesignMaxOutletTemp = Numbers(1);
1286 :
1287 : // Set the furnace design fan volumetric flow rate
1288 4 : thisFurnace.DesignFanVolFlowRate = Numbers(2);
1289 :
1290 : // Compare the flow rates.
1291 4 : if (thisFurnace.ActualFanVolFlowRate != DataSizing::AutoSize && thisFurnace.DesignFanVolFlowRate != DataSizing::AutoSize) {
1292 4 : if (thisFurnace.DesignFanVolFlowRate > thisFurnace.ActualFanVolFlowRate) {
1293 0 : ShowWarningError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1294 0 : ShowContinueError(
1295 0 : state, format("... The {} > Max Volume Flow Rate defined in the associated fan object, should be <=.", cNumericFields(2)));
1296 0 : ShowContinueError(state,
1297 0 : format("... Entered value = {:.4R}... Fan [{} = {}] Max Value = {:.4R}",
1298 0 : thisFurnace.DesignFanVolFlowRate,
1299 0 : HVAC::fanTypeNames[(int)thisFurnace.fanType],
1300 : FanName,
1301 0 : thisFurnace.ActualFanVolFlowRate));
1302 0 : ShowContinueError(state, " The HVAC system flow rate is reset to the fan flow rate and the simulation continues.");
1303 0 : thisFurnace.DesignFanVolFlowRate = thisFurnace.ActualFanVolFlowRate;
1304 : }
1305 : }
1306 4 : if (thisFurnace.DesignFanVolFlowRate != DataSizing::AutoSize) {
1307 4 : if (thisFurnace.DesignFanVolFlowRate <= 0.0) {
1308 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1309 0 : ShowContinueError(state, format("... The {} <= 0.0, it must be > 0.0.", cNumericFields(2)));
1310 0 : ShowContinueError(state, format("... Entered value = {:.2R}", thisFurnace.DesignFanVolFlowRate));
1311 0 : ErrorsFound = true;
1312 : }
1313 : }
1314 :
1315 : // HeatOnly furnace has only 1 flow rate, initialize other variables used in this module
1316 4 : thisFurnace.MaxHeatAirVolFlow = thisFurnace.DesignFanVolFlowRate;
1317 4 : thisFurnace.MaxCoolAirVolFlow = thisFurnace.DesignFanVolFlowRate;
1318 4 : thisFurnace.MaxNoCoolHeatAirVolFlow = thisFurnace.DesignFanVolFlowRate;
1319 4 : thisFurnace.AirFlowControl = AirFlowControlConstFan::UseCompressorOnFlow;
1320 :
1321 : // Set heating convergence tolerance
1322 4 : thisFurnace.HeatingConvergenceTolerance = 0.001;
1323 :
1324 : // set minimum outdoor temperature for compressor operation
1325 4 : SetMinOATCompressor(state, FurnaceNum, cCurrentModuleObject, ErrorsFound);
1326 :
1327 : } // End of the HeatOnly Furnace Loop
1328 :
1329 : // Get the data for the HeatCool Furnace or UnitarySystem
1330 278 : for (int HeatCoolNum = 1; HeatCoolNum <= NumHeatCool + NumUnitaryHeatCool; ++HeatCoolNum) {
1331 :
1332 181 : FanInletNode = 0;
1333 181 : FanOutletNode = 0;
1334 181 : CoolingCoilInletNode = 0;
1335 181 : CoolingCoilOutletNode = 0;
1336 181 : HeatingCoilInletNode = 0;
1337 181 : HeatingCoilOutletNode = 0;
1338 181 : int ReheatCoilInletNode = 0;
1339 181 : int ReheatCoilOutletNode = 0;
1340 181 : CoolingCoilType = ' ';
1341 181 : CoolingCoilName = ' ';
1342 181 : HeatingCoilType = ' ';
1343 181 : HeatingCoilName = ' ';
1344 :
1345 181 : FurnaceNum = HeatCoolNum + NumHeatOnly + NumUnitaryHeatOnly;
1346 181 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
1347 :
1348 : // Furnace and UnitarySystem objects are both read in here.
1349 : // Will still have 2 differently named objects for the user, but read in with 1 DO loop.
1350 181 : if (HeatCoolNum <= NumHeatCool) {
1351 108 : CurrentModuleObject = "AirLoopHVAC:Unitary:Furnace:HeatCool";
1352 108 : currentModuleObjectType = DataLoopNode::ConnectionObjectType::AirLoopHVACUnitaryFurnaceHeatCool;
1353 108 : thisFurnace.type = HVAC::UnitarySysType::Furnace_HeatCool;
1354 108 : GetObjectNum = HeatCoolNum;
1355 : } else {
1356 73 : CurrentModuleObject = "AirLoopHVAC:UnitaryHeatCool";
1357 73 : currentModuleObjectType = DataLoopNode::ConnectionObjectType::AirLoopHVACUnitaryHeatCool;
1358 73 : thisFurnace.type = HVAC::UnitarySysType::Unitary_HeatCool;
1359 73 : GetObjectNum = HeatCoolNum - NumHeatCool;
1360 : }
1361 :
1362 181 : thisFurnace.iterationMode.allocate(3);
1363 :
1364 181 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1365 : CurrentModuleObject,
1366 : GetObjectNum,
1367 : Alphas,
1368 : NumAlphas,
1369 : Numbers,
1370 : NumNumbers,
1371 : IOStatus,
1372 : lNumericBlanks,
1373 : lAlphaBlanks,
1374 : cAlphaFields,
1375 : cNumericFields);
1376 :
1377 362 : GlobalNames::VerifyUniqueInterObjectName(
1378 181 : state, state.dataFurnaces->UniqueFurnaceNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
1379 :
1380 181 : thisFurnace.Name = Alphas(1);
1381 :
1382 181 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, thisFurnace.Name};
1383 :
1384 181 : if (lAlphaBlanks(2)) {
1385 58 : thisFurnace.SchedPtr = ScheduleManager::ScheduleAlwaysOn;
1386 : } else {
1387 123 : thisFurnace.SchedPtr = ScheduleManager::GetScheduleIndex(state, Alphas(2));
1388 123 : if (thisFurnace.SchedPtr == 0) {
1389 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1390 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(2), Alphas(2)));
1391 0 : ErrorsFound = true;
1392 : }
1393 : }
1394 :
1395 181 : thisFurnace.FurnaceInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
1396 181 : Alphas(3),
1397 : ErrorsFound,
1398 : currentModuleObjectType,
1399 181 : Alphas(1),
1400 : DataLoopNode::NodeFluidType::Air,
1401 : DataLoopNode::ConnectionType::Inlet,
1402 : NodeInputManager::CompFluidStream::Primary,
1403 : DataLoopNode::ObjectIsParent);
1404 181 : thisFurnace.FurnaceOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
1405 181 : Alphas(4),
1406 : ErrorsFound,
1407 : currentModuleObjectType,
1408 181 : Alphas(1),
1409 : DataLoopNode::NodeFluidType::Air,
1410 : DataLoopNode::ConnectionType::Outlet,
1411 : NodeInputManager::CompFluidStream::Primary,
1412 : DataLoopNode::ObjectIsParent);
1413 :
1414 181 : BranchNodeConnections::TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(3), Alphas(4), "Air Nodes");
1415 :
1416 181 : thisFurnace.FanSchedPtr = ScheduleManager::GetScheduleIndex(state, Alphas(5));
1417 181 : if (!lAlphaBlanks(5) && thisFurnace.FanSchedPtr == 0) {
1418 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1419 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(5), Alphas(5)));
1420 0 : ErrorsFound = true;
1421 181 : } else if (lAlphaBlanks(5)) {
1422 20 : thisFurnace.fanOp = HVAC::FanOp::Cycling;
1423 : }
1424 :
1425 : // Get the Controlling Zone or Location of the Furnace Thermostat
1426 181 : thisFurnace.ControlZoneNum = Util::FindItemInList(Alphas(6), state.dataHeatBal->Zone);
1427 181 : if (thisFurnace.ControlZoneNum == 0) {
1428 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1429 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(6), Alphas(6)));
1430 0 : ErrorsFound = true;
1431 : }
1432 :
1433 : // Get the node number for the zone with the thermostat
1434 181 : if (thisFurnace.ControlZoneNum > 0) {
1435 181 : AirNodeFound = false;
1436 181 : AirLoopFound = false;
1437 181 : int ControlledZoneNum = thisFurnace.ControlZoneNum;
1438 : // Find the controlled zone number for the specified thermostat location
1439 181 : thisFurnace.NodeNumOfControlledZone = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneNode;
1440 : // Determine if system is on air loop served by the thermostat location specified
1441 186 : for (int zoneInNode = 1; zoneInNode <= state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumInletNodes; ++zoneInNode) {
1442 186 : int AirLoopNumber = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNodeAirLoopNum(zoneInNode);
1443 186 : if (AirLoopNumber > 0) {
1444 191 : for (int BranchNum = 1; BranchNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).NumBranches; ++BranchNum) {
1445 354 : for (int CompNum = 1;
1446 354 : CompNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).TotalComponents;
1447 : ++CompNum) {
1448 349 : if (!Util::SameString(state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).Name,
1449 879 : Alphas(1)) ||
1450 181 : !Util::SameString(
1451 181 : state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).TypeOf,
1452 : CurrentModuleObject))
1453 168 : continue;
1454 181 : AirLoopFound = true;
1455 181 : thisFurnace.ZoneInletNode = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNode(zoneInNode);
1456 181 : break;
1457 : }
1458 186 : if (AirLoopFound) break;
1459 : }
1460 2184 : for (TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumTempControlledZones; ++TstatZoneNum) {
1461 1998 : if (state.dataZoneCtrls->TempControlledZone(TstatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) continue;
1462 186 : AirNodeFound = true;
1463 : }
1464 187 : for (TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumComfortControlledZones; ++TstatZoneNum) {
1465 1 : if (state.dataZoneCtrls->ComfortControlledZone(TstatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) continue;
1466 1 : AirNodeFound = true;
1467 : }
1468 : }
1469 186 : if (AirLoopFound) break;
1470 : }
1471 181 : if (!AirNodeFound) {
1472 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1473 0 : ShowContinueError(state, "Did not find air node (zone with thermostat).");
1474 0 : ShowContinueError(state, format("Specified {} = {}", cAlphaFields(6), Alphas(6)));
1475 0 : ShowContinueError(
1476 : state, "Both a ZoneHVAC:EquipmentConnections object and a ZoneControl:Thermostat object must be specified for this zone.");
1477 0 : ErrorsFound = true;
1478 : }
1479 181 : if (!AirLoopFound) {
1480 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1481 0 : ShowContinueError(state, "Did not find correct AirLoopHVAC.");
1482 0 : ShowContinueError(state, format("Specified {} = {}", cAlphaFields(6), Alphas(6)));
1483 0 : ErrorsFound = true;
1484 : }
1485 : }
1486 :
1487 : // Get fan data
1488 181 : FanName = Alphas(8);
1489 :
1490 181 : thisFurnace.fanType = static_cast<HVAC::FanType>(getEnumValue(HVAC::fanTypeNamesUC, Alphas(7)));
1491 :
1492 181 : if (thisFurnace.fanType != HVAC::FanType::OnOff && thisFurnace.fanType != HVAC::FanType::Constant) {
1493 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1494 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(7), Alphas(7)));
1495 0 : ErrorsFound = true;
1496 :
1497 181 : } else if ((thisFurnace.FanIndex = Fans::GetFanIndex(state, FanName)) == 0) {
1498 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(8), FanName);
1499 0 : ErrorsFound = true;
1500 :
1501 : } else {
1502 181 : auto *fan = state.dataFans->fans(thisFurnace.FanIndex);
1503 181 : thisFurnace.ActualFanVolFlowRate = fan->maxAirFlowRate;
1504 181 : FanInletNode = fan->inletNodeNum;
1505 181 : FanOutletNode = fan->outletNodeNum;
1506 181 : thisFurnace.FanAvailSchedPtr = fan->availSchedNum;
1507 :
1508 : // Check fan's schedule for cycling fan operation if constant volume fan is used
1509 181 : if (thisFurnace.FanSchedPtr > 0 && thisFurnace.fanType == HVAC::FanType::Constant) {
1510 5 : if (!ScheduleManager::CheckScheduleValueMinMax(
1511 : state, thisFurnace.FanSchedPtr, ScheduleManager::Clusivity::Exclusive, 0.0, ScheduleManager::Clusivity::Inclusive, 1.0)) {
1512 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1513 0 : ShowContinueError(state, format("For {} = {}", cAlphaFields(7), Alphas(7)));
1514 0 : ShowContinueError(state, "Fan operating mode must be continuous (fan operating mode schedule values > 0).");
1515 0 : ShowContinueError(state, format("Error found in {} = {}", cAlphaFields(5), Alphas(5)));
1516 0 : ShowContinueError(state, "...schedule values must be (>0., <=1.)");
1517 0 : ErrorsFound = true;
1518 : }
1519 176 : } else if (lAlphaBlanks(5) && thisFurnace.fanType != HVAC::FanType::OnOff) {
1520 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisFurnace.Name));
1521 0 : ShowContinueError(state, format("{} = {}", cAlphaFields(7), Alphas(7)));
1522 0 : ShowContinueError(state, format("Fan type must be Fan:OnOff when {} = Blank.", cAlphaFields(5)));
1523 0 : ErrorsFound = true;
1524 : }
1525 : }
1526 :
1527 181 : thisFurnace.fanPlace = static_cast<HVAC::FanPlace>(getEnumValue(HVAC::fanPlaceNamesUC, Alphas(9)));
1528 181 : assert(thisFurnace.fanPlace != HVAC::FanPlace::Invalid);
1529 :
1530 : // Get coil data
1531 181 : HeatingCoilType = Alphas(10);
1532 181 : HeatingCoilName = Alphas(11);
1533 181 : HeatingCoilPLFCurveIndex = 0;
1534 181 : thisFurnace.HeatingCoilType = HeatingCoilType;
1535 181 : thisFurnace.HeatingCoilName = HeatingCoilName;
1536 181 : if (Util::SameString(HeatingCoilType, "Coil:Heating:Fuel") || Util::SameString(HeatingCoilType, "Coil:Heating:Electric")) {
1537 181 : errFlag = false;
1538 181 : thisFurnace.HeatingCoilType_Num = HeatingCoils::GetHeatingCoilTypeNum(state, HeatingCoilType, HeatingCoilName, errFlag);
1539 181 : if (errFlag) {
1540 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1541 0 : ErrorsFound = true;
1542 : } else {
1543 :
1544 181 : ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject);
1545 181 : if (IsNotOK) {
1546 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1547 0 : ErrorsFound = true;
1548 :
1549 : } else { // mine data from heating coil
1550 :
1551 : // Get heating coil index
1552 181 : errFlag = false;
1553 181 : HeatingCoils::GetCoilIndex(state, HeatingCoilName, thisFurnace.HeatingCoilIndex, errFlag);
1554 181 : if (errFlag) {
1555 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1556 0 : ErrorsFound = true;
1557 : }
1558 :
1559 : // Get the design heating capacity
1560 181 : errFlag = false;
1561 181 : thisFurnace.DesignHeatingCapacity = HeatingCoils::GetCoilCapacity(state, HeatingCoilType, HeatingCoilName, errFlag);
1562 181 : if (errFlag) {
1563 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1564 0 : ErrorsFound = true;
1565 : }
1566 :
1567 : // Get the Heating Coil Inlet Node
1568 181 : errFlag = false;
1569 181 : HeatingCoilInletNode = HeatingCoils::GetCoilInletNode(state, HeatingCoilType, HeatingCoilName, errFlag);
1570 181 : if (errFlag) {
1571 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1572 0 : ErrorsFound = true;
1573 : }
1574 :
1575 : // Get the Heating Coil Outlet Node
1576 181 : errFlag = false;
1577 181 : HeatingCoilOutletNode = HeatingCoils::GetCoilOutletNode(state, HeatingCoilType, HeatingCoilName, errFlag);
1578 181 : if (errFlag) {
1579 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1580 0 : ErrorsFound = true;
1581 : }
1582 :
1583 : // Get the Heating Coil PLF Curve Index
1584 181 : errFlag = false;
1585 181 : HeatingCoilPLFCurveIndex = HeatingCoils::GetHeatingCoilPLFCurveIndex(state, HeatingCoilType, HeatingCoilName, errFlag);
1586 181 : if (errFlag) {
1587 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1588 0 : ErrorsFound = true;
1589 : }
1590 :
1591 : } // IF (IsNotOK) THEN
1592 : }
1593 :
1594 0 : } else if (Util::SameString(HeatingCoilType, "Coil:Heating:Water")) {
1595 0 : thisFurnace.HeatingCoilType_Num = HVAC::Coil_HeatingWater;
1596 0 : ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject);
1597 0 : if (IsNotOK) {
1598 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1599 0 : ErrorsFound = true;
1600 : } else { // mine data from heating coil object
1601 :
1602 : // Get the Heating Coil water Inlet or control Node number
1603 0 : errFlag = false;
1604 0 : thisFurnace.CoilControlNode = WaterCoils::GetCoilWaterInletNode(state, "Coil:Heating:Water", HeatingCoilName, errFlag);
1605 0 : if (errFlag) {
1606 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1607 0 : ErrorsFound = true;
1608 : }
1609 :
1610 : // Get the Heating Coil hot water max volume flow rate
1611 0 : errFlag = false;
1612 0 : thisFurnace.MaxHeatCoilFluidFlow = WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", HeatingCoilName, errFlag);
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 Inlet Node
1619 0 : errFlag = false;
1620 0 : HeatingCoilInletNode = WaterCoils::GetCoilInletNode(state, "Coil:Heating:Water", HeatingCoilName, errFlag);
1621 0 : thisFurnace.HWCoilAirInletNode = HeatingCoilInletNode;
1622 0 : if (errFlag) {
1623 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1624 0 : ErrorsFound = true;
1625 : }
1626 :
1627 : // Get the Heating Coil Outlet Node
1628 0 : errFlag = false;
1629 0 : HeatingCoilOutletNode = WaterCoils::GetCoilOutletNode(state, "Coil:Heating:Water", HeatingCoilName, errFlag);
1630 0 : thisFurnace.HWCoilAirOutletNode = HeatingCoilOutletNode;
1631 0 : if (errFlag) {
1632 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1633 0 : ErrorsFound = true;
1634 : }
1635 :
1636 : // check if user has also used a water coil controller, which they should not do
1637 0 : errFlag = false;
1638 0 : HVACControllers::CheckCoilWaterInletNode(state, thisFurnace.CoilControlNode, errFlag);
1639 0 : if (!errFlag) { // then did find a controller so that is bad
1640 0 : ShowSevereError(state,
1641 0 : format("{} = {} has a conflicting Controller:WaterCoil object", CurrentModuleObject, thisFurnace.Name));
1642 0 : ShowContinueError(state, "Hot water coils are controlled directly by unitary and furnace systems.");
1643 0 : ShowContinueError(state, "No water coil controller should be input for the coil.");
1644 0 : ErrorsFound = true;
1645 : }
1646 : }
1647 :
1648 0 : } else if (Util::SameString(HeatingCoilType, "Coil:Heating:Steam")) {
1649 0 : thisFurnace.HeatingCoilType_Num = HVAC::Coil_HeatingSteam;
1650 0 : ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject);
1651 0 : if (IsNotOK) {
1652 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1653 0 : ErrorsFound = true;
1654 : } else { // mine data from heating coil object
1655 :
1656 0 : errFlag = false;
1657 0 : thisFurnace.HeatingCoilIndex = SteamCoils::GetSteamCoilIndex(state, "COIL:HEATING:STEAM", HeatingCoilName, errFlag);
1658 0 : if (thisFurnace.HeatingCoilIndex == 0) {
1659 0 : ShowSevereError(state, format("{} illegal {} = {}", CurrentModuleObject, cAlphaFields(11), HeatingCoilName));
1660 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1661 0 : ErrorsFound = true;
1662 : }
1663 :
1664 : // Get the Heating Coil steam inlet node number
1665 0 : errFlag = false;
1666 0 : thisFurnace.CoilControlNode = SteamCoils::GetCoilSteamInletNode(state, "Coil:Heating:Steam", HeatingCoilName, errFlag);
1667 0 : if (errFlag) {
1668 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1669 0 : ErrorsFound = true;
1670 : }
1671 :
1672 : // Get the Heating Coil steam max volume flow rate
1673 0 : thisFurnace.MaxHeatCoilFluidFlow = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.HeatingCoilIndex, errFlag);
1674 0 : if (thisFurnace.MaxHeatCoilFluidFlow > 0.0) {
1675 0 : SteamIndex = 0; // Function GetSatDensityRefrig will look up steam index if 0 is passed
1676 0 : SteamDensity = FluidProperties::GetSatDensityRefrig(
1677 0 : state, fluidNameSteam, state.dataFurnaces->TempSteamIn, 1.0, SteamIndex, getAirLoopHVACHeatCoolInput);
1678 0 : thisFurnace.MaxHeatCoilFluidFlow *= SteamDensity;
1679 : }
1680 :
1681 : // Get the Heating Coil Inlet Node
1682 0 : errFlag = false;
1683 0 : HeatingCoilInletNode = SteamCoils::GetCoilAirInletNode(state, thisFurnace.HeatingCoilIndex, HeatingCoilName, errFlag);
1684 0 : thisFurnace.HWCoilAirInletNode = HeatingCoilInletNode;
1685 0 : if (errFlag) {
1686 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1687 0 : ErrorsFound = true;
1688 : }
1689 :
1690 : // Get the Heating Coil Outlet Node
1691 0 : errFlag = false;
1692 0 : HeatingCoilOutletNode = SteamCoils::GetCoilAirOutletNode(state, thisFurnace.HeatingCoilIndex, HeatingCoilName, errFlag);
1693 0 : thisFurnace.HWCoilAirOutletNode = HeatingCoilOutletNode;
1694 0 : if (errFlag) {
1695 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
1696 0 : ErrorsFound = true;
1697 : }
1698 : }
1699 :
1700 : } else {
1701 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1702 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(11), Alphas(11)));
1703 0 : ErrorsFound = true;
1704 : } // IF (Furnace(FurnaceNum)%HeatingCoilType_Num == Coil_HeatingGasOrOtherFuel .OR. &, etc.
1705 :
1706 : // Get Cooling Coil Information if available
1707 181 : CoolingCoilType = Alphas(12);
1708 181 : CoolingCoilName = Alphas(13);
1709 : // Find the type of coil. Do not print message since this may not be the correct coil type.
1710 181 : errFlag = false;
1711 181 : PrintMessage = false;
1712 :
1713 358 : if (Util::SameString(CoolingCoilType, "COIL:COOLING:DX:VARIABLESPEED") ||
1714 358 : Util::SameString(CoolingCoilType, "COILSYSTEM:INTEGRATEDHEATPUMP:AIRSOURCE")) {
1715 4 : thisFurnace.CoolingCoilType_Num = HVAC::Coil_CoolingAirToAirVariableSpeed;
1716 4 : if (Util::SameString(CoolingCoilType, "COILSYSTEM:INTEGRATEDHEATPUMP:AIRSOURCE")) thisFurnace.bIsIHP = true;
1717 : } else {
1718 177 : thisFurnace.CoolingCoilType_Num = DXCoils::GetCoilTypeNum(state, CoolingCoilType, CoolingCoilName, errFlag, PrintMessage);
1719 : }
1720 :
1721 : // If coil type not found, check to see if a HX assisted cooling coil is used.
1722 181 : if (thisFurnace.CoolingCoilType_Num == 0) {
1723 3 : errFlag = false;
1724 3 : thisFurnace.CoolingCoilType_Num =
1725 3 : HVACHXAssistedCoolingCoil::GetCoilGroupTypeNum(state, CoolingCoilType, CoolingCoilName, errFlag, PrintMessage);
1726 : }
1727 :
1728 181 : if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingSingleSpeed) {
1729 174 : ValidateComponent(state, CoolingCoilType, CoolingCoilName, IsNotOK, CurrentModuleObject);
1730 174 : if (IsNotOK) {
1731 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1732 0 : ErrorsFound = true;
1733 :
1734 : } else { // mine data from DX cooling coil
1735 :
1736 : // Get DX cooling coil index
1737 174 : DXCoils::GetDXCoilIndex(state, CoolingCoilName, thisFurnace.CoolingCoilIndex, IsNotOK);
1738 174 : if (IsNotOK) {
1739 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1740 0 : ErrorsFound = true;
1741 : }
1742 :
1743 : // Get DX cooling coil capacity
1744 174 : errFlag = false;
1745 174 : thisFurnace.DesignCoolingCapacity = DXCoils::GetCoilCapacity(state, CoolingCoilType, CoolingCoilName, errFlag);
1746 174 : if (errFlag) {
1747 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1748 0 : ErrorsFound = true;
1749 : }
1750 :
1751 : // Get the Cooling Coil Nodes
1752 174 : errFlag = false;
1753 174 : CoolingCoilInletNode = DXCoils::GetCoilInletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
1754 174 : CoolingCoilOutletNode = DXCoils::GetCoilOutletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
1755 174 : if (errFlag) {
1756 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1757 0 : ErrorsFound = true;
1758 : }
1759 :
1760 : // Get outdoor condenser node from DX coil object
1761 174 : errFlag = false;
1762 174 : if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) {
1763 0 : if (thisFurnace.bIsIHP) {
1764 0 : IHPCoilIndex = IntegratedHeatPump::GetCoilIndexIHP(state, CoolingCoilType, CoolingCoilName, errFlag);
1765 0 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(IHPCoilIndex).SCCoilName;
1766 0 : thisFurnace.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, IHPCoilName, errFlag);
1767 : } else {
1768 0 : thisFurnace.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, CoolingCoilName, errFlag);
1769 : }
1770 : } else {
1771 174 : thisFurnace.CondenserNodeNum = DXCoils::GetCoilCondenserInletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
1772 : }
1773 174 : if (errFlag) {
1774 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1775 0 : ErrorsFound = true;
1776 : }
1777 :
1778 : } // IF (IsNotOK) THEN
1779 :
1780 : // Push heating coil PLF curve index to DX coil
1781 174 : if (HeatingCoilPLFCurveIndex > 0) {
1782 48 : DXCoils::SetDXCoolingCoilData(state, thisFurnace.CoolingCoilIndex, ErrorsFound, HeatingCoilPLFCurveIndex);
1783 : }
1784 :
1785 7 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) {
1786 3 : ValidateComponent(state, CoolingCoilType, CoolingCoilName, IsNotOK, CurrentModuleObject);
1787 3 : if (IsNotOK) {
1788 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1789 0 : ErrorsFound = true;
1790 :
1791 : } else { // mine data from heat exchanger assisted cooling coil
1792 :
1793 : // Get DX heat exchanger assisted cooling coil index
1794 3 : HVACHXAssistedCoolingCoil::GetHXDXCoilIndex(state, CoolingCoilName, thisFurnace.CoolingCoilIndex, IsNotOK);
1795 3 : if (IsNotOK) {
1796 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1797 0 : ErrorsFound = true;
1798 : }
1799 :
1800 : // Get DX cooling coil capacity
1801 3 : errFlag = false;
1802 3 : thisFurnace.DesignCoolingCapacity = HVACHXAssistedCoolingCoil::GetCoilCapacity(state, CoolingCoilType, CoolingCoilName, errFlag);
1803 3 : if (errFlag) {
1804 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1805 0 : ErrorsFound = true;
1806 : }
1807 :
1808 : // Get the Cooling Coil Nodes
1809 3 : errFlag = false;
1810 3 : CoolingCoilInletNode = HVACHXAssistedCoolingCoil::GetCoilInletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
1811 3 : CoolingCoilOutletNode = HVACHXAssistedCoolingCoil::GetCoilOutletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
1812 3 : if (errFlag) {
1813 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1814 0 : ErrorsFound = true;
1815 : }
1816 :
1817 : // Get outdoor condenser node from heat exchanger assisted DX coil object
1818 3 : errFlag = false;
1819 3 : std::string ChildCoolingCoilName = HVACHXAssistedCoolingCoil::GetHXDXCoilName(state, CoolingCoilType, CoolingCoilName, IsNotOK);
1820 3 : std::string ChildCoolingCoilType = HVACHXAssistedCoolingCoil::GetHXDXCoilType(state, CoolingCoilType, CoolingCoilName, IsNotOK);
1821 3 : if (IsNotOK) {
1822 0 : ShowContinueError(state, format("Occurs in {} = {}", cCurrentModuleObject, Alphas(1)));
1823 0 : ErrorsFound = true;
1824 : }
1825 :
1826 : // if (thisFurnace.CoolingCoilType_Num == CoilDX_CoolingHXAssisted) {
1827 3 : if (Util::SameString(ChildCoolingCoilType, "COIL:COOLING:DX")) {
1828 :
1829 1 : int childCCIndex = CoilCoolingDX::factory(state, ChildCoolingCoilName);
1830 1 : if (childCCIndex < 0) {
1831 0 : ShowContinueError(state, format("Occurs in {} = {}", cCurrentModuleObject, Alphas(1)));
1832 0 : errFlag = true;
1833 0 : ErrorsFound = true;
1834 : }
1835 1 : auto const &newCoil = state.dataCoilCooingDX->coilCoolingDXs[childCCIndex];
1836 :
1837 1 : thisFurnace.CondenserNodeNum = newCoil.condInletNodeIndex;
1838 :
1839 : }
1840 : // else if (thisFurnace.CoolingCoilType_Num == Coil_CoolingAirToAirVariableSpeed) {
1841 2 : else if (Util::SameString(ChildCoolingCoilType, "Coil:Cooling:DX:VariableSpeed")) {
1842 0 : if (thisFurnace.bIsIHP) {
1843 0 : IHPCoilIndex = IntegratedHeatPump::GetCoilIndexIHP(state, CoolingCoilType, CoolingCoilName, errFlag);
1844 0 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(IHPCoilIndex).SCCoilName;
1845 0 : thisFurnace.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, IHPCoilName, errFlag);
1846 : } else {
1847 0 : thisFurnace.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, CoolingCoilName, errFlag);
1848 : }
1849 : } else {
1850 2 : thisFurnace.CondenserNodeNum = DXCoils::GetCoilCondenserInletNode(
1851 : state,
1852 : "COIL:COOLING:DX:SINGLESPEED",
1853 4 : HVACHXAssistedCoolingCoil::GetHXDXCoilName(state, CoolingCoilType, CoolingCoilName, errFlag),
1854 : errFlag);
1855 : }
1856 :
1857 3 : if (errFlag) {
1858 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1859 0 : ErrorsFound = true;
1860 : }
1861 :
1862 : // Push heating coil PLF curve index to DX coil
1863 3 : if (HeatingCoilPLFCurveIndex > 0) {
1864 : // get the actual index to the DX cooling coil object
1865 0 : DXCoilIndex = HVACHXAssistedCoolingCoil::GetActualDXCoilIndex(state, CoolingCoilType, CoolingCoilName, ErrorsFound);
1866 0 : thisFurnace.ActualDXCoilIndexForHXAssisted = DXCoilIndex;
1867 : int ActualCoolCoilType =
1868 0 : HVACHXAssistedCoolingCoil::GetCoilObjectTypeNum(state, CoolingCoilType, CoolingCoilName, errFlag, true);
1869 0 : if (ActualCoolCoilType == HVAC::CoilDX_CoolingSingleSpeed) {
1870 0 : DXCoils::SetDXCoolingCoilData(state, DXCoilIndex, ErrorsFound, HeatingCoilPLFCurveIndex);
1871 : }
1872 : // what could we do for VS coil here? odd thing here
1873 : }
1874 :
1875 3 : } // IF (IsNotOK) THEN
1876 4 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) {
1877 : // BOS ADDED, AUG/2012, VARIIABLE SPEED DX COOLING COIL
1878 : // Furnace(FurnaceNum)%DXCoolCoilType = 'COIL:COOLING:DX:VARIABLESPEED'
1879 : // Furnace(FurnaceNum)%DXCoolCoilName = CoolingCoilName
1880 4 : if (Util::SameString(CoolingCoilType, "COILSYSTEM:INTEGRATEDHEATPUMP:AIRSOURCE")) thisFurnace.bIsIHP = true;
1881 4 : ValidateComponent(state, CoolingCoilType, CoolingCoilName, IsNotOK, CurrentModuleObject);
1882 :
1883 4 : if (IsNotOK) {
1884 0 : ShowContinueError(state, format("...specified in {}=\"{}\".", CurrentModuleObject, Alphas(1)));
1885 0 : ErrorsFound = true;
1886 : } else {
1887 4 : errFlag = false;
1888 4 : if (thisFurnace.bIsIHP) {
1889 0 : thisFurnace.CoolingCoilIndex = IntegratedHeatPump::GetCoilIndexIHP(state, CoolingCoilType, CoolingCoilName, errFlag);
1890 0 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SCCoilName;
1891 : } else {
1892 4 : thisFurnace.CoolingCoilIndex =
1893 4 : VariableSpeedCoils::GetCoilIndexVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
1894 4 : IHPCoilName = CoolingCoilName;
1895 : }
1896 :
1897 4 : if (errFlag) {
1898 0 : ShowContinueError(state, format("...specified in {}=\"{}\".", CurrentModuleObject, Alphas(1)));
1899 0 : ErrorsFound = true;
1900 : }
1901 :
1902 4 : if (thisFurnace.bIsIHP) {
1903 : CoolingCoilInletNode =
1904 0 : VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, "COIL:COOLING:DX:VARIABLESPEED", IHPCoilName, errFlag);
1905 : CoolingCoilOutletNode =
1906 0 : VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, "COIL:COOLING:DX:VARIABLESPEED", IHPCoilName, errFlag);
1907 0 : thisFurnace.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, IHPCoilName, errFlag);
1908 : } else {
1909 4 : CoolingCoilInletNode = VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
1910 4 : CoolingCoilOutletNode = VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
1911 4 : thisFurnace.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, CoolingCoilName, errFlag);
1912 : }
1913 :
1914 4 : if (errFlag) {
1915 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
1916 0 : ErrorsFound = true;
1917 : }
1918 : }
1919 : } else {
1920 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1921 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(12), Alphas(12)));
1922 0 : ErrorsFound = true;
1923 : }
1924 :
1925 181 : if (Util::SameString(Alphas(14), "None") || Util::SameString(Alphas(14), "Multimode") || Util::SameString(Alphas(14), "CoolReheat")) {
1926 181 : AirNodeFound = false;
1927 181 : if (Util::SameString(Alphas(14), "Multimode")) {
1928 3 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::Multimode;
1929 3 : thisFurnace.Humidistat = true;
1930 3 : if (thisFurnace.CoolingCoilType_Num != HVAC::CoilDX_CoolingHXAssisted) {
1931 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1932 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(14), Alphas(14)));
1933 0 : ShowContinueError(state, "Multimode control must be used with a Heat Exchanger Assisted Cooling Coil.");
1934 0 : if (lAlphaBlanks(15)) {
1935 0 : ShowContinueError(state,
1936 : "Dehumidification control type is assumed to be None since a reheat coil has not been specified and "
1937 : "the simulation continues.");
1938 0 : thisFurnace.Humidistat = false;
1939 0 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::None;
1940 : } else {
1941 0 : ShowContinueError(state, "Dehumidification control type is assumed to be CoolReheat and the simulation continues.");
1942 0 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::CoolReheat;
1943 : }
1944 : }
1945 : }
1946 181 : if (Util::SameString(Alphas(14), "CoolReheat")) {
1947 22 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::CoolReheat;
1948 22 : thisFurnace.Humidistat = true;
1949 22 : if (lAlphaBlanks(15)) {
1950 0 : ShowWarningError(state, format("{} \"{}\"", CurrentModuleObject, Alphas(1)));
1951 0 : ShowContinueError(state,
1952 : "Dehumidification control type is assumed to be None since a reheat coil has not been specified and the "
1953 : "simulation continues.");
1954 0 : thisFurnace.Humidistat = false;
1955 0 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::None;
1956 : }
1957 : }
1958 181 : if (Util::SameString(Alphas(14), "None")) {
1959 156 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::None;
1960 156 : thisFurnace.Humidistat = false;
1961 : }
1962 181 : if (thisFurnace.Humidistat) {
1963 62 : for (HStatZoneNum = 1; HStatZoneNum <= state.dataZoneCtrls->NumHumidityControlZones; ++HStatZoneNum) {
1964 37 : if (state.dataZoneCtrls->HumidityControlZone(HStatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) continue;
1965 25 : AirNodeFound = true;
1966 : }
1967 25 : if (!AirNodeFound) {
1968 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1969 0 : ShowContinueError(state, "Did not find Air Node (Zone with Humidistat).");
1970 0 : ShowContinueError(state, format("Specified {} = {}", cAlphaFields(6), Alphas(6)));
1971 0 : ErrorsFound = true;
1972 : }
1973 : }
1974 : } else { // invalid input
1975 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
1976 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(14), Alphas(14)));
1977 0 : thisFurnace.Humidistat = false;
1978 0 : ErrorsFound = true;
1979 : }
1980 :
1981 : // Check placement of cooling coil with respect to fan placement and dehumidification control type
1982 181 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
1983 178 : if (FanOutletNode == HeatingCoilInletNode && thisFurnace.DehumidControlType_Num != DehumidificationControlMode::CoolReheat) {
1984 102 : thisFurnace.CoolingCoilUpstream = false;
1985 : }
1986 : } else {
1987 3 : if (HeatingCoilOutletNode == CoolingCoilInletNode && thisFurnace.DehumidControlType_Num != DehumidificationControlMode::CoolReheat) {
1988 2 : thisFurnace.CoolingCoilUpstream = false;
1989 : }
1990 : }
1991 :
1992 : // Get reheat coil data if humidistat is used
1993 181 : ReheatingCoilType = Alphas(15);
1994 181 : ReheatingCoilName = Alphas(16);
1995 181 : thisFurnace.SuppHeatCoilType = ReheatingCoilType;
1996 181 : thisFurnace.SuppHeatCoilName = ReheatingCoilName;
1997 181 : errFlag = false;
1998 181 : if (!lAlphaBlanks(15)) {
1999 25 : if (Util::SameString(ReheatingCoilType, "Coil:Heating:Fuel") || Util::SameString(ReheatingCoilType, "Coil:Heating:Electric") ||
2000 25 : Util::SameString(ReheatingCoilType, "Coil:Heating:Desuperheater")) {
2001 :
2002 23 : thisFurnace.SuppHeatCoilType_Num = HeatingCoils::GetHeatingCoilTypeNum(state, ReheatingCoilType, ReheatingCoilName, errFlag);
2003 23 : if (errFlag) {
2004 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2005 0 : ErrorsFound = true;
2006 : } else {
2007 :
2008 23 : ValidateComponent(state, ReheatingCoilType, ReheatingCoilName, IsNotOK, CurrentModuleObject);
2009 23 : if (IsNotOK) {
2010 0 : ShowContinueError(state, format("In {} \"{}\"", CurrentModuleObject, Alphas(1)));
2011 0 : ErrorsFound = true;
2012 :
2013 : } else { // mine data from reheat coil
2014 :
2015 : // Get the heating coil index
2016 23 : HeatingCoils::GetCoilIndex(state, ReheatingCoilName, thisFurnace.SuppHeatCoilIndex, IsNotOK);
2017 23 : if (IsNotOK) {
2018 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2019 0 : ErrorsFound = true;
2020 : }
2021 :
2022 : // Get the design supplemental heating capacity
2023 23 : errFlag = false;
2024 23 : thisFurnace.DesignSuppHeatingCapacity =
2025 23 : HeatingCoils::GetCoilCapacity(state, ReheatingCoilType, ReheatingCoilName, errFlag);
2026 23 : if (errFlag) {
2027 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2028 0 : ErrorsFound = true;
2029 : }
2030 :
2031 : // Get the Reheat Coil Inlet Node
2032 23 : errFlag = false;
2033 23 : ReheatCoilInletNode = HeatingCoils::GetCoilInletNode(state, ReheatingCoilType, ReheatingCoilName, errFlag);
2034 23 : if (errFlag) {
2035 0 : ShowContinueError(state, format("...occurs in {} \"{}\"", CurrentModuleObject, Alphas(1)));
2036 0 : ErrorsFound = true;
2037 : }
2038 :
2039 : // Get the Reheat Coil Outlet Node
2040 23 : errFlag = false;
2041 23 : ReheatCoilOutletNode = HeatingCoils::GetCoilOutletNode(state, ReheatingCoilType, ReheatingCoilName, errFlag);
2042 23 : if (errFlag) {
2043 0 : ShowContinueError(state, format("...occurs in {} \"{}\"", CurrentModuleObject, Alphas(1)));
2044 0 : ErrorsFound = true;
2045 : }
2046 :
2047 : } // IF (IsNotOK) THEN
2048 : }
2049 :
2050 0 : } else if (Util::SameString(ReheatingCoilType, "Coil:Heating:Water")) {
2051 0 : thisFurnace.SuppHeatCoilType_Num = HVAC::Coil_HeatingWater;
2052 0 : ValidateComponent(state, ReheatingCoilType, ReheatingCoilName, IsNotOK, CurrentModuleObject);
2053 0 : if (IsNotOK) {
2054 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2055 0 : ErrorsFound = true;
2056 : } else { // mine data from heating coil object
2057 :
2058 : // Get the Heating Coil water Inlet or control Node number
2059 0 : errFlag = false;
2060 0 : thisFurnace.SuppCoilControlNode = WaterCoils::GetCoilWaterInletNode(state, "Coil:Heating:Water", ReheatingCoilName, errFlag);
2061 0 : if (errFlag) {
2062 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
2063 0 : ErrorsFound = true;
2064 : }
2065 :
2066 : // Get the ReHeat Coil hot water max volume flow rate
2067 0 : errFlag = false;
2068 0 : thisFurnace.MaxSuppCoilFluidFlow =
2069 0 : WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", ReheatingCoilName, errFlag);
2070 0 : if (errFlag) {
2071 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
2072 0 : ErrorsFound = true;
2073 : }
2074 :
2075 : // Get the ReHeat Coil Inlet Node
2076 0 : errFlag = false;
2077 0 : ReheatCoilInletNode = WaterCoils::GetCoilInletNode(state, "Coil:Heating:Water", ReheatingCoilName, errFlag);
2078 0 : thisFurnace.SuppCoilAirInletNode = ReheatCoilInletNode;
2079 0 : if (errFlag) {
2080 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
2081 0 : ErrorsFound = true;
2082 : }
2083 :
2084 : // Get the ReHeat Coil Outlet Node
2085 0 : errFlag = false;
2086 0 : ReheatCoilOutletNode = WaterCoils::GetCoilOutletNode(state, "Coil:Heating:Water", ReheatingCoilName, errFlag);
2087 0 : thisFurnace.SuppCoilAirOutletNode = ReheatCoilOutletNode;
2088 0 : if (errFlag) {
2089 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
2090 0 : ErrorsFound = true;
2091 : }
2092 :
2093 : // check if user has also used a water coil controller, which they should not do
2094 0 : errFlag = false;
2095 0 : HVACControllers::CheckCoilWaterInletNode(state, thisFurnace.CoilControlNode, errFlag);
2096 0 : if (!errFlag) { // then did find a controller so that is bad
2097 0 : ShowSevereError(state,
2098 0 : format("{} = {} has a conflicting Controller:WaterCoil object", CurrentModuleObject, thisFurnace.Name));
2099 0 : ShowContinueError(state, "Hot water coils are controlled directly by unitary and furnace systems.");
2100 0 : ShowContinueError(state, "No water coil controller should be input for the coil.");
2101 0 : ErrorsFound = true;
2102 : }
2103 : }
2104 :
2105 0 : } else if (Util::SameString(ReheatingCoilType, "Coil:Heating:Steam")) {
2106 0 : thisFurnace.SuppHeatCoilType_Num = HVAC::Coil_HeatingSteam;
2107 0 : ValidateComponent(state, ReheatingCoilType, ReheatingCoilName, IsNotOK, CurrentModuleObject);
2108 0 : if (IsNotOK) {
2109 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2110 0 : ErrorsFound = true;
2111 : } else { // mine data from heating coil object
2112 :
2113 0 : errFlag = false;
2114 0 : thisFurnace.SuppHeatCoilIndex = SteamCoils::GetSteamCoilIndex(state, "COIL:HEATING:STEAM", ReheatingCoilName, errFlag);
2115 0 : if (thisFurnace.SuppHeatCoilIndex == 0) {
2116 0 : ShowSevereError(state, format("{} illegal {} = {}", CurrentModuleObject, cAlphaFields(11), ReheatingCoilName));
2117 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
2118 0 : ErrorsFound = true;
2119 : }
2120 :
2121 : // Get the Heating Coil steam inlet node number
2122 0 : errFlag = false;
2123 0 : thisFurnace.SuppCoilControlNode = SteamCoils::GetCoilSteamInletNode(state, "Coil:Heating:Steam", ReheatingCoilName, errFlag);
2124 0 : if (errFlag) {
2125 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
2126 0 : ErrorsFound = true;
2127 : }
2128 :
2129 : // Get the Heating Coil steam max volume flow rate
2130 0 : thisFurnace.MaxSuppCoilFluidFlow = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.SuppHeatCoilIndex, errFlag);
2131 0 : if (thisFurnace.MaxSuppCoilFluidFlow > 0.0) {
2132 0 : SteamIndex = 0; // Function GetSatDensityRefrig will look up steam index if 0 is passed
2133 0 : SteamDensity = FluidProperties::GetSatDensityRefrig(
2134 0 : state, fluidNameSteam, state.dataFurnaces->TempSteamIn, 1.0, SteamIndex, getAirLoopHVACHeatCoolInput);
2135 0 : thisFurnace.MaxSuppCoilFluidFlow =
2136 0 : SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.SuppHeatCoilIndex, errFlag) * SteamDensity;
2137 : }
2138 :
2139 : // Get the Heating Coil Inlet Node
2140 0 : errFlag = false;
2141 0 : ReheatCoilInletNode = SteamCoils::GetCoilAirInletNode(state, thisFurnace.SuppHeatCoilIndex, ReheatingCoilName, errFlag);
2142 0 : thisFurnace.SuppCoilAirInletNode = ReheatCoilInletNode;
2143 0 : if (errFlag) {
2144 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
2145 0 : ErrorsFound = true;
2146 : }
2147 :
2148 : // Get the Heating Coil Outlet Node
2149 0 : errFlag = false;
2150 0 : ReheatCoilOutletNode = SteamCoils::GetCoilAirOutletNode(state, thisFurnace.SuppHeatCoilIndex, ReheatingCoilName, errFlag);
2151 0 : thisFurnace.SuppCoilAirOutletNode = ReheatCoilOutletNode;
2152 0 : if (errFlag) {
2153 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
2154 0 : ErrorsFound = true;
2155 : }
2156 : }
2157 :
2158 : } else { // Illeagal heating coil
2159 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2160 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(15), Alphas(15)));
2161 0 : ErrorsFound = true;
2162 : } // IF (Furnace(FurnaceNum)%SuppHeatCoilType_Num == Coil_HeatingGasOrOtherFuel .OR. &, etc.
2163 :
2164 : } // IF(.NOT. lAlphaBlanks(15))THEN
2165 :
2166 181 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
2167 :
2168 178 : if (FanInletNode != thisFurnace.FurnaceInletNodeNum) {
2169 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2170 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatCool) {
2171 0 : ShowContinueError(
2172 : state, "When a blow through fan is specified, the fan inlet node name must be the same as the furnace inlet node name.");
2173 0 : ShowContinueError(state, format("...Fan inlet node name = {}", state.dataLoopNodes->NodeID(FanInletNode)));
2174 0 : ShowContinueError(state,
2175 0 : format("...Furnace inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
2176 : } else {
2177 0 : ShowContinueError(
2178 : state,
2179 : "When a blow through fan is specified, the fan inlet node name must be the same as the unitary system inlet node name.");
2180 0 : ShowContinueError(state, format("...Fan inlet node name = {}", state.dataLoopNodes->NodeID(FanInletNode)));
2181 0 : ShowContinueError(
2182 0 : state, format("...UnitarySystem inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
2183 : }
2184 0 : ErrorsFound = true;
2185 : }
2186 178 : if (thisFurnace.CoolingCoilUpstream) {
2187 76 : if (FanOutletNode != CoolingCoilInletNode) {
2188 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2189 0 : ShowContinueError(
2190 : state,
2191 : "When a blow through fan is specified, the fan outlet node name must be the same as the cooling coil inlet node name.");
2192 0 : ShowContinueError(state, format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
2193 0 : ShowContinueError(state, format("...Cooling coil inlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilInletNode)));
2194 0 : ErrorsFound = true;
2195 : }
2196 76 : if (CoolingCoilOutletNode != HeatingCoilInletNode) {
2197 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2198 0 : ShowContinueError(state, "The cooling coil outlet node name must be the same as the heating coil inlet node name.");
2199 0 : ShowContinueError(state, format("...Cooling coil outlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilOutletNode)));
2200 0 : ShowContinueError(state, format("...Heating coil inlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
2201 0 : ErrorsFound = true;
2202 : }
2203 76 : if ((thisFurnace.Humidistat && thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat) ||
2204 : ReheatCoilInletNode > 0) {
2205 22 : if (HeatingCoilOutletNode != ReheatCoilInletNode) {
2206 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2207 0 : ShowContinueError(state,
2208 : "When a blow through fan is specified, the heating coil outlet node name must be the same as the "
2209 : "reheat coil inlet node name.");
2210 0 : ShowContinueError(state,
2211 0 : format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
2212 0 : ShowContinueError(state,
2213 0 : format("...Reheat coil inlet node name = {}", state.dataLoopNodes->NodeID(ReheatCoilInletNode)));
2214 0 : ErrorsFound = true;
2215 : }
2216 22 : if (ReheatCoilOutletNode != thisFurnace.FurnaceOutletNodeNum) {
2217 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2218 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatCool) {
2219 0 : ShowContinueError(state, "The reheat coil outlet node name must be the same as the furnace outlet node name.");
2220 0 : ShowContinueError(state,
2221 0 : format("...Reheat coil outlet node name = {}", state.dataLoopNodes->NodeID(ReheatCoilOutletNode)));
2222 0 : ShowContinueError(
2223 : state,
2224 0 : format("...Furnace outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
2225 : } else {
2226 0 : ShowContinueError(state, "The reheat coil outlet node name must be the same as the unitary system outlet node name.");
2227 0 : ShowContinueError(
2228 0 : state, format("...Reheat coil outlet node name = {}", state.dataLoopNodes->NodeID(ReheatCoilOutletNode)));
2229 0 : ShowContinueError(
2230 : state,
2231 0 : format("...UnitarySystem outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
2232 : }
2233 0 : ErrorsFound = true;
2234 : }
2235 : } else { // IF((Furnace(FurnaceNum)%Humidistat ...
2236 : // Heating coil outlet node name must be the same as the furnace outlet node name
2237 54 : if (HeatingCoilOutletNode != thisFurnace.FurnaceOutletNodeNum) {
2238 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2239 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatOnly) {
2240 0 : ShowContinueError(state,
2241 : "When a blow through fan is specified, the heating coil outlet node name must be the same as the "
2242 : "furnace outlet node name.");
2243 0 : ShowContinueError(
2244 0 : state, format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
2245 0 : ShowContinueError(
2246 : state,
2247 0 : format("...Furnace outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
2248 : } else {
2249 0 : ShowContinueError(state,
2250 : "When a blow through fan is specified, the heating coil outlet node name must be the same as the "
2251 : "unitary system outlet node name.");
2252 0 : ShowContinueError(
2253 0 : state, format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
2254 0 : ShowContinueError(
2255 : state,
2256 0 : format("...UnitarySystem outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
2257 : }
2258 0 : ErrorsFound = true;
2259 : }
2260 : }
2261 : } else { // IF(Furnace(FurnaceNum)%CoolingCoilUpstream)THEN
2262 102 : if (FanOutletNode != HeatingCoilInletNode) {
2263 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2264 0 : ShowContinueError(
2265 : state,
2266 : "When a blow through fan is specified, the fan outlet node name must be the same as the heating coil inlet node name.");
2267 0 : ShowContinueError(state, format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
2268 0 : ShowContinueError(state, format("...Heating coil inlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
2269 0 : ErrorsFound = true;
2270 : }
2271 102 : if (HeatingCoilOutletNode != CoolingCoilInletNode) {
2272 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2273 0 : ShowContinueError(state, "The heating coil outlet node name must be the same as the cooling coil inlet node name.");
2274 0 : ShowContinueError(state, format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
2275 0 : ShowContinueError(state, format("...Cooling coil inlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilInletNode)));
2276 0 : ErrorsFound = true;
2277 : }
2278 102 : if (CoolingCoilOutletNode != thisFurnace.FurnaceOutletNodeNum) {
2279 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2280 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatCool) {
2281 0 : ShowContinueError(state,
2282 : "When a blow through fan is specified, the cooling coil outlet node name must be the same as the "
2283 : "furnace outlet node name.");
2284 0 : ShowContinueError(state,
2285 0 : format("...Cooling coil outlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilOutletNode)));
2286 0 : ShowContinueError(
2287 : state,
2288 0 : format("...Furnace outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
2289 : } else {
2290 0 : ShowContinueError(state,
2291 : "When a blow through fan is specified, the cooling coil outlet node name must be the same as the "
2292 : "unitary system outlet node name.");
2293 0 : ShowContinueError(state,
2294 0 : format("...Cooling coil outlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilOutletNode)));
2295 0 : ShowContinueError(
2296 : state,
2297 0 : format("...UnitarySystem outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
2298 : }
2299 0 : ErrorsFound = true;
2300 : }
2301 : }
2302 :
2303 : } else { // ELSE from IF(Furnace(FurnaceNum)%FanPlace .EQ. BlowThru)THEN
2304 :
2305 3 : if (thisFurnace.CoolingCoilUpstream) {
2306 1 : if (CoolingCoilInletNode != thisFurnace.FurnaceInletNodeNum) {
2307 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2308 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatCool) {
2309 0 : ShowContinueError(state,
2310 : "When a draw through fan is specified, the cooling coil inlet node name must be the same as the "
2311 : "furnace inlet node name.");
2312 0 : ShowContinueError(state,
2313 0 : format("...Cooling coil inlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilInletNode)));
2314 0 : ShowContinueError(
2315 0 : state, format("...Furnace inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
2316 : } else {
2317 0 : ShowContinueError(state,
2318 : "When a draw through fan is specified, the cooling coil inlet node name must be the same as the "
2319 : "unitary system inlet node name.");
2320 0 : ShowContinueError(state,
2321 0 : format("...Cooling coil inlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilInletNode)));
2322 0 : ShowContinueError(
2323 0 : state, format("...UnitarySystem inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
2324 : }
2325 0 : ErrorsFound = true;
2326 : }
2327 1 : if (CoolingCoilOutletNode != HeatingCoilInletNode) {
2328 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2329 0 : ShowContinueError(state, "The cooling coil outlet node name must be the same as the heating coil inlet node name.");
2330 0 : ShowContinueError(state, format("...Cooling coil outlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilOutletNode)));
2331 0 : ShowContinueError(state, format("...Heating coil inlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
2332 0 : ErrorsFound = true;
2333 : }
2334 1 : if (HeatingCoilOutletNode != FanInletNode) {
2335 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2336 0 : ShowContinueError(
2337 : state,
2338 : "When a draw through fan is specified, the heating coil outlet node name must be the same as the fan inlet node name.");
2339 0 : ShowContinueError(state, format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
2340 0 : ShowContinueError(state, format("...Fan inlet node name = {}", state.dataLoopNodes->NodeID(FanInletNode)));
2341 0 : ErrorsFound = true;
2342 : }
2343 1 : if ((thisFurnace.Humidistat && thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat) ||
2344 : ReheatCoilInletNode > 0) {
2345 1 : if (FanOutletNode != ReheatCoilInletNode) {
2346 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2347 0 : ShowContinueError(state,
2348 : "When a draw through fan is specified, the fan outlet node name must be the same as the reheat coil "
2349 : "inlet node name.");
2350 0 : ShowContinueError(state, format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
2351 0 : ShowContinueError(state, format("...Reheat coil inlet node name = {}", state.dataLoopNodes->NodeID(ReheatCoilInletNode)));
2352 0 : ErrorsFound = true;
2353 : }
2354 1 : if (ReheatCoilOutletNode != thisFurnace.FurnaceOutletNodeNum) {
2355 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2356 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatCool) {
2357 0 : ShowContinueError(state, "The reheat coil outlet node name must be the same as the furnace outlet node name.");
2358 0 : ShowContinueError(state,
2359 0 : format("...Reheat coil outlet node name = {}", state.dataLoopNodes->NodeID(ReheatCoilOutletNode)));
2360 0 : ShowContinueError(
2361 : state,
2362 0 : format("...Furnace outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
2363 : } else {
2364 0 : ShowContinueError(state, "The reheat coil outlet node name must be the same as the unitary system outlet node name.");
2365 0 : ShowContinueError(
2366 0 : state, format("...Reheat coil outlet node name = {}", state.dataLoopNodes->NodeID(ReheatCoilOutletNode)));
2367 0 : ShowContinueError(
2368 : state,
2369 0 : format("...UnitarySystem outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
2370 : }
2371 0 : ErrorsFound = true;
2372 : }
2373 : } else {
2374 0 : if (FanOutletNode != thisFurnace.FurnaceOutletNodeNum) {
2375 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2376 0 : ShowContinueError(state,
2377 : "When a draw through fan is specified, the fan outlet node name must be the same as the unitary system "
2378 : "outlet node name.");
2379 0 : ShowContinueError(state, format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
2380 0 : ShowContinueError(
2381 : state,
2382 0 : format("...Unitary system outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
2383 0 : ErrorsFound = true;
2384 : }
2385 : }
2386 : } else { // IF(Furnace(FurnaceNum)%CoolingCoilUpstream)THEN
2387 2 : if (HeatingCoilInletNode != thisFurnace.FurnaceInletNodeNum) {
2388 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2389 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatCool) {
2390 0 : ShowContinueError(state,
2391 : "When a draw through fan is specified, the heating coil inlet node name must be the same as the "
2392 : "furnace inlet node name.");
2393 0 : ShowContinueError(state,
2394 0 : format("...Heating coil inlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
2395 0 : ShowContinueError(
2396 0 : state, format("...Furnace inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
2397 : } else {
2398 0 : ShowContinueError(state,
2399 : "When a draw through fan is specified, the heating coil inlet node name must be the same as the "
2400 : "unitary system inlet node name.");
2401 0 : ShowContinueError(state,
2402 0 : format("...Heating coil inlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
2403 0 : ShowContinueError(
2404 0 : state, format("...UnitarySystem inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
2405 : }
2406 0 : ErrorsFound = true;
2407 : }
2408 2 : if (HeatingCoilOutletNode != CoolingCoilInletNode) {
2409 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2410 0 : ShowContinueError(state, "The heating coil outlet node name must be the same as the cooling coil inlet node name.");
2411 0 : ShowContinueError(state, format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
2412 0 : ShowContinueError(state, format("...Cooling coil inlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilInletNode)));
2413 0 : ErrorsFound = true;
2414 : }
2415 2 : if (CoolingCoilOutletNode != FanInletNode) {
2416 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2417 0 : ShowContinueError(
2418 : state,
2419 : "When a draw through fan is specified, the cooling coil outlet node name must be the same as the fan inlet node name.");
2420 0 : ShowContinueError(state, format("...Cooling coil outlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilOutletNode)));
2421 0 : ShowContinueError(state, format("...Fan inlet node name = {}", state.dataLoopNodes->NodeID(FanInletNode)));
2422 0 : ErrorsFound = true;
2423 : }
2424 2 : if (FanOutletNode != thisFurnace.FurnaceOutletNodeNum) {
2425 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
2426 0 : if (thisFurnace.type == HVAC::UnitarySysType::Furnace_HeatCool) {
2427 0 : ShowContinueError(
2428 : state,
2429 : "When a draw through fan is specified, the fan outlet node name must be the same as the furnace outlet node name.");
2430 0 : ShowContinueError(state, format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
2431 0 : ShowContinueError(
2432 0 : state, format("...Furnace outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
2433 : } else {
2434 0 : ShowContinueError(state,
2435 : "When a draw through fan is specified, the fan outlet node name must be the same as the unitary system "
2436 : "outlet node name.");
2437 0 : ShowContinueError(state, format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
2438 0 : ShowContinueError(
2439 : state,
2440 0 : format("...UnitarySystem outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
2441 : }
2442 0 : ErrorsFound = true;
2443 : }
2444 : }
2445 : } // ELSE from IF(Furnace(FurnaceNum)%FanPlace .EQ. BlowThru)THEN
2446 :
2447 : // Add fan to component sets array
2448 362 : BranchNodeConnections::SetUpCompSets(state,
2449 : CurrentModuleObject,
2450 181 : Alphas(1),
2451 181 : Alphas(7),
2452 181 : Alphas(8),
2453 181 : state.dataLoopNodes->NodeID(FanInletNode),
2454 181 : state.dataLoopNodes->NodeID(FanOutletNode));
2455 :
2456 : // Add DX cooling coil to component sets array
2457 181 : if (thisFurnace.bIsIHP) {
2458 0 : BranchNodeConnections::SetUpCompSets(state,
2459 : CurrentModuleObject,
2460 0 : Alphas(1),
2461 0 : Alphas(12),
2462 0 : Alphas(13) + " Cooling Coil",
2463 0 : state.dataLoopNodes->NodeID(CoolingCoilInletNode),
2464 0 : state.dataLoopNodes->NodeID(CoolingCoilOutletNode));
2465 : } else {
2466 362 : BranchNodeConnections::SetUpCompSets(state,
2467 : CurrentModuleObject,
2468 181 : Alphas(1),
2469 181 : Alphas(12),
2470 181 : Alphas(13),
2471 181 : state.dataLoopNodes->NodeID(CoolingCoilInletNode),
2472 181 : state.dataLoopNodes->NodeID(CoolingCoilOutletNode));
2473 : }
2474 :
2475 : // Add heating coil to component sets array
2476 181 : if (thisFurnace.bIsIHP) {
2477 0 : BranchNodeConnections::SetUpCompSets(state,
2478 : CurrentModuleObject,
2479 0 : Alphas(1),
2480 0 : Alphas(10),
2481 0 : Alphas(11) + " Heating Coil",
2482 0 : state.dataLoopNodes->NodeID(HeatingCoilInletNode),
2483 0 : state.dataLoopNodes->NodeID(HeatingCoilOutletNode));
2484 : } else {
2485 362 : BranchNodeConnections::SetUpCompSets(state,
2486 : CurrentModuleObject,
2487 181 : Alphas(1),
2488 181 : Alphas(10),
2489 181 : Alphas(11),
2490 181 : state.dataLoopNodes->NodeID(HeatingCoilInletNode),
2491 181 : state.dataLoopNodes->NodeID(HeatingCoilOutletNode));
2492 : }
2493 :
2494 181 : if (ReheatCoilInletNode > 0) {
2495 :
2496 : // Add reheating coil to component sets array
2497 46 : BranchNodeConnections::SetUpCompSets(state,
2498 : CurrentModuleObject,
2499 23 : Alphas(1),
2500 23 : Alphas(15),
2501 23 : Alphas(16),
2502 23 : state.dataLoopNodes->NodeID(ReheatCoilInletNode),
2503 23 : state.dataLoopNodes->NodeID(ReheatCoilOutletNode));
2504 : }
2505 :
2506 : // Set the furnace max outlet temperature
2507 181 : thisFurnace.DesignMaxOutletTemp = Numbers(1);
2508 :
2509 181 : thisFurnace.MaxCoolAirVolFlow = Numbers(2);
2510 181 : if (thisFurnace.MaxCoolAirVolFlow <= 0 && thisFurnace.MaxCoolAirVolFlow != DataSizing::AutoSize) {
2511 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2512 0 : ShowContinueError(state, format("Illegal {} = {:.7T}", cNumericFields(2), Numbers(2)));
2513 0 : ErrorsFound = true;
2514 : }
2515 :
2516 181 : thisFurnace.MaxHeatAirVolFlow = Numbers(3);
2517 181 : if (thisFurnace.MaxHeatAirVolFlow <= 0 && thisFurnace.MaxHeatAirVolFlow != DataSizing::AutoSize) {
2518 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2519 0 : ShowContinueError(state, format("Illegal {} = {:.7T}", cNumericFields(3), Numbers(3)));
2520 0 : ErrorsFound = true;
2521 : }
2522 :
2523 181 : thisFurnace.MaxNoCoolHeatAirVolFlow = Numbers(4);
2524 181 : if (thisFurnace.MaxNoCoolHeatAirVolFlow < 0 && thisFurnace.MaxNoCoolHeatAirVolFlow != DataSizing::AutoSize) {
2525 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2526 0 : ShowContinueError(state, format("Illegal {} = {:.7T}", cNumericFields(4), Numbers(4)));
2527 0 : ErrorsFound = true;
2528 : }
2529 :
2530 181 : if (Numbers(2) != DataSizing::AutoSize && Numbers(3) != DataSizing::AutoSize && Numbers(4) != DataSizing::AutoSize) {
2531 25 : thisFurnace.DesignFanVolFlowRate = max(Numbers(2), Numbers(3), Numbers(4));
2532 : } else {
2533 156 : thisFurnace.DesignFanVolFlowRate = DataSizing::AutoSize;
2534 : }
2535 :
2536 181 : if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) {
2537 4 : errFlag = false;
2538 4 : if (thisFurnace.bIsIHP) {
2539 0 : thisFurnace.CoolingCoilIndex = IntegratedHeatPump::GetCoilIndexIHP(state, CoolingCoilType, CoolingCoilName, errFlag);
2540 0 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SCCoilName;
2541 0 : thisFurnace.MaxCoolAirVolFlow =
2542 0 : VariableSpeedCoils::GetCoilAirFlowRateVariableSpeed(state, "COIL:COOLING:DX:VARIABLESPEED", IHPCoilName, errFlag);
2543 : } else {
2544 4 : thisFurnace.MaxCoolAirVolFlow =
2545 4 : VariableSpeedCoils::GetCoilAirFlowRateVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
2546 : }
2547 :
2548 4 : if (errFlag) {
2549 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2550 0 : ErrorsFound = true;
2551 : }
2552 :
2553 4 : thisFurnace.MaxNoCoolHeatAirVolFlow = min(thisFurnace.MaxHeatAirVolFlow, thisFurnace.MaxCoolAirVolFlow);
2554 4 : if (thisFurnace.MaxHeatAirVolFlow != DataSizing::AutoSize && thisFurnace.MaxCoolAirVolFlow != DataSizing::AutoSize) {
2555 0 : thisFurnace.DesignFanVolFlowRate = max(thisFurnace.MaxHeatAirVolFlow, thisFurnace.MaxCoolAirVolFlow);
2556 : } else {
2557 4 : thisFurnace.DesignFanVolFlowRate = DataSizing::AutoSize;
2558 : }
2559 : }
2560 :
2561 181 : if (thisFurnace.ActualFanVolFlowRate != DataSizing::AutoSize) {
2562 25 : if (thisFurnace.ActualFanVolFlowRate < thisFurnace.MaxCoolAirVolFlow && thisFurnace.MaxCoolAirVolFlow != 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 cooling 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(2)));
2570 0 : thisFurnace.MaxCoolAirVolFlow = thisFurnace.ActualFanVolFlowRate;
2571 0 : thisFurnace.DesignFanVolFlowRate = thisFurnace.ActualFanVolFlowRate;
2572 : }
2573 25 : if (thisFurnace.ActualFanVolFlowRate < thisFurnace.MaxHeatAirVolFlow && thisFurnace.MaxHeatAirVolFlow != DataSizing::AutoSize) {
2574 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2575 0 : ShowContinueError(
2576 : state,
2577 0 : format("... air flow rate = {:.7T} in fan object {} is less than the maximum HVAC system air flow rate in heating mode.",
2578 0 : thisFurnace.ActualFanVolFlowRate,
2579 : FanName));
2580 0 : ShowContinueError(state, format(" The {} is reset to the fan flow rate and the simulation continues.", cNumericFields(3)));
2581 0 : thisFurnace.MaxHeatAirVolFlow = thisFurnace.ActualFanVolFlowRate;
2582 0 : thisFurnace.DesignFanVolFlowRate = thisFurnace.ActualFanVolFlowRate;
2583 : }
2584 : }
2585 :
2586 181 : if (thisFurnace.FanSchedPtr > 0) {
2587 161 : if (!ScheduleManager::CheckScheduleValueMinMax(state, thisFurnace.FanSchedPtr, ">=", 0.0, "<=", 0.0)) {
2588 : // set air flow control mode:
2589 : // UseCompressorOnFlow = operate at last cooling or heating air flow requested when compressor is off
2590 : // UseCompressorOffFlow = operate at value specified by user
2591 : // AirFlowControl only valid if fan opmode = ContFanCycComp
2592 96 : if (thisFurnace.MaxNoCoolHeatAirVolFlow == 0.0) {
2593 1 : thisFurnace.AirFlowControl = AirFlowControlConstFan::UseCompressorOnFlow;
2594 : } else {
2595 95 : thisFurnace.AirFlowControl = AirFlowControlConstFan::UseCompressorOffFlow;
2596 : }
2597 : }
2598 : }
2599 :
2600 181 : if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) {
2601 4 : errFlag = false;
2602 4 : if (thisFurnace.bIsIHP) {
2603 0 : thisFurnace.CoolingCoilIndex = IntegratedHeatPump::GetCoilIndexIHP(state, CoolingCoilType, CoolingCoilName, errFlag);
2604 0 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SCCoilName;
2605 0 : thisFurnace.DesignCoolingCapacity =
2606 0 : VariableSpeedCoils::GetCoilCapacityVariableSpeed(state, "COIL:COOLING:DX:VARIABLESPEED", IHPCoilName, errFlag);
2607 : } else {
2608 4 : thisFurnace.DesignCoolingCapacity =
2609 4 : VariableSpeedCoils::GetCoilCapacityVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
2610 : }
2611 :
2612 4 : if (errFlag) {
2613 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2614 0 : ErrorsFound = true;
2615 : }
2616 : }
2617 :
2618 : // Set heating convergence tolerance
2619 181 : thisFurnace.HeatingConvergenceTolerance = 0.001;
2620 :
2621 : // Set cooling convergence tolerance
2622 181 : thisFurnace.CoolingConvergenceTolerance = 0.001;
2623 :
2624 : // set minimum outdoor temperature for compressor operation
2625 181 : SetMinOATCompressor(state, FurnaceNum, cCurrentModuleObject, ErrorsFound);
2626 :
2627 : } // End of the HeatCool Furnace Loop
2628 :
2629 : // Get the data for the Unitary System HeatPump AirToAir (UnitarySystem:HeatPump:AirToAir)
2630 132 : for (int HeatPumpNum = 1; HeatPumpNum <= NumHeatPump; ++HeatPumpNum) {
2631 :
2632 35 : CurrentModuleObject = "AirLoopHVAC:UnitaryHeatPump:AirToAir";
2633 35 : FanInletNode = 0;
2634 35 : FanOutletNode = 0;
2635 35 : CoolingCoilInletNode = 0;
2636 35 : CoolingCoilOutletNode = 0;
2637 35 : HeatingCoilInletNode = 0;
2638 35 : HeatingCoilOutletNode = 0;
2639 35 : SupHeatCoilInletNode = 0;
2640 35 : SupHeatCoilOutletNode = 0;
2641 35 : CoolingCoilType = ' ';
2642 35 : CoolingCoilName = ' ';
2643 35 : HeatingCoilType = ' ';
2644 35 : HeatingCoilName = ' ';
2645 :
2646 35 : FurnaceNum = NumHeatOnly + NumHeatCool + NumUnitaryHeatOnly + NumUnitaryHeatCool + HeatPumpNum;
2647 35 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
2648 35 : thisFurnace.iterationMode.allocate(3);
2649 :
2650 35 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
2651 : CurrentModuleObject,
2652 : HeatPumpNum,
2653 : Alphas,
2654 : NumAlphas,
2655 : Numbers,
2656 : NumNumbers,
2657 : IOStatus,
2658 : lNumericBlanks,
2659 : lAlphaBlanks,
2660 : cAlphaFields,
2661 : cNumericFields);
2662 :
2663 70 : GlobalNames::VerifyUniqueInterObjectName(
2664 35 : state, state.dataFurnaces->UniqueFurnaceNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
2665 :
2666 35 : thisFurnace.type = HVAC::UnitarySysType::Unitary_HeatPump_AirToAir;
2667 35 : thisFurnace.Name = Alphas(1);
2668 :
2669 35 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, thisFurnace.Name};
2670 :
2671 35 : if (lAlphaBlanks(2)) {
2672 6 : thisFurnace.SchedPtr = ScheduleManager::ScheduleAlwaysOn;
2673 : } else {
2674 29 : thisFurnace.SchedPtr = ScheduleManager::GetScheduleIndex(state, Alphas(2));
2675 29 : if (thisFurnace.SchedPtr == 0) {
2676 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2677 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(2), Alphas(2)));
2678 0 : ErrorsFound = true;
2679 : }
2680 : }
2681 :
2682 35 : thisFurnace.FurnaceInletNodeNum =
2683 35 : NodeInputManager::GetOnlySingleNode(state,
2684 35 : Alphas(3),
2685 : ErrorsFound,
2686 : DataLoopNode::ConnectionObjectType::AirLoopHVACUnitaryHeatPumpAirToAir,
2687 35 : Alphas(1),
2688 : DataLoopNode::NodeFluidType::Air,
2689 : DataLoopNode::ConnectionType::Inlet,
2690 : NodeInputManager::CompFluidStream::Primary,
2691 : DataLoopNode::ObjectIsParent);
2692 :
2693 35 : thisFurnace.FurnaceOutletNodeNum =
2694 35 : NodeInputManager::GetOnlySingleNode(state,
2695 35 : Alphas(4),
2696 : ErrorsFound,
2697 : DataLoopNode::ConnectionObjectType::AirLoopHVACUnitaryHeatPumpAirToAir,
2698 35 : Alphas(1),
2699 : DataLoopNode::NodeFluidType::Air,
2700 : DataLoopNode::ConnectionType::Outlet,
2701 : NodeInputManager::CompFluidStream::Primary,
2702 : DataLoopNode::ObjectIsParent);
2703 :
2704 35 : BranchNodeConnections::TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(3), Alphas(4), "Air Nodes");
2705 :
2706 : // Get the Controlling Zone or Location of the Furnace Thermostat
2707 35 : thisFurnace.ControlZoneNum = Util::FindItemInList(Alphas(5), state.dataHeatBal->Zone);
2708 35 : if (thisFurnace.ControlZoneNum == 0) {
2709 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2710 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(5), Alphas(5)));
2711 0 : ErrorsFound = true;
2712 : }
2713 :
2714 : // Get the node number for the zone with the thermostat
2715 35 : if (thisFurnace.ControlZoneNum > 0) {
2716 35 : AirNodeFound = false;
2717 35 : AirLoopFound = false;
2718 35 : int ControlledZoneNum = thisFurnace.ControlZoneNum;
2719 : // Find the controlled zone number for the specified thermostat location
2720 35 : thisFurnace.NodeNumOfControlledZone = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneNode;
2721 : // Determine if furnace is on air loop served by the thermostat location specified
2722 35 : for (int zoneInNode = 1; zoneInNode <= state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumInletNodes; ++zoneInNode) {
2723 35 : int AirLoopNumber = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNodeAirLoopNum(zoneInNode);
2724 35 : if (AirLoopNumber > 0) {
2725 35 : for (int BranchNum = 1; BranchNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).NumBranches; ++BranchNum) {
2726 65 : for (int CompNum = 1;
2727 65 : CompNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).TotalComponents;
2728 : ++CompNum) {
2729 65 : if (!Util::SameString(state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).Name,
2730 165 : Alphas(1)) ||
2731 35 : !Util::SameString(
2732 35 : state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).TypeOf,
2733 : CurrentModuleObject))
2734 30 : continue;
2735 35 : AirLoopFound = true;
2736 35 : thisFurnace.ZoneInletNode = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNode(zoneInNode);
2737 35 : break;
2738 : }
2739 35 : if (AirLoopFound) break;
2740 : }
2741 115 : for (TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumTempControlledZones; ++TstatZoneNum) {
2742 80 : if (state.dataZoneCtrls->TempControlledZone(TstatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) continue;
2743 35 : AirNodeFound = true;
2744 : }
2745 35 : for (TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumComfortControlledZones; ++TstatZoneNum) {
2746 0 : if (state.dataZoneCtrls->ComfortControlledZone(TstatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) continue;
2747 0 : AirNodeFound = true;
2748 : }
2749 : }
2750 35 : if (AirLoopFound) break;
2751 : }
2752 35 : if (!AirNodeFound) {
2753 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2754 0 : ShowContinueError(state, "Did not find air node (zone with thermostat).");
2755 0 : ShowContinueError(state, format("Specified {} = {}", cAlphaFields(5), Alphas(5)));
2756 0 : ShowContinueError(
2757 : state, "Both a ZoneHVAC:EquipmentConnections object and a ZoneControl:Thermostat object must be specified for this zone.");
2758 0 : ErrorsFound = true;
2759 : }
2760 35 : if (!AirLoopFound) {
2761 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2762 0 : ShowContinueError(state, "Did not find correct AirLoopHVAC.");
2763 0 : ShowContinueError(state, format("Specified {} = {}", cAlphaFields(5), Alphas(5)));
2764 0 : ErrorsFound = true;
2765 : }
2766 : }
2767 :
2768 : // Get fan data
2769 35 : FanName = Alphas(7);
2770 :
2771 35 : thisFurnace.fanType = static_cast<HVAC::FanType>(getEnumValue(HVAC::fanTypeNamesUC, Alphas(6)));
2772 :
2773 35 : if (thisFurnace.fanType == HVAC::FanType::OnOff || thisFurnace.fanType == HVAC::FanType::Constant) {
2774 :
2775 35 : if ((thisFurnace.FanIndex = Fans::GetFanIndex(state, FanName)) == 0) {
2776 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(7), FanName);
2777 0 : ErrorsFound = true;
2778 : } else {
2779 35 : auto *fan = state.dataFans->fans(thisFurnace.FanIndex);
2780 35 : FanInletNode = fan->inletNodeNum;
2781 35 : FanOutletNode = fan->outletNodeNum;
2782 35 : thisFurnace.FanAvailSchedPtr = fan->availSchedNum;
2783 35 : thisFurnace.ActualFanVolFlowRate = fan->maxAirFlowRate;
2784 : }
2785 : }
2786 :
2787 : // Get heating coil type and name data
2788 35 : HeatingCoilType = Alphas(8);
2789 35 : HeatingCoilName = Alphas(9);
2790 :
2791 35 : errFlag = false;
2792 :
2793 68 : if (Util::SameString(HeatingCoilType, "COIL:HEATING:DX:VARIABLESPEED") ||
2794 68 : Util::SameString(HeatingCoilType, "COILSYSTEM:INTEGRATEDHEATPUMP:AIRSOURCE")) {
2795 3 : thisFurnace.HeatingCoilType_Num = HVAC::Coil_HeatingAirToAirVariableSpeed;
2796 3 : if (Util::SameString(HeatingCoilType, "COILSYSTEM:INTEGRATEDHEATPUMP:AIRSOURCE")) thisFurnace.bIsIHP = true;
2797 : } else {
2798 32 : thisFurnace.HeatingCoilType_Num = DXCoils::GetCoilTypeNum(state, HeatingCoilType, HeatingCoilName, errFlag);
2799 : }
2800 :
2801 35 : if (errFlag) {
2802 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2803 0 : ErrorsFound = true;
2804 : }
2805 :
2806 35 : if (thisFurnace.HeatingCoilType_Num == HVAC::CoilDX_HeatingEmpirical) {
2807 32 : ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject);
2808 32 : if (IsNotOK) {
2809 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2810 0 : ErrorsFound = true;
2811 :
2812 : } else { // mine data from DX heating coil
2813 :
2814 32 : DXCoils::GetDXCoilIndex(state, HeatingCoilName, thisFurnace.HeatingCoilIndex, IsNotOK);
2815 32 : if (IsNotOK) {
2816 0 : ShowContinueError(state, format("...occurs {} = {}", CurrentModuleObject, Alphas(1)));
2817 0 : ErrorsFound = true;
2818 : }
2819 :
2820 : // Get the Heating Coil Node Names
2821 32 : errFlag = false;
2822 32 : HeatingCoilInletNode = DXCoils::GetCoilInletNode(state, HeatingCoilType, HeatingCoilName, errFlag);
2823 32 : HeatingCoilOutletNode = DXCoils::GetCoilOutletNode(state, HeatingCoilType, HeatingCoilName, errFlag);
2824 32 : if (errFlag) {
2825 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2826 0 : ErrorsFound = true;
2827 : }
2828 :
2829 : // Get the design heating capacity
2830 32 : errFlag = false;
2831 32 : thisFurnace.DesignHeatingCapacity = DXCoils::GetCoilCapacity(state, HeatingCoilType, HeatingCoilName, errFlag);
2832 32 : if (errFlag) {
2833 0 : ShowContinueError(state, format("...occurs in {} ={}", CurrentModuleObject, Alphas(1)));
2834 0 : ErrorsFound = true;
2835 : }
2836 :
2837 : } // IF (IsNotOK) THEN
2838 3 : } else if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed) {
2839 3 : ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject);
2840 3 : if (IsNotOK) {
2841 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2842 0 : ErrorsFound = true;
2843 : } else {
2844 3 : if (thisFurnace.bIsIHP) {
2845 1 : thisFurnace.HeatingCoilIndex = IntegratedHeatPump::GetCoilIndexIHP(state, HeatingCoilType, HeatingCoilName, errFlag);
2846 1 : IHPCoilIndex = thisFurnace.HeatingCoilIndex;
2847 1 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(IHPCoilIndex).SHCoilName;
2848 : HeatingCoilInletNode =
2849 1 : VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, "COIL:HEATING:DX:VARIABLESPEED", IHPCoilName, errFlag);
2850 : HeatingCoilOutletNode =
2851 1 : VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, "COIL:HEATING:DX:VARIABLESPEED", IHPCoilName, errFlag);
2852 : } else {
2853 2 : thisFurnace.HeatingCoilIndex =
2854 2 : VariableSpeedCoils::GetCoilIndexVariableSpeed(state, HeatingCoilType, HeatingCoilName, errFlag);
2855 2 : HeatingCoilInletNode = VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, HeatingCoilType, HeatingCoilName, errFlag);
2856 2 : HeatingCoilOutletNode = VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, HeatingCoilType, HeatingCoilName, errFlag);
2857 : }
2858 : }
2859 : } else {
2860 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2861 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(8), Alphas(8)));
2862 0 : ErrorsFound = true;
2863 : }
2864 :
2865 : // Get Cooling Coil Information if available
2866 35 : CoolingCoilType = Alphas(10);
2867 35 : CoolingCoilName = Alphas(11);
2868 :
2869 68 : if (Util::SameString(CoolingCoilType, "COIL:COOLING:DX:VARIABLESPEED") ||
2870 68 : Util::SameString(CoolingCoilType, "COILSYSTEM:INTEGRATEDHEATPUMP:AIRSOURCE")) {
2871 3 : thisFurnace.CoolingCoilType_Num = HVAC::Coil_CoolingAirToAirVariableSpeed;
2872 3 : if (Util::SameString(CoolingCoilType, "COILSYSTEM:INTEGRATEDHEATPUMP:AIRSOURCE")) thisFurnace.bIsIHP = true;
2873 : }
2874 :
2875 35 : ValidateComponent(state, CoolingCoilType, CoolingCoilName, IsNotOK, CurrentModuleObject);
2876 :
2877 35 : if (IsNotOK) {
2878 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2879 0 : ErrorsFound = true;
2880 :
2881 : } else { // mine data from DX cooling coil
2882 :
2883 35 : errFlag = false;
2884 35 : PrintMessage = false;
2885 :
2886 35 : if (thisFurnace.CoolingCoilType_Num != HVAC::Coil_CoolingAirToAirVariableSpeed) {
2887 32 : thisFurnace.CoolingCoilType_Num = DXCoils::GetCoilTypeNum(state, CoolingCoilType, CoolingCoilName, errFlag, PrintMessage);
2888 : }
2889 :
2890 : // If coil type not found, check to see if a HX assisted cooling coil is used.
2891 35 : if (thisFurnace.CoolingCoilType_Num == 0) {
2892 0 : errFlag = false;
2893 0 : PrintMessage = false;
2894 0 : thisFurnace.CoolingCoilType_Num =
2895 0 : HVACHXAssistedCoolingCoil::GetCoilGroupTypeNum(state, CoolingCoilType, CoolingCoilName, errFlag, PrintMessage);
2896 : }
2897 :
2898 35 : if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingSingleSpeed) {
2899 :
2900 : // Get the cooling coil node numbers
2901 32 : errFlag = false;
2902 32 : DXCoils::GetDXCoilIndex(state, CoolingCoilName, thisFurnace.CoolingCoilIndex, errFlag);
2903 32 : CoolingCoilInletNode = DXCoils::GetCoilInletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
2904 32 : CoolingCoilOutletNode = DXCoils::GetCoilOutletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
2905 32 : if (errFlag) {
2906 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2907 0 : ErrorsFound = true;
2908 : }
2909 :
2910 : // Get the DX cooling coil design capacity
2911 32 : errFlag = false;
2912 32 : thisFurnace.DesignCoolingCapacity = DXCoils::GetCoilCapacity(state, CoolingCoilType, CoolingCoilName, errFlag);
2913 32 : if (errFlag) {
2914 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2915 0 : ErrorsFound = true;
2916 : }
2917 :
2918 3 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) {
2919 :
2920 : // Get the cooling coil node numbers
2921 0 : errFlag = false;
2922 0 : HVACHXAssistedCoolingCoil::GetHXDXCoilIndex(state, CoolingCoilName, thisFurnace.CoolingCoilIndex, errFlag);
2923 0 : CoolingCoilInletNode = HVACHXAssistedCoolingCoil::GetCoilInletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
2924 0 : CoolingCoilOutletNode = HVACHXAssistedCoolingCoil::GetCoilOutletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
2925 0 : if (errFlag) {
2926 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2927 0 : ErrorsFound = true;
2928 : }
2929 :
2930 : // Get the heat exchanger assisted cooling coil design capacity
2931 0 : errFlag = false;
2932 0 : thisFurnace.DesignCoolingCapacity = HVACHXAssistedCoolingCoil::GetCoilCapacity(state, CoolingCoilType, CoolingCoilName, errFlag);
2933 0 : if (errFlag) {
2934 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2935 0 : ErrorsFound = true;
2936 : }
2937 :
2938 : // get the actual index to the DX cooling coil object
2939 0 : DXCoilIndex = HVACHXAssistedCoolingCoil::GetActualDXCoilIndex(state, CoolingCoilType, CoolingCoilName, ErrorsFound);
2940 0 : thisFurnace.ActualDXCoilIndexForHXAssisted = DXCoilIndex;
2941 :
2942 3 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) {
2943 : // BOS ADDED, AUG/2012, VARIIABLE SPEED DX COOLING COIL
2944 : // Furnace(FurnaceNum)%DXCoolCoilType = 'COIL:COOLING:DX:VARIABLESPEED'
2945 : // Furnace(FurnaceNum)%DXCoolCoilName = CoolingCoilName
2946 3 : ValidateComponent(state, CoolingCoilType, CoolingCoilName, IsNotOK, CurrentModuleObject);
2947 3 : if (IsNotOK) {
2948 0 : ShowContinueError(state, format("...specified in {}=\"{}\".", CurrentModuleObject, Alphas(1)));
2949 0 : ErrorsFound = true;
2950 : } else {
2951 3 : errFlag = false;
2952 3 : if (thisFurnace.bIsIHP) {
2953 1 : thisFurnace.CoolingCoilIndex = IntegratedHeatPump::GetCoilIndexIHP(state, CoolingCoilType, CoolingCoilName, errFlag);
2954 1 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SCCoilName;
2955 : } else {
2956 2 : thisFurnace.CoolingCoilIndex =
2957 2 : VariableSpeedCoils::GetCoilIndexVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
2958 2 : IHPCoilName = CoolingCoilName;
2959 : }
2960 :
2961 3 : if (errFlag) {
2962 0 : ShowContinueError(state, format("...specified in {}=\"{}\".", CurrentModuleObject, Alphas(1)));
2963 0 : ErrorsFound = true;
2964 : }
2965 :
2966 3 : if (thisFurnace.bIsIHP) {
2967 : CoolingCoilInletNode =
2968 1 : VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, "COIL:COOLING:DX:VARIABLESPEED", IHPCoilName, errFlag);
2969 : CoolingCoilOutletNode =
2970 1 : VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, "COIL:COOLING:DX:VARIABLESPEED", IHPCoilName, errFlag);
2971 1 : thisFurnace.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, IHPCoilName, errFlag);
2972 : } else {
2973 : CoolingCoilInletNode =
2974 2 : VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
2975 : CoolingCoilOutletNode =
2976 2 : VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
2977 2 : thisFurnace.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, CoolingCoilName, errFlag);
2978 : }
2979 :
2980 3 : if (errFlag) {
2981 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
2982 0 : ErrorsFound = true;
2983 : }
2984 : }
2985 : } else {
2986 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
2987 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(10), Alphas(10)));
2988 0 : ErrorsFound = true;
2989 : }
2990 : }
2991 :
2992 35 : if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed &&
2993 3 : thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed) {
2994 : // Furnace(FurnaceNum)%WatertoAirHPType = WatertoAir_VarSpeedEquationFit
2995 3 : if (thisFurnace.bIsIHP) {
2996 3 : VariableSpeedCoils::SetVarSpeedCoilData(state,
2997 1 : state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SCCoilIndex,
2998 : ErrorsFound,
2999 : _,
3000 1 : state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SHCoilIndex);
3001 : } else {
3002 2 : VariableSpeedCoils::SetVarSpeedCoilData(state, thisFurnace.CoolingCoilIndex, ErrorsFound, _, thisFurnace.HeatingCoilIndex);
3003 : }
3004 : }
3005 :
3006 : // Get supplemental heating coil information
3007 35 : SuppHeatCoilType = Alphas(12);
3008 35 : SuppHeatCoilName = Alphas(13);
3009 35 : thisFurnace.SuppHeatCoilType = SuppHeatCoilType;
3010 35 : thisFurnace.SuppHeatCoilName = SuppHeatCoilName;
3011 35 : errFlag = false;
3012 35 : if (Util::SameString(SuppHeatCoilType, "Coil:Heating:Fuel") || Util::SameString(SuppHeatCoilType, "Coil:Heating:Electric")) {
3013 :
3014 34 : thisFurnace.SuppHeatCoilType_Num = HeatingCoils::GetHeatingCoilTypeNum(state, SuppHeatCoilType, SuppHeatCoilName, errFlag);
3015 34 : if (errFlag) {
3016 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3017 0 : ErrorsFound = true;
3018 : } else {
3019 34 : IsNotOK = false;
3020 34 : ValidateComponent(state, SuppHeatCoilType, SuppHeatCoilName, IsNotOK, CurrentModuleObject);
3021 34 : if (IsNotOK) {
3022 0 : ShowContinueError(state, format("In {} \"{}\"", CurrentModuleObject, Alphas(1)));
3023 0 : ErrorsFound = true;
3024 :
3025 : } else { // mine data from the supplemental heating coil
3026 :
3027 34 : HeatingCoils::GetCoilIndex(state, SuppHeatCoilName, thisFurnace.SuppHeatCoilIndex, IsNotOK);
3028 34 : if (IsNotOK) {
3029 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3030 0 : ErrorsFound = true;
3031 : }
3032 :
3033 : // Get the Supplemental Heating Coil Inlet Node Number
3034 34 : errFlag = false;
3035 34 : SupHeatCoilInletNode = HeatingCoils::GetCoilInletNode(state, SuppHeatCoilType, SuppHeatCoilName, errFlag);
3036 34 : if (errFlag) {
3037 0 : ShowContinueError(state, format("...occurs in {} \"{}\"", CurrentModuleObject, Alphas(1)));
3038 0 : ErrorsFound = true;
3039 : }
3040 :
3041 : // Get the Supplemental Heating Coil Outlet Node Number
3042 34 : errFlag = false;
3043 34 : SupHeatCoilOutletNode = HeatingCoils::GetCoilOutletNode(state, SuppHeatCoilType, SuppHeatCoilName, errFlag);
3044 :
3045 34 : if (errFlag) {
3046 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3047 0 : ErrorsFound = true;
3048 : }
3049 :
3050 : // Get the supplemental heating coil design capacity
3051 34 : errFlag = false;
3052 34 : thisFurnace.DesignSuppHeatingCapacity = HeatingCoils::GetCoilCapacity(state, SuppHeatCoilType, SuppHeatCoilName, errFlag);
3053 34 : if (errFlag) {
3054 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3055 0 : ErrorsFound = true;
3056 : }
3057 :
3058 : } // IF (IsNotOK) THEN
3059 : }
3060 1 : } else if (Util::SameString(SuppHeatCoilType, "Coil:Heating:Water")) {
3061 1 : thisFurnace.SuppHeatCoilType_Num = HVAC::Coil_HeatingWater;
3062 1 : ValidateComponent(state, SuppHeatCoilType, SuppHeatCoilName, IsNotOK, CurrentModuleObject);
3063 1 : if (IsNotOK) {
3064 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3065 0 : ErrorsFound = true;
3066 : } else { // mine data from heating coil object
3067 :
3068 : // Get the Heating Coil water Inlet or control Node number
3069 1 : errFlag = false;
3070 1 : thisFurnace.SuppCoilControlNode = WaterCoils::GetCoilWaterInletNode(state, "Coil:Heating:Water", SuppHeatCoilName, errFlag);
3071 1 : if (errFlag) {
3072 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3073 0 : ErrorsFound = true;
3074 : }
3075 :
3076 : // Get the ReHeat Coil hot water max volume flow rate
3077 1 : errFlag = false;
3078 1 : thisFurnace.MaxSuppCoilFluidFlow = WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", SuppHeatCoilName, errFlag);
3079 1 : if (errFlag) {
3080 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3081 0 : ErrorsFound = true;
3082 : }
3083 :
3084 : // Get the ReHeat Coil Inlet Node
3085 1 : errFlag = false;
3086 1 : SupHeatCoilInletNode = WaterCoils::GetCoilInletNode(state, "Coil:Heating:Water", SuppHeatCoilName, errFlag);
3087 1 : thisFurnace.SuppCoilAirInletNode = SupHeatCoilInletNode;
3088 1 : if (errFlag) {
3089 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3090 0 : ErrorsFound = true;
3091 : }
3092 :
3093 : // Get the ReHeat Coil Outlet Node
3094 1 : errFlag = false;
3095 1 : SupHeatCoilOutletNode = WaterCoils::GetCoilOutletNode(state, "Coil:Heating:Water", SuppHeatCoilName, errFlag);
3096 1 : thisFurnace.SuppCoilAirOutletNode = SupHeatCoilOutletNode;
3097 1 : if (errFlag) {
3098 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3099 0 : ErrorsFound = true;
3100 : }
3101 1 : errFlag = false;
3102 1 : HVACControllers::CheckCoilWaterInletNode(state, thisFurnace.CoilControlNode, errFlag);
3103 1 : if (!errFlag) { // then did find a controller so that is bad
3104 0 : ShowSevereError(state,
3105 0 : format("{} = {} has a conflicting Controller:WaterCoil object", CurrentModuleObject, thisFurnace.Name));
3106 0 : ShowContinueError(state, "Hot water coils are controlled directly by unitary and furnace systems.");
3107 0 : ShowContinueError(state, "No water coil controller should be input for the coil.");
3108 0 : ErrorsFound = true;
3109 : }
3110 : }
3111 :
3112 0 : } else if (Util::SameString(SuppHeatCoilType, "Coil:Heating:Steam")) {
3113 0 : thisFurnace.SuppHeatCoilType_Num = HVAC::Coil_HeatingSteam;
3114 0 : ValidateComponent(state, SuppHeatCoilType, SuppHeatCoilName, IsNotOK, CurrentModuleObject);
3115 0 : if (IsNotOK) {
3116 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3117 0 : ErrorsFound = true;
3118 : } else { // mine data from heating coil object
3119 :
3120 0 : errFlag = false;
3121 0 : thisFurnace.SuppHeatCoilIndex = SteamCoils::GetSteamCoilIndex(state, "COIL:HEATING:STEAM", SuppHeatCoilName, errFlag);
3122 0 : if (thisFurnace.SuppHeatCoilIndex == 0) {
3123 0 : ShowSevereError(state, format("{} illegal {} = {}", CurrentModuleObject, cAlphaFields(12), SuppHeatCoilName));
3124 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3125 0 : ErrorsFound = true;
3126 : }
3127 :
3128 : // Get the Heating Coil steam inlet node number
3129 0 : errFlag = false;
3130 0 : thisFurnace.SuppCoilControlNode = SteamCoils::GetCoilSteamInletNode(state, "Coil:Heating:Steam", SuppHeatCoilName, errFlag);
3131 0 : if (errFlag) {
3132 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3133 0 : ErrorsFound = true;
3134 : }
3135 :
3136 : // Get the Heating Coil steam max volume flow rate
3137 0 : thisFurnace.MaxSuppCoilFluidFlow = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.SuppHeatCoilIndex, errFlag);
3138 0 : if (thisFurnace.MaxSuppCoilFluidFlow > 0.0) {
3139 0 : SteamIndex = 0; // Function GetSatDensityRefrig will look up steam index if 0 is passed
3140 0 : SteamDensity = FluidProperties::GetSatDensityRefrig(
3141 0 : state, fluidNameSteam, state.dataFurnaces->TempSteamIn, 1.0, SteamIndex, getAirLoopHVACHeatCoolInput);
3142 0 : thisFurnace.MaxSuppCoilFluidFlow =
3143 0 : SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.SuppHeatCoilIndex, errFlag) * SteamDensity;
3144 : }
3145 :
3146 : // Get the Heating Coil Inlet Node
3147 0 : errFlag = false;
3148 0 : SupHeatCoilInletNode = SteamCoils::GetCoilAirInletNode(state, thisFurnace.SuppHeatCoilIndex, SuppHeatCoilName, errFlag);
3149 0 : thisFurnace.SuppCoilAirInletNode = SupHeatCoilInletNode;
3150 0 : if (errFlag) {
3151 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3152 0 : ErrorsFound = true;
3153 : }
3154 :
3155 : // Get the Heating Coil Outlet Node
3156 0 : errFlag = false;
3157 0 : SupHeatCoilOutletNode = SteamCoils::GetCoilAirOutletNode(state, thisFurnace.SuppHeatCoilIndex, SuppHeatCoilName, errFlag);
3158 0 : thisFurnace.SuppCoilAirOutletNode = SupHeatCoilOutletNode;
3159 0 : if (errFlag) {
3160 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3161 0 : ErrorsFound = true;
3162 : }
3163 : }
3164 :
3165 : } else {
3166 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3167 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(12), Alphas(12)));
3168 0 : ErrorsFound = true;
3169 : } // IF (Furnace(FurnaceNum)%HeatingCoilType_Num == Coil_HeatingGasOrOtherFuel .OR. &, etc.
3170 :
3171 35 : thisFurnace.fanPlace = static_cast<HVAC::FanPlace>(getEnumValue(HVAC::fanPlaceNamesUC, Alphas(14)));
3172 35 : assert(thisFurnace.fanPlace != HVAC::FanPlace::Invalid);
3173 :
3174 35 : thisFurnace.FanSchedPtr = ScheduleManager::GetScheduleIndex(state, Alphas(15));
3175 35 : if (!lAlphaBlanks(15) && thisFurnace.FanSchedPtr == 0) {
3176 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3177 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(15), Alphas(15)));
3178 0 : ErrorsFound = true;
3179 35 : } else if (lAlphaBlanks(15)) {
3180 0 : thisFurnace.fanOp = HVAC::FanOp::Cycling;
3181 0 : if (thisFurnace.fanType != HVAC::FanType::OnOff) {
3182 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisFurnace.Name));
3183 0 : ShowContinueError(state, format("{} = {}", cAlphaFields(6), Alphas(6)));
3184 0 : ShowContinueError(state, format("Fan type must be Fan:OnOff when {} = Blank.", cAlphaFields(15)));
3185 0 : ErrorsFound = true;
3186 : }
3187 : }
3188 :
3189 35 : if (thisFurnace.fanType == HVAC::FanType::Constant) {
3190 0 : if (thisFurnace.FanSchedPtr > 0) {
3191 0 : if (!ScheduleManager::CheckScheduleValueMinMax(state, thisFurnace.FanSchedPtr, ">", 0.0, "<=", 1.0)) {
3192 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3193 0 : ShowContinueError(state, format("For {} = {}", cAlphaFields(7), Alphas(7)));
3194 0 : ShowContinueError(state, "Fan operating mode must be continuous (fan operating mode schedule values > 0).");
3195 0 : ShowContinueError(state, format("Error found in {} = {}", cAlphaFields(15), Alphas(15)));
3196 0 : ShowContinueError(state, "...schedule values must be (>0., <=1.)");
3197 0 : ErrorsFound = true;
3198 : }
3199 : }
3200 : }
3201 :
3202 : // Dehumidification Control Type
3203 35 : if (Util::SameString(Alphas(16), "None") || Util::SameString(Alphas(16), "Multimode") || Util::SameString(Alphas(16), "CoolReheat")) {
3204 35 : AirNodeFound = false;
3205 35 : if (Util::SameString(Alphas(16), "Multimode")) {
3206 0 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::Multimode;
3207 0 : thisFurnace.Humidistat = true;
3208 0 : if (thisFurnace.CoolingCoilType_Num != HVAC::CoilDX_CoolingHXAssisted) {
3209 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3210 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(16), Alphas(16)));
3211 0 : ShowContinueError(state, "Multimode control must be used with a Heat Exchanger Assisted Cooling Coil.");
3212 0 : ErrorsFound = true;
3213 : }
3214 : }
3215 35 : if (Util::SameString(Alphas(16), "CoolReheat")) {
3216 3 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::CoolReheat;
3217 3 : thisFurnace.Humidistat = true;
3218 : }
3219 35 : if (Util::SameString(Alphas(16), "None")) {
3220 32 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::None;
3221 32 : thisFurnace.Humidistat = false;
3222 : }
3223 35 : if (thisFurnace.Humidistat) {
3224 6 : for (HStatZoneNum = 1; HStatZoneNum <= state.dataZoneCtrls->NumHumidityControlZones; ++HStatZoneNum) {
3225 3 : if (state.dataZoneCtrls->HumidityControlZone(HStatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) continue;
3226 3 : AirNodeFound = true;
3227 : }
3228 3 : if (!AirNodeFound) {
3229 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3230 0 : ShowContinueError(state, "Did not find Air Node (Zone with Humidistat).");
3231 0 : ShowContinueError(state, format("Specified {} = {}", cAlphaFields(5), Alphas(5)));
3232 0 : ErrorsFound = true;
3233 : }
3234 : }
3235 : } else { // invalid input or blank
3236 0 : if (!lAlphaBlanks(16)) {
3237 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3238 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(16), Alphas(16)));
3239 0 : ErrorsFound = true;
3240 : } else {
3241 0 : thisFurnace.Humidistat = false;
3242 0 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::None;
3243 : }
3244 : }
3245 :
3246 : // Check node names for child components
3247 35 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
3248 35 : if (FanInletNode != thisFurnace.FurnaceInletNodeNum) {
3249 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, Alphas(1)));
3250 0 : ShowContinueError(
3251 : state,
3252 : "When a blow through fan is specified, the fan inlet node name must be the same as the unitary system inlet node name.");
3253 0 : ShowContinueError(state, format("...Fan inlet node name = {}", state.dataLoopNodes->NodeID(FanInletNode)));
3254 0 : ShowContinueError(state,
3255 0 : format("...Unitary system inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
3256 0 : ErrorsFound = true;
3257 : }
3258 35 : if (FanOutletNode != CoolingCoilInletNode) {
3259 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, Alphas(1)));
3260 0 : ShowContinueError(
3261 : state,
3262 : "When a blow through fan is specified, the fan outlet node name must be the same as the cooling coil inlet node name.");
3263 0 : ShowContinueError(state, format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
3264 0 : ShowContinueError(state, format("...Cooling coil inlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilInletNode)));
3265 0 : ErrorsFound = true;
3266 : }
3267 35 : if (CoolingCoilOutletNode != HeatingCoilInletNode) {
3268 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, Alphas(1)));
3269 0 : ShowContinueError(state, "The cooling coil outlet node name must be the same as the heating coil inlet node name.");
3270 0 : ShowContinueError(state, format("...Cooling coil outlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilOutletNode)));
3271 0 : ShowContinueError(state, format("...Heating coil inlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
3272 0 : ErrorsFound = true;
3273 : }
3274 35 : if (HeatingCoilOutletNode != SupHeatCoilInletNode) {
3275 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, Alphas(1)));
3276 0 : ShowContinueError(state,
3277 : "When a blow through fan is specified, the heating coil outlet node name must be the same as the supplemental "
3278 : "heating coil inlet node name.");
3279 0 : ShowContinueError(
3280 0 : state, format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
3281 0 : ShowContinueError(
3282 0 : state, format("...Supplemental heating coil inlet node name = {}", state.dataLoopNodes->NodeID(SupHeatCoilInletNode)));
3283 0 : ErrorsFound = true;
3284 : }
3285 35 : if (SupHeatCoilOutletNode != thisFurnace.FurnaceOutletNodeNum) {
3286 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, Alphas(1)));
3287 0 : ShowContinueError(state,
3288 : "The supplemental heating coil outlet node name must be the same as the unitary system outlet node name.");
3289 0 : ShowContinueError(
3290 0 : state, format("...Supplemental heating coil outlet node name = {}", state.dataLoopNodes->NodeID(SupHeatCoilOutletNode)));
3291 0 : ShowContinueError(
3292 : state,
3293 0 : format("...Unitary system outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
3294 0 : ErrorsFound = true;
3295 : }
3296 : } else {
3297 0 : if (CoolingCoilInletNode != thisFurnace.FurnaceInletNodeNum) {
3298 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, Alphas(1)));
3299 0 : ShowContinueError(state,
3300 : "When a draw through fan is specified, the cooling coil inlet node name must be the same as the unitary system "
3301 : "inlet node name.");
3302 0 : ShowContinueError(state, format("...Cooling coil inlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilInletNode)));
3303 0 : ShowContinueError(state,
3304 0 : format("...Unitary system inlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
3305 0 : ErrorsFound = true;
3306 : }
3307 0 : if (CoolingCoilOutletNode != HeatingCoilInletNode) {
3308 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, Alphas(1)));
3309 0 : ShowContinueError(state, "The cooling coil outlet node name must be the same as the heating coil inlet node name.");
3310 0 : ShowContinueError(state, format("...Cooling coil outlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilOutletNode)));
3311 0 : ShowContinueError(state, format("...Heating coil inlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
3312 0 : ErrorsFound = true;
3313 : }
3314 0 : if (HeatingCoilOutletNode != FanInletNode) {
3315 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, Alphas(1)));
3316 0 : ShowContinueError(
3317 : state,
3318 : "When a draw through fan is specified, the heating coil outlet node name must be the same as the fan inlet node name.");
3319 0 : ShowContinueError(state, format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
3320 0 : ShowContinueError(state, format("...Fan inlet node name = {}", state.dataLoopNodes->NodeID(FanInletNode)));
3321 0 : ErrorsFound = true;
3322 : }
3323 0 : if (FanOutletNode != SupHeatCoilInletNode) {
3324 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, Alphas(1)));
3325 0 : ShowContinueError(state,
3326 : "When a draw through fan is specified, the fan outlet node name must be the same as the supplemental heating "
3327 : "coil inlet node name.");
3328 0 : ShowContinueError(state,
3329 0 : format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
3330 0 : ShowContinueError(
3331 0 : state, format("...Supplemental heating coil inlet node name = {}", state.dataLoopNodes->NodeID(SupHeatCoilInletNode)));
3332 0 : ErrorsFound = true;
3333 : }
3334 0 : if (SupHeatCoilOutletNode != thisFurnace.FurnaceOutletNodeNum) {
3335 0 : ShowSevereError(state, format("For {} \"{}\"", CurrentModuleObject, Alphas(1)));
3336 0 : ShowContinueError(state,
3337 : "The supplemental heating coil outlet node name must be the same as the unitary system outlet node name.");
3338 0 : ShowContinueError(
3339 0 : state, format("...Supplemental heating coil outlet node name = {}", state.dataLoopNodes->NodeID(SupHeatCoilOutletNode)));
3340 0 : ShowContinueError(
3341 : state,
3342 0 : format("...Unitary system outlet node name = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
3343 0 : ErrorsFound = true;
3344 : }
3345 : }
3346 :
3347 : // Add component sets array
3348 35 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
3349 35 : CompSetFanInlet = Alphas(3);
3350 35 : CompSetCoolInlet = "UNDEFINED";
3351 : } else {
3352 0 : CompSetFanInlet = "UNDEFINED";
3353 0 : CompSetCoolInlet = Alphas(3);
3354 : }
3355 35 : BranchNodeConnections::SetUpCompSets(state, CurrentModuleObject, Alphas(1), Alphas(6), Alphas(7), CompSetFanInlet, "UNDEFINED");
3356 :
3357 : // Add DX cooling coil to component sets array
3358 35 : if (thisFurnace.bIsIHP) {
3359 3 : BranchNodeConnections::SetUpCompSets(
3360 3 : state, CurrentModuleObject, Alphas(1), Alphas(10), Alphas(11) + " Cooling Coil", CompSetCoolInlet, "UNDEFINED");
3361 : } else {
3362 34 : BranchNodeConnections::SetUpCompSets(state, CurrentModuleObject, Alphas(1), Alphas(10), Alphas(11), CompSetCoolInlet, "UNDEFINED");
3363 : }
3364 : // Add DX heating coil to component sets array
3365 35 : if (thisFurnace.bIsIHP) {
3366 3 : BranchNodeConnections::SetUpCompSets(
3367 3 : state, CurrentModuleObject, Alphas(1), Alphas(8), Alphas(9) + " Heating Coil", "UNDEFINED", "UNDEFINED");
3368 : } else {
3369 34 : BranchNodeConnections::SetUpCompSets(state, CurrentModuleObject, Alphas(1), Alphas(8), Alphas(9), "UNDEFINED", "UNDEFINED");
3370 : }
3371 :
3372 : // Add supplemental heating coil to component sets array
3373 35 : BranchNodeConnections::SetUpCompSets(state, CurrentModuleObject, Alphas(1), Alphas(12), Alphas(13), "UNDEFINED", Alphas(4));
3374 :
3375 35 : thisFurnace.MaxCoolAirVolFlow = Numbers(1);
3376 35 : if (thisFurnace.MaxCoolAirVolFlow <= 0 && thisFurnace.MaxCoolAirVolFlow != DataSizing::AutoSize) {
3377 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3378 0 : ShowContinueError(state, format("Illegal {} = {:.7T}", cNumericFields(1), Numbers(1)));
3379 0 : ErrorsFound = true;
3380 : }
3381 :
3382 35 : thisFurnace.MaxHeatAirVolFlow = Numbers(2);
3383 35 : if (thisFurnace.MaxHeatAirVolFlow <= 0 && thisFurnace.MaxHeatAirVolFlow != DataSizing::AutoSize) {
3384 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3385 0 : ShowContinueError(state, format("Illegal {} = {:.7T}", cNumericFields(2), Numbers(2)));
3386 0 : ErrorsFound = true;
3387 : }
3388 :
3389 35 : thisFurnace.MaxNoCoolHeatAirVolFlow = Numbers(3);
3390 35 : if (thisFurnace.MaxNoCoolHeatAirVolFlow < 0 && thisFurnace.MaxNoCoolHeatAirVolFlow != DataSizing::AutoSize) {
3391 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3392 0 : ShowContinueError(state, format("Illegal {} = {:.7T}", cNumericFields(3), Numbers(3)));
3393 0 : ErrorsFound = true;
3394 : }
3395 :
3396 35 : if (thisFurnace.FanSchedPtr > 0) {
3397 35 : if (!ScheduleManager::CheckScheduleValueMinMax(
3398 : state, thisFurnace.FanSchedPtr, ">=", 0.0, "<=", 0.0)) { // Autodesk:Note Range is 0 to 0?
3399 : // set air flow control mode:
3400 : // UseCompressorOnFlow = operate at last cooling or heating air flow requested when compressor is off
3401 : // UseCompressorOffFlow = operate at value specified by user
3402 : // AirFlowControl only valid if fan opmode = ContFanCycComp
3403 16 : if (thisFurnace.MaxNoCoolHeatAirVolFlow == 0.0) {
3404 0 : thisFurnace.AirFlowControl = AirFlowControlConstFan::UseCompressorOnFlow;
3405 : } else {
3406 16 : thisFurnace.AirFlowControl = AirFlowControlConstFan::UseCompressorOffFlow;
3407 : }
3408 : }
3409 : }
3410 :
3411 35 : if (Numbers(1) != DataSizing::AutoSize && Numbers(2) != DataSizing::AutoSize && Numbers(3) != DataSizing::AutoSize) {
3412 21 : thisFurnace.DesignFanVolFlowRate = max(Numbers(1), Numbers(2), Numbers(3));
3413 : } else {
3414 14 : thisFurnace.DesignFanVolFlowRate = DataSizing::AutoSize;
3415 : }
3416 :
3417 35 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed) {
3418 3 : errFlag = false;
3419 :
3420 3 : if (thisFurnace.bIsIHP) {
3421 1 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SHCoilName;
3422 1 : thisFurnace.MaxHeatAirVolFlow =
3423 1 : VariableSpeedCoils::GetCoilAirFlowRateVariableSpeed(state, "COIL:HEATING:DX:VARIABLESPEED", IHPCoilName, errFlag);
3424 1 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SCCoilName;
3425 1 : thisFurnace.MaxCoolAirVolFlow =
3426 1 : VariableSpeedCoils::GetCoilAirFlowRateVariableSpeed(state, "COIL:COOLING:DX:VARIABLESPEED", IHPCoilName, errFlag);
3427 : } else {
3428 2 : thisFurnace.MaxHeatAirVolFlow =
3429 2 : VariableSpeedCoils::GetCoilAirFlowRateVariableSpeed(state, HeatingCoilType, HeatingCoilName, errFlag);
3430 2 : thisFurnace.MaxCoolAirVolFlow =
3431 2 : VariableSpeedCoils::GetCoilAirFlowRateVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
3432 : }
3433 :
3434 3 : if (errFlag) {
3435 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3436 0 : ErrorsFound = true;
3437 : }
3438 :
3439 3 : thisFurnace.MaxNoCoolHeatAirVolFlow = min(thisFurnace.MaxHeatAirVolFlow, thisFurnace.MaxCoolAirVolFlow);
3440 3 : if (thisFurnace.MaxHeatAirVolFlow != DataSizing::AutoSize && thisFurnace.MaxCoolAirVolFlow != DataSizing::AutoSize) {
3441 3 : thisFurnace.DesignFanVolFlowRate = max(thisFurnace.MaxHeatAirVolFlow, thisFurnace.MaxCoolAirVolFlow);
3442 : } else {
3443 0 : thisFurnace.DesignFanVolFlowRate = DataSizing::AutoSize;
3444 : }
3445 : }
3446 :
3447 35 : if (thisFurnace.ActualFanVolFlowRate != DataSizing::AutoSize) {
3448 21 : if (thisFurnace.ActualFanVolFlowRate < thisFurnace.MaxCoolAirVolFlow && thisFurnace.MaxCoolAirVolFlow != DataSizing::AutoSize) {
3449 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3450 0 : ShowContinueError(
3451 : state,
3452 0 : format("... air flow rate = {:.7T} in fan object {} is less than the maximum HVAC system air flow rate in cooling mode.",
3453 0 : thisFurnace.ActualFanVolFlowRate,
3454 : FanName));
3455 0 : ShowContinueError(state, format(" The {} is reset to the fan flow rate and the simulation continues.", cNumericFields(1)));
3456 0 : thisFurnace.MaxCoolAirVolFlow = thisFurnace.ActualFanVolFlowRate;
3457 0 : thisFurnace.DesignFanVolFlowRate = thisFurnace.ActualFanVolFlowRate;
3458 : }
3459 21 : if (thisFurnace.ActualFanVolFlowRate < thisFurnace.MaxHeatAirVolFlow && thisFurnace.MaxHeatAirVolFlow != DataSizing::AutoSize) {
3460 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3461 0 : ShowContinueError(
3462 : state,
3463 0 : format("... air flow rate = {:.7T} in fan object {} is less than the maximum HVAC system air flow rate in heating mode.",
3464 0 : thisFurnace.ActualFanVolFlowRate,
3465 : FanName));
3466 0 : ShowContinueError(state, format(" The {} is reset to the fan flow rate and the simulation continues.", cNumericFields(2)));
3467 0 : thisFurnace.MaxHeatAirVolFlow = thisFurnace.ActualFanVolFlowRate;
3468 0 : thisFurnace.DesignFanVolFlowRate = thisFurnace.ActualFanVolFlowRate;
3469 : }
3470 : }
3471 :
3472 : // Set heating convergence tolerance
3473 35 : thisFurnace.HeatingConvergenceTolerance = 0.001;
3474 :
3475 : // Mine heatpump outdoor condenser node from DX coil object
3476 35 : errFlag = false;
3477 35 : if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingSingleSpeed) {
3478 32 : thisFurnace.CondenserNodeNum = DXCoils::GetCoilCondenserInletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
3479 3 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) {
3480 3 : if (thisFurnace.bIsIHP) {
3481 1 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SCCoilName;
3482 1 : thisFurnace.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, IHPCoilName, errFlag);
3483 : } else {
3484 2 : thisFurnace.CondenserNodeNum = VariableSpeedCoils::GetVSCoilCondenserInletNode(state, CoolingCoilName, errFlag);
3485 : }
3486 : } else {
3487 0 : thisFurnace.CondenserNodeNum =
3488 0 : DXCoils::GetCoilCondenserInletNode(state,
3489 : "Coil:Cooling:DX:SingleSpeed",
3490 0 : HVACHXAssistedCoolingCoil::GetHXDXCoilName(state, CoolingCoilType, CoolingCoilName, errFlag),
3491 : errFlag);
3492 : }
3493 35 : if (errFlag) {
3494 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3495 0 : ErrorsFound = true;
3496 : }
3497 :
3498 35 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed) {
3499 3 : errFlag = false;
3500 3 : if (thisFurnace.bIsIHP) {
3501 1 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SHCoilName;
3502 1 : thisFurnace.DesignHeatingCapacity =
3503 1 : VariableSpeedCoils::GetCoilCapacityVariableSpeed(state, "Coil:Heating:DX:VariableSpeed", IHPCoilName, errFlag);
3504 : } else {
3505 2 : thisFurnace.DesignHeatingCapacity =
3506 2 : VariableSpeedCoils::GetCoilCapacityVariableSpeed(state, HeatingCoilType, HeatingCoilName, errFlag);
3507 : }
3508 :
3509 3 : if (errFlag) {
3510 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3511 0 : ErrorsFound = true;
3512 : }
3513 : }
3514 :
3515 35 : if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) {
3516 3 : errFlag = false;
3517 3 : if (thisFurnace.bIsIHP) {
3518 1 : IHPCoilName = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SCCoilName;
3519 1 : thisFurnace.DesignCoolingCapacity =
3520 1 : VariableSpeedCoils::GetCoilCapacityVariableSpeed(state, "COIL:COOLING:DX:VARIABLESPEED", IHPCoilName, errFlag);
3521 : } else {
3522 2 : thisFurnace.DesignCoolingCapacity =
3523 2 : VariableSpeedCoils::GetCoilCapacityVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
3524 : }
3525 :
3526 3 : if (errFlag) {
3527 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3528 0 : ErrorsFound = true;
3529 : }
3530 : }
3531 :
3532 : // Set cooling convergence tolerance
3533 35 : thisFurnace.CoolingConvergenceTolerance = 0.001;
3534 :
3535 : // Set the furnace max outlet temperature
3536 35 : thisFurnace.DesignMaxOutletTemp = Numbers(4);
3537 :
3538 : // Set maximum supply air temperature for supplemental heating coil
3539 35 : thisFurnace.MaxOATSuppHeat = Numbers(5);
3540 70 : OutputReportPredefined::PreDefTableEntry(
3541 35 : state, state.dataOutRptPredefined->pdchDXHeatCoilSuppHiT, HeatingCoilName, thisFurnace.MaxOATSuppHeat);
3542 :
3543 : // set minimum outdoor temperature for compressor operation
3544 35 : SetMinOATCompressor(state, FurnaceNum, cCurrentModuleObject, ErrorsFound);
3545 :
3546 : } // End of the Unitary System HeatPump Loop
3547 :
3548 : // Get the Input for the Water to Air Heat Pump (UnitarySystem:HeatPump:WaterToAir)
3549 236 : for (int HeatPumpNum = 1; HeatPumpNum <= NumWaterToAirHeatPump; ++HeatPumpNum) {
3550 :
3551 139 : CurrentModuleObject = "AirLoopHVAC:UnitaryHeatPump:WaterToAir";
3552 139 : FanInletNode = 0;
3553 139 : FanOutletNode = 0;
3554 139 : CoolingCoilInletNode = 0;
3555 139 : CoolingCoilOutletNode = 0;
3556 139 : HeatingCoilInletNode = 0;
3557 139 : HeatingCoilOutletNode = 0;
3558 139 : SupHeatCoilInletNode = 0;
3559 139 : SupHeatCoilOutletNode = 0;
3560 139 : CoolingCoilType = ' ';
3561 139 : CoolingCoilName = ' ';
3562 139 : HeatingCoilType = ' ';
3563 139 : HeatingCoilName = ' ';
3564 :
3565 139 : FurnaceNum = NumHeatOnly + NumHeatCool + NumUnitaryHeatOnly + NumUnitaryHeatCool + NumHeatPump + HeatPumpNum;
3566 139 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
3567 139 : thisFurnace.iterationMode.allocate(3);
3568 :
3569 139 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
3570 : CurrentModuleObject,
3571 : HeatPumpNum,
3572 : Alphas,
3573 : NumAlphas,
3574 : Numbers,
3575 : NumNumbers,
3576 : IOStatus,
3577 : lNumericBlanks,
3578 : lAlphaBlanks,
3579 : cAlphaFields,
3580 : cNumericFields);
3581 :
3582 278 : GlobalNames::VerifyUniqueInterObjectName(
3583 139 : state, state.dataFurnaces->UniqueFurnaceNames, Alphas(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
3584 :
3585 139 : thisFurnace.type = HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir;
3586 139 : thisFurnace.Name = Alphas(1);
3587 :
3588 139 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, thisFurnace.Name};
3589 :
3590 139 : if (lAlphaBlanks(2)) {
3591 0 : thisFurnace.SchedPtr = ScheduleManager::ScheduleAlwaysOn;
3592 : } else {
3593 139 : thisFurnace.SchedPtr = ScheduleManager::GetScheduleIndex(state, Alphas(2));
3594 139 : if (thisFurnace.SchedPtr == 0) {
3595 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3596 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(2), Alphas(2)));
3597 0 : ErrorsFound = true;
3598 : }
3599 : }
3600 :
3601 139 : thisFurnace.FurnaceInletNodeNum =
3602 139 : NodeInputManager::GetOnlySingleNode(state,
3603 139 : Alphas(3),
3604 : ErrorsFound,
3605 : DataLoopNode::ConnectionObjectType::AirLoopHVACUnitaryHeatPumpWaterToAir,
3606 139 : Alphas(1),
3607 : DataLoopNode::NodeFluidType::Air,
3608 : DataLoopNode::ConnectionType::Inlet,
3609 : NodeInputManager::CompFluidStream::Primary,
3610 : DataLoopNode::ObjectIsParent);
3611 :
3612 139 : thisFurnace.FurnaceOutletNodeNum =
3613 139 : NodeInputManager::GetOnlySingleNode(state,
3614 139 : Alphas(4),
3615 : ErrorsFound,
3616 : DataLoopNode::ConnectionObjectType::AirLoopHVACUnitaryHeatPumpWaterToAir,
3617 139 : Alphas(1),
3618 : DataLoopNode::NodeFluidType::Air,
3619 : DataLoopNode::ConnectionType::Outlet,
3620 : NodeInputManager::CompFluidStream::Primary,
3621 : DataLoopNode::ObjectIsParent);
3622 :
3623 139 : BranchNodeConnections::TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(3), Alphas(4), "Air Nodes");
3624 :
3625 : // Get the Controlling Zone or Location of the Furnace Thermostat
3626 139 : thisFurnace.ControlZoneNum = Util::FindItemInList(Alphas(5), state.dataHeatBal->Zone);
3627 139 : if (thisFurnace.ControlZoneNum == 0) {
3628 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3629 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(5), Alphas(5)));
3630 0 : ErrorsFound = true;
3631 : }
3632 :
3633 : // Get the node number for the zone with the thermostat
3634 139 : if (thisFurnace.ControlZoneNum > 0) {
3635 139 : AirNodeFound = false;
3636 139 : AirLoopFound = false;
3637 139 : int ControlledZoneNum = thisFurnace.ControlZoneNum;
3638 : // Find the controlled zone number for the specified thermostat location
3639 139 : thisFurnace.NodeNumOfControlledZone = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneNode;
3640 : // Determine if furnace is on air loop served by the thermostat location specified
3641 139 : for (int zoneInNode = 1; zoneInNode <= state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumInletNodes; ++zoneInNode) {
3642 139 : int AirLoopNumber = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNodeAirLoopNum(zoneInNode);
3643 139 : if (AirLoopNumber > 0) {
3644 139 : for (int BranchNum = 1; BranchNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).NumBranches; ++BranchNum) {
3645 268 : for (int CompNum = 1;
3646 268 : CompNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).TotalComponents;
3647 : ++CompNum) {
3648 268 : if (!Util::SameString(state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).Name,
3649 675 : Alphas(1)) ||
3650 139 : !Util::SameString(
3651 139 : state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).TypeOf,
3652 : CurrentModuleObject))
3653 129 : continue;
3654 139 : AirLoopFound = true;
3655 139 : thisFurnace.ZoneInletNode = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNode(zoneInNode);
3656 139 : break;
3657 : }
3658 139 : if (AirLoopFound) break;
3659 : }
3660 7066 : for (TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumTempControlledZones; ++TstatZoneNum) {
3661 6927 : if (state.dataZoneCtrls->TempControlledZone(TstatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) continue;
3662 139 : AirNodeFound = true;
3663 : }
3664 139 : for (TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumComfortControlledZones; ++TstatZoneNum) {
3665 0 : if (state.dataZoneCtrls->ComfortControlledZone(TstatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) continue;
3666 0 : AirNodeFound = true;
3667 : }
3668 : }
3669 139 : if (AirLoopFound) break;
3670 : }
3671 139 : if (!AirNodeFound) {
3672 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3673 0 : ShowContinueError(state, "Did not find air node (zone with thermostat).");
3674 0 : ShowContinueError(state, format("Specified {} = {}", cAlphaFields(5), Alphas(5)));
3675 0 : ShowContinueError(
3676 : state, "Both a ZoneHVAC:EquipmentConnections object and a ZoneControl:Thermostat object must be specified for this zone.");
3677 0 : ErrorsFound = true;
3678 : }
3679 139 : if (!AirLoopFound) {
3680 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3681 0 : ShowContinueError(state, "Did not find correct AirLoopHVAC.");
3682 0 : ShowContinueError(state, format("Specified {} = {}", cAlphaFields(5), Alphas(5)));
3683 0 : ErrorsFound = true;
3684 : }
3685 : }
3686 :
3687 : // Get fan data
3688 139 : FanName = Alphas(7);
3689 139 : errFlag = false;
3690 139 : thisFurnace.fanType = static_cast<HVAC::FanType>(getEnumValue(HVAC::fanTypeNamesUC, Alphas(6)));
3691 :
3692 139 : if (thisFurnace.fanType != HVAC::FanType::OnOff) {
3693 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3694 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(6), Alphas(6)));
3695 0 : ErrorsFound = true;
3696 :
3697 139 : } else if ((thisFurnace.FanIndex = Fans::GetFanIndex(state, FanName)) == 0) {
3698 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(7), FanName);
3699 0 : ErrorsFound = true;
3700 :
3701 : } else {
3702 139 : auto *fan = state.dataFans->fans(thisFurnace.FanIndex);
3703 139 : FanInletNode = fan->inletNodeNum;
3704 139 : FanOutletNode = fan->outletNodeNum;
3705 139 : thisFurnace.FanAvailSchedPtr = fan->availSchedNum;
3706 : }
3707 :
3708 : // Get heating coil type and name data
3709 139 : if (Alphas(8) == "COIL:HEATING:WATERTOAIRHEATPUMP:PARAMETERESTIMATION") {
3710 14 : HeatingCoilType = Alphas(8);
3711 14 : thisFurnace.HeatingCoilType_Num = HVAC::Coil_HeatingWaterToAirHP;
3712 14 : HeatingCoilName = Alphas(9);
3713 14 : ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject);
3714 14 : if (IsNotOK) {
3715 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3716 0 : ErrorsFound = true;
3717 : } else {
3718 14 : thisFurnace.HeatingCoilIndex = WaterToAirHeatPump::GetCoilIndex(state, HeatingCoilType, HeatingCoilName, errFlag);
3719 14 : HeatingCoilInletNode = WaterToAirHeatPump::GetCoilInletNode(state, HeatingCoilType, HeatingCoilName, errFlag);
3720 14 : HeatingCoilOutletNode = WaterToAirHeatPump::GetCoilOutletNode(state, HeatingCoilType, HeatingCoilName, errFlag);
3721 : }
3722 125 : } else if (Alphas(8) == "COIL:HEATING:WATERTOAIRHEATPUMP:EQUATIONFIT") {
3723 111 : HeatingCoilType = Alphas(8);
3724 111 : thisFurnace.HeatingCoilType_Num = HVAC::Coil_HeatingWaterToAirHPSimple;
3725 111 : HeatingCoilName = Alphas(9);
3726 111 : ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject);
3727 111 : if (IsNotOK) {
3728 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3729 0 : ErrorsFound = true;
3730 : } else {
3731 111 : thisFurnace.HeatingCoilIndex = WaterToAirHeatPumpSimple::GetCoilIndex(state, HeatingCoilType, HeatingCoilName, errFlag);
3732 111 : HeatingCoilInletNode = WaterToAirHeatPumpSimple::GetCoilInletNode(state, HeatingCoilType, HeatingCoilName, errFlag);
3733 111 : HeatingCoilOutletNode = WaterToAirHeatPumpSimple::GetCoilOutletNode(state, HeatingCoilType, HeatingCoilName, errFlag);
3734 : }
3735 14 : } else if (Alphas(8) == "COIL:HEATING:WATERTOAIRHEATPUMP:VARIABLESPEEDEQUATIONFIT") {
3736 14 : HeatingCoilType = Alphas(8);
3737 14 : thisFurnace.HeatingCoilType_Num = HVAC::Coil_HeatingWaterToAirHPVSEquationFit;
3738 14 : HeatingCoilName = Alphas(9);
3739 14 : ValidateComponent(state, HeatingCoilType, HeatingCoilName, IsNotOK, CurrentModuleObject);
3740 14 : if (IsNotOK) {
3741 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3742 0 : ErrorsFound = true;
3743 : } else {
3744 14 : thisFurnace.HeatingCoilIndex = VariableSpeedCoils::GetCoilIndexVariableSpeed(state, HeatingCoilType, HeatingCoilName, errFlag);
3745 14 : HeatingCoilInletNode = VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, HeatingCoilType, HeatingCoilName, errFlag);
3746 14 : HeatingCoilOutletNode = VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, HeatingCoilType, HeatingCoilName, errFlag);
3747 : }
3748 : } else {
3749 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3750 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(8), Alphas(8)));
3751 0 : ErrorsFound = true;
3752 : }
3753 :
3754 : // Get Cooling Coil Information if available
3755 139 : if (Alphas(10) == "COIL:COOLING:WATERTOAIRHEATPUMP:PARAMETERESTIMATION") {
3756 14 : CoolingCoilType = Alphas(10);
3757 14 : thisFurnace.CoolingCoilType_Num = HVAC::Coil_CoolingWaterToAirHP;
3758 14 : CoolingCoilName = Alphas(11);
3759 14 : ValidateComponent(state, CoolingCoilType, CoolingCoilName, IsNotOK, CurrentModuleObject);
3760 14 : if (IsNotOK) {
3761 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3762 0 : ErrorsFound = true;
3763 : } else {
3764 14 : thisFurnace.CoolingCoilIndex = WaterToAirHeatPump::GetCoilIndex(state, CoolingCoilType, CoolingCoilName, errFlag);
3765 14 : CoolingCoilInletNode = WaterToAirHeatPump::GetCoilInletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
3766 14 : CoolingCoilOutletNode = WaterToAirHeatPump::GetCoilOutletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
3767 : }
3768 125 : } else if (Alphas(10) == "COIL:COOLING:WATERTOAIRHEATPUMP:EQUATIONFIT") {
3769 111 : CoolingCoilType = Alphas(10);
3770 111 : thisFurnace.CoolingCoilType_Num = HVAC::Coil_CoolingWaterToAirHPSimple;
3771 111 : CoolingCoilName = Alphas(11);
3772 111 : ValidateComponent(state, CoolingCoilType, CoolingCoilName, IsNotOK, CurrentModuleObject);
3773 111 : if (IsNotOK) {
3774 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3775 0 : ErrorsFound = true;
3776 : } else {
3777 111 : thisFurnace.CoolingCoilIndex = WaterToAirHeatPumpSimple::GetCoilIndex(state, CoolingCoilType, CoolingCoilName, errFlag);
3778 111 : CoolingCoilInletNode = WaterToAirHeatPumpSimple::GetCoilInletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
3779 111 : CoolingCoilOutletNode = WaterToAirHeatPumpSimple::GetCoilOutletNode(state, CoolingCoilType, CoolingCoilName, errFlag);
3780 : }
3781 14 : } else if (Alphas(10) == "COIL:COOLING:WATERTOAIRHEATPUMP:VARIABLESPEEDEQUATIONFIT") {
3782 14 : CoolingCoilType = Alphas(10);
3783 14 : thisFurnace.CoolingCoilType_Num = HVAC::Coil_CoolingWaterToAirHPVSEquationFit;
3784 14 : CoolingCoilName = Alphas(11);
3785 14 : ValidateComponent(state, CoolingCoilType, CoolingCoilName, IsNotOK, CurrentModuleObject);
3786 14 : if (IsNotOK) {
3787 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3788 0 : ErrorsFound = true;
3789 : } else {
3790 14 : thisFurnace.CoolingCoilIndex = VariableSpeedCoils::GetCoilIndexVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
3791 14 : CoolingCoilInletNode = VariableSpeedCoils::GetCoilInletNodeVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
3792 14 : CoolingCoilOutletNode = VariableSpeedCoils::GetCoilOutletNodeVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
3793 : }
3794 : } else {
3795 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3796 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(10), Alphas(10)));
3797 0 : ErrorsFound = true;
3798 : }
3799 :
3800 0 : thisFurnace.WaterCyclingMode = (NumAlphas < 18 || lAlphaBlanks(18))
3801 139 : ? HVAC::WaterFlow::Cycling
3802 0 : : static_cast<HVAC::WaterFlow>(getEnumValue(HVAC::waterFlowNamesUC, Alphas(18)));
3803 :
3804 : // end get water flow mode info
3805 139 : if (Alphas(8) == "COIL:HEATING:WATERTOAIRHEATPUMP:EQUATIONFIT" && Alphas(10) == "COIL:COOLING:WATERTOAIRHEATPUMP:EQUATIONFIT") {
3806 111 : thisFurnace.WatertoAirHPType = WAHPCoilType::Simple;
3807 111 : WaterToAirHeatPumpSimple::SetSimpleWSHPData(
3808 111 : state, thisFurnace.CoolingCoilIndex, ErrorsFound, thisFurnace.WaterCyclingMode, _, thisFurnace.HeatingCoilIndex);
3809 42 : } else if (Alphas(8) == "COIL:HEATING:WATERTOAIRHEATPUMP:PARAMETERESTIMATION" &&
3810 14 : Alphas(10) == "COIL:COOLING:WATERTOAIRHEATPUMP:PARAMETERESTIMATION") {
3811 14 : thisFurnace.WatertoAirHPType = WAHPCoilType::ParEst;
3812 28 : } else if (Alphas(8) == "COIL:HEATING:WATERTOAIRHEATPUMP:VARIABLESPEEDEQUATIONFIT" &&
3813 14 : Alphas(10) == "COIL:COOLING:WATERTOAIRHEATPUMP:VARIABLESPEEDEQUATIONFIT") {
3814 14 : thisFurnace.WatertoAirHPType = WAHPCoilType::VarSpeedEquationFit;
3815 14 : VariableSpeedCoils::SetVarSpeedCoilData(state, thisFurnace.CoolingCoilIndex, ErrorsFound, _, thisFurnace.HeatingCoilIndex);
3816 : } else {
3817 0 : ShowContinueError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
3818 0 : ShowContinueError(state, "Cooling coil and heating coil should be of same general type");
3819 0 : ErrorsFound = true;
3820 : }
3821 :
3822 : // Get supplemental heating coil information
3823 :
3824 139 : SuppHeatCoilType = Alphas(12);
3825 139 : SuppHeatCoilName = Alphas(13);
3826 139 : thisFurnace.SuppHeatCoilType = SuppHeatCoilType;
3827 139 : thisFurnace.SuppHeatCoilName = SuppHeatCoilName;
3828 139 : errFlag = false;
3829 139 : if (Util::SameString(SuppHeatCoilType, "Coil:Heating:Fuel") || Util::SameString(SuppHeatCoilType, "Coil:Heating:Electric")) {
3830 :
3831 139 : thisFurnace.SuppHeatCoilType_Num = HeatingCoils::GetHeatingCoilTypeNum(state, SuppHeatCoilType, SuppHeatCoilName, errFlag);
3832 139 : if (errFlag) {
3833 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3834 0 : ErrorsFound = true;
3835 : } else {
3836 139 : IsNotOK = false;
3837 139 : ValidateComponent(state, SuppHeatCoilType, SuppHeatCoilName, IsNotOK, CurrentModuleObject);
3838 139 : if (IsNotOK) {
3839 0 : ShowContinueError(state, format("In {} \"{}\"", CurrentModuleObject, Alphas(1)));
3840 0 : ErrorsFound = true;
3841 :
3842 : } else { // mine data from the supplemental heating coil
3843 :
3844 139 : HeatingCoils::GetCoilIndex(state, SuppHeatCoilName, thisFurnace.SuppHeatCoilIndex, IsNotOK);
3845 139 : if (IsNotOK) {
3846 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3847 0 : ErrorsFound = true;
3848 : }
3849 :
3850 : // Get the Supplemental Heating Coil Inlet Node Number
3851 139 : errFlag = false;
3852 139 : SupHeatCoilInletNode = HeatingCoils::GetCoilInletNode(state, SuppHeatCoilType, SuppHeatCoilName, errFlag);
3853 139 : if (errFlag) {
3854 0 : ShowContinueError(state, format("...occurs in {} \"{}\"", CurrentModuleObject, Alphas(1)));
3855 0 : ErrorsFound = true;
3856 : }
3857 :
3858 : // Get the Supplemental Heating Coil Outlet Node Number
3859 139 : errFlag = false;
3860 139 : SupHeatCoilOutletNode = HeatingCoils::GetCoilOutletNode(state, SuppHeatCoilType, SuppHeatCoilName, errFlag);
3861 139 : if (errFlag) {
3862 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3863 0 : ErrorsFound = true;
3864 : }
3865 :
3866 : // Get the supplemental heating coil design capacity
3867 139 : errFlag = false;
3868 139 : thisFurnace.DesignSuppHeatingCapacity = HeatingCoils::GetCoilCapacity(state, SuppHeatCoilType, SuppHeatCoilName, errFlag);
3869 139 : if (errFlag) {
3870 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3871 0 : ErrorsFound = true;
3872 : }
3873 :
3874 : } // IF (IsNotOK) THEN
3875 : }
3876 0 : } else if (Util::SameString(SuppHeatCoilType, "Coil:Heating:Water")) {
3877 0 : thisFurnace.SuppHeatCoilType_Num = HVAC::Coil_HeatingWater;
3878 0 : ValidateComponent(state, SuppHeatCoilType, SuppHeatCoilName, IsNotOK, CurrentModuleObject);
3879 0 : if (IsNotOK) {
3880 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3881 0 : ErrorsFound = true;
3882 : } else { // mine data from heating coil object
3883 :
3884 : // Get the Heating Coil water Inlet or control Node number
3885 0 : errFlag = false;
3886 0 : thisFurnace.SuppCoilControlNode = WaterCoils::GetCoilWaterInletNode(state, "Coil:Heating:Water", SuppHeatCoilName, errFlag);
3887 0 : if (errFlag) {
3888 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3889 0 : ErrorsFound = true;
3890 : }
3891 :
3892 : // Get the ReHeat Coil hot water max volume flow rate
3893 0 : errFlag = false;
3894 0 : thisFurnace.MaxSuppCoilFluidFlow = WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", SuppHeatCoilName, errFlag);
3895 0 : if (errFlag) {
3896 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3897 0 : ErrorsFound = true;
3898 : }
3899 :
3900 : // Get the ReHeat Coil Inlet Node
3901 0 : errFlag = false;
3902 0 : SupHeatCoilInletNode = WaterCoils::GetCoilInletNode(state, "Coil:Heating:Water", SuppHeatCoilName, errFlag);
3903 0 : thisFurnace.SuppCoilAirInletNode = SupHeatCoilInletNode;
3904 0 : if (errFlag) {
3905 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3906 0 : ErrorsFound = true;
3907 : }
3908 :
3909 : // Get the ReHeat Coil Outlet Node
3910 0 : errFlag = false;
3911 0 : SupHeatCoilOutletNode = WaterCoils::GetCoilOutletNode(state, "Coil:Heating:Water", SuppHeatCoilName, errFlag);
3912 0 : thisFurnace.SuppCoilAirOutletNode = SupHeatCoilOutletNode;
3913 0 : if (errFlag) {
3914 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3915 0 : ErrorsFound = true;
3916 : }
3917 :
3918 0 : errFlag = false;
3919 0 : HVACControllers::CheckCoilWaterInletNode(state, thisFurnace.CoilControlNode, errFlag);
3920 0 : if (!errFlag) { // then did find a controller so that is bad
3921 0 : ShowSevereError(state,
3922 0 : format("{} = {} has a conflicting Controller:WaterCoil object", CurrentModuleObject, thisFurnace.Name));
3923 0 : ShowContinueError(state, "Hot water coils are controlled directly by unitary and furnace systems.");
3924 0 : ShowContinueError(state, "No water coil controller should be input for the coil.");
3925 0 : ErrorsFound = true;
3926 : }
3927 : }
3928 :
3929 0 : } else if (Util::SameString(SuppHeatCoilType, "Coil:Heating:Steam")) {
3930 0 : thisFurnace.SuppHeatCoilType_Num = HVAC::Coil_HeatingSteam;
3931 0 : ValidateComponent(state, SuppHeatCoilType, SuppHeatCoilName, IsNotOK, CurrentModuleObject);
3932 0 : if (IsNotOK) {
3933 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
3934 0 : ErrorsFound = true;
3935 : } else { // mine data from heating coil object
3936 :
3937 0 : errFlag = false;
3938 0 : thisFurnace.SuppHeatCoilIndex = SteamCoils::GetSteamCoilIndex(state, SuppHeatCoilType, SuppHeatCoilName, errFlag);
3939 0 : if (thisFurnace.SuppHeatCoilIndex == 0) {
3940 0 : ShowSevereError(state, format("{} illegal {} = {}", CurrentModuleObject, cAlphaFields(12), SuppHeatCoilName));
3941 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3942 0 : ErrorsFound = true;
3943 : }
3944 :
3945 : // Get the Heating Coil steam inlet node number
3946 0 : errFlag = false;
3947 0 : thisFurnace.SuppCoilControlNode = SteamCoils::GetCoilSteamInletNode(state, "Coil:Heating:Steam", SuppHeatCoilName, errFlag);
3948 0 : if (errFlag) {
3949 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3950 0 : ErrorsFound = true;
3951 : }
3952 :
3953 : // Get the Heating Coil steam max volume flow rate
3954 0 : thisFurnace.MaxSuppCoilFluidFlow = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.SuppHeatCoilIndex, errFlag);
3955 0 : if (thisFurnace.MaxSuppCoilFluidFlow > 0.0) {
3956 0 : SteamIndex = 0; // Function GetSatDensityRefrig will look up steam index if 0 is passed
3957 0 : SteamDensity = FluidProperties::GetSatDensityRefrig(
3958 0 : state, fluidNameSteam, state.dataFurnaces->TempSteamIn, 1.0, SteamIndex, getAirLoopHVACHeatCoolInput);
3959 0 : thisFurnace.MaxSuppCoilFluidFlow =
3960 0 : SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.SuppHeatCoilIndex, errFlag) * SteamDensity;
3961 : }
3962 :
3963 : // Get the Heating Coil Inlet Node
3964 0 : errFlag = false;
3965 0 : SupHeatCoilInletNode = SteamCoils::GetCoilAirInletNode(state, thisFurnace.SuppHeatCoilIndex, SuppHeatCoilName, errFlag);
3966 0 : thisFurnace.SuppCoilAirInletNode = SupHeatCoilInletNode;
3967 0 : if (errFlag) {
3968 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3969 0 : ErrorsFound = true;
3970 : }
3971 :
3972 : // Get the Heating Coil Outlet Node
3973 0 : errFlag = false;
3974 0 : SupHeatCoilOutletNode = SteamCoils::GetCoilAirOutletNode(state, thisFurnace.SuppHeatCoilIndex, SuppHeatCoilName, errFlag);
3975 0 : thisFurnace.SuppCoilAirOutletNode = SupHeatCoilOutletNode;
3976 0 : if (errFlag) {
3977 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, thisFurnace.Name));
3978 0 : ErrorsFound = true;
3979 : }
3980 : }
3981 :
3982 : } else {
3983 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
3984 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(12), Alphas(12)));
3985 0 : ErrorsFound = true;
3986 : } // IF (Furnace(FurnaceNum)%HeatingCoilType_Num == Coil_HeatingGasOrOtherFuel .OR. &, etc.
3987 :
3988 139 : if (lAlphaBlanks(14)) {
3989 0 : thisFurnace.CondenserNodeNum = 0;
3990 : } else {
3991 139 : thisFurnace.CondenserNodeNum =
3992 139 : NodeInputManager::GetOnlySingleNode(state,
3993 139 : Alphas(14),
3994 : ErrorsFound,
3995 : DataLoopNode::ConnectionObjectType::AirLoopHVACUnitaryHeatPumpWaterToAir,
3996 139 : Alphas(1),
3997 : DataLoopNode::NodeFluidType::Air,
3998 : DataLoopNode::ConnectionType::OutsideAirReference,
3999 : NodeInputManager::CompFluidStream::Primary,
4000 : DataLoopNode::ObjectIsNotParent);
4001 : // need better verification.
4002 139 : if (!OutAirNodeManager::CheckOutAirNodeNumber(state, thisFurnace.CondenserNodeNum)) {
4003 0 : ShowSevereError(state, format("For {} = {}", CurrentModuleObject, Alphas(1)));
4004 0 : ShowContinueError(state, format(" Node name of outdoor dry-bulb temperature sensor not valid outdoor air node= {}", Alphas(14)));
4005 0 : ShowContinueError(state, "...does not appear in an OutdoorAir:NodeList or as an OutdoorAir:Node.");
4006 0 : ErrorsFound = true;
4007 : }
4008 : }
4009 :
4010 139 : thisFurnace.fanPlace = static_cast<HVAC::FanPlace>(getEnumValue(HVAC::fanPlaceNamesUC, Alphas(15)));
4011 139 : assert(thisFurnace.fanPlace != HVAC::FanPlace::Invalid);
4012 :
4013 139 : thisFurnace.FanSchedPtr = ScheduleManager::GetScheduleIndex(state, Alphas(16));
4014 139 : if (!lAlphaBlanks(16) && thisFurnace.FanSchedPtr == 0) {
4015 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
4016 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(16), Alphas(16)));
4017 0 : ErrorsFound = true;
4018 139 : } else if (lAlphaBlanks(16)) {
4019 0 : thisFurnace.fanOp = HVAC::FanOp::Cycling;
4020 0 : if (thisFurnace.fanType != HVAC::FanType::OnOff) {
4021 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, thisFurnace.Name));
4022 0 : ShowContinueError(state, format("{} = {}", cAlphaFields(6), Alphas(6)));
4023 0 : ShowContinueError(state, format("Fan type must be Fan:OnOff when {} = Blank.", cAlphaFields(16)));
4024 0 : ErrorsFound = true;
4025 : }
4026 : }
4027 :
4028 : // add the Dehumidification Type
4029 139 : if (Util::SameString(Alphas(17), "None") || Util::SameString(Alphas(17), "CoolReheat")) {
4030 139 : AirNodeFound = false;
4031 139 : if (Util::SameString(Alphas(17), "CoolReheat")) {
4032 10 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::CoolReheat;
4033 10 : thisFurnace.Humidistat = true;
4034 10 : if (lAlphaBlanks(17)) {
4035 0 : ShowWarningError(state, format("{} \"{}\"", CurrentModuleObject, Alphas(1)));
4036 0 : ShowContinueError(state,
4037 : "Dehumidification control type is assumed to be None since a supplemental reheat coil has not been "
4038 : "specified and the simulation continues.");
4039 0 : thisFurnace.Humidistat = false;
4040 0 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::None;
4041 : }
4042 : }
4043 139 : if (Util::SameString(Alphas(17), "None")) {
4044 129 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::None;
4045 129 : thisFurnace.Humidistat = false;
4046 : }
4047 139 : if (thisFurnace.Humidistat) {
4048 60 : for (HStatZoneNum = 1; HStatZoneNum <= state.dataZoneCtrls->NumHumidityControlZones; ++HStatZoneNum) {
4049 50 : if (state.dataZoneCtrls->HumidityControlZone(HStatZoneNum).ActualZoneNum != thisFurnace.ControlZoneNum) continue;
4050 10 : AirNodeFound = true;
4051 : }
4052 10 : if (!AirNodeFound) {
4053 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
4054 0 : ShowContinueError(state, "Did not find Air Node (Zone with Humidistat).");
4055 0 : ShowContinueError(state, format("Specified {} = {}", cAlphaFields(5), Alphas(5)));
4056 0 : ErrorsFound = true;
4057 : }
4058 : }
4059 : } else { // invalid input or blank
4060 0 : if (!lAlphaBlanks(17)) {
4061 0 : ShowSevereError(state, format("{} = {}", CurrentModuleObject, Alphas(1)));
4062 0 : ShowContinueError(state, format("Illegal {} = {}", cAlphaFields(17), Alphas(17)));
4063 0 : ErrorsFound = true;
4064 : } else {
4065 0 : thisFurnace.Humidistat = false;
4066 0 : thisFurnace.DehumidControlType_Num = DehumidificationControlMode::None;
4067 : }
4068 : }
4069 :
4070 : // Add fan to component sets array
4071 :
4072 139 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
4073 139 : CompSetFanInlet = Alphas(3);
4074 139 : CompSetCoolInlet = "UNDEFINED";
4075 139 : if (FanInletNode != thisFurnace.FurnaceInletNodeNum) {
4076 0 : ShowSevereError(
4077 0 : state, format("For {} = {}, Mismatch between unitary system inlet node and fan inlet node.", CurrentModuleObject, Alphas(1)));
4078 0 : ShowContinueError(state, "..For \"BlowThrough\" fan, the inlet node name for the HeatPump should match the fan inlet node name.");
4079 0 : ShowContinueError(state, format("..HeatPump Inlet Node = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
4080 0 : ShowContinueError(state, format("..Fan Inlet Node = {}", state.dataLoopNodes->NodeID(FanInletNode)));
4081 0 : ErrorsFound = true;
4082 : }
4083 139 : if (FanOutletNode != CoolingCoilInletNode) {
4084 0 : ShowSevereError(
4085 0 : state, format("For {} = {}, Mismatch between fan outlet node and cooling coil inlet node.", CurrentModuleObject, Alphas(1)));
4086 0 : ShowContinueError(state, "..For \"BlowThrough\" fan, the fan outlet node name must match the cooling coil inlet node name.");
4087 0 : ShowContinueError(state, format("..Fan outlet node = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
4088 0 : ShowContinueError(state, format("..Cooling coil inlet node = {}", state.dataLoopNodes->NodeID(CoolingCoilInletNode)));
4089 0 : ErrorsFound = true;
4090 : }
4091 139 : if (CoolingCoilOutletNode != HeatingCoilInletNode) {
4092 0 : ShowSevereError(state,
4093 0 : format("For {} = {}, Mismatch between cooling coil outlet node and heating coil inlet node.",
4094 : CurrentModuleObject,
4095 : Alphas(1)));
4096 0 : ShowContinueError(state, "..The cooling coil outlet node name must match the heating coil inlet node name.");
4097 0 : ShowContinueError(state, format("..Cooling coil outlet node = {}", state.dataLoopNodes->NodeID(CoolingCoilOutletNode)));
4098 0 : ShowContinueError(state, format("..Heating coil inlet node = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
4099 0 : ErrorsFound = true;
4100 : }
4101 139 : if (HeatingCoilOutletNode != SupHeatCoilInletNode) {
4102 0 : ShowSevereError(state,
4103 0 : format("For {} = {}, Mismatch between heating coil outlet node and supplemental heating coil inlet node.",
4104 : CurrentModuleObject,
4105 : Alphas(1)));
4106 0 : ShowContinueError(
4107 : state,
4108 : "..For \"BlowThrough\" fan, the heating coil outlet node name must match the supplemental heating coil inlet node name.");
4109 0 : ShowContinueError(state,
4110 0 : format("..Heating coil outlet node = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
4111 0 : ShowContinueError(state,
4112 0 : format("..Supplemental heating coil inlet node = {}", state.dataLoopNodes->NodeID(SupHeatCoilInletNode)));
4113 0 : ErrorsFound = true;
4114 : }
4115 139 : if (SupHeatCoilOutletNode != thisFurnace.FurnaceOutletNodeNum) {
4116 0 : ShowSevereError(state,
4117 0 : format("For {} = {}, Mismatch between supplemental heating coil outlet node and HeatPump outlet node.",
4118 : CurrentModuleObject,
4119 : Alphas(1)));
4120 0 : ShowContinueError(state, "..The supplemental heating coil outlet node name must match the HeatPump outlet node name.");
4121 0 : ShowContinueError(state,
4122 0 : format("..Supplemental heating coil outlet node = {}", state.dataLoopNodes->NodeID(SupHeatCoilOutletNode)));
4123 0 : ShowContinueError(
4124 0 : state, format("..HeatPump outlet node = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
4125 0 : ErrorsFound = true;
4126 : }
4127 : } else {
4128 0 : CompSetFanInlet = "UNDEFINED";
4129 0 : CompSetCoolInlet = Alphas(3);
4130 0 : if (CoolingCoilInletNode != thisFurnace.FurnaceInletNodeNum) {
4131 0 : ShowSevereError(state,
4132 0 : format("For {} = {}, Mismatch between unitary system inlet node and cooling coil inlet node.",
4133 : CurrentModuleObject,
4134 : Alphas(1)));
4135 0 : ShowContinueError(
4136 : state, "..For \"DrawThrough\" fan, the inlet node name for the HeatPump should match the cooling coil inlet node name.");
4137 0 : ShowContinueError(state, format("..HeatPump inlet node = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceInletNodeNum)));
4138 0 : ShowContinueError(state, format("..Cooling coil inlet node = {}", state.dataLoopNodes->NodeID(CoolingCoilInletNode)));
4139 0 : ErrorsFound = true;
4140 : }
4141 0 : if (CoolingCoilOutletNode != HeatingCoilInletNode) {
4142 0 : ShowSevereError(state,
4143 0 : format("For {} = {}, Mismatch between cooling coil outlet node and heating coil inlet node.",
4144 : CurrentModuleObject,
4145 : Alphas(1)));
4146 0 : ShowContinueError(state, "..The outlet node name for the cooling coil should match the heating coil inlet node name.");
4147 0 : ShowContinueError(state, format("..Cooling coil outlet node = {}", state.dataLoopNodes->NodeID(CoolingCoilOutletNode)));
4148 0 : ShowContinueError(state, format("..Heating coil inlet node = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
4149 0 : ErrorsFound = true;
4150 : }
4151 0 : if (HeatingCoilOutletNode != FanInletNode) {
4152 0 : ShowSevereError(
4153 0 : state, format("For {} = {}, Mismatch between heating coil outlet node and fan inlet node.", CurrentModuleObject, Alphas(1)));
4154 0 : ShowContinueError(state,
4155 : "..For \"DrawThrough\" fan, the outlet node name for the heating coil should match the fan inlet node name.");
4156 0 : ShowContinueError(state, format("..Heating coil outlet node = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
4157 0 : ShowContinueError(state, format("..Fan inlet node = {}", state.dataLoopNodes->NodeID(FanInletNode)));
4158 0 : ErrorsFound = true;
4159 : }
4160 0 : if (FanOutletNode != SupHeatCoilInletNode) {
4161 0 : ShowSevereError(state,
4162 0 : format("For {} = {}, Mismatch between fan outlet node and supplemental heating coil inlet node.",
4163 : CurrentModuleObject,
4164 : Alphas(1)));
4165 0 : ShowContinueError(
4166 : state,
4167 : "..For \"DrawThrough\" fan, the outlet node name for the fan should match the supplemental heating coil inlet node name.");
4168 0 : ShowContinueError(state, format("..Fan outlet node = {}", state.dataLoopNodes->NodeID(FanOutletNode)));
4169 0 : ShowContinueError(state,
4170 0 : format("..Supplemental heating coil inlet node = {}", state.dataLoopNodes->NodeID(SupHeatCoilInletNode)));
4171 0 : ErrorsFound = true;
4172 : }
4173 0 : if (SupHeatCoilOutletNode != thisFurnace.FurnaceOutletNodeNum) {
4174 0 : ShowSevereError(state,
4175 0 : format("For {} = {}, Mismatch between supplemental heating coil outlet node and HeatPump outlet node.",
4176 : CurrentModuleObject,
4177 : Alphas(1)));
4178 0 : ShowContinueError(state, "..The supplemental heating coil outlet node name must match the HeatPump outlet node name.");
4179 0 : ShowContinueError(state,
4180 0 : format("..Supplemental heating coil outlet node = {}", state.dataLoopNodes->NodeID(SupHeatCoilOutletNode)));
4181 0 : ShowContinueError(
4182 0 : state, format("..HeatPump outlet node = {}", state.dataLoopNodes->NodeID(thisFurnace.FurnaceOutletNodeNum)));
4183 0 : ErrorsFound = true;
4184 : }
4185 : }
4186 : // (Set up validation here for the fan or cooling coil inlet?)
4187 139 : BranchNodeConnections::SetUpCompSets(state, CurrentModuleObject, Alphas(1), Alphas(6), Alphas(7), CompSetFanInlet, "UNDEFINED");
4188 :
4189 : // Add DX heating coil to component sets array
4190 139 : BranchNodeConnections::SetUpCompSets(state, CurrentModuleObject, Alphas(1), Alphas(8), Alphas(9), "UNDEFINED", "UNDEFINED");
4191 :
4192 : // Add DX cooling coil to component sets array
4193 139 : BranchNodeConnections::SetUpCompSets(state, CurrentModuleObject, Alphas(1), Alphas(10), Alphas(11), CompSetCoolInlet, "UNDEFINED");
4194 :
4195 : // Add supplemental heating coil to component sets array
4196 139 : BranchNodeConnections::SetUpCompSets(state, CurrentModuleObject, Alphas(1), Alphas(12), Alphas(13), "UNDEFINED", Alphas(4));
4197 :
4198 : // Set the Design Fan Volume Flow Rate
4199 139 : thisFurnace.ActualFanVolFlowRate = state.dataFans->fans(thisFurnace.FanIndex)->maxAirFlowRate;
4200 :
4201 : // CR8094 - simple water to air heat pump MUST operate at the same flow rate specified in the coil objects
4202 : // Furnace(FurnaceNum)%DesignFanVolFlowRate = Numbers(1)
4203 : // Furnace(FurnaceNum)%MaxHeatAirVolFlow = Furnace(FurnaceNum)%DesignFanVolFlowRate
4204 : // Furnace(FurnaceNum)%MaxCoolAirVolFlow = Furnace(FurnaceNum)%DesignFanVolFlowRate
4205 :
4206 : // parameter estimate model only specifies air flow rate in parent object
4207 139 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHP) {
4208 14 : thisFurnace.MaxHeatAirVolFlow = Numbers(1);
4209 14 : thisFurnace.MaxCoolAirVolFlow = Numbers(1);
4210 : // simple HP model specifies air flow rate in both the parent and child coils. Use coil air flow rates.
4211 : // simple HP model air flow rate input will not be used.
4212 125 : } else if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPSimple) {
4213 111 : errFlag = false;
4214 111 : thisFurnace.MaxHeatAirVolFlow = WaterToAirHeatPumpSimple::GetCoilAirFlowRate(state, HeatingCoilType, HeatingCoilName, errFlag);
4215 111 : thisFurnace.MaxCoolAirVolFlow = WaterToAirHeatPumpSimple::GetCoilAirFlowRate(state, CoolingCoilType, CoolingCoilName, errFlag);
4216 111 : if (errFlag) {
4217 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
4218 0 : ErrorsFound = true;
4219 : }
4220 14 : } else if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPVSEquationFit) {
4221 14 : errFlag = false;
4222 14 : thisFurnace.MaxHeatAirVolFlow = VariableSpeedCoils::GetCoilAirFlowRateVariableSpeed(state, HeatingCoilType, HeatingCoilName, errFlag);
4223 14 : thisFurnace.MaxCoolAirVolFlow = VariableSpeedCoils::GetCoilAirFlowRateVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
4224 14 : if (errFlag) {
4225 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
4226 0 : ErrorsFound = true;
4227 : }
4228 : }
4229 :
4230 139 : thisFurnace.MaxNoCoolHeatAirVolFlow = min(thisFurnace.MaxHeatAirVolFlow, thisFurnace.MaxCoolAirVolFlow);
4231 139 : if (thisFurnace.MaxHeatAirVolFlow != DataSizing::AutoSize && thisFurnace.MaxCoolAirVolFlow != DataSizing::AutoSize) {
4232 43 : thisFurnace.DesignFanVolFlowRate = max(thisFurnace.MaxHeatAirVolFlow, thisFurnace.MaxCoolAirVolFlow);
4233 : } else {
4234 96 : thisFurnace.DesignFanVolFlowRate = DataSizing::AutoSize;
4235 : }
4236 :
4237 139 : thisFurnace.AirFlowControl = AirFlowControlConstFan::UseCompressorOnFlow;
4238 :
4239 139 : if (thisFurnace.ActualFanVolFlowRate != DataSizing::AutoSize && thisFurnace.DesignFanVolFlowRate != DataSizing::AutoSize) {
4240 43 : if (thisFurnace.DesignFanVolFlowRate > thisFurnace.ActualFanVolFlowRate) {
4241 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
4242 0 : ShowContinueError(state, "... has a Cooling or Heating Air Flow Rate > Max Fan Volume Flow Rate, should be <=.");
4243 0 : ShowContinueError(state,
4244 0 : format("... Entered value={:.2R}... Fan [{}:{}] Max Value={:.2R}",
4245 0 : thisFurnace.DesignFanVolFlowRate,
4246 0 : HVAC::fanTypeNames[(int)thisFurnace.fanType],
4247 : FanName,
4248 0 : thisFurnace.ActualFanVolFlowRate));
4249 : }
4250 : }
4251 139 : if (thisFurnace.ActualFanVolFlowRate != DataSizing::AutoSize && thisFurnace.DesignFanVolFlowRate != DataSizing::AutoSize) {
4252 43 : if (thisFurnace.DesignFanVolFlowRate <= 0.0) {
4253 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
4254 0 : ShowContinueError(state, "... has a Design Fan Flow Rate <= 0.0, it must be >0.0");
4255 0 : ShowContinueError(state, format("... Entered value={:.2R}", thisFurnace.DesignFanVolFlowRate));
4256 0 : ErrorsFound = true;
4257 : }
4258 : }
4259 :
4260 : // Set the heat pump heating coil capacity
4261 : // Get from coil module.
4262 139 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHP) {
4263 14 : errFlag = false;
4264 14 : thisFurnace.DesignHeatingCapacity = WaterToAirHeatPump::GetCoilCapacity(state, HeatingCoilType, HeatingCoilName, errFlag);
4265 14 : if (errFlag) {
4266 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
4267 0 : ErrorsFound = true;
4268 : }
4269 125 : } else if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPSimple) {
4270 111 : errFlag = false;
4271 111 : thisFurnace.DesignHeatingCapacity = WaterToAirHeatPumpSimple::GetCoilCapacity(state, HeatingCoilType, HeatingCoilName, errFlag);
4272 111 : if (errFlag) {
4273 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
4274 0 : ErrorsFound = true;
4275 : }
4276 14 : } else if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPVSEquationFit) {
4277 14 : errFlag = false;
4278 14 : thisFurnace.DesignHeatingCapacity =
4279 14 : VariableSpeedCoils::GetCoilCapacityVariableSpeed(state, HeatingCoilType, HeatingCoilName, errFlag);
4280 14 : if (errFlag) {
4281 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
4282 0 : ErrorsFound = true;
4283 : }
4284 : }
4285 : // Set the heat pump heating coil convergence
4286 139 : thisFurnace.HeatingConvergenceTolerance = Numbers(2);
4287 : // Set the heat pump cooling coil capacity (Total capacity)
4288 : // Get from coil module.
4289 139 : if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingWaterToAirHP) {
4290 14 : errFlag = false;
4291 14 : thisFurnace.DesignCoolingCapacity = WaterToAirHeatPump::GetCoilCapacity(state, CoolingCoilType, CoolingCoilName, errFlag);
4292 14 : if (errFlag) {
4293 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
4294 0 : ErrorsFound = true;
4295 : }
4296 125 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingWaterToAirHPSimple) {
4297 111 : errFlag = false;
4298 111 : thisFurnace.DesignCoolingCapacity = WaterToAirHeatPumpSimple::GetCoilCapacity(state, CoolingCoilType, CoolingCoilName, errFlag);
4299 111 : if (errFlag) {
4300 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
4301 0 : ErrorsFound = true;
4302 : }
4303 14 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingWaterToAirHPVSEquationFit) {
4304 14 : errFlag = false;
4305 14 : thisFurnace.DesignCoolingCapacity =
4306 14 : VariableSpeedCoils::GetCoilCapacityVariableSpeed(state, CoolingCoilType, CoolingCoilName, errFlag);
4307 14 : if (errFlag) {
4308 0 : ShowContinueError(state, format("...occurs in {} = {}", CurrentModuleObject, Alphas(1)));
4309 0 : ErrorsFound = true;
4310 : }
4311 : }
4312 : // Set the heat pump cooling coil convergence
4313 139 : thisFurnace.CoolingConvergenceTolerance = Numbers(3);
4314 :
4315 : // Set the heatpump design supplemental heating capacity
4316 : // Get from coil module.
4317 :
4318 : // Set the heatpump max outlet temperature
4319 139 : thisFurnace.DesignMaxOutletTemp = Numbers(4);
4320 :
4321 : // Set maximum supply air temperature for supplemental heating coil
4322 139 : thisFurnace.MaxOATSuppHeat = Numbers(5);
4323 278 : OutputReportPredefined::PreDefTableEntry(
4324 139 : state, state.dataOutRptPredefined->pdchDXHeatCoilSuppHiT, HeatingCoilName, thisFurnace.MaxOATSuppHeat);
4325 :
4326 : // set minimum outdoor temperature for compressor operation
4327 139 : SetMinOATCompressor(state, FurnaceNum, cCurrentModuleObject, ErrorsFound);
4328 :
4329 : } // End of the Unitary System WaterToAirHeatPump Loop
4330 :
4331 97 : Alphas.deallocate();
4332 97 : Numbers.deallocate();
4333 :
4334 97 : if (ErrorsFound) {
4335 0 : ShowFatalError(state, "Errors found in getting Furnace or Unitary System input.");
4336 : }
4337 :
4338 100 : for (int HeatOnlyNum = 1; HeatOnlyNum <= NumHeatOnly; ++HeatOnlyNum) {
4339 3 : FurnaceNum = HeatOnlyNum;
4340 3 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
4341 : // Setup Report variables for the Furnace that are not reported in the components themselves
4342 6 : SetupOutputVariable(state,
4343 : "Unitary System Fan Part Load Ratio",
4344 : Constant::Units::None,
4345 3 : thisFurnace.FanPartLoadRatio,
4346 : OutputProcessor::TimeStepType::System,
4347 : OutputProcessor::StoreType::Average,
4348 3 : thisFurnace.Name);
4349 3 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
4350 0 : SetupEMSActuator(state,
4351 : "AirLoopHVAC:Unitary:Furnace:HeatOnly",
4352 : thisFurnace.Name,
4353 : "Autosized Supply Air Flow Rate",
4354 : "[m3/s]",
4355 0 : thisFurnace.DesignFanVolFlowRateEMSOverrideOn,
4356 0 : thisFurnace.DesignFanVolFlowRateEMSOverrideValue);
4357 : }
4358 : }
4359 :
4360 98 : for (int UnitaryHeatOnlyNum = NumHeatOnly + 1; UnitaryHeatOnlyNum <= NumHeatOnly + NumUnitaryHeatOnly; ++UnitaryHeatOnlyNum) {
4361 1 : FurnaceNum = UnitaryHeatOnlyNum;
4362 1 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
4363 : // Setup Report variables for Unitary System that are not reported in the components themselves
4364 2 : SetupOutputVariable(state,
4365 : "Unitary System Fan Part Load Ratio",
4366 : Constant::Units::None,
4367 1 : thisFurnace.FanPartLoadRatio,
4368 : OutputProcessor::TimeStepType::System,
4369 : OutputProcessor::StoreType::Average,
4370 1 : thisFurnace.Name);
4371 1 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
4372 0 : SetupEMSActuator(state,
4373 : "AirLoopHVAC:UnitaryHeatOnly",
4374 : thisFurnace.Name,
4375 : "Autosized Supply Air Flow Rate",
4376 : "[m3/s]",
4377 0 : thisFurnace.DesignFanVolFlowRateEMSOverrideOn,
4378 0 : thisFurnace.DesignFanVolFlowRateEMSOverrideValue);
4379 : }
4380 : }
4381 :
4382 205 : for (int HeatCoolNum = NumHeatOnly + NumUnitaryHeatOnly + 1; HeatCoolNum <= NumHeatOnly + NumUnitaryHeatOnly + NumHeatCool; ++HeatCoolNum) {
4383 108 : FurnaceNum = HeatCoolNum;
4384 108 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
4385 : // Setup Report variables for the Furnace that are not reported in the components themselves
4386 216 : SetupOutputVariable(state,
4387 : "Unitary System Fan Part Load Ratio",
4388 : Constant::Units::None,
4389 108 : thisFurnace.FanPartLoadRatio,
4390 : OutputProcessor::TimeStepType::System,
4391 : OutputProcessor::StoreType::Average,
4392 108 : thisFurnace.Name);
4393 216 : SetupOutputVariable(state,
4394 : "Unitary System Compressor Part Load Ratio",
4395 : Constant::Units::None,
4396 108 : thisFurnace.CompPartLoadRatio,
4397 : OutputProcessor::TimeStepType::System,
4398 : OutputProcessor::StoreType::Average,
4399 108 : thisFurnace.Name);
4400 :
4401 108 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
4402 24 : SetupEMSActuator(state,
4403 : "AirLoopHVAC:Unitary:Furnace:HeatCool",
4404 : thisFurnace.Name,
4405 : "Autosized Supply Air Flow Rate",
4406 : "[m3/s]",
4407 24 : thisFurnace.DesignFanVolFlowRateEMSOverrideOn,
4408 24 : thisFurnace.DesignFanVolFlowRateEMSOverrideValue);
4409 24 : SetupEMSActuator(state,
4410 : "AirLoopHVAC:Unitary:Furnace:HeatCool",
4411 : thisFurnace.Name,
4412 : "Autosized Supply Air Flow Rate During Cooling Operation",
4413 : "[m3/s]",
4414 24 : thisFurnace.MaxCoolAirVolFlowEMSOverrideOn,
4415 24 : thisFurnace.MaxCoolAirVolFlowEMSOverrideValue);
4416 24 : SetupEMSActuator(state,
4417 : "AirLoopHVAC:Unitary:Furnace:HeatCool",
4418 : thisFurnace.Name,
4419 : "Autosized Supply Air Flow Rate During Heating Operation",
4420 : "[m3/s]",
4421 24 : thisFurnace.MaxHeatAirVolFlowEMSOverrideOn,
4422 24 : thisFurnace.MaxHeatAirVolFlowEMSOverrideValue);
4423 24 : SetupEMSActuator(state,
4424 : "AirLoopHVAC:Unitary:Furnace:HeatCool",
4425 : thisFurnace.Name,
4426 : "Autosized Supply Air Flow Rate During No Heating or Cooling Operation",
4427 : "[m3/s]",
4428 24 : thisFurnace.MaxNoCoolHeatAirVolFlowEMSOverrideOn,
4429 24 : thisFurnace.MaxNoCoolHeatAirVolFlowEMSOverrideValue);
4430 : }
4431 : }
4432 :
4433 170 : for (int UnitaryHeatCoolNum = NumHeatOnly + NumHeatCool + NumUnitaryHeatOnly + 1;
4434 170 : UnitaryHeatCoolNum <= NumHeatOnly + NumHeatCool + NumUnitaryHeatOnly + NumUnitaryHeatCool;
4435 : ++UnitaryHeatCoolNum) {
4436 73 : FurnaceNum = UnitaryHeatCoolNum;
4437 73 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
4438 : // Setup Report variables for Unitary System that are not reported in the components themselves
4439 146 : SetupOutputVariable(state,
4440 : "Unitary System Fan Part Load Ratio",
4441 : Constant::Units::None,
4442 73 : thisFurnace.FanPartLoadRatio,
4443 : OutputProcessor::TimeStepType::System,
4444 : OutputProcessor::StoreType::Average,
4445 73 : thisFurnace.Name);
4446 146 : SetupOutputVariable(state,
4447 : "Unitary System Compressor Part Load Ratio",
4448 : Constant::Units::None,
4449 73 : thisFurnace.CompPartLoadRatio,
4450 : OutputProcessor::TimeStepType::System,
4451 : OutputProcessor::StoreType::Average,
4452 73 : thisFurnace.Name);
4453 73 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
4454 20 : SetupEMSActuator(state,
4455 : "AirLoopHVAC:UnitaryHeatCool",
4456 : thisFurnace.Name,
4457 : "Autosized Supply Air Flow Rate",
4458 : "[m3/s]",
4459 20 : thisFurnace.DesignFanVolFlowRateEMSOverrideOn,
4460 20 : thisFurnace.DesignFanVolFlowRateEMSOverrideValue);
4461 20 : SetupEMSActuator(state,
4462 : "AirLoopHVAC:UnitaryHeatCool",
4463 : thisFurnace.Name,
4464 : "Autosized Supply Air Flow Rate During Cooling Operation",
4465 : "[m3/s]",
4466 20 : thisFurnace.MaxCoolAirVolFlowEMSOverrideOn,
4467 20 : thisFurnace.MaxCoolAirVolFlowEMSOverrideValue);
4468 20 : SetupEMSActuator(state,
4469 : "AirLoopHVAC:UnitaryHeatCool",
4470 : thisFurnace.Name,
4471 : "Autosized Supply Air Flow Rate During Heating Operation",
4472 : "[m3/s]",
4473 20 : thisFurnace.MaxHeatAirVolFlowEMSOverrideOn,
4474 20 : thisFurnace.MaxHeatAirVolFlowEMSOverrideValue);
4475 20 : SetupEMSActuator(state,
4476 : "AirLoopHVAC:UnitaryHeatCool",
4477 : thisFurnace.Name,
4478 : "Autosized Supply Air Flow Rate During No Heating or Cooling Operation",
4479 : "[m3/s]",
4480 20 : thisFurnace.MaxNoCoolHeatAirVolFlowEMSOverrideOn,
4481 20 : thisFurnace.MaxNoCoolHeatAirVolFlowEMSOverrideValue);
4482 : }
4483 : }
4484 :
4485 132 : for (int HeatPumpNum = NumHeatOnly + NumHeatCool + NumUnitaryHeatOnly + NumUnitaryHeatCool + 1;
4486 132 : HeatPumpNum <= state.dataFurnaces->NumFurnaces - NumWaterToAirHeatPump;
4487 : ++HeatPumpNum) {
4488 35 : FurnaceNum = HeatPumpNum;
4489 35 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
4490 : // Setup Report variables for Unitary System that are not reported in the components themselves
4491 70 : SetupOutputVariable(state,
4492 : "Unitary System Fan Part Load Ratio",
4493 : Constant::Units::None,
4494 35 : thisFurnace.FanPartLoadRatio,
4495 : OutputProcessor::TimeStepType::System,
4496 : OutputProcessor::StoreType::Average,
4497 35 : thisFurnace.Name);
4498 70 : SetupOutputVariable(state,
4499 : "Unitary System Compressor Part Load Ratio",
4500 : Constant::Units::None,
4501 35 : thisFurnace.CompPartLoadRatio,
4502 : OutputProcessor::TimeStepType::System,
4503 : OutputProcessor::StoreType::Average,
4504 35 : thisFurnace.Name);
4505 70 : SetupOutputVariable(state,
4506 : "Unitary System Dehumidification Induced Heating Demand Rate",
4507 : Constant::Units::W,
4508 35 : thisFurnace.DehumidInducedHeatingDemandRate,
4509 : OutputProcessor::TimeStepType::System,
4510 : OutputProcessor::StoreType::Average,
4511 35 : thisFurnace.Name);
4512 :
4513 35 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
4514 5 : SetupEMSActuator(state,
4515 : "AirLoopHVAC:UnitaryHeatPump:AirToAir",
4516 : thisFurnace.Name,
4517 : "Autosized Supply Air Flow Rate",
4518 : "[m3/s]",
4519 5 : thisFurnace.DesignFanVolFlowRateEMSOverrideOn,
4520 5 : thisFurnace.DesignFanVolFlowRateEMSOverrideValue);
4521 : }
4522 : }
4523 :
4524 236 : for (int HeatPumpNum = NumHeatOnly + NumHeatCool + NumUnitaryHeatOnly + NumUnitaryHeatCool + NumHeatPump + 1;
4525 236 : HeatPumpNum <= state.dataFurnaces->NumFurnaces;
4526 : ++HeatPumpNum) {
4527 139 : FurnaceNum = HeatPumpNum;
4528 139 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
4529 : // Setup Report variables for Unitary System that are not reported in the components themselves
4530 278 : SetupOutputVariable(state,
4531 : "Unitary System Fan Part Load Ratio",
4532 : Constant::Units::None,
4533 139 : thisFurnace.FanPartLoadRatio,
4534 : OutputProcessor::TimeStepType::System,
4535 : OutputProcessor::StoreType::Average,
4536 139 : thisFurnace.Name);
4537 278 : SetupOutputVariable(state,
4538 : "Unitary System Compressor Part Load Ratio",
4539 : Constant::Units::None,
4540 139 : thisFurnace.CompPartLoadRatio,
4541 : OutputProcessor::TimeStepType::System,
4542 : OutputProcessor::StoreType::Average,
4543 139 : thisFurnace.Name);
4544 278 : SetupOutputVariable(state,
4545 : "Unitary System Requested Sensible Cooling Rate",
4546 : Constant::Units::W,
4547 139 : thisFurnace.CoolingCoilSensDemand,
4548 : OutputProcessor::TimeStepType::System,
4549 : OutputProcessor::StoreType::Average,
4550 139 : thisFurnace.Name);
4551 278 : SetupOutputVariable(state,
4552 : "Unitary System Requested Latent Cooling Rate",
4553 : Constant::Units::W,
4554 139 : thisFurnace.CoolingCoilLatentDemand,
4555 : OutputProcessor::TimeStepType::System,
4556 : OutputProcessor::StoreType::Average,
4557 139 : thisFurnace.Name);
4558 278 : SetupOutputVariable(state,
4559 : "Unitary System Requested Heating Rate",
4560 : Constant::Units::W,
4561 139 : thisFurnace.HeatingCoilSensDemand,
4562 : OutputProcessor::TimeStepType::System,
4563 : OutputProcessor::StoreType::Average,
4564 139 : thisFurnace.Name);
4565 278 : SetupOutputVariable(state,
4566 : "Unitary System Dehumidification Induced Heating Demand Rate",
4567 : Constant::Units::W,
4568 139 : thisFurnace.DehumidInducedHeatingDemandRate,
4569 : OutputProcessor::TimeStepType::System,
4570 : OutputProcessor::StoreType::Average,
4571 139 : thisFurnace.Name);
4572 :
4573 139 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
4574 96 : SetupEMSActuator(state,
4575 : "AirLoopHVAC:UnitaryHeatPump:WaterToAir",
4576 : thisFurnace.Name,
4577 : "Autosized Supply Air Flow Rate",
4578 : "[m3/s]",
4579 96 : thisFurnace.DesignFanVolFlowRateEMSOverrideOn,
4580 96 : thisFurnace.DesignFanVolFlowRateEMSOverrideValue);
4581 : }
4582 : }
4583 :
4584 97 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
4585 154 : for (FurnaceNum = 1; FurnaceNum <= state.dataFurnaces->NumFurnaces; ++FurnaceNum) {
4586 145 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
4587 145 : SetupEMSInternalVariable(state, "Unitary HVAC Design Heating Capacity", thisFurnace.Name, "[W]", thisFurnace.DesignHeatingCapacity);
4588 145 : SetupEMSInternalVariable(state, "Unitary HVAC Design Cooling Capacity", thisFurnace.Name, "[W]", thisFurnace.DesignCoolingCapacity);
4589 145 : SetupEMSActuator(state,
4590 : "Unitary HVAC",
4591 : thisFurnace.Name,
4592 : "Sensible Load Request",
4593 : "[W]",
4594 145 : thisFurnace.EMSOverrideSensZoneLoadRequest,
4595 145 : thisFurnace.EMSSensibleZoneLoadValue);
4596 145 : SetupEMSActuator(state,
4597 : "Unitary HVAC",
4598 : thisFurnace.Name,
4599 : "Moisture Load Request",
4600 : "[W]",
4601 145 : thisFurnace.EMSOverrideMoistZoneLoadRequest,
4602 145 : thisFurnace.EMSMoistureZoneLoadValue);
4603 : }
4604 : }
4605 : bool anyRan;
4606 97 : EMSManager::ManageEMS(state, EMSManager::EMSCallFrom::ComponentGetInput, anyRan, ObjexxFCL::Optional_int_const());
4607 97 : }
4608 :
4609 : // End of Get Input subroutines for this Module
4610 : //******************************************************************************
4611 :
4612 : // Beginning Initialization Section of the Module
4613 : //******************************************************************************
4614 :
4615 6243009 : void InitFurnace(EnergyPlusData &state,
4616 : int const FurnaceNum, // index to Furnace
4617 : int const AirLoopNum, // index to air loop
4618 : Real64 &OnOffAirFlowRatio, // ratio of on to off air mass flow rate
4619 : HVAC::FanOp &fanOp, // fan operating mode
4620 : Real64 &ZoneLoad, // zone sensible load to be met (modified here as needed) (W)
4621 : Real64 &MoistureLoad, // zone moisture load (W)
4622 : bool const FirstHVACIteration // TRUE if first HVAC iteration
4623 : )
4624 : {
4625 :
4626 : // SUBROUTINE INFORMATION:
4627 : // AUTHOR Richard J. Liesen
4628 : // DATE WRITTEN Feb 2001
4629 : // MODIFIED Oct 2001, Richard Raustad
4630 : // Sep 2008, R. Raustad - revised logic to determine load to be met
4631 : // Bereket Nigusse, June 2010 - added a procedure to calculate supply air flow fraction
4632 : // through controlled zone
4633 : // Bo Shen, March 2012 - for VS WSHP
4634 : // Bo Shen, ORNL, July 2012 - added variable-speed air source heat pump cooling and heating coils, using curve-fits
4635 :
4636 : // PURPOSE OF THIS SUBROUTINE:
4637 : // This subroutine is for initializations of the Furnace Components.
4638 :
4639 : // METHODOLOGY EMPLOYED:
4640 : // Uses the status flags to trigger initializations.
4641 : // The HeatCool furnace/unitarysystem and air-to-air heat pump may have alternate air flow rates
4642 : // in cooling, heating, and when no cooling or heating is needed. Set up the coil (comp) ON and OFF
4643 : // air flow rates during InitFurnace. Use these flow rates during the Calc routines to set the
4644 : // average mass flow rates based on PLR.
4645 :
4646 : // SUBROUTINE PARAMETER DEFINITIONS:
4647 6243009 : Real64 constexpr Small5WLoad(5.0);
4648 6243009 : std::string_view constexpr RoutineName("InitFurnace");
4649 :
4650 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4651 : bool errFlag; // error flag for mining functions
4652 : Real64 QZnReq; // furnace load based on control zone frac (W)
4653 : Real64 PartLoadRatio; // furnace part-load ratio
4654 : Real64 SensibleOutput; // no load sensible output (coils off) (W)
4655 : Real64 LatentOutput; // no load latent output (coils off) (W)
4656 : Real64 QToCoolSetPt; // sensible load to cooling setpoint (W)
4657 : Real64 QToHeatSetPt; // sensible load to heating setpoint (W)
4658 : // calculation (kg/kg)
4659 : Real64 DeltaMassRate; // Difference of mass flow rate between
4660 : // inlet node and system outlet node
4661 : Real64 MassFlowRate; // mass flow rate to calculate loss
4662 :
4663 6243009 : Real64 SumOfMassFlowRateMax(0.0); // the sum of mass flow rates at inlet to zones in an airloop
4664 6243009 : Real64 CntrlZoneTerminalUnitMassFlowRateMax(0.0); // Maximum mass flow rate through controlled zone terminal unit
4665 :
4666 6243009 : bool ErrorsFound(false); // flag returned from mining call
4667 6243009 : Real64 mdot(0.0); // local temporary for mass flow rate (kg/s)
4668 6243009 : Real64 rho(0.0); // local for fluid density
4669 6243009 : Real64 SteamDensity(0.0); // density of steam at 100C, used for steam heating coils
4670 6243009 : Real64 CoilMaxVolFlowRate(0.0); // coil fluid maximum volume flow rate
4671 6243009 : Real64 QActual(0.0); // coil actual capacity
4672 6243009 : Real64 SUPHEATERLOAD(0.0); // SUPPLEMENTAL HEATER LOAD
4673 : Real64 RhoAir; // Air density at InNode
4674 : Furnaces::ModeOfOperation OperatingMode; // track cooling, heating, and no cooling or heating modes
4675 : Furnaces::ModeOfOperation OperatingModeMinusOne;
4676 : Furnaces::ModeOfOperation OperatingModeMinusTwo;
4677 : bool Oscillate; // detection of oscillating operating modes
4678 :
4679 6243009 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
4680 6243009 : int InNode = thisFurnace.FurnaceInletNodeNum;
4681 6243009 : int OutNode = thisFurnace.FurnaceOutletNodeNum;
4682 :
4683 6243009 : if (state.dataFurnaces->InitFurnaceMyOneTimeFlag) {
4684 : // initialize the environment and sizing flags
4685 97 : state.dataFurnaces->MyEnvrnFlag.allocate(state.dataFurnaces->NumFurnaces);
4686 97 : state.dataFurnaces->MySizeFlag.allocate(state.dataFurnaces->NumFurnaces);
4687 97 : state.dataFurnaces->MySecondOneTimeFlag.allocate(state.dataFurnaces->NumFurnaces);
4688 97 : state.dataFurnaces->MyFanFlag.allocate(state.dataFurnaces->NumFurnaces);
4689 97 : state.dataFurnaces->MyCheckFlag.allocate(state.dataFurnaces->NumFurnaces);
4690 97 : state.dataFurnaces->MyFlowFracFlag.allocate(state.dataFurnaces->NumFurnaces);
4691 97 : state.dataFurnaces->MyPlantScanFlag.allocate(state.dataFurnaces->NumFurnaces);
4692 97 : state.dataFurnaces->MySuppCoilPlantScanFlag.allocate(state.dataFurnaces->NumFurnaces);
4693 97 : state.dataFurnaces->MyEnvrnFlag = true;
4694 97 : state.dataFurnaces->MySizeFlag = true;
4695 97 : state.dataFurnaces->MySecondOneTimeFlag = true;
4696 97 : state.dataFurnaces->MyFanFlag = true;
4697 97 : state.dataFurnaces->MyCheckFlag = true;
4698 97 : state.dataFurnaces->MyFlowFracFlag = true;
4699 97 : state.dataFurnaces->InitFurnaceMyOneTimeFlag = false;
4700 97 : state.dataFurnaces->MyPlantScanFlag = true;
4701 97 : state.dataFurnaces->MySuppCoilPlantScanFlag = true;
4702 : }
4703 :
4704 6243009 : if (state.dataGlobal->BeginEnvrnFlag && state.dataFurnaces->MyAirLoopPass) {
4705 588 : state.dataFurnaces->AirLoopPass = 0;
4706 588 : state.dataFurnaces->MyAirLoopPass = false;
4707 : }
4708 6243009 : if (!state.dataGlobal->BeginEnvrnFlag) {
4709 6222832 : state.dataFurnaces->MyAirLoopPass = true;
4710 : }
4711 :
4712 6243009 : ++state.dataFurnaces->AirLoopPass;
4713 6243009 : if (state.dataFurnaces->AirLoopPass > 2) state.dataFurnaces->AirLoopPass = 1;
4714 :
4715 6243009 : if (!state.dataGlobal->SysSizingCalc && state.dataFurnaces->MySizeFlag(FurnaceNum)) {
4716 : // for each furnace, do the sizing once.
4717 359 : SizeFurnace(state, FurnaceNum, FirstHVACIteration);
4718 359 : thisFurnace.ControlZoneMassFlowFrac = 1.0;
4719 :
4720 359 : state.dataFurnaces->MySizeFlag(FurnaceNum) = false;
4721 : // Pass the fan cycling schedule index up to the air loop. Set the air loop unitary system flag.
4722 359 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).CycFanSchedPtr = thisFurnace.FanSchedPtr;
4723 359 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).UnitarySys = true;
4724 : // RR this is wrong, Op mode needs to be updated each time atep
4725 359 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).fanOp = thisFurnace.fanOp;
4726 :
4727 : // Check that heat pump heating capacity is within 20% of cooling capacity
4728 359 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir) {
4729 35 : if (std::abs(thisFurnace.DesignCoolingCapacity - thisFurnace.DesignHeatingCapacity) / thisFurnace.DesignCoolingCapacity > 0.2) {
4730 0 : ShowWarningError(state,
4731 0 : format("{} \"{}\" heating capacity is disproportionate (> 20% different) to total cooling capacity",
4732 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
4733 0 : thisFurnace.Name));
4734 : }
4735 : }
4736 : }
4737 :
4738 6243009 : if (!state.dataGlobal->DoingSizing && state.dataFurnaces->MySecondOneTimeFlag(FurnaceNum)) {
4739 : // sizing all done. check fan air flow rates
4740 625 : thisFurnace.ActualFanVolFlowRate = state.dataFans->fans(thisFurnace.FanIndex)->maxAirFlowRate;
4741 625 : if (thisFurnace.ActualFanVolFlowRate != DataSizing::AutoSize) {
4742 359 : if (thisFurnace.DesignFanVolFlowRate > thisFurnace.ActualFanVolFlowRate) {
4743 0 : ShowWarningError(state,
4744 0 : format("{}={} has a Design Fan Volume Flow Rate > Max Fan Volume Flow Rate, should be <=",
4745 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
4746 0 : thisFurnace.Name));
4747 0 : ShowContinueError(state,
4748 0 : format("... Entered value={:.2R}... Fan [{}] Max Value={:.2R}",
4749 0 : thisFurnace.DesignFanVolFlowRate,
4750 0 : HVAC::fanTypeNames[(int)thisFurnace.fanType],
4751 0 : thisFurnace.ActualFanVolFlowRate));
4752 : }
4753 359 : if (thisFurnace.DesignFanVolFlowRate <= 0.0) {
4754 0 : ShowSevereError(state,
4755 0 : format("{}={} has a Design Fan Volume Flow Rate <= 0.0, it must be >0.0",
4756 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
4757 0 : thisFurnace.Name));
4758 0 : ShowContinueError(state, format("... Entered value={:.2R}", thisFurnace.DesignFanVolFlowRate));
4759 : }
4760 :
4761 359 : state.dataFurnaces->MySecondOneTimeFlag(FurnaceNum) = false;
4762 : }
4763 : }
4764 :
4765 : // Scan hot water and steam heating coil plant components for one time initializations
4766 6243009 : if (state.dataFurnaces->MyPlantScanFlag(FurnaceNum) && allocated(state.dataPlnt->PlantLoop)) {
4767 359 : if ((thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWater) || (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingSteam)) {
4768 :
4769 0 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWater) {
4770 :
4771 0 : errFlag = false;
4772 0 : PlantUtilities::ScanPlantLoopsForObject(state,
4773 : thisFurnace.HeatingCoilName,
4774 : DataPlant::PlantEquipmentType::CoilWaterSimpleHeating,
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 =
4786 0 : WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", thisFurnace.HeatingCoilName, ErrorsFound);
4787 0 : if (thisFurnace.MaxHeatCoilFluidFlow > 0.0) {
4788 0 : rho = FluidProperties::GetDensityGlycol(state,
4789 0 : state.dataPlnt->PlantLoop(thisFurnace.plantLoc.loopNum).FluidName,
4790 : Constant::HWInitConvTemp,
4791 0 : state.dataPlnt->PlantLoop(thisFurnace.plantLoc.loopNum).FluidIndex,
4792 : RoutineName);
4793 0 : thisFurnace.MaxHeatCoilFluidFlow *= rho;
4794 : }
4795 0 : } else if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingSteam) {
4796 :
4797 0 : errFlag = false;
4798 0 : PlantUtilities::ScanPlantLoopsForObject(state,
4799 : thisFurnace.HeatingCoilName,
4800 : DataPlant::PlantEquipmentType::CoilSteamAirHeating,
4801 0 : thisFurnace.plantLoc,
4802 : errFlag,
4803 : _,
4804 : _,
4805 : _,
4806 : _,
4807 : _);
4808 0 : if (errFlag) {
4809 0 : ShowFatalError(state, "InitFurnace: Program terminated for previous conditions.");
4810 : }
4811 0 : thisFurnace.MaxHeatCoilFluidFlow = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.HeatingCoilIndex, ErrorsFound);
4812 0 : if (thisFurnace.MaxHeatCoilFluidFlow > 0.0) {
4813 0 : int SteamIndex = 0; // Function GetSatDensityRefrig will look up steam index if 0 is passed
4814 0 : SteamDensity = FluidProperties::GetSatDensityRefrig(
4815 0 : state, fluidNameSteam, state.dataFurnaces->TempSteamIn, 1.0, SteamIndex, RoutineName);
4816 0 : thisFurnace.MaxHeatCoilFluidFlow *= SteamDensity;
4817 : }
4818 : }
4819 : // fill outlet node for coil
4820 0 : thisFurnace.CoilOutletNode = DataPlant::CompData::getPlantComponent(state, thisFurnace.plantLoc).NodeNumOut;
4821 0 : state.dataFurnaces->MyPlantScanFlag(FurnaceNum) = false;
4822 0 : } else { // pthp not connected to plant
4823 359 : state.dataFurnaces->MyPlantScanFlag(FurnaceNum) = false;
4824 : }
4825 6242650 : } else if (state.dataFurnaces->MyPlantScanFlag(FurnaceNum) && !state.dataGlobal->AnyPlantInModel) {
4826 0 : state.dataFurnaces->MyPlantScanFlag(FurnaceNum) = false;
4827 : }
4828 :
4829 : // Scan Supplemental hot water and steam heating coil plant components for one time initializations
4830 6243009 : if (state.dataFurnaces->MySuppCoilPlantScanFlag(FurnaceNum) && allocated(state.dataPlnt->PlantLoop)) {
4831 359 : if ((thisFurnace.SuppHeatCoilType_Num == HVAC::Coil_HeatingWater) || (thisFurnace.SuppHeatCoilType_Num == HVAC::Coil_HeatingSteam)) {
4832 :
4833 1 : if (thisFurnace.SuppHeatCoilType_Num == HVAC::Coil_HeatingWater) {
4834 1 : errFlag = false;
4835 2 : PlantUtilities::ScanPlantLoopsForObject(state,
4836 : thisFurnace.SuppHeatCoilName,
4837 : DataPlant::PlantEquipmentType::CoilWaterSimpleHeating,
4838 1 : thisFurnace.SuppPlantLoc,
4839 : errFlag,
4840 : _,
4841 : _,
4842 : _,
4843 : _,
4844 : _);
4845 1 : if (errFlag) {
4846 0 : ShowFatalError(state, "InitFurnace: Program terminated for previous conditions.");
4847 : }
4848 1 : thisFurnace.MaxSuppCoilFluidFlow =
4849 1 : WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", thisFurnace.SuppHeatCoilName, ErrorsFound);
4850 1 : if (thisFurnace.MaxSuppCoilFluidFlow > 0.0) {
4851 1 : rho = FluidProperties::GetDensityGlycol(state,
4852 1 : state.dataPlnt->PlantLoop(thisFurnace.SuppPlantLoc.loopNum).FluidName,
4853 : Constant::HWInitConvTemp,
4854 1 : state.dataPlnt->PlantLoop(thisFurnace.SuppPlantLoc.loopNum).FluidIndex,
4855 : RoutineName);
4856 1 : thisFurnace.MaxSuppCoilFluidFlow *= rho;
4857 : }
4858 0 : } else if (thisFurnace.SuppHeatCoilType_Num == HVAC::Coil_HeatingSteam) {
4859 0 : errFlag = false;
4860 0 : PlantUtilities::ScanPlantLoopsForObject(state,
4861 : thisFurnace.SuppHeatCoilName,
4862 : DataPlant::PlantEquipmentType::CoilSteamAirHeating,
4863 0 : thisFurnace.SuppPlantLoc,
4864 : errFlag,
4865 : _,
4866 : _,
4867 : _,
4868 : _,
4869 : _);
4870 0 : if (errFlag) {
4871 0 : ShowFatalError(state, "InitFurnace: Program terminated for previous conditions.");
4872 : }
4873 0 : thisFurnace.MaxSuppCoilFluidFlow = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.SuppHeatCoilIndex, ErrorsFound);
4874 0 : if (thisFurnace.MaxSuppCoilFluidFlow > 0.0) {
4875 0 : int SteamIndex = 0; // Function GetSatDensityRefrig will look up steam index if 0 is passed
4876 0 : SteamDensity = FluidProperties::GetSatDensityRefrig(
4877 0 : state, fluidNameSteam, state.dataFurnaces->TempSteamIn, 1.0, SteamIndex, RoutineName);
4878 0 : thisFurnace.MaxSuppCoilFluidFlow *= SteamDensity;
4879 : }
4880 : }
4881 : // fill outlet node for coil
4882 1 : thisFurnace.SuppCoilOutletNode = DataPlant::CompData::getPlantComponent(state, thisFurnace.SuppPlantLoc).NodeNumOut;
4883 1 : state.dataFurnaces->MySuppCoilPlantScanFlag(FurnaceNum) = false;
4884 1 : } else { // pthp not connected to plant
4885 358 : state.dataFurnaces->MySuppCoilPlantScanFlag(FurnaceNum) = false;
4886 : }
4887 :
4888 6242650 : } else if (state.dataFurnaces->MySuppCoilPlantScanFlag(FurnaceNum) && !state.dataGlobal->AnyPlantInModel) {
4889 0 : state.dataFurnaces->MySuppCoilPlantScanFlag(FurnaceNum) = false;
4890 : }
4891 :
4892 : // Do the Begin Environment initializations
4893 6243009 : if (state.dataGlobal->BeginEnvrnFlag && state.dataFurnaces->MyEnvrnFlag(FurnaceNum)) {
4894 : // Change the Volume Flow Rates to Mass Flow Rates
4895 2286 : thisFurnace.DesignMassFlowRate = thisFurnace.DesignFanVolFlowRate * state.dataEnvrn->StdRhoAir;
4896 2286 : thisFurnace.MaxCoolAirMassFlow = thisFurnace.MaxCoolAirVolFlow * state.dataEnvrn->StdRhoAir;
4897 2286 : thisFurnace.MaxHeatAirMassFlow = thisFurnace.MaxHeatAirVolFlow * state.dataEnvrn->StdRhoAir;
4898 2286 : thisFurnace.MaxNoCoolHeatAirMassFlow = thisFurnace.MaxNoCoolHeatAirVolFlow * state.dataEnvrn->StdRhoAir;
4899 2286 : thisFurnace.CompPartLoadRatio = 0.0;
4900 2286 : thisFurnace.CoolingCoilSensDemand = 0.0;
4901 2286 : thisFurnace.CoolingCoilLatentDemand = 0.0;
4902 2286 : thisFurnace.HeatingCoilSensDemand = 0.0;
4903 :
4904 2286 : thisFurnace.SenLoadLoss = 0.0;
4905 2286 : if (thisFurnace.Humidistat) {
4906 351 : thisFurnace.LatLoadLoss = 0.0;
4907 : }
4908 :
4909 : // set fluid-side hardware limits
4910 2286 : if (thisFurnace.CoilControlNode > 0) {
4911 :
4912 0 : if (thisFurnace.MaxHeatCoilFluidFlow == DataSizing::AutoSize) {
4913 : // If water coil max water flow rate is autosized, simulate once in order to mine max flow rate
4914 0 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWater) {
4915 0 : WaterCoils::SimulateWaterCoilComponents(state, thisFurnace.HeatingCoilName, FirstHVACIteration, thisFurnace.HeatingCoilIndex);
4916 : CoilMaxVolFlowRate =
4917 0 : WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", thisFurnace.HeatingCoilName, ErrorsFound);
4918 0 : if (CoilMaxVolFlowRate != DataSizing::AutoSize) {
4919 0 : rho = FluidProperties::GetDensityGlycol(state,
4920 0 : state.dataPlnt->PlantLoop(thisFurnace.plantLoc.loopNum).FluidName,
4921 : Constant::HWInitConvTemp,
4922 0 : state.dataPlnt->PlantLoop(thisFurnace.plantLoc.loopNum).FluidIndex,
4923 : RoutineName);
4924 0 : thisFurnace.MaxHeatCoilFluidFlow = CoilMaxVolFlowRate * rho;
4925 : }
4926 : }
4927 : // If steam coil max steam flow rate is autosized, simulate once in order to mine max flow rate
4928 0 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingSteam) {
4929 0 : SteamCoils::SimulateSteamCoilComponents(state,
4930 : thisFurnace.HeatingCoilName,
4931 : FirstHVACIteration,
4932 0 : thisFurnace.HeatingCoilIndex,
4933 0 : 1.0,
4934 : QActual); // QCoilReq, simulate any load > 0 to get max capacity
4935 0 : CoilMaxVolFlowRate = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.HeatingCoilIndex, ErrorsFound);
4936 0 : if (CoilMaxVolFlowRate != DataSizing::AutoSize) {
4937 0 : int SteamIndex = 0; // Function GetSatDensityRefrig will look up steam index if 0 is passed
4938 0 : SteamDensity = FluidProperties::GetSatDensityRefrig(
4939 0 : state, fluidNameSteam, state.dataFurnaces->TempSteamIn, 1.0, SteamIndex, RoutineName);
4940 0 : thisFurnace.MaxHeatCoilFluidFlow = CoilMaxVolFlowRate * SteamDensity;
4941 : }
4942 : }
4943 : }
4944 :
4945 0 : PlantUtilities::InitComponentNodes(
4946 : state, 0.0, thisFurnace.MaxHeatCoilFluidFlow, thisFurnace.CoilControlNode, thisFurnace.CoilOutletNode);
4947 : }
4948 2286 : if (thisFurnace.SuppCoilControlNode > 0) {
4949 7 : if (thisFurnace.MaxSuppCoilFluidFlow == DataSizing::AutoSize) {
4950 0 : if (thisFurnace.SuppHeatCoilType_Num == HVAC::Coil_HeatingWater) {
4951 : // If water coil max water flow rate is autosized, simulate once in order to mine max flow rate
4952 0 : WaterCoils::SimulateWaterCoilComponents(
4953 0 : state, thisFurnace.SuppHeatCoilName, FirstHVACIteration, thisFurnace.SuppHeatCoilIndex);
4954 : CoilMaxVolFlowRate =
4955 0 : WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", thisFurnace.SuppHeatCoilName, ErrorsFound);
4956 0 : if (CoilMaxVolFlowRate != DataSizing::AutoSize) {
4957 0 : rho = FluidProperties::GetDensityGlycol(state,
4958 0 : state.dataPlnt->PlantLoop(thisFurnace.SuppPlantLoc.loopNum).FluidName,
4959 : Constant::HWInitConvTemp,
4960 0 : state.dataPlnt->PlantLoop(thisFurnace.SuppPlantLoc.loopNum).FluidIndex,
4961 : RoutineName);
4962 0 : thisFurnace.MaxSuppCoilFluidFlow = CoilMaxVolFlowRate * rho;
4963 : }
4964 : }
4965 0 : if (thisFurnace.SuppHeatCoilType_Num == HVAC::Coil_HeatingSteam) {
4966 0 : SteamCoils::SimulateSteamCoilComponents(state,
4967 : thisFurnace.SuppHeatCoilName,
4968 : FirstHVACIteration,
4969 0 : thisFurnace.SuppHeatCoilIndex,
4970 0 : 1.0,
4971 : QActual); // QCoilReq, simulate any load > 0 to get max capacity
4972 0 : CoilMaxVolFlowRate = SteamCoils::GetCoilMaxSteamFlowRate(state, thisFurnace.SuppHeatCoilIndex, ErrorsFound);
4973 0 : if (CoilMaxVolFlowRate != DataSizing::AutoSize) {
4974 0 : int SteamIndex = 0; // Function GetSatDensityRefrig will look up steam index if 0 is passed
4975 0 : SteamDensity = FluidProperties::GetSatDensityRefrig(
4976 0 : state, fluidNameSteam, state.dataFurnaces->TempSteamIn, 1.0, SteamIndex, RoutineName);
4977 0 : thisFurnace.MaxSuppCoilFluidFlow = CoilMaxVolFlowRate * SteamDensity;
4978 : }
4979 : }
4980 0 : PlantUtilities::InitComponentNodes(
4981 : state, 0.0, thisFurnace.MaxSuppCoilFluidFlow, thisFurnace.SuppCoilControlNode, thisFurnace.SuppCoilOutletNode);
4982 : }
4983 : }
4984 2286 : state.dataFurnaces->MyEnvrnFlag(FurnaceNum) = false;
4985 : }
4986 :
4987 6243009 : if (!state.dataGlobal->BeginEnvrnFlag) {
4988 6222832 : state.dataFurnaces->MyEnvrnFlag(FurnaceNum) = true;
4989 : }
4990 :
4991 6243009 : if (state.dataFurnaces->MyFanFlag(FurnaceNum)) {
4992 625 : if (thisFurnace.ActualFanVolFlowRate != DataSizing::AutoSize) {
4993 359 : if (thisFurnace.ActualFanVolFlowRate > 0.0) {
4994 359 : thisFurnace.HeatingSpeedRatio = thisFurnace.MaxHeatAirVolFlow / thisFurnace.ActualFanVolFlowRate;
4995 359 : thisFurnace.CoolingSpeedRatio = thisFurnace.MaxCoolAirVolFlow / thisFurnace.ActualFanVolFlowRate;
4996 359 : thisFurnace.NoHeatCoolSpeedRatio = thisFurnace.MaxNoCoolHeatAirVolFlow / thisFurnace.ActualFanVolFlowRate;
4997 : }
4998 359 : if (dynamic_cast<Fans::FanComponent *>(state.dataFans->fans(thisFurnace.FanIndex))->powerRatioAtSpeedRatioCurveNum > 0) {
4999 0 : if (thisFurnace.ActualFanVolFlowRate == thisFurnace.MaxHeatAirVolFlow &&
5000 0 : thisFurnace.ActualFanVolFlowRate == thisFurnace.MaxCoolAirVolFlow &&
5001 0 : thisFurnace.ActualFanVolFlowRate == thisFurnace.MaxNoCoolHeatAirVolFlow) {
5002 0 : std::string FanName = state.dataFans->fans(thisFurnace.FanIndex)->Name;
5003 0 : ShowWarningError(state, format("{} \"{}\"", HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name));
5004 0 : ShowContinueError(state,
5005 0 : format("...For fan type and name = {} \"{}\"", HVAC::fanTypeNames[(int)thisFurnace.fanType], FanName));
5006 0 : ShowContinueError(state,
5007 : "...Fan power ratio function of speed ratio curve has no impact if fan volumetric flow rate is the same as "
5008 : "the unitary system volumetric flow rate.");
5009 0 : ShowContinueError(state, format("...Fan volumetric flow rate = {:.5R} m3/s.", thisFurnace.ActualFanVolFlowRate));
5010 0 : ShowContinueError(state, format("...Unitary system volumetric flow rate = {:.5R} m3/s.", thisFurnace.MaxHeatAirVolFlow));
5011 0 : }
5012 : }
5013 359 : state.dataFurnaces->MyFanFlag(FurnaceNum) = false;
5014 : } else {
5015 266 : thisFurnace.ActualFanVolFlowRate = state.dataFans->fans(thisFurnace.FanIndex)->maxAirFlowRate;
5016 : }
5017 : }
5018 :
5019 6243009 : if (allocated(state.dataZoneEquip->ZoneEquipConfig) && state.dataFurnaces->MyCheckFlag(FurnaceNum)) {
5020 359 : int zoneNum = thisFurnace.ControlZoneNum;
5021 359 : int zoneInlet = thisFurnace.ZoneInletNode;
5022 : // setup furnace zone equipment sequence information based on finding matching air terminal
5023 359 : if (state.dataZoneEquip->ZoneEquipConfig(zoneNum).EquipListIndex > 0) {
5024 359 : int coolingPriority = 0;
5025 359 : int heatingPriority = 0;
5026 359 : state.dataZoneEquip->ZoneEquipList(state.dataZoneEquip->ZoneEquipConfig(zoneNum).EquipListIndex)
5027 359 : .getPrioritiesForInletNode(state, zoneInlet, coolingPriority, heatingPriority);
5028 359 : thisFurnace.ZoneSequenceCoolingNum = coolingPriority;
5029 359 : thisFurnace.ZoneSequenceHeatingNum = heatingPriority;
5030 : }
5031 359 : state.dataFurnaces->MyCheckFlag(FurnaceNum) = false;
5032 359 : if (thisFurnace.ZoneSequenceCoolingNum == 0 || thisFurnace.ZoneSequenceHeatingNum == 0) {
5033 0 : ShowSevereError(state,
5034 0 : format("{} \"{}\": Airloop air terminal in the zone equipment list for zone = {} not found or is not allowed Zone "
5035 : "Equipment Cooling or Heating Sequence = 0.",
5036 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
5037 0 : thisFurnace.Name,
5038 0 : state.dataHeatBal->Zone(thisFurnace.ControlZoneNum).Name));
5039 0 : ShowFatalError(state,
5040 0 : format("Subroutine InitFurnace: Errors found in getting {} input. Preceding condition(s) causes termination.",
5041 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type]));
5042 : }
5043 : }
5044 :
5045 : // Find the number of zones (zone Inlet Nodes) attached to an air loop from the air loop number
5046 : int NumAirLoopZones =
5047 6243009 : state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesCooled + state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesHeated;
5048 6243009 : if (allocated(state.dataAirLoop->AirToZoneNodeInfo) && state.dataFurnaces->MyFlowFracFlag(FurnaceNum)) {
5049 359 : state.dataFurnaces->FlowFracFlagReady = true;
5050 799 : for (int ZoneInSysIndex = 1; ZoneInSysIndex <= NumAirLoopZones; ++ZoneInSysIndex) {
5051 : // zone inlet nodes for cooling
5052 440 : if (state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesCooled > 0) {
5053 440 : if (state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolInletNodes(ZoneInSysIndex) == -999) {
5054 : // the data structure for the zones inlet nodes has not been filled
5055 0 : state.dataFurnaces->FlowFracFlagReady = false;
5056 : }
5057 : }
5058 : // zone inlet nodes for heating
5059 440 : if (state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesHeated > 0) {
5060 0 : if (state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitHeatInletNodes(ZoneInSysIndex) == -999) {
5061 : // the data structure for the zones inlet nodes has not been filled
5062 0 : state.dataFurnaces->FlowFracFlagReady = false;
5063 : }
5064 : }
5065 : }
5066 : }
5067 :
5068 6243009 : if (state.dataFurnaces->MyFlowFracFlag(FurnaceNum)) {
5069 359 : if (allocated(state.dataAirLoop->AirToZoneNodeInfo) && state.dataFurnaces->FlowFracFlagReady) {
5070 359 : SumOfMassFlowRateMax = 0.0; // initialize the sum of the maximum flows
5071 799 : for (int ZoneInSysIndex = 1; ZoneInSysIndex <= NumAirLoopZones; ++ZoneInSysIndex) {
5072 440 : int ZoneInletNodeNum = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolInletNodes(ZoneInSysIndex);
5073 440 : SumOfMassFlowRateMax += state.dataLoopNodes->Node(ZoneInletNodeNum).MassFlowRateMax;
5074 440 : if (state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).CoolCtrlZoneNums(ZoneInSysIndex) == thisFurnace.ControlZoneNum) {
5075 359 : CntrlZoneTerminalUnitMassFlowRateMax = state.dataLoopNodes->Node(ZoneInletNodeNum).MassFlowRateMax;
5076 : }
5077 : }
5078 359 : if (SumOfMassFlowRateMax != 0.0) {
5079 359 : if (CntrlZoneTerminalUnitMassFlowRateMax >= HVAC::SmallAirVolFlow) {
5080 359 : thisFurnace.ControlZoneMassFlowFrac = CntrlZoneTerminalUnitMassFlowRateMax / SumOfMassFlowRateMax;
5081 : } else {
5082 0 : ShowSevereError(state, format("{} = {}", HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name));
5083 0 : ShowContinueError(state, " The Fraction of Supply Air Flow That Goes Through the Controlling Zone is set to 1.");
5084 : }
5085 718 : BaseSizer::reportSizerOutput(state,
5086 359 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
5087 : thisFurnace.Name,
5088 : "Fraction of Supply Air Flow That Goes Through the Controlling Zone",
5089 : thisFurnace.ControlZoneMassFlowFrac);
5090 359 : state.dataFurnaces->MyFlowFracFlag(FurnaceNum) = false;
5091 : }
5092 : }
5093 : }
5094 :
5095 : // Calculate air distribution losses
5096 6243009 : if (!FirstHVACIteration && state.dataFurnaces->AirLoopPass == 1) {
5097 2238178 : int ZoneInNode = thisFurnace.ZoneInletNode;
5098 2238178 : MassFlowRate = state.dataLoopNodes->Node(ZoneInNode).MassFlowRate / thisFurnace.ControlZoneMassFlowFrac;
5099 2238178 : if (state.afn->distribution_simulated) {
5100 72768 : DeltaMassRate = state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum).MassFlowRate -
5101 72768 : state.dataLoopNodes->Node(ZoneInNode).MassFlowRate / thisFurnace.ControlZoneMassFlowFrac;
5102 72768 : if (DeltaMassRate < 0.0) DeltaMassRate = 0.0;
5103 : } else {
5104 2165410 : MassFlowRate = state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum).MassFlowRate;
5105 2165410 : DeltaMassRate = 0.0;
5106 : }
5107 2238178 : Real64 TotalOutput(0.0); // total output rate, {W}
5108 2238178 : Real64 SensibleOutputDelta(0.0); // delta sensible output rate, {W}
5109 2238178 : Real64 LatentOutputDelta(0.0); // delta latent output rate, {W}
5110 2238178 : Real64 TotalOutputDelta(0.0); // delta total output rate, {W}
5111 8952712 : CalcZoneSensibleLatentOutput(MassFlowRate,
5112 2238178 : state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum).Temp,
5113 2238178 : state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum).HumRat,
5114 2238178 : state.dataLoopNodes->Node(ZoneInNode).Temp,
5115 2238178 : state.dataLoopNodes->Node(ZoneInNode).HumRat,
5116 2238178 : thisFurnace.SenLoadLoss,
5117 2238178 : thisFurnace.LatLoadLoss,
5118 : TotalOutput);
5119 8952712 : CalcZoneSensibleLatentOutput(DeltaMassRate,
5120 2238178 : state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum).Temp,
5121 2238178 : state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum).HumRat,
5122 2238178 : state.dataLoopNodes->Node(thisFurnace.NodeNumOfControlledZone).Temp,
5123 2238178 : state.dataLoopNodes->Node(thisFurnace.NodeNumOfControlledZone).HumRat,
5124 : SensibleOutputDelta,
5125 : LatentOutputDelta,
5126 : TotalOutputDelta);
5127 2238178 : thisFurnace.SenLoadLoss = thisFurnace.SenLoadLoss + SensibleOutputDelta;
5128 2238178 : if (std::abs(thisFurnace.SensibleLoadMet) > 0.0) {
5129 1409029 : if (std::abs(thisFurnace.SenLoadLoss / thisFurnace.SensibleLoadMet) < 0.001) thisFurnace.SenLoadLoss = 0.0;
5130 : }
5131 2238178 : if (thisFurnace.Humidistat) {
5132 260797 : thisFurnace.LatLoadLoss = thisFurnace.LatLoadLoss + LatentOutputDelta;
5133 260797 : if (std::abs(thisFurnace.LatentLoadMet) > 0.0) {
5134 231001 : if (std::abs(thisFurnace.LatLoadLoss / thisFurnace.LatentLoadMet) < 0.001) thisFurnace.LatLoadLoss = 0.0;
5135 : }
5136 : }
5137 : }
5138 :
5139 6243009 : if (thisFurnace.FanSchedPtr > 0) {
5140 5885489 : if (ScheduleManager::GetCurrentScheduleValue(state, thisFurnace.FanSchedPtr) == 0.0) {
5141 2501454 : thisFurnace.fanOp = HVAC::FanOp::Cycling;
5142 : } else {
5143 3384035 : thisFurnace.fanOp = HVAC::FanOp::Continuous;
5144 : }
5145 5885489 : if (AirLoopNum > 0) {
5146 5885489 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).fanOp = thisFurnace.fanOp;
5147 : }
5148 : }
5149 :
5150 6243009 : fanOp = thisFurnace.fanOp;
5151 6243009 : state.dataFurnaces->EconomizerFlag = state.dataAirLoop->AirLoopControlInfo(AirLoopNum).EconoActive;
5152 :
5153 6243009 : if (thisFurnace.ControlZoneMassFlowFrac > 0.0) {
5154 6243009 : QZnReq = ZoneLoad / thisFurnace.ControlZoneMassFlowFrac;
5155 6243009 : MoistureLoad /= thisFurnace.ControlZoneMassFlowFrac;
5156 6243009 : ZoneLoad = QZnReq;
5157 : } else {
5158 0 : QZnReq = ZoneLoad;
5159 : }
5160 :
5161 : // Original thermostat control logic (works only for cycling fan systems)
5162 8269675 : if (QZnReq > HVAC::SmallLoad && QZnReq > (Small5WLoad / thisFurnace.ControlZoneMassFlowFrac) &&
5163 2026666 : !state.dataZoneEnergyDemand->CurDeadBandOrSetback(thisFurnace.ControlZoneNum)) {
5164 2014394 : state.dataFurnaces->HeatingLoad = true;
5165 2014394 : state.dataFurnaces->CoolingLoad = false;
5166 7270639 : } else if (QZnReq < -HVAC::SmallLoad && std::abs(QZnReq) > (Small5WLoad / thisFurnace.ControlZoneMassFlowFrac) &&
5167 3042024 : !state.dataZoneEnergyDemand->CurDeadBandOrSetback(thisFurnace.ControlZoneNum)) {
5168 3041900 : state.dataFurnaces->HeatingLoad = false;
5169 3041900 : state.dataFurnaces->CoolingLoad = true;
5170 : } else {
5171 1186715 : state.dataFurnaces->HeatingLoad = false;
5172 1186715 : state.dataFurnaces->CoolingLoad = false;
5173 : }
5174 :
5175 6243009 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir ||
5176 5821217 : (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir &&
5177 2058572 : (thisFurnace.WatertoAirHPType == WAHPCoilType::Simple || thisFurnace.WatertoAirHPType == WAHPCoilType::VarSpeedEquationFit))) {
5178 2361094 : if (MoistureLoad < 0.0 && thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat) {
5179 125668 : state.dataFurnaces->HPDehumidificationLoadFlag = true;
5180 125668 : state.dataFurnaces->HeatingLoad = false;
5181 125668 : state.dataFurnaces->CoolingLoad = true;
5182 : } else {
5183 2235426 : state.dataFurnaces->HPDehumidificationLoadFlag = false;
5184 : }
5185 : }
5186 :
5187 : // Check for heat only furnace
5188 6243009 : if (thisFurnace.type != HVAC::UnitarySysType::Furnace_HeatOnly && thisFurnace.type != HVAC::UnitarySysType::Unitary_HeatOnly) {
5189 :
5190 6218565 : if (ScheduleManager::GetCurrentScheduleValue(state, thisFurnace.SchedPtr) > 0.0) {
5191 5978520 : if ((state.dataFurnaces->HeatingLoad || state.dataFurnaces->CoolingLoad) || (thisFurnace.Humidistat && MoistureLoad < 0.0)) {
5192 5267872 : PartLoadRatio = 1.0;
5193 : } else {
5194 710648 : PartLoadRatio = 0.0;
5195 : }
5196 : } else {
5197 240045 : PartLoadRatio = 0.0;
5198 : }
5199 : } else {
5200 24444 : PartLoadRatio = 1.0;
5201 : }
5202 :
5203 : // get current time step operating capacity of water and steam coils
5204 : // (dependent on entering water and steam temperature)
5205 6243009 : if (FirstHVACIteration) {
5206 1733311 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWater) {
5207 : // set water-side mass flow rates
5208 0 : state.dataLoopNodes->Node(thisFurnace.HWCoilAirInletNode).MassFlowRate = state.dataFurnaces->CompOnMassFlow;
5209 0 : mdot = thisFurnace.MaxHeatCoilFluidFlow;
5210 0 : PlantUtilities::SetComponentFlowRate(state, mdot, thisFurnace.CoilControlNode, thisFurnace.CoilOutletNode, thisFurnace.plantLoc);
5211 : // simulate water coil to find operating capacity
5212 0 : WaterCoils::SimulateWaterCoilComponents(
5213 0 : state, thisFurnace.HeatingCoilName, FirstHVACIteration, thisFurnace.HeatingCoilIndex, QActual);
5214 0 : thisFurnace.DesignHeatingCapacity = QActual;
5215 :
5216 : } // from IF(furnace%HeatingCoilType_Num == Coil_HeatingWater) THEN
5217 :
5218 1733311 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingSteam) {
5219 : // set air-side and steam-side mass flow rates
5220 0 : state.dataLoopNodes->Node(thisFurnace.HWCoilAirInletNode).MassFlowRate = state.dataFurnaces->CompOnMassFlow;
5221 0 : mdot = thisFurnace.MaxHeatCoilFluidFlow;
5222 0 : PlantUtilities::SetComponentFlowRate(state, mdot, thisFurnace.CoilControlNode, thisFurnace.CoilOutletNode, thisFurnace.plantLoc);
5223 :
5224 : // simulate steam coil to find operating capacity
5225 0 : SteamCoils::SimulateSteamCoilComponents(state,
5226 : thisFurnace.HeatingCoilName,
5227 : FirstHVACIteration,
5228 0 : thisFurnace.HeatingCoilIndex,
5229 0 : 1.0,
5230 : QActual); // QCoilReq, simulate any load > 0 to get max capacity of steam coil
5231 0 : thisFurnace.DesignHeatingCapacity =
5232 0 : SteamCoils::GetCoilCapacity(state, thisFurnace.HeatingCoilType, thisFurnace.HeatingCoilName, ErrorsFound);
5233 :
5234 : } // from IF(Furnace(FurnaceNum)%HeatingCoilType_Num == Coil_HeatingSteam) THEN
5235 :
5236 1733311 : if (thisFurnace.SuppHeatCoilType_Num == HVAC::Coil_HeatingWater) {
5237 :
5238 : // set air-side and steam-side mass flow rates
5239 3678 : state.dataLoopNodes->Node(thisFurnace.SuppCoilAirInletNode).MassFlowRate = state.dataFurnaces->CompOnMassFlow;
5240 3678 : mdot = thisFurnace.MaxSuppCoilFluidFlow;
5241 3678 : PlantUtilities::SetComponentFlowRate(
5242 3678 : state, mdot, thisFurnace.SuppCoilControlNode, thisFurnace.SuppCoilOutletNode, thisFurnace.SuppPlantLoc);
5243 :
5244 : // simulate water coil to find operating capacity
5245 7356 : WaterCoils::SimulateWaterCoilComponents(
5246 3678 : state, thisFurnace.SuppHeatCoilName, FirstHVACIteration, thisFurnace.SuppHeatCoilIndex, QActual);
5247 3678 : thisFurnace.DesignSuppHeatingCapacity = QActual;
5248 :
5249 : } // from IF(Furnace(FurnaceNum)%SuppHeatCoilType_Num == Coil_HeatingWater) THEN
5250 1733311 : if (thisFurnace.SuppHeatCoilType_Num == HVAC::Coil_HeatingSteam) {
5251 : // set air-side and steam-side mass flow rates
5252 0 : state.dataLoopNodes->Node(thisFurnace.SuppCoilAirInletNode).MassFlowRate = state.dataFurnaces->CompOnMassFlow;
5253 0 : mdot = thisFurnace.MaxSuppCoilFluidFlow;
5254 0 : PlantUtilities::SetComponentFlowRate(
5255 0 : state, mdot, thisFurnace.SuppCoilControlNode, thisFurnace.SuppCoilOutletNode, thisFurnace.SuppPlantLoc);
5256 :
5257 : // simulate steam coil to find operating capacity
5258 0 : SteamCoils::SimulateSteamCoilComponents(state,
5259 : thisFurnace.SuppHeatCoilName,
5260 : FirstHVACIteration,
5261 0 : thisFurnace.SuppHeatCoilIndex,
5262 0 : 1.0,
5263 : QActual); // QCoilReq, simulate any load > 0 to get max capacity of steam coil
5264 0 : thisFurnace.DesignSuppHeatingCapacity =
5265 0 : SteamCoils::GetCoilCapacity(state, thisFurnace.SuppHeatCoilType, thisFurnace.SuppHeatCoilName, ErrorsFound);
5266 :
5267 : } // from IF(Furnace(FurnaceNum)%SuppHeatCoilType_Num == Coil_HeatingSteam) THEN
5268 : } // from IF( FirstHVACIteration ) THEN
5269 :
5270 6243009 : if (thisFurnace.NumOfSpeedCooling > 0) { // BoS, variable-speed water source hp
5271 : // Furnace(FurnaceNum)%IdleMassFlowRate = RhoAir*Furnace(FurnaceNum)%IdleVolumeAirRate
5272 1507624 : int NumOfSpeedCooling = thisFurnace.NumOfSpeedCooling;
5273 1507624 : int NumOfSpeedHeating = thisFurnace.NumOfSpeedHeating;
5274 : // IF MSHP system was not autosized and the fan is autosized, check that fan volumetric flow rate is greater than MSHP flow rates
5275 1507624 : if (thisFurnace.CheckFanFlow) {
5276 21 : state.dataFurnaces->CurrentModuleObject = "AirLoopHVAC:UnitaryHeatPump:VariableSpeed";
5277 21 : thisFurnace.FanVolFlow = state.dataFans->fans(thisFurnace.FanIndex)->maxAirFlowRate;
5278 :
5279 21 : if (thisFurnace.FanVolFlow != DataSizing::AutoSize) {
5280 : // Check fan versus system supply air flow rates
5281 17 : if (thisFurnace.FanVolFlow + 1e-10 < thisFurnace.CoolVolumeFlowRate(NumOfSpeedCooling)) {
5282 0 : ShowWarningError(state,
5283 0 : format("{} - air flow rate = {:.7T} in fan object is less than the MSHP system air flow rate when cooling "
5284 : "is required ({:.7T}).",
5285 0 : state.dataFurnaces->CurrentModuleObject,
5286 0 : thisFurnace.FanVolFlow,
5287 : thisFurnace.CoolVolumeFlowRate(NumOfSpeedCooling)));
5288 0 : ShowContinueError(
5289 : state, " The MSHP system flow rate when cooling is required is reset to the fan flow rate and the simulation continues.");
5290 0 : ShowContinueError(state, format(" Occurs in {} = {}", state.dataFurnaces->CurrentModuleObject, thisFurnace.Name));
5291 0 : thisFurnace.CoolVolumeFlowRate(NumOfSpeedCooling) = thisFurnace.FanVolFlow;
5292 :
5293 0 : if (thisFurnace.bIsIHP) // set max fan flow rate to the IHP collection
5294 : {
5295 0 : state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).MaxCoolAirVolFlow = thisFurnace.FanVolFlow;
5296 0 : state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).MaxCoolAirMassFlow =
5297 0 : thisFurnace.FanVolFlow * state.dataEnvrn->StdRhoAir;
5298 : }
5299 :
5300 : // Check flow rates in other speeds and ensure flow rates are not above the max flow rate
5301 0 : for (int i = NumOfSpeedCooling - 1; i >= 1; --i) {
5302 0 : if (thisFurnace.CoolVolumeFlowRate(i) > thisFurnace.CoolVolumeFlowRate(i + 1)) {
5303 0 : ShowContinueError(state,
5304 0 : format(" The MSHP system flow rate when cooling is required is reset to the flow rate at higher "
5305 : "speed and the simulation continues at Speed{}.",
5306 : i));
5307 0 : ShowContinueError(state, format(" Occurs in {} = {}", state.dataFurnaces->CurrentModuleObject, thisFurnace.Name));
5308 0 : thisFurnace.CoolVolumeFlowRate(i) = thisFurnace.CoolVolumeFlowRate(i + 1);
5309 : }
5310 : }
5311 : }
5312 17 : if (NumOfSpeedHeating > 0) {
5313 17 : if (thisFurnace.FanVolFlow + 1e-10 < thisFurnace.HeatVolumeFlowRate(NumOfSpeedHeating)) {
5314 0 : ShowWarningError(state,
5315 0 : format("{} - air flow rate = {:.7T} in fan object is less than the MSHP system air flow rate when "
5316 : "heating is required ({:.7T}).",
5317 0 : state.dataFurnaces->CurrentModuleObject,
5318 0 : thisFurnace.FanVolFlow,
5319 : thisFurnace.HeatVolumeFlowRate(NumOfSpeedHeating)));
5320 0 : ShowContinueError(
5321 : state,
5322 : " The MSHP system flow rate when heating is required is reset to the fan flow rate and the simulation continues.");
5323 0 : ShowContinueError(state, format(" Occurs in {} = {}", state.dataFurnaces->CurrentModuleObject, thisFurnace.Name));
5324 0 : thisFurnace.HeatVolumeFlowRate(NumOfSpeedHeating) = thisFurnace.FanVolFlow;
5325 :
5326 0 : if (thisFurnace.bIsIHP) // set max fan flow rate to the IHP collection
5327 : {
5328 0 : state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).MaxHeatAirVolFlow = thisFurnace.FanVolFlow;
5329 0 : state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).MaxHeatAirMassFlow =
5330 0 : thisFurnace.FanVolFlow * state.dataEnvrn->StdRhoAir;
5331 : }
5332 :
5333 0 : for (int i = NumOfSpeedHeating - 1; i >= 1; --i) {
5334 0 : if (thisFurnace.HeatVolumeFlowRate(i) > thisFurnace.HeatVolumeFlowRate(i + 1)) {
5335 0 : ShowContinueError(state,
5336 0 : format(" The MSHP system flow rate when heating is required is reset to the flow rate at "
5337 : "higher speed and the simulation continues at Speed{}.",
5338 : i));
5339 0 : ShowContinueError(state,
5340 0 : format(" Occurs in {} system = {}", state.dataFurnaces->CurrentModuleObject, thisFurnace.Name));
5341 0 : thisFurnace.HeatVolumeFlowRate(i) = thisFurnace.HeatVolumeFlowRate(i + 1);
5342 : }
5343 : }
5344 : }
5345 : }
5346 17 : if (thisFurnace.FanVolFlow < thisFurnace.IdleVolumeAirRate && thisFurnace.IdleVolumeAirRate != 0.0) {
5347 0 : ShowWarningError(state,
5348 0 : format("{} - air flow rate = {:.7T} in fan object is less than the MSHP system air flow rate when no "
5349 : "heating or cooling is needed ({:.7T}).",
5350 0 : state.dataFurnaces->CurrentModuleObject,
5351 0 : thisFurnace.FanVolFlow,
5352 0 : thisFurnace.IdleVolumeAirRate));
5353 0 : ShowContinueError(state,
5354 : " The MSHP system flow rate when no heating or cooling is needed is reset to the fan flow rate and the "
5355 : "simulation continues.");
5356 0 : ShowContinueError(state, format(" Occurs in {} = {}", state.dataFurnaces->CurrentModuleObject, thisFurnace.Name));
5357 0 : thisFurnace.IdleVolumeAirRate = thisFurnace.FanVolFlow;
5358 : }
5359 17 : RhoAir = state.dataEnvrn->StdRhoAir;
5360 : // set the mass flow rates from the reset volume flow rates
5361 187 : for (int i = 1; i <= NumOfSpeedCooling; ++i) {
5362 170 : thisFurnace.CoolMassFlowRate(i) = RhoAir * thisFurnace.CoolVolumeFlowRate(i);
5363 170 : if (thisFurnace.FanVolFlow > 0.0) {
5364 170 : thisFurnace.MSCoolingSpeedRatio(i) = thisFurnace.CoolVolumeFlowRate(i) / thisFurnace.FanVolFlow;
5365 : }
5366 : }
5367 187 : for (int i = 1; i <= NumOfSpeedHeating; ++i) {
5368 170 : thisFurnace.HeatMassFlowRate(i) = RhoAir * thisFurnace.HeatVolumeFlowRate(i);
5369 170 : if (thisFurnace.FanVolFlow > 0.0) {
5370 170 : thisFurnace.MSHeatingSpeedRatio(i) = thisFurnace.HeatVolumeFlowRate(i) / thisFurnace.FanVolFlow;
5371 : }
5372 : }
5373 17 : thisFurnace.IdleMassFlowRate = RhoAir * thisFurnace.IdleVolumeAirRate;
5374 17 : if (thisFurnace.FanVolFlow > 0.0) {
5375 17 : thisFurnace.IdleSpeedRatio = thisFurnace.IdleVolumeAirRate / thisFurnace.FanVolFlow;
5376 : }
5377 : // set the node max and min mass flow rates based on reset volume flow rates
5378 17 : if (NumOfSpeedCooling > 0 && NumOfSpeedHeating == 0) {
5379 0 : state.dataLoopNodes->Node(InNode).MassFlowRateMax =
5380 0 : max(thisFurnace.CoolMassFlowRate(NumOfSpeedCooling), thisFurnace.MaxHeatAirMassFlow);
5381 0 : state.dataLoopNodes->Node(InNode).MassFlowRateMaxAvail =
5382 0 : max(thisFurnace.CoolMassFlowRate(NumOfSpeedCooling), thisFurnace.MaxHeatAirMassFlow);
5383 17 : } else if (NumOfSpeedCooling == 0 && NumOfSpeedHeating > 0) {
5384 0 : state.dataLoopNodes->Node(InNode).MassFlowRateMax =
5385 0 : max(thisFurnace.MaxCoolAirMassFlow, thisFurnace.HeatMassFlowRate(NumOfSpeedHeating));
5386 0 : state.dataLoopNodes->Node(InNode).MassFlowRateMaxAvail =
5387 0 : max(thisFurnace.MaxCoolAirMassFlow, thisFurnace.HeatMassFlowRate(NumOfSpeedHeating));
5388 : } else {
5389 17 : state.dataLoopNodes->Node(InNode).MassFlowRateMax =
5390 17 : max(thisFurnace.CoolMassFlowRate(NumOfSpeedCooling), thisFurnace.HeatMassFlowRate(NumOfSpeedHeating));
5391 17 : state.dataLoopNodes->Node(InNode).MassFlowRateMaxAvail =
5392 17 : max(thisFurnace.CoolMassFlowRate(NumOfSpeedCooling), thisFurnace.HeatMassFlowRate(NumOfSpeedHeating));
5393 : }
5394 17 : state.dataLoopNodes->Node(InNode).MassFlowRateMin = 0.0;
5395 17 : state.dataLoopNodes->Node(InNode).MassFlowRateMinAvail = 0.0;
5396 17 : state.dataLoopNodes->Node(OutNode) = state.dataLoopNodes->Node(InNode);
5397 : }
5398 : }
5399 :
5400 1507624 : thisFurnace.CheckFanFlow = false;
5401 : }
5402 6243009 : SetOnOffMassFlowRate(state, FurnaceNum, AirLoopNum, OnOffAirFlowRatio, fanOp, QZnReq, MoistureLoad, PartLoadRatio);
5403 :
5404 : // Check ventilation/fan load for constant fan systems to see if load to be met changes
5405 : // Same IF logic used in Subroutine SetAverageAirFlow to determine if unit is ON or OFF
5406 :
5407 6243009 : QToCoolSetPt = 0.0;
5408 6243009 : QToHeatSetPt = 0.0;
5409 9418627 : if (fanOp == HVAC::FanOp::Continuous && ScheduleManager::GetCurrentScheduleValue(state, thisFurnace.SchedPtr) > 0.0 &&
5410 3175618 : ((ScheduleManager::GetCurrentScheduleValue(state, thisFurnace.FanAvailSchedPtr) > 0.0 || state.dataHVACGlobal->TurnFansOn) &&
5411 3165070 : !state.dataHVACGlobal->TurnFansOff)) {
5412 :
5413 3165070 : if (thisFurnace.NumOfSpeedCooling > 0) {
5414 1465806 : CalcVarSpeedHeatPump(state,
5415 : FurnaceNum,
5416 : false,
5417 : HVAC::CompressorOp::Off,
5418 : 1,
5419 : 0.0,
5420 : 0.0,
5421 : SensibleOutput,
5422 : LatentOutput,
5423 : 0.0,
5424 : 0.0,
5425 : OnOffAirFlowRatio,
5426 : SUPHEATERLOAD);
5427 : } else {
5428 1699264 : CalcFurnaceOutput(state,
5429 : FurnaceNum,
5430 : false,
5431 : HVAC::FanOp::Invalid, // Looks like Invalid is used to mean that the fan is off here?
5432 : HVAC::CompressorOp::Off,
5433 : 0.0,
5434 : 0.0,
5435 : 0.0,
5436 : 0.0,
5437 : SensibleOutput,
5438 : LatentOutput,
5439 : OnOffAirFlowRatio,
5440 : false);
5441 : }
5442 :
5443 3165070 : if (thisFurnace.ControlZoneMassFlowFrac > 0.0) {
5444 3165070 : if (thisFurnace.ZoneSequenceCoolingNum > 0 && thisFurnace.ZoneSequenceHeatingNum > 0) {
5445 3165070 : QToCoolSetPt = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(thisFurnace.ControlZoneNum)
5446 3165070 : .SequencedOutputRequiredToCoolingSP(thisFurnace.ZoneSequenceCoolingNum) /
5447 3165070 : thisFurnace.ControlZoneMassFlowFrac;
5448 3165070 : QToHeatSetPt = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(thisFurnace.ControlZoneNum)
5449 3165070 : .SequencedOutputRequiredToHeatingSP(thisFurnace.ZoneSequenceHeatingNum) /
5450 3165070 : thisFurnace.ControlZoneMassFlowFrac;
5451 : } else {
5452 0 : QToCoolSetPt = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(thisFurnace.ControlZoneNum).OutputRequiredToCoolingSP /
5453 0 : thisFurnace.ControlZoneMassFlowFrac;
5454 0 : QToHeatSetPt = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(thisFurnace.ControlZoneNum).OutputRequiredToHeatingSP /
5455 0 : thisFurnace.ControlZoneMassFlowFrac;
5456 : }
5457 : // If the furnace has a net cooling capacity (SensibleOutput < 0) and
5458 : // the zone temp is above the Tstat heating setpoint (QToHeatSetPt < 0) and
5459 : // the net cooling capacity does not just offset the cooling load
5460 3867650 : if (SensibleOutput < 0.0 && QToHeatSetPt < 0.0 &&
5461 702580 : std::abs(QToCoolSetPt - SensibleOutput) > (Small5WLoad / thisFurnace.ControlZoneMassFlowFrac)) {
5462 : // Only switch modes when humidistat is not used or no moisture load exists, otherwise let
5463 : // reheat coil pick up load
5464 : // IF((SensibleOutput .LT. QToHeatSetPt .AND. .NOT. Furnace(FurnaceNum)%Humidistat) .OR. &
5465 : // (SensibleOutput .LT. QToHeatSetPt .AND. Furnace(FurnaceNum)%Humidistat .AND. MoistureLoad .GE. 0.0))THEN
5466 701883 : if ((SensibleOutput < QToHeatSetPt && !thisFurnace.Humidistat) ||
5467 697867 : (SensibleOutput < QToHeatSetPt && thisFurnace.Humidistat && MoistureLoad >= 0.0)) {
5468 4562 : QZnReq = QToHeatSetPt;
5469 4562 : state.dataFurnaces->CoolingLoad = false;
5470 : // Don't set mode TRUE unless mode is allowed. Also check for floating zone.
5471 9122 : if (state.dataHeatBalFanSys->TempControlType(thisFurnace.ControlZoneNum) == HVAC::ThermostatType::SingleCooling ||
5472 4560 : state.dataHeatBalFanSys->TempControlType(thisFurnace.ControlZoneNum) == HVAC::ThermostatType::Uncontrolled) {
5473 2 : state.dataFurnaces->HeatingLoad = false;
5474 : } else {
5475 4560 : state.dataFurnaces->HeatingLoad = true;
5476 : }
5477 :
5478 4562 : SetOnOffMassFlowRate(state, FurnaceNum, AirLoopNum, OnOffAirFlowRatio, fanOp, QZnReq, MoistureLoad, PartLoadRatio);
5479 4562 : if (thisFurnace.NumOfSpeedCooling > 0) {
5480 338 : CalcVarSpeedHeatPump(state,
5481 : FurnaceNum,
5482 : false,
5483 : HVAC::CompressorOp::Off,
5484 : 1,
5485 : 0.0,
5486 : 0.0,
5487 : SensibleOutput,
5488 : LatentOutput,
5489 : 0.0,
5490 : 0.0,
5491 : OnOffAirFlowRatio,
5492 : SUPHEATERLOAD);
5493 : } else {
5494 4224 : CalcFurnaceOutput(state,
5495 : FurnaceNum,
5496 : false,
5497 : HVAC::FanOp::Invalid,
5498 : HVAC::CompressorOp::Off,
5499 : 0.0,
5500 : 0.0,
5501 : 0.0,
5502 : 0.0,
5503 : SensibleOutput,
5504 : LatentOutput,
5505 : OnOffAirFlowRatio,
5506 : false);
5507 : }
5508 4562 : if (SensibleOutput > QToHeatSetPt) {
5509 : // If changing operating mode (flow rates) does not overshoot heating setpoint, turn off heating
5510 0 : QZnReq = 0.0;
5511 0 : state.dataFurnaces->HeatingLoad = false;
5512 0 : SetOnOffMassFlowRate(state, FurnaceNum, AirLoopNum, OnOffAirFlowRatio, fanOp, QZnReq, MoistureLoad, PartLoadRatio);
5513 : }
5514 697321 : } else if (SensibleOutput < QZnReq) {
5515 : // If the net cooling capacity meets the zone cooling load but does not overshoot heating setpoint, turn off cooling
5516 : // (dehumidification may still occur)
5517 63386 : QZnReq = 0.0;
5518 63386 : state.dataFurnaces->CoolingLoad = false;
5519 63386 : if (state.dataFurnaces->HPDehumidificationLoadFlag) {
5520 134 : state.dataFurnaces->CoolingLoad = true;
5521 134 : state.dataFurnaces->HeatingLoad = false;
5522 : }
5523 63386 : SetOnOffMassFlowRate(state, FurnaceNum, AirLoopNum, OnOffAirFlowRatio, fanOp, QZnReq, MoistureLoad, PartLoadRatio);
5524 : }
5525 : // the net cooling capacity just offsets the cooling load, turn off cooling
5526 2463884 : } else if (SensibleOutput < 0.0 && QToCoolSetPt < 0.0 &&
5527 697 : std::abs(QToCoolSetPt - SensibleOutput) < (Small5WLoad / thisFurnace.ControlZoneMassFlowFrac)) {
5528 697 : state.dataFurnaces->CoolingLoad = false;
5529 697 : if (state.dataFurnaces->HPDehumidificationLoadFlag) {
5530 0 : state.dataFurnaces->CoolingLoad = true;
5531 0 : state.dataFurnaces->HeatingLoad = false;
5532 : }
5533 : } // SensibleOutput .LT. 0.0d0 .AND. QToHeatSetPt .LT. 0.0d0
5534 :
5535 : // If the furnace has a net heating capacity and the zone temp is below the Tstat cooling setpoint and
5536 : // the net heating capacity does not just offset the heating load
5537 4016225 : if (SensibleOutput > 0.0 && QToCoolSetPt > 0.0 &&
5538 851155 : std::abs(SensibleOutput - QToHeatSetPt) > (Small5WLoad / thisFurnace.ControlZoneMassFlowFrac)) {
5539 850898 : if (SensibleOutput > QToCoolSetPt) {
5540 96234 : QZnReq = QToCoolSetPt;
5541 : // Don't set mode TRUE unless mode is allowed. Also check for floating zone.
5542 192418 : if (state.dataHeatBalFanSys->TempControlType(thisFurnace.ControlZoneNum) == HVAC::ThermostatType::SingleHeating ||
5543 96184 : state.dataHeatBalFanSys->TempControlType(thisFurnace.ControlZoneNum) == HVAC::ThermostatType::Uncontrolled) {
5544 50 : state.dataFurnaces->CoolingLoad = false;
5545 : } else {
5546 96184 : state.dataFurnaces->CoolingLoad = true;
5547 : }
5548 96234 : state.dataFurnaces->HeatingLoad = false;
5549 :
5550 96234 : SetOnOffMassFlowRate(state, FurnaceNum, AirLoopNum, OnOffAirFlowRatio, fanOp, QZnReq, MoistureLoad, PartLoadRatio);
5551 96234 : if (thisFurnace.NumOfSpeedCooling > 0) {
5552 6895 : CalcVarSpeedHeatPump(state,
5553 : FurnaceNum,
5554 : false,
5555 : HVAC::CompressorOp::Off,
5556 : 1,
5557 : 0.0,
5558 : 0.0,
5559 : SensibleOutput,
5560 : LatentOutput,
5561 : 0.0,
5562 : 0.0,
5563 : OnOffAirFlowRatio,
5564 : SUPHEATERLOAD);
5565 : } else {
5566 89339 : CalcFurnaceOutput(state,
5567 : FurnaceNum,
5568 : false,
5569 : HVAC::FanOp::Invalid,
5570 : HVAC::CompressorOp::Off,
5571 : 0.0,
5572 : 0.0,
5573 : 0.0,
5574 : 0.0,
5575 : SensibleOutput,
5576 : LatentOutput,
5577 : OnOffAirFlowRatio,
5578 : false);
5579 : }
5580 96234 : if (SensibleOutput < QToCoolSetPt) {
5581 : // If changing operating mode (flow rates) does not overshoot cooling setpoint, turn off cooling
5582 0 : if (state.dataFurnaces->HPDehumidificationLoadFlag) {
5583 0 : state.dataFurnaces->CoolingLoad = true;
5584 0 : state.dataFurnaces->HeatingLoad = false;
5585 : } else {
5586 0 : QZnReq = 0.0;
5587 0 : state.dataFurnaces->CoolingLoad = false;
5588 : }
5589 0 : SetOnOffMassFlowRate(state, FurnaceNum, AirLoopNum, OnOffAirFlowRatio, fanOp, QZnReq, MoistureLoad, PartLoadRatio);
5590 : }
5591 754664 : } else if (SensibleOutput > QZnReq) {
5592 : // If the net heating capacity meets the zone heating load but does not overshoot, turn off heating
5593 658456 : QZnReq = 0.0;
5594 658456 : state.dataFurnaces->HeatingLoad = false;
5595 658456 : SetOnOffMassFlowRate(state, FurnaceNum, AirLoopNum, OnOffAirFlowRatio, fanOp, QZnReq, MoistureLoad, PartLoadRatio);
5596 : }
5597 : // the net heating capacity just offsets the heating load, turn off heating
5598 2314429 : } else if (SensibleOutput > 0.0 && QToHeatSetPt > 0.0 &&
5599 257 : std::abs(SensibleOutput - QToHeatSetPt) < (Small5WLoad / thisFurnace.ControlZoneMassFlowFrac)) {
5600 257 : state.dataFurnaces->HeatingLoad = false;
5601 : } // SensibleOutput .GT. 0.0d0 .AND. QToCoolSetPt .GT. 0.0d0
5602 : } // Furnace(FurnaceNum)%ControlZoneMassFlowFrac .GT. 0.0d0
5603 3165070 : ZoneLoad = QZnReq;
5604 : } // fanOp .EQ. FanOp::Continuous
5605 :
5606 6243009 : if (FirstHVACIteration) {
5607 1733311 : thisFurnace.iterationCounter = 0;
5608 1733311 : thisFurnace.iterationMode = Furnaces::ModeOfOperation::NoCoolHeat;
5609 : }
5610 6243009 : thisFurnace.iterationCounter += 1;
5611 :
5612 : // push iteration mode stack and set current mode
5613 6243009 : thisFurnace.iterationMode(3) = thisFurnace.iterationMode(2);
5614 6243009 : thisFurnace.iterationMode(2) = thisFurnace.iterationMode(1);
5615 6243009 : if (state.dataFurnaces->CoolingLoad) {
5616 3237836 : thisFurnace.iterationMode(1) = Furnaces::ModeOfOperation::CoolingMode;
5617 3005173 : } else if (state.dataFurnaces->HeatingLoad) {
5618 1974343 : thisFurnace.iterationMode(1) = Furnaces::ModeOfOperation::HeatingMode;
5619 : } else {
5620 1030830 : thisFurnace.iterationMode(1) = Furnaces::ModeOfOperation::NoCoolHeat;
5621 : }
5622 :
5623 : // IF small loads to meet or not converging, just shut down unit
5624 6243009 : if (std::abs(ZoneLoad) < Small5WLoad) {
5625 1103286 : ZoneLoad = 0.0;
5626 1103286 : state.dataFurnaces->CoolingLoad = false;
5627 1103286 : state.dataFurnaces->HeatingLoad = false;
5628 5139723 : } else if (thisFurnace.iterationCounter > (state.dataHVACGlobal->MinAirLoopIterationsAfterFirst + 4)) {
5629 : // attempt to lock output (air flow) if oscillations are detected
5630 1973783 : OperatingMode = thisFurnace.iterationMode(1);
5631 1973783 : OperatingModeMinusOne = thisFurnace.iterationMode(2);
5632 1973783 : OperatingModeMinusTwo = thisFurnace.iterationMode(3);
5633 1973783 : Oscillate = true;
5634 1973783 : if (OperatingMode == OperatingModeMinusOne && OperatingMode == OperatingModeMinusTwo) Oscillate = false;
5635 1973783 : if (Oscillate) {
5636 44 : if (QToCoolSetPt < 0.0) {
5637 8 : state.dataFurnaces->HeatingLoad = false;
5638 8 : state.dataFurnaces->CoolingLoad = true;
5639 8 : ZoneLoad = QToCoolSetPt;
5640 36 : } else if (QToHeatSetPt > 0.0) {
5641 12 : state.dataFurnaces->HeatingLoad = true;
5642 12 : state.dataFurnaces->CoolingLoad = false;
5643 12 : ZoneLoad = QToHeatSetPt;
5644 : } else {
5645 24 : state.dataFurnaces->HeatingLoad = false;
5646 24 : state.dataFurnaces->CoolingLoad = false;
5647 24 : ZoneLoad = 0.0;
5648 : }
5649 : }
5650 : }
5651 :
5652 : // EMS override point
5653 6243009 : if (thisFurnace.EMSOverrideSensZoneLoadRequest) ZoneLoad = thisFurnace.EMSSensibleZoneLoadValue;
5654 6243009 : if (thisFurnace.EMSOverrideMoistZoneLoadRequest) MoistureLoad = thisFurnace.EMSMoistureZoneLoadValue;
5655 6243009 : if (thisFurnace.EMSOverrideSensZoneLoadRequest || thisFurnace.EMSOverrideMoistZoneLoadRequest) {
5656 0 : if ((ZoneLoad != 0.0) && (thisFurnace.EMSOverrideSensZoneLoadRequest)) {
5657 0 : PartLoadRatio = 1.0;
5658 0 : } else if ((MoistureLoad != 0.0) && (thisFurnace.EMSOverrideMoistZoneLoadRequest)) {
5659 0 : PartLoadRatio = 1.0;
5660 : } else {
5661 0 : PartLoadRatio = 0.0;
5662 : }
5663 0 : if (thisFurnace.NumOfSpeedCooling > 0) {
5664 0 : SetOnOffMassFlowRate(state, FurnaceNum, AirLoopNum, OnOffAirFlowRatio, fanOp, QZnReq, MoistureLoad, PartLoadRatio);
5665 : } else {
5666 : // This line is suspicious - all other calls to SetOnOffMassFlowRate pass in QZnReq, not ZoneLoad
5667 : // either way, it seems these two should be using the same parameters.
5668 0 : SetOnOffMassFlowRate(state, FurnaceNum, AirLoopNum, OnOffAirFlowRatio, fanOp, ZoneLoad, MoistureLoad, PartLoadRatio);
5669 : }
5670 : }
5671 :
5672 : // AirflowNetwork global variable
5673 6243009 : if (state.afn->distribution_simulated) {
5674 214495 : state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).AFNLoopHeatingCoilMaxRTF = 0.0;
5675 : }
5676 6243009 : }
5677 :
5678 7065647 : void SetOnOffMassFlowRate(EnergyPlusData &state,
5679 : int const FurnaceNum, // index to furnace
5680 : [[maybe_unused]] int const AirLoopNum, // index to air loop !unused1208
5681 : Real64 &OnOffAirFlowRatio, // ratio of coil on to coil off air flow rate
5682 : HVAC::FanOp const fanOp, // fan operating mode
5683 : [[maybe_unused]] Real64 const ZoneLoad, // sensible load to be met (W) !unused1208
5684 : Real64 const MoistureLoad, // moisture load to be met (W)
5685 : Real64 const PartLoadRatio // coil part-load ratio
5686 : )
5687 : {
5688 :
5689 : // SUBROUTINE INFORMATION:
5690 : // AUTHOR Richard Raustad
5691 : // DATE WRITTEN Sep 2008
5692 :
5693 : // PURPOSE OF THIS SUBROUTINE:
5694 : // This subroutine is for initializations of the Furnace Components.
5695 :
5696 : // METHODOLOGY EMPLOYED:
5697 : // The HeatCool furnace/unitarysystem and air-to-air heat pump may have alternate air flow rates
5698 : // in cooling, heating, and when no cooling or heating is needed. Set up the coil (comp) ON and OFF
5699 : // air flow rates. Use these flow rates during the Calc routines to set the average mass flow rates
5700 : // based on PLR.
5701 :
5702 7065647 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
5703 : // Check for heat only furnace
5704 7065647 : if (thisFurnace.type != HVAC::UnitarySysType::Furnace_HeatOnly && thisFurnace.type != HVAC::UnitarySysType::Unitary_HeatOnly) {
5705 :
5706 : // Set the system mass flow rates
5707 7041203 : if (fanOp == HVAC::FanOp::Continuous) {
5708 : // Set the compressor or coil ON mass flow rate
5709 : // constant fan mode
5710 4206673 : if (state.dataFurnaces->HeatingLoad) {
5711 : // IF a heating and moisture load exists, operate at the cooling mass flow rate ELSE operate at the heating flow rate
5712 466631 : if (MoistureLoad < 0.0 && thisFurnace.Humidistat &&
5713 7419 : thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat) {
5714 6429 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxCoolAirMassFlow;
5715 6429 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.CoolingSpeedRatio;
5716 : } else {
5717 460202 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxHeatAirMassFlow;
5718 460202 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.HeatingSpeedRatio;
5719 : }
5720 466631 : thisFurnace.LastMode = Furnaces::ModeOfOperation::HeatingMode;
5721 : // IF a cooling load exists, operate at the cooling mass flow rate
5722 3740042 : } else if (state.dataFurnaces->CoolingLoad) {
5723 2201364 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxCoolAirMassFlow;
5724 2201364 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.CoolingSpeedRatio;
5725 2201364 : thisFurnace.LastMode = Furnaces::ModeOfOperation::CoolingMode;
5726 : // If no load exists, set the compressor on mass flow rate.
5727 : // Set equal the mass flow rate when no heating or cooling is needed if no moisture load exists.
5728 : // If the user has set the off mass flow rate to 0, set according to the last operating mode.
5729 : } else {
5730 1538678 : if (MoistureLoad < 0.0 && thisFurnace.Humidistat &&
5731 513049 : thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat) {
5732 482878 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxCoolAirMassFlow;
5733 482878 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.CoolingSpeedRatio;
5734 : } else {
5735 1055800 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxNoCoolHeatAirMassFlow;
5736 1055800 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.HeatingSpeedRatio;
5737 : // User may have entered a 0 for MaxNoCoolHeatAirMassFlow
5738 1055800 : if (state.dataFurnaces->CompOnMassFlow == 0.0) {
5739 33239 : if (thisFurnace.LastMode == Furnaces::ModeOfOperation::HeatingMode) {
5740 3390 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxHeatAirMassFlow;
5741 3390 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.HeatingSpeedRatio;
5742 : } else {
5743 29849 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxCoolAirMassFlow;
5744 29849 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.CoolingSpeedRatio;
5745 : }
5746 : }
5747 : }
5748 : }
5749 :
5750 : // Set the compressor or coil OFF mass flow rate based on LOGICAL flag
5751 : // UseCompressorOnFlow is used when the user does not enter a value for no cooling or heating flow rate
5752 4206673 : if (thisFurnace.AirFlowControl == AirFlowControlConstFan::UseCompressorOnFlow) {
5753 1056944 : if (thisFurnace.LastMode == Furnaces::ModeOfOperation::HeatingMode) {
5754 152149 : if (MoistureLoad < 0.0 && thisFurnace.Humidistat &&
5755 4344 : thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat) {
5756 0 : state.dataFurnaces->CompOffMassFlow = thisFurnace.MaxCoolAirMassFlow;
5757 0 : state.dataFurnaces->CompOffFlowRatio = thisFurnace.CoolingSpeedRatio;
5758 : } else {
5759 152149 : state.dataFurnaces->CompOffMassFlow = thisFurnace.MaxHeatAirMassFlow;
5760 152149 : state.dataFurnaces->CompOffFlowRatio = thisFurnace.HeatingSpeedRatio;
5761 : }
5762 : } else {
5763 904795 : state.dataFurnaces->CompOffMassFlow = thisFurnace.MaxCoolAirMassFlow;
5764 904795 : state.dataFurnaces->CompOffFlowRatio = thisFurnace.CoolingSpeedRatio;
5765 : }
5766 : // ELSE use the user specified value
5767 : } else {
5768 3149729 : state.dataFurnaces->CompOffMassFlow = thisFurnace.MaxNoCoolHeatAirMassFlow;
5769 3149729 : state.dataFurnaces->CompOffFlowRatio = thisFurnace.NoHeatCoolSpeedRatio;
5770 : }
5771 : } else {
5772 : // cycling fan mode
5773 4168116 : if (state.dataFurnaces->HeatingLoad ||
5774 1333586 : (thisFurnace.Humidistat && MoistureLoad < 0.0 && thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat)) {
5775 :
5776 1502100 : if (thisFurnace.Humidistat && MoistureLoad < 0.0 &&
5777 4584 : thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat) {
5778 1160 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxCoolAirMassFlow;
5779 1160 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.CoolingSpeedRatio;
5780 1160 : thisFurnace.LastMode = Furnaces::ModeOfOperation::CoolingMode;
5781 : } else {
5782 1500940 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxHeatAirMassFlow;
5783 1500940 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.HeatingSpeedRatio;
5784 1500940 : thisFurnace.LastMode = Furnaces::ModeOfOperation::HeatingMode;
5785 : }
5786 1332430 : } else if (state.dataFurnaces->CoolingLoad) {
5787 1126036 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxCoolAirMassFlow;
5788 1126036 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.CoolingSpeedRatio;
5789 : } else {
5790 206394 : state.dataFurnaces->CompOnMassFlow = 0.0;
5791 206394 : state.dataFurnaces->CompOnFlowRatio = 0.0;
5792 : }
5793 2834530 : state.dataFurnaces->CompOffMassFlow = 0.0;
5794 2834530 : state.dataFurnaces->CompOffFlowRatio = 0.0;
5795 : }
5796 : } else { // Is a HeatOnly furnace
5797 :
5798 24444 : state.dataFurnaces->CompOnMassFlow = thisFurnace.DesignMassFlowRate;
5799 24444 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.HeatingSpeedRatio;
5800 24444 : if (fanOp == HVAC::FanOp::Continuous) {
5801 0 : state.dataFurnaces->CompOffMassFlow = thisFurnace.MaxNoCoolHeatAirMassFlow;
5802 0 : state.dataFurnaces->CompOffFlowRatio = thisFurnace.HeatingSpeedRatio;
5803 : } else {
5804 24444 : state.dataFurnaces->CompOffMassFlow = 0.0;
5805 24444 : state.dataFurnaces->CompOffFlowRatio = 0.0;
5806 : }
5807 :
5808 : } // End check for heat only furnace or water-to-air heat pump
5809 :
5810 : // Set the system mass flow rates
5811 7065647 : SetAverageAirFlow(state, FurnaceNum, PartLoadRatio, OnOffAirFlowRatio);
5812 7065647 : }
5813 :
5814 359 : void SizeFurnace(EnergyPlusData &state, int const FurnaceNum, bool const FirstHVACIteration)
5815 : {
5816 :
5817 : // SUBROUTINE INFORMATION:
5818 : // AUTHOR Fred Buhl
5819 : // DATE WRITTEN January 2002
5820 : // MODIFIED Bereket Nigusse, May 2010, removed the autosize option for the input field supply air
5821 : // flow fraction through controlled zone.
5822 : // Bo Shen, March 2012, size the air flow rates at individual speed levels for VS WSHP
5823 : // Bo Shen, ORNL, July 2012 - added variable-speed air source heat pump cooling and heating coils, using curve-fits
5824 :
5825 : // PURPOSE OF THIS SUBROUTINE:
5826 : // This subroutine is for sizing Furnace Components for which nominal cpacities
5827 : // and flow rates have not been specified in the input
5828 :
5829 : // METHODOLOGY EMPLOYED:
5830 : // Obtains heating capacities and flow rates from the zone or system sizing arrays.
5831 : // NOTE: In UNITARYSYSTEM:HEATPUMP:AIRTOAIR we are sizing the heating capacity to be
5832 : // equal to the cooling capacity. Thus the cooling and
5833 : // and heating capacities of a DX heat pump system will be identical. In real life the ARI
5834 : // heating and cooling capacities are close but not identical.
5835 :
5836 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
5837 : int Iter; // iteration count
5838 : Real64 MulSpeedFlowScale; // variable speed air flow scaling factor
5839 : int IHPCoilIndex; // refer to cooling or heating coil in IHP
5840 359 : Real64 dummy(0.0);
5841 : bool anyRan;
5842 359 : EMSManager::ManageEMS(state, EMSManager::EMSCallFrom::UnitarySystemSizing, anyRan, ObjexxFCL::Optional_int_const()); // calling point
5843 :
5844 359 : state.dataSize->DXCoolCap = 0.0;
5845 359 : state.dataSize->UnitaryHeatCap = 0.0;
5846 359 : state.dataSize->SuppHeatCap = 0.0;
5847 359 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
5848 :
5849 359 : state.dataAirSystemsData->PrimaryAirSystems(state.dataSize->CurSysNum).supFanNum = thisFurnace.FanIndex;
5850 359 : state.dataAirSystemsData->PrimaryAirSystems(state.dataSize->CurSysNum).supFanType = thisFurnace.fanType;
5851 359 : state.dataSize->DataFanType = thisFurnace.fanType;
5852 359 : state.dataSize->DataFanIndex = thisFurnace.FanIndex;
5853 :
5854 359 : state.dataAirSystemsData->PrimaryAirSystems(state.dataSize->CurSysNum).supFanPlace = thisFurnace.fanPlace;
5855 :
5856 359 : if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingSingleSpeed) {
5857 206 : DXCoils::SimDXCoil(state, BlankString, HVAC::CompressorOp::On, true, thisFurnace.CoolingCoilIndex, HVAC::FanOp::Cycling, 0.0);
5858 153 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) {
5859 3 : int HXCC_Index = thisFurnace.CoolingCoilIndex;
5860 3 : int childCCType_Num = state.dataHVACAssistedCC->HXAssistedCoil(HXCC_Index).CoolingCoilType_Num;
5861 3 : if (childCCType_Num == HVAC::CoilDX_Cooling) {
5862 1 : int childCCIndex = state.dataHVACAssistedCC->HXAssistedCoil(HXCC_Index).CoolingCoilIndex;
5863 1 : if (childCCIndex < 0) {
5864 0 : ShowContinueError(state, "Occurs in sizing HeatExchangerAssistedCoolingCoil.");
5865 : }
5866 1 : auto &newCoil = state.dataCoilCooingDX->coilCoolingDXs[childCCIndex];
5867 1 : newCoil.size(state);
5868 : }
5869 9 : HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(
5870 6 : state, BlankString, true, HVAC::CompressorOp::On, 0.0, thisFurnace.CoolingCoilIndex, HVAC::FanOp::Cycling, false, 1.0, false);
5871 150 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingWaterToAirHPSimple) {
5872 111 : WaterToAirHeatPumpSimple::SimWatertoAirHPSimple(state,
5873 : BlankString,
5874 111 : thisFurnace.CoolingCoilIndex,
5875 : thisFurnace.CoolingCoilSensDemand,
5876 : thisFurnace.CoolingCoilLatentDemand,
5877 : HVAC::FanOp::Invalid, // Using invalid to mean off?
5878 : HVAC::CompressorOp::Off,
5879 : 0.0,
5880 : FirstHVACIteration); // CoolPartLoadRatio
5881 111 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPSimple) {
5882 111 : WaterToAirHeatPumpSimple::SimWatertoAirHPSimple(state,
5883 : BlankString,
5884 111 : thisFurnace.HeatingCoilIndex,
5885 : thisFurnace.HeatingCoilSensDemand,
5886 : dummy,
5887 : HVAC::FanOp::Invalid, // using Invalid to mean off?
5888 : HVAC::CompressorOp::Off,
5889 : 0.0,
5890 : FirstHVACIteration);
5891 : }
5892 39 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingWaterToAirHPVSEquationFit ||
5893 25 : thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) {
5894 21 : if (thisFurnace.bIsIHP) {
5895 1 : IntegratedHeatPump::SizeIHP(state, thisFurnace.CoolingCoilIndex);
5896 1 : IHPCoilIndex = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SCCoilIndex;
5897 1 : thisFurnace.NumOfSpeedCooling = state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).NumOfSpeeds;
5898 1 : MulSpeedFlowScale = state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).RatedAirVolFlowRate /
5899 1 : state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex)
5900 1 : .MSRatedAirVolFlowRate(state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).NormSpedLevel);
5901 1 : state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).CoolVolFlowScale = MulSpeedFlowScale;
5902 : } else {
5903 20 : VariableSpeedCoils::SimVariableSpeedCoils(state,
5904 : BlankString,
5905 20 : thisFurnace.CoolingCoilIndex,
5906 : HVAC::FanOp::Invalid, // USing Invalid for off?
5907 : HVAC::CompressorOp::Off,
5908 : 0.0,
5909 : 1,
5910 : 0.0,
5911 : 0.0,
5912 : 0.0,
5913 : 0.0); // conduct the sizing operation in the VS WSHP
5914 20 : thisFurnace.NumOfSpeedCooling = state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.CoolingCoilIndex).NumOfSpeeds;
5915 20 : MulSpeedFlowScale =
5916 20 : state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.CoolingCoilIndex).RatedAirVolFlowRate /
5917 20 : state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.CoolingCoilIndex)
5918 20 : .MSRatedAirVolFlowRate(state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.CoolingCoilIndex).NormSpedLevel);
5919 20 : IHPCoilIndex = thisFurnace.CoolingCoilIndex;
5920 : }
5921 :
5922 231 : for (Iter = 1; Iter <= thisFurnace.NumOfSpeedCooling; ++Iter) {
5923 420 : thisFurnace.CoolVolumeFlowRate(Iter) =
5924 210 : state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).MSRatedAirVolFlowRate(Iter) * MulSpeedFlowScale;
5925 420 : thisFurnace.CoolMassFlowRate(Iter) =
5926 210 : state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).MSRatedAirMassFlowRate(Iter) * MulSpeedFlowScale;
5927 210 : thisFurnace.MSCoolingSpeedRatio(Iter) =
5928 210 : state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).MSRatedAirVolFlowRate(Iter) /
5929 210 : state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).MSRatedAirVolFlowRate(thisFurnace.NumOfSpeedCooling);
5930 : }
5931 :
5932 21 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPVSEquationFit ||
5933 7 : thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed) {
5934 :
5935 17 : if (thisFurnace.bIsIHP) {
5936 1 : IntegratedHeatPump::SizeIHP(state, thisFurnace.CoolingCoilIndex);
5937 1 : IHPCoilIndex = state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).SHCoilIndex;
5938 1 : thisFurnace.NumOfSpeedHeating = state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).NumOfSpeeds;
5939 1 : MulSpeedFlowScale = state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).RatedAirVolFlowRate /
5940 1 : state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex)
5941 1 : .MSRatedAirVolFlowRate(state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).NormSpedLevel);
5942 1 : state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).HeatVolFlowScale = MulSpeedFlowScale;
5943 : } else {
5944 16 : VariableSpeedCoils::SimVariableSpeedCoils(state,
5945 : BlankString,
5946 16 : thisFurnace.HeatingCoilIndex,
5947 : HVAC::FanOp::Invalid, // Invalid for off?
5948 : HVAC::CompressorOp::Off,
5949 : 0.0,
5950 : 1,
5951 : 0.0,
5952 : 0.0,
5953 : 0.0,
5954 : 0.0); // conduct the sizing operation in the VS WSHP
5955 16 : thisFurnace.NumOfSpeedHeating = state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.HeatingCoilIndex).NumOfSpeeds;
5956 16 : MulSpeedFlowScale =
5957 16 : state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.HeatingCoilIndex).RatedAirVolFlowRate /
5958 16 : state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.HeatingCoilIndex)
5959 16 : .MSRatedAirVolFlowRate(state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.HeatingCoilIndex).NormSpedLevel);
5960 16 : IHPCoilIndex = thisFurnace.HeatingCoilIndex;
5961 : }
5962 :
5963 187 : for (Iter = 1; Iter <= thisFurnace.NumOfSpeedHeating; ++Iter) {
5964 340 : thisFurnace.HeatVolumeFlowRate(Iter) =
5965 170 : state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).MSRatedAirVolFlowRate(Iter) * MulSpeedFlowScale;
5966 340 : thisFurnace.HeatMassFlowRate(Iter) =
5967 170 : state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).MSRatedAirMassFlowRate(Iter) * MulSpeedFlowScale;
5968 170 : thisFurnace.MSHeatingSpeedRatio(Iter) =
5969 170 : state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).MSRatedAirVolFlowRate(Iter) /
5970 170 : state.dataVariableSpeedCoils->VarSpeedCoil(IHPCoilIndex).MSRatedAirVolFlowRate(thisFurnace.NumOfSpeedHeating);
5971 : }
5972 : }
5973 :
5974 21 : if (thisFurnace.NumOfSpeedHeating > 0) {
5975 17 : thisFurnace.IdleMassFlowRate = min(thisFurnace.HeatMassFlowRate(1), thisFurnace.CoolMassFlowRate(1));
5976 17 : thisFurnace.IdleSpeedRatio = min(thisFurnace.MSHeatingSpeedRatio(1), thisFurnace.MSCoolingSpeedRatio(1));
5977 17 : thisFurnace.IdleVolumeAirRate = min(thisFurnace.HeatVolumeFlowRate(1), thisFurnace.CoolVolumeFlowRate(1));
5978 : } else {
5979 4 : thisFurnace.IdleMassFlowRate = thisFurnace.CoolMassFlowRate(1);
5980 4 : thisFurnace.IdleSpeedRatio = thisFurnace.MSCoolingSpeedRatio(1);
5981 4 : thisFurnace.IdleVolumeAirRate = thisFurnace.CoolVolumeFlowRate(1);
5982 : }
5983 :
5984 21 : if (thisFurnace.fanOp == HVAC::FanOp::Continuous) {
5985 0 : thisFurnace.MaxNoCoolHeatAirVolFlow = thisFurnace.IdleVolumeAirRate;
5986 0 : thisFurnace.MaxNoCoolHeatAirMassFlow = thisFurnace.IdleMassFlowRate;
5987 0 : thisFurnace.NoHeatCoolSpeedRatio = thisFurnace.IdleSpeedRatio;
5988 : }
5989 : }
5990 :
5991 359 : if (thisFurnace.DesignFanVolFlowRate == DataSizing::AutoSize) {
5992 :
5993 266 : if (state.dataSize->CurSysNum > 0) {
5994 :
5995 266 : CheckSysSizing(state, HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name);
5996 266 : if (state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesMainVolFlow >= HVAC::SmallAirVolFlow) {
5997 266 : thisFurnace.DesignFanVolFlowRate = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesMainVolFlow;
5998 : } else {
5999 0 : thisFurnace.DesignFanVolFlowRate = 0.0;
6000 : }
6001 :
6002 266 : if (thisFurnace.DesignFanVolFlowRateEMSOverrideOn) {
6003 0 : thisFurnace.DesignFanVolFlowRate = thisFurnace.DesignFanVolFlowRateEMSOverrideValue;
6004 : }
6005 :
6006 532 : BaseSizer::reportSizerOutput(state,
6007 266 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6008 : thisFurnace.Name,
6009 : "Supply Air Flow Rate [m3/s]",
6010 : thisFurnace.DesignFanVolFlowRate);
6011 : }
6012 : }
6013 :
6014 359 : if (thisFurnace.MaxHeatAirVolFlow == DataSizing::AutoSize) {
6015 :
6016 266 : if (state.dataSize->CurSysNum > 0) {
6017 :
6018 266 : CheckSysSizing(state, HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name);
6019 266 : if (state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesMainVolFlow >= HVAC::SmallAirVolFlow) {
6020 266 : thisFurnace.MaxHeatAirVolFlow = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesMainVolFlow;
6021 : } else {
6022 0 : thisFurnace.MaxHeatAirVolFlow = 0.0;
6023 : }
6024 :
6025 266 : if (thisFurnace.MaxHeatAirVolFlowEMSOverrideOn) {
6026 0 : thisFurnace.MaxHeatAirVolFlow = thisFurnace.MaxHeatAirVolFlowEMSOverrideValue;
6027 : }
6028 532 : BaseSizer::reportSizerOutput(state,
6029 266 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6030 : thisFurnace.Name,
6031 : "Supply Air Flow Rate During Heating Operation [m3/s]",
6032 : thisFurnace.MaxHeatAirVolFlow);
6033 : }
6034 : }
6035 :
6036 359 : if (thisFurnace.MaxCoolAirVolFlow == DataSizing::AutoSize) {
6037 :
6038 266 : if (state.dataSize->CurSysNum > 0) {
6039 :
6040 266 : CheckSysSizing(state, HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name);
6041 266 : if (state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesMainVolFlow >= HVAC::SmallAirVolFlow) {
6042 266 : thisFurnace.MaxCoolAirVolFlow = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesMainVolFlow;
6043 : } else {
6044 0 : thisFurnace.MaxCoolAirVolFlow = 0.0;
6045 : }
6046 :
6047 266 : if (thisFurnace.MaxCoolAirVolFlowEMSOverrideOn) {
6048 0 : thisFurnace.MaxCoolAirVolFlow = thisFurnace.MaxCoolAirVolFlowEMSOverrideValue;
6049 : }
6050 :
6051 532 : BaseSizer::reportSizerOutput(state,
6052 266 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6053 : thisFurnace.Name,
6054 : "Supply Air Flow Rate During Cooling Operation [m3/s]",
6055 : thisFurnace.MaxCoolAirVolFlow);
6056 : }
6057 : }
6058 :
6059 359 : if (thisFurnace.MaxNoCoolHeatAirVolFlow == DataSizing::AutoSize) {
6060 :
6061 261 : if (state.dataSize->CurSysNum > 0) {
6062 :
6063 261 : CheckSysSizing(state, HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name);
6064 261 : if (state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesMainVolFlow >= HVAC::SmallAirVolFlow) {
6065 261 : thisFurnace.MaxNoCoolHeatAirVolFlow = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesMainVolFlow;
6066 : } else {
6067 0 : thisFurnace.MaxNoCoolHeatAirVolFlow = 0.0;
6068 : }
6069 :
6070 261 : if (thisFurnace.MaxNoCoolHeatAirVolFlowEMSOverrideOn) {
6071 0 : thisFurnace.MaxNoCoolHeatAirVolFlow = thisFurnace.MaxNoCoolHeatAirVolFlowEMSOverrideValue;
6072 : }
6073 :
6074 522 : BaseSizer::reportSizerOutput(state,
6075 261 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6076 : thisFurnace.Name,
6077 : "Supply Air Flow Rate When No Cooling or Heating is Needed [m3/s]",
6078 : thisFurnace.MaxNoCoolHeatAirVolFlow);
6079 : }
6080 : }
6081 :
6082 359 : if (thisFurnace.DesignHeatingCapacity == DataSizing::AutoSize) {
6083 :
6084 266 : if (state.dataSize->CurSysNum > 0) {
6085 :
6086 266 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir ||
6087 252 : thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir) {
6088 :
6089 110 : CheckSysSizing(state, HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name);
6090 :
6091 110 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingWaterToAirHPSimple) {
6092 96 : thisFurnace.DesignHeatingCapacity =
6093 96 : state.dataWaterToAirHeatPumpSimple->SimpleWatertoAirHP(thisFurnace.HeatingCoilIndex).RatedCapHeat;
6094 : } else {
6095 14 : thisFurnace.DesignHeatingCapacity = state.dataSize->DXCoolCap;
6096 : }
6097 :
6098 : } else {
6099 :
6100 156 : CheckSysSizing(state, HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name);
6101 :
6102 156 : thisFurnace.DesignHeatingCapacity = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).HeatCap;
6103 : }
6104 :
6105 266 : if (thisFurnace.DesignHeatingCapacity < HVAC::SmallLoad) {
6106 0 : thisFurnace.DesignHeatingCapacity = 0.0;
6107 : }
6108 :
6109 532 : BaseSizer::reportSizerOutput(state,
6110 266 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6111 : thisFurnace.Name,
6112 : "Nominal Heating Capacity [W]",
6113 : thisFurnace.DesignHeatingCapacity);
6114 : }
6115 : }
6116 :
6117 359 : if (thisFurnace.DesignCoolingCapacity == DataSizing::AutoSize) {
6118 :
6119 266 : if (state.dataSize->CurSysNum > 0) {
6120 :
6121 266 : CheckSysSizing(state, HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name);
6122 266 : if (state.dataSize->DXCoolCap >= HVAC::SmallLoad) {
6123 266 : thisFurnace.DesignCoolingCapacity = state.dataSize->DXCoolCap;
6124 : } else {
6125 0 : thisFurnace.DesignCoolingCapacity = 0.0;
6126 : }
6127 532 : BaseSizer::reportSizerOutput(state,
6128 266 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6129 : thisFurnace.Name,
6130 : "Nominal Cooling Capacity [W]",
6131 : thisFurnace.DesignCoolingCapacity);
6132 : }
6133 : }
6134 :
6135 359 : if (thisFurnace.DesignMaxOutletTemp == DataSizing::AutoSize) {
6136 :
6137 83 : if (state.dataSize->CurSysNum > 0) {
6138 :
6139 83 : CheckSysSizing(state, HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name);
6140 83 : thisFurnace.DesignMaxOutletTemp = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).HeatSupTemp;
6141 166 : BaseSizer::reportSizerOutput(state,
6142 83 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6143 : thisFurnace.Name,
6144 : "Maximum Supply Air Temperature from Supplemental Heater [C]",
6145 : thisFurnace.DesignMaxOutletTemp);
6146 : }
6147 : }
6148 :
6149 359 : if (thisFurnace.DesignSuppHeatingCapacity == DataSizing::AutoSize) {
6150 :
6151 110 : if (state.dataSize->CurSysNum > 0) {
6152 :
6153 110 : CheckSysSizing(state, HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name);
6154 110 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir ||
6155 96 : thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir) {
6156 : // set the supplemental heating capacity to the actual heating load
6157 110 : thisFurnace.DesignSuppHeatingCapacity = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).HeatCap;
6158 : // if reheat needed for humidity control, make sure supplemental heating is at least as big
6159 : // as the cooling capacity
6160 110 : if (thisFurnace.Humidistat && thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat) {
6161 0 : thisFurnace.DesignSuppHeatingCapacity = max(thisFurnace.DesignSuppHeatingCapacity, thisFurnace.DesignCoolingCapacity);
6162 0 : if (thisFurnace.DesignSuppHeatingCapacity < HVAC::SmallLoad) {
6163 0 : thisFurnace.DesignSuppHeatingCapacity = 0.0;
6164 : }
6165 : }
6166 :
6167 : } else {
6168 :
6169 0 : if (thisFurnace.Humidistat && thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat) {
6170 0 : thisFurnace.DesignSuppHeatingCapacity = thisFurnace.DesignCoolingCapacity;
6171 : } else {
6172 0 : thisFurnace.DesignSuppHeatingCapacity = 0.0;
6173 : }
6174 : }
6175 :
6176 220 : BaseSizer::reportSizerOutput(state,
6177 110 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6178 : thisFurnace.Name,
6179 : "Supplemental Heating Coil Nominal Capacity [W]",
6180 : thisFurnace.DesignSuppHeatingCapacity);
6181 : }
6182 : }
6183 :
6184 359 : state.dataSize->UnitaryHeatCap = thisFurnace.DesignHeatingCapacity;
6185 359 : state.dataSize->SuppHeatCap = thisFurnace.DesignSuppHeatingCapacity;
6186 359 : }
6187 :
6188 : // End Initialization Section of the Module
6189 : //******************************************************************************
6190 :
6191 : // Beginning of Update subroutines for the Furnace Module
6192 : // *****************************************************************************
6193 :
6194 24444 : void CalcNewZoneHeatOnlyFlowRates(EnergyPlusData &state,
6195 : int const FurnaceNum, // Index to furnace
6196 : bool const FirstHVACIteration, // Iteration flag
6197 : Real64 const ZoneLoad, // load to be met by furnace (W)
6198 : Real64 &HeatCoilLoad, // actual load passed to heating coil (W)
6199 : Real64 &OnOffAirFlowRatio // ratio of coil on to coil off air flow rate
6200 : )
6201 : {
6202 : // SUBROUTINE INFORMATION:
6203 : // AUTHOR Richard Liesen
6204 : // DATE WRITTEN Feb 2001
6205 : // MODIFIED Don Shirey and R. Raustad, Mar 2001 & Mar 2003
6206 :
6207 : // PURPOSE OF THIS SUBROUTINE:
6208 : // This subroutine updates the coil outlet nodes by simulating a heat-only
6209 : // furnace or unitary system.
6210 :
6211 : // METHODOLOGY EMPLOYED:
6212 : // Determine the operating PLR to meet the zone sensible load.
6213 :
6214 : // SUBROUTINE PARAMETER DEFINITIONS:
6215 24444 : int constexpr MaxIter(15); // maximum number of iterations
6216 24444 : Real64 constexpr MinPLR(0.0); // minimum part load ratio allowed
6217 :
6218 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
6219 24444 : Real64 Error(1.0);
6220 : Real64 SystemSensibleLoad; // Sensible load to be met by furnace (W)
6221 : Real64 FullSensibleOutput; // Full sensible output of furnace (W)
6222 : Real64 FullLatentOutput; // Full latent output of furnace = 0 (W)
6223 : Real64 NoSensibleOutput; // Sensible output of furnace with no heating allowed (W)
6224 : Real64 NoLatentOutput; // Latent output of furnace = 0 (W)
6225 : Real64 PartLoadRatio; // Part load ratio of furnace
6226 : Real64 HeatErrorToler; // Error tolerance in heating mode
6227 : Real64 IterRelax; // Relaxation factor for iterations
6228 : Real64 ActualSensibleOutput; // Actual furnace sensible capacity
6229 : Real64 ActualLatentOutput; // Actual furnace latent capacity = 0
6230 : Real64 deltaT; // Heater outlet temp minus design heater outlet temp
6231 :
6232 24444 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
6233 : // Retrieve the load on the controlled zone
6234 24444 : auto &furnaceInNode = state.dataLoopNodes->Node(thisFurnace.FurnaceInletNodeNum);
6235 24444 : auto const &furnaceOutNode = state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum);
6236 24444 : int ControlZoneNode = thisFurnace.NodeNumOfControlledZone;
6237 24444 : HVAC::FanOp fanOp = thisFurnace.fanOp; // fan operating mode
6238 24444 : thisFurnace.MdotFurnace = thisFurnace.DesignMassFlowRate;
6239 24444 : thisFurnace.CoolPartLoadRatio = 0.0;
6240 :
6241 : // Calculate the Cp Air of zone
6242 24444 : Real64 cpair = Psychrometrics::PsyCpAirFnW(state.dataLoopNodes->Node(ControlZoneNode).HumRat);
6243 :
6244 24444 : if (FirstHVACIteration) {
6245 10592 : HeatCoilLoad = ZoneLoad;
6246 10592 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
6247 : } else {
6248 : // If Furnace runs then set HeatCoilLoad on Heating Coil and the Mass Flow
6249 26034 : if ((ScheduleManager::GetCurrentScheduleValue(state, thisFurnace.SchedPtr) > 0.0) && (furnaceInNode.MassFlowRate > 0.0) &&
6250 12182 : (state.dataFurnaces->HeatingLoad)) {
6251 :
6252 5599 : furnaceInNode.MassFlowRate = thisFurnace.MdotFurnace;
6253 5599 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity;
6254 5599 : SystemSensibleLoad = ZoneLoad;
6255 :
6256 : // Get no load result
6257 5599 : if (fanOp == HVAC::FanOp::Cycling) {
6258 5599 : furnaceInNode.MassFlowRate = 0.0;
6259 : }
6260 5599 : if (fanOp == HVAC::FanOp::Continuous) {
6261 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0; // The on/off fan will not cycle, so set part-load fraction = 1
6262 : }
6263 :
6264 : // Set the inlet mass flow rate based on user specified coil OFF flow rate
6265 5599 : PartLoadRatio = 0.0;
6266 5599 : SetAverageAirFlow(state, FurnaceNum, PartLoadRatio, OnOffAirFlowRatio);
6267 :
6268 5599 : CalcFurnaceOutput(state,
6269 : FurnaceNum,
6270 : FirstHVACIteration,
6271 : fanOp,
6272 : HVAC::CompressorOp::On,
6273 : 0.0,
6274 : 0.0,
6275 : 0.0,
6276 : 0.0,
6277 : NoSensibleOutput,
6278 : NoLatentOutput,
6279 : OnOffAirFlowRatio,
6280 : false);
6281 :
6282 5599 : furnaceInNode.MassFlowRate = thisFurnace.MdotFurnace;
6283 :
6284 : // Set fan part-load fraction equal to 1 while getting full load result
6285 5599 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
6286 5599 : OnOffAirFlowRatio = 1.0;
6287 :
6288 : // Get full load result
6289 5599 : CalcFurnaceOutput(state,
6290 : FurnaceNum,
6291 : FirstHVACIteration,
6292 : fanOp,
6293 : HVAC::CompressorOp::On,
6294 : 0.0,
6295 : 1.0,
6296 : HeatCoilLoad,
6297 : 0.0,
6298 : FullSensibleOutput,
6299 : FullLatentOutput,
6300 : OnOffAirFlowRatio,
6301 : false);
6302 :
6303 : // Since we are heating, we expect FullSensibleOutput to be > 0 and FullSensibleOutput > NoSensibleOutput
6304 : // Check that this is the case; if not set PartLoadRatio = 0.0d0 (off) and return
6305 :
6306 5599 : if (FullSensibleOutput > NoSensibleOutput) {
6307 : PartLoadRatio =
6308 5599 : max(MinPLR, min(1.0, std::abs(SystemSensibleLoad - NoSensibleOutput) / std::abs(FullSensibleOutput - NoSensibleOutput)));
6309 5599 : if (fanOp == HVAC::FanOp::Cycling) {
6310 5599 : furnaceInNode.MassFlowRate = thisFurnace.MdotFurnace * PartLoadRatio;
6311 5599 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity * PartLoadRatio;
6312 : } else { // FanOp::Continuous
6313 0 : if (furnaceOutNode.Temp > thisFurnace.DesignMaxOutletTemp) {
6314 0 : deltaT = furnaceOutNode.Temp - thisFurnace.DesignMaxOutletTemp;
6315 0 : if (HeatCoilLoad > thisFurnace.DesignHeatingCapacity) HeatCoilLoad = thisFurnace.DesignHeatingCapacity;
6316 0 : HeatCoilLoad -= furnaceInNode.MassFlowRate * cpair * deltaT;
6317 : } else {
6318 0 : HeatCoilLoad = SystemSensibleLoad - NoSensibleOutput;
6319 : }
6320 : }
6321 :
6322 : // Calculate the part load ratio through iteration
6323 5599 : HeatErrorToler = thisFurnace.HeatingConvergenceTolerance; // Error tolerance for convergence from input deck
6324 5599 : Error = 1.0; // initialize error value for comparison against tolerance
6325 5599 : state.dataFurnaces->Iter = 0; // initialize iteration counter
6326 5599 : IterRelax = 0.9; // relaxation factor for iterations
6327 6589 : while (state.dataFurnaces->Iter <= MaxIter) {
6328 :
6329 6589 : if (fanOp == HVAC::FanOp::Cycling) furnaceInNode.MassFlowRate = thisFurnace.MdotFurnace * PartLoadRatio;
6330 6589 : CalcFurnaceOutput(state,
6331 : FurnaceNum,
6332 : FirstHVACIteration,
6333 : fanOp,
6334 : HVAC::CompressorOp::On,
6335 : 0.0,
6336 : PartLoadRatio,
6337 : HeatCoilLoad,
6338 : 0.0,
6339 : ActualSensibleOutput,
6340 : ActualLatentOutput,
6341 : OnOffAirFlowRatio,
6342 : false);
6343 :
6344 6589 : if (SystemSensibleLoad != 0.0) Error = (SystemSensibleLoad - ActualSensibleOutput) / (SystemSensibleLoad);
6345 6589 : if (std::abs(Error) <= HeatErrorToler) break;
6346 1452 : PartLoadRatio = max(
6347 : MinPLR,
6348 : min(1.0,
6349 1452 : PartLoadRatio + IterRelax * (SystemSensibleLoad - ActualSensibleOutput) / (FullSensibleOutput - NoSensibleOutput)));
6350 :
6351 : // limit the heating coil outlet air temperature to DesignMaxOutletTemp
6352 1452 : if (furnaceOutNode.Temp > thisFurnace.DesignMaxOutletTemp) {
6353 0 : deltaT = furnaceOutNode.Temp - thisFurnace.DesignMaxOutletTemp;
6354 0 : if (HeatCoilLoad > thisFurnace.DesignHeatingCapacity) HeatCoilLoad = thisFurnace.DesignHeatingCapacity;
6355 0 : HeatCoilLoad -= furnaceInNode.MassFlowRate * cpair * deltaT;
6356 0 : CalcFurnaceOutput(state,
6357 : FurnaceNum,
6358 : FirstHVACIteration,
6359 : fanOp,
6360 : HVAC::CompressorOp::On,
6361 : 0.0,
6362 : PartLoadRatio,
6363 : HeatCoilLoad,
6364 : 0.0,
6365 : ActualSensibleOutput,
6366 : ActualLatentOutput,
6367 : OnOffAirFlowRatio,
6368 : false);
6369 :
6370 0 : if (SystemSensibleLoad != 0.0) Error = (SystemSensibleLoad - ActualSensibleOutput) / (SystemSensibleLoad);
6371 0 : PartLoadRatio = max(MinPLR,
6372 : min(1.0,
6373 0 : PartLoadRatio + IterRelax * (SystemSensibleLoad - ActualSensibleOutput) /
6374 0 : (FullSensibleOutput - NoSensibleOutput)));
6375 : } else {
6376 1452 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity * PartLoadRatio;
6377 : }
6378 :
6379 1452 : if (PartLoadRatio == MinPLR) break;
6380 1452 : if (PartLoadRatio == 1.0) break;
6381 990 : ++state.dataFurnaces->Iter;
6382 990 : if (state.dataFurnaces->Iter == 7) IterRelax = 0.7;
6383 990 : if (state.dataFurnaces->Iter == 15) IterRelax = 0.4;
6384 : }
6385 :
6386 5599 : if (state.dataFurnaces->Iter > MaxIter) {
6387 0 : if (thisFurnace.HeatingMaxIterIndex2 == 0) {
6388 0 : ShowWarningMessage(state,
6389 0 : format("{} \"{}\" -- Exceeded max heating iterations ({}) while adjusting furnace runtime.",
6390 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6391 0 : thisFurnace.Name,
6392 : MaxIter));
6393 0 : ShowContinueErrorTimeStamp(state, "");
6394 : }
6395 0 : ShowRecurringWarningErrorAtEnd(state,
6396 0 : format("{} \"{}\" -- Exceeded max heating iterations error continues...",
6397 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6398 0 : thisFurnace.Name),
6399 0 : thisFurnace.HeatingMaxIterIndex2);
6400 : }
6401 :
6402 : } else { // ELSE from IF(FullSensibleOutput.GT.NoSensibleOutput)THEN above
6403 : // Set part load ratio to 1 and run heater at design heating capacity
6404 0 : PartLoadRatio = 1.0;
6405 0 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity;
6406 : }
6407 : // Set the final results
6408 : // IF (fanOp .EQ. FanOp::Cycling) THEN
6409 : // Furnace(FurnaceNum)%MdotFurnace = Furnace(FurnaceNum)%MdotFurnace * PartLoadRatio
6410 : // END IF
6411 5599 : thisFurnace.MdotFurnace = furnaceInNode.MassFlowRate;
6412 :
6413 8253 : } else if ((ScheduleManager::GetCurrentScheduleValue(state, thisFurnace.SchedPtr) > 0.0) && (furnaceInNode.MassFlowRate > 0.0) &&
6414 : (fanOp == HVAC::FanOp::Continuous)) {
6415 0 : HeatCoilLoad = 0.0;
6416 : } else { // no heating and no flow
6417 8253 : thisFurnace.MdotFurnace = 0.0;
6418 8253 : HeatCoilLoad = 0.0;
6419 : } // End of the Scheduled Furnace If block
6420 :
6421 : } // End of the FirstHVACIteration control of the mass flow If block
6422 :
6423 : // Set the fan inlet node flow rates
6424 24444 : furnaceInNode.MassFlowRateMaxAvail = thisFurnace.MdotFurnace;
6425 24444 : furnaceInNode.MassFlowRate = thisFurnace.MdotFurnace;
6426 24444 : }
6427 :
6428 4597475 : void CalcNewZoneHeatCoolFlowRates(EnergyPlusData &state,
6429 : int const FurnaceNum,
6430 : bool const FirstHVACIteration,
6431 : HVAC::CompressorOp const compressorOp, // compressor operation flag (1=On, 0=Off)
6432 : Real64 const ZoneLoad, // the control zone load (watts)
6433 : Real64 const MoistureLoad, // the control zone latent load (watts)
6434 : Real64 &HeatCoilLoad, // Heating load to be met by heating coil ( excluding heat pump DX coil)
6435 : Real64 &ReheatCoilLoad, // Heating load to be met by reheat coil using hstat (excluding HP DX coil)
6436 : Real64 &OnOffAirFlowRatio, // Ratio of compressor ON air flow to AVERAGE air flow over time step
6437 : bool &HXUnitOn // flag to control HX based on zone moisture load
6438 : )
6439 : {
6440 : // SUBROUTINE INFORMATION:
6441 : // AUTHOR Richard Liesen
6442 : // DATE WRITTEN Feb 2001
6443 : // MODIFIED R. Raustad and D. Shirey, Feb/Mar/Sept/Oct/Dec 2001, Jan/Oct 2002
6444 : // RE-ENGINEERED R. Raustad, Feb. 2005 (added RegulaFalsi for iteration technique)
6445 :
6446 : // PURPOSE OF THIS SUBROUTINE:
6447 : // This subroutine updates the coil outlet nodes.
6448 :
6449 : // METHODOLOGY EMPLOYED:
6450 : // Determine the operating PLR to meet the zone sensible load. If a humidistat is specified, determine
6451 : // the operating PLR (greater of the sensible and latent PLR) to meet the zone SENSIBLE load
6452 : // (Multimode dehumidification control) or zone LATENT load (CoolReheat dehumidification control).
6453 : // For dehumidification control type COOLREHEAT, both a sensible and latent PLR may exist for a
6454 : // single time step (heating and dehumidificaiton can occur). For all other sytem types,
6455 : // only a single PLR is allowed for any given time step.
6456 : // Order of simulation depends on dehumidification control option as described below.
6457 : // Dehumidificaiton control options:
6458 : // Dehumidification Control NONE: Cooling performance is simulated first and then heating performance. If a HX
6459 : // assisted cooling coil is selected, the HX is always active.
6460 : // Dehumidification Control COOLREHEAT: Continuous Fan Operation:
6461 : // For cooling operation, the sensible and latent capacities are calculated to
6462 : // meet the thermostat setpoint. If a HX assisted cooling coil is selected,
6463 : // the HX is always active. If the latent load is not met by operating the
6464 : // system at the sensible PLR, a new PLR is calculated to meet the humidistat
6465 : // setpoint. The reheat coil load is then calculated to meet the HEATING
6466 : // setpoint temperature.
6467 : // Cycling Fan Operation:
6468 : // The heating part-load ratio is calculated first. Since the fan will be
6469 : // controlled at the higher of the heating or cooling PLR's, a ratio of the
6470 : // cooling to heating PLR is used to pass to the cooling coil (MAX=1). This allows
6471 : // the cooling coil to operate at the heating PLR when the heating PLR is
6472 : // higher than the cooling PLR. The sensible and latent capacities are then
6473 : // calculated to meet the thermostat setpoint.
6474 : // If a HX assisted cooling coil is selected, the HX is always active.
6475 : // If the latent load is not met by operating the system at the sensible PLR,
6476 : // a new PLR is calculated to meet the humidistat setpoint.
6477 : // The reheat coil load is then calculated to meet the HEATING setpoint temperature.
6478 : // Dehumidification Control MULTIMODE: For cooling operation, the sensible and latent capacities are calculated to
6479 : // meet the thermostat setpoint. If a HX assisted cooling coil is selected,
6480 : // the HX is off for this calculation. If the latent load is not met by operating
6481 : // the system at the sensible PLR, a new PLR is calculated with the HX operating
6482 : // and the target is the thermostat setpoint. Humidity is not controlled in this
6483 : // mode. No reheat coil is used in this configuration.
6484 : // Note: A supplemental heater augments the heating capacity for air-to-air heat pumps.
6485 : // A reheat coil is used for the HeatCool furnace/unitarysystem to offset the sensible cooling when the
6486 : // dehumidification control type is COOLREHEAT. Both the supplemental and reheat heating coil load is calculated
6487 : // in the Calc routines. The actual simulation of these coils is performed in the SimFurnace routine (i.e. the
6488 : // supplemental and reheat coil loads are passed as 0 to CalcFurnaceOutput).
6489 :
6490 : // SUBROUTINE PARAMETER DEFINITIONS:
6491 4597475 : int constexpr MaxIter(100); // maximum number of iterations
6492 4597475 : Real64 constexpr MinPLR(0.0); // minimum part load ratio allowed
6493 :
6494 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
6495 : Real64 SystemMoistureLoad; // Total latent load to be removed by furnace/unitary system
6496 : Real64 deltaT; // Temperature rise across heating coil (C)
6497 : Real64 TempOutHeatingCoil; // Temperature leaving heating coil (C)
6498 : Real64 FullSensibleOutput; // Full sensible output of AC (W)
6499 : Real64 FullLatentOutput; // Full latent output of AC (W)
6500 : Real64 NoCoolOutput; // Sensible output of AC with no cooling allowed (W)
6501 : Real64 NoHeatOutput; // Sensible output of heater with no heating allowed (W)
6502 : Real64 NoLatentOutput; // Latent output of AC with no cooling allowed (W)
6503 : Real64 CoolErrorToler; // Error tolerance in cooling mode
6504 : Real64 HeatErrorToler; // Error tolerance in heating mode
6505 : Real64 ActualSensibleOutput; // Actual furnace sensible capacity
6506 : Real64 ActualLatentOutput; // Actual furnace latent capacity
6507 : Real64 PartLoadRatio; // Part load ratio (greater of sensible or latent part load ratio for cooling,
6508 : // or heating PLR)
6509 : Real64 LatentPartLoadRatio; // Part load ratio to meet dehumidification load
6510 : Real64 TempCoolOutput; // Temporary Sensible output of AC while iterating on PLR (W)
6511 : Real64 TempHeatOutput; // Temporary Sensible output of heating coil while iterating on PLR (W)
6512 : Real64 TempLatentOutput; // Temporary Latent output of AC at increasing PLR (W)
6513 : // ! (Temp variables are used to find min PLR for positive latent removal)
6514 : Real64 TempMinPLR; // Temporary min latent PLR when hum control is required and iter is exceeded
6515 : Real64 TempMinPLR2; // Temporary min latent PLR when cyc fan hum control is required and iter is exceeded
6516 : Real64 TempMaxPLR; // Temporary max latent PLR when hum control is required and iter is exceeded
6517 : Real64 QToHeatSetPt; // Load required to meet heating setpoint temp (>0 is a heating load)
6518 : Real64 CoolingHeatingPLRRatio; // ratio of cooling to heating PLR (MAX=1). Used in heating mode.
6519 : Real64 HeatingSensibleOutput;
6520 : Real64 HeatingLatentOutput;
6521 : Real64 OutdoorDryBulbTemp; // secondary coil (condenser) entering dry bulb temperature
6522 :
6523 4597475 : Real64 &SystemSensibleLoad = state.dataFurnaces->SystemSensibleLoad;
6524 4597475 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
6525 : // Set local variables
6526 4597475 : int FurnaceOutletNode = thisFurnace.FurnaceOutletNodeNum;
6527 4597475 : int FurnaceInletNode = thisFurnace.FurnaceInletNodeNum;
6528 4597475 : int ControlZoneNode = thisFurnace.NodeNumOfControlledZone;
6529 4597475 : HVAC::FanOp fanOp = thisFurnace.fanOp; // fan operating mode
6530 4597475 : bool HumControl = false;
6531 : // Calculate the Cp Air of zone
6532 4597475 : Real64 cpair = Psychrometrics::PsyCpAirFnW(state.dataLoopNodes->Node(ControlZoneNode).HumRat);
6533 4597475 : NoHeatOutput = 0.0;
6534 4597475 : SystemSensibleLoad = 0.0;
6535 4597475 : ReheatCoilLoad = 0.0;
6536 4597475 : HeatCoilLoad = 0.0;
6537 4597475 : ReheatCoilLoad = 0.0;
6538 4597475 : PartLoadRatio = 0.0;
6539 :
6540 4597475 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir) {
6541 391662 : if (state.dataDXCoils->DXCoil(thisFurnace.HeatingCoilIndex)
6542 391662 : .IsSecondaryDXCoilInZone) { // assumes compressor is in same location as secondary coil
6543 16288 : OutdoorDryBulbTemp =
6544 16288 : state.dataZoneTempPredictorCorrector->zoneHeatBalance(state.dataDXCoils->DXCoil(thisFurnace.HeatingCoilIndex).SecZonePtr).ZT;
6545 375374 : } else if (state.dataDXCoils->DXCoil(thisFurnace.CoolingCoilIndex).IsSecondaryDXCoilInZone) {
6546 0 : OutdoorDryBulbTemp =
6547 0 : state.dataZoneTempPredictorCorrector->zoneHeatBalance(state.dataDXCoils->DXCoil(thisFurnace.CoolingCoilIndex).SecZonePtr).ZT;
6548 : } else {
6549 375374 : if (thisFurnace.CondenserNodeNum > 0) {
6550 63402 : OutdoorDryBulbTemp = state.dataLoopNodes->Node(thisFurnace.CondenserNodeNum).Temp;
6551 : } else {
6552 311972 : OutdoorDryBulbTemp = state.dataEnvrn->OutDryBulbTemp;
6553 : }
6554 : }
6555 : } else {
6556 4205813 : OutdoorDryBulbTemp = state.dataEnvrn->OutDryBulbTemp;
6557 : }
6558 4597475 : if (FirstHVACIteration) {
6559 : // Set selected values during first HVAC iteration
6560 :
6561 : // Init for heating
6562 1595035 : if (state.dataFurnaces->HeatingLoad) {
6563 572012 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir ||
6564 515602 : (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir && thisFurnace.WatertoAirHPType == WAHPCoilType::Simple)) {
6565 170850 : thisFurnace.HeatPartLoadRatio = 1.0;
6566 170850 : HeatCoilLoad = 0.0;
6567 170850 : thisFurnace.HeatingCoilSensDemand = 0.0;
6568 170850 : thisFurnace.CoolingCoilSensDemand = 0.0;
6569 170850 : thisFurnace.CoolingCoilLatentDemand = 0.0;
6570 : } else { // for furnaces
6571 401162 : thisFurnace.HeatPartLoadRatio = 0.0;
6572 401162 : HeatCoilLoad = ZoneLoad;
6573 401162 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.MdotFurnace;
6574 401162 : thisFurnace.HeatingCoilSensDemand = 0.0;
6575 401162 : thisFurnace.CoolingCoilSensDemand = 0.0;
6576 401162 : thisFurnace.CoolingCoilLatentDemand = 0.0;
6577 : }
6578 572012 : ReheatCoilLoad = 0.0;
6579 572012 : thisFurnace.CoolPartLoadRatio = 0.0;
6580 :
6581 : // Init for cooling
6582 1023023 : } else if (state.dataFurnaces->CoolingLoad) {
6583 : // air to air heat pumps
6584 555293 : thisFurnace.CoolPartLoadRatio = 1.0;
6585 555293 : thisFurnace.HeatPartLoadRatio = 0.0;
6586 555293 : HeatCoilLoad = 0.0;
6587 555293 : ReheatCoilLoad = 0.0;
6588 :
6589 : // Init for moisture load only
6590 : } else {
6591 467730 : thisFurnace.CoolPartLoadRatio = 0.0;
6592 467730 : thisFurnace.HeatPartLoadRatio = 0.0;
6593 467730 : HeatCoilLoad = 0.0;
6594 467730 : ReheatCoilLoad = 0.0;
6595 467730 : thisFurnace.HeatingCoilSensDemand = 0.0;
6596 467730 : thisFurnace.CoolingCoilSensDemand = 0.0;
6597 467730 : thisFurnace.CoolingCoilLatentDemand = 0.0;
6598 : }
6599 :
6600 1595035 : SetAverageAirFlow(state, FurnaceNum, max(thisFurnace.HeatPartLoadRatio, thisFurnace.CoolPartLoadRatio), OnOffAirFlowRatio);
6601 : // if dehumidification load exists (for heat pumps) turn on the supplmental heater
6602 1595035 : if (state.dataFurnaces->HPDehumidificationLoadFlag) HumControl = true;
6603 : } else { // not FirstHVACIteration
6604 : // Init for heating
6605 3002440 : Real64 &CoolCoilLoad = state.dataFurnaces->CoolCoilLoad;
6606 3002440 : if (state.dataFurnaces->HeatingLoad) {
6607 1230288 : CoolCoilLoad = 0.0;
6608 1230288 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir ||
6609 1138478 : (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir && thisFurnace.WatertoAirHPType == WAHPCoilType::Simple)) {
6610 630470 : SystemSensibleLoad = ZoneLoad;
6611 630470 : SystemMoistureLoad = 0.0;
6612 630470 : HeatCoilLoad = 0.0;
6613 630470 : thisFurnace.HeatingCoilSensDemand = SystemSensibleLoad;
6614 630470 : thisFurnace.CoolingCoilSensDemand = 0.0;
6615 630470 : thisFurnace.CoolingCoilLatentDemand = 0.0;
6616 : } else {
6617 599818 : SystemMoistureLoad = MoistureLoad;
6618 599818 : HeatCoilLoad = ZoneLoad;
6619 : }
6620 :
6621 : // Init for cooling
6622 1772152 : } else if (state.dataFurnaces->CoolingLoad) {
6623 1248779 : CoolCoilLoad = ZoneLoad;
6624 1248779 : SystemMoistureLoad = MoistureLoad;
6625 1248779 : HeatCoilLoad = 0.0;
6626 1248779 : thisFurnace.CoolingCoilSensDemand = std::abs(CoolCoilLoad);
6627 1248779 : thisFurnace.CoolingCoilLatentDemand = std::abs(SystemMoistureLoad);
6628 1248779 : thisFurnace.HeatingCoilSensDemand = 0.0;
6629 :
6630 : // Init for latent
6631 : } else {
6632 523373 : SystemMoistureLoad = MoistureLoad;
6633 523373 : CoolCoilLoad = 0.0;
6634 523373 : HeatCoilLoad = 0.0;
6635 : // set report variables
6636 523373 : thisFurnace.CoolingCoilSensDemand = 0.0;
6637 523373 : thisFurnace.CoolingCoilLatentDemand = SystemMoistureLoad;
6638 523373 : thisFurnace.HeatingCoilSensDemand = 0.0;
6639 : }
6640 3002440 : HeatingSensibleOutput = 0.0;
6641 3002440 : HeatingLatentOutput = 0.0;
6642 3002440 : ReheatCoilLoad = 0.0;
6643 3002440 : thisFurnace.CoolPartLoadRatio = 0.0;
6644 3002440 : thisFurnace.HeatPartLoadRatio = 0.0;
6645 3002440 : thisFurnace.CompPartLoadRatio = 0.0;
6646 3002440 : thisFurnace.DehumidInducedHeatingDemandRate = 0.0;
6647 :
6648 : // When humidity control is used with cycling fan control and a heating load exists, if a moisture load
6649 : // also exists, the heating PLR must be available for the cooling coil calculations.
6650 : //*********** Heating Section ************
6651 : // If Furnace runs with a heating load then set HeatCoilLoad on Heating Coil and the Mass Flow
6652 : // (Node(FurnaceInletNode)%MassFlowRate .gt. 0.0d0) .and. &
6653 3002440 : if ((ScheduleManager::GetCurrentScheduleValue(state, thisFurnace.SchedPtr) > 0.0) && (state.dataFurnaces->HeatingLoad)) {
6654 :
6655 : // Heat pumps only calculate a single PLR each time step (i.e. only cooling or heating allowed in a single time step)
6656 1219760 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir ||
6657 1127950 : (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir && thisFurnace.WatertoAirHPType == WAHPCoilType::Simple)) {
6658 :
6659 630470 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.MdotFurnace;
6660 :
6661 : // Get no load result
6662 630470 : if (fanOp == HVAC::FanOp::Cycling) {
6663 593322 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = 0.0;
6664 : }
6665 :
6666 : // Set the inlet mass flow rate based on user specified coil OFF flow rate
6667 630470 : PartLoadRatio = 0.0;
6668 :
6669 630470 : SetAverageAirFlow(state, FurnaceNum, PartLoadRatio, OnOffAirFlowRatio);
6670 :
6671 : // Set the input parameters for CalcFurnaceOutput
6672 630470 : thisFurnace.CompPartLoadRatio = 0.0; // compressor off
6673 :
6674 630470 : CalcFurnaceOutput(state,
6675 : FurnaceNum,
6676 : FirstHVACIteration,
6677 : fanOp,
6678 : compressorOp,
6679 : 0.0,
6680 : MinPLR,
6681 : 0.0,
6682 : 0.0,
6683 : NoHeatOutput,
6684 : NoLatentOutput,
6685 : OnOffAirFlowRatio,
6686 : false);
6687 :
6688 630470 : PartLoadRatio = 1.0;
6689 630470 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.MdotFurnace;
6690 :
6691 630470 : thisFurnace.CompPartLoadRatio = 1.0; // compressor ON
6692 :
6693 : // Set fan part-load fraction equal to 1 while getting full load result
6694 630470 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
6695 630470 : OnOffAirFlowRatio = 1.0;
6696 :
6697 : // Get full load result
6698 630470 : CalcFurnaceOutput(state,
6699 : FurnaceNum,
6700 : FirstHVACIteration,
6701 : fanOp,
6702 : compressorOp,
6703 : 0.0,
6704 : PartLoadRatio,
6705 : 0.0,
6706 : 0.0,
6707 : FullSensibleOutput,
6708 : FullLatentOutput,
6709 : OnOffAirFlowRatio,
6710 : false);
6711 :
6712 : // Check that SystemSensibleLoad is between FullSensibleOutput and NoHeatOutput
6713 : // If so then calculate PartLoadRatio for the DX Heating coil
6714 630470 : if (SystemSensibleLoad < FullSensibleOutput && SystemSensibleLoad > NoHeatOutput) {
6715 :
6716 : // Calculate the part load ratio through iteration
6717 544890 : HeatErrorToler = thisFurnace.HeatingConvergenceTolerance; // Error tolerance for convergence from input deck
6718 :
6719 544890 : int SolFlag = 0; // # of iterations if positive, -1 means failed to converge, -2 means bounds are incorrect
6720 : // HeatErrorToler is in fraction of load, MaxIter = 30, SolFalg = # of iterations or error as appropriate
6721 2700486 : auto f = [&state, FurnaceNum, FirstHVACIteration, fanOp, compressorOp, SystemSensibleLoad](Real64 const PartLoadRatio) {
6722 2155596 : return CalcFurnaceResidual(state,
6723 : PartLoadRatio,
6724 : FurnaceNum,
6725 : FirstHVACIteration,
6726 : fanOp,
6727 : compressorOp,
6728 : SystemSensibleLoad,
6729 : 0.0, // par6_loadFlag,
6730 : 1.0, // par7_sensLatentFlag,
6731 : 0.0, // par9_HXOnFlag,
6732 2155596 : 0.0); // par10_HeatingCoilPLR);
6733 544890 : };
6734 544890 : General::SolveRoot(state, HeatErrorToler, MaxIter, SolFlag, PartLoadRatio, f, 0.0, 1.0);
6735 : // OnOffAirFlowRatio is updated during the above iteration. Reset to correct value based on PLR.
6736 544890 : OnOffAirFlowRatio = state.dataFurnaces->OnOffAirFlowRatioSave;
6737 544890 : if (SolFlag < 0) {
6738 0 : if (SolFlag == -1) {
6739 0 : CalcFurnaceOutput(state,
6740 : FurnaceNum,
6741 : FirstHVACIteration,
6742 : fanOp,
6743 : compressorOp,
6744 : 0.0,
6745 : PartLoadRatio,
6746 : 0.0,
6747 : 0.0,
6748 : TempHeatOutput,
6749 : TempLatentOutput,
6750 : OnOffAirFlowRatio,
6751 : false);
6752 0 : if (std::abs(SystemSensibleLoad - TempHeatOutput) > HVAC::SmallLoad) {
6753 0 : if (thisFurnace.DXHeatingMaxIterIndex == 0) {
6754 0 : ShowWarningMessage(state,
6755 0 : format("Heating coil control failed to converge for {}:{}",
6756 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6757 0 : thisFurnace.Name));
6758 0 : ShowContinueError(state,
6759 : " Iteration limit exceeded in calculating DX heating coil sensible part-load ratio.");
6760 0 : ShowContinueErrorTimeStamp(
6761 : state,
6762 0 : format("Sensible load to be met by DX heating coil = {:.2T} (watts), sensible output of DX heating "
6763 : "coil = {:.2T} (watts), and the simulation continues.",
6764 : SystemSensibleLoad,
6765 : TempHeatOutput));
6766 : }
6767 0 : ShowRecurringWarningErrorAtEnd(state,
6768 0 : format("{} \"{}\" - Iteration limit exceeded in calculating DX sensible heating "
6769 : "part-load ratio error continues. "
6770 : "Sensible load statistics:",
6771 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6772 0 : thisFurnace.Name),
6773 0 : thisFurnace.DXHeatingMaxIterIndex,
6774 : SystemSensibleLoad,
6775 : SystemSensibleLoad);
6776 : }
6777 0 : } else if (SolFlag == -2) {
6778 0 : if (thisFurnace.DXHeatingRegulaFalsiFailedIndex == 0) {
6779 0 : ShowWarningMessage(state,
6780 0 : format("Heating coil control failed for {}:{}",
6781 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6782 0 : thisFurnace.Name));
6783 0 : ShowContinueError(state, " DX sensible heating part-load ratio determined to be outside the range of 0-1.");
6784 0 : ShowContinueErrorTimeStamp(
6785 : state,
6786 0 : format("Sensible load to be met by DX heating coil = {:.2T} (watts), and the simulation continues.",
6787 : SystemSensibleLoad));
6788 : }
6789 0 : ShowRecurringWarningErrorAtEnd(
6790 : state,
6791 0 : format("{} \"{}\" - DX sensible heating part-load ratio out of range error continues. Sensible load statistics:",
6792 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
6793 0 : thisFurnace.Name),
6794 0 : thisFurnace.DXHeatingRegulaFalsiFailedIndex,
6795 : SystemSensibleLoad,
6796 : SystemSensibleLoad);
6797 : }
6798 : }
6799 :
6800 544890 : thisFurnace.HeatPartLoadRatio = PartLoadRatio;
6801 : // Check if Heat Pump compressor is allowed to run based on outdoor temperature
6802 544890 : if (OutdoorDryBulbTemp > thisFurnace.MinOATCompressorHeating) {
6803 544872 : thisFurnace.CompPartLoadRatio = PartLoadRatio;
6804 : } else {
6805 18 : thisFurnace.CompPartLoadRatio = 0.0;
6806 : }
6807 630470 : } else if (SystemSensibleLoad > FullSensibleOutput) {
6808 : // SystemSensibleLoad is greater than full DX Heating coil output so heat pump runs entire
6809 : // timestep and additional supplemental heating is required
6810 85580 : thisFurnace.HeatPartLoadRatio = 1.0;
6811 85580 : if (OutdoorDryBulbTemp > thisFurnace.MinOATCompressorHeating) {
6812 : // Check to see if Heat Pump compressor was allowed to run based on outdoor temperature
6813 4142 : thisFurnace.CompPartLoadRatio = 1.0;
6814 : } else {
6815 81438 : thisFurnace.CompPartLoadRatio = 0.0;
6816 : }
6817 0 : } else if (SystemSensibleLoad < NoHeatOutput) {
6818 : // SystemSensibleLoad is less than minimum DX Heating coil output so heat pump does not run and
6819 : // the load will be met by the supplemental heater
6820 0 : thisFurnace.CompPartLoadRatio = 0.0;
6821 0 : thisFurnace.HeatPartLoadRatio = 1.0;
6822 : }
6823 630470 : if (thisFurnace.HeatPartLoadRatio == 1.0) {
6824 : // Determine the load on the supplemental heating coil
6825 85580 : if ((SystemSensibleLoad - FullSensibleOutput) > thisFurnace.DesignSuppHeatingCapacity) {
6826 24992 : HeatCoilLoad = thisFurnace.DesignSuppHeatingCapacity;
6827 24992 : TempOutHeatingCoil = state.dataLoopNodes->Node(FurnaceOutletNode).Temp + HeatCoilLoad / (cpair * thisFurnace.MdotFurnace);
6828 60588 : } else if (SystemSensibleLoad < NoHeatOutput) {
6829 0 : HeatCoilLoad = max(0.0, SystemSensibleLoad); // BG 10/22/2008 need a case for when its all suppl heat
6830 0 : TempOutHeatingCoil = state.dataLoopNodes->Node(FurnaceInletNode).Temp + HeatCoilLoad / (cpair * thisFurnace.MdotFurnace);
6831 : } else {
6832 60588 : HeatCoilLoad = max(0.0, (SystemSensibleLoad - FullSensibleOutput));
6833 60588 : TempOutHeatingCoil = state.dataLoopNodes->Node(FurnaceOutletNode).Temp + HeatCoilLoad / (cpair * thisFurnace.MdotFurnace);
6834 : }
6835 85580 : if (OutdoorDryBulbTemp > thisFurnace.MaxOATSuppHeat) {
6836 0 : HeatCoilLoad = 0.0;
6837 0 : if (SystemSensibleLoad < NoHeatOutput) {
6838 0 : TempOutHeatingCoil = state.dataLoopNodes->Node(FurnaceInletNode).Temp;
6839 : } else {
6840 0 : TempOutHeatingCoil = state.dataLoopNodes->Node(FurnaceOutletNode).Temp;
6841 : }
6842 : }
6843 85580 : if ((TempOutHeatingCoil > thisFurnace.DesignMaxOutletTemp) && (HeatCoilLoad > 0.0)) {
6844 : // deltaT = Furnace(FurnaceNum)%DesignMaxOutletTemp - Node(FurnaceOutletNode)%Temp
6845 : // BG 10/22/2008 above made no sense if DX heat is off and its all supplemental,
6846 : // because Node(FurnaceOutletNode)%Temp will have been calc'd with full DX heat in last faux call to CalcFurnaceOutput
6847 :
6848 1374 : Real64 cpairSupply = Psychrometrics::PsyCpAirFnW(state.dataLoopNodes->Node(FurnaceInletNode).HumRat);
6849 1374 : deltaT = (thisFurnace.DesignMaxOutletTemp - TempOutHeatingCoil);
6850 1374 : HeatCoilLoad += (state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate * cpairSupply * deltaT);
6851 1374 : HeatCoilLoad = max(0.0, HeatCoilLoad);
6852 : }
6853 : } else {
6854 544890 : HeatCoilLoad = 0.0;
6855 : }
6856 630470 : PartLoadRatio = 0.0;
6857 :
6858 : // HeatCool systems can have both a sensible and latent PLR in a single time step
6859 : // (i.e. both cooling and heating can occur in a single time step)
6860 630470 : } else { // else not a heatpump DX coil ** non-HP heating coils are not DX so testing if OutdoorDryBulbTemp < MinOATCompressorHeating
6861 : // is not necessary **
6862 :
6863 589290 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.MdotFurnace;
6864 589290 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity;
6865 589290 : SystemSensibleLoad = ZoneLoad;
6866 :
6867 : // Get no load result
6868 589290 : if (fanOp == HVAC::FanOp::Cycling) {
6869 443811 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = 0.0;
6870 : }
6871 589290 : if (fanOp == HVAC::FanOp::Continuous) {
6872 145479 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0; // The on/off fan will not cycle, so set part-load fraction = 1
6873 : }
6874 :
6875 : // Set the inlet mass flow rate based on user specified coil OFF flow rate
6876 589290 : PartLoadRatio = 0.0;
6877 589290 : SetAverageAirFlow(state, FurnaceNum, PartLoadRatio, OnOffAirFlowRatio);
6878 :
6879 589290 : CalcFurnaceOutput(state,
6880 : FurnaceNum,
6881 : FirstHVACIteration,
6882 : fanOp,
6883 : compressorOp,
6884 : 0.0,
6885 : MinPLR,
6886 : 0.0,
6887 : 0.0,
6888 : NoHeatOutput,
6889 : NoLatentOutput,
6890 : OnOffAirFlowRatio,
6891 : false);
6892 :
6893 589290 : if (NoHeatOutput < SystemSensibleLoad) {
6894 589290 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.MdotFurnace;
6895 :
6896 : // Set fan part-load fraction equal to 1 while getting full load result
6897 589290 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
6898 589290 : OnOffAirFlowRatio = 1.0;
6899 :
6900 : // Get full load result
6901 589290 : CalcFurnaceOutput(state,
6902 : FurnaceNum,
6903 : FirstHVACIteration,
6904 : fanOp,
6905 : compressorOp,
6906 : 0.0,
6907 : 1.0,
6908 : HeatCoilLoad,
6909 : 0.0,
6910 : FullSensibleOutput,
6911 : FullLatentOutput,
6912 : OnOffAirFlowRatio,
6913 : false);
6914 : } else {
6915 0 : FullSensibleOutput = NoHeatOutput + 0.000000001;
6916 : }
6917 :
6918 : // Since we are heating, we expect FullSensibleOutput to be > 0 and FullSensibleOutput > NoSensibleOutput
6919 : // Check that this is the case; if not set PartLoadRatio = 0.0 (off) and return
6920 :
6921 589290 : if (FullSensibleOutput > NoHeatOutput) {
6922 :
6923 : // check bounds on sensible output prior to iteration using RegulaFalsi
6924 534244 : if (FullSensibleOutput <= SystemSensibleLoad) {
6925 96967 : PartLoadRatio = 1.0;
6926 : // save modified HeatCoilLoad in case it was reset because outlet temp > DesignMaxOutletTemp
6927 96967 : if (state.dataFurnaces->ModifiedHeatCoilLoad > 0.0) {
6928 14808 : HeatCoilLoad = state.dataFurnaces->ModifiedHeatCoilLoad;
6929 : } else {
6930 82159 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity;
6931 : }
6932 437277 : } else if (NoHeatOutput >= SystemSensibleLoad) {
6933 0 : PartLoadRatio = 0.0;
6934 0 : HeatCoilLoad = 0.0;
6935 : } else {
6936 :
6937 : // Calculate the part load ratio through iteration
6938 437277 : HeatErrorToler = thisFurnace.HeatingConvergenceTolerance; // Error tolerance for convergence from input deck
6939 :
6940 437277 : int SolFlag = 0; // # of iterations if positive, -1 means failed to converge, -2 means bounds are incorrect
6941 : // HeatErrorToler is in fraction load, MaxIter = 30, SolFalg = # of iterations or error as appropriate
6942 1753894 : auto f = [&state, FurnaceNum, FirstHVACIteration, fanOp, compressorOp, SystemSensibleLoad](Real64 const PartLoadRatio) {
6943 1316617 : return CalcFurnaceResidual(state,
6944 : PartLoadRatio,
6945 : FurnaceNum,
6946 : FirstHVACIteration,
6947 : fanOp,
6948 : compressorOp,
6949 : SystemSensibleLoad,
6950 : 0.0, // par6_loadFlag,
6951 : 1.0, // par7_sensLatentFlag,
6952 : 0.0, // par9_HXOnFlag,
6953 1316617 : 0.0); // par10_HeatingCoilPLR);
6954 437277 : };
6955 437277 : General::SolveRoot(state, HeatErrorToler, MaxIter, SolFlag, PartLoadRatio, f, 0.0, 1.0);
6956 : // OnOffAirFlowRatio is updated during the above iteration. Reset to correct value based on PLR.
6957 437277 : OnOffAirFlowRatio = state.dataFurnaces->OnOffAirFlowRatioSave;
6958 : // Reset HeatCoilLoad calculated in CalcFurnaceResidual (in case it was reset because output temp >
6959 : // DesignMaxOutletTemp)
6960 437277 : if (state.dataFurnaces->ModifiedHeatCoilLoad > 0.0) {
6961 62506 : HeatCoilLoad = state.dataFurnaces->ModifiedHeatCoilLoad;
6962 : } else {
6963 374771 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity * PartLoadRatio;
6964 : }
6965 437277 : if (SolFlag == -1) {
6966 :
6967 : // RegulaFalsi may not find heating PLR when the maximum supply air temperature is exceeded.
6968 : // If iteration limit is exceeded, find tighter boundary of solution and repeat RegulaFalsi
6969 0 : TempMaxPLR = -0.1;
6970 0 : TempHeatOutput = NoHeatOutput;
6971 0 : while ((TempHeatOutput - SystemSensibleLoad) < 0.0 && TempMaxPLR < 1.0) {
6972 : // find upper limit of HeatingPLR
6973 0 : TempMaxPLR += 0.1;
6974 0 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity * TempMaxPLR;
6975 0 : CalcFurnaceOutput(state,
6976 : FurnaceNum,
6977 : FirstHVACIteration,
6978 : fanOp,
6979 : compressorOp,
6980 : 0.0,
6981 : TempMaxPLR,
6982 : HeatCoilLoad,
6983 : 0.0,
6984 : TempHeatOutput,
6985 : TempLatentOutput,
6986 : OnOffAirFlowRatio,
6987 : false);
6988 : }
6989 0 : TempMinPLR = TempMaxPLR;
6990 0 : while ((TempHeatOutput - SystemSensibleLoad) > 0.0 && TempMinPLR > 0.0) {
6991 : // pull upper limit of HeatingPLR down to last valid limit (i.e. heat output still exceeds
6992 : // SystemSensibleLoad)
6993 0 : TempMaxPLR = TempMinPLR;
6994 : // find minimum limit of HeatingPLR
6995 0 : TempMinPLR -= 0.01;
6996 :
6997 0 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity * TempMinPLR;
6998 0 : CalcFurnaceOutput(state,
6999 : FurnaceNum,
7000 : FirstHVACIteration,
7001 : fanOp,
7002 : compressorOp,
7003 : 0.0,
7004 : TempMinPLR,
7005 : HeatCoilLoad,
7006 : 0.0,
7007 : TempHeatOutput,
7008 : TempLatentOutput,
7009 : OnOffAirFlowRatio,
7010 : false);
7011 : }
7012 : // Now solve again with tighter PLR limits
7013 : auto f2 = // (AUTO_OK_LAMBDA)
7014 0 : [&state, FurnaceNum, FirstHVACIteration, fanOp, compressorOp, SystemSensibleLoad](Real64 const PartLoadRatio) {
7015 0 : return CalcFurnaceResidual(state,
7016 : PartLoadRatio,
7017 : FurnaceNum,
7018 : FirstHVACIteration,
7019 : fanOp,
7020 : compressorOp,
7021 : SystemSensibleLoad,
7022 : 0.0, // par6_loadFlag,
7023 : 1.0, // par7_sensLatentFlag,
7024 : 0.0, // par9_HXOnFlag,
7025 0 : 0.0); // par10_HeatingCoilPLR);
7026 0 : };
7027 0 : General::SolveRoot(state, HeatErrorToler, MaxIter, SolFlag, PartLoadRatio, f2, TempMinPLR, TempMaxPLR);
7028 0 : if (state.dataFurnaces->ModifiedHeatCoilLoad > 0.0) {
7029 0 : HeatCoilLoad = state.dataFurnaces->ModifiedHeatCoilLoad;
7030 : } else {
7031 0 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity * PartLoadRatio;
7032 : }
7033 0 : CalcFurnaceOutput(state,
7034 : FurnaceNum,
7035 : FirstHVACIteration,
7036 : fanOp,
7037 : compressorOp,
7038 : 0.0,
7039 : PartLoadRatio,
7040 : HeatCoilLoad,
7041 : 0.0,
7042 : TempHeatOutput,
7043 : TempLatentOutput,
7044 : OnOffAirFlowRatio,
7045 : false);
7046 :
7047 : // After iterating with tighter boundaries, if still out of tolerance, show warning.
7048 0 : if (SolFlag == -1 && std::abs(SystemSensibleLoad - TempHeatOutput) > HVAC::SmallLoad) {
7049 0 : if (thisFurnace.HeatingMaxIterIndex == 0) {
7050 0 : ShowWarningMessage(state,
7051 0 : format("Heating coil control failed to converge for {}:{}",
7052 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7053 0 : thisFurnace.Name));
7054 0 : ShowContinueError(state, " Iteration limit exceeded in calculating heating coil sensible part-load ratio.");
7055 0 : ShowContinueErrorTimeStamp(state,
7056 0 : format("Sensible load to be met by heating coil = {:.2T} (watts), sensible output "
7057 : "of heating coil = {:.2T} (watts), and the simulation continues.",
7058 : SystemSensibleLoad,
7059 : TempHeatOutput));
7060 : }
7061 0 : ShowRecurringWarningErrorAtEnd(
7062 : state,
7063 0 : format("{} \"{}\" - Iteration limit exceeded in calculating sensible heating part-load "
7064 : "ratio error continues. Sensible load statistics:",
7065 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7066 0 : thisFurnace.Name),
7067 0 : thisFurnace.HeatingMaxIterIndex,
7068 : SystemSensibleLoad,
7069 : SystemSensibleLoad);
7070 : }
7071 437277 : } else if (SolFlag == -2) {
7072 0 : if (thisFurnace.HeatingRegulaFalsiFailedIndex == 0) {
7073 0 : ShowWarningMessage(state,
7074 0 : format("Heating coil control failed for {}:{}",
7075 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7076 0 : thisFurnace.Name));
7077 0 : ShowContinueError(state, " Sensible heating part-load ratio determined to be outside the range of 0-1.");
7078 0 : ShowContinueErrorTimeStamp(
7079 : state,
7080 0 : format("Sensible load to be met by heating coil = {:.2T} (watts), and the simulation continues.",
7081 : SystemSensibleLoad));
7082 : }
7083 0 : ShowRecurringWarningErrorAtEnd(
7084 : state,
7085 0 : format("{} \"{}\" - Sensible heating part-load ratio out of range error continues. Sensible load statistics:",
7086 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7087 0 : thisFurnace.Name),
7088 0 : thisFurnace.HeatingRegulaFalsiFailedIndex,
7089 : SystemSensibleLoad,
7090 : SystemSensibleLoad);
7091 : }
7092 : }
7093 :
7094 : } else { // ELSE from IF(FullSensibleOutput.GT.NoSensibleOutput)THEN above
7095 : // Set part load ratio to 1 and run heater at design heating capacity
7096 55046 : PartLoadRatio = 1.0;
7097 55046 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity;
7098 : }
7099 :
7100 : } // End of IF HeatPump
7101 :
7102 : } // End of IF for heating
7103 :
7104 : // Non-heat pump systems do not set a heating PLR, set it here for use with the DX cooling coil calculations.
7105 : // Set this variable back to 0 for non-heat pump systems at the end of this routine.
7106 3002440 : thisFurnace.HeatPartLoadRatio = max(PartLoadRatio, thisFurnace.HeatPartLoadRatio);
7107 3002440 : CalcFurnaceOutput(state,
7108 : FurnaceNum,
7109 : FirstHVACIteration,
7110 : fanOp,
7111 : compressorOp,
7112 : 0.0,
7113 : thisFurnace.HeatPartLoadRatio,
7114 : HeatCoilLoad,
7115 : 0.0,
7116 : HeatingSensibleOutput,
7117 : HeatingLatentOutput,
7118 : OnOffAirFlowRatio,
7119 : false);
7120 :
7121 5756598 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir ||
7122 2754158 : (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir && thisFurnace.WatertoAirHPType == WAHPCoilType::Simple &&
7123 1352600 : state.dataFurnaces->CoolingLoad)) {
7124 938770 : HeatingSensibleOutput = 0.0;
7125 938770 : HeatingLatentOutput = 0.0;
7126 : }
7127 : //***********Cooling Section*****************
7128 : // Simulate if scheduled ON and cooling load or if a moisture load exists when using a humidistat
7129 : // Check of HeatingLatentOutput is used to reduce overshoot during simultaneous heating and cooling
7130 : // Setback flag is used to avoid continued RH control when Tstat is setback (RH should float down)
7131 4763470 : if ((ScheduleManager::GetCurrentScheduleValue(state, thisFurnace.SchedPtr) > 0.0 && state.dataFurnaces->CoolingLoad) ||
7132 1761030 : (thisFurnace.Humidistat && thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat &&
7133 335771 : (SystemMoistureLoad < 0.0 || (SystemMoistureLoad >= 0.0 && HeatingLatentOutput > SystemMoistureLoad &&
7134 10847 : !state.dataZoneEnergyDemand->Setback(thisFurnace.ControlZoneNum))))) {
7135 :
7136 : // For cooling operation, the first step is to set the HX operation flag in case a HX assisted coil is used.
7137 : // (if a HX assisted coil is not used, this flag is not used. It's only used in the CALL to SimHXAssistedCoolingCoil)
7138 : // Check the dehumidification control type:
7139 : // For dehumidification control options CoolReheat and None, the HX is always active (locked ON).
7140 : // For dehumidification control option Multimode, the system is operated first with the HX off.
7141 : // If the moisture load is not met, the HX will then be turned on and the system is re-simulated.
7142 :
7143 1402258 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat ||
7144 1142919 : thisFurnace.DehumidControlType_Num == DehumidificationControlMode::None) {
7145 1393818 : HXUnitOn = true;
7146 : } else {
7147 8440 : HXUnitOn = false;
7148 : }
7149 :
7150 : // The next step is to determine the system output at no load (PLR=0) and full load (PLR=1)
7151 :
7152 : // Set the inlet mass flow rate based on user specified coil OFF flow rate
7153 1402258 : PartLoadRatio = 0.0;
7154 :
7155 1402258 : thisFurnace.CompPartLoadRatio = 0.0; // compressor off
7156 :
7157 : // SetAverageAirFlow calculates the operating mass flow rate based on PLR and the user specified inputs
7158 : // for MaxCoolAirMassFlow and MaxNoCoolHeatAirMassFlow.
7159 : // Air flow rate is set according to max of cooling and heating PLR if heating and latent load exists.
7160 787692 : if (fanOp == HVAC::FanOp::Cycling && thisFurnace.HeatPartLoadRatio > 0.0 && thisFurnace.Humidistat &&
7161 2189952 : thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat &&
7162 2 : (SystemMoistureLoad < 0.0 || (SystemMoistureLoad >= 0.0 && HeatingLatentOutput > SystemMoistureLoad &&
7163 0 : !state.dataZoneEnergyDemand->Setback(thisFurnace.ControlZoneNum)))) {
7164 2 : CoolingHeatingPLRRatio = min(1.0, PartLoadRatio / thisFurnace.HeatPartLoadRatio);
7165 2 : SetAverageAirFlow(state, FurnaceNum, max(PartLoadRatio, thisFurnace.HeatPartLoadRatio), OnOffAirFlowRatio);
7166 :
7167 : } else {
7168 1402256 : CoolingHeatingPLRRatio = 1.0;
7169 1402256 : SetAverageAirFlow(state, FurnaceNum, PartLoadRatio, OnOffAirFlowRatio);
7170 : }
7171 :
7172 : // Get no load result (coils simulated OFF)
7173 1402258 : CalcFurnaceOutput(state,
7174 : FurnaceNum,
7175 : FirstHVACIteration,
7176 : fanOp,
7177 : compressorOp,
7178 : MinPLR,
7179 : PartLoadRatio,
7180 : 0.0,
7181 : 0.0,
7182 : NoCoolOutput,
7183 : NoLatentOutput,
7184 : OnOffAirFlowRatio,
7185 1402258 : HXUnitOn,
7186 : CoolingHeatingPLRRatio);
7187 :
7188 : // Don't calculate full load output if no load output can meet sensible load
7189 1402258 : if (NoCoolOutput >= CoolCoilLoad && (CoolCoilLoad != 0.0 || state.dataFurnaces->HPDehumidificationLoadFlag)) {
7190 : // Set full mass flow rate for full load calculation
7191 1254656 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.MdotFurnace;
7192 :
7193 : // Set fan part-load fraction equal to 1 while getting full load result
7194 1254656 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
7195 1254656 : OnOffAirFlowRatio = 1.0;
7196 1254656 : PartLoadRatio = 1.0;
7197 1254656 : thisFurnace.CompPartLoadRatio = 1.0; // compressor ON
7198 :
7199 : // Get full load result (coils simulated full ON)
7200 1254656 : CalcFurnaceOutput(state,
7201 : FurnaceNum,
7202 : FirstHVACIteration,
7203 : fanOp,
7204 : compressorOp,
7205 : PartLoadRatio,
7206 : 0.0,
7207 : 0.0,
7208 : 0.0,
7209 : FullSensibleOutput,
7210 : FullLatentOutput,
7211 : OnOffAirFlowRatio,
7212 1254656 : HXUnitOn);
7213 : } else {
7214 147602 : FullSensibleOutput = NoCoolOutput - 0.00000001;
7215 : }
7216 :
7217 : // The next step is to compare the results of the full load and no load results
7218 : // 1) Since we are cooling, we expect FullSensibleOutput < NoCoolOutput
7219 : // Check that this is the case; if not set PartLoadRatio = 0.0 (off)
7220 : // 2) Verify that the load to be met is within the range of available output
7221 : // (i.e. between FullSensibleOutput and NoCoolOutput)
7222 : // 3) Set PLR if load is out of range or RegulaFalsi on PLR if system can meet the load
7223 1402258 : if (FullSensibleOutput < NoCoolOutput) {
7224 1397548 : if (CoolCoilLoad != 0.0 || state.dataFurnaces->HPDehumidificationLoadFlag) {
7225 :
7226 : // check bounds on sensible output prior to iteration using RegulaFalsi
7227 : // Negative value represents cooling load, IF FullSensibleOutput .GT. CoolCoilLoad, load is greater than capacity
7228 1252012 : if (FullSensibleOutput >= CoolCoilLoad) {
7229 113274 : PartLoadRatio = 1.0;
7230 : // Likewise IF NoCoolOutput .LT. CoolCoilLoad, then load can be met using only the fan (constant fan mode only)
7231 1138738 : } else if (NoCoolOutput <= CoolCoilLoad) {
7232 2066 : PartLoadRatio = 0.0;
7233 : // ELSE load is between NoCoolOutput and FullSensibleOuput, find PLR required to meet load
7234 : } else {
7235 :
7236 : // Calculate the sensible part load ratio through iteration
7237 1136672 : CoolErrorToler = thisFurnace.CoolingConvergenceTolerance; // Error tolerance for convergence from input deck
7238 1136672 : int SolFlag = 0; // # of iterations if positive, -1 means failed to converge, -2 means bounds are incorrect
7239 1136672 : Real64 par8_HXFlag = HXUnitOn ? 1.0 : 0.0;
7240 : // CoolErrorToler is in fraction of load, MaxIter = 30, SolFalg = # of iterations or error as appropriate
7241 : auto f =
7242 5451712 : [&state, FurnaceNum, FirstHVACIteration, fanOp, compressorOp, CoolCoilLoad, par8_HXFlag](Real64 const PartLoadRatio) {
7243 4315040 : return CalcFurnaceResidual(state,
7244 : PartLoadRatio,
7245 : FurnaceNum,
7246 : FirstHVACIteration,
7247 : fanOp,
7248 : compressorOp,
7249 : CoolCoilLoad,
7250 : 1.0, // par6_loadFlag,
7251 : 1.0, // par7_sensLatentFlag,
7252 : par8_HXFlag, // par9_HXOnFlag,
7253 4315040 : 0.0); // par10_HeatingCoilPLR);
7254 1136672 : };
7255 1136672 : General::SolveRoot(state, CoolErrorToler, MaxIter, SolFlag, PartLoadRatio, f, 0.0, 1.0);
7256 : // OnOffAirFlowRatio is updated during the above iteration. Reset to correct value based on PLR.
7257 1136672 : OnOffAirFlowRatio = state.dataFurnaces->OnOffAirFlowRatioSave;
7258 1136672 : if (SolFlag < 0) {
7259 0 : if (SolFlag == -1) {
7260 0 : CalcFurnaceOutput(state,
7261 : FurnaceNum,
7262 : FirstHVACIteration,
7263 : fanOp,
7264 : compressorOp,
7265 : PartLoadRatio,
7266 : 0.0,
7267 : 0.0,
7268 : 0.0,
7269 : TempCoolOutput,
7270 : TempLatentOutput,
7271 : OnOffAirFlowRatio,
7272 0 : HXUnitOn);
7273 0 : if (!state.dataGlobal->WarmupFlag) {
7274 0 : if (std::abs(CoolCoilLoad - TempCoolOutput) > HVAC::SmallLoad) {
7275 0 : if (thisFurnace.SensibleMaxIterIndex == 0) {
7276 0 : ShowWarningMessage(state,
7277 0 : format("Cooling coil control failed to converge for {}:{}",
7278 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7279 0 : thisFurnace.Name));
7280 0 : ShowContinueError(
7281 : state, " Iteration limit exceeded in calculating DX cooling coil sensible part-load ratio.");
7282 0 : ShowContinueErrorTimeStamp(state,
7283 0 : format("Sensible load to be met by DX coil = {:.2T} (watts), sensible "
7284 : "output of DX coil = {:.2T} (watts), and the simulation continues.",
7285 : CoolCoilLoad,
7286 : TempCoolOutput));
7287 : }
7288 0 : ShowRecurringWarningErrorAtEnd(
7289 : state,
7290 0 : format("{} \"{}\" - Iteration limit exceeded in calculating sensible cooling "
7291 : "part-load ratio error continues. Sensible load statistics:",
7292 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7293 0 : thisFurnace.Name),
7294 0 : thisFurnace.SensibleMaxIterIndex,
7295 : CoolCoilLoad,
7296 : CoolCoilLoad);
7297 : }
7298 : }
7299 0 : } else if (SolFlag == -2) {
7300 0 : if (!state.dataGlobal->WarmupFlag) {
7301 0 : if (thisFurnace.SensibleRegulaFalsiFailedIndex == 0) {
7302 0 : ShowWarningMessage(state,
7303 0 : format("Cooling coil control failed for {}:{}",
7304 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7305 0 : thisFurnace.Name));
7306 0 : ShowContinueError(state, " Cooling sensible part-load ratio determined to be outside the range of 0-1.");
7307 0 : ShowContinueErrorTimeStamp(state, format(" Cooling sensible load = {:.2T}", CoolCoilLoad));
7308 : }
7309 0 : ShowRecurringWarningErrorAtEnd(
7310 : state,
7311 0 : format("{} \"{}\" - Cooling sensible part-load ratio out of range error continues. Sensible cooling load "
7312 : "statistics:",
7313 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7314 0 : thisFurnace.Name),
7315 0 : thisFurnace.SensibleRegulaFalsiFailedIndex,
7316 : CoolCoilLoad,
7317 : CoolCoilLoad);
7318 : }
7319 : }
7320 : }
7321 : }
7322 :
7323 : } else {
7324 145536 : PartLoadRatio = 0.0;
7325 : } // EndIf for IF(CoolCoilLoad.NE.0.0)
7326 :
7327 : // Calculate the delivered capacity from the PLR caculated above
7328 1397548 : CalcFurnaceOutput(state,
7329 : FurnaceNum,
7330 : FirstHVACIteration,
7331 : fanOp,
7332 : compressorOp,
7333 : PartLoadRatio,
7334 : thisFurnace.HeatPartLoadRatio,
7335 : 0.0,
7336 : 0.0,
7337 : TempCoolOutput,
7338 : TempLatentOutput,
7339 : OnOffAirFlowRatio,
7340 1397548 : HXUnitOn);
7341 :
7342 : // Calculate the latent part load ratio through iteration
7343 : // Negative SystemMoistureLoad means dehumidification load is present
7344 : // IF this furnace uses MultiMode control AND there is a moisture load AND the moisture load met by the furnace in
7345 : // cooling only mode above is sufficient to meet the moisture demand OR there is no sensible load (PLR=0 from above)
7346 : // then set LatentPartLoadRatio to 0 (no additional dehumidification is required).
7347 1397548 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::Multimode &&
7348 8440 : ((SystemMoistureLoad < 0.0 && TempLatentOutput < SystemMoistureLoad) || PartLoadRatio == 0.0)) {
7349 634 : LatentPartLoadRatio = 0.0;
7350 : // ELSE calculate a new PLR for valid dehumidification control types if a moisture load exists.
7351 1664029 : } else if (thisFurnace.DehumidControlType_Num != DehumidificationControlMode::None &&
7352 267115 : (SystemMoistureLoad < 0.0 || (SystemMoistureLoad >= 0.0 && TempLatentOutput > SystemMoistureLoad &&
7353 8816 : !state.dataZoneEnergyDemand->Setback(thisFurnace.ControlZoneNum)))) {
7354 :
7355 : // IF the furnace uses dehumidification control MultiMode, turn on the HX and calculate the latent output with
7356 : // the HX ON to compare to the moisture load predicted by the humidistat.
7357 188058 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::Multimode) {
7358 7580 : HXUnitOn = true;
7359 7580 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.MdotFurnace;
7360 : // Set fan part-load fraction equal to 1 while getting full load result
7361 7580 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
7362 7580 : OnOffAirFlowRatio = 1.0;
7363 : // Get full load result
7364 7580 : CalcFurnaceOutput(state,
7365 : FurnaceNum,
7366 : FirstHVACIteration,
7367 : fanOp,
7368 : compressorOp,
7369 : 1.0,
7370 : 0.0,
7371 : 0.0,
7372 : 0.0,
7373 : TempCoolOutput,
7374 : TempLatentOutput,
7375 : OnOffAirFlowRatio,
7376 7580 : HXUnitOn);
7377 : }
7378 :
7379 : // Set the global cooling to heating PLR ratio. CoolHeatPLRRat = MIN(1,CoolingPLR/HeatingPLR)
7380 188058 : state.dataFurnaces->CoolHeatPLRRat = 1.0; // means cooling dominated operation (applies to cycling fan mode)
7381 :
7382 188058 : if (TempLatentOutput > SystemMoistureLoad) {
7383 : // Set full mass flow rate for full load calculation
7384 184495 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.MdotFurnace;
7385 :
7386 : // Set fan part-load fraction equal to 1 while getting full load result
7387 184495 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
7388 184495 : OnOffAirFlowRatio = 1.0;
7389 184495 : thisFurnace.CompPartLoadRatio = 1.0; // compressor ON
7390 :
7391 : // Get full load result (coils simulated full ON)
7392 184495 : CalcFurnaceOutput(state,
7393 : FurnaceNum,
7394 : FirstHVACIteration,
7395 : fanOp,
7396 : compressorOp,
7397 : 1.0,
7398 : 0.0,
7399 : 0.0,
7400 : 0.0,
7401 : TempCoolOutput,
7402 : TempLatentOutput,
7403 : OnOffAirFlowRatio,
7404 184495 : HXUnitOn);
7405 : }
7406 :
7407 : // check bounds on latent output prior to iteration using RegulaFalsi
7408 188058 : if (TempLatentOutput > SystemMoistureLoad ||
7409 55180 : (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::Multimode && TempCoolOutput > CoolCoilLoad)) {
7410 132878 : LatentPartLoadRatio = 1.0;
7411 55180 : } else if (NoLatentOutput < SystemMoistureLoad || HeatingLatentOutput < SystemMoistureLoad) {
7412 94 : LatentPartLoadRatio = 0.0;
7413 : } else {
7414 :
7415 55086 : CoolErrorToler = thisFurnace.CoolingConvergenceTolerance; // Error tolerance for convergence
7416 :
7417 55086 : int SolFlag = 0; // # of iterations if positive, -1 means failed to converge, -2 means bounds are incorrect
7418 : // Multimode always controls to meet the SENSIBLE load (however, HXUnitOn is now TRUE)
7419 : Real64 par4_load;
7420 55086 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::Multimode) {
7421 772 : par4_load = CoolCoilLoad;
7422 : } else {
7423 54314 : par4_load = SystemMoistureLoad;
7424 : }
7425 : // Multimode always controls to meet the SENSIBLE load (however, HXUnitOn is now TRUE)
7426 : Real64 par6_LatentSens;
7427 55086 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::Multimode) {
7428 772 : par6_LatentSens = 1.0;
7429 : } else {
7430 54314 : par6_LatentSens = 0.0;
7431 : }
7432 55086 : Real64 par8_HXUnit = HXUnitOn ? 1.0 : 0.0;
7433 : Real64 par9_HtgCoilPLR;
7434 55086 : if (fanOp == HVAC::FanOp::Cycling && thisFurnace.HeatPartLoadRatio > 0.0 && par6_LatentSens == 0.0) {
7435 0 : par9_HtgCoilPLR = thisFurnace.HeatPartLoadRatio;
7436 : } else {
7437 55086 : par9_HtgCoilPLR = 0.0;
7438 : }
7439 448688 : auto f = [&state,
7440 : FurnaceNum,
7441 : FirstHVACIteration,
7442 : fanOp,
7443 : compressorOp,
7444 : par4_load,
7445 : par6_LatentSens,
7446 : par8_HXUnit,
7447 448688 : par9_HtgCoilPLR](Real64 const PartLoadRatio) {
7448 448688 : return CalcFurnaceResidual(state,
7449 : PartLoadRatio,
7450 : FurnaceNum,
7451 : FirstHVACIteration,
7452 : fanOp,
7453 : compressorOp,
7454 : par4_load,
7455 : 1.0, // par6_loadFlag,
7456 : par6_LatentSens, // par7_sensLatentFlag,
7457 : par8_HXUnit, // par9_HXOnFlag,
7458 448688 : par9_HtgCoilPLR); // par10_HeatingCoilPLR);
7459 55086 : };
7460 : // CoolErrorToler is in fraction of load, MaxIter = 30, SolFalg = # of iterations or error as appropriate
7461 55086 : General::SolveRoot(state, CoolErrorToler, MaxIter, SolFlag, LatentPartLoadRatio, f, 0.0, 1.0);
7462 : // OnOffAirFlowRatio is updated during the above iteration. Reset to correct value based on PLR.
7463 55086 : OnOffAirFlowRatio = state.dataFurnaces->OnOffAirFlowRatioSave;
7464 55086 : if (SolFlag == -1) {
7465 : // RegulaFalsi may not find latent PLR when the latent degradation model is used.
7466 : // If iteration limit is exceeded, find tighter boundary of solution and repeat RegulaFalsi
7467 98 : TempMaxPLR = -0.1;
7468 98 : TempLatentOutput = NoLatentOutput;
7469 498 : while ((TempLatentOutput - SystemMoistureLoad) > 0.0 && TempMaxPLR < 1.0) {
7470 : // find upper limit of LatentPLR
7471 400 : TempMaxPLR += 0.1;
7472 :
7473 : // Same calculation as is done in Function CalcFurnaceResidual for latent PLR calculation.
7474 : // Set cooling to heating PLR for use with Subroutine CalcFurnaceOutput. IF Par(10) = 0,
7475 : // heating PLR = 0 so set the CoolingHeatingPLRRatio to 1 so the cooling PLR is used in the
7476 : // DX cooling coil calculations.
7477 400 : if (par9_HtgCoilPLR > 0.0) {
7478 : // Par(10) = Furnace(FurnaceNum)%HeatPartLoadRatio
7479 : // fanOp = CycFan and Furnace(FurnaceNum)%HeatPartLoadRatio must be > 0 for Part(10) to be
7480 : // greater than 0
7481 0 : CoolingHeatingPLRRatio = min(1.0, TempMaxPLR / thisFurnace.HeatPartLoadRatio);
7482 : } else {
7483 400 : CoolingHeatingPLRRatio = 1.0;
7484 : }
7485 :
7486 400 : CalcFurnaceOutput(state,
7487 : FurnaceNum,
7488 : FirstHVACIteration,
7489 : fanOp,
7490 : compressorOp,
7491 : TempMaxPLR,
7492 : 0.0,
7493 : 0.0,
7494 : 0.0,
7495 : TempCoolOutput,
7496 : TempLatentOutput,
7497 : OnOffAirFlowRatio,
7498 400 : HXUnitOn,
7499 : CoolingHeatingPLRRatio);
7500 : }
7501 98 : TempMinPLR = TempMaxPLR;
7502 876 : while ((TempLatentOutput - SystemMoistureLoad) < 0.0 && TempMinPLR > 0.0) {
7503 : // pull upper limit of LatentPLR down to last valid limit (i.e. latent output still exceeds
7504 : // SystemMoisuterLoad) CR7558 - relax final limits to allow HX assisted coils to converge
7505 778 : TempMaxPLR = TempMinPLR + 0.001;
7506 : // find minimum limit of Latent PLR
7507 778 : TempMinPLR -= 0.001;
7508 :
7509 : // Set cooling to heating PLR for use with Subroutine CalcFurnaceOutput.
7510 778 : if (par9_HtgCoilPLR > 0.0) {
7511 : // Par(10) = Furnace(FurnaceNum)%HeatPartLoadRatio
7512 : // fanOp = CycFan and Furnace(FurnaceNum)%HeatPartLoadRatio must be > 0 for Part(10) to be
7513 : // greater than 0 Since the latent output of cycling fan systems is 0 at PLR=0, do not allow
7514 : // the PLR to be 0, otherwise RegulaFalsi can fail when a heating and moisture load exists and
7515 : // heating PLR > latent PLR.
7516 0 : TempMinPLR2 = max(0.0000000001, TempMinPLR);
7517 0 : CoolingHeatingPLRRatio = min(1.0, TempMinPLR2 / thisFurnace.HeatPartLoadRatio);
7518 : } else {
7519 778 : TempMinPLR2 = TempMinPLR;
7520 778 : CoolingHeatingPLRRatio = 1.0;
7521 : }
7522 :
7523 778 : CalcFurnaceOutput(state,
7524 : FurnaceNum,
7525 : FirstHVACIteration,
7526 : fanOp,
7527 : compressorOp,
7528 : TempMinPLR2,
7529 : 0.0,
7530 : 0.0,
7531 : 0.0,
7532 : TempCoolOutput,
7533 : TempLatentOutput,
7534 : OnOffAirFlowRatio,
7535 778 : HXUnitOn,
7536 : CoolingHeatingPLRRatio);
7537 : }
7538 : // tighter boundary of solution has been found, call RegulaFalsi a second time
7539 494 : auto f2 = [&state,
7540 : FurnaceNum,
7541 : FirstHVACIteration,
7542 : fanOp,
7543 : compressorOp,
7544 : par4_load,
7545 : par6_LatentSens,
7546 : par8_HXUnit,
7547 494 : par9_HtgCoilPLR](Real64 const PartLoadRatio) {
7548 494 : return CalcFurnaceResidual(state,
7549 : PartLoadRatio,
7550 : FurnaceNum,
7551 : FirstHVACIteration,
7552 : fanOp,
7553 : compressorOp,
7554 : par4_load,
7555 : 1.0, // par6_loadFlag,
7556 : par6_LatentSens, // par7_sensLatentFlag,
7557 : par8_HXUnit, // par9_HXOnFlag,
7558 494 : par9_HtgCoilPLR); // par10_HeatingCoilPLR);
7559 98 : };
7560 98 : General::SolveRoot(state, CoolErrorToler, MaxIter, SolFlag, LatentPartLoadRatio, f2, TempMinPLR2, TempMaxPLR);
7561 : // OnOffAirFlowRatio is updated during the above iteration. Reset to correct value based on PLR.
7562 98 : OnOffAirFlowRatio = state.dataFurnaces->OnOffAirFlowRatioSave;
7563 98 : if (SolFlag == -1) {
7564 :
7565 : // Set cooling to heating PLR for use with Subroutine CalcFurnaceOutput.
7566 48 : if (par9_HtgCoilPLR > 0.0) {
7567 : // Par(10) = Furnace(FurnaceNum)%HeatPartLoadRatio
7568 : // fanOp = CycFan and Furnace(FurnaceNum)%HeatPartLoadRatio must be > 0 for Part(10) to be
7569 : // greater than 0
7570 0 : CoolingHeatingPLRRatio = min(1.0, LatentPartLoadRatio / thisFurnace.HeatPartLoadRatio);
7571 : } else {
7572 48 : CoolingHeatingPLRRatio = 1.0;
7573 : }
7574 :
7575 48 : CalcFurnaceOutput(state,
7576 : FurnaceNum,
7577 : FirstHVACIteration,
7578 : fanOp,
7579 : compressorOp,
7580 : LatentPartLoadRatio,
7581 : 0.0,
7582 : 0.0,
7583 : 0.0,
7584 : TempCoolOutput,
7585 : TempLatentOutput,
7586 : OnOffAirFlowRatio,
7587 48 : HXUnitOn,
7588 : CoolingHeatingPLRRatio);
7589 96 : if (std::abs((SystemMoistureLoad - TempLatentOutput) / SystemMoistureLoad) > CoolErrorToler &&
7590 48 : std::abs(SystemMoistureLoad - TempLatentOutput) > 10.0) {
7591 0 : if (!state.dataGlobal->WarmupFlag) {
7592 0 : if (thisFurnace.LatentMaxIterIndex == 0) {
7593 0 : ShowWarningMessage(state,
7594 0 : format("Cooling coil control failed to converge for {}:{}",
7595 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7596 0 : thisFurnace.Name));
7597 0 : ShowContinueError(state,
7598 : " Iteration limit exceeded in calculating cooling coil latent part-load ratio.");
7599 0 : ShowContinueError(
7600 : state,
7601 0 : format(" Latent load convergence error (percent) = {:.2T}",
7602 0 : 100.0 * std::abs((SystemMoistureLoad - TempLatentOutput) / SystemMoistureLoad)));
7603 0 : ShowContinueErrorTimeStamp(state,
7604 0 : format("Moisture load to be met by DX coil = {:.2T} (watts), Latent "
7605 : "output of DX coil = {:.2T} (watts), and the simulation continues.",
7606 : SystemMoistureLoad,
7607 : TempLatentOutput));
7608 : }
7609 0 : ShowRecurringWarningErrorAtEnd(
7610 : state,
7611 0 : format("{} \"{}\" - Iteration limit exceeded in calculating latent part-load ratio error continues. "
7612 : "Latent "
7613 : "load convergence error (percent) statistics follow.",
7614 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7615 0 : thisFurnace.Name),
7616 0 : thisFurnace.LatentMaxIterIndex,
7617 0 : 100.0 * std::abs((SystemMoistureLoad - TempLatentOutput) / SystemMoistureLoad),
7618 0 : 100.0 * std::abs((SystemMoistureLoad - TempLatentOutput) / SystemMoistureLoad));
7619 : }
7620 : }
7621 50 : } else if (SolFlag == -2) {
7622 0 : if (thisFurnace.LatentRegulaFalsiFailedIndex2 == 0) {
7623 0 : ShowWarningMessage(state,
7624 0 : format("Cooling coil control failed for {}:{}",
7625 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7626 0 : thisFurnace.Name));
7627 0 : ShowContinueError(state,
7628 0 : format(" Latent part-load ratio determined to be outside the range of {:.3T} to {:.3T}.",
7629 : TempMinPLR,
7630 : TempMaxPLR));
7631 0 : ShowContinueErrorTimeStamp(state,
7632 0 : format("A PLR of {:.3T} will be used and the simulation continues.", TempMinPLR));
7633 : }
7634 0 : ShowRecurringWarningErrorAtEnd(state,
7635 0 : format("{} \"{}\" - Cooling sensible part-load ratio out of range error "
7636 : "continues. System moisture load statistics:",
7637 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7638 0 : thisFurnace.Name),
7639 0 : thisFurnace.LatentRegulaFalsiFailedIndex2,
7640 : SystemMoistureLoad,
7641 : SystemMoistureLoad);
7642 0 : LatentPartLoadRatio = TempMinPLR;
7643 : }
7644 54988 : } else if (SolFlag == -2) {
7645 0 : if (thisFurnace.LatentRegulaFalsiFailedIndex == 0) {
7646 0 : ShowWarningMessage(state,
7647 0 : format("Cooling coil control failed for {}:{}",
7648 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7649 0 : thisFurnace.Name));
7650 0 : ShowContinueError(state, " Latent part-load ratio determined to be outside the range of 0-1.");
7651 0 : ShowContinueErrorTimeStamp(state, "A PLR of 0 will be used and the simulation continues.");
7652 : }
7653 0 : ShowRecurringWarningErrorAtEnd(
7654 : state,
7655 0 : format("{} \"{}\" - Latent part-load ratio out of range or 0-1 error continues. System moisture load statistics:",
7656 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
7657 0 : thisFurnace.Name),
7658 0 : thisFurnace.LatentRegulaFalsiFailedIndex,
7659 : SystemMoistureLoad,
7660 : SystemMoistureLoad);
7661 0 : LatentPartLoadRatio = 0.0;
7662 : }
7663 : }
7664 :
7665 : // Cooling to heating PLR ratio is now known as CoolHeatPLRRat (Module level global set in CalcFurnaceOutput
7666 : // This same variable is use in Subroutine SimFurnace for final calculations.
7667 : // Get the actual output in case reheat needs to be calculated (HumControl=TRUE [latent PLR > sensible PLR])
7668 188058 : CalcFurnaceOutput(state,
7669 : FurnaceNum,
7670 : FirstHVACIteration,
7671 : fanOp,
7672 : compressorOp,
7673 : LatentPartLoadRatio,
7674 : 0.0,
7675 : 0.0,
7676 : 0.0,
7677 : ActualSensibleOutput,
7678 : ActualLatentOutput,
7679 : OnOffAirFlowRatio,
7680 188058 : HXUnitOn,
7681 188058 : state.dataFurnaces->CoolHeatPLRRat);
7682 :
7683 : } else {
7684 1208856 : LatentPartLoadRatio = 0.0;
7685 : } // ENDIF for valid dehumidification control types
7686 :
7687 : // IF a humidistat is used and there is a moisture load, check if the latent PLR is greater than the (sensible) PLR
7688 : // IF(LatentPartLoadRatio .GT. PartLoadRatio .and. SystemMoistureLoad .lt. 0.0 .and. Furnace(FurnaceNum)%Humidistat) THEN
7689 1397548 : if (LatentPartLoadRatio > PartLoadRatio && thisFurnace.Humidistat) {
7690 : // For dehumidification mode CoolReheat, compare the Sensible and Latent PLR values, if latentPLR is greater
7691 : // than PLR (sensible), then overcooling is required and reheat will be activated using the HumControl flag.
7692 185083 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat) {
7693 177589 : PartLoadRatio = LatentPartLoadRatio;
7694 177589 : HumControl = true;
7695 : }
7696 : // For dehumidification mode MultiMode, compare the Sensible and Latent PLR values, if latentPLR is
7697 : // greater than PLR (sensible), then use the latent PLR to control the unit.
7698 : // For MultiMode control, the latent PLR is found by enabling the HX and calculating a PLR required to meet the
7699 : // sensible load. Overcooling is not required, and reheat will not be activated using the HumControl flag.
7700 185083 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::Multimode) {
7701 7494 : PartLoadRatio = LatentPartLoadRatio;
7702 : }
7703 : }
7704 :
7705 1397548 : thisFurnace.CoolPartLoadRatio = PartLoadRatio;
7706 1397548 : if (compressorOp == HVAC::CompressorOp::Off) {
7707 4090 : thisFurnace.CompPartLoadRatio = 0.0;
7708 : } else {
7709 1393458 : thisFurnace.CompPartLoadRatio = PartLoadRatio;
7710 : }
7711 :
7712 : } else { // ELSE from IF(FullSensibleOutput.LT.NoCoolOutput)THEN above
7713 : // CR8679 - Unitary Heat Cool control problem, will not run to meeting cooling load
7714 : // underlying problem is that FullSensibleOutput is greater than 0 due to very high inlet temp, so the system should be on
7715 : // NoCoolOutput was 0 since the defect file is a cycling fan system and the system was turned off
7716 :
7717 : // if FullSensibleOutput > NoCoolOutput, it means the system cannot meet the load and will run full out
7718 : // this same logic for WSHP does not seem to work (only the Unitary Heat Pump Compressor Part-Load Ratio report
7719 : // variable was affected in the HeatPumpWaterToAirRHControl.idf file while other variables showed very small diffs).
7720 : // The defect files meter.csv showed 2% diffs so this IF test is used to keep the results the same in that file.
7721 : // Additional logic is used here to make sure the coil actually turned on, e.g., if DX coil PLR > 0 then set to 1,
7722 : // otherwise 0 (to make sure coil is actually ON and not off due to schedule, OAT, or other reason).
7723 : // The global variable DXCoilPartLoadRatio(DXCoilNum) is not yet used for the WSHP to make the same check.
7724 4710 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir) {
7725 230 : thisFurnace.CoolPartLoadRatio = 0.0;
7726 230 : thisFurnace.CompPartLoadRatio = 0.0;
7727 : } else {
7728 4480 : if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) {
7729 :
7730 : // VS coil issue here...
7731 0 : if (state.dataDXCoils->DXCoilPartLoadRatio(thisFurnace.ActualDXCoilIndexForHXAssisted) > 0.0) {
7732 0 : thisFurnace.CoolPartLoadRatio = 1.0;
7733 0 : thisFurnace.CompPartLoadRatio = 1.0;
7734 : } else {
7735 0 : thisFurnace.CoolPartLoadRatio = 0.0;
7736 0 : thisFurnace.CompPartLoadRatio = 0.0;
7737 : }
7738 : } else {
7739 4480 : if (state.dataDXCoils->DXCoilPartLoadRatio(thisFurnace.CoolingCoilIndex) > 0.0) {
7740 0 : thisFurnace.CoolPartLoadRatio = 1.0;
7741 0 : thisFurnace.CompPartLoadRatio = 1.0;
7742 : } else {
7743 4480 : thisFurnace.CoolPartLoadRatio = 0.0;
7744 4480 : thisFurnace.CompPartLoadRatio = 0.0;
7745 : }
7746 : }
7747 : }
7748 : }
7749 :
7750 : // Calculate the reheat coil output
7751 1402258 : if (HumControl) { // HumControl = .TRUE. if a Humidistat is installed and dehumdification control type is CoolReheat
7752 177589 : if (thisFurnace.ZoneSequenceHeatingNum > 0) {
7753 177589 : QToHeatSetPt = (state.dataZoneEnergyDemand->ZoneSysEnergyDemand(thisFurnace.ControlZoneNum)
7754 177589 : .SequencedOutputRequiredToHeatingSP(thisFurnace.ZoneSequenceHeatingNum) /
7755 177589 : thisFurnace.ControlZoneMassFlowFrac);
7756 : } else {
7757 0 : QToHeatSetPt = (state.dataZoneEnergyDemand->ZoneSysEnergyDemand(thisFurnace.ControlZoneNum).OutputRequiredToHeatingSP /
7758 0 : thisFurnace.ControlZoneMassFlowFrac);
7759 : }
7760 : // Cooling mode or floating condition and dehumidification is required
7761 177589 : if (QToHeatSetPt < 0.0) {
7762 : // Calculate the reheat coil load wrt the heating setpoint temperature. Reheat coil picks up
7763 : // the entire excess sensible cooling (DX cooling coil and impact of outdoor air).
7764 165238 : ReheatCoilLoad = max(0.0, (QToHeatSetPt - ActualSensibleOutput));
7765 165238 : thisFurnace.DehumidInducedHeatingDemandRate = ReheatCoilLoad;
7766 : // Heating mode and dehumidification is required
7767 : } else {
7768 : // Calculate the reheat coil load as the sensible capacity of the DX cooling coil only. Let
7769 : // the heating coil pick up the load due to outdoor air.
7770 12351 : ReheatCoilLoad = max(0.0, (ActualSensibleOutput - NoCoolOutput) * (-1.0));
7771 : // Dehumidification is not required
7772 12351 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir ||
7773 10293 : (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir &&
7774 7122 : thisFurnace.WatertoAirHPType == WAHPCoilType::Simple)) {
7775 9180 : ReheatCoilLoad = max(QToHeatSetPt, QToHeatSetPt - ActualSensibleOutput);
7776 : }
7777 12351 : thisFurnace.DehumidInducedHeatingDemandRate = max(0.0, ActualSensibleOutput * (-1.0));
7778 : }
7779 : } else {
7780 : // No humidistat installed
7781 1224669 : ReheatCoilLoad = 0.0;
7782 : }
7783 : } // End of cooling section IF statement
7784 :
7785 3002440 : if (NoHeatOutput > SystemSensibleLoad && ReheatCoilLoad > 0.0) {
7786 : // Reduce reheat coil load if you are controlling high humidity but outside air
7787 : // and/or the supply air fan is providing enough heat to meet the system sensible load.
7788 : // This will bring the zone temp closer to the heating setpoint temp.
7789 0 : ReheatCoilLoad = max(0.0, ReheatCoilLoad - (NoHeatOutput - SystemSensibleLoad));
7790 : }
7791 :
7792 : // Set the final air flow. MdotFurnace will be used to set the fan part-load ratio in ReportFurnace
7793 3002440 : if (HumControl && SystemMoistureLoad < 0.0) {
7794 169165 : if (fanOp == HVAC::FanOp::Cycling) {
7795 : // set the flow rate at the maximum of the cooling and heating PLR's
7796 420 : SetAverageAirFlow(state, FurnaceNum, max(thisFurnace.CoolPartLoadRatio, thisFurnace.HeatPartLoadRatio), OnOffAirFlowRatio);
7797 : } else {
7798 : // ELSE set the flow rate at the cooling PLR
7799 168745 : SetAverageAirFlow(state, FurnaceNum, thisFurnace.CoolPartLoadRatio, OnOffAirFlowRatio);
7800 : }
7801 : } else {
7802 2833275 : SetAverageAirFlow(state, FurnaceNum, max(thisFurnace.CoolPartLoadRatio, thisFurnace.HeatPartLoadRatio), OnOffAirFlowRatio);
7803 : }
7804 3002440 : thisFurnace.MdotFurnace = state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate;
7805 :
7806 3002440 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir ||
7807 2754158 : (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir && thisFurnace.WatertoAirHPType == WAHPCoilType::Simple)) {
7808 : } else {
7809 : // Non-HeatPump (non-DX) heating coils do not set PLR, reset to 0 here. This variable was set for non-DX
7810 : // coils to allow the SetAverageAirFlow CALL above to set the correct air mass flow rate. See this
7811 : // IF block above in heating section. HeatPLR is not set in the ELSE part of the IF (only HeatCoilLoad is set).
7812 1401558 : thisFurnace.HeatPartLoadRatio = 0.0;
7813 : }
7814 :
7815 : //*********HVAC Scheduled OFF*************
7816 : // No heating or cooling or dehumidification
7817 : //!!LKL discrepancy with < 0?
7818 5927599 : if (ScheduleManager::GetCurrentScheduleValue(state, thisFurnace.SchedPtr) == 0.0 ||
7819 2925159 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate == 0.0) {
7820 248712 : thisFurnace.MdotFurnace = 0.0;
7821 248712 : CoolCoilLoad = 0.0;
7822 248712 : HeatCoilLoad = 0.0;
7823 248712 : ReheatCoilLoad = 0.0;
7824 248712 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0; // System off, so set on/off fan part-load fraction = 1
7825 248712 : thisFurnace.CoolPartLoadRatio = 0.0;
7826 248712 : thisFurnace.HeatPartLoadRatio = 0.0;
7827 248712 : thisFurnace.CompPartLoadRatio = 0.0;
7828 : // set report variables
7829 248712 : thisFurnace.CoolingCoilSensDemand = 0.0;
7830 248712 : thisFurnace.CoolingCoilLatentDemand = 0.0;
7831 248712 : thisFurnace.HeatingCoilSensDemand = 0.0;
7832 : }
7833 :
7834 : } // End of the FirstHVACIteration control of the mass flow If block
7835 :
7836 : // Set the fan inlet node flow rates
7837 4597475 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRateMaxAvail = thisFurnace.MdotFurnace;
7838 4597475 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.MdotFurnace;
7839 4597475 : }
7840 :
7841 119270 : void CalcWaterToAirHeatPump(EnergyPlusData &state,
7842 : int const FurnaceNum, // index to Furnace
7843 : bool const FirstHVACIteration, // TRUE on first HVAC iteration
7844 : HVAC::CompressorOp const compressorOp, // compressor operation flag (1=On, 0=Off)
7845 : Real64 const ZoneLoad, // the control zone load (watts)
7846 : Real64 const MoistureLoad // the control zone latent load (watts)
7847 : )
7848 : {
7849 :
7850 : // SUBROUTINE INFORMATION:
7851 : // AUTHOR Dan Fisher
7852 : // DATE WRITTEN Feb 2004
7853 : // MODIFIED R. Raustad (Oct 2006) Revised iteration technique
7854 :
7855 : // PURPOSE OF THIS SUBROUTINE:
7856 : // This subroutine manages the heat pump simulation
7857 :
7858 : // METHODOLOGY EMPLOYED:
7859 : // Calculate the part-load ratio required to meet the zone sensible load.
7860 :
7861 : // SUBROUTINE PARAMETER DEFINITIONS:
7862 119270 : int constexpr MaxIter(600); // maximum number of iterations
7863 119270 : Real64 constexpr MinPLR(0.0); // minimum part load ratio allowed
7864 :
7865 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
7866 : Real64 ZoneSensLoadMet; // Actual zone sensible load met by heat pump (W)
7867 : Real64 ZoneLatLoadMet; // Actual zone latent load met by heat pump (W)
7868 : Real64 ZoneSensLoadMetFanONCompON; // Max Zone sensible load heat pump can meet (W)
7869 : Real64 ZoneLatLoadMetFanONCompON; // Max Zone latentload heat pump can meet (W)
7870 : Real64 ZoneSensLoadMetFanONCompOFF; // control zone sensible load met using only outside air
7871 : // and fan heat (no coil output) (W)
7872 : Real64 ZoneLatLoadMetFanONCompOFF; // control zone Latent load met using only outside air
7873 : // and fan heat (no coil output) (W)
7874 : Real64 HPCoilSensDemand; // Heat pump sensible demand
7875 : Real64 HPCoilSensCapacity; // Heat pump sensible capacity
7876 :
7877 : Real64 SuppHeatCoilLoad; // Load passed to supplemental heater (W)
7878 : Real64 CoolErrorToler; // convergence tolerance used in cooling mode
7879 : Real64 HeatErrorToler; // convergence tolerance used in heating mode
7880 : int SolFlag; // flag returned from iteration routine to denote problems
7881 :
7882 119270 : Real64 &TotalZoneLatentLoad = state.dataFurnaces->TotalZoneLatentLoad;
7883 119270 : Real64 &TotalZoneSensLoad = state.dataFurnaces->TotalZoneSensLoad;
7884 119270 : Real64 &CoolPartLoadRatio = state.dataFurnaces->CoolPartLoadRatio;
7885 119270 : Real64 &HeatPartLoadRatio = state.dataFurnaces->HeatPartLoadRatio;
7886 119270 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
7887 :
7888 : // Set local variables
7889 119270 : Real64 Dummy2 = 0.0; // used as dummy heat and reheat coil load
7890 119270 : Real64 OnOffAirFlowRatio = 1.0; // Ratio of compressor ON air mass flow to AVERAGE air mass flow over time step
7891 119270 : int FurnaceInletNode = thisFurnace.FurnaceInletNodeNum;
7892 119270 : HVAC::FanOp fanOp = thisFurnace.fanOp; // fan operting mode
7893 119270 : thisFurnace.MdotFurnace = thisFurnace.DesignMassFlowRate;
7894 :
7895 : //*********INITIAL CALCULATIONS****************
7896 : // set the fan part load fraction
7897 : // Note: OnOffFanPartLoadFraction is passed to the
7898 : // fan module by DataHVACGlobals. It should be
7899 : // set =1 for all cases except cycling fan/cycling
7900 : // coil. For this case it is set to the part load
7901 : // factor. In SimOnOffFan, the part load ratio is
7902 : // divided by the part load factor (OnOffFanPartLoadFraction)
7903 : // in order to match the run time fraction of the cycling
7904 : // fan with the run time fraction of the cycling compressor
7905 119270 : if (FirstHVACIteration) state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
7906 :
7907 : // Calc Zone sensible loads for heating (+) and cooling (-)
7908 119270 : TotalZoneSensLoad = ZoneLoad;
7909 :
7910 119270 : if (state.dataFurnaces->HeatingLoad) {
7911 55271 : TotalZoneLatentLoad = 0.0; // Set latent load for heating
7912 : } else {
7913 63999 : TotalZoneLatentLoad = MoistureLoad; // Set latent load for cooling and no sensible load condition
7914 : }
7915 :
7916 : //*********COOLING CALCULATIONS****************
7917 : // IF scheduled on...
7918 : // AND air flow rate is greater than zero...
7919 : // AND the air system has a cooling load and is not set back or in the deadband...
7920 : // OR the system is controlled by a humidistat and there is a latent load
7921 119270 : if ((ScheduleManager::GetCurrentScheduleValue(state, thisFurnace.SchedPtr) > 0.0 &&
7922 212252 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate > 0.0) &&
7923 92982 : ((state.dataFurnaces->CoolingLoad) || (thisFurnace.Humidistat && thisFurnace.CoolingCoilLatentDemand < 0.0))) {
7924 :
7925 : // Set the air flow rate to the design flow rate and set the fan operation fraction to 1 (continuous operation)
7926 37711 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.DesignMassFlowRate;
7927 37711 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0; // see 'Note' under INITIAL CALCULATIONS
7928 :
7929 : // !Set the operation flag to run the fan continuously
7930 : // fanOp = FanOp::Continuous
7931 :
7932 : // Set the input parameters for CalcFurnaceOutput
7933 37711 : thisFurnace.HeatingCoilSensDemand = 0.0;
7934 37711 : thisFurnace.CoolingCoilLatentDemand = 0.0;
7935 37711 : thisFurnace.CoolingCoilSensDemand = 0.0;
7936 37711 : thisFurnace.CompPartLoadRatio = 0.0; // compressor off
7937 37711 : thisFurnace.InitHeatPump = true; // initialization call to Calc Furnace
7938 37711 : CoolPartLoadRatio = 0.0;
7939 :
7940 : // Get no load result in order to calculate the effect of the fan and the mixed air equipment
7941 37711 : CalcFurnaceOutput(state,
7942 : FurnaceNum,
7943 : FirstHVACIteration,
7944 : fanOp,
7945 : compressorOp,
7946 : CoolPartLoadRatio,
7947 : HeatPartLoadRatio,
7948 : Dummy2,
7949 : Dummy2,
7950 : ZoneSensLoadMetFanONCompOFF,
7951 : ZoneLatLoadMetFanONCompOFF,
7952 : OnOffAirFlowRatio,
7953 : false);
7954 :
7955 : // Set the input parameters for CalcFurnaceOutput
7956 37711 : thisFurnace.CoolingCoilSensDemand = 1.0;
7957 37711 : thisFurnace.CompPartLoadRatio = 1.0; // compressor ON
7958 37711 : CoolPartLoadRatio = 1.0;
7959 :
7960 : // Get full load result in order to estimate the operating part load ratio for continuous fan operation
7961 37711 : CalcFurnaceOutput(state,
7962 : FurnaceNum,
7963 : FirstHVACIteration,
7964 : fanOp,
7965 : compressorOp,
7966 : CoolPartLoadRatio,
7967 : HeatPartLoadRatio,
7968 : Dummy2,
7969 : Dummy2,
7970 : ZoneSensLoadMetFanONCompON,
7971 : ZoneLatLoadMetFanONCompON,
7972 : OnOffAirFlowRatio,
7973 : false);
7974 :
7975 : // Calculate the heating coil demand for continuous fan operation as:
7976 : // (the zone sensible load - the zone sensible load met by fan heat and mixed air)
7977 : // Note; The sensible zone load met by fan heat and mixed air is calculated as:
7978 : // mdotsys(control zone inlet enthalpy - control zone outlet enthalpy)
7979 : // This accounts for the negative sign in the equation.
7980 37711 : HPCoilSensDemand = TotalZoneSensLoad - ZoneSensLoadMetFanONCompOFF;
7981 :
7982 : // Calculate the heating coil capacity for continuous fan operation as:
7983 : // (the zone sensible load met by fan heat and mixed air and coil
7984 : // - the zone sensible load met by fan heat and mixed air)
7985 37711 : HPCoilSensCapacity = ZoneSensLoadMetFanONCompON - ZoneSensLoadMetFanONCompOFF;
7986 :
7987 : // Calculate the part load ratio for continuous fan operation with cycling coil
7988 37711 : if (HPCoilSensCapacity == 0.0) {
7989 0 : CoolPartLoadRatio = 0.0;
7990 : } else {
7991 37711 : CoolPartLoadRatio = max(MinPLR, min(1.0, std::abs(HPCoilSensDemand) / std::abs(HPCoilSensCapacity)));
7992 : }
7993 :
7994 37711 : thisFurnace.InitHeatPump = false;
7995 :
7996 : // check bounds on sensible output prior to iteration using RegulaFalsi
7997 37711 : if (ZoneSensLoadMetFanONCompON > TotalZoneSensLoad) {
7998 2160 : CoolPartLoadRatio = 1.0;
7999 2160 : HPCoilSensDemand = std::abs(ZoneSensLoadMetFanONCompON - ZoneSensLoadMetFanONCompOFF);
8000 2160 : thisFurnace.CoolingCoilSensDemand = HPCoilSensDemand;
8001 35551 : } else if (ZoneSensLoadMetFanONCompOFF < TotalZoneSensLoad) {
8002 0 : CoolPartLoadRatio = 0.0;
8003 0 : thisFurnace.CompPartLoadRatio = 0.0; // compressor OFF
8004 0 : thisFurnace.CoolingCoilSensDemand = 0.0;
8005 0 : CalcFurnaceOutput(state,
8006 : FurnaceNum,
8007 : FirstHVACIteration,
8008 : fanOp,
8009 : compressorOp,
8010 : CoolPartLoadRatio,
8011 : HeatPartLoadRatio,
8012 : Dummy2,
8013 : Dummy2,
8014 : ZoneSensLoadMetFanONCompOFF,
8015 : ZoneLatLoadMetFanONCompOFF,
8016 : OnOffAirFlowRatio,
8017 : false);
8018 : } else {
8019 : // Calculate the sensible part load ratio through iteration
8020 35551 : CoolErrorToler = thisFurnace.CoolingConvergenceTolerance;
8021 35551 : SolFlag = 0; // # of iterations if positive, -1 means failed to converge, -2 means bounds are incorrect
8022 : // CoolErrorToler is in fraction of load, MaxIter = 600, SolFalg = # of iterations or error as appropriate
8023 143703 : auto f = [&state, FurnaceNum, FirstHVACIteration, fanOp, compressorOp, TotalZoneSensLoad, ZoneSensLoadMetFanONCompOFF](
8024 108152 : Real64 const PartLoadRatio) {
8025 108152 : return CalcWaterToAirResidual(state,
8026 : PartLoadRatio,
8027 : FurnaceNum,
8028 : FirstHVACIteration,
8029 : fanOp,
8030 : compressorOp,
8031 : TotalZoneSensLoad,
8032 : 1.0,
8033 : 1.0,
8034 : ZoneSensLoadMetFanONCompOFF,
8035 108152 : 0.0);
8036 35551 : };
8037 35551 : General::SolveRoot(state, CoolErrorToler, MaxIter, SolFlag, CoolPartLoadRatio, f, 0.0, 1.0);
8038 35551 : if (SolFlag == -1 && !state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
8039 13 : state.dataHVACGlobal->OnOffFanPartLoadFraction = state.dataFurnaces->OnOffFanPartLoadFractionSave;
8040 13 : CalcFurnaceOutput(state,
8041 : FurnaceNum,
8042 : FirstHVACIteration,
8043 : fanOp,
8044 : compressorOp,
8045 : CoolPartLoadRatio,
8046 : 0.0,
8047 : 0.0,
8048 : 0.0,
8049 : ZoneSensLoadMet,
8050 : ZoneLatLoadMet,
8051 : OnOffAirFlowRatio,
8052 : false);
8053 13 : if (std::abs(ZoneSensLoadMet - TotalZoneSensLoad) / TotalZoneSensLoad > CoolErrorToler) {
8054 0 : if (thisFurnace.SensibleMaxIterIndex == 0) {
8055 0 : ShowWarningMessage(state,
8056 0 : format("Cooling coil control failed to converge for {}:{}",
8057 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
8058 0 : thisFurnace.Name));
8059 0 : ShowContinueError(state, " Iteration limit exceeded in calculating DX cooling coil sensible part-load ratio.");
8060 0 : ShowContinueErrorTimeStamp(state,
8061 0 : format("Sensible load to be met by DX coil = {:.2T} (watts), sensible output of DX coil = "
8062 : "{:.2T} (watts), and the simulation continues.",
8063 : TotalZoneSensLoad,
8064 : ZoneSensLoadMet));
8065 : }
8066 0 : ShowRecurringWarningErrorAtEnd(
8067 : state,
8068 0 : format("{} \"{}\" - Iteration limit exceeded in calculating sensible cooling part-load ratio error "
8069 : "continues. Sensible load statistics:",
8070 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
8071 0 : thisFurnace.Name),
8072 0 : thisFurnace.SensibleMaxIterIndex,
8073 : TotalZoneSensLoad,
8074 : TotalZoneSensLoad);
8075 : }
8076 35538 : } else if (SolFlag == -2 && !state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
8077 0 : CoolPartLoadRatio = max(MinPLR, min(1.0, std::abs(HPCoilSensDemand) / std::abs(HPCoilSensCapacity)));
8078 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
8079 0 : CalcFurnaceOutput(state,
8080 : FurnaceNum,
8081 : FirstHVACIteration,
8082 : fanOp,
8083 : compressorOp,
8084 : CoolPartLoadRatio,
8085 : 0.0,
8086 : 0.0,
8087 : 0.0,
8088 : ZoneSensLoadMet,
8089 : ZoneLatLoadMet,
8090 : OnOffAirFlowRatio,
8091 : false);
8092 0 : if ((ZoneSensLoadMet - TotalZoneSensLoad) / TotalZoneSensLoad > CoolErrorToler) {
8093 0 : if (thisFurnace.SensibleRegulaFalsiFailedIndex == 0) {
8094 0 : ShowWarningMessage(
8095 : state,
8096 0 : format("Cooling coil control failed for {}:{}", HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name));
8097 0 : ShowContinueError(state, " Cooling sensible part-load ratio determined to be outside the range of 0-1.");
8098 0 : ShowContinueError(
8099 : state,
8100 0 : format(" An estimated part-load ratio = {:.2T} will be used and the simulation continues.", CoolPartLoadRatio));
8101 0 : ShowContinueError(
8102 0 : state, format(" The estimated part-load ratio provides a cooling sensible capacity = {:.2T}", ZoneSensLoadMet));
8103 0 : ShowContinueErrorTimeStamp(state, format(" Cooling sensible load required = {:.2T}", TotalZoneSensLoad));
8104 : }
8105 0 : ShowRecurringWarningErrorAtEnd(
8106 : state,
8107 0 : format("{} \"{}\" - Cooling sensible part-load ratio out of range error continues. Sensible cooling load statistics:",
8108 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
8109 0 : thisFurnace.Name),
8110 0 : thisFurnace.SensibleRegulaFalsiFailedIndex,
8111 : TotalZoneSensLoad,
8112 : TotalZoneSensLoad);
8113 : }
8114 : }
8115 : }
8116 :
8117 37711 : if (fanOp == HVAC::FanOp::Cycling) {
8118 37711 : thisFurnace.MdotFurnace *= CoolPartLoadRatio;
8119 : }
8120 :
8121 : //*********HEATING CALCULATIONS****************
8122 : // If Furnace runs with a heating load then set HeatCoilLoad on Heating Coil and the Mass Flow
8123 81559 : } else if ((ScheduleManager::GetCurrentScheduleValue(state, thisFurnace.SchedPtr) > 0.0) &&
8124 81559 : (state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate > 0.0) && state.dataFurnaces->HeatingLoad) {
8125 :
8126 : // Set the air flow rate to the design flow rate and set the fan operation fraction to 1 (continuous operation)
8127 55271 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.DesignMassFlowRate;
8128 55271 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0; // see 'Note' under INITIAL CALCULATIONS
8129 :
8130 : // !Set the operation flag to run the fan continuously
8131 : // fanOp = FanOp::Continuous
8132 :
8133 : // Set the input parameters for CalcFurnaceOutput
8134 55271 : thisFurnace.HeatingCoilSensDemand = 0.0;
8135 55271 : thisFurnace.CoolingCoilLatentDemand = 0.0;
8136 55271 : thisFurnace.CoolingCoilSensDemand = 0.0;
8137 55271 : thisFurnace.CompPartLoadRatio = 0.0; // compressor off
8138 55271 : thisFurnace.InitHeatPump = true; // initialization call to Calc Furnace
8139 55271 : HeatPartLoadRatio = 0.0;
8140 :
8141 : // Get no load result in order to calculate the effect of the fan and the mixed air equipment
8142 55271 : CalcFurnaceOutput(state,
8143 : FurnaceNum,
8144 : FirstHVACIteration,
8145 : fanOp,
8146 : compressorOp,
8147 : CoolPartLoadRatio,
8148 : HeatPartLoadRatio,
8149 : Dummy2,
8150 : Dummy2,
8151 : ZoneSensLoadMetFanONCompOFF,
8152 : ZoneLatLoadMetFanONCompOFF,
8153 : OnOffAirFlowRatio,
8154 : false);
8155 :
8156 : // Set the input parameters for CalcFurnaceOutput
8157 55271 : thisFurnace.HeatingCoilSensDemand = 1.0;
8158 55271 : thisFurnace.CompPartLoadRatio = 1.0; // compressor ON
8159 55271 : HeatPartLoadRatio = 1.0;
8160 :
8161 : // Get full load result in order to estimate the operating part load ratio for continuous fan operation
8162 :
8163 55271 : CalcFurnaceOutput(state,
8164 : FurnaceNum,
8165 : FirstHVACIteration,
8166 : fanOp,
8167 : compressorOp,
8168 : CoolPartLoadRatio,
8169 : HeatPartLoadRatio,
8170 : Dummy2,
8171 : Dummy2,
8172 : ZoneSensLoadMetFanONCompON,
8173 : ZoneLatLoadMetFanONCompON,
8174 : OnOffAirFlowRatio,
8175 : false);
8176 :
8177 : // Calculate the heating coil demand for continuous fan operation as:
8178 : // (the zone sensible load - the zone sensible load met by fan heat and mixed air)
8179 : // Note; The sensible zone load met by fan heat and mixed air is calculated as:
8180 : // mdotsys(control zone inlet enthalpy - control zone outlet enthalpy)
8181 : // This accounts for the negative sign in the equation.
8182 55271 : HPCoilSensDemand = TotalZoneSensLoad - ZoneSensLoadMetFanONCompOFF;
8183 :
8184 : // Calculate the heating coil capacity for continuous fan operation as:
8185 : // (the zone sensible load met by fan heat and mixed air and coil
8186 : // - the zone sensible load met by fan heat and mixed air)
8187 55271 : HPCoilSensCapacity = ZoneSensLoadMetFanONCompON - ZoneSensLoadMetFanONCompOFF;
8188 :
8189 : // Calculate the part load ratio for continuous fan operation with cycling coil
8190 55271 : if (HPCoilSensCapacity == 0.0) {
8191 0 : HeatPartLoadRatio = 0.0;
8192 : } else {
8193 55271 : HeatPartLoadRatio = max(MinPLR, min(1.0, std::abs(HPCoilSensDemand) / std::abs(HPCoilSensCapacity)));
8194 : }
8195 :
8196 55271 : thisFurnace.InitHeatPump = false;
8197 :
8198 : // check bounds on sensible output prior to iteration using RegulaFalsi
8199 55271 : if (ZoneSensLoadMetFanONCompON < TotalZoneSensLoad) {
8200 4228 : HeatPartLoadRatio = 1.0;
8201 4228 : ZoneSensLoadMet = ZoneSensLoadMetFanONCompON;
8202 4228 : HPCoilSensDemand = std::abs(ZoneSensLoadMetFanONCompON - ZoneSensLoadMetFanONCompOFF);
8203 4228 : thisFurnace.HeatingCoilSensDemand = HPCoilSensDemand;
8204 51043 : } else if (ZoneSensLoadMetFanONCompOFF > TotalZoneSensLoad) {
8205 0 : HeatPartLoadRatio = 0.0;
8206 0 : ZoneSensLoadMet = ZoneSensLoadMetFanONCompOFF;
8207 0 : thisFurnace.CompPartLoadRatio = 0.0; // compressor ON
8208 0 : CalcFurnaceOutput(state,
8209 : FurnaceNum,
8210 : FirstHVACIteration,
8211 : fanOp,
8212 : compressorOp,
8213 : CoolPartLoadRatio,
8214 : HeatPartLoadRatio,
8215 : Dummy2,
8216 : Dummy2,
8217 : ZoneSensLoadMet,
8218 : ZoneLatLoadMet,
8219 : OnOffAirFlowRatio,
8220 : false);
8221 : } else {
8222 : // Calculate the sensible part load ratio through iteration
8223 51043 : HeatErrorToler = thisFurnace.HeatingConvergenceTolerance;
8224 51043 : SolFlag = 0; // # of iterations if positive, -1 means failed to converge, -2 means bounds are incorrect
8225 : // HeatErrorToler is in fraction of load, MaxIter = 600, SolFalg = # of iterations or error as appropriate
8226 204172 : auto f = [&state, FurnaceNum, FirstHVACIteration, fanOp, compressorOp, TotalZoneSensLoad, ZoneSensLoadMetFanONCompOFF](
8227 153129 : Real64 const PartLoadRatio) {
8228 153129 : return CalcWaterToAirResidual(state,
8229 : PartLoadRatio,
8230 : FurnaceNum,
8231 : FirstHVACIteration,
8232 : fanOp,
8233 : compressorOp,
8234 : TotalZoneSensLoad,
8235 : 0.0,
8236 : 1.0,
8237 : ZoneSensLoadMetFanONCompOFF,
8238 153129 : 0.0);
8239 51043 : };
8240 51043 : General::SolveRoot(state, HeatErrorToler, MaxIter, SolFlag, HeatPartLoadRatio, f, 0.0, 1.0);
8241 51043 : state.dataHVACGlobal->OnOffFanPartLoadFraction = state.dataFurnaces->OnOffFanPartLoadFractionSave;
8242 51043 : CalcFurnaceOutput(state,
8243 : FurnaceNum,
8244 : FirstHVACIteration,
8245 : fanOp,
8246 : compressorOp,
8247 : CoolPartLoadRatio,
8248 : HeatPartLoadRatio,
8249 : Dummy2,
8250 : Dummy2,
8251 : ZoneSensLoadMet,
8252 : ZoneLatLoadMet,
8253 : OnOffAirFlowRatio,
8254 : false);
8255 51043 : if (SolFlag == -1 && !state.dataGlobal->WarmupFlag && !FirstHVACIteration) {
8256 0 : if (std::abs(ZoneSensLoadMet - TotalZoneSensLoad) / TotalZoneSensLoad > HeatErrorToler) {
8257 0 : if (thisFurnace.WSHPHeatMaxIterIndex == 0) {
8258 0 : ShowWarningMessage(state,
8259 0 : format("Heating coil control failed to converge for {}:{}",
8260 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
8261 0 : thisFurnace.Name));
8262 0 : ShowContinueError(state, " Iteration limit exceeded in calculating DX heating coil sensible part-load ratio.");
8263 0 : ShowContinueErrorTimeStamp(state,
8264 0 : format("Sensible load to be met by DX coil = {:.2T} (watts), sensible output of DX coil = "
8265 : "{:.2T} (watts), and the simulation continues.",
8266 : TotalZoneSensLoad,
8267 : ZoneSensLoadMet));
8268 : }
8269 0 : ShowRecurringWarningErrorAtEnd(
8270 : state,
8271 0 : format("{} \"{}\" - Iteration limit exceeded in calculating sensible heating part-load ratio error continues.",
8272 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
8273 0 : thisFurnace.Name),
8274 0 : thisFurnace.WSHPHeatMaxIterIndex,
8275 : TotalZoneSensLoad,
8276 : TotalZoneSensLoad);
8277 : }
8278 51043 : } else if (SolFlag == -2) {
8279 0 : HeatPartLoadRatio = max(MinPLR, min(1.0, std::abs(HPCoilSensDemand) / std::abs(HPCoilSensCapacity)));
8280 0 : CalcFurnaceOutput(state,
8281 : FurnaceNum,
8282 : FirstHVACIteration,
8283 : fanOp,
8284 : compressorOp,
8285 : 0.0,
8286 : HeatPartLoadRatio,
8287 : 0.0,
8288 : 0.0,
8289 : ZoneSensLoadMet,
8290 : ZoneLatLoadMet,
8291 : OnOffAirFlowRatio,
8292 : false);
8293 0 : if ((ZoneSensLoadMet - TotalZoneSensLoad) / TotalZoneSensLoad > HeatErrorToler) {
8294 0 : if (thisFurnace.WSHPHeatRegulaFalsiFailedIndex == 0) {
8295 0 : ShowWarningError(
8296 : state,
8297 0 : format("Heating coil control failed for {}:{}", HVAC::unitarySysTypeNames[(int)thisFurnace.type], thisFurnace.Name));
8298 0 : ShowContinueError(state, " Heating sensible part-load ratio determined to be outside the range of 0-1.");
8299 0 : ShowContinueError(
8300 : state,
8301 0 : format(" An estimated part-load ratio = {:.2T} will be used and the simulation continues.", HeatPartLoadRatio));
8302 0 : ShowContinueError(
8303 0 : state, format(" The estimated part-load ratio provides a heating sensible capacity = {:.2T}", ZoneSensLoadMet));
8304 0 : ShowContinueErrorTimeStamp(state, format(" Heating sensible load required = {:.2T}", TotalZoneSensLoad));
8305 : }
8306 0 : ShowRecurringWarningErrorAtEnd(state,
8307 0 : format("{} \"{}\" - Heating sensible part-load ratio out of range error continues.",
8308 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
8309 0 : thisFurnace.Name),
8310 0 : thisFurnace.WSHPHeatRegulaFalsiFailedIndex,
8311 : TotalZoneSensLoad,
8312 : TotalZoneSensLoad);
8313 : }
8314 : }
8315 : }
8316 :
8317 : // CALL supplemental heater if required
8318 55271 : if ((TotalZoneSensLoad - ZoneSensLoadMet) > HVAC::SmallLoad && HeatPartLoadRatio >= 1.0) {
8319 4228 : SuppHeatCoilLoad = TotalZoneSensLoad - ZoneSensLoadMet;
8320 4228 : CalcFurnaceOutput(state,
8321 : FurnaceNum,
8322 : FirstHVACIteration,
8323 : fanOp,
8324 : compressorOp,
8325 : CoolPartLoadRatio,
8326 : HeatPartLoadRatio,
8327 : SuppHeatCoilLoad,
8328 : Dummy2,
8329 : ZoneSensLoadMet,
8330 : ZoneLatLoadMet,
8331 : OnOffAirFlowRatio,
8332 : false);
8333 : }
8334 :
8335 55271 : if (fanOp == HVAC::FanOp::Cycling) {
8336 55271 : thisFurnace.MdotFurnace *= HeatPartLoadRatio;
8337 : }
8338 :
8339 : //**********HVAC Scheduled ON, but no cooling, dehumidification or heating load*********
8340 26288 : } else if (ScheduleManager::GetCurrentScheduleValue(state, thisFurnace.SchedPtr) > 0.0) {
8341 12252 : thisFurnace.InitHeatPump = true; // initialization call to Calc Furnace
8342 12252 : HeatPartLoadRatio = 0.0;
8343 12252 : CoolPartLoadRatio = 0.0;
8344 12252 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0; //! see 'Note' under INITIAL CALCULATIONS
8345 : // set report variables
8346 12252 : thisFurnace.CompPartLoadRatio = 0.0;
8347 12252 : thisFurnace.CoolingCoilSensDemand = 0.0;
8348 12252 : thisFurnace.CoolingCoilLatentDemand = 0.0;
8349 12252 : thisFurnace.HeatingCoilSensDemand = 0.0;
8350 12252 : if (fanOp == HVAC::FanOp::Cycling) {
8351 12252 : thisFurnace.MdotFurnace = 0.0;
8352 12252 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0; // see 'Note' under INITIAL CALCULATIONS
8353 12252 : CalcFurnaceOutput(state,
8354 : FurnaceNum,
8355 : FirstHVACIteration,
8356 : fanOp,
8357 : compressorOp,
8358 : CoolPartLoadRatio,
8359 : HeatPartLoadRatio,
8360 : Dummy2,
8361 : Dummy2,
8362 : ZoneSensLoadMet,
8363 : ZoneLatLoadMet,
8364 : OnOffAirFlowRatio,
8365 : false);
8366 12252 : thisFurnace.MdotFurnace = 0.0;
8367 : } else { // continuous fan, cycling coil
8368 0 : CalcFurnaceOutput(state,
8369 : FurnaceNum,
8370 : FirstHVACIteration,
8371 : fanOp,
8372 : compressorOp,
8373 : CoolPartLoadRatio,
8374 : HeatPartLoadRatio,
8375 : Dummy2,
8376 : Dummy2,
8377 : ZoneSensLoadMet,
8378 : ZoneLatLoadMet,
8379 : OnOffAirFlowRatio,
8380 : false);
8381 : }
8382 : //*********No heating or cooling or dehumidification*********
8383 : } else {
8384 14036 : thisFurnace.InitHeatPump = true; // initialization call to Calc Furnace
8385 14036 : thisFurnace.MdotFurnace = 0.0;
8386 14036 : HeatPartLoadRatio = 0.0;
8387 14036 : CoolPartLoadRatio = 0.0;
8388 14036 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0; // see 'Note' under INITIAL CALCULATIONS
8389 14036 : thisFurnace.CompPartLoadRatio = 0.0;
8390 14036 : thisFurnace.CoolingCoilSensDemand = 0.0;
8391 14036 : thisFurnace.CoolingCoilLatentDemand = 0.0;
8392 14036 : thisFurnace.HeatingCoilSensDemand = 0.0;
8393 14036 : CalcFurnaceOutput(state,
8394 : FurnaceNum,
8395 : FirstHVACIteration,
8396 : fanOp,
8397 : compressorOp,
8398 : CoolPartLoadRatio,
8399 : HeatPartLoadRatio,
8400 : Dummy2,
8401 : Dummy2,
8402 : ZoneSensLoadMet,
8403 : ZoneLatLoadMet,
8404 : OnOffAirFlowRatio,
8405 : false);
8406 14036 : thisFurnace.MdotFurnace = 0.0;
8407 : }
8408 :
8409 : // Set the fan inlet node flow rates
8410 119270 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRateMaxAvail = thisFurnace.MdotFurnace;
8411 119270 : state.dataLoopNodes->Node(FurnaceInletNode).MassFlowRate = thisFurnace.MdotFurnace;
8412 119270 : }
8413 :
8414 20453647 : void CalcFurnaceOutput(EnergyPlusData &state,
8415 : int const FurnaceNum,
8416 : bool const FirstHVACIteration,
8417 : HVAC::FanOp const fanOp, // Cycling fan or constant fan
8418 : HVAC::CompressorOp const compressorOp, // Compressor on/off; 1=on, 0=off
8419 : Real64 const CoolPartLoadRatio, // DX cooling coil part load ratio
8420 : Real64 const HeatPartLoadRatio, // DX heating coil part load ratio (0 for other heating coil types)
8421 : Real64 const HeatCoilLoad, // Heating coil load for gas heater
8422 : Real64 const ReheatCoilLoad, // Reheating coil load for gas heater
8423 : Real64 &SensibleLoadMet, // Sensible cooling load met (furnace outlet with respect to control zone temp)
8424 : Real64 &LatentLoadMet, // Latent cooling load met (furnace outlet with respect to control zone humidity ratio)
8425 : Real64 &OnOffAirFlowRatio, // Ratio of compressor ON mass flow rate to AVERAGE
8426 : bool const HXUnitOn, // flag to enable HX based on zone moisture load
8427 : Real64 const CoolingHeatingPLRRatio // cooling PLR to heating PLR ratio, used for cycling fan RH control
8428 : )
8429 : {
8430 :
8431 : // SUBROUTINE INFORMATION:
8432 : // AUTHOR Richard Raustad
8433 : // DATE WRITTEN Sept 2001
8434 : // MODIFIED Dec 2001
8435 :
8436 : // PURPOSE OF THIS SUBROUTINE:
8437 : // This subroutine calculates to sensible and latent loads met by the DX coils
8438 : // specified. Load met is the outlet node with respect to the control zone's
8439 : // temperature and humidity ratio.
8440 :
8441 : // METHODOLOGY EMPLOYED:
8442 : // Simulate each child object in the correct order for each system type. This routine is used in the
8443 : // RegulaFalsi function CALL. Air mass flow rate is set each iteration based on PLR.
8444 :
8445 20453647 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
8446 20453647 : auto &inletNode = state.dataLoopNodes->Node(thisFurnace.FurnaceInletNodeNum);
8447 20453647 : int CoolingCoilType_Num = thisFurnace.CoolingCoilType_Num;
8448 20453647 : Real64 QActual = 0.0; // heating coil load met or delivered
8449 20453647 : state.dataFurnaces->ModifiedHeatCoilLoad = 0.0;
8450 :
8451 20453647 : state.dataFurnaces->CoolHeatPLRRat = CoolingHeatingPLRRatio;
8452 :
8453 : // Cooling to Heating PLR Ratio (CoolHeatPLRRat) is used to track the air mass flow rate of both the heating
8454 : // and cooling coils when RH control is used and the heating coil operates longer than the cooling coil.
8455 : // When CoolPartLoadRatio/CoolHeatPLRRat is used, the PLR calculated is acutally the PLR for the heating
8456 : // coil (heating PLR is greater than cooling PLR), it is this PLR that determines the air mass flow rate.
8457 : // When MAX(HeatPartLoadRatio,CoolPartLoadRatio) is used, only one of these values is non-zero.
8458 20453647 : if (fanOp == HVAC::FanOp::Cycling) {
8459 12941008 : if (state.dataFurnaces->CoolHeatPLRRat < 1.0) {
8460 2 : if (state.dataFurnaces->CoolHeatPLRRat > 0.0) {
8461 0 : inletNode.MassFlowRate = state.dataFurnaces->CompOnMassFlow * CoolPartLoadRatio / state.dataFurnaces->CoolHeatPLRRat;
8462 0 : if (thisFurnace.type != HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir) {
8463 0 : SetAverageAirFlow(state, FurnaceNum, CoolPartLoadRatio / state.dataFurnaces->CoolHeatPLRRat, OnOffAirFlowRatio);
8464 : }
8465 : } else {
8466 2 : inletNode.MassFlowRate = state.dataFurnaces->CompOnMassFlow * CoolPartLoadRatio;
8467 2 : if (thisFurnace.type != HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir) {
8468 2 : SetAverageAirFlow(state, FurnaceNum, max(HeatPartLoadRatio, CoolPartLoadRatio), OnOffAirFlowRatio);
8469 : }
8470 : }
8471 : } else {
8472 12941006 : inletNode.MassFlowRate = state.dataFurnaces->CompOnMassFlow * max(HeatPartLoadRatio, CoolPartLoadRatio);
8473 12941006 : if (thisFurnace.type != HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir) {
8474 5308941 : SetAverageAirFlow(state, FurnaceNum, max(HeatPartLoadRatio, CoolPartLoadRatio), OnOffAirFlowRatio);
8475 : }
8476 : }
8477 : } else {
8478 7512639 : if (thisFurnace.type != HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir) {
8479 4981695 : SetAverageAirFlow(state, FurnaceNum, max(HeatPartLoadRatio, CoolPartLoadRatio), OnOffAirFlowRatio);
8480 : }
8481 : }
8482 :
8483 20453647 : inletNode.MassFlowRateMaxAvail = inletNode.MassFlowRate;
8484 :
8485 : // Simulate the air-to-air heat pump
8486 20453647 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir) {
8487 : // Simulate blow-thru fan and non-linear coils twice to update PLF used by the ONOFF Fan
8488 1635454 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
8489 1635454 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
8490 1635454 : if (CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) {
8491 0 : HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(state,
8492 : BlankString,
8493 : FirstHVACIteration,
8494 : compressorOp,
8495 : CoolPartLoadRatio,
8496 0 : thisFurnace.CoolingCoilIndex,
8497 : fanOp,
8498 : HXUnitOn,
8499 : OnOffAirFlowRatio,
8500 0 : state.dataFurnaces->EconomizerFlag);
8501 : } else {
8502 3270908 : DXCoils::SimDXCoil(state,
8503 : BlankString,
8504 : compressorOp,
8505 : FirstHVACIteration,
8506 1635454 : thisFurnace.CoolingCoilIndex,
8507 : fanOp,
8508 : CoolPartLoadRatio,
8509 : OnOffAirFlowRatio);
8510 : }
8511 3270908 : DXCoils::SimDXCoil(
8512 1635454 : state, BlankString, compressorOp, FirstHVACIteration, thisFurnace.HeatingCoilIndex, fanOp, HeatPartLoadRatio, OnOffAirFlowRatio);
8513 1635454 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
8514 : }
8515 : // Simulate cooling and heating coils
8516 1635454 : if (CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) {
8517 0 : HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(state,
8518 : BlankString,
8519 : FirstHVACIteration,
8520 : compressorOp,
8521 : CoolPartLoadRatio,
8522 0 : thisFurnace.CoolingCoilIndex,
8523 : fanOp,
8524 : HXUnitOn,
8525 : OnOffAirFlowRatio,
8526 0 : state.dataFurnaces->EconomizerFlag);
8527 : } else {
8528 3270908 : DXCoils::SimDXCoil(
8529 1635454 : state, BlankString, compressorOp, FirstHVACIteration, thisFurnace.CoolingCoilIndex, fanOp, CoolPartLoadRatio, OnOffAirFlowRatio);
8530 : }
8531 3270908 : DXCoils::SimDXCoil(
8532 1635454 : state, BlankString, compressorOp, FirstHVACIteration, thisFurnace.HeatingCoilIndex, fanOp, HeatPartLoadRatio, OnOffAirFlowRatio);
8533 : // Simulate the draw-thru fan
8534 1635454 : if (thisFurnace.fanPlace == HVAC::FanPlace::DrawThru) {
8535 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
8536 : }
8537 : // Simulate the supplemental heating coil
8538 1635454 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat && ReheatCoilLoad > 0.0) {
8539 0 : bool SuppHeatingCoilFlag = true;
8540 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, ReheatCoilLoad, fanOp, QActual);
8541 0 : } else {
8542 : // equivalent to QCoilReq=0.0d0 or ReHeatCoilLoad = 0.0d0
8543 1635454 : bool SuppHeatingCoilFlag = true;
8544 1635454 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, ReheatCoilLoad, fanOp, QActual);
8545 : }
8546 : // Simulate the parameter estimate water-to-air heat pump
8547 18818193 : } else if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir && thisFurnace.WatertoAirHPType == WAHPCoilType::Simple) {
8548 : // Simulate blow-thru fan and non-linear coils twice to update PLF used by the ONOFF Fan
8549 9634192 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
8550 9634192 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
8551 : // COIL:WATERTOAIRHPSIMPLE:COOLING
8552 9634192 : WaterToAirHeatPumpSimple::SimWatertoAirHPSimple(state,
8553 : BlankString,
8554 9634192 : thisFurnace.CoolingCoilIndex,
8555 : thisFurnace.CoolingCoilSensDemand,
8556 : thisFurnace.CoolingCoilLatentDemand,
8557 : fanOp,
8558 : compressorOp,
8559 : CoolPartLoadRatio,
8560 : FirstHVACIteration); // CoolPartLoadRatio
8561 9634192 : Real64 Dummy = 0.0;
8562 : // COIL:WATERTOAIRHPSIMPLE:HEATING
8563 9634192 : WaterToAirHeatPumpSimple::SimWatertoAirHPSimple(state,
8564 : BlankString,
8565 9634192 : thisFurnace.HeatingCoilIndex,
8566 : thisFurnace.HeatingCoilSensDemand,
8567 : Dummy,
8568 : fanOp,
8569 : compressorOp,
8570 : HeatPartLoadRatio,
8571 : FirstHVACIteration); // HeatPartLoadRatio
8572 : // Simulate the whole thing a second time so that the correct PLF required by the coils is used by the Fan. *******
8573 9634192 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
8574 : }
8575 : // Simulate the cooling and heating coils
8576 : // COIL:WATERTOAIRHPSIMPLE:COOLING
8577 9634192 : WaterToAirHeatPumpSimple::SimWatertoAirHPSimple(state,
8578 : BlankString,
8579 9634192 : thisFurnace.CoolingCoilIndex,
8580 : thisFurnace.CoolingCoilSensDemand,
8581 : thisFurnace.CoolingCoilLatentDemand,
8582 : fanOp,
8583 : compressorOp,
8584 : CoolPartLoadRatio,
8585 : FirstHVACIteration); // CoolPartLoadRatio
8586 9634192 : Real64 Dummy = 0.0;
8587 : // COIL:WATERTOAIRHPSIMPLE:HEATING
8588 9634192 : WaterToAirHeatPumpSimple::SimWatertoAirHPSimple(state,
8589 : BlankString,
8590 9634192 : thisFurnace.HeatingCoilIndex,
8591 : thisFurnace.HeatingCoilSensDemand,
8592 : Dummy,
8593 : fanOp,
8594 : compressorOp,
8595 : HeatPartLoadRatio,
8596 : FirstHVACIteration); // HeatPartLoadRatio
8597 : // Simulate the draw-thru fan
8598 9634192 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
8599 9634192 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
8600 : }
8601 : // Simulate the supplemental heating coil
8602 9634192 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat && ReheatCoilLoad > 0.0) {
8603 0 : bool SuppHeatingCoilFlag = true; // if true simulates supplemental heating coil
8604 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, ReheatCoilLoad, fanOp, QActual);
8605 0 : } else {
8606 9634192 : bool SuppHeatingCoilFlag = true; // if true simulates supplemental heating coil
8607 9634192 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, fanOp, QActual);
8608 : }
8609 : // Simulate the detailed water-to-air heat pump
8610 18818193 : } else if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir && thisFurnace.WatertoAirHPType == WAHPCoilType::ParEst) {
8611 : // Simulate the draw-thru fan
8612 528817 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
8613 528817 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
8614 : }
8615 : // Simulate the cooling and heating coils
8616 528817 : WaterToAirHeatPump::SimWatertoAirHP(state,
8617 : BlankString,
8618 528817 : thisFurnace.CoolingCoilIndex,
8619 : thisFurnace.DesignMassFlowRate,
8620 : fanOp,
8621 : FirstHVACIteration,
8622 528817 : thisFurnace.InitHeatPump,
8623 : thisFurnace.CoolingCoilSensDemand,
8624 : thisFurnace.CoolingCoilLatentDemand,
8625 : compressorOp,
8626 : CoolPartLoadRatio);
8627 528817 : Real64 Dummy = 0.0;
8628 528817 : WaterToAirHeatPump::SimWatertoAirHP(state,
8629 : BlankString,
8630 528817 : thisFurnace.HeatingCoilIndex,
8631 : thisFurnace.DesignMassFlowRate,
8632 : fanOp,
8633 : FirstHVACIteration,
8634 528817 : thisFurnace.InitHeatPump,
8635 : thisFurnace.HeatingCoilSensDemand,
8636 : Dummy,
8637 : compressorOp,
8638 : HeatPartLoadRatio);
8639 : // Simulate the draw-thru fan
8640 528817 : if (thisFurnace.fanPlace == HVAC::FanPlace::DrawThru) {
8641 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
8642 : }
8643 : // Simulate the supplemental heating coil
8644 2115268 : HeatingCoils::SimulateHeatingCoilComponents(
8645 1586451 : state, BlankString, FirstHVACIteration, HeatCoilLoad, thisFurnace.SuppHeatCoilIndex, _, true, fanOp);
8646 :
8647 528817 : } else { // ELSE it's not a heat pump
8648 : // Simulate blow-thru fan
8649 8655184 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
8650 :
8651 8455786 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
8652 :
8653 : // For non-linear coils, simulate coil to update PLF used by the ONOFF Fan
8654 8455786 : if (thisFurnace.fanType == HVAC::FanType::OnOff) {
8655 6463895 : if (thisFurnace.type != HVAC::UnitarySysType::Unitary_HeatOnly && thisFurnace.type != HVAC::UnitarySysType::Furnace_HeatOnly) {
8656 :
8657 6446108 : if (!thisFurnace.CoolingCoilUpstream) {
8658 4244823 : bool SuppHeatingCoilFlag = false; // if false simulates heating coil
8659 4244823 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, fanOp, QActual);
8660 : }
8661 :
8662 6446108 : if (CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) {
8663 69930 : HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(state,
8664 : BlankString,
8665 : FirstHVACIteration,
8666 : compressorOp,
8667 : CoolPartLoadRatio,
8668 23310 : thisFurnace.CoolingCoilIndex,
8669 : fanOp,
8670 : HXUnitOn,
8671 : OnOffAirFlowRatio,
8672 23310 : state.dataFurnaces->EconomizerFlag);
8673 : } else {
8674 19268394 : DXCoils::SimDXCoil(state,
8675 : BlankString,
8676 : compressorOp,
8677 : FirstHVACIteration,
8678 6422798 : thisFurnace.CoolingCoilIndex,
8679 : fanOp,
8680 : CoolPartLoadRatio,
8681 : OnOffAirFlowRatio,
8682 6422798 : state.dataFurnaces->CoolHeatPLRRat);
8683 : }
8684 : }
8685 :
8686 6463895 : if (thisFurnace.CoolingCoilUpstream) {
8687 2219072 : bool SuppHeatingCoilFlag = false; // if false simulates heating coil
8688 2219072 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, fanOp, QActual);
8689 : }
8690 6463895 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
8691 : } // Simple OnOff fan
8692 :
8693 : } // Blow thru fan
8694 :
8695 : // Simulate the cooling and heating coils
8696 8655184 : if (thisFurnace.type != HVAC::UnitarySysType::Unitary_HeatOnly && thisFurnace.type != HVAC::UnitarySysType::Furnace_HeatOnly) {
8697 :
8698 8637397 : if (!thisFurnace.CoolingCoilUpstream) {
8699 4307625 : bool SuppHeatingCoilFlag = false; // if false simulates heating coil
8700 4307625 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, fanOp, QActual);
8701 : }
8702 :
8703 8637397 : if (CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) {
8704 461826 : HVACHXAssistedCoolingCoil::SimHXAssistedCoolingCoil(state,
8705 : BlankString,
8706 : FirstHVACIteration,
8707 : compressorOp,
8708 : CoolPartLoadRatio,
8709 153942 : thisFurnace.CoolingCoilIndex,
8710 : fanOp,
8711 : HXUnitOn,
8712 : OnOffAirFlowRatio,
8713 153942 : state.dataFurnaces->EconomizerFlag);
8714 : } else {
8715 25450365 : DXCoils::SimDXCoil(state,
8716 : BlankString,
8717 : compressorOp,
8718 : FirstHVACIteration,
8719 8483455 : thisFurnace.CoolingCoilIndex,
8720 : fanOp,
8721 : CoolPartLoadRatio,
8722 : OnOffAirFlowRatio,
8723 8483455 : state.dataFurnaces->CoolHeatPLRRat);
8724 : }
8725 : }
8726 :
8727 8655184 : if (thisFurnace.CoolingCoilUpstream) {
8728 4347559 : bool SuppHeatingCoilFlag = false; // if false simulates heating coil
8729 4347559 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, fanOp, QActual);
8730 : }
8731 : // Simulate the draw-thru fan
8732 8655184 : if (thisFurnace.fanPlace == HVAC::FanPlace::DrawThru) {
8733 199398 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
8734 : }
8735 8655184 : if (thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat || thisFurnace.SuppHeatCoilIndex > 0) {
8736 2712851 : bool SuppHeatingCoilFlag = true; // if truee simulates supplemental heating coil
8737 2712851 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, ReheatCoilLoad, fanOp, QActual);
8738 : }
8739 : } // IF(Furnace(FurnaceNum)%type == UnitarySys_HeatPump_AirToAir)THEN
8740 :
8741 : // Get mass flow rate after components are simulated
8742 20453647 : auto &outletNode = state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum);
8743 20453647 : Real64 AirMassFlow = inletNode.MassFlowRate; // this should be outlet node as in 9897?
8744 :
8745 : // check the DesignMaxOutletTemp and reset if necessary (for Coil:Gas:Heating or Coil:Electric:Heating only)
8746 20453647 : if (outletNode.Temp > thisFurnace.DesignMaxOutletTemp) {
8747 215214 : Real64 Wout = outletNode.HumRat;
8748 215214 : Real64 Tout = thisFurnace.DesignMaxOutletTemp;
8749 215214 : state.dataFurnaces->ModifiedHeatCoilLoad = HeatCoilLoad - (AirMassFlow * Psychrometrics::PsyCpAirFnW(Wout) * (outletNode.Temp - Tout));
8750 215214 : outletNode.Temp = Tout;
8751 : }
8752 :
8753 : // If the fan runs continually do not allow coils to set OnOffFanPartLoadRatio.
8754 20453647 : if (fanOp == HVAC::FanOp::Continuous) state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
8755 :
8756 20453647 : Real64 SensibleOutput = 0.0; // sensible output rate, {W}
8757 20453647 : Real64 LatentOutput = 0.0; // latent output rate, {W}
8758 20453647 : Real64 TotalOutput = 0.0; // total output rate, {W}
8759 40907294 : CalcZoneSensibleLatentOutput(AirMassFlow,
8760 : outletNode.Temp,
8761 : outletNode.HumRat,
8762 20453647 : state.dataLoopNodes->Node(thisFurnace.NodeNumOfControlledZone).Temp,
8763 20453647 : state.dataLoopNodes->Node(thisFurnace.NodeNumOfControlledZone).HumRat,
8764 : SensibleOutput,
8765 : LatentOutput,
8766 : TotalOutput);
8767 20453647 : SensibleLoadMet = SensibleOutput - thisFurnace.SenLoadLoss;
8768 20453647 : thisFurnace.SensibleLoadMet = SensibleLoadMet;
8769 :
8770 20453647 : if (thisFurnace.Humidistat) {
8771 3388605 : LatentLoadMet = LatentOutput - thisFurnace.LatLoadLoss;
8772 : } else {
8773 17065042 : LatentLoadMet = 0.0;
8774 : }
8775 20453647 : thisFurnace.LatentLoadMet = LatentLoadMet;
8776 20453647 : }
8777 :
8778 : // End of Update subroutines for the Furnace Module
8779 : // *****************************************************************************
8780 :
8781 8236435 : Real64 CalcFurnaceResidual(EnergyPlusData &state,
8782 : Real64 const PartLoadRatio, // DX cooling coil part load ratio
8783 : int FurnaceNum,
8784 : bool FirstHVACIteration,
8785 : HVAC::FanOp const fanOp,
8786 : HVAC::CompressorOp compressorOp,
8787 : Real64 LoadToBeMet,
8788 : Real64 par6_loadFlag,
8789 : Real64 par7_sensLatentFlag,
8790 : Real64 par9_HXOnFlag,
8791 : Real64 par10_HeatingCoilPLR)
8792 : {
8793 :
8794 : // FUNCTION INFORMATION:
8795 : // AUTHOR Richard Raustad
8796 : // DATE WRITTEN Feb 2005
8797 :
8798 : // PURPOSE OF THIS SUBROUTINE:
8799 : // To calculate the part-load ratio for cooling and heating coils
8800 :
8801 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
8802 : Real64 CoolPartLoadRatio; // DX cooling coil part load ratio
8803 : Real64 HeatPartLoadRatio; // DX heating coil part load ratio (0 for other heating coil types)
8804 : Real64 HeatCoilLoad; // Heating coil load for gas heater
8805 : Real64 SensibleLoadMet; // Sensible cooling load met (furnace outlet with respect to control zone temp)
8806 : Real64 LatentLoadMet; // Latent cooling load met (furnace outlet with respect to control zone humidity ratio)
8807 : Real64 OnOffAirFlowRatio; // Ratio of compressor ON air mass flow to AVERAGE air mass flow over time step
8808 : Real64 CoolingHeatingPLRRatio; // ratio of cooling PLR to heating PLR, used for cycling fan RH control
8809 : bool HXUnitOn; // flag to enable HX based on zone moisture load
8810 :
8811 : // // Convert parameters to usable variables
8812 : // int FurnaceNum = int(Par(1));
8813 : // bool FirstHVACIteration = Par(2) == 1.0;
8814 : // int FanfanOp = int(Par(3));
8815 : // CompressorOperation CompressorOp = static_cast<CompressorOperation>(Par(4));
8816 : // Real64 LoadToBeMet = Par(5);
8817 : // Real64 par6_loadFlag = Par(6);
8818 : // Real64 par7_sensLatentFlag = Par(7);
8819 : // Real64 par9_HXOnFlag = Par(9);
8820 : // Real64 par10_HeatingCoilPLR = Par(10);
8821 :
8822 8236435 : if (par6_loadFlag == 1.0) {
8823 4764222 : CoolPartLoadRatio = PartLoadRatio;
8824 4764222 : HeatPartLoadRatio = 0.0;
8825 4764222 : HeatCoilLoad = 0.0;
8826 : } else {
8827 3472213 : CoolPartLoadRatio = 0.0;
8828 3472213 : HeatPartLoadRatio = PartLoadRatio;
8829 :
8830 3472213 : int const HeatingCoilType_Num(state.dataFurnaces->Furnace(FurnaceNum).HeatingCoilType_Num);
8831 3472213 : if (HeatingCoilType_Num == HVAC::Coil_HeatingGasOrOtherFuel || HeatingCoilType_Num == HVAC::Coil_HeatingElectric ||
8832 2155596 : HeatingCoilType_Num == HVAC::Coil_HeatingWater || HeatingCoilType_Num == HVAC::Coil_HeatingSteam) {
8833 1316617 : HeatCoilLoad = state.dataFurnaces->Furnace(FurnaceNum).DesignHeatingCapacity * PartLoadRatio;
8834 : } else {
8835 2155596 : HeatCoilLoad = 0.0;
8836 : }
8837 : }
8838 :
8839 : // OnOffAirFlowRatio = Par(8)
8840 8236435 : if (state.dataFurnaces->Furnace(FurnaceNum).type == HVAC::UnitarySysType::Unitary_HeatPump_WaterToAir) {
8841 4509204 : state.dataFurnaces->Furnace(FurnaceNum).CompPartLoadRatio = PartLoadRatio;
8842 : }
8843 :
8844 8236435 : if (par9_HXOnFlag == 1.0) {
8845 4731402 : HXUnitOn = true;
8846 : } else {
8847 3505033 : HXUnitOn = false;
8848 : }
8849 :
8850 8236435 : if (par10_HeatingCoilPLR > 0.0) {
8851 : // Par(10) = Furnace(FurnaceNum)%HeatPartLoadRatio
8852 : // FanOp = CycFan and Furnace(FurnaceNum)%HeatPartLoadRatio must be > 0 for Part(10) to be greater than 0
8853 : // This variable used when in heating mode and dehumidification (cooling) is required.
8854 0 : CoolingHeatingPLRRatio = min(1.0, CoolPartLoadRatio / state.dataFurnaces->Furnace(FurnaceNum).HeatPartLoadRatio);
8855 : } else {
8856 8236435 : CoolingHeatingPLRRatio = 1.0;
8857 : }
8858 :
8859 : // Subroutine arguments
8860 8236435 : CalcFurnaceOutput(state,
8861 : FurnaceNum,
8862 : FirstHVACIteration,
8863 : fanOp,
8864 : compressorOp,
8865 : CoolPartLoadRatio,
8866 : HeatPartLoadRatio,
8867 : HeatCoilLoad,
8868 : 0.0,
8869 : SensibleLoadMet,
8870 : LatentLoadMet,
8871 : OnOffAirFlowRatio,
8872 : HXUnitOn,
8873 : CoolingHeatingPLRRatio);
8874 :
8875 : // Calculate residual based on output calculation flag
8876 8236435 : if (par7_sensLatentFlag == 1.0) {
8877 7791655 : if (LoadToBeMet == 0.0) {
8878 65344 : return (SensibleLoadMet - LoadToBeMet) / 100.0;
8879 : } else {
8880 7726311 : return (SensibleLoadMet - LoadToBeMet) / LoadToBeMet;
8881 : }
8882 : } else {
8883 444780 : if (LoadToBeMet == 0.0) {
8884 0 : return (LatentLoadMet - LoadToBeMet) / 100.0;
8885 : } else {
8886 444780 : return (LatentLoadMet - LoadToBeMet) / LoadToBeMet;
8887 : }
8888 : }
8889 : }
8890 :
8891 261281 : Real64 CalcWaterToAirResidual(EnergyPlusData &state,
8892 : Real64 const PartLoadRatio, // DX cooling coil part load ratio
8893 : int FurnaceNum,
8894 : bool FirstHVACIteration,
8895 : HVAC::FanOp const fanOp,
8896 : HVAC::CompressorOp compressorOp,
8897 : Real64 LoadToBeMet,
8898 : Real64 par6_loadTypeFlag,
8899 : Real64 par7_latentOrSensible,
8900 : Real64 ZoneSensLoadMetFanONCompOFF,
8901 : Real64 par9_HXUnitOne)
8902 : {
8903 :
8904 : // FUNCTION INFORMATION:
8905 : // AUTHOR Richard Raustad
8906 : // DATE WRITTEN October 2006
8907 :
8908 : // PURPOSE OF THIS SUBROUTINE:
8909 : // To calculate the part-load ratio for water to air HP's
8910 : // this is used for parameter estimation WAHPs but not equation fit WAHPs
8911 :
8912 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
8913 : Real64 CoolPartLoadRatio; // DX cooling coil part load ratio
8914 : Real64 HeatPartLoadRatio; // DX heating coil part load ratio (0 for other heating coil types)
8915 : Real64 HeatCoilLoad; // Heating coil load for gas heater
8916 : Real64 ZoneSensLoadMet; // Sensible cooling load met (furnace outlet with respect to control zone temp)
8917 : Real64 ZoneLatLoadMet; // Latent cooling load met (furnace outlet with respect to control zone humidity ratio)
8918 : Real64 Dummy;
8919 : Real64 HPCoilSensDemand;
8920 : Real64 OnOffAirFlowRatio;
8921 : bool HXUnitOn; // flag to enable HX based on zone moisture load (not valid for water-to-air HP's
8922 :
8923 : // Convert parameters to usable variables
8924 : // int FurnaceNum = int(Par[0]);
8925 : // bool FirstHVACIteration = Par[1] == 1.0;
8926 : // int FanOp = int(Par[2]);
8927 : // CompressorOperation CompressorOp = static_cast<CompressorOperation>(Par[3]);
8928 : // Real64 LoadToBeMet = Par[4];
8929 : // Real64 par6_loadTypeFlag = Par[5];
8930 : // Real64 par7_latentOrSensible = Par[6];
8931 : // Real64 ZoneSensLoadMetFanONCompOFF = Par[7];
8932 : // Real64 par9_HXUnitOne = Par[8];
8933 :
8934 : int CoilIndex;
8935 261281 : if (par6_loadTypeFlag == 1.0) {
8936 108152 : CoolPartLoadRatio = PartLoadRatio;
8937 108152 : HeatPartLoadRatio = 0.0;
8938 108152 : HeatCoilLoad = 0.0;
8939 108152 : CoilIndex = state.dataFurnaces->Furnace(FurnaceNum).CoolingCoilIndex;
8940 : } else {
8941 153129 : CoolPartLoadRatio = 0.0;
8942 153129 : HeatPartLoadRatio = PartLoadRatio;
8943 153129 : CoilIndex = state.dataFurnaces->Furnace(FurnaceNum).HeatingCoilIndex;
8944 : }
8945 :
8946 : // Get child component RuntimeFrac
8947 : Real64 RuntimeFrac;
8948 261281 : switch (state.dataFurnaces->Furnace(FurnaceNum).WatertoAirHPType) {
8949 0 : case WAHPCoilType::Simple: {
8950 0 : RuntimeFrac = state.dataWaterToAirHeatPumpSimple->SimpleWatertoAirHP(CoilIndex).RunFrac;
8951 0 : break;
8952 : }
8953 261281 : case WAHPCoilType::ParEst: {
8954 261281 : RuntimeFrac = state.dataWaterToAirHeatPump->WatertoAirHP(CoilIndex).RunFrac;
8955 261281 : break;
8956 : }
8957 0 : case WAHPCoilType::VarSpeedEquationFit: {
8958 0 : RuntimeFrac = state.dataVariableSpeedCoils->VarSpeedCoil(CoilIndex).RunFrac;
8959 0 : break;
8960 : }
8961 0 : default:
8962 0 : RuntimeFrac = 1.0; // Programming error. Assert failure?
8963 : }
8964 :
8965 261281 : state.dataFurnaces->OnOffFanPartLoadFractionSave = state.dataHVACGlobal->OnOffFanPartLoadFraction;
8966 : // update fan and compressor run times
8967 261281 : state.dataFurnaces->Furnace(FurnaceNum).CompPartLoadRatio = PartLoadRatio;
8968 :
8969 : // Calculate the heating coil demand as (the zone sensible load - load met by fan heat and mixed air)
8970 : // Note; The load met by fan heat and mixed air is calculated as mdot(zoneinletenthalpy-zoneoutletenthalpy)
8971 : // This accounts for the negative sign in the equation.
8972 :
8973 : // Calculate the heat coil sensible capacity as the load met by the system with the fan and compressor on less
8974 : // the load met by the system with the compressor off.
8975 : // HPCoilSensCapacity = ZoneSensLoadMetFanONCompON - ZoneSensLoadMetFanONCompOFF
8976 :
8977 : // Set input parameters for heat pump coil model
8978 261281 : HPCoilSensDemand = LoadToBeMet - RuntimeFrac * ZoneSensLoadMetFanONCompOFF;
8979 : // HPCoilSensDemand = LoadToBeMet - PartLoadRatio*ZoneSensLoadMetFanONCompOFF
8980 261281 : if (par6_loadTypeFlag == 1.0) {
8981 108152 : state.dataFurnaces->Furnace(FurnaceNum).HeatingCoilSensDemand = 0.0;
8982 108152 : state.dataFurnaces->Furnace(FurnaceNum).CoolingCoilSensDemand = std::abs(HPCoilSensDemand);
8983 : } else {
8984 153129 : state.dataFurnaces->Furnace(FurnaceNum).HeatingCoilSensDemand = HPCoilSensDemand;
8985 153129 : state.dataFurnaces->Furnace(FurnaceNum).CoolingCoilSensDemand = 0.0;
8986 : }
8987 261281 : state.dataFurnaces->Furnace(FurnaceNum).InitHeatPump = false; // initialization call to Calc Furnace
8988 :
8989 : // Calculate the zone loads met and the new part load ratio and for the specified run time
8990 261281 : Dummy = 0.0;
8991 261281 : OnOffAirFlowRatio = 1.0;
8992 261281 : if (par9_HXUnitOne == 1.0) {
8993 0 : HXUnitOn = true;
8994 : } else {
8995 261281 : HXUnitOn = false;
8996 : }
8997 :
8998 : // Subroutine arguments
8999 : // CALL CalcFurnaceOutput(FurnaceNum,FirstHVACIteration,FanOp,compressorOp,CoolPartLoadRatio,&
9000 : // HeatPartLoadRatio, HeatCoilLoad, ReHeatCoilLoad, SensibleLoadMet, LatentLoadMet, HXUnitOn)
9001 261281 : CalcFurnaceOutput(state,
9002 : FurnaceNum,
9003 : FirstHVACIteration,
9004 : fanOp,
9005 : compressorOp,
9006 : CoolPartLoadRatio,
9007 : HeatPartLoadRatio,
9008 : Dummy,
9009 : Dummy,
9010 : ZoneSensLoadMet,
9011 : ZoneLatLoadMet,
9012 : OnOffAirFlowRatio,
9013 : HXUnitOn);
9014 :
9015 : // Calculate residual based on output calculation flag
9016 261281 : if (par7_latentOrSensible == 1.0) {
9017 261281 : return (ZoneSensLoadMet - LoadToBeMet) / LoadToBeMet;
9018 : } else {
9019 0 : return (ZoneLatLoadMet - LoadToBeMet) / LoadToBeMet;
9020 : }
9021 : }
9022 :
9023 24581377 : void SetAverageAirFlow(EnergyPlusData &state,
9024 : int const FurnaceNum, // Unit index
9025 : Real64 const PartLoadRatio, // unit part load ratio
9026 : Real64 &OnOffAirFlowRatio // ratio of compressor ON airflow to AVERAGE airflow over timestep
9027 : )
9028 : {
9029 :
9030 : // SUBROUTINE INFORMATION:
9031 : // AUTHOR Richard Raustad
9032 : // DATE WRITTEN July 2005
9033 :
9034 : // PURPOSE OF THIS SUBROUTINE:
9035 : // Set the average air mass flow rates using the part-load fraction of the HVAC system for this time step
9036 : // Set OnOffAirFlowRatio to be used by DX coils
9037 :
9038 : // METHODOLOGY EMPLOYED:
9039 : // The air flow rate in cooling, heating, and no cooling or heating can be different.
9040 : // Calculate the air flow rate based on initializations made in InitFurnace.
9041 :
9042 24581377 : int InletNode = state.dataFurnaces->Furnace(FurnaceNum).FurnaceInletNodeNum;
9043 : Real64 AverageUnitMassFlow =
9044 24581377 : (PartLoadRatio * state.dataFurnaces->CompOnMassFlow) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffMassFlow);
9045 24581377 : if (state.dataFurnaces->CompOffFlowRatio > 0.0) {
9046 11892234 : state.dataFurnaces->FanSpeedRatio =
9047 11892234 : (PartLoadRatio * state.dataFurnaces->CompOnFlowRatio) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffFlowRatio);
9048 : } else {
9049 12689143 : state.dataFurnaces->FanSpeedRatio = state.dataFurnaces->CompOnFlowRatio;
9050 : }
9051 : // IF the furnace is scheduled on or nightime cycle overrides fan schedule. Uses same logic as fan.
9052 48471899 : if (ScheduleManager::GetCurrentScheduleValue(state, state.dataFurnaces->Furnace(FurnaceNum).SchedPtr) > 0.0 &&
9053 23890522 : ((ScheduleManager::GetCurrentScheduleValue(state, state.dataFurnaces->Furnace(FurnaceNum).FanAvailSchedPtr) > 0.0 ||
9054 1638986 : state.dataHVACGlobal->TurnFansOn) &&
9055 23216522 : !state.dataHVACGlobal->TurnFansOff)) {
9056 23216522 : state.dataLoopNodes->Node(InletNode).MassFlowRate = AverageUnitMassFlow;
9057 23216522 : state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AverageUnitMassFlow;
9058 23216522 : if (AverageUnitMassFlow > 0.0) {
9059 19156275 : OnOffAirFlowRatio = state.dataFurnaces->CompOnMassFlow / AverageUnitMassFlow;
9060 : } else {
9061 4060247 : OnOffAirFlowRatio = 0.0;
9062 : }
9063 : } else {
9064 1364855 : state.dataLoopNodes->Node(InletNode).MassFlowRate = 0.0;
9065 1364855 : OnOffAirFlowRatio = 1.0;
9066 : }
9067 :
9068 24581377 : state.dataFurnaces->Furnace(FurnaceNum).MdotFurnace = state.dataFurnaces->CompOnMassFlow;
9069 24581377 : state.dataFurnaces->OnOffAirFlowRatioSave = OnOffAirFlowRatio;
9070 24581377 : }
9071 :
9072 : // Beginning of Reporting subroutines for the Furnace Module
9073 : // *****************************************************************************
9074 :
9075 6243009 : void ReportFurnace(EnergyPlusData &state, int const FurnaceNum, int const AirLoopNum)
9076 : {
9077 :
9078 : // SUBROUTINE INFORMATION:
9079 : // AUTHOR Richard Liesen
9080 : // DATE WRITTEN Feb 2001
9081 :
9082 : // PURPOSE OF THIS SUBROUTINE:
9083 : // This subroutine updates the report variable for the coils.
9084 :
9085 : // METHODOLOGY EMPLOYED:
9086 : // Update fan part-load ratio based on mass flow rate ratio.
9087 : // Update global variables used by AirflowNetwork module.
9088 :
9089 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
9090 : Real64 ratio;
9091 : Real64 OnOffRatio;
9092 6243009 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
9093 :
9094 : // Report the Furnace Fan Part Load Ratio
9095 6243009 : if (thisFurnace.NumOfSpeedCooling < 1) {
9096 4735385 : if (thisFurnace.DesignMassFlowRate > 0.0) {
9097 4735385 : thisFurnace.FanPartLoadRatio = thisFurnace.MdotFurnace / thisFurnace.DesignMassFlowRate;
9098 : } else {
9099 0 : thisFurnace.FanPartLoadRatio = 0.0;
9100 : }
9101 : }
9102 :
9103 : // Set mass flow rates during on and off cylce using an OnOff fan
9104 6243009 : if (state.afn->distribution_simulated) {
9105 214495 : state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopSystemOnMassFlowrate = state.dataFurnaces->CompOnMassFlow;
9106 214495 : state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopSystemOffMassFlowrate = state.dataFurnaces->CompOffMassFlow;
9107 214495 : state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopFanOperationMode = thisFurnace.fanOp;
9108 214495 : state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopOnOffFanPartLoadRatio = thisFurnace.FanPartLoadRatio;
9109 214495 : OnOffRatio = state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopOnOffFanPartLoadRatio;
9110 214495 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatPump_AirToAir) {
9111 150922 : state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopOnOffFanPartLoadRatio =
9112 150922 : max(thisFurnace.FanPartLoadRatio, thisFurnace.HeatPartLoadRatio, thisFurnace.CoolPartLoadRatio);
9113 150922 : state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopOnOffFanPartLoadRatio =
9114 150922 : min(1.0, state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopOnOffFanPartLoadRatio);
9115 : }
9116 214495 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool) {
9117 24774 : if (thisFurnace.HeatPartLoadRatio == 0.0 && thisFurnace.CoolPartLoadRatio == 0.0 && thisFurnace.FanPartLoadRatio > 0.0) {
9118 7424 : if (state.dataFurnaces->CompOnMassFlow < max(thisFurnace.MaxCoolAirMassFlow, thisFurnace.MaxHeatAirMassFlow) &&
9119 0 : state.dataFurnaces->CompOnMassFlow > 0.0) {
9120 0 : ratio = max(thisFurnace.MaxCoolAirMassFlow, thisFurnace.MaxHeatAirMassFlow) / state.dataFurnaces->CompOnMassFlow;
9121 0 : state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopOnOffFanPartLoadRatio =
9122 0 : state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopOnOffFanPartLoadRatio * ratio;
9123 : }
9124 : }
9125 : }
9126 : }
9127 6243009 : if (thisFurnace.FirstPass) {
9128 359 : if (!state.dataGlobal->SysSizingCalc) {
9129 359 : DataSizing::resetHVACSizingGlobals(state, 0, state.dataSize->CurSysNum, thisFurnace.FirstPass);
9130 : }
9131 : }
9132 6243009 : state.dataHVACGlobal->OnOffFanPartLoadFraction =
9133 : 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)
9134 6243009 : }
9135 :
9136 67595255 : void CalcNonDXHeatingCoils(EnergyPlusData &state,
9137 : int const FurnaceNum, // Furnace Index
9138 : bool const SuppHeatingCoilFlag, // .TRUE. if supplemental heating coil
9139 : bool const FirstHVACIteration, // flag for first HVAC iteration in the time step
9140 : Real64 const QCoilLoad, // load met by unit (watts)
9141 : HVAC::FanOp const fanOp, // fan operation mode
9142 : Real64 &HeatCoilLoadmet // Heating Load Met
9143 : )
9144 : {
9145 : // SUBROUTINE INFORMATION:
9146 : // AUTHOR Bereket Nigusse, FSEC/UCF
9147 : // DATE WRITTEN January 2012
9148 :
9149 : // PURPOSE OF THIS SUBROUTINE:
9150 : // This subroutine simulates the four non dx heating coil types: Gas, Electric, hot water and steam.
9151 :
9152 : // METHODOLOGY EMPLOYED:
9153 : // Simply calls the different heating coil component. The hot water flow rate matching the coil load
9154 : // is calculated iteratively.
9155 :
9156 : // SUBROUTINE PARAMETER DEFINITIONS:
9157 67595255 : Real64 constexpr ErrTolerance(0.001); // convergence limit for hotwater coil
9158 67595255 : int constexpr SolveMaxIter(50);
9159 :
9160 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
9161 : Real64 mdot; // heating coil steam or hot water mass flow rate
9162 : Real64 MinWaterFlow; // coil minimum hot water mass flow rate, kg/s
9163 : Real64 MaxHotWaterFlow; // coil maximum hot water mass flow rate, kg/s
9164 : Real64 HotWaterMdot; // actual hot water mass flow rate
9165 67595255 : int CoilTypeNum(0); // heating coil type number
9166 67595255 : int HeatingCoilIndex(0); // heating coil index
9167 67595255 : int CoilControlNode(0); // control node for hot water and steam heating coils
9168 67595255 : int CoilOutletNode(0); // air outlet node of the heatiing coils
9169 67595255 : PlantLocation plantLoc{}; // plant loop location
9170 :
9171 67595255 : Real64 QActual = 0.0; // actual heating load
9172 67595255 : std::string &HeatingCoilName = state.dataFurnaces->HeatingCoilName; // name of heating coil
9173 67595255 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
9174 :
9175 67595255 : if (SuppHeatingCoilFlag) {
9176 19257203 : HeatingCoilName = thisFurnace.SuppHeatCoilName;
9177 19257203 : HeatingCoilIndex = thisFurnace.SuppHeatCoilIndex;
9178 19257203 : CoilControlNode = thisFurnace.SuppCoilControlNode;
9179 19257203 : CoilOutletNode = thisFurnace.SuppCoilOutletNode;
9180 19257203 : CoilTypeNum = thisFurnace.SuppHeatCoilType_Num;
9181 19257203 : plantLoc = thisFurnace.SuppPlantLoc;
9182 19257203 : MaxHotWaterFlow = thisFurnace.MaxSuppCoilFluidFlow;
9183 : } else {
9184 48338052 : HeatingCoilName = thisFurnace.HeatingCoilName;
9185 48338052 : HeatingCoilIndex = thisFurnace.HeatingCoilIndex;
9186 48338052 : CoilControlNode = thisFurnace.CoilControlNode;
9187 48338052 : CoilOutletNode = thisFurnace.CoilOutletNode;
9188 48338052 : CoilTypeNum = thisFurnace.HeatingCoilType_Num;
9189 48338052 : plantLoc = thisFurnace.plantLoc;
9190 48338052 : MaxHotWaterFlow = thisFurnace.MaxHeatCoilFluidFlow;
9191 : }
9192 :
9193 67595255 : switch (CoilTypeNum) {
9194 67504527 : case HVAC::Coil_HeatingGasOrOtherFuel:
9195 : case HVAC::Coil_HeatingElectric:
9196 : case HVAC::Coil_HeatingDesuperheater: {
9197 67504527 : HeatingCoils::SimulateHeatingCoilComponents(
9198 : state, HeatingCoilName, FirstHVACIteration, QCoilLoad, HeatingCoilIndex, QActual, SuppHeatingCoilFlag, fanOp);
9199 67504527 : } break;
9200 90728 : case HVAC::Coil_HeatingWater: {
9201 90728 : if (QCoilLoad > HVAC::SmallLoad) {
9202 1590 : PlantUtilities::SetComponentFlowRate(state, MaxHotWaterFlow, CoilControlNode, CoilOutletNode, plantLoc);
9203 1590 : WaterCoils::SimulateWaterCoilComponents(state, HeatingCoilName, FirstHVACIteration, HeatingCoilIndex, QActual, fanOp);
9204 :
9205 1590 : if (QActual > (QCoilLoad + HVAC::SmallLoad)) {
9206 : // control water flow to obtain output matching QCoilLoad
9207 1468 : MinWaterFlow = 0.0;
9208 337740 : auto f = [&state, FurnaceNum, FirstHVACIteration, QCoilLoad, SuppHeatingCoilFlag](Real64 const HWFlow) {
9209 22516 : Real64 QCoilRequested = QCoilLoad;
9210 :
9211 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
9212 : Real64 QCoilActual; // delivered coil load, W
9213 22516 : Real64 mdot = HWFlow; // to get non-const argument
9214 22516 : QCoilActual = QCoilRequested;
9215 22516 : if (!SuppHeatingCoilFlag) {
9216 0 : PlantUtilities::SetComponentFlowRate(state,
9217 : mdot,
9218 0 : state.dataFurnaces->Furnace(FurnaceNum).CoilControlNode,
9219 0 : state.dataFurnaces->Furnace(FurnaceNum).CoilOutletNode,
9220 0 : state.dataFurnaces->Furnace(FurnaceNum).plantLoc);
9221 0 : WaterCoils::SimulateWaterCoilComponents(state,
9222 0 : state.dataFurnaces->Furnace(FurnaceNum).HeatingCoilName,
9223 : FirstHVACIteration,
9224 0 : state.dataFurnaces->Furnace(FurnaceNum).HeatingCoilIndex,
9225 : QCoilActual,
9226 0 : state.dataFurnaces->Furnace(FurnaceNum).fanOp);
9227 : } else {
9228 : // supplemental coil
9229 45032 : PlantUtilities::SetComponentFlowRate(state,
9230 : mdot,
9231 22516 : state.dataFurnaces->Furnace(FurnaceNum).SuppCoilControlNode,
9232 22516 : state.dataFurnaces->Furnace(FurnaceNum).SuppCoilOutletNode,
9233 22516 : state.dataFurnaces->Furnace(FurnaceNum).SuppPlantLoc);
9234 : // simulate the hot water supplemental heating coil
9235 67548 : WaterCoils::SimulateWaterCoilComponents(state,
9236 22516 : state.dataFurnaces->Furnace(FurnaceNum).SuppHeatCoilName,
9237 : FirstHVACIteration,
9238 22516 : state.dataFurnaces->Furnace(FurnaceNum).SuppHeatCoilIndex,
9239 : QCoilActual,
9240 22516 : state.dataFurnaces->Furnace(FurnaceNum).fanOp);
9241 : }
9242 22516 : return QCoilRequested != 0.0 ? (QCoilActual - QCoilRequested) / QCoilRequested : 0.0;
9243 1468 : };
9244 1468 : int SolFlag = 0;
9245 1468 : General::SolveRoot(state, ErrTolerance, SolveMaxIter, SolFlag, HotWaterMdot, f, MinWaterFlow, MaxHotWaterFlow);
9246 1468 : if (SolFlag == -1) {
9247 0 : if (thisFurnace.HotWaterCoilMaxIterIndex == 0) {
9248 0 : ShowWarningMessage(state,
9249 0 : format("CalcNonDXHeatingCoils: Hot water coil control failed for {}=\"{}\"",
9250 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
9251 0 : thisFurnace.Name));
9252 0 : ShowContinueErrorTimeStamp(state, "");
9253 0 : ShowContinueError(state, format(" Iteration limit [{}] exceeded in calculating hot water mass flow rate", SolveMaxIter));
9254 : }
9255 0 : ShowRecurringWarningErrorAtEnd(
9256 : state,
9257 0 : format("CalcNonDXHeatingCoils: Hot water coil control failed (iteration limit [{}]) for {}=\"{}",
9258 : SolveMaxIter,
9259 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
9260 0 : thisFurnace.Name),
9261 0 : thisFurnace.HotWaterCoilMaxIterIndex);
9262 1468 : } else if (SolFlag == -2) {
9263 0 : if (thisFurnace.HotWaterCoilMaxIterIndex2 == 0) {
9264 0 : ShowWarningMessage(state,
9265 0 : format("CalcNonDXHeatingCoils: Hot water coil control failed (maximum flow limits) for {}=\"{}\"",
9266 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
9267 0 : thisFurnace.Name));
9268 0 : ShowContinueErrorTimeStamp(state, "");
9269 0 : ShowContinueError(state, "...Bad hot water maximum flow rate limits");
9270 0 : ShowContinueError(state, format("...Given minimum water flow rate={:.3R} kg/s", MinWaterFlow));
9271 0 : ShowContinueError(state, format("...Given maximum water flow rate={:.3R} kg/s", MaxHotWaterFlow));
9272 : }
9273 0 : ShowRecurringWarningErrorAtEnd(state,
9274 0 : format("CalcNonDXHeatingCoils: Hot water coil control failed (flow limits) for {}=\"{}\"",
9275 0 : HVAC::unitarySysTypeNames[(int)thisFurnace.type],
9276 0 : thisFurnace.Name),
9277 0 : thisFurnace.HotWaterCoilMaxIterIndex2,
9278 : MaxHotWaterFlow,
9279 : MinWaterFlow,
9280 : _,
9281 : "[kg/s]",
9282 : "[kg/s]");
9283 : }
9284 : }
9285 : } else {
9286 89138 : mdot = 0.0;
9287 89138 : PlantUtilities::SetComponentFlowRate(state, mdot, CoilControlNode, CoilOutletNode, plantLoc);
9288 : }
9289 : // simulate the hot water heating coil
9290 90728 : WaterCoils::SimulateWaterCoilComponents(state, HeatingCoilName, FirstHVACIteration, HeatingCoilIndex, QActual, fanOp);
9291 90728 : } break;
9292 0 : case HVAC::Coil_HeatingSteam: {
9293 0 : if (QCoilLoad > HVAC::SmallLoad) {
9294 0 : PlantUtilities::SetComponentFlowRate(state, MaxHotWaterFlow, CoilControlNode, CoilOutletNode, plantLoc);
9295 : // simulate the steam heating coil
9296 0 : SteamCoils::SimulateSteamCoilComponents(state, HeatingCoilName, FirstHVACIteration, HeatingCoilIndex, QCoilLoad, QActual, fanOp);
9297 : } else {
9298 0 : mdot = 0.0;
9299 0 : PlantUtilities::SetComponentFlowRate(state, mdot, CoilControlNode, CoilOutletNode, plantLoc);
9300 : // simulate the steam heating coil
9301 0 : SteamCoils::SimulateSteamCoilComponents(state, HeatingCoilName, FirstHVACIteration, HeatingCoilIndex, QCoilLoad, QActual, fanOp);
9302 : }
9303 0 : } break;
9304 0 : default:
9305 0 : break;
9306 : }
9307 :
9308 67595255 : HeatCoilLoadmet = QActual;
9309 67595255 : }
9310 :
9311 : // End of Reporting subroutines for the Furnace Module
9312 :
9313 : //******************************************************************************
9314 :
9315 1507624 : void SimVariableSpeedHP(EnergyPlusData &state,
9316 : int const FurnaceNum, // number of the current engine driven Heat Pump being simulated
9317 : bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
9318 : int const AirLoopNum, // index to air loop
9319 : Real64 const QZnReq, // required zone load
9320 : Real64 const QLatReq, // required latent load
9321 : Real64 &OnOffAirFlowRatio // ratio of compressor ON airflow to AVERAGE airflow over timestep
9322 : )
9323 : {
9324 :
9325 : // SUBROUTINE INFORMATION:
9326 : // AUTHOR Bo Shen, based on HVACMultiSpeedHeatPump:CalcMSHeatPump
9327 : // DATE WRITTEN March, 2012
9328 :
9329 : // PURPOSE OF THIS SUBROUTINE:
9330 : // Simulate a multispeed heat pump; adjust its output to match the
9331 : // required system load.
9332 :
9333 : // METHODOLOGY EMPLOYED:
9334 : // Calls ControlMSHPOutput to obtain the desired unit output
9335 :
9336 : Real64 PartLoadFrac; // compressor part load fraction
9337 : Real64 SpeedRatio; // compressor speed ratio
9338 : Real64 QTotUnitOut; // capacity output
9339 1507624 : auto &SpeedNum = state.dataFurnaces->SpeedNum;
9340 1507624 : auto &SupHeaterLoad = state.dataFurnaces->SupHeaterLoad;
9341 : HVAC::CompressorOp compressorOp; // compressor operation; 1=on, 0=off
9342 : Real64 QSensUnitOut; // sensible capacity output
9343 : Real64 QLatUnitOut; // latent capacity output
9344 : Real64 ActualSensibleOutput; // Actual furnace sensible capacity
9345 : Real64 QToHeatSetPt; // Load required to meet heating setpoint temp (>0 is a heating load)
9346 : Real64 NoCompOutput; // output when no active compressor [W]
9347 : bool EconoActive; // TRUE if Economizer is active
9348 :
9349 : // zero DX coils, and supplemental electric heater electricity consumption
9350 1507624 : state.dataHVACGlobal->DXElecHeatingPower = 0.0;
9351 1507624 : state.dataHVACGlobal->DXElecCoolingPower = 0.0;
9352 1507624 : state.dataFurnaces->SaveCompressorPLR = 0.0;
9353 1507624 : state.dataHVACGlobal->ElecHeatingCoilPower = 0.0;
9354 1507624 : state.dataHVACGlobal->SuppHeatingCoilPower = 0.0;
9355 1507624 : state.dataHVACGlobal->DefrostElecPower = 0.0;
9356 :
9357 1507624 : Real64 SystemSensibleLoad = QZnReq; // Positive value means heating required
9358 1507624 : Real64 TotalZoneSensibleLoad = QZnReq;
9359 1507624 : Real64 TotalZoneLatentLoad = QLatReq;
9360 1507624 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
9361 : // initialize local variables
9362 1507624 : bool UnitOn = true;
9363 1507624 : int OutletNode = thisFurnace.FurnaceOutletNodeNum;
9364 1507624 : int InletNode = thisFurnace.FurnaceInletNodeNum;
9365 1507624 : Real64 AirMassFlow = thisFurnace.DesignMassFlowRate;
9366 1507624 : HVAC::FanOp fanOp = thisFurnace.fanOp; // fan operating mode
9367 1507624 : int ZoneNum = thisFurnace.ControlZoneNum;
9368 :
9369 : // Set latent load for heating
9370 1507624 : if (state.dataFurnaces->HeatingLoad) {
9371 105434 : thisFurnace.HeatCoolMode = Furnaces::ModeOfOperation::HeatingMode;
9372 : // Set latent load for cooling and no sensible load condition
9373 1402190 : } else if (state.dataFurnaces->CoolingLoad) {
9374 1302969 : thisFurnace.HeatCoolMode = Furnaces::ModeOfOperation::CoolingMode;
9375 : } else {
9376 99221 : thisFurnace.HeatCoolMode = Furnaces::ModeOfOperation::NoCoolHeat;
9377 : }
9378 :
9379 : // set the on/off flags
9380 1507624 : if (thisFurnace.fanOp == HVAC::FanOp::Cycling) {
9381 : // cycling unit only runs if there is a cooling or heating load.
9382 55903 : if (std::abs(QZnReq) < HVAC::SmallLoad || AirMassFlow < HVAC::SmallMassFlow ||
9383 25641 : state.dataZoneEnergyDemand->CurDeadBandOrSetback(ZoneNum)) {
9384 4624 : UnitOn = false;
9385 : }
9386 1477362 : } else if (thisFurnace.fanOp == HVAC::FanOp::Continuous) {
9387 : // continuous unit: fan runs if scheduled on; coil runs only if there is a cooling or heating load
9388 1477362 : if (AirMassFlow < HVAC::SmallMassFlow) {
9389 0 : UnitOn = false;
9390 : }
9391 : }
9392 :
9393 1507624 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
9394 1507624 : EconoActive = (AirLoopNum != 0) ? state.dataAirLoop->AirLoopControlInfo(AirLoopNum).EconoActive : false;
9395 :
9396 1507624 : Real64 SaveMassFlowRate = state.dataLoopNodes->Node(InletNode).MassFlowRate;
9397 : // decide current working mode for IHP
9398 1507624 : if ((FirstHVACIteration) && (thisFurnace.bIsIHP))
9399 5024 : IntegratedHeatPump::DecideWorkMode(state, thisFurnace.CoolingCoilIndex, TotalZoneSensibleLoad, TotalZoneLatentLoad);
9400 :
9401 1507624 : if (!FirstHVACIteration && thisFurnace.fanOp == HVAC::FanOp::Cycling &&
9402 15160 : (QZnReq < (-1.0 * HVAC::SmallLoad) || TotalZoneLatentLoad < (-HVAC::SmallLoad)) && EconoActive) {
9403 : // for cycling fan, cooling load, check whether furnace can meet load with compressor off
9404 0 : compressorOp = HVAC::CompressorOp::Off;
9405 0 : ControlVSHPOutput(state,
9406 : FurnaceNum,
9407 : FirstHVACIteration,
9408 : compressorOp,
9409 : fanOp,
9410 : TotalZoneSensibleLoad,
9411 : TotalZoneLatentLoad,
9412 : SpeedNum,
9413 : SpeedRatio,
9414 : PartLoadFrac,
9415 : OnOffAirFlowRatio,
9416 : SupHeaterLoad);
9417 :
9418 0 : TotalZoneSensibleLoad = QZnReq;
9419 0 : TotalZoneLatentLoad = QLatReq;
9420 :
9421 0 : if (SpeedNum == thisFurnace.NumOfSpeedCooling && SpeedRatio == 1.0) {
9422 : // compressor on (reset inlet air mass flow rate to starting value)
9423 0 : state.dataLoopNodes->Node(InletNode).MassFlowRate = SaveMassFlowRate;
9424 0 : compressorOp = HVAC::CompressorOp::On;
9425 0 : ControlVSHPOutput(state,
9426 : FurnaceNum,
9427 : FirstHVACIteration,
9428 : compressorOp,
9429 : fanOp,
9430 : TotalZoneSensibleLoad,
9431 : TotalZoneLatentLoad,
9432 : SpeedNum,
9433 : SpeedRatio,
9434 : PartLoadFrac,
9435 : OnOffAirFlowRatio,
9436 : SupHeaterLoad);
9437 : }
9438 : } else {
9439 : // compressor on
9440 1507624 : compressorOp = HVAC::CompressorOp::On;
9441 :
9442 1507624 : ControlVSHPOutput(state,
9443 : FurnaceNum,
9444 : FirstHVACIteration,
9445 : compressorOp,
9446 : fanOp,
9447 : TotalZoneSensibleLoad,
9448 : TotalZoneLatentLoad,
9449 : SpeedNum,
9450 : SpeedRatio,
9451 : PartLoadFrac,
9452 : OnOffAirFlowRatio,
9453 : SupHeaterLoad);
9454 : }
9455 :
9456 1507624 : if (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool) {
9457 1247320 : state.dataFurnaces->SaveCompressorPLR = PartLoadFrac;
9458 : } else {
9459 260304 : if (SpeedNum > 1) {
9460 110053 : state.dataFurnaces->SaveCompressorPLR = 1.0;
9461 : }
9462 :
9463 260304 : if (PartLoadFrac == 1.0 && state.dataFurnaces->SaveCompressorPLR < 1.0) {
9464 10 : PartLoadFrac = state.dataFurnaces->SaveCompressorPLR;
9465 : }
9466 : }
9467 :
9468 1507624 : Real64 ReheatCoilLoad = 0.0;
9469 1507624 : TotalZoneSensibleLoad = QZnReq;
9470 1507624 : TotalZoneLatentLoad = QLatReq;
9471 : // Calculate the reheat coil output
9472 3003668 : if ((ScheduleManager::GetCurrentScheduleValue(state, thisFurnace.SchedPtr) > 0.0) &&
9473 1496044 : (thisFurnace.Humidistat && thisFurnace.DehumidControlType_Num == DehumidificationControlMode::CoolReheat &&
9474 : (QLatReq < 0.0))) { // if a Humidistat is installed and dehumdification control type is CoolReheat
9475 74584 : CalcVarSpeedHeatPump(state,
9476 : FurnaceNum,
9477 : FirstHVACIteration,
9478 : compressorOp,
9479 : SpeedNum,
9480 : SpeedRatio,
9481 : PartLoadFrac,
9482 : ActualSensibleOutput,
9483 : QLatUnitOut,
9484 : TotalZoneSensibleLoad,
9485 : TotalZoneLatentLoad,
9486 : OnOffAirFlowRatio,
9487 : ReheatCoilLoad);
9488 74584 : if (thisFurnace.ZoneSequenceHeatingNum > 0) {
9489 74584 : QToHeatSetPt = (state.dataZoneEnergyDemand->ZoneSysEnergyDemand(thisFurnace.ControlZoneNum)
9490 74584 : .SequencedOutputRequiredToHeatingSP(thisFurnace.ZoneSequenceHeatingNum) /
9491 74584 : thisFurnace.ControlZoneMassFlowFrac);
9492 : } else {
9493 0 : QToHeatSetPt = (state.dataZoneEnergyDemand->ZoneSysEnergyDemand(thisFurnace.ControlZoneNum).OutputRequiredToHeatingSP /
9494 0 : thisFurnace.ControlZoneMassFlowFrac);
9495 : }
9496 : // Cooling mode or floating condition and dehumidification is required
9497 74584 : if (QToHeatSetPt < 0.0) {
9498 : // Calculate the reheat coil load wrt the heating setpoint temperature. Reheat coil picks up
9499 : // the entire excess sensible cooling (DX cooling coil and impact of outdoor air).
9500 52682 : ReheatCoilLoad = max(0.0, (QToHeatSetPt - ActualSensibleOutput));
9501 52682 : thisFurnace.DehumidInducedHeatingDemandRate = ReheatCoilLoad;
9502 : // Heating mode and dehumidification is required
9503 : } else {
9504 21902 : ReheatCoilLoad = max(QToHeatSetPt, QToHeatSetPt - ActualSensibleOutput);
9505 21902 : thisFurnace.DehumidInducedHeatingDemandRate = max(0.0, ActualSensibleOutput * (-1.0));
9506 : }
9507 :
9508 74584 : SupHeaterLoad = 0.0;
9509 74584 : CalcVarSpeedHeatPump(state,
9510 : FurnaceNum,
9511 : FirstHVACIteration,
9512 : compressorOp,
9513 : 1,
9514 : 0.0,
9515 : 0.0,
9516 : NoCompOutput,
9517 : QLatUnitOut,
9518 : 0.0,
9519 : 0.0,
9520 : OnOffAirFlowRatio,
9521 : SupHeaterLoad);
9522 :
9523 74584 : if (NoCompOutput > SystemSensibleLoad && SystemSensibleLoad > 0.0 && ReheatCoilLoad > 0.0) {
9524 : // Reduce reheat coil load if you are controlling high humidity but outside air
9525 : // and/or the supply air fan is providing enough heat to meet the system sensible load.
9526 : // This will bring the zone temp closer to the heating setpoint temp.
9527 4561 : ReheatCoilLoad = max(0.0, ReheatCoilLoad - (NoCompOutput - SystemSensibleLoad));
9528 : }
9529 : } else {
9530 : // No humidistat installed
9531 1433040 : ReheatCoilLoad = 0.0;
9532 : }
9533 :
9534 1507624 : TotalZoneSensibleLoad = QZnReq;
9535 1507624 : TotalZoneLatentLoad = QLatReq;
9536 1507624 : if (ReheatCoilLoad > 0.0) {
9537 65311 : CalcVarSpeedHeatPump(state,
9538 : FurnaceNum,
9539 : FirstHVACIteration,
9540 : compressorOp,
9541 : SpeedNum,
9542 : SpeedRatio,
9543 : PartLoadFrac,
9544 : QSensUnitOut,
9545 : QLatUnitOut,
9546 : TotalZoneSensibleLoad,
9547 : TotalZoneLatentLoad,
9548 : OnOffAirFlowRatio,
9549 : ReheatCoilLoad);
9550 : } else {
9551 1442313 : CalcVarSpeedHeatPump(state,
9552 : FurnaceNum,
9553 : FirstHVACIteration,
9554 : compressorOp,
9555 : SpeedNum,
9556 : SpeedRatio,
9557 : PartLoadFrac,
9558 : QSensUnitOut,
9559 : QLatUnitOut,
9560 : TotalZoneSensibleLoad,
9561 : TotalZoneLatentLoad,
9562 : OnOffAirFlowRatio,
9563 : SupHeaterLoad);
9564 : }
9565 :
9566 : // calculate delivered capacity
9567 1507624 : AirMassFlow = state.dataLoopNodes->Node(InletNode).MassFlowRate;
9568 :
9569 1507624 : thisFurnace.MdotFurnace = AirMassFlow;
9570 :
9571 1507624 : QTotUnitOut =
9572 1507624 : AirMassFlow * (state.dataLoopNodes->Node(OutletNode).Enthalpy - state.dataLoopNodes->Node(thisFurnace.NodeNumOfControlledZone).Enthalpy);
9573 :
9574 1507624 : state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AirMassFlow;
9575 1507624 : state.dataLoopNodes->Node(OutletNode).MassFlowRateMaxAvail = AirMassFlow;
9576 :
9577 1507624 : if (!FirstHVACIteration && AirMassFlow > 0.0 && AirLoopNum > 0) {
9578 1408368 : int TotBranchNum = state.dataAirSystemsData->PrimaryAirSystems(AirLoopNum).NumOutletBranches;
9579 1408368 : if (TotBranchNum == 1) {
9580 1408368 : int ZoneSideNodeNum = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).ZoneEquipSupplyNodeNum(1);
9581 : // THE MASS FLOW PRECISION of the system solver is not enough for some small air flow rate iterations , BY DEBUGGING
9582 : // it may cause mass flow rate occilations between airloop and zoneequip
9583 : // specify the air flow rate directly for one-to-one system, when the iteration deviation is closing the solver precision level
9584 : // 0.02 is 2 * HVACFlowRateToler, in order to accomodate the system solver precision level
9585 1408368 : if (std::abs(AirMassFlow - state.dataLoopNodes->Node(ZoneSideNodeNum).MassFlowRate) < 0.02)
9586 797935 : state.dataLoopNodes->Node(ZoneSideNodeNum).MassFlowRateMaxAvail = AirMassFlow;
9587 1408368 : state.dataLoopNodes->Node(ZoneSideNodeNum).MassFlowRate = AirMassFlow;
9588 : }
9589 :
9590 : // the below might be useful if more divergences occur
9591 : // Node(PrimaryAirSystem(AirLoopNumber)%Branch(1)%NodeNumIn)%MassFlowRateMaxAvail = AirMassFlow
9592 : // Node(PrimaryAirSystem(AirLoopNumber)%Branch(1)%NodeNumIn)%MassFlowRate = AirMassFlow
9593 : }
9594 :
9595 : // report variables
9596 1507624 : thisFurnace.DehumidInducedHeatingDemandRate = ReheatCoilLoad;
9597 1507624 : if (QZnReq > HVAC::SmallLoad) { // HEATING LOAD
9598 123543 : thisFurnace.CoolingCoilSensDemand = 0.0;
9599 123543 : thisFurnace.HeatingCoilSensDemand = QZnReq;
9600 : } else {
9601 1384081 : thisFurnace.CoolingCoilSensDemand = std::abs(QZnReq);
9602 1384081 : thisFurnace.HeatingCoilSensDemand = 0.0;
9603 : }
9604 :
9605 1507624 : thisFurnace.CompPartLoadRatio = state.dataFurnaces->SaveCompressorPLR;
9606 1507624 : if (thisFurnace.fanOp == HVAC::FanOp::Cycling) {
9607 30262 : if (SupHeaterLoad > 0.0) {
9608 13986 : thisFurnace.FanPartLoadRatio = 1.0;
9609 : } else {
9610 16276 : if (SpeedNum < 2) {
9611 8962 : thisFurnace.FanPartLoadRatio = PartLoadFrac;
9612 : } else {
9613 7314 : thisFurnace.FanPartLoadRatio = 1.0;
9614 : }
9615 : }
9616 : } else {
9617 1477362 : if (UnitOn) {
9618 1477362 : thisFurnace.FanPartLoadRatio = 1.0;
9619 : } else {
9620 0 : if (SpeedNum < 2) {
9621 0 : thisFurnace.FanPartLoadRatio = PartLoadFrac;
9622 : } else {
9623 0 : thisFurnace.FanPartLoadRatio = 1.0;
9624 : }
9625 : }
9626 : }
9627 1507624 : }
9628 :
9629 : //******************************************************************************
9630 :
9631 1507624 : void ControlVSHPOutput(EnergyPlusData &state,
9632 : int const FurnaceNum, // Unit index of engine driven heat pump
9633 : bool const FirstHVACIteration, // flag for 1st HVAC iteration in the time step
9634 : HVAC::CompressorOp const compressorOp, // compressor operation; 1=on, 0=off
9635 : HVAC::FanOp const fanOp, // operating mode: FanOp::Cycling | FanOp::Continuous
9636 : Real64 &QZnReq, // cooling or heating output needed by zone [W]
9637 : Real64 QLatReq, // latent cooling output needed by zone [W]
9638 : int &SpeedNum, // Speed number
9639 : Real64 &SpeedRatio, // unit speed ratio for DX coils
9640 : Real64 &PartLoadFrac, // unit part load fraction
9641 : Real64 &OnOffAirFlowRatio, // ratio of compressor ON airflow to AVERAGE airflow over timestep
9642 : Real64 &SupHeaterLoad // Supplemental heater load [W]
9643 : )
9644 : {
9645 :
9646 : // SUBROUTINE INFORMATION:
9647 : // AUTHOR Bo Shen, based on HVACMultiSpeedHeatPump:ControlMSHPOutput
9648 : // DATE WRITTEN March, 2012
9649 :
9650 : // PURPOSE OF THIS SUBROUTINE:
9651 : // Determine the part load fraction at low speed, and speed ratio at high speed for this time step.
9652 :
9653 : // METHODOLOGY EMPLOYED:
9654 : // Use RegulaFalsi technique to iterate on part-load ratio until convergence is achieved.
9655 :
9656 : // SUBROUTINE PARAMETER DEFINITIONS:
9657 1507624 : int constexpr MaxIte(500); // maximum number of iterations
9658 :
9659 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
9660 : Real64 FullOutput; // unit full output when compressor is operating [W]
9661 : Real64 LowOutput; // unit full output at low speed [W]
9662 : Real64 TempOutput; // unit output when iteration limit exceeded [W]
9663 : Real64 NoCompOutput; // output when no active compressor [W]
9664 : int SolFla; // Flag of RegulaFalsi solver
9665 : Real64 QCoilActual; // coil load actually delivered returned to calling component
9666 : int i; // Speed index
9667 1507624 : IntegratedHeatPump::IHPOperationMode IHPMode(IntegratedHeatPump::IHPOperationMode::Idle);
9668 :
9669 1507624 : SupHeaterLoad = 0.0;
9670 1507624 : PartLoadFrac = 0.0;
9671 1507624 : SpeedRatio = 0.0;
9672 1507624 : SpeedNum = 1;
9673 1507624 : Real64 LatOutput = 0.0;
9674 1507624 : Real64 noLatOutput = 0.0;
9675 1507624 : Real64 ErrorToler = 0.001; // Error tolerance for convergence from input deck
9676 :
9677 1507624 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
9678 1544558 : if (ScheduleManager::GetCurrentScheduleValue(state, thisFurnace.SchedPtr) == 0.0) return;
9679 :
9680 : // Get result when DX coil is off
9681 1496044 : SupHeaterLoad = 0.0;
9682 1496044 : CalcVarSpeedHeatPump(state,
9683 : FurnaceNum,
9684 : FirstHVACIteration,
9685 : compressorOp,
9686 : SpeedNum,
9687 : SpeedRatio,
9688 : PartLoadFrac,
9689 : NoCompOutput,
9690 : noLatOutput,
9691 : 0.0,
9692 : 0.0,
9693 : OnOffAirFlowRatio,
9694 : SupHeaterLoad);
9695 :
9696 1496044 : if (thisFurnace.bIsIHP) {
9697 10094 : IHPMode = IntegratedHeatPump::GetCurWorkMode(state, thisFurnace.CoolingCoilIndex);
9698 10094 : if ((IntegratedHeatPump::IHPOperationMode::DedicatedWaterHtg == IHPMode) ||
9699 : (IntegratedHeatPump::IHPOperationMode::SCWHMatchWH == IHPMode)) { // cooling capacity is a resultant
9700 280 : return;
9701 : }
9702 : }
9703 :
9704 : // If cooling and NoCompOutput < QZnReq, the coil needs to be off
9705 : // If heating and NoCompOutput > QZnReq, the coil needs to be off
9706 : // If no cooling or heating and no latent load, the coil needs to be off
9707 1495764 : if (QZnReq < -HVAC::SmallLoad) {
9708 1285333 : if (NoCompOutput < QZnReq && QLatReq >= -HVAC::SmallLoad) return;
9709 210431 : } else if (QZnReq > HVAC::SmallLoad) {
9710 123543 : if (NoCompOutput > QZnReq && QLatReq >= -HVAC::SmallLoad) return;
9711 122174 : if (QLatReq <= -HVAC::SmallLoad) QZnReq = 0.0; // Zero heating load to allow dehumidification
9712 : } else {
9713 86888 : if (QLatReq >= -HVAC::SmallLoad) return;
9714 : }
9715 :
9716 : // Get full load result
9717 1461601 : PartLoadFrac = 1.0;
9718 1461601 : SpeedRatio = 1.0;
9719 1461601 : if (thisFurnace.HeatCoolMode == Furnaces::ModeOfOperation::HeatingMode) {
9720 105096 : SpeedNum = thisFurnace.NumOfSpeedHeating;
9721 1356505 : } else if (thisFurnace.HeatCoolMode == Furnaces::ModeOfOperation::CoolingMode) {
9722 1301628 : SpeedNum = thisFurnace.NumOfSpeedCooling;
9723 54877 : } else if (QLatReq < -HVAC::SmallLoad) {
9724 54476 : SpeedNum = thisFurnace.NumOfSpeedCooling;
9725 : } else {
9726 401 : SpeedNum = 1;
9727 401 : PartLoadFrac = 0.0;
9728 : }
9729 :
9730 1461601 : if (thisFurnace.bIsIHP) SpeedNum = IntegratedHeatPump::GetMaxSpeedNumIHP(state, thisFurnace.CoolingCoilIndex);
9731 :
9732 1461601 : CalcVarSpeedHeatPump(state,
9733 : FurnaceNum,
9734 : FirstHVACIteration,
9735 : compressorOp,
9736 : SpeedNum,
9737 : SpeedRatio,
9738 : PartLoadFrac,
9739 : FullOutput,
9740 : LatOutput,
9741 : QZnReq,
9742 : QLatReq,
9743 : OnOffAirFlowRatio,
9744 : SupHeaterLoad);
9745 :
9746 1461601 : if (QLatReq < (-1.0 * HVAC::SmallLoad)) { // dehumidification mode
9747 74584 : if (QLatReq <= LatOutput || (QZnReq < -HVAC::SmallLoad && QZnReq <= FullOutput) || (QZnReq > HVAC::SmallLoad && QZnReq >= FullOutput)) {
9748 138 : PartLoadFrac = 1.0;
9749 138 : SpeedRatio = 1.0;
9750 138 : thisFurnace.CompPartLoadRatio = PartLoadFrac;
9751 138 : thisFurnace.CompSpeedRatio = SpeedRatio;
9752 138 : thisFurnace.CompSpeedNum = SpeedNum;
9753 138 : return;
9754 : }
9755 1387017 : } else if (QZnReq < -HVAC::SmallLoad) {
9756 1281851 : if (QZnReq <= FullOutput) {
9757 2353 : PartLoadFrac = 1.0;
9758 2353 : SpeedRatio = 1.0;
9759 2353 : thisFurnace.CompPartLoadRatio = PartLoadFrac;
9760 2353 : thisFurnace.CompSpeedRatio = SpeedRatio;
9761 2353 : thisFurnace.CompSpeedNum = SpeedNum;
9762 2353 : return;
9763 : }
9764 : } else {
9765 105166 : if (QZnReq >= FullOutput) {
9766 46302 : PartLoadFrac = 1.0;
9767 46302 : SpeedRatio = 1.0;
9768 : // may need supplemental heating so don't return in heating mode
9769 : }
9770 : }
9771 :
9772 1459110 : if ((QZnReq < -HVAC::SmallLoad && NoCompOutput - QZnReq > HVAC::SmallLoad) ||
9773 176512 : (QZnReq > HVAC::SmallLoad && QZnReq - NoCompOutput > HVAC::SmallLoad)) {
9774 1387744 : if ((QZnReq > HVAC::SmallLoad && QZnReq < FullOutput) || (QZnReq < (-1.0 * HVAC::SmallLoad) && QZnReq > FullOutput)) {
9775 : // Check whether the low speed coil can meet the load or not
9776 1341462 : CalcVarSpeedHeatPump(state,
9777 : FurnaceNum,
9778 : FirstHVACIteration,
9779 : compressorOp,
9780 : 1,
9781 : 0.0,
9782 : 1.0,
9783 : LowOutput,
9784 : LatOutput,
9785 : QZnReq,
9786 : QLatReq,
9787 : OnOffAirFlowRatio,
9788 : SupHeaterLoad);
9789 1341462 : if ((QZnReq > HVAC::SmallLoad && QZnReq <= LowOutput) || (QZnReq < (-HVAC::SmallLoad) && QZnReq >= LowOutput)) {
9790 : // Calculate the part load fraction
9791 335879 : SpeedRatio = 0.0;
9792 335879 : SpeedNum = 1;
9793 : auto f = // (AUTO_OK_LAMBDA)
9794 2031213 : [&state, FurnaceNum, FirstHVACIteration, QZnReq, OnOffAirFlowRatio, SupHeaterLoad, compressorOp](Real64 const PartLoadFrac) {
9795 1695334 : return VSHPCyclingResidual(
9796 1695334 : state, PartLoadFrac, FurnaceNum, FirstHVACIteration, QZnReq, OnOffAirFlowRatio, SupHeaterLoad, compressorOp, 1.0);
9797 335879 : };
9798 335879 : General::SolveRoot(state, ErrorToler, MaxIte, SolFla, PartLoadFrac, f, 0.0, 1.0);
9799 335879 : if (SolFla == -1) {
9800 0 : if (!state.dataGlobal->WarmupFlag) {
9801 0 : if (thisFurnace.ErrCountCyc == 0) {
9802 0 : ++thisFurnace.ErrCountCyc;
9803 0 : ShowWarningError(
9804 0 : state, format("Iteration limit exceeded calculating VS WSHP unit cycling ratio, for unit={}", thisFurnace.Name));
9805 0 : ShowContinueErrorTimeStamp(state, format("Cycling ratio returned={:.2R}", PartLoadFrac));
9806 : } else {
9807 0 : ShowRecurringWarningErrorAtEnd(
9808 : state,
9809 0 : thisFurnace.Name + "\": Iteration limit warning exceeding calculating DX unit cycling ratio continues...",
9810 0 : thisFurnace.ErrIndexCyc,
9811 : PartLoadFrac,
9812 : PartLoadFrac);
9813 : }
9814 : }
9815 335879 : } else if (SolFla == -2) {
9816 0 : ShowFatalError(
9817 0 : state, format("VS WSHP unit cycling ratio calculation failed: cycling limits exceeded, for unit={}", thisFurnace.Name));
9818 : }
9819 335879 : } else {
9820 : // Check to see which speed to meet the load
9821 1005583 : PartLoadFrac = 1.0;
9822 1005583 : SpeedRatio = 1.0;
9823 1005583 : if (QZnReq < -HVAC::SmallLoad) { // Cooling
9824 4429293 : for (i = 2; i <= thisFurnace.NumOfSpeedCooling; ++i) {
9825 4429293 : CalcVarSpeedHeatPump(state,
9826 : FurnaceNum,
9827 : FirstHVACIteration,
9828 : compressorOp,
9829 : i,
9830 : SpeedRatio,
9831 : PartLoadFrac,
9832 : TempOutput,
9833 : LatOutput,
9834 : QZnReq,
9835 : QLatReq,
9836 : OnOffAirFlowRatio,
9837 : SupHeaterLoad);
9838 :
9839 4429293 : if (QZnReq >= TempOutput) {
9840 965495 : SpeedNum = i;
9841 965495 : break;
9842 : }
9843 : }
9844 : } else {
9845 190721 : for (i = 2; i <= thisFurnace.NumOfSpeedHeating; ++i) {
9846 190721 : CalcVarSpeedHeatPump(state,
9847 : FurnaceNum,
9848 : FirstHVACIteration,
9849 : compressorOp,
9850 : i,
9851 : SpeedRatio,
9852 : PartLoadFrac,
9853 : TempOutput,
9854 : LatOutput,
9855 : QZnReq,
9856 : QLatReq,
9857 : OnOffAirFlowRatio,
9858 : SupHeaterLoad);
9859 190721 : if (QZnReq <= TempOutput) {
9860 40088 : SpeedNum = i;
9861 40088 : break;
9862 : }
9863 : }
9864 : }
9865 4433648 : auto f = [&state, FurnaceNum, FirstHVACIteration, QZnReq, OnOffAirFlowRatio, SupHeaterLoad, SpeedNum, compressorOp](
9866 3428065 : Real64 const SpeedRatio) {
9867 3428065 : return VSHPSpeedResidual(
9868 3428065 : state, SpeedRatio, FurnaceNum, FirstHVACIteration, QZnReq, OnOffAirFlowRatio, SupHeaterLoad, SpeedNum, compressorOp, 1.0);
9869 1005583 : };
9870 1005583 : General::SolveRoot(state, ErrorToler, MaxIte, SolFla, SpeedRatio, f, 1.0e-10, 1.0);
9871 1005583 : if (SolFla == -1) {
9872 0 : if (!state.dataGlobal->WarmupFlag) {
9873 0 : if (thisFurnace.ErrCountVar == 0) {
9874 0 : ++thisFurnace.ErrCountVar;
9875 0 : ShowWarningError(
9876 0 : state, format("Iteration limit exceeded calculating VS WSHP unit speed ratio, for unit={}", thisFurnace.Name));
9877 0 : ShowContinueErrorTimeStamp(state, format("Speed ratio returned=[{:.2R}], Speed number ={}", SpeedRatio, SpeedNum));
9878 : } else {
9879 0 : ShowRecurringWarningErrorAtEnd(
9880 : state,
9881 0 : thisFurnace.Name + "\": Iteration limit warning exceeding calculating DX unit speed ratio continues...",
9882 0 : thisFurnace.ErrIndexVar,
9883 : SpeedRatio,
9884 : SpeedRatio);
9885 : }
9886 : }
9887 1005583 : } else if (SolFla == -2) {
9888 0 : ShowFatalError(
9889 0 : state, format("VS WSHP unit compressor speed calculation failed: speed limits exceeded, for unit={}", thisFurnace.Name));
9890 : }
9891 : }
9892 1341462 : } else {
9893 46282 : LatOutput = noLatOutput; // reset full output if not needed for sensible load
9894 46282 : SpeedNum = 1; // reset speed from full output test
9895 : }
9896 1387744 : } else {
9897 71366 : LatOutput = noLatOutput; // reset full output if not needed for sensible load
9898 71366 : SpeedNum = 1; // reset speed from full output test
9899 : }
9900 : // meet the latent load
9901 1459110 : if (QLatReq < -HVAC::SmallLoad && QLatReq < LatOutput) {
9902 71282 : PartLoadFrac = 1.0;
9903 71282 : SpeedRatio = 1.0;
9904 113772 : for (i = SpeedNum; i <= thisFurnace.NumOfSpeedCooling; ++i) {
9905 113772 : CalcVarSpeedHeatPump(state,
9906 : FurnaceNum,
9907 : FirstHVACIteration,
9908 : compressorOp,
9909 : i,
9910 : SpeedRatio,
9911 : PartLoadFrac,
9912 : TempOutput,
9913 : LatOutput,
9914 : QZnReq,
9915 : QLatReq,
9916 : OnOffAirFlowRatio,
9917 : SupHeaterLoad);
9918 :
9919 113772 : if (QLatReq > LatOutput) {
9920 71282 : SpeedNum = i;
9921 71282 : break;
9922 : }
9923 : }
9924 71282 : if (QLatReq - LatOutput > HVAC::SmallLoad) {
9925 71227 : if (SpeedNum < 2) {
9926 : auto f = // (AUTO_OK_LAMBDA)
9927 316336 : [&state, FurnaceNum, FirstHVACIteration, QLatReq, OnOffAirFlowRatio, SupHeaterLoad, compressorOp](Real64 const PartLoadFrac) {
9928 269407 : return VSHPCyclingResidual(
9929 269407 : state, PartLoadFrac, FurnaceNum, FirstHVACIteration, QLatReq, OnOffAirFlowRatio, SupHeaterLoad, compressorOp, 0.0);
9930 46929 : };
9931 46929 : General::SolveRoot(state, ErrorToler, MaxIte, SolFla, PartLoadFrac, f, 0.0, 1.0);
9932 : } else {
9933 130582 : auto f = [&state, FurnaceNum, FirstHVACIteration, QLatReq, OnOffAirFlowRatio, SupHeaterLoad, SpeedNum, compressorOp](
9934 106284 : Real64 const SpeedRatio) {
9935 106284 : return VSHPSpeedResidual(state,
9936 : SpeedRatio,
9937 : FurnaceNum,
9938 : FirstHVACIteration,
9939 : QLatReq,
9940 : OnOffAirFlowRatio,
9941 : SupHeaterLoad,
9942 : SpeedNum,
9943 : compressorOp,
9944 106284 : 0.0);
9945 24298 : };
9946 24298 : General::SolveRoot(state, ErrorToler, MaxIte, SolFla, SpeedRatio, f, 1.0e-10, 1.0);
9947 : }
9948 71227 : if (SolFla == -1) {
9949 0 : if (!state.dataGlobal->WarmupFlag) {
9950 0 : if (thisFurnace.ErrCountVar2 == 0) {
9951 0 : ++thisFurnace.ErrCountVar2;
9952 0 : ShowWarningError(state,
9953 0 : format("Iteration limit exceeded calculating VS WSHP unit speed ratio, for unit={}", thisFurnace.Name));
9954 0 : ShowContinueErrorTimeStamp(state, format("Speed ratio returned=[{:.2R}], Speed number ={}", SpeedRatio, SpeedNum));
9955 : } else {
9956 0 : ShowRecurringWarningErrorAtEnd(state,
9957 0 : thisFurnace.Name +
9958 : "\": Iteration limit warning exceeding calculating DX unit speed ratio continues...",
9959 0 : thisFurnace.ErrIndexVar,
9960 : SpeedRatio,
9961 : SpeedRatio);
9962 : }
9963 : }
9964 71227 : } else if (SolFla == -2) {
9965 0 : ShowFatalError(state,
9966 0 : format("VS WSHP unit compressor speed calculation failed: speed limits exceeded, for unit={}", thisFurnace.Name));
9967 : }
9968 : }
9969 : }
9970 : // end meet the latent load
9971 :
9972 : // if the heating coil cannot meet the load, trim with supplemental heater
9973 : // occurs with constant fan mode when compressor is on or off
9974 : // occurs with cycling fan mode when compressor PLR is equal to 1
9975 1459110 : if ((QZnReq > HVAC::SmallLoad && QZnReq > FullOutput) && (thisFurnace.SuppHeatCoilIndex != 0)) {
9976 25968 : PartLoadFrac = 1.0;
9977 25968 : SpeedRatio = 1.0;
9978 25968 : if (thisFurnace.NumOfSpeedHeating > 0)
9979 25968 : SpeedNum = thisFurnace.NumOfSpeedHeating; // maximum heating speed, avoid zero for cooling only mode
9980 :
9981 25968 : if (state.dataEnvrn->OutDryBulbTemp <= thisFurnace.MaxOATSuppHeat) {
9982 25968 : SupHeaterLoad = QZnReq - FullOutput;
9983 : } else {
9984 0 : SupHeaterLoad = 0.0;
9985 : }
9986 25968 : CalcVarSpeedHeatPump(state,
9987 : FurnaceNum,
9988 : FirstHVACIteration,
9989 : compressorOp,
9990 : SpeedNum,
9991 : SpeedRatio,
9992 : PartLoadFrac,
9993 : TempOutput,
9994 : LatOutput,
9995 : QZnReq,
9996 : QLatReq,
9997 : OnOffAirFlowRatio,
9998 : SupHeaterLoad);
9999 : }
10000 :
10001 : // check the outlet of the supplemental heater to be lower than the maximum supplemental heater supply air temperature
10002 1459110 : if (state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum).Temp > thisFurnace.DesignMaxOutletTemp && SupHeaterLoad > 0.0) {
10003 :
10004 : // If the supply air temperature is to high, turn off the supplemental heater to recalculate the outlet temperature
10005 96 : CalcNonDXHeatingCoils(state, FurnaceNum, true, FirstHVACIteration, 0.0, fanOp, QCoilActual);
10006 : // If the outlet temperature is below the maximum supplemental heater supply air temperature, reduce the load passed to
10007 : // the supplemental heater, otherwise leave the supplemental heater off. If the supplemental heater is to be turned on,
10008 : // use the outlet conditions when the supplemental heater was off (CALL above) as the inlet conditions for the calculation
10009 : // of supplemental heater load to just meet the maximum supply air temperature from the supplemental heater.
10010 96 : if (state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum).Temp < thisFurnace.DesignMaxOutletTemp) {
10011 96 : Real64 CpAir = Psychrometrics::PsyCpAirFnW(state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum).HumRat);
10012 96 : SupHeaterLoad = state.dataLoopNodes->Node(thisFurnace.FurnaceInletNodeNum).MassFlowRate * CpAir *
10013 96 : (thisFurnace.DesignMaxOutletTemp - state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum).Temp);
10014 :
10015 : } else {
10016 0 : SupHeaterLoad = 0.0;
10017 : }
10018 : }
10019 :
10020 : // prepare module level output
10021 1459110 : thisFurnace.CompPartLoadRatio = PartLoadFrac;
10022 1459110 : thisFurnace.CompSpeedRatio = SpeedRatio;
10023 1459110 : thisFurnace.CompSpeedNum = SpeedNum;
10024 1459110 : thisFurnace.CoolingCoilLatentDemand = std::abs(QLatReq);
10025 :
10026 1459110 : if (thisFurnace.fanOp == HVAC::FanOp::Continuous) {
10027 1433624 : thisFurnace.FanPartLoadRatio = 1.0;
10028 : } else {
10029 25486 : thisFurnace.FanPartLoadRatio = PartLoadFrac;
10030 : }
10031 : }
10032 :
10033 : //******************************************************************************
10034 :
10035 17687782 : void CalcVarSpeedHeatPump(EnergyPlusData &state,
10036 : int const FurnaceNum, // Variable speed heat pump number
10037 : bool const FirstHVACIteration, // Flag for 1st HVAC iteration
10038 : HVAC::CompressorOp const compressorOp, // Compressor on/off; 1=on, 0=off
10039 : int const SpeedNum, // Speed number
10040 : Real64 const SpeedRatio, // Compressor speed ratio
10041 : Real64 const PartLoadFrac, // Compressor part load fraction
10042 : Real64 &SensibleLoadMet, // Sensible cooling load met (furnace outlet with respect to control zone temp)
10043 : Real64 &LatentLoadMet, // Latent cooling load met (furnace outlet with respect to control zone humidity ratio)
10044 : Real64 const QZnReq, // Zone load (W)
10045 : Real64 const QLatReq, // Zone latent load []
10046 : Real64 &OnOffAirFlowRatio, // Ratio of compressor ON airflow to AVERAGE airflow over timestep
10047 : Real64 const SupHeaterLoad // supplemental heater load (W)
10048 : )
10049 : {
10050 : // SUBROUTINE INFORMATION:
10051 : // AUTHOR: Bo Shen, based on HVACMultiSpeedHeatPump:CalcMSHeatPump
10052 : // DATE WRITTEN: March 2012
10053 :
10054 : // PURPOSE OF THIS SUBROUTINE:
10055 : // This routine will calcultes MSHP performance based on given system load
10056 :
10057 17687782 : Real64 SavePartloadRatio = 0.0; // part-load ratio
10058 17687782 : Real64 SaveSpeedRatio = 0.0; // speed ratio
10059 17687782 : Real64 QCoilActual = 0.0; // coil load actually delivered returned to calling component
10060 17687782 : Real64 HeatCoilLoad = 0.0; // required heating coil load
10061 :
10062 17687782 : state.dataFurnaces->SaveCompressorPLR = 0.0;
10063 :
10064 : // Set inlet air mass flow rate based on PLR and compressor on/off air flow rates
10065 17687782 : SetVSHPAirFlow(state, FurnaceNum, PartLoadFrac, OnOffAirFlowRatio, SpeedNum, SpeedRatio);
10066 :
10067 17687782 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
10068 :
10069 17687782 : if ((SupHeaterLoad > 1.0e-10) && (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool) && (thisFurnace.SuppHeatCoilIndex == 0)) {
10070 : // ONLY HEATING COIL, NO SUPPLEMENTAL COIL, USED FOR REHEAT DURING DUHMI
10071 0 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity * PartLoadFrac; // REHEAT IN FAN ON TIME
10072 :
10073 0 : if (HeatCoilLoad > SupHeaterLoad) HeatCoilLoad = SupHeaterLoad; // HEATING COIL RUN TIME < FAN ON TIME
10074 :
10075 17687782 : } else if ((QZnReq > HVAC::SmallLoad) && (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool)) {
10076 63320 : HeatCoilLoad = thisFurnace.DesignHeatingCapacity * PartLoadFrac;
10077 : } else {
10078 17624462 : HeatCoilLoad = 0.0;
10079 : }
10080 :
10081 17687782 : Real64 AirMassFlow = state.dataLoopNodes->Node(thisFurnace.FurnaceInletNodeNum).MassFlowRate;
10082 : // if blow through, simulate fan then coils
10083 17687782 : if (thisFurnace.fanPlace == HVAC::FanPlace::BlowThru) {
10084 17687782 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
10085 :
10086 17687782 : if ((!thisFurnace.CoolingCoilUpstream) && (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool)) {
10087 : // simulate thisFurnace heating coil
10088 0 : bool SuppHeatingCoilFlag = false; // if true simulates supplemental heating coil
10089 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, thisFurnace.fanOp, QCoilActual);
10090 : }
10091 :
10092 31623779 : if ((QZnReq < -HVAC::SmallLoad || (QLatReq < -HVAC::SmallLoad)) &&
10093 13935997 : (state.dataEnvrn->OutDryBulbTemp >= thisFurnace.MinOATCompressorCooling)) { // COOLING MODE or dehumidification mode
10094 :
10095 13935997 : if (thisFurnace.bIsIHP) {
10096 73294 : IntegratedHeatPump::SimIHP(state,
10097 : BlankString,
10098 36647 : thisFurnace.CoolingCoilIndex,
10099 : thisFurnace.fanOp,
10100 : compressorOp,
10101 : PartLoadFrac,
10102 : SpeedNum,
10103 : SpeedRatio,
10104 : QZnReq,
10105 : QLatReq,
10106 : false,
10107 : false,
10108 : OnOffAirFlowRatio);
10109 : } else {
10110 13899350 : VariableSpeedCoils::SimVariableSpeedCoils(state,
10111 : BlankString,
10112 13899350 : thisFurnace.CoolingCoilIndex,
10113 : thisFurnace.fanOp,
10114 : compressorOp,
10115 : PartLoadFrac,
10116 : SpeedNum,
10117 : SpeedRatio,
10118 : QZnReq,
10119 : QLatReq,
10120 : OnOffAirFlowRatio);
10121 : }
10122 :
10123 13935997 : SavePartloadRatio = PartLoadFrac;
10124 13935997 : SaveSpeedRatio = SpeedRatio;
10125 :
10126 13935997 : state.dataFurnaces->SaveCompressorPLR = state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.CoolingCoilIndex).PartLoadRatio;
10127 : } else {
10128 3751785 : if (thisFurnace.bIsIHP) {
10129 51358 : IntegratedHeatPump::SimIHP(state,
10130 : BlankString,
10131 25679 : thisFurnace.CoolingCoilIndex,
10132 : thisFurnace.fanOp,
10133 : compressorOp,
10134 : PartLoadFrac,
10135 : SpeedNum,
10136 : SpeedRatio,
10137 : QZnReq,
10138 : QLatReq,
10139 : false,
10140 : false,
10141 : OnOffAirFlowRatio);
10142 : } else {
10143 3726106 : VariableSpeedCoils::SimVariableSpeedCoils(
10144 3726106 : state, BlankString, thisFurnace.CoolingCoilIndex, thisFurnace.fanOp, compressorOp, 0.0, 1, 0.0, 0.0, 0.0, OnOffAirFlowRatio);
10145 : }
10146 : }
10147 :
10148 17687782 : if (thisFurnace.type != HVAC::UnitarySysType::Unitary_HeatCool) {
10149 2335958 : if ((QZnReq > HVAC::SmallLoad) && state.dataFurnaces->HeatingLoad) {
10150 598955 : if (thisFurnace.bIsIHP) {
10151 27964 : IntegratedHeatPump::SimIHP(state,
10152 : BlankString,
10153 13982 : thisFurnace.HeatingCoilIndex,
10154 : thisFurnace.fanOp,
10155 : compressorOp,
10156 : PartLoadFrac,
10157 : SpeedNum,
10158 : SpeedRatio,
10159 : QZnReq,
10160 : QLatReq,
10161 : false,
10162 : false,
10163 : OnOffAirFlowRatio);
10164 : } else {
10165 584973 : VariableSpeedCoils::SimVariableSpeedCoils(state,
10166 : BlankString,
10167 584973 : thisFurnace.HeatingCoilIndex,
10168 : thisFurnace.fanOp,
10169 : compressorOp,
10170 : PartLoadFrac,
10171 : SpeedNum,
10172 : SpeedRatio,
10173 : QZnReq,
10174 : QLatReq,
10175 : OnOffAirFlowRatio);
10176 : }
10177 :
10178 598955 : SavePartloadRatio = PartLoadFrac;
10179 598955 : SaveSpeedRatio = SpeedRatio;
10180 :
10181 598955 : state.dataFurnaces->SaveCompressorPLR = state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.HeatingCoilIndex).PartLoadRatio;
10182 : } else {
10183 1737003 : if (thisFurnace.bIsIHP) {
10184 96688 : IntegratedHeatPump::SimIHP(state,
10185 : BlankString,
10186 48344 : thisFurnace.CoolingCoilIndex,
10187 : thisFurnace.fanOp,
10188 : compressorOp,
10189 : PartLoadFrac,
10190 : SpeedNum,
10191 : SpeedRatio,
10192 : QZnReq,
10193 : QLatReq,
10194 : false,
10195 : false,
10196 : OnOffAirFlowRatio);
10197 : } else {
10198 1688659 : VariableSpeedCoils::SimVariableSpeedCoils(state,
10199 : BlankString,
10200 1688659 : thisFurnace.HeatingCoilIndex,
10201 : thisFurnace.fanOp,
10202 : compressorOp,
10203 : 0.0,
10204 : 1,
10205 : 0.0,
10206 : 0.0,
10207 : 0.0,
10208 : OnOffAirFlowRatio);
10209 : }
10210 : }
10211 15351824 : } else if (thisFurnace.CoolingCoilUpstream && (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool)) {
10212 : // simulate thisFurnace heating coil
10213 15351824 : bool SuppHeatingCoilFlag = false; // if true simulates supplemental heating coil
10214 15351824 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, thisFurnace.fanOp, QCoilActual);
10215 : }
10216 :
10217 : // Call twice to ensure the fan outlet conditions are updated
10218 17687782 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
10219 :
10220 17687782 : if ((!thisFurnace.CoolingCoilUpstream) && (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool)) {
10221 : // simulate thisFurnace heating coil
10222 0 : bool SuppHeatingCoilFlag = false; // if true simulates supplemental heating coil
10223 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, thisFurnace.fanOp, QCoilActual);
10224 : }
10225 :
10226 31623779 : if ((QZnReq < -HVAC::SmallLoad || (QLatReq < -HVAC::SmallLoad)) &&
10227 13935997 : (state.dataEnvrn->OutDryBulbTemp >= thisFurnace.MinOATCompressorCooling)) {
10228 :
10229 13935997 : if (thisFurnace.bIsIHP) {
10230 73294 : IntegratedHeatPump::SimIHP(state,
10231 : BlankString,
10232 36647 : thisFurnace.CoolingCoilIndex,
10233 : thisFurnace.fanOp,
10234 : compressorOp,
10235 : PartLoadFrac,
10236 : SpeedNum,
10237 : SpeedRatio,
10238 : QZnReq,
10239 : QLatReq,
10240 : false,
10241 : false,
10242 : OnOffAirFlowRatio);
10243 : } else {
10244 13899350 : VariableSpeedCoils::SimVariableSpeedCoils(state,
10245 : BlankString,
10246 13899350 : thisFurnace.CoolingCoilIndex,
10247 : thisFurnace.fanOp,
10248 : compressorOp,
10249 : PartLoadFrac,
10250 : SpeedNum,
10251 : SpeedRatio,
10252 : QZnReq,
10253 : QLatReq,
10254 : OnOffAirFlowRatio);
10255 : }
10256 :
10257 13935997 : SavePartloadRatio = PartLoadFrac;
10258 13935997 : SaveSpeedRatio = SpeedRatio;
10259 13935997 : state.dataFurnaces->SaveCompressorPLR = state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.CoolingCoilIndex).PartLoadRatio;
10260 : } else {
10261 :
10262 3751785 : if (thisFurnace.bIsIHP) {
10263 51358 : IntegratedHeatPump::SimIHP(state,
10264 : BlankString,
10265 25679 : thisFurnace.CoolingCoilIndex,
10266 : thisFurnace.fanOp,
10267 : compressorOp,
10268 : PartLoadFrac,
10269 : SpeedNum,
10270 : SpeedRatio,
10271 : QZnReq,
10272 : QLatReq,
10273 : false,
10274 : false,
10275 : OnOffAirFlowRatio);
10276 : } else {
10277 3726106 : VariableSpeedCoils::SimVariableSpeedCoils(
10278 3726106 : state, BlankString, thisFurnace.CoolingCoilIndex, thisFurnace.fanOp, compressorOp, 0.0, 1, 0.0, 0.0, 0.0, OnOffAirFlowRatio);
10279 : }
10280 : }
10281 :
10282 17687782 : if (thisFurnace.type != HVAC::UnitarySysType::Unitary_HeatCool) {
10283 2335958 : if ((QZnReq > HVAC::SmallLoad) && state.dataFurnaces->HeatingLoad) {
10284 598955 : if (thisFurnace.bIsIHP) {
10285 27964 : IntegratedHeatPump::SimIHP(state,
10286 : BlankString,
10287 13982 : thisFurnace.HeatingCoilIndex,
10288 : thisFurnace.fanOp,
10289 : compressorOp,
10290 : PartLoadFrac,
10291 : SpeedNum,
10292 : SpeedRatio,
10293 : QZnReq,
10294 : QLatReq,
10295 : false,
10296 : false,
10297 : OnOffAirFlowRatio);
10298 : } else {
10299 584973 : VariableSpeedCoils::SimVariableSpeedCoils(state,
10300 : BlankString,
10301 584973 : thisFurnace.HeatingCoilIndex,
10302 : thisFurnace.fanOp,
10303 : compressorOp,
10304 : PartLoadFrac,
10305 : SpeedNum,
10306 : SpeedRatio,
10307 : QZnReq,
10308 : QLatReq,
10309 : OnOffAirFlowRatio);
10310 : }
10311 :
10312 598955 : SavePartloadRatio = PartLoadFrac;
10313 598955 : SaveSpeedRatio = SpeedRatio;
10314 598955 : state.dataFurnaces->SaveCompressorPLR = state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.HeatingCoilIndex).PartLoadRatio;
10315 : } else {
10316 1737003 : if (thisFurnace.bIsIHP) {
10317 96688 : IntegratedHeatPump::SimIHP(state,
10318 : BlankString,
10319 48344 : thisFurnace.CoolingCoilIndex,
10320 : thisFurnace.fanOp,
10321 : compressorOp,
10322 : PartLoadFrac,
10323 : SpeedNum,
10324 : SpeedRatio,
10325 : QZnReq,
10326 : QLatReq,
10327 : false,
10328 : false,
10329 : OnOffAirFlowRatio);
10330 : } else {
10331 1688659 : VariableSpeedCoils::SimVariableSpeedCoils(state,
10332 : BlankString,
10333 1688659 : thisFurnace.HeatingCoilIndex,
10334 : thisFurnace.fanOp,
10335 : compressorOp,
10336 : 0.0,
10337 : 1,
10338 : 0.0,
10339 : 0.0,
10340 : 0.0,
10341 : OnOffAirFlowRatio);
10342 : }
10343 : }
10344 15351824 : } else if (thisFurnace.CoolingCoilUpstream && (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool)) {
10345 : // simulate thisFurnace heating coil
10346 15351824 : bool SuppHeatingCoilFlag = false; // if true simulates supplemental heating coil
10347 15351824 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, thisFurnace.fanOp, QCoilActual);
10348 : }
10349 :
10350 : // Simulate supplemental heating coil for blow through fan
10351 17687782 : if (thisFurnace.SuppHeatCoilIndex > 0) {
10352 2335958 : bool SuppHeatingCoilFlag = true; // if true simulates supplemental heating coil
10353 2335958 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, SupHeaterLoad, thisFurnace.fanOp, QCoilActual);
10354 : }
10355 : } else { // otherwise simulate DX coils then fan then supplemental heater
10356 :
10357 0 : if ((!thisFurnace.CoolingCoilUpstream) && (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool)) {
10358 : // simulate thisFurnace heating coil
10359 0 : bool SuppHeatingCoilFlag = false; // if true simulates supplemental heating coil
10360 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, thisFurnace.fanOp, QCoilActual);
10361 : }
10362 :
10363 0 : if ((QZnReq < -HVAC::SmallLoad || (QLatReq < -HVAC::SmallLoad)) &&
10364 0 : (state.dataEnvrn->OutDryBulbTemp >= thisFurnace.MinOATCompressorCooling)) {
10365 :
10366 0 : if (thisFurnace.bIsIHP) {
10367 0 : IntegratedHeatPump::SimIHP(state,
10368 : BlankString,
10369 0 : thisFurnace.CoolingCoilIndex,
10370 : thisFurnace.fanOp,
10371 : compressorOp,
10372 : PartLoadFrac,
10373 : SpeedNum,
10374 : SpeedRatio,
10375 : QZnReq,
10376 : QLatReq,
10377 : false,
10378 : false,
10379 : OnOffAirFlowRatio);
10380 : } else {
10381 0 : VariableSpeedCoils::SimVariableSpeedCoils(state,
10382 : BlankString,
10383 0 : thisFurnace.CoolingCoilIndex,
10384 : thisFurnace.fanOp,
10385 : compressorOp,
10386 : PartLoadFrac,
10387 : SpeedNum,
10388 : SpeedRatio,
10389 : QZnReq,
10390 : QLatReq,
10391 : OnOffAirFlowRatio);
10392 : }
10393 :
10394 0 : SavePartloadRatio = PartLoadFrac;
10395 0 : SaveSpeedRatio = SpeedRatio;
10396 :
10397 0 : state.dataFurnaces->SaveCompressorPLR = state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.CoolingCoilIndex).PartLoadRatio;
10398 : } else {
10399 0 : if (thisFurnace.bIsIHP) {
10400 0 : IntegratedHeatPump::SimIHP(state,
10401 : BlankString,
10402 0 : thisFurnace.CoolingCoilIndex,
10403 : thisFurnace.fanOp,
10404 : compressorOp,
10405 : PartLoadFrac,
10406 : SpeedNum,
10407 : SpeedRatio,
10408 : QZnReq,
10409 : QLatReq,
10410 : false,
10411 : false,
10412 : OnOffAirFlowRatio);
10413 : } else {
10414 0 : VariableSpeedCoils::SimVariableSpeedCoils(
10415 0 : state, BlankString, thisFurnace.CoolingCoilIndex, thisFurnace.fanOp, compressorOp, 0.0, 1, 0.0, 0.0, 0.0, OnOffAirFlowRatio);
10416 : }
10417 : }
10418 :
10419 0 : if (thisFurnace.type != HVAC::UnitarySysType::Unitary_HeatCool) {
10420 0 : if (QZnReq > HVAC::SmallLoad && (state.dataEnvrn->OutDryBulbTemp >= thisFurnace.MinOATCompressorCooling)) {
10421 :
10422 0 : if (thisFurnace.bIsIHP) {
10423 0 : IntegratedHeatPump::SimIHP(state,
10424 : BlankString,
10425 0 : thisFurnace.HeatingCoilIndex,
10426 : thisFurnace.fanOp,
10427 : compressorOp,
10428 : PartLoadFrac,
10429 : SpeedNum,
10430 : SpeedRatio,
10431 : QZnReq,
10432 : QLatReq,
10433 : false,
10434 : false,
10435 : OnOffAirFlowRatio);
10436 : } else {
10437 0 : VariableSpeedCoils::SimVariableSpeedCoils(state,
10438 : BlankString,
10439 0 : thisFurnace.HeatingCoilIndex,
10440 : thisFurnace.fanOp,
10441 : compressorOp,
10442 : PartLoadFrac,
10443 : SpeedNum,
10444 : SpeedRatio,
10445 : QZnReq,
10446 : QLatReq,
10447 : OnOffAirFlowRatio);
10448 : }
10449 :
10450 0 : SavePartloadRatio = PartLoadFrac;
10451 0 : SaveSpeedRatio = SpeedRatio;
10452 0 : state.dataFurnaces->SaveCompressorPLR = state.dataVariableSpeedCoils->VarSpeedCoil(thisFurnace.HeatingCoilIndex).PartLoadRatio;
10453 : } else {
10454 0 : if (thisFurnace.bIsIHP) {
10455 0 : IntegratedHeatPump::SimIHP(state,
10456 : BlankString,
10457 0 : thisFurnace.CoolingCoilIndex,
10458 : thisFurnace.fanOp,
10459 : compressorOp,
10460 : PartLoadFrac,
10461 : SpeedNum,
10462 : SpeedRatio,
10463 : QZnReq,
10464 : QLatReq,
10465 : false,
10466 : false,
10467 : OnOffAirFlowRatio);
10468 : } else {
10469 0 : VariableSpeedCoils::SimVariableSpeedCoils(state,
10470 : BlankString,
10471 0 : thisFurnace.HeatingCoilIndex,
10472 : thisFurnace.fanOp,
10473 : compressorOp,
10474 : 0.0,
10475 : 1,
10476 : 0.0,
10477 : 0.0,
10478 : 0.0,
10479 : OnOffAirFlowRatio);
10480 : }
10481 : }
10482 0 : } else if (thisFurnace.CoolingCoilUpstream && (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool)) {
10483 : // simulate thisFurnace heating coil
10484 0 : bool SuppHeatingCoilFlag = false; // if true simulates supplemental heating coil
10485 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, HeatCoilLoad, thisFurnace.fanOp, QCoilActual);
10486 : }
10487 :
10488 0 : state.dataFans->fans(thisFurnace.FanIndex)->simulate(state, FirstHVACIteration, state.dataFurnaces->FanSpeedRatio);
10489 : // Simulate supplemental heating coil for draw through fan
10490 0 : if (thisFurnace.SuppHeatCoilIndex > 0) {
10491 0 : bool SuppHeatingCoilFlag = true; // if true simulates supplemental heating coil
10492 0 : CalcNonDXHeatingCoils(state, FurnaceNum, SuppHeatingCoilFlag, FirstHVACIteration, SupHeaterLoad, thisFurnace.fanOp, QCoilActual);
10493 : }
10494 : }
10495 :
10496 : // If the fan runs continually do not allow coils to set OnOffFanPartLoadRatio.
10497 17687782 : if (thisFurnace.fanOp == HVAC::FanOp::Continuous) state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
10498 :
10499 17687782 : auto &outNode = state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum);
10500 17687782 : auto &zoneNode = state.dataLoopNodes->Node(thisFurnace.NodeNumOfControlledZone);
10501 17687782 : Real64 zoneEnthalpy = Psychrometrics::PsyHFnTdbW(zoneNode.Temp, zoneNode.HumRat);
10502 17687782 : Real64 outletEnthalpy = Psychrometrics::PsyHFnTdbW(outNode.Temp, outNode.HumRat);
10503 17687782 : Real64 totalLoadMet = AirMassFlow * (outletEnthalpy - zoneEnthalpy);
10504 17687782 : SensibleLoadMet =
10505 17687782 : AirMassFlow * Psychrometrics::PsyDeltaHSenFnTdb2W2Tdb1W1(outNode.Temp, outNode.HumRat, zoneNode.Temp, zoneNode.HumRat); // sensible {W};
10506 17687782 : LatentLoadMet = totalLoadMet - SensibleLoadMet;
10507 17687782 : thisFurnace.LatentLoadMet = LatentLoadMet;
10508 17687782 : }
10509 :
10510 : //******************************************************************************
10511 :
10512 1964741 : Real64 VSHPCyclingResidual(EnergyPlusData &state,
10513 : Real64 const PartLoadFrac, // compressor cycling ratio (1.0 is continuous, 0.0 is off)
10514 : int FurnaceNum,
10515 : // int ZoneNum,
10516 : bool FirstHVACIteration,
10517 : // int fanOp,
10518 : Real64 LoadToBeMet,
10519 : Real64 OnOffAirFlowRatio,
10520 : Real64 SupHeaterLoad,
10521 : HVAC::CompressorOp compressorOp,
10522 : Real64 par9_SensLatFlag)
10523 : {
10524 : // FUNCTION INFORMATION:
10525 : // AUTHOR Bo Shen, based on HVACMultiSpeedHeatPump:MSHPCyclingResidual
10526 : // DATE WRITTEN March, 2012
10527 :
10528 : // PURPOSE OF THIS FUNCTION:
10529 : // Calculates residual function ((ActualOutput - QZnReq)/QZnReq)
10530 : // MSHP output depends on the part load ratio which is being varied to zero the residual.
10531 :
10532 : // METHODOLOGY EMPLOYED:
10533 : // Calls CalcMSHeatPump to get ActualOutput at the given part load ratio
10534 : // and calculates the residual as defined above
10535 :
10536 : // int FurnaceNum = int(Par[0]);
10537 : // int ZoneNum = int(Par[1]);
10538 : // bool FirstHVACIteration = (Par[2] == 1.0);
10539 : // int fanOp = int(Par[3]);
10540 : // Real64 LoadToBeMet = Par[4];
10541 : // Real64 OnOffAirFlowRatio = Par[5];
10542 : // Real64 SupHeaterLoad = Par[6];
10543 : // CompressorOperation CompressorOp = static_cast<CompressorOperation>(Par[8]);
10544 : // Real64 par9_SensLatFlag = Par[9];
10545 :
10546 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
10547 : Real64 ZoneSensLoadMet; // delivered sensible capacity of MSHP
10548 : Real64 ZoneLatLoadMet; // delivered latent capacity of MSHP
10549 :
10550 1964741 : Real64 QZnReq = 0.0;
10551 1964741 : Real64 QZnLat = 0.0;
10552 1964741 : if (par9_SensLatFlag == 1.0) {
10553 1695334 : QZnReq = LoadToBeMet;
10554 : } else {
10555 269407 : QZnLat = LoadToBeMet;
10556 : }
10557 :
10558 1964741 : CalcVarSpeedHeatPump(state,
10559 : FurnaceNum,
10560 : FirstHVACIteration,
10561 : compressorOp,
10562 : 1,
10563 : 0.0,
10564 : PartLoadFrac,
10565 : ZoneSensLoadMet,
10566 : ZoneLatLoadMet,
10567 : QZnReq,
10568 : QZnLat,
10569 : OnOffAirFlowRatio,
10570 : SupHeaterLoad);
10571 :
10572 1964741 : Real64 ResScale = std::abs(LoadToBeMet);
10573 1964741 : if (ResScale < 100.0) {
10574 7954 : ResScale = 100.0;
10575 : } else {
10576 1956787 : ResScale = LoadToBeMet;
10577 : }
10578 :
10579 : // Calculate residual based on output calculation flag
10580 1964741 : if (par9_SensLatFlag == 1.0) {
10581 1695334 : return (ZoneSensLoadMet - LoadToBeMet) / ResScale;
10582 : } else {
10583 269407 : return (ZoneLatLoadMet - LoadToBeMet) / ResScale;
10584 : }
10585 : }
10586 :
10587 : //******************************************************************************
10588 :
10589 3534349 : Real64 VSHPSpeedResidual(EnergyPlusData &state,
10590 : Real64 const SpeedRatio, // compressor cycling ratio (1.0 is continuous, 0.0 is off)
10591 : int FurnaceNum,
10592 : // int ZoneNum,
10593 : bool FirstHVACIteration,
10594 : // int fanOp
10595 : Real64 LoadToBeMet,
10596 : Real64 OnOffAirFlowRatio,
10597 : Real64 SupHeaterLoad,
10598 : int SpeedNum,
10599 : HVAC::CompressorOp compressorOp,
10600 : Real64 par9_SensLatFlag)
10601 : {
10602 : // FUNCTION INFORMATION:
10603 : // AUTHOR Bo Shen, , based on HVACMultiSpeedHeatPump:MSHPVarSpeedgResidual
10604 : // DATE WRITTEN March, 2012
10605 :
10606 : // PURPOSE OF THIS FUNCTION:
10607 : // Calculates residual function ((ActualOutput - QZnReq)/QZnReq)
10608 : // MSHP output depends on the part load ratio which is being varied to zero the residual.
10609 :
10610 : // METHODOLOGY EMPLOYED:
10611 : // Calls CalcMSHeatPump to get ActualOutput at the given speed ratio (partload ratio for high speed)
10612 : // and calculates the residual as defined above
10613 :
10614 3534349 : Real64 QZnReq = 0.0;
10615 3534349 : Real64 QZnLat = 0.0;
10616 3534349 : if (par9_SensLatFlag == 1.0) {
10617 3428065 : QZnReq = LoadToBeMet;
10618 : } else {
10619 106284 : QZnLat = LoadToBeMet;
10620 : }
10621 :
10622 : Real64 ZoneSensLoadMet; // delivered sensible capacity of MSHP
10623 : Real64 ZoneLatLoadMet; // delivered latent capacity of MSHP
10624 3534349 : CalcVarSpeedHeatPump(state,
10625 : FurnaceNum,
10626 : FirstHVACIteration,
10627 : compressorOp,
10628 : SpeedNum,
10629 : SpeedRatio,
10630 : 1.0,
10631 : ZoneSensLoadMet,
10632 : ZoneLatLoadMet,
10633 : QZnReq,
10634 : QZnLat,
10635 : OnOffAirFlowRatio,
10636 : SupHeaterLoad);
10637 :
10638 3534349 : Real64 ResScale = std::abs(LoadToBeMet);
10639 3534349 : if (ResScale < 100.0) {
10640 0 : ResScale = 100.0;
10641 : } else {
10642 3534349 : ResScale = LoadToBeMet;
10643 : }
10644 :
10645 : // Calculate residual based on output calculation flag
10646 3534349 : if (par9_SensLatFlag == 1.0) {
10647 3428065 : return (ZoneSensLoadMet - LoadToBeMet) / ResScale;
10648 : } else {
10649 106284 : return (ZoneLatLoadMet - LoadToBeMet) / ResScale;
10650 : }
10651 : }
10652 :
10653 17687782 : void SetVSHPAirFlow(EnergyPlusData &state,
10654 : int const FurnaceNum, // Unit index
10655 : Real64 const PartLoadRatio, // unit part load ratio
10656 : Real64 &OnOffAirFlowRatio, // ratio of compressor ON airflow to average airflow over timestep
10657 : ObjexxFCL::Optional_int_const SpeedNum, // Speed number
10658 : ObjexxFCL::Optional<Real64 const> SpeedRatio // Speed ratio
10659 : )
10660 : {
10661 :
10662 : // SUBROUTINE INFORMATION:
10663 : // AUTHOR Bo Shen, based on HVACMultiSpeedHeatPump:SetAverageAirFlow
10664 : // DATE WRITTEN March, 2012
10665 :
10666 : // PURPOSE OF THIS SUBROUTINE:
10667 : // Set the average air mass flow rates using the part load fraction of the heat pump for this time step
10668 : // Set OnOffAirFlowRatio to be used by DX coils
10669 :
10670 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
10671 : Real64 AverageUnitMassFlow; // average supply air mass flow rate over time step
10672 :
10673 17687782 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
10674 :
10675 17687782 : state.dataHVACGlobal->MSHPMassFlowRateLow = 0.0; // Mass flow rate at low speed
10676 17687782 : state.dataHVACGlobal->MSHPMassFlowRateHigh = 0.0; // Mass flow rate at high speed
10677 :
10678 17687782 : if (thisFurnace.fanOp == HVAC::FanOp::Continuous) {
10679 17499846 : state.dataFurnaces->CompOffMassFlow = thisFurnace.IdleMassFlowRate;
10680 17499846 : state.dataFurnaces->CompOffFlowRatio = thisFurnace.IdleSpeedRatio;
10681 : } else {
10682 187936 : state.dataFurnaces->CompOffMassFlow = 0.0;
10683 187936 : state.dataFurnaces->CompOffFlowRatio = 0.0;
10684 : }
10685 :
10686 17687782 : if (state.dataFurnaces->CoolingLoad && (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool)) {
10687 15238427 : if (thisFurnace.NumOfSpeedCooling > 0) {
10688 15238427 : state.dataFurnaces->CompOnMassFlow = thisFurnace.CoolMassFlowRate(thisFurnace.NumOfSpeedCooling);
10689 15238427 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.MSCoolingSpeedRatio(thisFurnace.NumOfSpeedCooling);
10690 15238427 : state.dataHVACGlobal->MSHPMassFlowRateLow = thisFurnace.CoolMassFlowRate(thisFurnace.NumOfSpeedCooling);
10691 15238427 : state.dataHVACGlobal->MSHPMassFlowRateHigh = thisFurnace.CoolMassFlowRate(thisFurnace.NumOfSpeedCooling);
10692 : } else {
10693 0 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxCoolAirMassFlow;
10694 0 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.CoolingSpeedRatio;
10695 : }
10696 15238427 : AverageUnitMassFlow = (PartLoadRatio * state.dataFurnaces->CompOnMassFlow) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffMassFlow);
10697 15238427 : if (state.dataFurnaces->CompOffFlowRatio > 0.0) {
10698 15238427 : state.dataFurnaces->FanSpeedRatio =
10699 15238427 : (PartLoadRatio * state.dataFurnaces->CompOnFlowRatio) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffFlowRatio);
10700 : } else {
10701 0 : state.dataFurnaces->FanSpeedRatio = state.dataFurnaces->CompOnFlowRatio;
10702 : }
10703 2449355 : } else if (state.dataFurnaces->HeatingLoad && (thisFurnace.type == HVAC::UnitarySysType::Unitary_HeatCool)) {
10704 111753 : if (thisFurnace.NumOfSpeedHeating > 0) {
10705 0 : state.dataFurnaces->CompOnMassFlow = thisFurnace.HeatMassFlowRate(thisFurnace.NumOfSpeedHeating);
10706 0 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.MSHeatingSpeedRatio(thisFurnace.NumOfSpeedHeating);
10707 0 : state.dataHVACGlobal->MSHPMassFlowRateLow = thisFurnace.HeatMassFlowRate(thisFurnace.NumOfSpeedHeating);
10708 0 : state.dataHVACGlobal->MSHPMassFlowRateHigh = thisFurnace.HeatMassFlowRate(thisFurnace.NumOfSpeedHeating);
10709 : } else {
10710 111753 : state.dataFurnaces->CompOnMassFlow = thisFurnace.MaxHeatAirMassFlow;
10711 111753 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.HeatingSpeedRatio;
10712 : }
10713 111753 : AverageUnitMassFlow = (PartLoadRatio * state.dataFurnaces->CompOnMassFlow) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffMassFlow);
10714 111753 : if (state.dataFurnaces->CompOffFlowRatio > 0.0) {
10715 111753 : state.dataFurnaces->FanSpeedRatio =
10716 111753 : (PartLoadRatio * state.dataFurnaces->CompOnFlowRatio) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffFlowRatio);
10717 : } else {
10718 0 : state.dataFurnaces->FanSpeedRatio = state.dataFurnaces->CompOnFlowRatio;
10719 : }
10720 2337602 : } else if (thisFurnace.bIsIHP) {
10721 62326 : if (!state.dataZoneEnergyDemand->CurDeadBandOrSetback(thisFurnace.ControlZoneNum) && present(SpeedNum)) {
10722 : // if(present(SpeedNum)) {
10723 118274 : state.dataFurnaces->CompOnMassFlow =
10724 59137 : IntegratedHeatPump::GetAirMassFlowRateIHP(state, thisFurnace.CoolingCoilIndex, SpeedNum, SpeedRatio, false);
10725 118274 : state.dataFurnaces->CompOnFlowRatio =
10726 59137 : state.dataFurnaces->CompOnMassFlow /
10727 59137 : IntegratedHeatPump::GetAirMassFlowRateIHP(
10728 : state, thisFurnace.CoolingCoilIndex, IntegratedHeatPump::GetMaxSpeedNumIHP(state, thisFurnace.CoolingCoilIndex), 1.0, false);
10729 118274 : state.dataHVACGlobal->MSHPMassFlowRateLow =
10730 59137 : IntegratedHeatPump::GetAirMassFlowRateIHP(state, thisFurnace.CoolingCoilIndex, SpeedNum, 0.0, false);
10731 59137 : state.dataHVACGlobal->MSHPMassFlowRateHigh =
10732 59137 : IntegratedHeatPump::GetAirMassFlowRateIHP(state, thisFurnace.CoolingCoilIndex, SpeedNum, 1.0, false);
10733 : }
10734 :
10735 : // Set up fan flow rate during compressor off time
10736 62326 : if (thisFurnace.fanOp == HVAC::FanOp::Continuous && present(SpeedNum)) {
10737 0 : if (thisFurnace.AirFlowControl == AirFlowControlConstFan::UseCompressorOnFlow && state.dataFurnaces->CompOnMassFlow > 0.0) {
10738 0 : state.dataFurnaces->CompOffMassFlow =
10739 0 : IntegratedHeatPump::GetAirMassFlowRateIHP(state, thisFurnace.CoolingCoilIndex, SpeedNum, 1.0, false);
10740 0 : state.dataFurnaces->CompOffFlowRatio =
10741 0 : state.dataFurnaces->CompOffMassFlow /
10742 0 : IntegratedHeatPump::GetAirMassFlowRateIHP(state,
10743 : thisFurnace.CoolingCoilIndex,
10744 : IntegratedHeatPump::GetMaxSpeedNumIHP(state, thisFurnace.CoolingCoilIndex),
10745 : 1.0,
10746 : false);
10747 : }
10748 : }
10749 :
10750 62326 : if (present(SpeedNum)) {
10751 62326 : if (SpeedNum > 1) {
10752 39843 : AverageUnitMassFlow = state.dataFurnaces->CompOnMassFlow;
10753 39843 : state.dataFurnaces->FanSpeedRatio = state.dataFurnaces->CompOnFlowRatio;
10754 : } else {
10755 22483 : AverageUnitMassFlow =
10756 22483 : (PartLoadRatio * state.dataFurnaces->CompOnMassFlow) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffMassFlow);
10757 22483 : if (state.dataFurnaces->CompOffFlowRatio > 0.0) {
10758 0 : state.dataFurnaces->FanSpeedRatio =
10759 0 : (PartLoadRatio * state.dataFurnaces->CompOnFlowRatio) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffFlowRatio);
10760 : } else {
10761 22483 : state.dataFurnaces->FanSpeedRatio = state.dataFurnaces->CompOnFlowRatio;
10762 : }
10763 : }
10764 : } else {
10765 0 : AverageUnitMassFlow =
10766 0 : (PartLoadRatio * state.dataFurnaces->CompOnMassFlow) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffMassFlow);
10767 0 : if (state.dataFurnaces->CompOffFlowRatio > 0.0) {
10768 0 : state.dataFurnaces->FanSpeedRatio =
10769 0 : (PartLoadRatio * state.dataFurnaces->CompOnFlowRatio) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffFlowRatio);
10770 : } else {
10771 0 : state.dataFurnaces->FanSpeedRatio = state.dataFurnaces->CompOnFlowRatio;
10772 : }
10773 : }
10774 :
10775 62326 : if (IntegratedHeatPump::IHPOperationMode::SCWHMatchWH ==
10776 62326 : state.dataIntegratedHP->IntegratedHeatPumps(thisFurnace.CoolingCoilIndex).CurMode) {
10777 672 : state.dataFurnaces->CompOnMassFlow =
10778 336 : IntegratedHeatPump::GetAirMassFlowRateIHP(state, thisFurnace.CoolingCoilIndex, SpeedNum, SpeedRatio, false);
10779 336 : AverageUnitMassFlow = state.dataFurnaces->CompOnMassFlow;
10780 : }
10781 : } else {
10782 2275276 : if (!state.dataZoneEnergyDemand->CurDeadBandOrSetback(thisFurnace.ControlZoneNum) && present(SpeedNum)) {
10783 1503373 : if (thisFurnace.HeatCoolMode == Furnaces::ModeOfOperation::HeatingMode) {
10784 728218 : if (SpeedNum == 1) {
10785 258337 : state.dataFurnaces->CompOnMassFlow = thisFurnace.HeatMassFlowRate(SpeedNum);
10786 258337 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.MSHeatingSpeedRatio(SpeedNum);
10787 258337 : state.dataHVACGlobal->MSHPMassFlowRateLow = thisFurnace.HeatMassFlowRate(1);
10788 258337 : state.dataHVACGlobal->MSHPMassFlowRateHigh = thisFurnace.HeatMassFlowRate(1);
10789 469881 : } else if (SpeedNum > 1) {
10790 939762 : state.dataFurnaces->CompOnMassFlow =
10791 469881 : SpeedRatio * thisFurnace.HeatMassFlowRate(SpeedNum) + (1.0 - SpeedRatio) * thisFurnace.HeatMassFlowRate(SpeedNum - 1);
10792 469881 : state.dataFurnaces->CompOnFlowRatio = SpeedRatio * thisFurnace.MSHeatingSpeedRatio(SpeedNum) +
10793 469881 : (1.0 - SpeedRatio) * thisFurnace.MSHeatingSpeedRatio(SpeedNum - 1);
10794 469881 : state.dataHVACGlobal->MSHPMassFlowRateLow = thisFurnace.HeatMassFlowRate(SpeedNum - 1);
10795 469881 : state.dataHVACGlobal->MSHPMassFlowRateHigh = thisFurnace.HeatMassFlowRate(SpeedNum);
10796 : }
10797 775155 : } else if (thisFurnace.HeatCoolMode == Furnaces::ModeOfOperation::CoolingMode) {
10798 629651 : if (SpeedNum == 1) {
10799 445955 : state.dataFurnaces->CompOnMassFlow = thisFurnace.CoolMassFlowRate(SpeedNum);
10800 445955 : state.dataFurnaces->CompOnFlowRatio = thisFurnace.MSCoolingSpeedRatio(SpeedNum);
10801 445955 : state.dataHVACGlobal->MSHPMassFlowRateLow = thisFurnace.CoolMassFlowRate(1);
10802 445955 : state.dataHVACGlobal->MSHPMassFlowRateHigh = thisFurnace.CoolMassFlowRate(1);
10803 183696 : } else if (SpeedNum > 1) {
10804 367392 : state.dataFurnaces->CompOnMassFlow =
10805 183696 : SpeedRatio * thisFurnace.CoolMassFlowRate(SpeedNum) + (1.0 - SpeedRatio) * thisFurnace.CoolMassFlowRate(SpeedNum - 1);
10806 183696 : state.dataFurnaces->CompOnFlowRatio = SpeedRatio * thisFurnace.MSCoolingSpeedRatio(SpeedNum) +
10807 183696 : (1.0 - SpeedRatio) * thisFurnace.MSCoolingSpeedRatio(SpeedNum - 1);
10808 183696 : state.dataHVACGlobal->MSHPMassFlowRateLow = thisFurnace.CoolMassFlowRate(SpeedNum - 1);
10809 183696 : state.dataHVACGlobal->MSHPMassFlowRateHigh = thisFurnace.CoolMassFlowRate(SpeedNum);
10810 : }
10811 : }
10812 : }
10813 :
10814 : // Set up fan flow rate during compressor off time
10815 2275276 : if (thisFurnace.fanOp == HVAC::FanOp::Continuous && present(SpeedNum)) {
10816 2149666 : if (thisFurnace.AirFlowControl == AirFlowControlConstFan::UseCompressorOnFlow && state.dataFurnaces->CompOnMassFlow > 0.0) {
10817 2148022 : if (SpeedNum == 1) { // LOWEST SPEED USE IDLE FLOW
10818 1318263 : state.dataFurnaces->CompOffMassFlow = thisFurnace.IdleMassFlowRate;
10819 1318263 : state.dataFurnaces->CompOffFlowRatio = thisFurnace.IdleSpeedRatio;
10820 829759 : } else if (thisFurnace.LastMode == Furnaces::ModeOfOperation::HeatingMode) {
10821 441861 : state.dataFurnaces->CompOffMassFlow = thisFurnace.HeatMassFlowRate(SpeedNum);
10822 441861 : state.dataFurnaces->CompOffFlowRatio = thisFurnace.MSHeatingSpeedRatio(SpeedNum);
10823 : } else {
10824 387898 : state.dataFurnaces->CompOffMassFlow = thisFurnace.CoolMassFlowRate(SpeedNum);
10825 387898 : state.dataFurnaces->CompOffFlowRatio = thisFurnace.MSCoolingSpeedRatio(SpeedNum);
10826 : }
10827 : }
10828 : }
10829 :
10830 2275276 : if (present(SpeedNum)) {
10831 2275276 : if (SpeedNum > 1) {
10832 910227 : AverageUnitMassFlow = state.dataFurnaces->CompOnMassFlow;
10833 910227 : state.dataFurnaces->FanSpeedRatio = state.dataFurnaces->CompOnFlowRatio;
10834 : } else {
10835 1365049 : AverageUnitMassFlow =
10836 1365049 : (PartLoadRatio * state.dataFurnaces->CompOnMassFlow) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffMassFlow);
10837 1365049 : if (state.dataFurnaces->CompOffFlowRatio > 0.0) {
10838 1319907 : state.dataFurnaces->FanSpeedRatio =
10839 1319907 : (PartLoadRatio * state.dataFurnaces->CompOnFlowRatio) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffFlowRatio);
10840 : } else {
10841 45142 : state.dataFurnaces->FanSpeedRatio = state.dataFurnaces->CompOnFlowRatio;
10842 : }
10843 : }
10844 : } else {
10845 0 : AverageUnitMassFlow =
10846 0 : (PartLoadRatio * state.dataFurnaces->CompOnMassFlow) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffMassFlow);
10847 0 : if (state.dataFurnaces->CompOffFlowRatio > 0.0) {
10848 0 : state.dataFurnaces->FanSpeedRatio =
10849 0 : (PartLoadRatio * state.dataFurnaces->CompOnFlowRatio) + ((1 - PartLoadRatio) * state.dataFurnaces->CompOffFlowRatio);
10850 : } else {
10851 0 : state.dataFurnaces->FanSpeedRatio = state.dataFurnaces->CompOnFlowRatio;
10852 : }
10853 : }
10854 : }
10855 :
10856 35363984 : if ((ScheduleManager::GetCurrentScheduleValue(state, thisFurnace.SchedPtr) == 0.0) || state.dataHVACGlobal->TurnFansOff ||
10857 17676202 : (ScheduleManager::GetCurrentScheduleValue(state, thisFurnace.FanAvailSchedPtr) == 0.0 && !state.dataHVACGlobal->TurnFansOn)) {
10858 11580 : state.dataLoopNodes->Node(thisFurnace.FurnaceInletNodeNum).MassFlowRate = 0.0;
10859 11580 : OnOffAirFlowRatio = 0.0;
10860 : } else {
10861 17676202 : state.dataLoopNodes->Node(thisFurnace.FurnaceInletNodeNum).MassFlowRate = AverageUnitMassFlow;
10862 17676202 : state.dataLoopNodes->Node(thisFurnace.FurnaceInletNodeNum).MassFlowRateMaxAvail = AverageUnitMassFlow;
10863 17676202 : if (AverageUnitMassFlow > 0.0) {
10864 17637342 : OnOffAirFlowRatio = state.dataFurnaces->CompOnMassFlow / AverageUnitMassFlow;
10865 : } else {
10866 38860 : OnOffAirFlowRatio = 0.0;
10867 : }
10868 : }
10869 :
10870 17687782 : state.dataLoopNodes->Node(thisFurnace.FurnaceOutletNodeNum).MassFlowRate =
10871 17687782 : state.dataLoopNodes->Node(thisFurnace.FurnaceInletNodeNum).MassFlowRate;
10872 17687782 : }
10873 :
10874 359 : void SetMinOATCompressor(EnergyPlusData &state,
10875 : int const FurnaceNum, // index to furnace
10876 : std::string const &cCurrentModuleObject, // type of furnace
10877 : bool &ErrorsFound // GetInput logical that errors were found
10878 : )
10879 : {
10880 359 : bool errFlag = false;
10881 359 : auto &thisFurnace = state.dataFurnaces->Furnace(FurnaceNum);
10882 :
10883 : // Set minimum OAT for heat pump compressor operation in heating mode
10884 359 : if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingSingleSpeed) {
10885 206 : thisFurnace.MinOATCompressorCooling = DXCoils::GetMinOATCompressor(state, thisFurnace.CoolingCoilIndex, errFlag);
10886 153 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::CoilDX_CoolingHXAssisted) {
10887 3 : std::string ChildCoolingCoilType = state.dataHVACAssistedCC->HXAssistedCoil(thisFurnace.CoolingCoilIndex).CoolingCoilType;
10888 3 : std::string ChildCoolingCoilName = state.dataHVACAssistedCC->HXAssistedCoil(thisFurnace.CoolingCoilIndex).CoolingCoilName;
10889 :
10890 3 : if (Util::SameString(ChildCoolingCoilType, "COIL:COOLING:DX")) {
10891 1 : int childCCIndex_DX = CoilCoolingDX::factory(state, ChildCoolingCoilName);
10892 1 : if (childCCIndex_DX < 0) {
10893 0 : ShowContinueError(state, format("Occurs in {} = {}", cCurrentModuleObject, thisFurnace.Name));
10894 0 : errFlag = true;
10895 0 : ErrorsFound = true;
10896 : }
10897 1 : auto const &newCoil = state.dataCoilCooingDX->coilCoolingDXs[childCCIndex_DX];
10898 1 : thisFurnace.MinOATCompressorCooling = newCoil.performance.minOutdoorDrybulb;
10899 2 : } else if (Util::SameString(ChildCoolingCoilType, "Coil:Cooling:DX:VariableSpeed")) {
10900 0 : int childCCIndex_VS = state.dataHVACAssistedCC->HXAssistedCoil(thisFurnace.CoolingCoilIndex).CoolingCoilIndex;
10901 0 : thisFurnace.MinOATCompressorCooling = VariableSpeedCoils::GetVSCoilMinOATCompressor(state, childCCIndex_VS, errFlag);
10902 : } else { // Single speed
10903 2 : int childCCIndex_SP = state.dataHVACAssistedCC->HXAssistedCoil(thisFurnace.CoolingCoilIndex).CoolingCoilIndex;
10904 2 : thisFurnace.MinOATCompressorCooling = DXCoils::GetMinOATCompressor(state, childCCIndex_SP, errFlag);
10905 : }
10906 153 : } else if (thisFurnace.CoolingCoilType_Num == HVAC::Coil_CoolingAirToAirVariableSpeed) {
10907 7 : thisFurnace.MinOATCompressorCooling = VariableSpeedCoils::GetVSCoilMinOATCompressor(state, thisFurnace.CoolingCoilIndex, errFlag);
10908 : } else {
10909 143 : thisFurnace.MinOATCompressorCooling = -1000.0;
10910 : }
10911 359 : if (errFlag) {
10912 0 : ShowContinueError(state, format("...occurs in {} = {}", cCurrentModuleObject, thisFurnace.Name));
10913 0 : ErrorsFound = true;
10914 : }
10915 :
10916 : // Set minimum OAT for heat pump compressor operation in heating mode
10917 359 : errFlag = false;
10918 359 : if (thisFurnace.HeatingCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed) {
10919 3 : thisFurnace.MinOATCompressorHeating = VariableSpeedCoils::GetVSCoilMinOATCompressor(state, thisFurnace.HeatingCoilIndex, errFlag);
10920 356 : } else if (thisFurnace.HeatingCoilType_Num == HVAC::CoilDX_HeatingEmpirical) {
10921 32 : thisFurnace.MinOATCompressorHeating = DXCoils::GetMinOATCompressor(state, thisFurnace.HeatingCoilIndex, errFlag);
10922 : } else {
10923 324 : thisFurnace.MinOATCompressorHeating = -1000.0;
10924 : }
10925 359 : if (errFlag) {
10926 0 : ShowContinueError(state, format("...occurs in {} = {}", cCurrentModuleObject, thisFurnace.Name));
10927 0 : ErrorsFound = true;
10928 : }
10929 359 : }
10930 :
10931 : } // namespace Furnaces
10932 :
10933 : } // namespace EnergyPlus
|