Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // C++ Headers
49 : #include <cmath>
50 :
51 : // ObjexxFCL Headers
52 : #include <ObjexxFCL/Array.functions.hh>
53 : #include <ObjexxFCL/Fmath.hh>
54 :
55 : // EnergyPlus Headers
56 : #include <AirflowNetwork/Solver.hpp>
57 : #include <EnergyPlus/Autosizing/Base.hh>
58 : #include <EnergyPlus/BranchNodeConnections.hh>
59 : #include <EnergyPlus/DXCoils.hh>
60 : #include <EnergyPlus/Data/EnergyPlusData.hh>
61 : #include <EnergyPlus/DataAirSystems.hh>
62 : #include <EnergyPlus/DataEnvironment.hh>
63 : #include <EnergyPlus/DataHVACGlobals.hh>
64 : #include <EnergyPlus/DataLoopNode.hh>
65 : #include <EnergyPlus/DataSizing.hh>
66 : #include <EnergyPlus/DataZoneControls.hh>
67 : #include <EnergyPlus/DataZoneEnergyDemands.hh>
68 : #include <EnergyPlus/DataZoneEquipment.hh>
69 : #include <EnergyPlus/EMSManager.hh>
70 : #include <EnergyPlus/Fans.hh>
71 : #include <EnergyPlus/FluidProperties.hh>
72 : #include <EnergyPlus/General.hh>
73 : #include <EnergyPlus/GeneralRoutines.hh>
74 : #include <EnergyPlus/HVACMultiSpeedHeatPump.hh>
75 : #include <EnergyPlus/HeatingCoils.hh>
76 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
77 : #include <EnergyPlus/NodeInputManager.hh>
78 : #include <EnergyPlus/OutputProcessor.hh>
79 : #include <EnergyPlus/OutputReportPredefined.hh>
80 : #include <EnergyPlus/Plant/DataPlant.hh>
81 : #include <EnergyPlus/PlantUtilities.hh>
82 : #include <EnergyPlus/Psychrometrics.hh>
83 : #include <EnergyPlus/ScheduleManager.hh>
84 : #include <EnergyPlus/SteamCoils.hh>
85 : #include <EnergyPlus/UtilityRoutines.hh>
86 : #include <EnergyPlus/WaterCoils.hh>
87 : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
88 :
89 : namespace EnergyPlus {
90 :
91 : namespace HVACMultiSpeedHeatPump {
92 :
93 : // Module containing the Multi Speed Heat Pump simulation routines
94 :
95 : // MODULE INFORMATION:
96 : // AUTHOR Lixing Gu, Florida Solar Energy Center
97 : // DATE WRITTEN June 2007
98 : // MODIFIED Bereket Nigusse, FSEC, June 2010 - deprecated supply air flow fraction through controlled
99 : // zone from the furnace object input field. Now, the flow fraction is calculated internally
100 : // Brent Griffith, NREL, Dec 2010 -- upgrade to new plant for heat recovery, general fluid props.
101 : // Bereket Nigusse, FSEC, Jan. 2012 -- added hot water and steam heating coil
102 : // PURPOSE OF THIS MODULE:
103 : // To encapsulate the data and algorithms required to simulate Multi Speed Heat Pump in
104 : // EnergyPlus.
105 :
106 : // Module currently models air-cooled or evap-cooled direct expansion systems
107 : // (split or packaged) with multiple speeds. Air-side performance is modeled to determine
108 : // coil discharge air conditions. The module also determines the DX unit's energy
109 : // usage. Neither the air-side performance nor the energy usage includes the effect
110 : // of supply air fan heat/energy usage. The supply air fan is modeled by other modules.
111 :
112 : // Curve Types
113 : enum class CurveType
114 : {
115 : Invalid = -1,
116 : Linear, // Linear curve type
117 : BiLinear, // Bi-linear curve type
118 : Quadratic, // Quadratic curve type
119 : BiQuadratic, // Bi-quadratic curve type
120 : Cubic, // Cubic curve type
121 : Num
122 : };
123 :
124 0 : void SimMSHeatPump(EnergyPlusData &state,
125 : std::string_view CompName, // Name of the unitary engine driven heat pump system
126 : bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system time step
127 : int const AirLoopNum, // air loop index
128 : int &CompIndex // Index to changeover-bypass VAV system
129 : )
130 : {
131 :
132 : // SUBROUTINE INFORMATION:
133 : // AUTHOR Lixing Gu, Florida Solar Energy Center
134 : // DATE WRITTEN June. 2007
135 :
136 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
137 : int MSHeatPumpNum; // index of fan coil unit being simulated
138 : Real64 OnOffAirFlowRatio; // Ratio of compressor ON airflow to average airflow over timestep
139 : Real64 QZnLoad; // Zone load required by all zones served by this air loop system
140 : Real64 QSensUnitOut; // MSHP sensible capacity output [W]
141 :
142 : // First time SimMSHeatPump is called, get the input
143 0 : if (state.dataHVACMultiSpdHP->GetInputFlag) {
144 0 : GetMSHeatPumpInput(state);
145 0 : state.dataHVACMultiSpdHP->GetInputFlag = false; // Set GetInputFlag false so you don't get coil inputs again
146 : }
147 :
148 0 : if (CompIndex == 0) {
149 0 : MSHeatPumpNum = Util::FindItemInList(CompName, state.dataHVACMultiSpdHP->MSHeatPump);
150 0 : if (MSHeatPumpNum == 0) {
151 0 : ShowFatalError(state, format("MultiSpeed Heat Pump is not found={}", CompName));
152 : }
153 0 : CompIndex = MSHeatPumpNum;
154 : } else {
155 0 : MSHeatPumpNum = CompIndex;
156 0 : if (MSHeatPumpNum > state.dataHVACMultiSpdHP->NumMSHeatPumps || MSHeatPumpNum < 1) {
157 0 : ShowFatalError(state,
158 0 : format("SimMSHeatPump: Invalid CompIndex passed={}, Number of MultiSpeed Heat Pumps={}, Heat Pump name={}",
159 : MSHeatPumpNum,
160 0 : state.dataHVACMultiSpdHP->NumMSHeatPumps,
161 : CompName));
162 : }
163 0 : if (state.dataHVACMultiSpdHP->CheckEquipName(MSHeatPumpNum)) {
164 0 : if (CompName != state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).Name) {
165 0 : ShowFatalError(state,
166 0 : format("SimMSHeatPump: Invalid CompIndex passed={}, Heat Pump name={}{}",
167 : MSHeatPumpNum,
168 : CompName,
169 0 : state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).Name));
170 : }
171 0 : state.dataHVACMultiSpdHP->CheckEquipName(MSHeatPumpNum) = false;
172 : }
173 : }
174 :
175 0 : OnOffAirFlowRatio = 0.0;
176 :
177 : // Initialize the engine driven heat pump
178 0 : InitMSHeatPump(state, MSHeatPumpNum, FirstHVACIteration, AirLoopNum, QZnLoad, OnOffAirFlowRatio);
179 :
180 0 : SimMSHP(state, MSHeatPumpNum, FirstHVACIteration, AirLoopNum, QSensUnitOut, QZnLoad, OnOffAirFlowRatio);
181 :
182 : // Update the unit outlet nodes
183 0 : UpdateMSHeatPump(state, MSHeatPumpNum);
184 :
185 : // Report the result of the simulation
186 0 : ReportMSHeatPump(state, MSHeatPumpNum);
187 0 : }
188 :
189 : //******************************************************************************
190 :
191 12 : void SimMSHP(EnergyPlusData &state,
192 : int const MSHeatPumpNum, // number of the current engine driven Heat Pump being simulated
193 : bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
194 : int const AirLoopNum, // air loop index
195 : Real64 &QSensUnitOut, // cooling/heating delivered to zones [W]
196 : Real64 const QZnReq, // required zone load
197 : Real64 &OnOffAirFlowRatio // ratio of compressor ON airflow to AVERAGE airflow over timestep
198 : )
199 : {
200 :
201 : // SUBROUTINE INFORMATION:
202 : // AUTHOR Lixing Gu
203 : // DATE WRITTEN June 2007
204 : // RE-ENGINEERED Revised based on SimPTHP
205 :
206 : // PURPOSE OF THIS SUBROUTINE:
207 : // Simulate a multispeed heat pump; adjust its output to match the
208 : // required system load.
209 :
210 : // METHODOLOGY EMPLOYED:
211 : // Calls ControlMSHPOutput to obtain the desired unit output
212 :
213 : // Locals
214 : Real64 SupHeaterLoad;
215 :
216 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
217 : Real64 PartLoadFrac; // compressor part load fraction
218 : Real64 SpeedRatio; // compressor speed ratio
219 : bool UnitOn; // TRUE if unit is on
220 : int OutletNode; // MSHP air outlet node
221 : int InletNode; // MSHP air inlet node
222 : Real64 AirMassFlow; // air mass flow rate [kg/s]
223 : HVAC::FanOp fanOp; // operating mode (fan cycling or continuous; DX coil always cycles)
224 : int ZoneNum; // Controlled zone number
225 : Real64 QTotUnitOut;
226 : int SpeedNum; // Speed number
227 : HVAC::CompressorOp compressorOp; // compressor operation; 1=on, 0=off
228 : Real64 SaveMassFlowRate; // saved inlet air mass flow rate [kg/s]
229 :
230 : // zero the fan, DX coils, and supplemental electric heater electricity consumption
231 12 : state.dataHVACGlobal->DXElecHeatingPower = 0.0;
232 12 : state.dataHVACGlobal->DXElecCoolingPower = 0.0;
233 12 : state.dataHVACMultiSpdHP->SaveCompressorPLR = 0.0;
234 12 : state.dataHVACGlobal->ElecHeatingCoilPower = 0.0;
235 12 : state.dataHVACGlobal->SuppHeatingCoilPower = 0.0;
236 12 : state.dataHVACGlobal->DefrostElecPower = 0.0;
237 :
238 12 : auto &multiSpeedHeatPump = state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum);
239 :
240 : // initialize local variables
241 12 : UnitOn = true;
242 12 : OutletNode = multiSpeedHeatPump.AirOutletNodeNum;
243 12 : InletNode = multiSpeedHeatPump.AirInletNodeNum;
244 12 : AirMassFlow = state.dataLoopNodes->Node(InletNode).MassFlowRate;
245 12 : fanOp = multiSpeedHeatPump.fanOp;
246 12 : ZoneNum = multiSpeedHeatPump.ControlZoneNum;
247 12 : compressorOp = HVAC::CompressorOp::On;
248 :
249 : // set the on/off flags
250 12 : if (multiSpeedHeatPump.fanOp == HVAC::FanOp::Cycling) {
251 : // cycling unit only runs if there is a cooling or heating load.
252 0 : if (std::abs(QZnReq) < HVAC::SmallLoad || AirMassFlow < HVAC::SmallMassFlow ||
253 0 : state.dataZoneEnergyDemand->CurDeadBandOrSetback(ZoneNum)) {
254 0 : UnitOn = false;
255 : }
256 12 : } else if (multiSpeedHeatPump.fanOp == HVAC::FanOp::Continuous) {
257 : // continuous unit: fan runs if scheduled on; coil runs only if there is a cooling or heating load
258 12 : if (AirMassFlow < HVAC::SmallMassFlow) {
259 0 : UnitOn = false;
260 : }
261 : }
262 :
263 12 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
264 :
265 12 : SaveMassFlowRate = state.dataLoopNodes->Node(InletNode).MassFlowRate;
266 12 : if (multiSpeedHeatPump.EMSOverrideCoilSpeedNumOn) {
267 4 : Real64 SpeedVal = multiSpeedHeatPump.EMSOverrideCoilSpeedNumValue;
268 :
269 4 : if (!FirstHVACIteration && multiSpeedHeatPump.fanOp == HVAC::FanOp::Cycling && QZnReq < 0.0 &&
270 0 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).EconoActive) {
271 0 : compressorOp = HVAC::CompressorOp::Off;
272 0 : ControlMSHPOutputEMS(state,
273 : MSHeatPumpNum,
274 : FirstHVACIteration,
275 : compressorOp,
276 : fanOp,
277 : QZnReq,
278 : SpeedVal,
279 : SpeedNum,
280 : SpeedRatio,
281 : PartLoadFrac,
282 : OnOffAirFlowRatio,
283 : SupHeaterLoad);
284 0 : if (ceil(SpeedVal) == multiSpeedHeatPump.NumOfSpeedCooling && SpeedRatio == 1.0) {
285 0 : state.dataLoopNodes->Node(InletNode).MassFlowRate = SaveMassFlowRate;
286 0 : compressorOp = HVAC::CompressorOp::On;
287 0 : ControlMSHPOutputEMS(state,
288 : MSHeatPumpNum,
289 : FirstHVACIteration,
290 : compressorOp,
291 : fanOp,
292 : QZnReq,
293 : SpeedVal,
294 : SpeedNum,
295 : SpeedRatio,
296 : PartLoadFrac,
297 : OnOffAirFlowRatio,
298 : SupHeaterLoad);
299 : }
300 : } else {
301 4 : ControlMSHPOutputEMS(state,
302 : MSHeatPumpNum,
303 : FirstHVACIteration,
304 : compressorOp,
305 : fanOp,
306 : QZnReq,
307 : SpeedVal,
308 : SpeedNum,
309 : SpeedRatio,
310 : PartLoadFrac,
311 : OnOffAirFlowRatio,
312 : SupHeaterLoad);
313 : }
314 : } else {
315 8 : if (!FirstHVACIteration && multiSpeedHeatPump.fanOp == HVAC::FanOp::Cycling && QZnReq < 0.0 &&
316 0 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).EconoActive) {
317 : // for cycling fan, cooling load, check whether furnace can meet load with compressor off
318 0 : compressorOp = HVAC::CompressorOp::Off;
319 0 : ControlMSHPOutput(state,
320 : MSHeatPumpNum,
321 : FirstHVACIteration,
322 : compressorOp,
323 : fanOp,
324 : QZnReq,
325 : ZoneNum,
326 : SpeedNum,
327 : SpeedRatio,
328 : PartLoadFrac,
329 : OnOffAirFlowRatio,
330 : SupHeaterLoad);
331 0 : if (SpeedNum == multiSpeedHeatPump.NumOfSpeedCooling && SpeedRatio == 1.0) {
332 : // compressor on (reset inlet air mass flow rate to starting value)
333 0 : state.dataLoopNodes->Node(InletNode).MassFlowRate = SaveMassFlowRate;
334 0 : compressorOp = HVAC::CompressorOp::On;
335 0 : ControlMSHPOutput(state,
336 : MSHeatPumpNum,
337 : FirstHVACIteration,
338 : compressorOp,
339 : fanOp,
340 : QZnReq,
341 : ZoneNum,
342 : SpeedNum,
343 : SpeedRatio,
344 : PartLoadFrac,
345 : OnOffAirFlowRatio,
346 : SupHeaterLoad);
347 : }
348 : } else {
349 : // compressor on
350 8 : ControlMSHPOutput(state,
351 : MSHeatPumpNum,
352 : FirstHVACIteration,
353 : compressorOp,
354 : fanOp,
355 : QZnReq,
356 : ZoneNum,
357 : SpeedNum,
358 : SpeedRatio,
359 : PartLoadFrac,
360 : OnOffAirFlowRatio,
361 : SupHeaterLoad);
362 : }
363 : }
364 :
365 12 : if (multiSpeedHeatPump.HeatCoilType != MultiSpeedHeatingCoil) {
366 0 : state.dataHVACMultiSpdHP->SaveCompressorPLR = PartLoadFrac;
367 : } else {
368 12 : if (SpeedNum > 1) {
369 3 : state.dataHVACMultiSpdHP->SaveCompressorPLR = 1.0;
370 : }
371 :
372 12 : if (PartLoadFrac == 1.0 && state.dataHVACMultiSpdHP->SaveCompressorPLR < 1.0 && (!multiSpeedHeatPump.Staged)) {
373 0 : PartLoadFrac = state.dataHVACMultiSpdHP->SaveCompressorPLR;
374 : }
375 : }
376 :
377 12 : CalcMSHeatPump(state,
378 : MSHeatPumpNum,
379 : FirstHVACIteration,
380 : compressorOp,
381 : SpeedNum,
382 : SpeedRatio,
383 : PartLoadFrac,
384 : QSensUnitOut,
385 : QZnReq,
386 : OnOffAirFlowRatio,
387 : SupHeaterLoad);
388 :
389 : // calculate delivered capacity
390 12 : AirMassFlow = state.dataLoopNodes->Node(InletNode).MassFlowRate;
391 :
392 12 : QTotUnitOut = AirMassFlow * (state.dataLoopNodes->Node(OutletNode).Enthalpy -
393 12 : state.dataLoopNodes->Node(multiSpeedHeatPump.NodeNumOfControlledZone).Enthalpy);
394 :
395 : // report variables
396 12 : multiSpeedHeatPump.CompPartLoadRatio = state.dataHVACMultiSpdHP->SaveCompressorPLR;
397 12 : if (multiSpeedHeatPump.fanOp == HVAC::FanOp::Cycling) {
398 0 : if (SupHeaterLoad > 0.0) {
399 0 : multiSpeedHeatPump.FanPartLoadRatio = 1.0;
400 : } else {
401 0 : if (SpeedNum < 2) {
402 0 : multiSpeedHeatPump.FanPartLoadRatio = PartLoadFrac;
403 : } else {
404 0 : multiSpeedHeatPump.FanPartLoadRatio = 1.0;
405 : }
406 : }
407 : } else {
408 12 : if (UnitOn) {
409 12 : multiSpeedHeatPump.FanPartLoadRatio = 1.0;
410 : } else {
411 0 : if (SpeedNum < 2) {
412 0 : multiSpeedHeatPump.FanPartLoadRatio = PartLoadFrac;
413 : } else {
414 0 : multiSpeedHeatPump.FanPartLoadRatio = 1.0;
415 : }
416 : }
417 : }
418 :
419 12 : if (multiSpeedHeatPump.HeatCoolMode == ModeOfOperation::HeatingMode) {
420 8 : multiSpeedHeatPump.TotHeatEnergyRate = std::abs(max(0.0, QTotUnitOut));
421 8 : multiSpeedHeatPump.SensHeatEnergyRate = std::abs(max(0.0, QSensUnitOut));
422 8 : multiSpeedHeatPump.LatHeatEnergyRate = std::abs(max(0.0, (QTotUnitOut - QSensUnitOut)));
423 8 : multiSpeedHeatPump.TotCoolEnergyRate = 0.0;
424 8 : multiSpeedHeatPump.SensCoolEnergyRate = 0.0;
425 8 : multiSpeedHeatPump.LatCoolEnergyRate = 0.0;
426 : }
427 12 : if (multiSpeedHeatPump.HeatCoolMode == ModeOfOperation::CoolingMode) {
428 4 : multiSpeedHeatPump.TotCoolEnergyRate = std::abs(min(0.0, QTotUnitOut));
429 4 : multiSpeedHeatPump.SensCoolEnergyRate = std::abs(min(0.0, QSensUnitOut));
430 4 : multiSpeedHeatPump.LatCoolEnergyRate = std::abs(min(0.0, (QTotUnitOut - QSensUnitOut)));
431 4 : multiSpeedHeatPump.TotHeatEnergyRate = 0.0;
432 4 : multiSpeedHeatPump.SensHeatEnergyRate = 0.0;
433 4 : multiSpeedHeatPump.LatHeatEnergyRate = 0.0;
434 : }
435 :
436 12 : multiSpeedHeatPump.AuxElecPower = multiSpeedHeatPump.AuxOnCyclePower * state.dataHVACMultiSpdHP->SaveCompressorPLR +
437 12 : multiSpeedHeatPump.AuxOffCyclePower * (1.0 - state.dataHVACMultiSpdHP->SaveCompressorPLR);
438 12 : Real64 locFanElecPower = 0.0;
439 12 : locFanElecPower = state.dataFans->fans(multiSpeedHeatPump.FanNum)->totalPower;
440 12 : multiSpeedHeatPump.ElecPower = locFanElecPower + state.dataHVACGlobal->DXElecCoolingPower + state.dataHVACGlobal->DXElecHeatingPower +
441 12 : state.dataHVACGlobal->ElecHeatingCoilPower + state.dataHVACGlobal->SuppHeatingCoilPower +
442 12 : state.dataHVACGlobal->DefrostElecPower + multiSpeedHeatPump.AuxElecPower;
443 12 : }
444 :
445 : //******************************************************************************
446 :
447 2 : void GetMSHeatPumpInput(EnergyPlusData &state)
448 : {
449 : // SUBROUTINE INFORMATION:
450 : // AUTHOR: Lixing Gu, FSEC
451 : // DATE WRITTEN: July 2007
452 :
453 : // PURPOSE OF THIS SUBROUTINE:
454 : // This routine will get the input required by the multispeed heat pump model
455 :
456 : using namespace OutputReportPredefined;
457 :
458 : // PARAMETERS
459 : static constexpr std::string_view RoutineName("GetMSHeatPumpInput: "); // include trailing blank space
460 : static constexpr std::string_view routineName = "GetMSHeatPumpInput";
461 :
462 : // LOCAL VARIABLES
463 : int NumAlphas; // Number of elements in the alpha array
464 : int NumNumbers; // Number of Numbers for each GetObjectItem call
465 : int IOStatus; // Used in GetObjectItem
466 2 : bool ErrorsFound(false); // True when input errors found
467 : bool IsNotOK; // Flag to verify name
468 : bool AirNodeFound; // True when an air node is found
469 : bool AirLoopFound; // True when an air loop is found
470 : int i; // Index to speeds
471 : int j; // Index to speeds
472 : bool Found; // Flag to find autosize
473 : bool LocalError; // Local error flag
474 2 : Array1D_string Alphas; // Alpha input items for object
475 2 : Array1D_string cAlphaFields; // Alpha field names
476 2 : Array1D_string cNumericFields; // Numeric field names
477 2 : Array1D<Real64> Numbers; // Numeric input items for object
478 2 : Array1D_bool lAlphaBlanks; // Logical array, alpha field input BLANK = .TRUE.
479 2 : Array1D_bool lNumericBlanks; // Logical array, numeric field input BLANK = .TRUE.
480 2 : int MaxNums(0); // Maximum number of numeric input fields
481 2 : int MaxAlphas(0); // Maximum number of alpha input fields
482 2 : int TotalArgs(0); // Total number of alpha and numeric arguments (max) for a
483 : // certain object in the input file
484 : bool errFlag;
485 : Real64 SteamDensity; // density of steam at 100C
486 :
487 2 : auto &MSHeatPump(state.dataHVACMultiSpdHP->MSHeatPump);
488 :
489 2 : if (MSHeatPump.allocated()) return;
490 :
491 2 : state.dataHVACMultiSpdHP->CurrentModuleObject =
492 2 : "AirLoopHVAC:UnitaryHeatPump:AirToAir:MultiSpeed"; // Object type for getting and error messages
493 :
494 4 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
495 2 : state, state.dataHVACMultiSpdHP->CurrentModuleObject, TotalArgs, NumAlphas, NumNumbers);
496 2 : MaxNums = max(MaxNums, NumNumbers);
497 2 : MaxAlphas = max(MaxAlphas, NumAlphas);
498 :
499 2 : Alphas.allocate(MaxAlphas);
500 2 : cAlphaFields.allocate(MaxAlphas);
501 2 : Numbers.dimension(MaxNums, 0.0);
502 2 : cNumericFields.allocate(MaxNums);
503 2 : lAlphaBlanks.dimension(MaxAlphas, true);
504 2 : lNumericBlanks.dimension(MaxNums, true);
505 :
506 4 : state.dataHVACMultiSpdHP->NumMSHeatPumps =
507 2 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, state.dataHVACMultiSpdHP->CurrentModuleObject);
508 :
509 2 : if (state.dataHVACMultiSpdHP->NumMSHeatPumps <= 0) {
510 0 : ShowSevereError(state, format("No {} objects specified in input file.", state.dataHVACMultiSpdHP->CurrentModuleObject));
511 0 : ErrorsFound = true;
512 : }
513 :
514 : // ALLOCATE ARRAYS
515 2 : MSHeatPump.allocate(state.dataHVACMultiSpdHP->NumMSHeatPumps);
516 2 : state.dataHVACMultiSpdHP->MSHeatPumpReport.allocate(state.dataHVACMultiSpdHP->NumMSHeatPumps);
517 2 : state.dataHVACMultiSpdHP->CheckEquipName.dimension(state.dataHVACMultiSpdHP->NumMSHeatPumps, true);
518 :
519 : // Load arrays with reformulated electric EIR chiller data
520 5 : for (int MSHPNum = 1; MSHPNum <= state.dataHVACMultiSpdHP->NumMSHeatPumps; ++MSHPNum) {
521 3 : auto &thisMSHP = MSHeatPump(MSHPNum);
522 3 : int HeatingCoilInletNode = 0;
523 3 : int HeatingCoilOutletNode = 0;
524 3 : int CoolingCoilInletNode = 0;
525 3 : int CoolingCoilOutletNode = 0;
526 3 : int SuppHeatCoilInletNode = 0;
527 3 : int SuppHeatCoilOutletNode = 0;
528 :
529 6 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
530 3 : state.dataHVACMultiSpdHP->CurrentModuleObject,
531 : MSHPNum,
532 : Alphas,
533 : NumAlphas,
534 : Numbers,
535 : NumNumbers,
536 : IOStatus,
537 : lNumericBlanks,
538 : lAlphaBlanks,
539 : cAlphaFields,
540 : cNumericFields);
541 :
542 3 : thisMSHP.Name = Alphas(1);
543 :
544 3 : ErrorObjectHeader eoh{routineName, state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name};
545 :
546 3 : if (lAlphaBlanks(2)) {
547 0 : thisMSHP.availSched = Sched::GetScheduleAlwaysOn(state);
548 3 : } else if ((thisMSHP.availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) {
549 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
550 0 : ErrorsFound = true;
551 : }
552 :
553 3 : thisMSHP.AirInletNodeName = Alphas(3);
554 3 : thisMSHP.AirOutletNodeName = Alphas(4);
555 3 : thisMSHP.AirInletNodeNum = GetOnlySingleNode(state,
556 3 : Alphas(3),
557 : ErrorsFound,
558 : DataLoopNode::ConnectionObjectType::AirLoopHVACUnitaryHeatPumpAirToAirMultiSpeed,
559 3 : Alphas(1),
560 : DataLoopNode::NodeFluidType::Air,
561 : DataLoopNode::ConnectionType::Inlet,
562 : NodeInputManager::CompFluidStream::Primary,
563 : DataLoopNode::ObjectIsParent);
564 :
565 6 : thisMSHP.AirOutletNodeNum = GetOnlySingleNode(state,
566 3 : Alphas(4),
567 : ErrorsFound,
568 : DataLoopNode::ConnectionObjectType::AirLoopHVACUnitaryHeatPumpAirToAirMultiSpeed,
569 3 : Alphas(1),
570 : DataLoopNode::NodeFluidType::Air,
571 : DataLoopNode::ConnectionType::Outlet,
572 : NodeInputManager::CompFluidStream::Primary,
573 : DataLoopNode::ObjectIsParent);
574 :
575 3 : BranchNodeConnections::TestCompSet(state, state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1), Alphas(3), Alphas(4), "Air Nodes");
576 :
577 : // Get the Controlling Zone or Location of the engine driven heat pump Thermostat
578 3 : thisMSHP.ControlZoneNum = Util::FindItemInList(Alphas(5), state.dataHeatBal->Zone);
579 3 : thisMSHP.ControlZoneName = Alphas(5);
580 3 : if (thisMSHP.ControlZoneNum == 0) {
581 0 : ShowSevereError(state,
582 0 : format("{}, \"{}\" {} not found: {}",
583 0 : state.dataHVACMultiSpdHP->CurrentModuleObject,
584 0 : thisMSHP.Name,
585 : cAlphaFields(5),
586 0 : thisMSHP.ControlZoneName));
587 0 : ErrorsFound = true;
588 : }
589 :
590 : // Get the node number for the zone with the thermostat
591 3 : if (thisMSHP.ControlZoneNum > 0) {
592 3 : AirNodeFound = false;
593 3 : AirLoopFound = false;
594 3 : int ControlledZoneNum = thisMSHP.ControlZoneNum;
595 : // Find the controlled zone number for the specified thermostat location
596 3 : thisMSHP.NodeNumOfControlledZone = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneNode;
597 : // Determine if furnace is on air loop served by the thermostat location specified
598 3 : for (int zoneInNode = 1; zoneInNode <= state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).NumInletNodes; ++zoneInNode) {
599 3 : int AirLoopNumber = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNodeAirLoopNum(zoneInNode);
600 3 : if (AirLoopNumber > 0) {
601 3 : for (int BranchNum = 1; BranchNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).NumBranches; ++BranchNum) {
602 6 : for (int CompNum = 1;
603 6 : CompNum <= state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).TotalComponents;
604 : ++CompNum) {
605 6 : if (!Util::SameString(state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).Name,
606 9 : thisMSHP.Name) ||
607 6 : !Util::SameString(
608 3 : state.dataAirSystemsData->PrimaryAirSystems(AirLoopNumber).Branch(BranchNum).Comp(CompNum).TypeOf,
609 3 : state.dataHVACMultiSpdHP->CurrentModuleObject))
610 3 : continue;
611 3 : AirLoopFound = true;
612 3 : thisMSHP.AirLoopNumber = AirLoopNumber;
613 3 : break;
614 : }
615 3 : thisMSHP.ZoneInletNode = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).InletNode(zoneInNode);
616 3 : if (AirLoopFound) break;
617 : }
618 8 : for (int TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumTempControlledZones; ++TstatZoneNum) {
619 5 : if (state.dataZoneCtrls->TempControlledZone(TstatZoneNum).ActualZoneNum != thisMSHP.ControlZoneNum) continue;
620 3 : AirNodeFound = true;
621 : }
622 3 : for (int TstatZoneNum = 1; TstatZoneNum <= state.dataZoneCtrls->NumComfortControlledZones; ++TstatZoneNum) {
623 0 : if (state.dataZoneCtrls->ComfortControlledZone(TstatZoneNum).ActualZoneNum != thisMSHP.ControlZoneNum) continue;
624 0 : AirNodeFound = true;
625 : }
626 3 : for (int TstatZoneNum = 1; TstatZoneNum <= state.dataZoneTempPredictorCorrector->NumStageCtrZone; ++TstatZoneNum) {
627 0 : if (state.dataZoneCtrls->StageControlledZone(TstatZoneNum).ActualZoneNum != thisMSHP.ControlZoneNum) continue;
628 0 : AirNodeFound = true;
629 : }
630 : }
631 3 : if (AirLoopFound) break;
632 : }
633 3 : if (!AirNodeFound) {
634 0 : ShowSevereError(state,
635 0 : format("Did not find Air Node ({}), {} = \"\"{}",
636 : cAlphaFields(5),
637 0 : state.dataHVACMultiSpdHP->CurrentModuleObject,
638 0 : thisMSHP.Name));
639 0 : ShowContinueError(state, format("Specified {} = {}", cAlphaFields(5), Alphas(5)));
640 0 : ErrorsFound = true;
641 : }
642 3 : if (!AirLoopFound) {
643 0 : ShowSevereError(
644 0 : state, format("Did not find correct AirLoopHVAC for {} = {}", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name));
645 0 : ShowContinueError(state, format("The {} = {} is not served by this Primary Air Loop equipment.", cAlphaFields(5), Alphas(5)));
646 0 : ErrorsFound = true;
647 : }
648 : }
649 :
650 : // Get supply fan data
651 3 : thisMSHP.FanNum = Fans::GetFanIndex(state, Alphas(7));
652 3 : if (thisMSHP.FanNum == 0) {
653 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(7), Alphas(7));
654 0 : ErrorsFound = true;
655 : } else {
656 3 : auto *fan = state.dataFans->fans(thisMSHP.FanNum);
657 3 : thisMSHP.FanName = fan->Name;
658 3 : thisMSHP.fanType = fan->type;
659 3 : thisMSHP.FanInletNode = fan->inletNodeNum;
660 3 : thisMSHP.FanOutletNode = fan->outletNodeNum;
661 9 : BranchNodeConnections::SetUpCompSets(state,
662 3 : state.dataHVACMultiSpdHP->CurrentModuleObject,
663 : thisMSHP.Name,
664 3 : HVAC::fanTypeNames[(int)thisMSHP.fanType],
665 : thisMSHP.FanName,
666 : "UNDEFINED",
667 : "UNDEFINED");
668 : }
669 :
670 : // Get supply fan placement data
671 3 : thisMSHP.fanPlace = static_cast<HVAC::FanPlace>(getEnumValue(HVAC::fanPlaceNamesUC, Alphas(8)));
672 3 : assert(thisMSHP.fanPlace != HVAC::FanPlace::Invalid);
673 :
674 3 : if ((thisMSHP.fanOpModeSched = Sched::GetSchedule(state, Alphas(9))) == nullptr) {
675 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(9), Alphas(9));
676 0 : ErrorsFound = true;
677 : }
678 :
679 3 : if (thisMSHP.fanOpModeSched != nullptr && thisMSHP.fanType == HVAC::FanType::Constant) {
680 0 : if (!thisMSHP.fanOpModeSched->checkMinMaxVals(state, Clusive::Ex, 0.0, Clusive::In, 1.0)) {
681 0 : Sched::ShowSevereBadMinMax(state,
682 : eoh,
683 0 : cAlphaFields(9),
684 0 : Alphas(9),
685 : Clusive::Ex,
686 : 0.0,
687 : Clusive::In,
688 : 1.0,
689 : "Fan mode must be continuous (schedule values > 0) for Fan:ConstantVolume.");
690 0 : ErrorsFound = true;
691 : }
692 : }
693 :
694 3 : if (Util::SameString(Alphas(10), "Coil:Heating:DX:MultiSpeed")) {
695 3 : thisMSHP.HeatCoilType = MultiSpeedHeatingCoil;
696 3 : thisMSHP.HeatCoilNum = state.dataInputProcessing->inputProcessor->getObjectItemNum(state, "Coil:Heating:DX:MultiSpeed", Alphas(11));
697 3 : thisMSHP.DXHeatCoilName = Alphas(11);
698 3 : if (thisMSHP.HeatCoilNum <= 0) {
699 0 : ShowSevereError(state, format("Configuration error in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1)));
700 0 : ShowContinueError(state, format("{} \"{}\" not found.", cAlphaFields(11), Alphas(11)));
701 0 : ShowContinueError(state, format("{} must be Coil:Heating:DX:MultiSpeed ", cAlphaFields(10)));
702 0 : ShowFatalError(state,
703 0 : format("{}Errors found in getting {} input. Preceding condition(s) causes termination.",
704 : RoutineName,
705 0 : state.dataHVACMultiSpdHP->CurrentModuleObject));
706 0 : ErrorsFound = true;
707 : }
708 3 : LocalError = false;
709 3 : DXCoils::GetDXCoilIndex(state, thisMSHP.DXHeatCoilName, thisMSHP.DXHeatCoilIndex, LocalError, "Coil:Heating:DX:MultiSpeed");
710 3 : if (LocalError) {
711 0 : ShowSevereError(state, format("The index of {} is not found \"{}\"", cAlphaFields(11), Alphas(11)));
712 0 : ShowContinueError(state, format("...occurs in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1)));
713 0 : ErrorsFound = true;
714 0 : LocalError = false;
715 : }
716 3 : HeatingCoilInletNode = DXCoils::GetCoilInletNode(state, Alphas(10), Alphas(11), LocalError);
717 3 : if (LocalError) {
718 0 : ShowSevereError(state, format("The inlet node number of {} is not found \"{}\"", cAlphaFields(11), Alphas(11)));
719 0 : ShowContinueError(state, format("...occurs in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1)));
720 0 : ErrorsFound = true;
721 0 : LocalError = false;
722 : }
723 3 : HeatingCoilOutletNode = DXCoils::GetCoilOutletNode(state, Alphas(10), Alphas(11), LocalError);
724 3 : if (LocalError) {
725 0 : ShowSevereError(state, format("The outlet node number of {} is not found \"{}\"", cAlphaFields(11), Alphas(11)));
726 0 : ShowContinueError(state, format("...occurs in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1)));
727 0 : ErrorsFound = true;
728 0 : LocalError = false;
729 : }
730 3 : thisMSHP.MinOATCompressorHeating = DXCoils::GetMinOATCompressor(state, thisMSHP.DXHeatCoilIndex, LocalError);
731 3 : if (LocalError) {
732 0 : ShowContinueError(state,
733 0 : format("...for heating coil. Occurs in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1)));
734 0 : LocalError = false;
735 : }
736 6 : BranchNodeConnections::SetUpCompSets(state,
737 3 : state.dataHVACMultiSpdHP->CurrentModuleObject,
738 : thisMSHP.Name,
739 : "Coil:Heating:DX:MultiSpeed",
740 : thisMSHP.DXHeatCoilName,
741 : "UNDEFINED",
742 : "UNDEFINED");
743 0 : } else if (Util::SameString(Alphas(10), "Coil:Heating:Electric:MultiStage") ||
744 0 : Util::SameString(Alphas(10), "Coil:Heating:Gas:MultiStage")) {
745 :
746 0 : if (Util::SameString(Alphas(10), "Coil:Heating:Electric:MultiStage")) {
747 0 : thisMSHP.HeatCoilType = HVAC::Coil_HeatingElectric_MultiStage;
748 0 : thisMSHP.HeatCoilNum =
749 0 : state.dataInputProcessing->inputProcessor->getObjectItemNum(state, "Coil:Heating:Electric:MultiStage", Alphas(11));
750 0 : if (thisMSHP.HeatCoilNum <= 0) {
751 0 : ShowSevereError(state, format("Configuration error in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1)));
752 0 : ShowContinueError(state, format("{} \"{}\" not found.", cAlphaFields(11), Alphas(11)));
753 0 : ShowContinueError(state, format("{} must be Coil:Heating:Electric:MultiStage ", cAlphaFields(10)));
754 0 : ShowFatalError(state,
755 0 : format("{}Errors found in getting {} input. Preceding condition(s) causes termination.",
756 : RoutineName,
757 0 : state.dataHVACMultiSpdHP->CurrentModuleObject));
758 0 : ErrorsFound = true;
759 : }
760 : } else {
761 0 : thisMSHP.HeatCoilType = HVAC::Coil_HeatingGas_MultiStage;
762 0 : thisMSHP.HeatCoilNum =
763 0 : state.dataInputProcessing->inputProcessor->getObjectItemNum(state, "Coil:Heating:Gas:MultiStage", Alphas(11));
764 0 : if (thisMSHP.HeatCoilNum <= 0) {
765 0 : ShowSevereError(state, format("Configuration error in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1)));
766 0 : ShowContinueError(state, format("{} \"{}\" not found.", cAlphaFields(11), Alphas(11)));
767 0 : ShowContinueError(state, format("{} must be Coil:Heating:Gas:MultiStage ", cAlphaFields(10)));
768 0 : ShowFatalError(state,
769 0 : format("{}Errors found in getting {} input. Preceding condition(s) causes termination.",
770 : RoutineName,
771 0 : state.dataHVACMultiSpdHP->CurrentModuleObject));
772 0 : ErrorsFound = true;
773 : }
774 : }
775 0 : thisMSHP.HeatCoilName = Alphas(11);
776 0 : LocalError = false;
777 0 : if (Util::SameString(Alphas(10), "Coil:Heating:Electric:MultiStage")) {
778 0 : HeatingCoils::GetCoilIndex(state, thisMSHP.HeatCoilName, thisMSHP.HeatCoilIndex, LocalError);
779 : } else {
780 0 : HeatingCoils::GetCoilIndex(state, thisMSHP.HeatCoilName, thisMSHP.HeatCoilIndex, LocalError);
781 : }
782 0 : if (LocalError) {
783 0 : ShowSevereError(state, format("The index of {} is not found \"{}\"", cAlphaFields(11), Alphas(11)));
784 0 : ShowContinueError(state, format("...occurs in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1)));
785 0 : ErrorsFound = true;
786 0 : LocalError = false;
787 : }
788 0 : HeatingCoilInletNode = HeatingCoils::GetCoilInletNode(state, Alphas(10), Alphas(11), LocalError);
789 0 : if (LocalError) {
790 0 : ShowSevereError(state, format("The inlet node number of {} is not found \"{}\"", cAlphaFields(11), Alphas(11)));
791 0 : ShowContinueError(state, format("...occurs in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1)));
792 0 : ErrorsFound = true;
793 0 : LocalError = false;
794 : }
795 0 : HeatingCoilOutletNode = HeatingCoils::GetCoilOutletNode(state, Alphas(10), Alphas(11), LocalError);
796 0 : if (LocalError) {
797 0 : ShowSevereError(state, format("The outlet node number of {} is not found \"{}\"", cAlphaFields(11), Alphas(11)));
798 0 : ShowContinueError(state, format("...occurs in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1)));
799 0 : ErrorsFound = true;
800 0 : LocalError = false;
801 : }
802 0 : if (Util::SameString(Alphas(10), "Coil:Heating:Electric:MultiStage")) {
803 0 : BranchNodeConnections::SetUpCompSets(state,
804 0 : state.dataHVACMultiSpdHP->CurrentModuleObject,
805 : thisMSHP.Name,
806 : "Coil:Heating:Electric:MultiStage",
807 : thisMSHP.HeatCoilName,
808 : "UNDEFINED",
809 : "UNDEFINED");
810 : } else {
811 0 : BranchNodeConnections::SetUpCompSets(state,
812 0 : state.dataHVACMultiSpdHP->CurrentModuleObject,
813 : thisMSHP.Name,
814 : "Coil:Heating:Gas:MultiStage",
815 : thisMSHP.HeatCoilName,
816 : "UNDEFINED",
817 : "UNDEFINED");
818 : }
819 0 : } else if (Util::SameString(Alphas(10), "Coil:Heating:Water")) {
820 0 : thisMSHP.HeatCoilType = HVAC::Coil_HeatingWater;
821 0 : ValidateComponent(state, Alphas(10), Alphas(11), IsNotOK, state.dataHVACMultiSpdHP->CurrentModuleObject);
822 0 : if (IsNotOK) {
823 0 : ShowContinueError(state, format("...occurs in {} = {}", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1)));
824 0 : ErrorsFound = true;
825 : } else { // mine data from heating coil object
826 :
827 0 : thisMSHP.HeatCoilName = Alphas(11);
828 : // Get the Heating Coil water Inlet or control Node number
829 0 : errFlag = false;
830 0 : thisMSHP.CoilControlNode = WaterCoils::GetCoilWaterInletNode(state, "Coil:Heating:Water", thisMSHP.HeatCoilName, errFlag);
831 0 : if (errFlag) {
832 0 : ShowContinueError(state, format("Occurs in {} = {}", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name));
833 0 : ErrorsFound = true;
834 : }
835 :
836 : // Get the ReHeat Coil hot water max volume flow rate
837 0 : errFlag = false;
838 0 : thisMSHP.MaxCoilFluidFlow = WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", thisMSHP.HeatCoilName, errFlag);
839 0 : if (errFlag) {
840 0 : ShowContinueError(state, format("Occurs in {} = {}", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name));
841 0 : ErrorsFound = true;
842 : }
843 :
844 : // Get the supplemental Heating Coil Inlet Node
845 0 : errFlag = false;
846 0 : HeatingCoilInletNode = WaterCoils::GetCoilInletNode(state, "Coil:Heating:Water", thisMSHP.HeatCoilName, errFlag);
847 0 : thisMSHP.CoilAirInletNode = HeatingCoilInletNode;
848 0 : if (errFlag) {
849 0 : ShowContinueError(state, format("Occurs in {} = {}", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name));
850 0 : ErrorsFound = true;
851 : }
852 :
853 : // Get the supplemental Heating Coil Outlet Node
854 0 : errFlag = false;
855 0 : HeatingCoilOutletNode = WaterCoils::GetCoilOutletNode(state, "Coil:Heating:Water", thisMSHP.HeatCoilName, errFlag);
856 0 : if (errFlag) {
857 0 : ShowContinueError(state, format("Occurs in {} = {}", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name));
858 0 : ErrorsFound = true;
859 : }
860 0 : BranchNodeConnections::SetUpCompSets(state,
861 0 : state.dataHVACMultiSpdHP->CurrentModuleObject,
862 : thisMSHP.Name,
863 : "Coil:Heating:Water",
864 : thisMSHP.HeatCoilName,
865 0 : state.dataLoopNodes->NodeID(HeatingCoilInletNode),
866 0 : state.dataLoopNodes->NodeID(HeatingCoilOutletNode));
867 : }
868 0 : } else if (Util::SameString(Alphas(10), "Coil:Heating:Steam")) {
869 0 : thisMSHP.HeatCoilType = HVAC::Coil_HeatingSteam;
870 0 : ValidateComponent(state, Alphas(10), Alphas(11), IsNotOK, state.dataHVACMultiSpdHP->CurrentModuleObject);
871 0 : if (IsNotOK) {
872 0 : ShowContinueError(state, format("...occurs in {} = {}", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name));
873 0 : ErrorsFound = true;
874 : } else { // mine data from heating coil object
875 :
876 0 : thisMSHP.HeatCoilName = Alphas(11);
877 0 : errFlag = false;
878 0 : thisMSHP.HeatCoilNum = SteamCoils::GetSteamCoilIndex(state, Alphas(10), thisMSHP.HeatCoilName, errFlag);
879 0 : if (thisMSHP.HeatCoilNum == 0) {
880 0 : ShowSevereError(
881 : state,
882 0 : format("{} illegal {} = {}", state.dataHVACMultiSpdHP->CurrentModuleObject, cAlphaFields(10), thisMSHP.HeatCoilName));
883 0 : ShowContinueError(state, format("Occurs in {} = {}", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name));
884 0 : ErrorsFound = true;
885 : }
886 :
887 : // Get the supplemental Heating Coil steam inlet node number
888 0 : errFlag = false;
889 0 : thisMSHP.CoilControlNode = SteamCoils::GetCoilAirOutletNode(state, "Coil:Heating:Steam", thisMSHP.HeatCoilName, errFlag);
890 0 : if (errFlag) {
891 0 : ShowContinueError(state, format("Occurs in {} = {}", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name));
892 0 : ErrorsFound = true;
893 : }
894 :
895 : // Get the supplemental Heating Coil steam max volume flow rate
896 0 : thisMSHP.MaxCoilFluidFlow = SteamCoils::GetCoilMaxSteamFlowRate(state, thisMSHP.HeatCoilNum, errFlag);
897 0 : if (thisMSHP.MaxCoilFluidFlow > 0.0) {
898 0 : SteamDensity = Fluid::GetSteam(state)->getSatDensity(state, state.dataHVACMultiSpdHP->TempSteamIn, 1.0, routineName);
899 0 : thisMSHP.MaxCoilFluidFlow *= SteamDensity;
900 : }
901 :
902 : // Get the supplemental Heating Coil Inlet Node
903 0 : errFlag = false;
904 0 : HeatingCoilInletNode = SteamCoils::GetCoilAirInletNode(state, thisMSHP.HeatCoilNum, thisMSHP.HeatCoilName, errFlag);
905 0 : thisMSHP.CoilAirInletNode = HeatingCoilInletNode;
906 0 : if (errFlag) {
907 0 : ShowContinueError(state, format("Occurs in {} = {}", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name));
908 0 : ErrorsFound = true;
909 : }
910 :
911 : // Get the supplemental Heating Coil Outlet Node
912 0 : errFlag = false;
913 0 : HeatingCoilOutletNode = SteamCoils::GetCoilAirOutletNode(state, thisMSHP.HeatCoilNum, thisMSHP.HeatCoilName, errFlag);
914 0 : if (errFlag) {
915 0 : ShowContinueError(state, format("Occurs in {} = {}", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name));
916 0 : ErrorsFound = true;
917 : }
918 :
919 0 : BranchNodeConnections::SetUpCompSets(state,
920 0 : state.dataHVACMultiSpdHP->CurrentModuleObject,
921 : thisMSHP.Name,
922 : "Coil:Heating:Steam",
923 : thisMSHP.HeatCoilName,
924 0 : state.dataLoopNodes->NodeID(HeatingCoilInletNode),
925 0 : state.dataLoopNodes->NodeID(HeatingCoilOutletNode));
926 : }
927 : } else {
928 0 : ShowSevereError(state,
929 0 : format("The allowed {} are Coil:Heating:DX:MultiSpeed, Coil:Heating:Electric:MultiStage, and "
930 : "Coil:Heating:Gas:MultiStage in {} \"{}\"",
931 : cAlphaFields(10),
932 0 : state.dataHVACMultiSpdHP->CurrentModuleObject,
933 : Alphas(1)));
934 0 : ShowContinueError(state, format("The entered {} = \"{}\".", cAlphaFields(10), Alphas(10)));
935 0 : ErrorsFound = true;
936 : }
937 :
938 : // thisMSHP.MinOATCompressor = Numbers(1); // deprecated, now uses coil MinOAT inputs
939 :
940 3 : if (Util::SameString(Alphas(12), "Coil:Cooling:DX:MultiSpeed")) {
941 3 : thisMSHP.CoolCoilType = MultiSpeedCoolingCoil;
942 3 : thisMSHP.DXCoolCoilName = Alphas(13);
943 3 : if (state.dataInputProcessing->inputProcessor->getObjectItemNum(state, "Coil:Cooling:DX:MultiSpeed", Alphas(13)) <= 0) {
944 0 : ShowSevereError(state, format("Configuration error in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1)));
945 0 : ShowContinueError(state, format("{} \"{}\" not found.", cAlphaFields(13), Alphas(13)));
946 0 : ShowContinueError(state, format("{} must be Coil:Cooling:DX:MultiSpeed ", cAlphaFields(12)));
947 0 : ShowFatalError(state,
948 0 : format("{}Errors found in getting {} input. Preceding condition(s) causes termination.",
949 : RoutineName,
950 0 : state.dataHVACMultiSpdHP->CurrentModuleObject));
951 0 : ErrorsFound = true;
952 : }
953 3 : LocalError = false;
954 3 : DXCoils::GetDXCoilIndex(state, thisMSHP.DXCoolCoilName, thisMSHP.DXCoolCoilIndex, LocalError, "Coil:Cooling:DX:MultiSpeed");
955 3 : if (LocalError) {
956 0 : ShowSevereError(state, format("The index of {} is not found \"{}\"", cAlphaFields(13), Alphas(13)));
957 0 : ShowContinueError(state, format("...occurs in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1)));
958 0 : ErrorsFound = true;
959 0 : LocalError = false;
960 : }
961 3 : CoolingCoilInletNode = DXCoils::GetCoilInletNode(state, Alphas(12), Alphas(13), LocalError);
962 3 : if (LocalError) {
963 0 : ShowSevereError(state, format("The inlet node number of {} is not found \"{}\"", cAlphaFields(13), Alphas(13)));
964 0 : ShowContinueError(state, format("...occurs in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1)));
965 0 : ErrorsFound = true;
966 0 : LocalError = false;
967 : }
968 3 : CoolingCoilOutletNode = DXCoils::GetCoilOutletNode(state, Alphas(12), Alphas(13), LocalError);
969 3 : if (LocalError) {
970 0 : ShowSevereError(state, format("The outlet node number of {} is not found \"{}\"", cAlphaFields(13), Alphas(13)));
971 0 : ShowContinueError(state, format("...occurs in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1)));
972 0 : ErrorsFound = true;
973 0 : LocalError = false;
974 : }
975 3 : thisMSHP.MinOATCompressorCooling = DXCoils::GetMinOATCompressor(state, thisMSHP.DXCoolCoilIndex, LocalError);
976 3 : if (LocalError) {
977 0 : ShowContinueError(state,
978 0 : format("...for cooling coil. Occurs in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1)));
979 0 : LocalError = false;
980 : }
981 : } else {
982 0 : ShowSevereError(state,
983 0 : format("The allowed {} is Coil:Cooling:DX:MultiSpeed in {} \"{}\"",
984 : cAlphaFields(12),
985 0 : state.dataHVACMultiSpdHP->CurrentModuleObject,
986 : Alphas(1)));
987 0 : ShowContinueError(state, format("The entered {} = \"{}\".", cAlphaFields(12), Alphas(12)));
988 0 : ErrorsFound = true;
989 : }
990 6 : BranchNodeConnections::SetUpCompSets(state,
991 3 : state.dataHVACMultiSpdHP->CurrentModuleObject,
992 : thisMSHP.Name,
993 : "Coil:Cooling:DX:MultiSpeed",
994 : thisMSHP.DXCoolCoilName,
995 : "UNDEFINED",
996 : "UNDEFINED");
997 :
998 : // Get supplemental heating coil data
999 3 : thisMSHP.SuppHeatCoilName = Alphas(15);
1000 3 : if (Util::SameString(Alphas(14), "Coil:Heating:Fuel")) {
1001 0 : thisMSHP.SuppHeatCoilType = SuppHeatingCoilGas;
1002 0 : errFlag = false;
1003 0 : thisMSHP.SuppHeatCoilNum = HeatingCoils::GetHeatingCoilIndex(state, "Coil:Heating:Fuel", Alphas(15), errFlag);
1004 0 : if (thisMSHP.SuppHeatCoilNum <= 0 || errFlag) {
1005 0 : ShowContinueError(state, format("Configuration error in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1)));
1006 0 : ShowContinueError(state, format("{} of type Coil:Heating:Fuel \"{}\" not found.", cAlphaFields(15), Alphas(15)));
1007 0 : ErrorsFound = true;
1008 : }
1009 :
1010 : // Get the Supplemental Heating Coil Node Numbers
1011 0 : LocalError = false;
1012 0 : SuppHeatCoilInletNode = HeatingCoils::GetCoilInletNode(state, Alphas(14), Alphas(15), LocalError);
1013 0 : if (LocalError) {
1014 0 : ShowSevereError(state, format("The inlet node number of {} is not found \"{}\"", cAlphaFields(15), Alphas(15)));
1015 0 : ShowContinueError(state, format("...occurs in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1)));
1016 0 : ErrorsFound = true;
1017 0 : LocalError = false;
1018 : }
1019 0 : SuppHeatCoilOutletNode = HeatingCoils::GetCoilOutletNode(state, Alphas(14), Alphas(15), LocalError);
1020 0 : if (LocalError) {
1021 0 : ShowSevereError(state, format("The outlet node number of {} is not found \"{}\"", cAlphaFields(15), Alphas(15)));
1022 0 : ShowContinueError(state, format("...occurs in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1)));
1023 0 : ErrorsFound = true;
1024 0 : LocalError = false;
1025 : }
1026 :
1027 : // Get supplemental heating coil capacity to see if it is autosize
1028 0 : thisMSHP.DesignSuppHeatingCapacity = HeatingCoils::GetCoilCapacity(state, Alphas(14), Alphas(15), LocalError);
1029 0 : if (LocalError) {
1030 0 : ShowSevereError(state, format("The capacity {} is not found \"{}\"", cAlphaFields(15), Alphas(15)));
1031 0 : ShowContinueError(state, format("...occurs in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1)));
1032 0 : ErrorsFound = true;
1033 0 : LocalError = false;
1034 : }
1035 0 : BranchNodeConnections::SetUpCompSets(state,
1036 0 : state.dataHVACMultiSpdHP->CurrentModuleObject,
1037 : thisMSHP.Name,
1038 : "Coil:Heating:Fuel",
1039 : thisMSHP.SuppHeatCoilName,
1040 : "UNDEFINED",
1041 : "UNDEFINED");
1042 : }
1043 3 : if (Util::SameString(Alphas(14), "Coil:Heating:Electric")) {
1044 3 : thisMSHP.SuppHeatCoilType = SuppHeatingCoilElec;
1045 3 : errFlag = false;
1046 6 : thisMSHP.SuppHeatCoilNum = HeatingCoils::GetHeatingCoilIndex(state, "Coil:Heating:Electric", Alphas(15), errFlag);
1047 3 : if (thisMSHP.SuppHeatCoilNum <= 0 || errFlag) {
1048 0 : ShowContinueError(state, format("Configuration error in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1)));
1049 0 : ShowContinueError(state, format("{} of type Coil:Heating:Electric \"{}\" not found.", cAlphaFields(15), Alphas(15)));
1050 0 : ErrorsFound = true;
1051 : }
1052 :
1053 : // Get the Supplemental Heating Coil Node Numbers
1054 3 : LocalError = false;
1055 3 : SuppHeatCoilInletNode = HeatingCoils::GetCoilInletNode(state, Alphas(14), Alphas(15), LocalError);
1056 3 : if (LocalError) {
1057 0 : ShowSevereError(state, format("The inlet node number of {} is not found \"{}\"", cAlphaFields(15), Alphas(15)));
1058 0 : ShowContinueError(state, format("...occurs in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1)));
1059 0 : ErrorsFound = true;
1060 0 : LocalError = false;
1061 : }
1062 3 : SuppHeatCoilOutletNode = HeatingCoils::GetCoilOutletNode(state, Alphas(14), Alphas(15), LocalError);
1063 3 : if (LocalError) {
1064 0 : ShowSevereError(state, format("The outlet node number of {} is not found \"{}\"", cAlphaFields(15), Alphas(15)));
1065 0 : ShowContinueError(state, format("...occurs in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1)));
1066 0 : ErrorsFound = true;
1067 0 : LocalError = false;
1068 : }
1069 :
1070 : // Get supplemental heating coil capacity to see if it is autosize
1071 3 : thisMSHP.DesignSuppHeatingCapacity = HeatingCoils::GetCoilCapacity(state, Alphas(14), Alphas(15), LocalError);
1072 3 : if (LocalError) {
1073 0 : ShowSevereError(state, format("The capacity {} is not found \"{}\"", cAlphaFields(15), Alphas(15)));
1074 0 : ShowContinueError(state, format("...occurs in {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1)));
1075 0 : ErrorsFound = true;
1076 0 : LocalError = false;
1077 : }
1078 :
1079 6 : BranchNodeConnections::SetUpCompSets(state,
1080 3 : state.dataHVACMultiSpdHP->CurrentModuleObject,
1081 : thisMSHP.Name,
1082 : "Coil:Heating:Electric",
1083 : thisMSHP.SuppHeatCoilName,
1084 : "UNDEFINED",
1085 : "UNDEFINED");
1086 : }
1087 :
1088 3 : if (Util::SameString(Alphas(14), "Coil:Heating:Water")) {
1089 0 : thisMSHP.SuppHeatCoilType = HVAC::Coil_HeatingWater;
1090 0 : ValidateComponent(state, Alphas(14), thisMSHP.SuppHeatCoilName, IsNotOK, state.dataHVACMultiSpdHP->CurrentModuleObject);
1091 0 : if (IsNotOK) {
1092 0 : ShowContinueError(state, format("...occurs in {} = {}", state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1)));
1093 0 : ErrorsFound = true;
1094 : } else { // mine data from heating coil object
1095 :
1096 : // Get the Heating Coil water Inlet or control Node number
1097 0 : errFlag = false;
1098 0 : thisMSHP.SuppCoilControlNode = WaterCoils::GetCoilWaterInletNode(state, "Coil:Heating:Water", thisMSHP.SuppHeatCoilName, errFlag);
1099 0 : if (errFlag) {
1100 0 : ShowContinueError(state, format("Occurs in {} = {}", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name));
1101 0 : ErrorsFound = true;
1102 : }
1103 :
1104 : // Get the ReHeat Coil hot water max volume flow rate
1105 0 : errFlag = false;
1106 0 : thisMSHP.MaxSuppCoilFluidFlow =
1107 0 : WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", thisMSHP.SuppHeatCoilName, errFlag);
1108 0 : if (errFlag) {
1109 0 : ShowContinueError(state, format("Occurs in {} = {}", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name));
1110 0 : ErrorsFound = true;
1111 : }
1112 :
1113 : // Get the Supplemental Heating Coil Inlet Node
1114 0 : errFlag = false;
1115 0 : SuppHeatCoilInletNode = WaterCoils::GetCoilInletNode(state, "Coil:Heating:Water", thisMSHP.SuppHeatCoilName, errFlag);
1116 0 : thisMSHP.SuppCoilAirInletNode = SuppHeatCoilInletNode;
1117 0 : if (errFlag) {
1118 0 : ShowContinueError(state, format("Occurs in {} = {}", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name));
1119 0 : ErrorsFound = true;
1120 : }
1121 :
1122 : // Get the Supplemental Heating Coil Outlet Node
1123 0 : errFlag = false;
1124 0 : SuppHeatCoilOutletNode = WaterCoils::GetCoilOutletNode(state, "Coil:Heating:Water", thisMSHP.SuppHeatCoilName, errFlag);
1125 0 : thisMSHP.SuppCoilAirOutletNode = SuppHeatCoilOutletNode;
1126 0 : if (errFlag) {
1127 0 : ShowContinueError(state, format("Occurs in {} = {}", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name));
1128 0 : ErrorsFound = true;
1129 : }
1130 0 : BranchNodeConnections::SetUpCompSets(state,
1131 0 : state.dataHVACMultiSpdHP->CurrentModuleObject,
1132 : thisMSHP.Name,
1133 : "Coil:Heating:Water",
1134 : thisMSHP.SuppHeatCoilName,
1135 0 : state.dataLoopNodes->NodeID(SuppHeatCoilInletNode),
1136 0 : state.dataLoopNodes->NodeID(SuppHeatCoilOutletNode));
1137 : }
1138 : }
1139 3 : if (Util::SameString(Alphas(14), "Coil:Heating:Steam")) {
1140 0 : thisMSHP.SuppHeatCoilType = HVAC::Coil_HeatingSteam;
1141 0 : ValidateComponent(state, Alphas(14), thisMSHP.SuppHeatCoilName, IsNotOK, state.dataHVACMultiSpdHP->CurrentModuleObject);
1142 0 : if (IsNotOK) {
1143 0 : ShowContinueError(state, format("...occurs in {} = {}", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name));
1144 0 : ErrorsFound = true;
1145 : } else { // mine data from heating coil object
1146 :
1147 0 : errFlag = false;
1148 0 : thisMSHP.SuppHeatCoilNum = SteamCoils::GetSteamCoilIndex(state, Alphas(14), thisMSHP.SuppHeatCoilName, errFlag);
1149 0 : if (thisMSHP.SuppHeatCoilNum == 0) {
1150 0 : ShowSevereError(
1151 : state,
1152 0 : format("{} illegal {} = {}", state.dataHVACMultiSpdHP->CurrentModuleObject, cAlphaFields(14), thisMSHP.SuppHeatCoilName));
1153 0 : ShowContinueError(state, format("Occurs in {} = {}", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name));
1154 0 : ErrorsFound = true;
1155 : }
1156 :
1157 : // Get the Supplemental Heating Coil steam inlet node number
1158 0 : errFlag = false;
1159 0 : thisMSHP.SuppCoilControlNode = SteamCoils::GetCoilAirOutletNode(state, "Coil:Heating:Steam", thisMSHP.SuppHeatCoilName, errFlag);
1160 0 : if (errFlag) {
1161 0 : ShowContinueError(state, format("Occurs in {} = {}", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name));
1162 0 : ErrorsFound = true;
1163 : }
1164 :
1165 : // Get the Supplemental Heating Coil steam max volume flow rate
1166 0 : thisMSHP.MaxSuppCoilFluidFlow = SteamCoils::GetCoilMaxSteamFlowRate(state, thisMSHP.SuppHeatCoilNum, errFlag);
1167 0 : if (thisMSHP.MaxSuppCoilFluidFlow > 0.0) {
1168 0 : SteamDensity = Fluid::GetSteam(state)->getSatDensity(state, state.dataHVACMultiSpdHP->TempSteamIn, 1.0, routineName);
1169 0 : thisMSHP.MaxSuppCoilFluidFlow *= SteamDensity;
1170 : }
1171 :
1172 : // Get the Supplemental Heating Coil Inlet Node
1173 0 : errFlag = false;
1174 0 : SuppHeatCoilInletNode = SteamCoils::GetCoilAirInletNode(state, thisMSHP.SuppHeatCoilNum, thisMSHP.SuppHeatCoilName, errFlag);
1175 0 : thisMSHP.SuppCoilAirInletNode = SuppHeatCoilInletNode;
1176 0 : if (errFlag) {
1177 0 : ShowContinueError(state, format("Occurs in {} = {}", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name));
1178 0 : ErrorsFound = true;
1179 : }
1180 :
1181 : // Get the Supplemental Heating Coil Outlet Node
1182 0 : errFlag = false;
1183 0 : SuppHeatCoilOutletNode = SteamCoils::GetCoilAirOutletNode(state, thisMSHP.SuppHeatCoilNum, thisMSHP.SuppHeatCoilName, errFlag);
1184 0 : thisMSHP.SuppCoilAirOutletNode = SuppHeatCoilOutletNode;
1185 0 : if (errFlag) {
1186 0 : ShowContinueError(state, format("Occurs in {} = {}", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name));
1187 0 : ErrorsFound = true;
1188 : }
1189 :
1190 0 : BranchNodeConnections::SetUpCompSets(state,
1191 0 : state.dataHVACMultiSpdHP->CurrentModuleObject,
1192 : thisMSHP.Name,
1193 : "Coil:Heating:Steam",
1194 : thisMSHP.SuppHeatCoilName,
1195 0 : state.dataLoopNodes->NodeID(SuppHeatCoilInletNode),
1196 0 : state.dataLoopNodes->NodeID(SuppHeatCoilOutletNode));
1197 : }
1198 : }
1199 :
1200 3 : if (thisMSHP.SuppHeatCoilType == 0) {
1201 0 : ShowSevereError(state,
1202 0 : format("{}, \"{}\", {} is not allowed = {}",
1203 0 : state.dataHVACMultiSpdHP->CurrentModuleObject,
1204 0 : thisMSHP.Name,
1205 : cAlphaFields(14),
1206 : Alphas(14)));
1207 0 : ShowContinueError(state, "Valid choices are Coil:Heating:Fuel,Coil:Heating:Electric,Coil:Heating:Steam,or Coil:Heating:Water");
1208 0 : ErrorsFound = true;
1209 : }
1210 :
1211 3 : thisMSHP.SuppMaxAirTemp = Numbers(2);
1212 3 : thisMSHP.SuppMaxOATemp = Numbers(3);
1213 3 : if (thisMSHP.SuppMaxOATemp > 21.0) {
1214 0 : ShowSevereError(
1215 : state,
1216 0 : format("{}, \"{}\", {} is greater than 21.0", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name, cNumericFields(3)));
1217 0 : ShowContinueError(state, format("The input value is {:.2R}", Numbers(3)));
1218 0 : ErrorsFound = true;
1219 : }
1220 6 : OutputReportPredefined::PreDefTableEntry(
1221 3 : state, state.dataOutRptPredefined->pdchDXHeatCoilSuppHiT, thisMSHP.DXHeatCoilName, thisMSHP.SuppMaxOATemp);
1222 :
1223 3 : thisMSHP.AuxOnCyclePower = Numbers(4);
1224 3 : thisMSHP.AuxOffCyclePower = Numbers(5);
1225 3 : if (thisMSHP.AuxOnCyclePower < 0.0) {
1226 0 : ShowSevereError(state,
1227 0 : format("{}, \"{}\", A negative value for {} is not allowed ",
1228 0 : state.dataHVACMultiSpdHP->CurrentModuleObject,
1229 0 : thisMSHP.Name,
1230 : cNumericFields(4)));
1231 0 : ErrorsFound = true;
1232 : }
1233 3 : if (thisMSHP.AuxOffCyclePower < 0.0) {
1234 0 : ShowSevereError(state,
1235 0 : format("{}, \"{}\", A negative value for {} is not allowed ",
1236 0 : state.dataHVACMultiSpdHP->CurrentModuleObject,
1237 0 : thisMSHP.Name,
1238 : cNumericFields(5)));
1239 0 : ErrorsFound = true;
1240 : }
1241 :
1242 : // Heat recovery
1243 3 : thisMSHP.DesignHeatRecFlowRate = Numbers(6);
1244 3 : if (thisMSHP.DesignHeatRecFlowRate > 0.0) {
1245 0 : thisMSHP.HeatRecActive = true;
1246 0 : thisMSHP.DesignHeatRecMassFlowRate = Psychrometrics::RhoH2O(Constant::HWInitConvTemp) * thisMSHP.DesignHeatRecFlowRate;
1247 0 : thisMSHP.HeatRecInletNodeNum = GetOnlySingleNode(state,
1248 0 : Alphas(16),
1249 : ErrorsFound,
1250 : DataLoopNode::ConnectionObjectType::AirLoopHVACUnitaryHeatPumpAirToAirMultiSpeed,
1251 0 : Alphas(1),
1252 : DataLoopNode::NodeFluidType::Water,
1253 : DataLoopNode::ConnectionType::Inlet,
1254 : NodeInputManager::CompFluidStream::Tertiary,
1255 : DataLoopNode::ObjectIsNotParent);
1256 0 : if (thisMSHP.HeatRecInletNodeNum == 0) {
1257 0 : ShowSevereError(
1258 0 : state, format("{}, \"{}\", Missing {}.", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name, cAlphaFields(16)));
1259 0 : ErrorsFound = true;
1260 : }
1261 0 : thisMSHP.HeatRecOutletNodeNum = GetOnlySingleNode(state,
1262 0 : Alphas(17),
1263 : ErrorsFound,
1264 : DataLoopNode::ConnectionObjectType::AirLoopHVACUnitaryHeatPumpAirToAirMultiSpeed,
1265 0 : Alphas(1),
1266 : DataLoopNode::NodeFluidType::Water,
1267 : DataLoopNode::ConnectionType::Outlet,
1268 : NodeInputManager::CompFluidStream::Tertiary,
1269 : DataLoopNode::ObjectIsNotParent);
1270 0 : if (thisMSHP.HeatRecOutletNodeNum == 0) {
1271 0 : ShowSevereError(
1272 0 : state, format("{}, \"{}\", Missing {}.", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name, cAlphaFields(17)));
1273 0 : ErrorsFound = true;
1274 : }
1275 0 : BranchNodeConnections::TestCompSet(
1276 0 : state, state.dataHVACMultiSpdHP->CurrentModuleObject, Alphas(1), Alphas(16), Alphas(17), "MSHP Heat Recovery Nodes");
1277 0 : DXCoils::SetMSHPDXCoilHeatRecoveryFlag(state, thisMSHP.DXCoolCoilIndex);
1278 0 : if (thisMSHP.DXHeatCoilIndex > 0) {
1279 0 : DXCoils::SetMSHPDXCoilHeatRecoveryFlag(state, thisMSHP.DXHeatCoilIndex);
1280 : }
1281 : } else {
1282 3 : thisMSHP.HeatRecActive = false;
1283 3 : thisMSHP.DesignHeatRecMassFlowRate = 0.0;
1284 3 : thisMSHP.HeatRecInletNodeNum = 0;
1285 3 : thisMSHP.HeatRecOutletNodeNum = 0;
1286 3 : if (!lAlphaBlanks(16) || !lAlphaBlanks(17)) {
1287 0 : ShowWarningError(state,
1288 0 : format("Since {} = 0.0, heat recovery is inactive for {} = {}",
1289 : cNumericFields(6),
1290 0 : state.dataHVACMultiSpdHP->CurrentModuleObject,
1291 : Alphas(1)));
1292 0 : ShowContinueError(state, format("However, {} or {} was specified.", cAlphaFields(16), cAlphaFields(17)));
1293 : }
1294 : }
1295 3 : thisMSHP.MaxHeatRecOutletTemp = Numbers(7);
1296 3 : if (thisMSHP.MaxHeatRecOutletTemp < 0.0) {
1297 0 : ShowSevereError(state,
1298 0 : format("{}, \"{}\", The value for {} is below 0.0",
1299 0 : state.dataHVACMultiSpdHP->CurrentModuleObject,
1300 0 : thisMSHP.Name,
1301 : cNumericFields(7)));
1302 0 : ErrorsFound = true;
1303 : }
1304 3 : if (thisMSHP.MaxHeatRecOutletTemp > 100.0) {
1305 0 : ShowSevereError(state,
1306 0 : format("{}, \"{}\", The value for {} is above 100.0",
1307 0 : state.dataHVACMultiSpdHP->CurrentModuleObject,
1308 0 : thisMSHP.Name,
1309 : cNumericFields(7)));
1310 0 : ErrorsFound = true;
1311 : }
1312 :
1313 3 : thisMSHP.IdleVolumeAirRate = Numbers(8);
1314 3 : if (thisMSHP.IdleVolumeAirRate < 0.0 && thisMSHP.IdleVolumeAirRate != DataSizing::AutoSize) {
1315 0 : ShowSevereError(
1316 : state,
1317 0 : format(
1318 0 : "{}, \"{}\", {} cannot be less than zero.", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name, cNumericFields(8)));
1319 0 : ErrorsFound = true;
1320 : }
1321 :
1322 : // AirFlowControl only valid if fan opmode = FanOp::Continuous
1323 3 : if (thisMSHP.IdleVolumeAirRate == 0.0) {
1324 0 : thisMSHP.AirFlowControl = AirflowControl::UseCompressorOnFlow;
1325 : } else {
1326 3 : thisMSHP.AirFlowControl = AirflowControl::UseCompressorOffFlow;
1327 : }
1328 :
1329 : // Initialize last mode of compressor operation
1330 3 : thisMSHP.LastMode = ModeOfOperation::HeatingMode;
1331 :
1332 3 : thisMSHP.NumOfSpeedHeating = Numbers(9);
1333 3 : if (thisMSHP.NumOfSpeedHeating < 2 || thisMSHP.NumOfSpeedHeating > 4) {
1334 0 : if (thisMSHP.HeatCoilType == MultiSpeedHeatingCoil) {
1335 0 : ShowSevereError(state,
1336 0 : format("{}, The maximum {} is 4, and the minimum number is 2",
1337 0 : state.dataHVACMultiSpdHP->CurrentModuleObject,
1338 : cNumericFields(9)));
1339 0 : ShowContinueError(state, format("The input value is {:.0R}", Numbers(9)));
1340 0 : ErrorsFound = true;
1341 : }
1342 : }
1343 3 : thisMSHP.NumOfSpeedCooling = Numbers(10);
1344 3 : if (thisMSHP.NumOfSpeedCooling < 2 || thisMSHP.NumOfSpeedCooling > 4) {
1345 0 : ShowSevereError(state,
1346 0 : format("{}, The maximum {} is 4, and the minimum number is 2",
1347 0 : state.dataHVACMultiSpdHP->CurrentModuleObject,
1348 : cNumericFields(10)));
1349 0 : ShowContinueError(state, format("The input value is {:.0R}", Numbers(10)));
1350 0 : ErrorsFound = true;
1351 : }
1352 :
1353 : // Generate a dynamic array for heating
1354 3 : if (thisMSHP.NumOfSpeedHeating > 0) {
1355 3 : thisMSHP.HeatMassFlowRate.allocate(thisMSHP.NumOfSpeedHeating);
1356 3 : thisMSHP.HeatVolumeFlowRate.allocate(thisMSHP.NumOfSpeedHeating);
1357 3 : thisMSHP.HeatingSpeedRatio.allocate(thisMSHP.NumOfSpeedHeating);
1358 3 : thisMSHP.HeatingSpeedRatio = 1.0;
1359 9 : for (i = 1; i <= thisMSHP.NumOfSpeedHeating; ++i) {
1360 6 : thisMSHP.HeatVolumeFlowRate(i) = Numbers(10 + i);
1361 6 : if (thisMSHP.HeatCoilType == MultiSpeedHeatingCoil) {
1362 6 : if (thisMSHP.HeatVolumeFlowRate(i) <= 0.0 && thisMSHP.HeatVolumeFlowRate(i) != DataSizing::AutoSize) {
1363 0 : ShowSevereError(state,
1364 0 : format("{}, \"{}\", {} must be greater than zero.",
1365 0 : state.dataHVACMultiSpdHP->CurrentModuleObject,
1366 0 : thisMSHP.Name,
1367 : cNumericFields(10 + i)));
1368 0 : ErrorsFound = true;
1369 : }
1370 : }
1371 : }
1372 : // Ensure flow rate at high speed should be greater or equal to the flow rate at low speed
1373 6 : for (i = 2; i <= thisMSHP.NumOfSpeedHeating; ++i) {
1374 3 : if (thisMSHP.HeatVolumeFlowRate(i) == DataSizing::AutoSize) continue;
1375 3 : Found = false;
1376 3 : for (j = i - 1; j >= 1; --j) {
1377 3 : if (thisMSHP.HeatVolumeFlowRate(i) != DataSizing::AutoSize) {
1378 3 : Found = true;
1379 3 : break;
1380 : }
1381 : }
1382 3 : if (Found) {
1383 3 : if (thisMSHP.HeatVolumeFlowRate(i) < thisMSHP.HeatVolumeFlowRate(j)) {
1384 0 : ShowSevereError(
1385 : state,
1386 0 : format("{}, \"{}\", {}", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name, cNumericFields(10 + i)));
1387 0 : ShowContinueError(state, format(" cannot be less than {}", cNumericFields(10 + j)));
1388 0 : ErrorsFound = true;
1389 : }
1390 : }
1391 : }
1392 : }
1393 :
1394 3 : if (state.dataGlobal->DoCoilDirectSolutions) {
1395 0 : int MaxNumber = std::max(thisMSHP.NumOfSpeedCooling, thisMSHP.NumOfSpeedHeating);
1396 0 : thisMSHP.FullOutput.allocate(MaxNumber);
1397 0 : DXCoils::DisableLatentDegradation(state, thisMSHP.DXCoolCoilIndex);
1398 : }
1399 : // Generate a dynamic array for cooling
1400 3 : if (thisMSHP.NumOfSpeedCooling > 0) {
1401 3 : thisMSHP.CoolMassFlowRate.allocate(thisMSHP.NumOfSpeedCooling);
1402 3 : thisMSHP.CoolVolumeFlowRate.allocate(thisMSHP.NumOfSpeedCooling);
1403 3 : thisMSHP.CoolingSpeedRatio.allocate(thisMSHP.NumOfSpeedCooling);
1404 3 : thisMSHP.CoolingSpeedRatio = 1.0;
1405 9 : for (i = 1; i <= thisMSHP.NumOfSpeedCooling; ++i) {
1406 6 : thisMSHP.CoolVolumeFlowRate(i) = Numbers(14 + i);
1407 6 : if (thisMSHP.CoolVolumeFlowRate(i) <= 0.0 && thisMSHP.CoolVolumeFlowRate(i) != DataSizing::AutoSize) {
1408 0 : ShowSevereError(state,
1409 0 : format("{}, \"{}\", {} must be greater than zero.",
1410 0 : state.dataHVACMultiSpdHP->CurrentModuleObject,
1411 0 : thisMSHP.Name,
1412 : cNumericFields(14 + i)));
1413 0 : ErrorsFound = true;
1414 : }
1415 : }
1416 : // Ensure flow rate at high speed should be greater or equal to the flow rate at low speed
1417 6 : for (i = 2; i <= thisMSHP.NumOfSpeedCooling; ++i) {
1418 3 : if (thisMSHP.CoolVolumeFlowRate(i) == DataSizing::AutoSize) continue;
1419 3 : Found = false;
1420 3 : for (j = i - 1; j >= 1; --j) {
1421 3 : if (thisMSHP.CoolVolumeFlowRate(i) != DataSizing::AutoSize) {
1422 3 : Found = true;
1423 3 : break;
1424 : }
1425 : }
1426 3 : if (Found) {
1427 3 : if (thisMSHP.CoolVolumeFlowRate(i) < thisMSHP.CoolVolumeFlowRate(j)) {
1428 0 : ShowSevereError(
1429 : state,
1430 0 : format("{}, \"{}\", {}", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name, cNumericFields(14 + i)));
1431 0 : ShowContinueError(state, format(" cannot be less than {}", cNumericFields(14 + j)));
1432 0 : ErrorsFound = true;
1433 : }
1434 : }
1435 : }
1436 : }
1437 :
1438 : // Check node integrity
1439 3 : if (thisMSHP.fanPlace == HVAC::FanPlace::BlowThru) {
1440 3 : if (thisMSHP.FanInletNode != thisMSHP.AirInletNodeNum) {
1441 0 : ShowSevereError(state, format("For {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name));
1442 0 : ShowContinueError(
1443 0 : state, format("When a blow through fan is specified, the fan inlet node name must be the same as the {}", cAlphaFields(3)));
1444 0 : ShowContinueError(state, format("...Fan inlet node name = {}", state.dataLoopNodes->NodeID(thisMSHP.FanInletNode)));
1445 0 : ShowContinueError(state, format("...{} = {}", cAlphaFields(3), state.dataLoopNodes->NodeID(thisMSHP.AirInletNodeNum)));
1446 0 : ErrorsFound = true;
1447 : }
1448 3 : if (thisMSHP.FanOutletNode != CoolingCoilInletNode) {
1449 0 : ShowSevereError(state, format("For {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name));
1450 0 : ShowContinueError(
1451 : state,
1452 : "When a blow through fan is specified, the fan outlet node name must be the same as the cooling coil inlet node name.");
1453 0 : ShowContinueError(state, format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(thisMSHP.FanOutletNode)));
1454 0 : ShowContinueError(state, format("...Cooling coil inlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilInletNode)));
1455 0 : ErrorsFound = true;
1456 : }
1457 3 : if (CoolingCoilOutletNode != HeatingCoilInletNode) {
1458 0 : ShowSevereError(state, format("For {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name));
1459 0 : ShowContinueError(state, "The cooling coil outlet node name must be the same as the heating coil inlet node name.");
1460 0 : ShowContinueError(state, format("...Cooling coil outlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilOutletNode)));
1461 0 : ShowContinueError(state, format("...Heating coil inlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
1462 0 : ErrorsFound = true;
1463 : }
1464 3 : if (HeatingCoilOutletNode != SuppHeatCoilInletNode) {
1465 0 : ShowSevereError(state, format("For {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name));
1466 0 : ShowContinueError(state,
1467 : "When a blow through fan is specified, the heating coil outlet node name must be the same as the reheat coil "
1468 : "inlet node name.");
1469 0 : ShowContinueError(state, format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
1470 0 : ShowContinueError(state, format("...Reheat coil inlet node name = {}", state.dataLoopNodes->NodeID(SuppHeatCoilInletNode)));
1471 0 : ErrorsFound = true;
1472 : }
1473 3 : if (SuppHeatCoilOutletNode != thisMSHP.AirOutletNodeNum) {
1474 0 : ShowSevereError(state, format("For {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name));
1475 0 : ShowContinueError(state, format("The supplemental heating coil outlet node name must be the same as the {}", cAlphaFields(4)));
1476 0 : ShowContinueError(
1477 0 : state, format("...Supplemental heating coil outlet node name = {}", state.dataLoopNodes->NodeID(SuppHeatCoilOutletNode)));
1478 0 : ShowContinueError(state, format("...{} = {}", cAlphaFields(4), state.dataLoopNodes->NodeID(thisMSHP.AirOutletNodeNum)));
1479 0 : ErrorsFound = true;
1480 : }
1481 : } else {
1482 0 : if (CoolingCoilInletNode != thisMSHP.AirInletNodeNum) {
1483 0 : ShowSevereError(state, format("For {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name));
1484 0 : ShowContinueError(
1485 : state,
1486 0 : format("When a draw through fan is specified, the cooling coil inlet node name must be the same as the {}", cAlphaFields(3)));
1487 0 : ShowContinueError(state, format("...Cooling coil inlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilInletNode)));
1488 0 : ShowContinueError(state, format("...{} = {}", cAlphaFields(3), state.dataLoopNodes->NodeID(thisMSHP.AirInletNodeNum)));
1489 0 : ErrorsFound = true;
1490 : }
1491 0 : if (CoolingCoilOutletNode != HeatingCoilInletNode) {
1492 0 : ShowSevereError(state, format("For {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name));
1493 0 : ShowContinueError(state, "The cooling coil outlet node name must be the same as the heating coil inlet node name.");
1494 0 : ShowContinueError(state, format("...Cooling coil outlet node name = {}", state.dataLoopNodes->NodeID(CoolingCoilOutletNode)));
1495 0 : ShowContinueError(state, format("...Heating coil inlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilInletNode)));
1496 0 : ErrorsFound = true;
1497 : }
1498 0 : if (HeatingCoilOutletNode != thisMSHP.FanInletNode) {
1499 0 : ShowSevereError(state, format("For {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name));
1500 0 : ShowContinueError(
1501 : state,
1502 : "When a draw through fan is specified, the heating coil outlet node name must be the same as the fan inlet node name.");
1503 0 : ShowContinueError(state, format("...Heating coil outlet node name = {}", state.dataLoopNodes->NodeID(HeatingCoilOutletNode)));
1504 0 : ShowContinueError(state, format("...Fan inlet node name = {}", state.dataLoopNodes->NodeID(thisMSHP.FanInletNode)));
1505 0 : ErrorsFound = true;
1506 : }
1507 0 : if (thisMSHP.FanOutletNode != SuppHeatCoilInletNode) {
1508 0 : ShowSevereError(state, format("For {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name));
1509 0 : ShowContinueError(
1510 : state, "When a draw through fan is specified, the fan outlet node name must be the same as the reheat coil inlet node name.");
1511 0 : ShowContinueError(state, format("...Fan outlet node name = {}", state.dataLoopNodes->NodeID(thisMSHP.FanOutletNode)));
1512 0 : ShowContinueError(state, format("...Reheat coil inlet node name = {}", state.dataLoopNodes->NodeID(SuppHeatCoilInletNode)));
1513 0 : ErrorsFound = true;
1514 : }
1515 0 : if (SuppHeatCoilOutletNode != thisMSHP.AirOutletNodeNum) {
1516 0 : ShowSevereError(state, format("For {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name));
1517 0 : ShowContinueError(state, format("The reheat coil outlet node name must be the same as the {}", cAlphaFields(4)));
1518 0 : ShowContinueError(state, format("...Reheat coil outlet node name = {}", state.dataLoopNodes->NodeID(SuppHeatCoilOutletNode)));
1519 0 : ShowContinueError(state, format("...{} = {}", cAlphaFields(4), state.dataLoopNodes->NodeID(thisMSHP.AirOutletNodeNum)));
1520 0 : ErrorsFound = true;
1521 : }
1522 : }
1523 :
1524 : // Ensure the numbers of speeds defined in the parent object are equal to the numbers defined in coil objects
1525 3 : if (thisMSHP.HeatCoilType == MultiSpeedHeatingCoil) {
1526 3 : i = DXCoils::GetDXCoilNumberOfSpeeds(state, Alphas(10), Alphas(11), ErrorsFound);
1527 3 : if (thisMSHP.NumOfSpeedHeating != i) {
1528 0 : ShowSevereError(state, format("For {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name));
1529 0 : ShowContinueError(
1530 0 : state, format("The {} is not equal to the number defined in {} = {}", cNumericFields(9), cAlphaFields(11), Alphas(11)));
1531 0 : ErrorsFound = true;
1532 : }
1533 0 : } else if (thisMSHP.HeatCoilType == HVAC::Coil_HeatingElectric_MultiStage || thisMSHP.HeatCoilType == HVAC::Coil_HeatingGas_MultiStage) {
1534 0 : i = HeatingCoils::GetHeatingCoilNumberOfStages(state, Alphas(10), Alphas(11), ErrorsFound);
1535 0 : if (thisMSHP.NumOfSpeedHeating != i) {
1536 0 : ShowSevereError(state, format("For {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name));
1537 0 : ShowContinueError(
1538 0 : state, format("The {} is not equal to the number defined in {} = {}", cNumericFields(9), cAlphaFields(11), Alphas(11)));
1539 0 : ErrorsFound = true;
1540 : }
1541 : }
1542 3 : i = DXCoils::GetDXCoilNumberOfSpeeds(state, Alphas(12), Alphas(13), ErrorsFound);
1543 3 : if (thisMSHP.NumOfSpeedCooling != i) {
1544 0 : ShowSevereError(state, format("For {} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, thisMSHP.Name));
1545 0 : ShowContinueError(state,
1546 0 : format("The {} is not equal to the number defined in {} = {}", cNumericFields(10), cAlphaFields(13), Alphas(13)));
1547 0 : ErrorsFound = true;
1548 : }
1549 : }
1550 :
1551 2 : if (ErrorsFound) {
1552 0 : ShowFatalError(state,
1553 0 : format("{}Errors found in getting {} input. Preceding condition(s) causes termination.",
1554 : RoutineName,
1555 0 : state.dataHVACMultiSpdHP->CurrentModuleObject));
1556 : }
1557 : // End of multispeed heat pump
1558 :
1559 2 : int MSHPNum = 0;
1560 5 : for (auto &thisMSHeatPump : state.dataHVACMultiSpdHP->MSHeatPump) {
1561 3 : auto &thisMSHPReport = state.dataHVACMultiSpdHP->MSHeatPumpReport(++MSHPNum);
1562 : // Setup Report Variables for MSHP Equipment
1563 6 : SetupOutputVariable(state,
1564 : "Unitary System Ancillary Electricity Rate",
1565 : Constant::Units::W,
1566 3 : thisMSHeatPump.AuxElecPower,
1567 : OutputProcessor::TimeStepType::System,
1568 : OutputProcessor::StoreType::Average,
1569 3 : thisMSHeatPump.Name);
1570 6 : SetupOutputVariable(state,
1571 : "Unitary System Cooling Ancillary Electricity Energy",
1572 : Constant::Units::J,
1573 3 : thisMSHPReport.AuxElecCoolConsumption,
1574 : OutputProcessor::TimeStepType::System,
1575 : OutputProcessor::StoreType::Sum,
1576 3 : thisMSHeatPump.Name,
1577 : Constant::eResource::Electricity,
1578 : OutputProcessor::Group::HVAC,
1579 : OutputProcessor::EndUseCat::Cooling);
1580 6 : SetupOutputVariable(state,
1581 : "Unitary System Heating Ancillary Electricity Energy",
1582 : Constant::Units::J,
1583 3 : thisMSHPReport.AuxElecHeatConsumption,
1584 : OutputProcessor::TimeStepType::System,
1585 : OutputProcessor::StoreType::Sum,
1586 3 : thisMSHeatPump.Name,
1587 : Constant::eResource::Electricity,
1588 : OutputProcessor::Group::HVAC,
1589 : OutputProcessor::EndUseCat::Heating);
1590 6 : SetupOutputVariable(state,
1591 : "Unitary System Fan Part Load Ratio",
1592 : Constant::Units::None,
1593 3 : thisMSHeatPump.FanPartLoadRatio,
1594 : OutputProcessor::TimeStepType::System,
1595 : OutputProcessor::StoreType::Average,
1596 3 : thisMSHeatPump.Name);
1597 6 : SetupOutputVariable(state,
1598 : "Unitary System Compressor Part Load Ratio",
1599 : Constant::Units::None,
1600 3 : thisMSHeatPump.CompPartLoadRatio,
1601 : OutputProcessor::TimeStepType::System,
1602 : OutputProcessor::StoreType::Average,
1603 3 : thisMSHeatPump.Name);
1604 6 : SetupOutputVariable(state,
1605 : "Unitary System Electricity Rate",
1606 : Constant::Units::W,
1607 3 : thisMSHeatPump.ElecPower,
1608 : OutputProcessor::TimeStepType::System,
1609 : OutputProcessor::StoreType::Average,
1610 3 : thisMSHeatPump.Name);
1611 6 : SetupOutputVariable(state,
1612 : "Unitary System Electricity Energy",
1613 : Constant::Units::J,
1614 3 : thisMSHPReport.ElecPowerConsumption,
1615 : OutputProcessor::TimeStepType::System,
1616 : OutputProcessor::StoreType::Sum,
1617 3 : thisMSHeatPump.Name);
1618 6 : SetupOutputVariable(state,
1619 : "Unitary System DX Coil Cycling Ratio",
1620 : Constant::Units::None,
1621 3 : thisMSHPReport.CycRatio,
1622 : OutputProcessor::TimeStepType::System,
1623 : OutputProcessor::StoreType::Average,
1624 3 : thisMSHeatPump.Name);
1625 6 : SetupOutputVariable(state,
1626 : "Unitary System DX Coil Speed Ratio",
1627 : Constant::Units::None,
1628 3 : thisMSHPReport.SpeedRatio,
1629 : OutputProcessor::TimeStepType::System,
1630 : OutputProcessor::StoreType::Average,
1631 3 : thisMSHeatPump.Name);
1632 3 : SetupOutputVariable(state,
1633 : "Unitary System DX Coil Speed Level",
1634 : Constant::Units::None,
1635 3 : thisMSHPReport.SpeedNum,
1636 : OutputProcessor::TimeStepType::System,
1637 : OutputProcessor::StoreType::Average,
1638 3 : thisMSHeatPump.Name);
1639 6 : SetupOutputVariable(state,
1640 : "Unitary System Total Cooling Rate",
1641 : Constant::Units::W,
1642 3 : thisMSHeatPump.TotCoolEnergyRate,
1643 : OutputProcessor::TimeStepType::System,
1644 : OutputProcessor::StoreType::Average,
1645 3 : thisMSHeatPump.Name);
1646 6 : SetupOutputVariable(state,
1647 : "Unitary System Total Heating Rate",
1648 : Constant::Units::W,
1649 3 : thisMSHeatPump.TotHeatEnergyRate,
1650 : OutputProcessor::TimeStepType::System,
1651 : OutputProcessor::StoreType::Average,
1652 3 : thisMSHeatPump.Name);
1653 6 : SetupOutputVariable(state,
1654 : "Unitary System Sensible Cooling Rate",
1655 : Constant::Units::W,
1656 3 : thisMSHeatPump.SensCoolEnergyRate,
1657 : OutputProcessor::TimeStepType::System,
1658 : OutputProcessor::StoreType::Average,
1659 3 : thisMSHeatPump.Name);
1660 6 : SetupOutputVariable(state,
1661 : "Unitary System Sensible Heating Rate",
1662 : Constant::Units::W,
1663 3 : thisMSHeatPump.SensHeatEnergyRate,
1664 : OutputProcessor::TimeStepType::System,
1665 : OutputProcessor::StoreType::Average,
1666 3 : thisMSHeatPump.Name);
1667 6 : SetupOutputVariable(state,
1668 : "Unitary System Latent Cooling Rate",
1669 : Constant::Units::W,
1670 3 : thisMSHeatPump.LatCoolEnergyRate,
1671 : OutputProcessor::TimeStepType::System,
1672 : OutputProcessor::StoreType::Average,
1673 3 : thisMSHeatPump.Name);
1674 6 : SetupOutputVariable(state,
1675 : "Unitary System Latent Heating Rate",
1676 : Constant::Units::W,
1677 3 : thisMSHeatPump.LatHeatEnergyRate,
1678 : OutputProcessor::TimeStepType::System,
1679 : OutputProcessor::StoreType::Average,
1680 3 : thisMSHeatPump.Name);
1681 3 : if (thisMSHeatPump.HeatRecActive) {
1682 0 : SetupOutputVariable(state,
1683 : "Unitary System Heat Recovery Rate",
1684 : Constant::Units::W,
1685 0 : thisMSHeatPump.HeatRecoveryRate,
1686 : OutputProcessor::TimeStepType::System,
1687 : OutputProcessor::StoreType::Average,
1688 0 : thisMSHeatPump.Name);
1689 0 : SetupOutputVariable(state,
1690 : "Unitary System Heat Recovery Inlet Temperature",
1691 : Constant::Units::C,
1692 0 : thisMSHeatPump.HeatRecoveryInletTemp,
1693 : OutputProcessor::TimeStepType::System,
1694 : OutputProcessor::StoreType::Average,
1695 0 : thisMSHeatPump.Name);
1696 0 : SetupOutputVariable(state,
1697 : "Unitary System Heat Recovery Outlet Temperature",
1698 : Constant::Units::C,
1699 0 : thisMSHeatPump.HeatRecoveryOutletTemp,
1700 : OutputProcessor::TimeStepType::System,
1701 : OutputProcessor::StoreType::Average,
1702 0 : thisMSHeatPump.Name);
1703 0 : SetupOutputVariable(state,
1704 : "Unitary System Heat Recovery Fluid Mass Flow Rate",
1705 : Constant::Units::kg_s,
1706 0 : thisMSHeatPump.HeatRecoveryMassFlowRate,
1707 : OutputProcessor::TimeStepType::System,
1708 : OutputProcessor::StoreType::Average,
1709 0 : thisMSHeatPump.Name);
1710 0 : SetupOutputVariable(state,
1711 : "Unitary System Heat Recovery Energy",
1712 : Constant::Units::J,
1713 0 : thisMSHPReport.HeatRecoveryEnergy,
1714 : OutputProcessor::TimeStepType::System,
1715 : OutputProcessor::StoreType::Sum,
1716 0 : thisMSHeatPump.Name);
1717 : }
1718 : }
1719 2 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
1720 0 : for (auto &thisCoil : state.dataHVACMultiSpdHP->MSHeatPump) {
1721 0 : SetupEMSActuator(state,
1722 : "Coil Speed Control",
1723 : thisCoil.Name,
1724 : "Unitary System DX Coil Speed Value",
1725 : "[]",
1726 0 : thisCoil.EMSOverrideCoilSpeedNumOn,
1727 0 : thisCoil.EMSOverrideCoilSpeedNumValue);
1728 : }
1729 : }
1730 2 : }
1731 :
1732 : //******************************************************************************
1733 :
1734 2 : void InitMSHeatPump(EnergyPlusData &state,
1735 : int const MSHeatPumpNum, // Engine driven heat pump number
1736 : bool const FirstHVACIteration, // TRUE if first HVAC iteration
1737 : int const AirLoopNum, // air loop index
1738 : Real64 &QZnReq, // Heating/Cooling load for all served zones
1739 : Real64 &OnOffAirFlowRatio // Ratio of compressor ON airflow to average airflow over timestep
1740 : )
1741 : {
1742 :
1743 : // SUBROUTINE INFORMATION:
1744 : // AUTHOR: Lixing Gu, FSEC
1745 : // DATE WRITTEN: July 2007
1746 : // MODIFIED Bereket Nigusse, June 2010 - added a procedure to calculate supply air flow fraction
1747 : // through controlled zone
1748 :
1749 : // PURPOSE OF THIS SUBROUTINE:
1750 : // This subroutine is for initializations of the multispeed heat pump (MSHP) components.
1751 :
1752 : // METHODOLOGY EMPLOYED:
1753 : // Uses the status flags to trigger initializations. The MSHP system is simulated with no load (coils off) to
1754 : // determine the outlet temperature. A setpoint temperature is calculated on FirstHVACIteration = TRUE.
1755 : // Once the setpoint is calculated, the inlet mass flow rate on FirstHVACIteration = FALSE is used to
1756 : // determine the bypass fraction. The simulation converges quickly on mass flow rate. If the zone
1757 : // temperatures float in the deadband, additional iterations are required to converge on mass flow rate.
1758 :
1759 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1760 : static constexpr std::string_view RoutineName("InitMSHeatPump");
1761 : Real64 RhoAir; // Air density at InNode
1762 :
1763 : Real64 QSensUnitOut; // Output of MSHP system with coils off
1764 : Real64 PartLoadFrac; // Part-load ratio
1765 : int ZoneNum;
1766 : int i; // Index to speed
1767 : Real64 DeltaMassRate; // Difference of mass flow rate between inlet node and system outlet node
1768 :
1769 2 : int NumAirLoopZones(0); // number of zone inlet nodes in an air loop
1770 2 : Real64 SumOfMassFlowRateMax(0.0); // the sum of mass flow rates at inlet to zones in an airloop
1771 2 : Real64 CntrlZoneTerminalUnitMassFlowRateMax(0.0); // Maximum mass flow rate through controlled zone terminal unit
1772 : Real64 rho; // local fluid density
1773 : Real64 MdotHR; // local temporary for heat recovery fluid mass flow rate (kg/s)
1774 : Real64 ZoneLoadToCoolSPSequenced;
1775 : Real64 ZoneLoadToHeatSPSequenced;
1776 :
1777 2 : bool ErrorsFound(false); // flag returned from mining call
1778 2 : Real64 mdot(0.0); // local temporary for mass flow rate (kg/s)
1779 2 : Real64 SteamDensity(0.0); // density of steam at 100C, used for steam heating coils
1780 2 : Real64 CoilMaxVolFlowRate(0.0); // coil fluid maximum volume flow rate
1781 2 : Real64 QActual(0.0); // coil actual capacity
1782 :
1783 2 : auto &MSHeatPump = state.dataHVACMultiSpdHP->MSHeatPump;
1784 :
1785 2 : int InNode = MSHeatPump(MSHeatPumpNum).AirInletNodeNum;
1786 2 : int OutNode = MSHeatPump(MSHeatPumpNum).AirOutletNodeNum;
1787 2 : int NumOfSpeedCooling = MSHeatPump(MSHeatPumpNum).NumOfSpeedCooling;
1788 2 : int NumOfSpeedHeating = MSHeatPump(MSHeatPumpNum).NumOfSpeedHeating;
1789 :
1790 2 : ++state.dataHVACMultiSpdHP->AirLoopPass;
1791 2 : if (state.dataHVACMultiSpdHP->AirLoopPass > 2) state.dataHVACMultiSpdHP->AirLoopPass = 1;
1792 :
1793 2 : if (MSHeatPump(MSHeatPumpNum).MyPlantScantFlag && allocated(state.dataPlnt->PlantLoop)) {
1794 : bool errFlag;
1795 0 : if (MSHeatPump(MSHeatPumpNum).HeatRecActive) {
1796 0 : errFlag = false;
1797 0 : PlantUtilities::ScanPlantLoopsForObject(state,
1798 0 : MSHeatPump(MSHeatPumpNum).Name,
1799 : DataPlant::PlantEquipmentType::MultiSpeedHeatPumpRecovery,
1800 0 : MSHeatPump(MSHeatPumpNum).HRPlantLoc,
1801 : errFlag,
1802 : _,
1803 : _,
1804 : _,
1805 : _,
1806 : _);
1807 0 : if (errFlag) {
1808 0 : ShowFatalError(state, "InitMSHeatPump: Program terminated for previous conditions.");
1809 : }
1810 :
1811 0 : MSHeatPump(MSHeatPumpNum).MyPlantScantFlag = false;
1812 : } else {
1813 0 : MSHeatPump(MSHeatPumpNum).MyPlantScantFlag = false;
1814 : }
1815 0 : if (MSHeatPump(MSHeatPumpNum).HeatCoilType == HVAC::Coil_HeatingWater) {
1816 0 : errFlag = false;
1817 0 : PlantUtilities::ScanPlantLoopsForObject(state,
1818 0 : MSHeatPump(MSHeatPumpNum).HeatCoilName,
1819 : DataPlant::PlantEquipmentType::CoilWaterSimpleHeating,
1820 0 : MSHeatPump(MSHeatPumpNum).plantLoc,
1821 : errFlag,
1822 : _,
1823 : _,
1824 : _,
1825 : _,
1826 : _);
1827 0 : if (errFlag) {
1828 0 : ShowFatalError(state, "InitMSHeatPump: Program terminated for previous conditions.");
1829 : }
1830 0 : MSHeatPump(MSHeatPumpNum).MaxCoilFluidFlow =
1831 0 : WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", MSHeatPump(MSHeatPumpNum).HeatCoilName, ErrorsFound);
1832 :
1833 0 : if (MSHeatPump(MSHeatPumpNum).MaxCoilFluidFlow > 0.0) {
1834 0 : rho = state.dataPlnt->PlantLoop(MSHeatPump(MSHeatPumpNum).plantLoc.loopNum)
1835 0 : .glycol->getDensity(state, Constant::HWInitConvTemp, RoutineName);
1836 0 : MSHeatPump(MSHeatPumpNum).MaxCoilFluidFlow =
1837 0 : WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", MSHeatPump(MSHeatPumpNum).HeatCoilName, ErrorsFound) * rho;
1838 : }
1839 : // fill outlet node for coil
1840 0 : MSHeatPump(MSHeatPumpNum).CoilOutletNode =
1841 0 : DataPlant::CompData::getPlantComponent(state, MSHeatPump(MSHeatPumpNum).plantLoc).NodeNumOut;
1842 0 : MSHeatPump(MSHeatPumpNum).MyPlantScantFlag = false;
1843 :
1844 0 : } else if (MSHeatPump(MSHeatPumpNum).HeatCoilType == HVAC::Coil_HeatingSteam) {
1845 0 : errFlag = false;
1846 0 : PlantUtilities::ScanPlantLoopsForObject(state,
1847 0 : MSHeatPump(MSHeatPumpNum).HeatCoilName,
1848 : DataPlant::PlantEquipmentType::CoilSteamAirHeating,
1849 0 : MSHeatPump(MSHeatPumpNum).plantLoc,
1850 : errFlag,
1851 : _,
1852 : _,
1853 : _,
1854 : _,
1855 : _);
1856 0 : if (errFlag) {
1857 0 : ShowFatalError(state, "InitMSHeatPump: Program terminated for previous conditions.");
1858 : }
1859 0 : MSHeatPump(MSHeatPumpNum).MaxCoilFluidFlow =
1860 0 : SteamCoils::GetCoilMaxSteamFlowRate(state, MSHeatPump(MSHeatPumpNum).HeatCoilNum, ErrorsFound);
1861 0 : if (MSHeatPump(MSHeatPumpNum).MaxCoilFluidFlow > 0.0) {
1862 0 : SteamDensity = Fluid::GetSteam(state)->getSatDensity(state, state.dataHVACMultiSpdHP->TempSteamIn, 1.0, RoutineName);
1863 0 : MSHeatPump(MSHeatPumpNum).MaxCoilFluidFlow *= SteamDensity;
1864 : }
1865 :
1866 : // fill outlet node for coil
1867 0 : MSHeatPump(MSHeatPumpNum).CoilOutletNode =
1868 0 : DataPlant::CompData::getPlantComponent(state, MSHeatPump(MSHeatPumpNum).plantLoc).NodeNumOut;
1869 0 : MSHeatPump(MSHeatPumpNum).MyPlantScantFlag = false;
1870 : }
1871 0 : if (MSHeatPump(MSHeatPumpNum).SuppHeatCoilType == HVAC::Coil_HeatingWater) {
1872 0 : errFlag = false;
1873 0 : PlantUtilities::ScanPlantLoopsForObject(state,
1874 0 : MSHeatPump(MSHeatPumpNum).SuppHeatCoilName,
1875 : DataPlant::PlantEquipmentType::CoilWaterSimpleHeating,
1876 0 : MSHeatPump(MSHeatPumpNum).SuppPlantLoc,
1877 : errFlag,
1878 : _,
1879 : _,
1880 : _,
1881 : _,
1882 : _);
1883 0 : if (errFlag) {
1884 0 : ShowFatalError(state, "InitMSHeatPump: Program terminated for previous conditions.");
1885 : }
1886 0 : MSHeatPump(MSHeatPumpNum).MaxSuppCoilFluidFlow =
1887 0 : WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", MSHeatPump(MSHeatPumpNum).SuppHeatCoilName, ErrorsFound);
1888 :
1889 0 : if (MSHeatPump(MSHeatPumpNum).MaxSuppCoilFluidFlow > 0.0) {
1890 0 : rho = state.dataPlnt->PlantLoop(MSHeatPump(MSHeatPumpNum).SuppPlantLoc.loopNum)
1891 0 : .glycol->getDensity(state, Constant::HWInitConvTemp, RoutineName);
1892 0 : MSHeatPump(MSHeatPumpNum).MaxSuppCoilFluidFlow =
1893 0 : WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", MSHeatPump(MSHeatPumpNum).SuppHeatCoilName, ErrorsFound) *
1894 : rho;
1895 : }
1896 : // fill outlet node for coil
1897 0 : MSHeatPump(MSHeatPumpNum).SuppCoilOutletNode =
1898 0 : DataPlant::CompData::getPlantComponent(state, MSHeatPump(MSHeatPumpNum).SuppPlantLoc).NodeNumOut;
1899 0 : MSHeatPump(MSHeatPumpNum).MyPlantScantFlag = false;
1900 :
1901 0 : } else if (MSHeatPump(MSHeatPumpNum).SuppHeatCoilType == HVAC::Coil_HeatingSteam) {
1902 0 : errFlag = false;
1903 0 : PlantUtilities::ScanPlantLoopsForObject(state,
1904 0 : MSHeatPump(MSHeatPumpNum).SuppHeatCoilName,
1905 : DataPlant::PlantEquipmentType::CoilSteamAirHeating,
1906 0 : MSHeatPump(MSHeatPumpNum).SuppPlantLoc,
1907 : errFlag,
1908 : _,
1909 : _,
1910 : _,
1911 : _,
1912 : _);
1913 0 : if (errFlag) {
1914 0 : ShowFatalError(state, "InitMSHeatPump: Program terminated for previous conditions.");
1915 : }
1916 0 : MSHeatPump(MSHeatPumpNum).MaxSuppCoilFluidFlow =
1917 0 : SteamCoils::GetCoilMaxSteamFlowRate(state, MSHeatPump(MSHeatPumpNum).SuppHeatCoilNum, ErrorsFound);
1918 0 : if (MSHeatPump(MSHeatPumpNum).MaxSuppCoilFluidFlow > 0.0) {
1919 0 : SteamDensity = Fluid::GetSteam(state)->getSatDensity(state, state.dataHVACMultiSpdHP->TempSteamIn, 1.0, RoutineName);
1920 0 : MSHeatPump(MSHeatPumpNum).MaxSuppCoilFluidFlow *= SteamDensity;
1921 : }
1922 :
1923 : // fill outlet node for coil
1924 0 : MSHeatPump(MSHeatPumpNum).SuppCoilOutletNode =
1925 0 : DataPlant::CompData::getPlantComponent(state, MSHeatPump(MSHeatPumpNum).SuppPlantLoc).NodeNumOut;
1926 0 : MSHeatPump(MSHeatPumpNum).MyPlantScantFlag = false;
1927 : }
1928 2 : } else if (MSHeatPump(MSHeatPumpNum).MyPlantScantFlag && !state.dataGlobal->AnyPlantInModel) {
1929 2 : MSHeatPump(MSHeatPumpNum).MyPlantScantFlag = false;
1930 : }
1931 :
1932 2 : if (!state.dataGlobal->SysSizingCalc && MSHeatPump(MSHeatPumpNum).MySizeFlag) {
1933 0 : MSHeatPump(MSHeatPumpNum).FanVolFlow = state.dataFans->fans(MSHeatPump(MSHeatPumpNum).FanNum)->maxAirFlowRate;
1934 0 : SizeMSHeatPump(state, MSHeatPumpNum);
1935 0 : MSHeatPump(MSHeatPumpNum).FlowFraction = 1.0;
1936 0 : MSHeatPump(MSHeatPumpNum).MySizeFlag = false;
1937 : // Pass the fan cycling schedule index up to the air loop. Set the air loop unitary system flag.
1938 0 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).cycFanSched = MSHeatPump(MSHeatPumpNum).fanOpModeSched;
1939 0 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).UnitarySys = true;
1940 0 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).UnitarySysSimulating =
1941 : false; // affects child coil sizing by allowing coil to size itself instead of parent telling coil what size to use
1942 0 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).fanOp = MSHeatPump(MSHeatPumpNum).fanOp;
1943 : }
1944 :
1945 2 : if (allocated(state.dataZoneEquip->ZoneEquipConfig) && MSHeatPump(MSHeatPumpNum).MyCheckFlag) {
1946 2 : int zoneNum = MSHeatPump(MSHeatPumpNum).ControlZoneNum;
1947 2 : int zoneInlet = MSHeatPump(MSHeatPumpNum).ZoneInletNode;
1948 : // setup furnace zone equipment sequence information based on finding matching air terminal
1949 2 : if (state.dataZoneEquip->ZoneEquipConfig(zoneNum).EquipListIndex > 0) {
1950 2 : int coolingPriority = 0;
1951 2 : int heatingPriority = 0;
1952 2 : state.dataZoneEquip->ZoneEquipList(state.dataZoneEquip->ZoneEquipConfig(zoneNum).EquipListIndex)
1953 2 : .getPrioritiesForInletNode(state, zoneInlet, coolingPriority, heatingPriority);
1954 2 : MSHeatPump(MSHeatPumpNum).ZoneSequenceCoolingNum = coolingPriority;
1955 2 : MSHeatPump(MSHeatPumpNum).ZoneSequenceHeatingNum = heatingPriority;
1956 : }
1957 2 : MSHeatPump(MSHeatPumpNum).MyCheckFlag = false;
1958 2 : if (MSHeatPump(MSHeatPumpNum).ZoneSequenceCoolingNum == 0 || MSHeatPump(MSHeatPumpNum).ZoneSequenceHeatingNum == 0) {
1959 0 : ShowSevereError(state,
1960 0 : format("AirLoopHVAC:UnitaryHeatPump:AirToAir:MultiSpeed, \"{}\": Airloop air terminal in the zone equipment list for "
1961 : "zone = {} not found or is not allowed Zone Equipment Cooling or Heating Sequence = 0.",
1962 0 : MSHeatPump(MSHeatPumpNum).Name,
1963 0 : MSHeatPump(MSHeatPumpNum).ControlZoneName));
1964 0 : ShowFatalError(state,
1965 : "Subroutine InitMSHeatPump: Errors found in getting AirLoopHVAC:UnitaryHeatPump:AirToAir:MultiSpeed input. Preceding "
1966 : "condition(s) causes termination.");
1967 : }
1968 : }
1969 :
1970 : // Find the number of zones (zone Inlet Nodes) attached to an air loop from the air loop number
1971 2 : NumAirLoopZones =
1972 2 : state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesCooled + state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesHeated;
1973 2 : if (allocated(state.dataAirLoop->AirToZoneNodeInfo) && MSHeatPump(MSHeatPumpNum).MyFlowFracFlag) {
1974 1 : state.dataHVACMultiSpdHP->FlowFracFlagReady = true;
1975 2 : for (int ZoneInSysIndex = 1; ZoneInSysIndex <= NumAirLoopZones; ++ZoneInSysIndex) {
1976 : // zone inlet nodes for cooling
1977 1 : if (state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesCooled > 0) {
1978 1 : if (state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolInletNodes(ZoneInSysIndex) == -999) {
1979 : // the data structure for the zones inlet nodes has not been filled
1980 0 : state.dataHVACMultiSpdHP->FlowFracFlagReady = false;
1981 : }
1982 : }
1983 : // zone inlet nodes for heating
1984 1 : if (state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).NumZonesHeated > 0) {
1985 0 : if (state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitHeatInletNodes(ZoneInSysIndex) == -999) {
1986 : // the data structure for the zones inlet nodes has not been filled
1987 0 : state.dataHVACMultiSpdHP->FlowFracFlagReady = false;
1988 : }
1989 : }
1990 : }
1991 : }
1992 2 : if (allocated(state.dataAirLoop->AirToZoneNodeInfo) && state.dataHVACMultiSpdHP->FlowFracFlagReady) {
1993 1 : SumOfMassFlowRateMax = 0.0; // initialize the sum of the maximum flows
1994 2 : for (int ZoneInSysIndex = 1; ZoneInSysIndex <= NumAirLoopZones; ++ZoneInSysIndex) {
1995 1 : int ZoneInletNodeNum = state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).TermUnitCoolInletNodes(ZoneInSysIndex);
1996 1 : SumOfMassFlowRateMax += state.dataLoopNodes->Node(ZoneInletNodeNum).MassFlowRateMax;
1997 1 : if (state.dataAirLoop->AirToZoneNodeInfo(AirLoopNum).CoolCtrlZoneNums(ZoneInSysIndex) == MSHeatPump(MSHeatPumpNum).ControlZoneNum) {
1998 1 : CntrlZoneTerminalUnitMassFlowRateMax = state.dataLoopNodes->Node(ZoneInletNodeNum).MassFlowRateMax;
1999 : }
2000 : }
2001 1 : if (SumOfMassFlowRateMax != 0.0 && MSHeatPump(MSHeatPumpNum).MyFlowFracFlag) {
2002 1 : if (CntrlZoneTerminalUnitMassFlowRateMax >= HVAC::SmallAirVolFlow) {
2003 0 : MSHeatPump(MSHeatPumpNum).FlowFraction = CntrlZoneTerminalUnitMassFlowRateMax / SumOfMassFlowRateMax;
2004 : } else {
2005 1 : ShowSevereError(state, format("{} = {}", state.dataHVACMultiSpdHP->CurrentModuleObject, MSHeatPump(MSHeatPumpNum).Name));
2006 3 : ShowContinueError(state, " The Fraction of Supply Air Flow That Goes Through the Controlling Zone is set to 1.");
2007 : }
2008 2 : BaseSizer::reportSizerOutput(state,
2009 1 : state.dataHVACMultiSpdHP->CurrentModuleObject,
2010 1 : MSHeatPump(MSHeatPumpNum).Name,
2011 : "Fraction of Supply Air Flow That Goes Through the Controlling Zone",
2012 1 : MSHeatPump(MSHeatPumpNum).FlowFraction);
2013 1 : MSHeatPump(MSHeatPumpNum).MyFlowFracFlag = false;
2014 : }
2015 : }
2016 :
2017 : // Do the Begin Environment initializations
2018 2 : if (state.dataGlobal->BeginEnvrnFlag && MSHeatPump(MSHeatPumpNum).MyEnvrnFlag) {
2019 1 : RhoAir = state.dataEnvrn->StdRhoAir;
2020 : // set the mass flow rates from the input volume flow rates
2021 3 : for (i = 1; i <= NumOfSpeedCooling; ++i) {
2022 2 : MSHeatPump(MSHeatPumpNum).CoolMassFlowRate(i) = RhoAir * MSHeatPump(MSHeatPumpNum).CoolVolumeFlowRate(i);
2023 : }
2024 3 : for (i = 1; i <= NumOfSpeedHeating; ++i) {
2025 2 : MSHeatPump(MSHeatPumpNum).HeatMassFlowRate(i) = RhoAir * MSHeatPump(MSHeatPumpNum).HeatVolumeFlowRate(i);
2026 : }
2027 1 : MSHeatPump(MSHeatPumpNum).IdleMassFlowRate = RhoAir * MSHeatPump(MSHeatPumpNum).IdleVolumeAirRate;
2028 : // set the node max and min mass flow rates
2029 1 : state.dataLoopNodes->Node(InNode).MassFlowRateMax =
2030 1 : max(MSHeatPump(MSHeatPumpNum).CoolMassFlowRate(NumOfSpeedCooling), MSHeatPump(MSHeatPumpNum).HeatMassFlowRate(NumOfSpeedHeating));
2031 1 : state.dataLoopNodes->Node(InNode).MassFlowRateMaxAvail =
2032 1 : max(MSHeatPump(MSHeatPumpNum).CoolMassFlowRate(NumOfSpeedCooling), MSHeatPump(MSHeatPumpNum).HeatMassFlowRate(NumOfSpeedHeating));
2033 1 : state.dataLoopNodes->Node(InNode).MassFlowRateMin = 0.0;
2034 1 : state.dataLoopNodes->Node(InNode).MassFlowRateMinAvail = 0.0;
2035 1 : state.dataLoopNodes->Node(OutNode) = state.dataLoopNodes->Node(InNode);
2036 1 : MSHeatPump(MSHeatPumpNum).LoadLoss = 0.0;
2037 :
2038 1 : if ((MSHeatPump(MSHeatPumpNum).HeatRecActive) && (!MSHeatPump(MSHeatPumpNum).MyPlantScantFlag)) {
2039 :
2040 0 : rho = state.dataPlnt->PlantLoop(MSHeatPump(MSHeatPumpNum).HRPlantLoc.loopNum)
2041 0 : .glycol->getDensity(state, Constant::HWInitConvTemp, RoutineName);
2042 :
2043 0 : MSHeatPump(MSHeatPumpNum).DesignHeatRecMassFlowRate = MSHeatPump(MSHeatPumpNum).DesignHeatRecFlowRate * rho;
2044 :
2045 0 : PlantUtilities::InitComponentNodes(state,
2046 : 0.0,
2047 0 : MSHeatPump(MSHeatPumpNum).DesignHeatRecMassFlowRate,
2048 0 : MSHeatPump(MSHeatPumpNum).HeatRecInletNodeNum,
2049 0 : MSHeatPump(MSHeatPumpNum).HeatRecOutletNodeNum);
2050 : }
2051 1 : if (MSHeatPump(MSHeatPumpNum).CoilControlNode > 0) {
2052 0 : if (MSHeatPump(MSHeatPumpNum).MaxCoilFluidFlow == DataSizing::AutoSize) {
2053 0 : if (MSHeatPump(MSHeatPumpNum).HeatCoilType == HVAC::Coil_HeatingWater) {
2054 0 : WaterCoils::SimulateWaterCoilComponents(
2055 0 : state, MSHeatPump(MSHeatPumpNum).HeatCoilName, FirstHVACIteration, MSHeatPump(MSHeatPumpNum).HeatCoilNum);
2056 :
2057 : CoilMaxVolFlowRate =
2058 0 : WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", MSHeatPump(MSHeatPumpNum).HeatCoilName, ErrorsFound);
2059 0 : if (CoilMaxVolFlowRate != DataSizing::AutoSize) {
2060 0 : rho = state.dataPlnt->PlantLoop(MSHeatPump(MSHeatPumpNum).plantLoc.loopNum)
2061 0 : .glycol->getDensity(state, Constant::HWInitConvTemp, RoutineName);
2062 0 : MSHeatPump(MSHeatPumpNum).MaxCoilFluidFlow = CoilMaxVolFlowRate * rho;
2063 : }
2064 0 : PlantUtilities::InitComponentNodes(state,
2065 : 0.0,
2066 0 : MSHeatPump(MSHeatPumpNum).MaxCoilFluidFlow,
2067 0 : MSHeatPump(MSHeatPumpNum).CoilControlNode,
2068 0 : MSHeatPump(MSHeatPumpNum).CoilOutletNode);
2069 : }
2070 0 : if (MSHeatPump(MSHeatPumpNum).HeatCoilType == HVAC::Coil_HeatingSteam) {
2071 :
2072 0 : SteamCoils::SimulateSteamCoilComponents(state,
2073 0 : MSHeatPump(MSHeatPumpNum).HeatCoilName,
2074 : FirstHVACIteration,
2075 0 : MSHeatPump(MSHeatPumpNum).HeatCoilNum,
2076 0 : 1.0,
2077 : QActual); // QCoilReq, simulate any load > 0 to get max capacity of steam coil
2078 0 : CoilMaxVolFlowRate = SteamCoils::GetCoilMaxSteamFlowRate(state, MSHeatPump(MSHeatPumpNum).HeatCoilNum, ErrorsFound);
2079 :
2080 0 : if (CoilMaxVolFlowRate != DataSizing::AutoSize) {
2081 0 : SteamDensity = Fluid::GetSteam(state)->getSatDensity(state, state.dataHVACMultiSpdHP->TempSteamIn, 1.0, RoutineName);
2082 0 : MSHeatPump(MSHeatPumpNum).MaxCoilFluidFlow = CoilMaxVolFlowRate * SteamDensity;
2083 : }
2084 0 : PlantUtilities::InitComponentNodes(state,
2085 : 0.0,
2086 0 : MSHeatPump(MSHeatPumpNum).MaxCoilFluidFlow,
2087 0 : MSHeatPump(MSHeatPumpNum).CoilControlNode,
2088 0 : MSHeatPump(MSHeatPumpNum).CoilOutletNode);
2089 : }
2090 : }
2091 : }
2092 1 : if (MSHeatPump(MSHeatPumpNum).SuppCoilControlNode > 0) {
2093 0 : if (MSHeatPump(MSHeatPumpNum).MaxSuppCoilFluidFlow == DataSizing::AutoSize) {
2094 0 : if (MSHeatPump(MSHeatPumpNum).SuppHeatCoilType == HVAC::Coil_HeatingWater) {
2095 0 : WaterCoils::SimulateWaterCoilComponents(
2096 0 : state, MSHeatPump(MSHeatPumpNum).SuppHeatCoilName, FirstHVACIteration, MSHeatPump(MSHeatPumpNum).SuppHeatCoilNum);
2097 :
2098 : CoilMaxVolFlowRate =
2099 0 : WaterCoils::GetCoilMaxWaterFlowRate(state, "Coil:Heating:Water", MSHeatPump(MSHeatPumpNum).SuppHeatCoilName, ErrorsFound);
2100 0 : if (CoilMaxVolFlowRate != DataSizing::AutoSize) {
2101 0 : rho = state.dataPlnt->PlantLoop(MSHeatPump(MSHeatPumpNum).SuppPlantLoc.loopNum)
2102 0 : .glycol->getDensity(state, Constant::HWInitConvTemp, RoutineName);
2103 0 : MSHeatPump(MSHeatPumpNum).MaxSuppCoilFluidFlow = CoilMaxVolFlowRate * rho;
2104 : }
2105 0 : PlantUtilities::InitComponentNodes(state,
2106 : 0.0,
2107 0 : MSHeatPump(MSHeatPumpNum).MaxSuppCoilFluidFlow,
2108 0 : MSHeatPump(MSHeatPumpNum).SuppCoilControlNode,
2109 0 : MSHeatPump(MSHeatPumpNum).SuppCoilOutletNode);
2110 : }
2111 0 : if (MSHeatPump(MSHeatPumpNum).SuppHeatCoilType == HVAC::Coil_HeatingSteam) {
2112 :
2113 0 : SteamCoils::SimulateSteamCoilComponents(state,
2114 0 : MSHeatPump(MSHeatPumpNum).SuppHeatCoilName,
2115 : FirstHVACIteration,
2116 0 : MSHeatPump(MSHeatPumpNum).SuppHeatCoilNum,
2117 0 : 1.0,
2118 : QActual); // QCoilReq, simulate any load > 0 to get max capacity of steam coil
2119 0 : CoilMaxVolFlowRate = SteamCoils::GetCoilMaxSteamFlowRate(state, MSHeatPump(MSHeatPumpNum).SuppHeatCoilNum, ErrorsFound);
2120 :
2121 0 : if (CoilMaxVolFlowRate != DataSizing::AutoSize) {
2122 0 : SteamDensity = Fluid::GetSteam(state)->getSatDensity(state, state.dataHVACMultiSpdHP->TempSteamIn, 1.0, RoutineName);
2123 0 : MSHeatPump(MSHeatPumpNum).MaxSuppCoilFluidFlow = CoilMaxVolFlowRate * SteamDensity;
2124 : }
2125 0 : PlantUtilities::InitComponentNodes(state,
2126 : 0.0,
2127 0 : MSHeatPump(MSHeatPumpNum).MaxSuppCoilFluidFlow,
2128 0 : MSHeatPump(MSHeatPumpNum).SuppCoilControlNode,
2129 0 : MSHeatPump(MSHeatPumpNum).SuppCoilOutletNode);
2130 : }
2131 : }
2132 : }
2133 1 : MSHeatPump(MSHeatPumpNum).MyEnvrnFlag = false;
2134 : } // end one time inits
2135 :
2136 2 : if (!state.dataGlobal->BeginEnvrnFlag) {
2137 1 : MSHeatPump(MSHeatPumpNum).MyEnvrnFlag = true;
2138 : }
2139 :
2140 : // IF MSHP system was not autosized and the fan is autosized, check that fan volumetric flow rate is greater than MSHP flow rates
2141 2 : if (!state.dataGlobal->DoingSizing && MSHeatPump(MSHeatPumpNum).CheckFanFlow) {
2142 2 : state.dataHVACMultiSpdHP->CurrentModuleObject = "AirLoopHVAC:UnitaryHeatPump:AirToAir:MultiSpeed";
2143 2 : MSHeatPump(MSHeatPumpNum).FanVolFlow = state.dataFans->fans(MSHeatPump(MSHeatPumpNum).FanNum)->maxAirFlowRate;
2144 2 : if (MSHeatPump(MSHeatPumpNum).FanVolFlow != DataSizing::AutoSize) {
2145 : // Check fan versus system supply air flow rates
2146 2 : if (MSHeatPump(MSHeatPumpNum).FanVolFlow < MSHeatPump(MSHeatPumpNum).CoolVolumeFlowRate(NumOfSpeedCooling)) {
2147 0 : ShowWarningError(state,
2148 0 : format("{} - air flow rate = {:.7T} in fan object {} is less than the MSHP system air flow rate when cooling is "
2149 : "required ({:.7T}).",
2150 0 : state.dataHVACMultiSpdHP->CurrentModuleObject,
2151 0 : MSHeatPump(MSHeatPumpNum).FanVolFlow,
2152 0 : MSHeatPump(MSHeatPumpNum).FanName,
2153 0 : MSHeatPump(MSHeatPumpNum).CoolVolumeFlowRate(NumOfSpeedCooling)));
2154 0 : ShowContinueError(
2155 : state, " The MSHP system flow rate when cooling is required is reset to the fan flow rate and the simulation continues.");
2156 0 : ShowContinueError(state,
2157 0 : format(" Occurs in {} = {}", state.dataHVACMultiSpdHP->CurrentModuleObject, MSHeatPump(MSHeatPumpNum).Name));
2158 0 : MSHeatPump(MSHeatPumpNum).CoolVolumeFlowRate(NumOfSpeedCooling) = MSHeatPump(MSHeatPumpNum).FanVolFlow;
2159 : // Check flow rates in other speeds and ensure flow rates are not above the max flow rate
2160 0 : for (i = NumOfSpeedCooling - 1; i >= 1; --i) {
2161 0 : if (MSHeatPump(MSHeatPumpNum).CoolVolumeFlowRate(i) > MSHeatPump(MSHeatPumpNum).CoolVolumeFlowRate(i + 1)) {
2162 0 : ShowContinueError(state,
2163 0 : format(" The MSHP system flow rate when cooling is required is reset to the flow rate at higher speed "
2164 : "and the simulation continues at Speed{}.",
2165 : i));
2166 0 : ShowContinueError(
2167 0 : state, format(" Occurs in {} = {}", state.dataHVACMultiSpdHP->CurrentModuleObject, MSHeatPump(MSHeatPumpNum).Name));
2168 0 : MSHeatPump(MSHeatPumpNum).CoolVolumeFlowRate(i) = MSHeatPump(MSHeatPumpNum).CoolVolumeFlowRate(i + 1);
2169 : }
2170 : }
2171 : }
2172 2 : if (MSHeatPump(MSHeatPumpNum).FanVolFlow < MSHeatPump(MSHeatPumpNum).HeatVolumeFlowRate(NumOfSpeedHeating)) {
2173 0 : ShowWarningError(state,
2174 0 : format("{} - air flow rate = {:.7T} in fan object {} is less than the MSHP system air flow rate when heating is "
2175 : "required ({:.7T}).",
2176 0 : state.dataHVACMultiSpdHP->CurrentModuleObject,
2177 0 : MSHeatPump(MSHeatPumpNum).FanVolFlow,
2178 0 : MSHeatPump(MSHeatPumpNum).FanName,
2179 0 : MSHeatPump(MSHeatPumpNum).HeatVolumeFlowRate(NumOfSpeedHeating)));
2180 0 : ShowContinueError(
2181 : state, " The MSHP system flow rate when heating is required is reset to the fan flow rate and the simulation continues.");
2182 0 : ShowContinueError(state,
2183 0 : format(" Occurs in {} = {}", state.dataHVACMultiSpdHP->CurrentModuleObject, MSHeatPump(MSHeatPumpNum).Name));
2184 0 : MSHeatPump(MSHeatPumpNum).HeatVolumeFlowRate(NumOfSpeedHeating) = MSHeatPump(MSHeatPumpNum).FanVolFlow;
2185 0 : for (i = NumOfSpeedHeating - 1; i >= 1; --i) {
2186 0 : if (MSHeatPump(MSHeatPumpNum).HeatVolumeFlowRate(i) > MSHeatPump(MSHeatPumpNum).HeatVolumeFlowRate(i + 1)) {
2187 0 : ShowContinueError(state,
2188 0 : format(" The MSHP system flow rate when heating is required is reset to the flow rate at higher speed "
2189 : "and the simulation continues at Speed{}.",
2190 : i));
2191 0 : ShowContinueError(
2192 : state,
2193 0 : format(" Occurs in {} system = {}", state.dataHVACMultiSpdHP->CurrentModuleObject, MSHeatPump(MSHeatPumpNum).Name));
2194 0 : MSHeatPump(MSHeatPumpNum).HeatVolumeFlowRate(i) = MSHeatPump(MSHeatPumpNum).HeatVolumeFlowRate(i + 1);
2195 : }
2196 : }
2197 : }
2198 2 : if (MSHeatPump(MSHeatPumpNum).FanVolFlow < MSHeatPump(MSHeatPumpNum).IdleVolumeAirRate &&
2199 0 : MSHeatPump(MSHeatPumpNum).IdleVolumeAirRate != 0.0) {
2200 0 : ShowWarningError(state,
2201 0 : format("{} - air flow rate = {:.7T} in fan object {} is less than the MSHP system air flow rate when no heating "
2202 : "or cooling is needed ({:.7T}).",
2203 0 : state.dataHVACMultiSpdHP->CurrentModuleObject,
2204 0 : MSHeatPump(MSHeatPumpNum).FanVolFlow,
2205 0 : MSHeatPump(MSHeatPumpNum).FanName,
2206 0 : MSHeatPump(MSHeatPumpNum).IdleVolumeAirRate));
2207 0 : ShowContinueError(state,
2208 : " The MSHP system flow rate when no heating or cooling is needed is reset to the fan flow rate and the "
2209 : "simulation continues.");
2210 0 : ShowContinueError(state,
2211 0 : format(" Occurs in {} = {}", state.dataHVACMultiSpdHP->CurrentModuleObject, MSHeatPump(MSHeatPumpNum).Name));
2212 0 : MSHeatPump(MSHeatPumpNum).IdleVolumeAirRate = MSHeatPump(MSHeatPumpNum).FanVolFlow;
2213 : }
2214 2 : RhoAir = state.dataEnvrn->StdRhoAir;
2215 : // set the mass flow rates from the reset volume flow rates
2216 6 : for (i = 1; i <= NumOfSpeedCooling; ++i) {
2217 4 : MSHeatPump(MSHeatPumpNum).CoolMassFlowRate(i) = RhoAir * MSHeatPump(MSHeatPumpNum).CoolVolumeFlowRate(i);
2218 4 : if (MSHeatPump(MSHeatPumpNum).FanVolFlow > 0.0) {
2219 4 : MSHeatPump(MSHeatPumpNum).CoolingSpeedRatio(i) =
2220 4 : MSHeatPump(MSHeatPumpNum).CoolVolumeFlowRate(i) / MSHeatPump(MSHeatPumpNum).FanVolFlow;
2221 : }
2222 : }
2223 6 : for (i = 1; i <= NumOfSpeedHeating; ++i) {
2224 4 : MSHeatPump(MSHeatPumpNum).HeatMassFlowRate(i) = RhoAir * MSHeatPump(MSHeatPumpNum).HeatVolumeFlowRate(i);
2225 4 : if (MSHeatPump(MSHeatPumpNum).FanVolFlow > 0.0) {
2226 4 : MSHeatPump(MSHeatPumpNum).HeatingSpeedRatio(i) =
2227 4 : MSHeatPump(MSHeatPumpNum).HeatVolumeFlowRate(i) / MSHeatPump(MSHeatPumpNum).FanVolFlow;
2228 : }
2229 : }
2230 2 : MSHeatPump(MSHeatPumpNum).IdleMassFlowRate = RhoAir * MSHeatPump(MSHeatPumpNum).IdleVolumeAirRate;
2231 2 : if (MSHeatPump(MSHeatPumpNum).FanVolFlow > 0.0) {
2232 2 : MSHeatPump(MSHeatPumpNum).IdleSpeedRatio = MSHeatPump(MSHeatPumpNum).IdleVolumeAirRate / MSHeatPump(MSHeatPumpNum).FanVolFlow;
2233 : }
2234 : // set the node max and min mass flow rates based on reset volume flow rates
2235 2 : state.dataLoopNodes->Node(InNode).MassFlowRateMax =
2236 2 : max(MSHeatPump(MSHeatPumpNum).CoolMassFlowRate(NumOfSpeedCooling), MSHeatPump(MSHeatPumpNum).HeatMassFlowRate(NumOfSpeedHeating));
2237 2 : state.dataLoopNodes->Node(InNode).MassFlowRateMaxAvail =
2238 2 : max(MSHeatPump(MSHeatPumpNum).CoolMassFlowRate(NumOfSpeedCooling), MSHeatPump(MSHeatPumpNum).HeatMassFlowRate(NumOfSpeedHeating));
2239 2 : state.dataLoopNodes->Node(InNode).MassFlowRateMin = 0.0;
2240 2 : state.dataLoopNodes->Node(InNode).MassFlowRateMinAvail = 0.0;
2241 2 : state.dataLoopNodes->Node(OutNode) = state.dataLoopNodes->Node(InNode);
2242 2 : MSHeatPump(MSHeatPumpNum).CheckFanFlow = false;
2243 : }
2244 : }
2245 :
2246 2 : if (MSHeatPump(MSHeatPumpNum).fanOpModeSched != nullptr) {
2247 2 : MSHeatPump(MSHeatPumpNum).fanOp =
2248 2 : (MSHeatPump(MSHeatPumpNum).fanOpModeSched->getCurrentVal() == 0.0) ? HVAC::FanOp::Cycling : HVAC::FanOp::Continuous;
2249 : }
2250 :
2251 : // Calculate air distribution losses
2252 2 : if (!FirstHVACIteration && state.dataHVACMultiSpdHP->AirLoopPass == 1) {
2253 0 : int ZoneInNode = MSHeatPump(MSHeatPumpNum).ZoneInletNode;
2254 0 : DeltaMassRate = state.dataLoopNodes->Node(OutNode).MassFlowRate -
2255 0 : state.dataLoopNodes->Node(ZoneInNode).MassFlowRate / MSHeatPump(MSHeatPumpNum).FlowFraction;
2256 0 : if (DeltaMassRate < 0.0) DeltaMassRate = 0.0;
2257 0 : Real64 MassFlowRate(0.0); // parent mass flow rate
2258 0 : Real64 LatentOutput(0.0); // latent output rate
2259 0 : Real64 TotalOutput(0.0); // total output rate
2260 0 : Real64 SensibleOutputDelta(0.0); // delta sensible output rate
2261 0 : Real64 LatentOutputDelta(0.0); // delta latent output rate
2262 0 : Real64 TotalOutputDelta(0.0); // delta total output rate
2263 0 : MassFlowRate = state.dataLoopNodes->Node(ZoneInNode).MassFlowRate / MSHeatPump(MSHeatPumpNum).FlowFraction;
2264 0 : Real64 MinHumRat = state.dataLoopNodes->Node(ZoneInNode).HumRat;
2265 0 : if (state.dataLoopNodes->Node(OutNode).Temp < state.dataLoopNodes->Node(MSHeatPump(MSHeatPumpNum).NodeNumOfControlledZone).Temp)
2266 0 : MinHumRat = state.dataLoopNodes->Node(OutNode).HumRat;
2267 0 : CalcZoneSensibleLatentOutput(MassFlowRate,
2268 0 : state.dataLoopNodes->Node(OutNode).Temp,
2269 : MinHumRat,
2270 0 : state.dataLoopNodes->Node(ZoneInNode).Temp,
2271 : MinHumRat,
2272 0 : MSHeatPump(MSHeatPumpNum).LoadLoss,
2273 : LatentOutput,
2274 : TotalOutput);
2275 0 : CalcZoneSensibleLatentOutput(DeltaMassRate,
2276 0 : state.dataLoopNodes->Node(OutNode).Temp,
2277 : MinHumRat,
2278 0 : state.dataLoopNodes->Node(MSHeatPump(MSHeatPumpNum).NodeNumOfControlledZone).Temp,
2279 : MinHumRat,
2280 : SensibleOutputDelta,
2281 : LatentOutputDelta,
2282 : TotalOutputDelta);
2283 0 : MSHeatPump(MSHeatPumpNum).LoadLoss = MSHeatPump(MSHeatPumpNum).LoadLoss + SensibleOutputDelta;
2284 0 : if (std::abs(MSHeatPump(MSHeatPumpNum).LoadLoss) < 1.0e-6) MSHeatPump(MSHeatPumpNum).LoadLoss = 0.0;
2285 : }
2286 :
2287 : // Returns load only for zones requesting cooling (heating). If in deadband, Qzoneload = 0.
2288 2 : ZoneNum = MSHeatPump(MSHeatPumpNum).ControlZoneNum;
2289 2 : if ((MSHeatPump(MSHeatPumpNum).ZoneSequenceCoolingNum > 0) && (MSHeatPump(MSHeatPumpNum).ZoneSequenceHeatingNum > 0)) {
2290 2 : ZoneLoadToCoolSPSequenced = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(MSHeatPump(MSHeatPumpNum).ControlZoneNum)
2291 2 : .SequencedOutputRequiredToCoolingSP(MSHeatPump(MSHeatPumpNum).ZoneSequenceCoolingNum);
2292 2 : ZoneLoadToHeatSPSequenced = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(MSHeatPump(MSHeatPumpNum).ControlZoneNum)
2293 2 : .SequencedOutputRequiredToHeatingSP(MSHeatPump(MSHeatPumpNum).ZoneSequenceHeatingNum);
2294 2 : if (ZoneLoadToHeatSPSequenced > HVAC::SmallLoad && ZoneLoadToCoolSPSequenced > HVAC::SmallLoad) {
2295 1 : QZnReq = ZoneLoadToHeatSPSequenced;
2296 1 : } else if (ZoneLoadToHeatSPSequenced < (-1.0 * HVAC::SmallLoad) && ZoneLoadToCoolSPSequenced < (-1.0 * HVAC::SmallLoad)) {
2297 1 : QZnReq = ZoneLoadToCoolSPSequenced;
2298 0 : } else if (ZoneLoadToHeatSPSequenced <= (-1.0 * HVAC::SmallLoad) && ZoneLoadToCoolSPSequenced >= HVAC::SmallLoad) {
2299 0 : QZnReq = 0.0;
2300 : } else {
2301 0 : QZnReq = 0.0; // Autodesk:Init Case added to prevent use of uninitialized value (occurred in MultiSpeedACFurnace example)
2302 : }
2303 2 : QZnReq /= MSHeatPump(MSHeatPumpNum).FlowFraction;
2304 : } else {
2305 0 : QZnReq = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputRequired / MSHeatPump(MSHeatPumpNum).FlowFraction;
2306 : }
2307 2 : if (state.dataZoneEnergyDemand->CurDeadBandOrSetback(ZoneNum)) QZnReq = 0.0;
2308 :
2309 2 : if (QZnReq > HVAC::SmallLoad) {
2310 1 : MSHeatPump(MSHeatPumpNum).HeatCoolMode = ModeOfOperation::HeatingMode;
2311 1 : } else if (QZnReq < (-1.0 * HVAC::SmallLoad)) {
2312 1 : MSHeatPump(MSHeatPumpNum).HeatCoolMode = ModeOfOperation::CoolingMode;
2313 : } else {
2314 0 : MSHeatPump(MSHeatPumpNum).HeatCoolMode = ModeOfOperation::Invalid;
2315 : }
2316 :
2317 : // Determine the staged status
2318 2 : if (allocated(state.dataZoneCtrls->StageZoneLogic)) {
2319 0 : if (state.dataZoneCtrls->StageZoneLogic(ZoneNum)) {
2320 0 : MSHeatPump(MSHeatPumpNum).Staged = true;
2321 0 : MSHeatPump(MSHeatPumpNum).StageNum = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).StageNum;
2322 : } else {
2323 0 : if (MSHeatPump(MSHeatPumpNum).MyStagedFlag) {
2324 0 : ShowWarningError(state,
2325 : "ZoneControl:Thermostat:StagedDualSetpoint is found, but is not applied to this "
2326 : "AirLoopHVAC:UnitaryHeatPump:AirToAir:MultiSpeed object = ");
2327 0 : ShowContinueError(state, format("{}. Please make correction. Simulation continues...", MSHeatPump(MSHeatPumpNum).Name));
2328 0 : MSHeatPump(MSHeatPumpNum).MyStagedFlag = false;
2329 : }
2330 : }
2331 : }
2332 : // Set the inlet node mass flow rate
2333 2 : if (MSHeatPump(MSHeatPumpNum).fanOp == HVAC::FanOp::Continuous) {
2334 : // constant fan mode
2335 2 : if (QZnReq > HVAC::SmallLoad && !state.dataZoneEnergyDemand->CurDeadBandOrSetback(ZoneNum)) {
2336 1 : state.dataHVACMultiSpdHP->CompOnMassFlow = MSHeatPump(MSHeatPumpNum).HeatMassFlowRate(1);
2337 1 : state.dataHVACMultiSpdHP->CompOnFlowRatio = MSHeatPump(MSHeatPumpNum).HeatingSpeedRatio(1);
2338 1 : MSHeatPump(MSHeatPumpNum).LastMode = ModeOfOperation::HeatingMode;
2339 1 : } else if (QZnReq < (-1.0 * HVAC::SmallLoad) && !state.dataZoneEnergyDemand->CurDeadBandOrSetback(ZoneNum)) {
2340 1 : state.dataHVACMultiSpdHP->CompOnMassFlow = MSHeatPump(MSHeatPumpNum).CoolMassFlowRate(1);
2341 1 : state.dataHVACMultiSpdHP->CompOnFlowRatio = MSHeatPump(MSHeatPumpNum).CoolingSpeedRatio(1);
2342 1 : MSHeatPump(MSHeatPumpNum).LastMode = ModeOfOperation::CoolingMode;
2343 : } else {
2344 0 : state.dataHVACMultiSpdHP->CompOnMassFlow = MSHeatPump(MSHeatPumpNum).IdleMassFlowRate;
2345 0 : state.dataHVACMultiSpdHP->CompOnFlowRatio = MSHeatPump(MSHeatPumpNum).IdleSpeedRatio;
2346 : }
2347 2 : state.dataHVACMultiSpdHP->CompOffMassFlow = MSHeatPump(MSHeatPumpNum).IdleMassFlowRate;
2348 2 : state.dataHVACMultiSpdHP->CompOffFlowRatio = MSHeatPump(MSHeatPumpNum).IdleSpeedRatio;
2349 : } else {
2350 : // cycling fan mode
2351 0 : if (QZnReq > HVAC::SmallLoad && !state.dataZoneEnergyDemand->CurDeadBandOrSetback(ZoneNum)) {
2352 0 : state.dataHVACMultiSpdHP->CompOnMassFlow = MSHeatPump(MSHeatPumpNum).HeatMassFlowRate(1);
2353 0 : state.dataHVACMultiSpdHP->CompOnFlowRatio = MSHeatPump(MSHeatPumpNum).HeatingSpeedRatio(1);
2354 0 : } else if (QZnReq < (-1.0 * HVAC::SmallLoad) && !state.dataZoneEnergyDemand->CurDeadBandOrSetback(ZoneNum)) {
2355 0 : state.dataHVACMultiSpdHP->CompOnMassFlow = MSHeatPump(MSHeatPumpNum).CoolMassFlowRate(1);
2356 0 : state.dataHVACMultiSpdHP->CompOnFlowRatio = MSHeatPump(MSHeatPumpNum).CoolingSpeedRatio(1);
2357 : } else {
2358 0 : state.dataHVACMultiSpdHP->CompOnMassFlow = 0.0;
2359 0 : state.dataHVACMultiSpdHP->CompOnFlowRatio = 0.0;
2360 : }
2361 0 : state.dataHVACMultiSpdHP->CompOffMassFlow = 0.0;
2362 0 : state.dataHVACMultiSpdHP->CompOffFlowRatio = 0.0;
2363 : }
2364 :
2365 : // Set the inlet node mass flow rate
2366 2 : if (MSHeatPump(MSHeatPumpNum).availSched->getCurrentVal() > 0.0 && state.dataHVACMultiSpdHP->CompOnMassFlow != 0.0) {
2367 2 : OnOffAirFlowRatio = 1.0;
2368 2 : if (FirstHVACIteration) {
2369 2 : state.dataLoopNodes->Node(MSHeatPump(MSHeatPumpNum).AirInletNodeNum).MassFlowRate = state.dataHVACMultiSpdHP->CompOnMassFlow;
2370 2 : PartLoadFrac = 0.0;
2371 : } else {
2372 0 : if (MSHeatPump(MSHeatPumpNum).HeatCoolMode != ModeOfOperation::Invalid) {
2373 0 : PartLoadFrac = 1.0;
2374 : } else {
2375 0 : PartLoadFrac = 0.0;
2376 : }
2377 : }
2378 : } else {
2379 0 : PartLoadFrac = 0.0;
2380 0 : state.dataLoopNodes->Node(InNode).MassFlowRate = 0.0;
2381 0 : state.dataLoopNodes->Node(OutNode).MassFlowRate = 0.0;
2382 0 : state.dataLoopNodes->Node(OutNode).MassFlowRateMaxAvail = 0.0;
2383 0 : OnOffAirFlowRatio = 1.0;
2384 : }
2385 :
2386 : // Check availability of DX coils
2387 2 : if (MSHeatPump(MSHeatPumpNum).availSched->getCurrentVal() > 0.0) {
2388 2 : if (MSHeatPump(MSHeatPumpNum).HeatCoolMode == ModeOfOperation::CoolingMode) {
2389 2 : auto *coilAvailSched = DXCoils::GetDXCoilAvailSched( // TODO: Why isn't this stored on the struct?
2390 : state,
2391 : "Coil:Cooling:DX:MultiSpeed",
2392 1 : MSHeatPump(MSHeatPumpNum).DXCoolCoilName,
2393 : ErrorsFound,
2394 1 : MSHeatPump(MSHeatPumpNum).DXCoolCoilIndex);
2395 1 : if (ErrorsFound) {
2396 0 : ShowFatalError(state, "InitMSHeatPump, The previous error causes termination.");
2397 : }
2398 1 : if (coilAvailSched->getCurrentVal() == 0.0) {
2399 0 : if (MSHeatPump(MSHeatPumpNum).CoolCountAvail == 0) {
2400 0 : ++MSHeatPump(MSHeatPumpNum).CoolCountAvail;
2401 0 : ShowWarningError(
2402 : state,
2403 0 : format("{} is ready to perform cooling, but its DX cooling coil = {} is not available at Available Schedule = {}.",
2404 0 : MSHeatPump(MSHeatPumpNum).Name,
2405 0 : MSHeatPump(MSHeatPumpNum).DXCoolCoilName,
2406 0 : coilAvailSched->Name));
2407 0 : ShowContinueErrorTimeStamp(state, format("Availability schedule returned={:.1R}", coilAvailSched->getCurrentVal()));
2408 : } else {
2409 0 : ++MSHeatPump(MSHeatPumpNum).CoolCountAvail;
2410 0 : ShowRecurringWarningErrorAtEnd(state,
2411 0 : MSHeatPump(MSHeatPumpNum).Name + ": Cooling coil is still not available ...",
2412 0 : MSHeatPump(MSHeatPumpNum).CoolIndexAvail,
2413 0 : coilAvailSched->getCurrentVal(),
2414 0 : coilAvailSched->getCurrentVal());
2415 : }
2416 : }
2417 : }
2418 3 : if (MSHeatPump(MSHeatPumpNum).HeatCoolMode == ModeOfOperation::HeatingMode &&
2419 1 : MSHeatPump(MSHeatPumpNum).HeatCoilType == MultiSpeedHeatingCoil) {
2420 2 : auto *coilAvailSched = DXCoils::GetDXCoilAvailSched(state,
2421 : "Coil:Heating:DX:MultiSpeed",
2422 1 : MSHeatPump(MSHeatPumpNum).DXHeatCoilName,
2423 : ErrorsFound,
2424 1 : MSHeatPump(MSHeatPumpNum).DXHeatCoilIndex);
2425 1 : if (ErrorsFound) {
2426 0 : ShowFatalError(state, "InitMSHeatPump, The previous error causes termination.");
2427 : }
2428 1 : if (coilAvailSched->getCurrentVal() == 0.0) {
2429 0 : if (MSHeatPump(MSHeatPumpNum).HeatCountAvail == 0) {
2430 0 : ++MSHeatPump(MSHeatPumpNum).HeatCountAvail;
2431 0 : ShowWarningError(
2432 : state,
2433 0 : format("{} is ready to perform heating, but its DX heating coil = {} is not available at Available Schedule = {}.",
2434 0 : MSHeatPump(MSHeatPumpNum).Name,
2435 0 : MSHeatPump(MSHeatPumpNum).DXCoolCoilName,
2436 0 : coilAvailSched->Name));
2437 0 : ShowContinueErrorTimeStamp(state, format("Availability schedule returned={:.1R}", coilAvailSched->getCurrentVal()));
2438 : } else {
2439 0 : ++MSHeatPump(MSHeatPumpNum).HeatCountAvail;
2440 0 : ShowRecurringWarningErrorAtEnd(state,
2441 0 : MSHeatPump(MSHeatPumpNum).Name + ": Heating coil is still not available ...",
2442 0 : MSHeatPump(MSHeatPumpNum).HeatIndexAvail,
2443 0 : coilAvailSched->getCurrentVal(),
2444 0 : coilAvailSched->getCurrentVal());
2445 : }
2446 : }
2447 : }
2448 : }
2449 :
2450 2 : state.dataHVACMultiSpdHP->MSHeatPumpReport(MSHeatPumpNum).CycRatio = 0.0;
2451 2 : state.dataHVACMultiSpdHP->MSHeatPumpReport(MSHeatPumpNum).SpeedRatio = 0.0;
2452 2 : state.dataHVACMultiSpdHP->MSHeatPumpReport(MSHeatPumpNum).SpeedNum = 0;
2453 :
2454 2 : CalcMSHeatPump(state,
2455 : MSHeatPumpNum,
2456 : FirstHVACIteration,
2457 : HVAC::CompressorOp::On,
2458 : 1,
2459 : 0.0,
2460 : PartLoadFrac,
2461 : QSensUnitOut,
2462 : QZnReq,
2463 : OnOffAirFlowRatio,
2464 2 : state.dataHVACMultiSpdHP->SupHeaterLoad);
2465 :
2466 2 : auto &e = MSHeatPump(MSHeatPumpNum);
2467 : {
2468 2 : e.TotHeatEnergyRate = 0.0;
2469 2 : e.SensHeatEnergyRate = 0.0;
2470 2 : e.LatHeatEnergyRate = 0.0;
2471 2 : e.TotCoolEnergyRate = 0.0;
2472 2 : e.SensCoolEnergyRate = 0.0;
2473 2 : e.LatCoolEnergyRate = 0.0;
2474 : }
2475 : // If unit is scheduled OFF, setpoint is equal to inlet node temperature.
2476 : //!!LKL Discrepancy with < 0
2477 2 : if (MSHeatPump(MSHeatPumpNum).availSched->getCurrentVal() == 0.0) {
2478 0 : state.dataLoopNodes->Node(OutNode).Temp = state.dataLoopNodes->Node(InNode).Temp;
2479 0 : return;
2480 : }
2481 :
2482 4 : if ((MSHeatPump(MSHeatPumpNum).HeatCoolMode == ModeOfOperation::Invalid && MSHeatPump(MSHeatPumpNum).fanOp == HVAC::FanOp::Cycling) ||
2483 2 : state.dataHVACMultiSpdHP->CompOnMassFlow == 0.0) {
2484 0 : QZnReq = 0.0;
2485 0 : PartLoadFrac = 0.0;
2486 0 : state.dataLoopNodes->Node(InNode).MassFlowRate = 0.0;
2487 0 : state.dataLoopNodes->Node(OutNode).MassFlowRateMaxAvail = 0.0;
2488 : }
2489 2 : MSHeatPump(MSHeatPumpNum).LoadMet = 0.0;
2490 2 : SetAverageAirFlow(state, MSHeatPumpNum, PartLoadFrac, OnOffAirFlowRatio);
2491 :
2492 : // Init maximum available Heat Recovery flow rate
2493 2 : if ((MSHeatPump(MSHeatPumpNum).HeatRecActive) && (!MSHeatPump(MSHeatPumpNum).MyPlantScantFlag)) {
2494 0 : if (PartLoadFrac > 0.0) {
2495 0 : if (FirstHVACIteration) {
2496 0 : MdotHR = MSHeatPump(MSHeatPumpNum).DesignHeatRecMassFlowRate;
2497 : } else {
2498 0 : if (MSHeatPump(MSHeatPumpNum).HeatRecoveryMassFlowRate > 0.0) {
2499 0 : MdotHR = MSHeatPump(MSHeatPumpNum).HeatRecoveryMassFlowRate;
2500 : } else {
2501 0 : MdotHR = MSHeatPump(MSHeatPumpNum).DesignHeatRecMassFlowRate;
2502 : }
2503 : }
2504 : } else {
2505 0 : MdotHR = 0.0;
2506 : }
2507 :
2508 0 : PlantUtilities::SetComponentFlowRate(state,
2509 : MdotHR,
2510 0 : MSHeatPump(MSHeatPumpNum).HeatRecInletNodeNum,
2511 0 : MSHeatPump(MSHeatPumpNum).HeatRecOutletNodeNum,
2512 0 : MSHeatPump(MSHeatPumpNum).HRPlantLoc);
2513 : }
2514 :
2515 : // get operating capacity of water and steam coil
2516 2 : if (FirstHVACIteration) {
2517 2 : if (MSHeatPump(MSHeatPumpNum).HeatCoilType == HVAC::Coil_HeatingWater) {
2518 : // set air-side and steam-side mass flow rates
2519 0 : state.dataLoopNodes->Node(MSHeatPump(MSHeatPumpNum).CoilAirInletNode).MassFlowRate = state.dataHVACMultiSpdHP->CompOnMassFlow;
2520 0 : mdot = MSHeatPump(MSHeatPumpNum).MaxCoilFluidFlow;
2521 0 : PlantUtilities::SetComponentFlowRate(state,
2522 : mdot,
2523 0 : MSHeatPump(MSHeatPumpNum).CoilControlNode,
2524 0 : MSHeatPump(MSHeatPumpNum).CoilOutletNode,
2525 0 : MSHeatPump(MSHeatPumpNum).plantLoc);
2526 : // simulate water coil to find operating capacity
2527 0 : WaterCoils::SimulateWaterCoilComponents(
2528 0 : state, MSHeatPump(MSHeatPumpNum).HeatCoilName, FirstHVACIteration, MSHeatPump(MSHeatPumpNum).HeatCoilNum, QActual);
2529 : } // from IF(MSHeatPump(MSHeatPumpNum)%HeatCoilType == Coil_HeatingWater) THEN
2530 :
2531 2 : if (MSHeatPump(MSHeatPumpNum).HeatCoilType == HVAC::Coil_HeatingSteam) {
2532 :
2533 : // set air-side and steam-side mass flow rates
2534 0 : state.dataLoopNodes->Node(MSHeatPump(MSHeatPumpNum).CoilAirInletNode).MassFlowRate = state.dataHVACMultiSpdHP->CompOnMassFlow;
2535 0 : mdot = MSHeatPump(MSHeatPumpNum).MaxCoilFluidFlow;
2536 0 : PlantUtilities::SetComponentFlowRate(state,
2537 : mdot,
2538 0 : MSHeatPump(MSHeatPumpNum).CoilControlNode,
2539 0 : MSHeatPump(MSHeatPumpNum).CoilOutletNode,
2540 0 : MSHeatPump(MSHeatPumpNum).plantLoc);
2541 :
2542 : // simulate steam coil to find operating capacity
2543 0 : SteamCoils::SimulateSteamCoilComponents(state,
2544 0 : MSHeatPump(MSHeatPumpNum).HeatCoilName,
2545 : FirstHVACIteration,
2546 0 : MSHeatPump(MSHeatPumpNum).HeatCoilNum,
2547 0 : 1.0,
2548 : QActual); // QCoilReq, simulate any load > 0 to get max capacity of steam coil
2549 :
2550 : } // from IF(MSHeatPump(MSHeatPumpNum)%HeatCoilType == Coil_HeatingSteam) THEN
2551 2 : if (MSHeatPump(MSHeatPumpNum).SuppHeatCoilType == HVAC::Coil_HeatingWater) {
2552 : // set air-side and steam-side mass flow rates
2553 0 : state.dataLoopNodes->Node(MSHeatPump(MSHeatPumpNum).SuppCoilAirInletNode).MassFlowRate = state.dataHVACMultiSpdHP->CompOnMassFlow;
2554 0 : mdot = MSHeatPump(MSHeatPumpNum).MaxSuppCoilFluidFlow;
2555 0 : PlantUtilities::SetComponentFlowRate(state,
2556 : mdot,
2557 0 : MSHeatPump(MSHeatPumpNum).SuppCoilControlNode,
2558 0 : MSHeatPump(MSHeatPumpNum).SuppCoilOutletNode,
2559 0 : MSHeatPump(MSHeatPumpNum).SuppPlantLoc);
2560 : // simulate water coil to find operating capacity
2561 0 : WaterCoils::SimulateWaterCoilComponents(
2562 0 : state, MSHeatPump(MSHeatPumpNum).SuppHeatCoilName, FirstHVACIteration, MSHeatPump(MSHeatPumpNum).SuppHeatCoilNum, QActual);
2563 0 : MSHeatPump(MSHeatPumpNum).DesignSuppHeatingCapacity = QActual;
2564 :
2565 : } // from IF(MSHeatPump(MSHeatPumpNum)%SuppHeatCoilType == Coil_HeatingWater) THEN
2566 :
2567 2 : if (MSHeatPump(MSHeatPumpNum).SuppHeatCoilType == HVAC::Coil_HeatingSteam) {
2568 :
2569 : // set air-side and steam-side mass flow rates
2570 0 : state.dataLoopNodes->Node(MSHeatPump(MSHeatPumpNum).SuppCoilAirInletNode).MassFlowRate = state.dataHVACMultiSpdHP->CompOnMassFlow;
2571 0 : mdot = MSHeatPump(MSHeatPumpNum).MaxSuppCoilFluidFlow;
2572 0 : PlantUtilities::SetComponentFlowRate(state,
2573 : mdot,
2574 0 : MSHeatPump(MSHeatPumpNum).SuppCoilControlNode,
2575 0 : MSHeatPump(MSHeatPumpNum).SuppCoilOutletNode,
2576 0 : MSHeatPump(MSHeatPumpNum).SuppPlantLoc);
2577 :
2578 : // simulate steam coil to find operating capacity
2579 0 : SteamCoils::SimulateSteamCoilComponents(state,
2580 0 : MSHeatPump(MSHeatPumpNum).SuppHeatCoilName,
2581 : FirstHVACIteration,
2582 0 : MSHeatPump(MSHeatPumpNum).SuppHeatCoilNum,
2583 0 : 1.0,
2584 : QActual); // QCoilReq, simulate any load > 0 to get max capacity of steam coil
2585 0 : MSHeatPump(MSHeatPumpNum).DesignSuppHeatingCapacity =
2586 0 : SteamCoils::GetCoilCapacity(state, "Coil:Heating:Steam", MSHeatPump(MSHeatPumpNum).SuppHeatCoilName, ErrorsFound);
2587 :
2588 : } // from IF(MSHeatPump(MSHeatPumpNum)%SuppHeatCoilType == Coil_HeatingSteam) THEN
2589 : } // from IF( FirstHVACIteration ) THEN
2590 : }
2591 :
2592 : //******************************************************************************
2593 :
2594 0 : void SizeMSHeatPump(EnergyPlusData &state, int const MSHeatPumpNum) // Engine driven heat pump number
2595 : {
2596 : // SUBROUTINE INFORMATION:
2597 : // AUTHOR: Lixing Gu, FSEC
2598 : // DATE WRITTEN: June 2007
2599 :
2600 : // PURPOSE OF THIS SUBROUTINE:
2601 : // This subroutine is for sizing multispeed heat pump airflow rates and flow fraction.
2602 :
2603 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2604 : int NumOfSpeedCooling; // Number of speeds for cooling
2605 : int NumOfSpeedHeating; // Number of speeds for heating
2606 : int i; // Index to speed
2607 :
2608 0 : auto &MSHeatPump = state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum);
2609 0 : if (state.dataSize->CurSysNum > 0 && state.dataSize->CurOASysNum == 0) {
2610 0 : state.dataAirSystemsData->PrimaryAirSystems(state.dataSize->CurSysNum).supFanNum = MSHeatPump.FanNum;
2611 0 : state.dataAirSystemsData->PrimaryAirSystems(state.dataSize->CurSysNum).supFanType = MSHeatPump.fanType;
2612 0 : state.dataAirSystemsData->PrimaryAirSystems(state.dataSize->CurSysNum).supFanPlace = MSHeatPump.fanPlace;
2613 : }
2614 :
2615 0 : NumOfSpeedCooling = MSHeatPump.NumOfSpeedCooling;
2616 0 : NumOfSpeedHeating = MSHeatPump.NumOfSpeedHeating;
2617 :
2618 0 : for (i = NumOfSpeedCooling; i >= 1; --i) {
2619 :
2620 0 : if (MSHeatPump.CoolVolumeFlowRate(i) == DataSizing::AutoSize) {
2621 0 : if (state.dataSize->CurSysNum > 0) {
2622 0 : if (i == NumOfSpeedCooling) {
2623 0 : CheckSysSizing(state, state.dataHVACMultiSpdHP->CurrentModuleObject, MSHeatPump.Name);
2624 0 : MSHeatPump.CoolVolumeFlowRate(i) = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesMainVolFlow;
2625 0 : if (MSHeatPump.FanVolFlow < MSHeatPump.CoolVolumeFlowRate(i) && MSHeatPump.FanVolFlow != DataSizing::AutoSize) {
2626 0 : MSHeatPump.CoolVolumeFlowRate(i) = MSHeatPump.FanVolFlow;
2627 0 : ShowWarningError(state, format("{} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, MSHeatPump.Name));
2628 0 : ShowContinueError(state,
2629 : "The supply air flow rate at high speed is less than the autosized value for the supply air flow rate "
2630 : "in cooling mode. Consider autosizing the fan for this simulation.");
2631 0 : ShowContinueError(
2632 : state,
2633 : "The air flow rate at high speed in cooling mode is reset to the supply air flow rate and the simulation continues.");
2634 : }
2635 : } else {
2636 0 : MSHeatPump.CoolVolumeFlowRate(i) = MSHeatPump.CoolVolumeFlowRate(NumOfSpeedCooling) * i / NumOfSpeedCooling;
2637 : }
2638 0 : if (MSHeatPump.CoolVolumeFlowRate(i) < HVAC::SmallAirVolFlow) {
2639 0 : MSHeatPump.CoolVolumeFlowRate = 0.0;
2640 : }
2641 : // Ensure the flow rate at lower speed has to be less or equal to the flow rate at higher speed
2642 0 : if (i != NumOfSpeedCooling) {
2643 0 : if (MSHeatPump.CoolVolumeFlowRate(i) > MSHeatPump.CoolVolumeFlowRate(i + 1)) {
2644 0 : MSHeatPump.CoolVolumeFlowRate(i) = MSHeatPump.CoolVolumeFlowRate(i + 1);
2645 : }
2646 : }
2647 0 : BaseSizer::reportSizerOutput(state,
2648 0 : state.dataHVACMultiSpdHP->CurrentModuleObject,
2649 : MSHeatPump.Name,
2650 0 : format("Speed {} Supply Air Flow Rate During Cooling Operation [m3/s]", i),
2651 0 : MSHeatPump.CoolVolumeFlowRate(i));
2652 : }
2653 : }
2654 : }
2655 :
2656 0 : for (i = NumOfSpeedHeating; i >= 1; --i) {
2657 0 : if (MSHeatPump.HeatVolumeFlowRate(i) == DataSizing::AutoSize) {
2658 0 : if (state.dataSize->CurSysNum > 0) {
2659 0 : if (i == NumOfSpeedHeating) {
2660 0 : CheckSysSizing(state, state.dataHVACMultiSpdHP->CurrentModuleObject, MSHeatPump.Name);
2661 0 : MSHeatPump.HeatVolumeFlowRate(i) = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesMainVolFlow;
2662 0 : if (MSHeatPump.FanVolFlow < MSHeatPump.HeatVolumeFlowRate(i) && MSHeatPump.FanVolFlow != DataSizing::AutoSize) {
2663 0 : MSHeatPump.HeatVolumeFlowRate(i) = MSHeatPump.FanVolFlow;
2664 0 : ShowWarningError(state, format("{} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, MSHeatPump.Name));
2665 0 : ShowContinueError(state,
2666 : "The supply air flow rate at high speed is less than the autosized value for the maximum air flow rate "
2667 : "in heating mode. Consider autosizing the fan for this simulation.");
2668 0 : ShowContinueError(state,
2669 : "The maximum air flow rate at high speed in heating mode is reset to the supply air flow rate and the "
2670 : "simulation continues.");
2671 : }
2672 : } else {
2673 0 : MSHeatPump.HeatVolumeFlowRate(i) = MSHeatPump.HeatVolumeFlowRate(NumOfSpeedHeating) * i / NumOfSpeedHeating;
2674 : }
2675 0 : if (MSHeatPump.HeatVolumeFlowRate(i) < HVAC::SmallAirVolFlow) {
2676 0 : MSHeatPump.HeatVolumeFlowRate(i) = 0.0;
2677 : }
2678 : // Ensure the flow rate at lower speed has to be less or equal to the flow rate at higher speed
2679 0 : if (i != NumOfSpeedHeating) {
2680 0 : if (MSHeatPump.HeatVolumeFlowRate(i) > MSHeatPump.HeatVolumeFlowRate(i + 1)) {
2681 0 : MSHeatPump.HeatVolumeFlowRate(i) = MSHeatPump.HeatVolumeFlowRate(i + 1);
2682 : }
2683 : }
2684 0 : BaseSizer::reportSizerOutput(state,
2685 0 : state.dataHVACMultiSpdHP->CurrentModuleObject,
2686 : MSHeatPump.Name,
2687 0 : format("Speed{}Supply Air Flow Rate During Heating Operation [m3/s]", i),
2688 0 : MSHeatPump.HeatVolumeFlowRate(i));
2689 : }
2690 : }
2691 : }
2692 :
2693 0 : if (MSHeatPump.IdleVolumeAirRate == DataSizing::AutoSize) {
2694 0 : if (state.dataSize->CurSysNum > 0) {
2695 0 : CheckSysSizing(state, state.dataHVACMultiSpdHP->CurrentModuleObject, MSHeatPump.Name);
2696 0 : MSHeatPump.IdleVolumeAirRate = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).DesMainVolFlow;
2697 0 : if (MSHeatPump.FanVolFlow < MSHeatPump.IdleVolumeAirRate && MSHeatPump.FanVolFlow != DataSizing::AutoSize) {
2698 0 : MSHeatPump.IdleVolumeAirRate = MSHeatPump.FanVolFlow;
2699 0 : ShowWarningError(state, format("{} \"{}\"", state.dataHVACMultiSpdHP->CurrentModuleObject, MSHeatPump.Name));
2700 0 : ShowContinueError(state,
2701 : "The supply air flow rate is less than the autosized value for the maximum air flow rate when no heating or "
2702 : "cooling is needed. Consider autosizing the fan for this simulation.");
2703 0 : ShowContinueError(state,
2704 : "The maximum air flow rate when no heating or cooling is needed is reset to the supply air flow rate and the "
2705 : "simulation continues.");
2706 : }
2707 0 : if (MSHeatPump.IdleVolumeAirRate < HVAC::SmallAirVolFlow) {
2708 0 : MSHeatPump.IdleVolumeAirRate = 0.0;
2709 : }
2710 :
2711 0 : BaseSizer::reportSizerOutput(state,
2712 0 : state.dataHVACMultiSpdHP->CurrentModuleObject,
2713 : MSHeatPump.Name,
2714 : "Supply Air Flow Rate When No Cooling or Heating is Needed [m3/s]",
2715 : MSHeatPump.IdleVolumeAirRate);
2716 : }
2717 : }
2718 :
2719 0 : if (MSHeatPump.SuppMaxAirTemp == DataSizing::AutoSize) {
2720 0 : if (state.dataSize->CurSysNum > 0) {
2721 0 : if (MSHeatPump.SuppHeatCoilType == 1) { // Gas
2722 0 : CheckZoneSizing(state, "Coil:Heating:Fuel", MSHeatPump.Name);
2723 : } else {
2724 0 : CheckZoneSizing(state, "Coil:Heating:Electric", MSHeatPump.Name);
2725 : }
2726 0 : MSHeatPump.SuppMaxAirTemp = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).HeatSupTemp;
2727 0 : BaseSizer::reportSizerOutput(state,
2728 0 : state.dataHVACMultiSpdHP->CurrentModuleObject,
2729 : MSHeatPump.Name,
2730 : "Maximum Supply Air Temperature from Supplemental Heater [C]",
2731 : MSHeatPump.SuppMaxAirTemp);
2732 : }
2733 : }
2734 :
2735 0 : if (MSHeatPump.DesignSuppHeatingCapacity == DataSizing::AutoSize) {
2736 0 : if (state.dataSize->CurSysNum > 0) {
2737 0 : if (MSHeatPump.SuppHeatCoilType == 1) { // Gas
2738 0 : CheckSysSizing(state, "Coil:Heating:Fuel", MSHeatPump.Name);
2739 : } else {
2740 0 : CheckSysSizing(state, "Coil:Heating:Electric", MSHeatPump.Name);
2741 : }
2742 0 : MSHeatPump.DesignSuppHeatingCapacity = state.dataSize->FinalSysSizing(state.dataSize->CurSysNum).HeatCap;
2743 : } else {
2744 0 : MSHeatPump.DesignSuppHeatingCapacity = 0.0;
2745 : }
2746 0 : BaseSizer::reportSizerOutput(state,
2747 0 : state.dataHVACMultiSpdHP->CurrentModuleObject,
2748 : MSHeatPump.Name,
2749 : "Supplemental Heating Coil Nominal Capacity [W]",
2750 : MSHeatPump.DesignSuppHeatingCapacity);
2751 : }
2752 0 : state.dataSize->SuppHeatCap = MSHeatPump.DesignSuppHeatingCapacity;
2753 :
2754 0 : if (MSHeatPump.HeatRecActive) {
2755 0 : PlantUtilities::RegisterPlantCompDesignFlow(state, MSHeatPump.HeatRecInletNodeNum, MSHeatPump.DesignHeatRecFlowRate);
2756 : }
2757 0 : }
2758 :
2759 : //******************************************************************************
2760 :
2761 4 : void ControlMSHPOutputEMS(EnergyPlusData &state,
2762 : int const MSHeatPumpNum, // Unit index of engine driven heat pump
2763 : bool const FirstHVACIteration, // flag for 1st HVAC iteration in the time step
2764 : HVAC::CompressorOp const compressorOp, // compressor operation; 1=on, 0=off
2765 : HVAC::FanOp const fanOp, // operating mode: FanOp::Cycling | FanOp::Continuous
2766 : Real64 const QZnReq, // cooling or heating output needed by zone [W]
2767 : Real64 const SpeedVal, // continuous speed value
2768 : int &SpeedNum, // discrete speed level
2769 : Real64 &SpeedRatio, // unit speed ratio for DX coils
2770 : Real64 &PartLoadFrac, // unit part load fraction
2771 : Real64 &OnOffAirFlowRatio, // ratio of compressor ON airflow to AVERAGE airflow over timestep
2772 : Real64 &SupHeaterLoad // Supplemental heater load [W]
2773 :
2774 : )
2775 : {
2776 4 : OnOffAirFlowRatio = 0.0;
2777 4 : SupHeaterLoad = 0.0;
2778 :
2779 4 : auto &MSHeatPump = state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum);
2780 :
2781 : // Get EMS output
2782 4 : SpeedNum = ceil(SpeedVal);
2783 4 : bool useMaxedSpeed = false;
2784 4 : std::string useMaxedSpeedCoilName;
2785 4 : if (MSHeatPump.HeatCoolMode == ModeOfOperation::HeatingMode) {
2786 4 : if (SpeedNum > MSHeatPump.NumOfSpeedHeating) {
2787 1 : SpeedNum = MSHeatPump.NumOfSpeedHeating;
2788 1 : useMaxedSpeed = true;
2789 1 : useMaxedSpeedCoilName = MSHeatPump.DXHeatCoilName;
2790 : }
2791 0 : } else if (MSHeatPump.HeatCoolMode == ModeOfOperation::CoolingMode) {
2792 0 : if (SpeedNum > MSHeatPump.NumOfSpeedCooling) {
2793 0 : SpeedNum = MSHeatPump.NumOfSpeedCooling;
2794 0 : useMaxedSpeed = true;
2795 0 : useMaxedSpeedCoilName = MSHeatPump.DXCoolCoilName;
2796 : }
2797 : }
2798 4 : if (useMaxedSpeed) {
2799 1 : MSHeatPump.CoilSpeedErrIndex++;
2800 8 : ShowRecurringWarningErrorAtEnd(state,
2801 2 : "Wrong coil speed EMS override value, for unit=\"" + useMaxedSpeedCoilName +
2802 : "\". Exceeding maximum coil speed level. Speed level is set to the maximum coil speed level allowed.",
2803 1 : MSHeatPump.CoilSpeedErrIndex,
2804 : SpeedVal,
2805 : SpeedVal,
2806 : _,
2807 : "",
2808 : "");
2809 : }
2810 : // Calculate TempOutput
2811 4 : Real64 TempOutput = 0.0; // unit output when iteration limit exceeded [W]
2812 :
2813 4 : if (SpeedNum == 1) {
2814 2 : SpeedRatio = 0.0;
2815 2 : if (useMaxedSpeed || floor(SpeedVal) == SpeedVal) {
2816 1 : PartLoadFrac = 1;
2817 : } else {
2818 1 : PartLoadFrac = SpeedVal - floor(SpeedVal);
2819 : }
2820 2 : CalcMSHeatPump(state,
2821 : MSHeatPumpNum,
2822 : FirstHVACIteration,
2823 : compressorOp,
2824 : SpeedNum,
2825 : SpeedRatio,
2826 : PartLoadFrac,
2827 : TempOutput,
2828 : QZnReq,
2829 : OnOffAirFlowRatio,
2830 : SupHeaterLoad);
2831 : } else {
2832 2 : PartLoadFrac = 0.0;
2833 2 : if (useMaxedSpeed || floor(SpeedVal) == SpeedVal) {
2834 1 : SpeedRatio = 1;
2835 : } else {
2836 1 : SpeedRatio = SpeedVal - floor(SpeedVal);
2837 : }
2838 2 : CalcMSHeatPump(state,
2839 : MSHeatPumpNum,
2840 : FirstHVACIteration,
2841 : compressorOp,
2842 : SpeedNum,
2843 : SpeedRatio,
2844 : PartLoadFrac,
2845 : TempOutput,
2846 : QZnReq,
2847 : OnOffAirFlowRatio,
2848 : SupHeaterLoad);
2849 : }
2850 :
2851 4 : ControlMSHPSupHeater(state,
2852 : MSHeatPumpNum,
2853 : FirstHVACIteration,
2854 : compressorOp,
2855 : fanOp,
2856 : QZnReq,
2857 : TempOutput,
2858 : SpeedNum,
2859 : SpeedRatio,
2860 : PartLoadFrac,
2861 : OnOffAirFlowRatio,
2862 : SupHeaterLoad);
2863 4 : state.dataHVACMultiSpdHP->MSHeatPumpReport(MSHeatPumpNum).CycRatio = PartLoadFrac;
2864 4 : state.dataHVACMultiSpdHP->MSHeatPumpReport(MSHeatPumpNum).SpeedRatio = SpeedRatio;
2865 4 : state.dataHVACMultiSpdHP->MSHeatPumpReport(MSHeatPumpNum).SpeedNum = SpeedNum;
2866 4 : }
2867 :
2868 4 : void ControlMSHPSupHeater(EnergyPlusData &state,
2869 : int const MSHeatPumpNum, // Unit index of engine driven heat pump
2870 : bool const FirstHVACIteration, // flag for 1st HVAC iteration in the time step
2871 : HVAC::CompressorOp const compressorOp, // compressor operation; 1=on, 0=off
2872 : HVAC::FanOp const fanOp, // operating mode: FanOp::Cycling | FanOp::Continuous
2873 : Real64 const QZnReq, // cooling or heating output needed by zone [W]
2874 : int const EMSOutput, // unit full output when compressor is operating [W]
2875 : int const SpeedNum, // Speed number
2876 : Real64 SpeedRatio, // unit speed ratio for DX coils
2877 : Real64 PartLoadFrac, // unit part load fraction
2878 : Real64 OnOffAirFlowRatio, // ratio of compressor ON airflow to AVERAGE airflow over timestep
2879 : Real64 &SupHeaterLoad // Supplemental heater load [W]
2880 :
2881 : )
2882 : {
2883 : // if the DX heating coil cannot meet the load, trim with supplemental heater
2884 : // occurs with constant fan mode when compressor is on or off
2885 : // occurs with cycling fan mode when compressor PLR is equal to 1
2886 4 : auto &MSHeatPump = state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum);
2887 :
2888 4 : if ((QZnReq > HVAC::SmallLoad && QZnReq > EMSOutput)) {
2889 : Real64 TempOutput;
2890 3 : if (state.dataEnvrn->OutDryBulbTemp <= MSHeatPump.SuppMaxAirTemp) {
2891 3 : SupHeaterLoad = QZnReq - EMSOutput;
2892 : } else {
2893 0 : SupHeaterLoad = 0.0;
2894 : }
2895 3 : CalcMSHeatPump(state,
2896 : MSHeatPumpNum,
2897 : FirstHVACIteration,
2898 : compressorOp,
2899 : SpeedNum,
2900 : SpeedRatio,
2901 : PartLoadFrac,
2902 : TempOutput,
2903 : QZnReq,
2904 : OnOffAirFlowRatio,
2905 : SupHeaterLoad);
2906 : }
2907 :
2908 : // check the outlet of the supplemental heater to be lower than the maximum supplemental heater supply air temperature
2909 4 : if (state.dataLoopNodes->Node(MSHeatPump.AirOutletNodeNum).Temp > MSHeatPump.SuppMaxAirTemp && SupHeaterLoad > 0.0) {
2910 :
2911 : // If the supply air temperature is to high, turn off the supplemental heater to recalculate the outlet temperature
2912 0 : SupHeaterLoad = 0.0;
2913 : Real64 QCoilActual; // coil load actually delivered returned to calling component
2914 0 : CalcNonDXHeatingCoils(state, MSHeatPumpNum, FirstHVACIteration, SupHeaterLoad, fanOp, QCoilActual);
2915 :
2916 : // If the outlet temperature is below the maximum supplemental heater supply air temperature, reduce the load passed to
2917 : // the supplemental heater, otherwise leave the supplemental heater off. If the supplemental heater is to be turned on,
2918 : // use the outlet conditions when the supplemental heater was off (CALL above) as the inlet conditions for the calculation
2919 : // of supplemental heater load to just meet the maximum supply air temperature from the supplemental heater.
2920 0 : if (state.dataLoopNodes->Node(MSHeatPump.AirOutletNodeNum).Temp < MSHeatPump.SuppMaxAirTemp) {
2921 0 : Real64 CpAir = Psychrometrics::PsyCpAirFnW(state.dataLoopNodes->Node(MSHeatPump.AirOutletNodeNum).HumRat);
2922 0 : SupHeaterLoad = state.dataLoopNodes->Node(MSHeatPump.AirInletNodeNum).MassFlowRate * CpAir *
2923 0 : (MSHeatPump.SuppMaxAirTemp - state.dataLoopNodes->Node(MSHeatPump.AirOutletNodeNum).Temp);
2924 :
2925 : } else {
2926 0 : SupHeaterLoad = 0.0;
2927 : }
2928 : }
2929 4 : }
2930 :
2931 8 : void ControlMSHPOutput(EnergyPlusData &state,
2932 : int const MSHeatPumpNum, // Unit index of engine driven heat pump
2933 : bool const FirstHVACIteration, // flag for 1st HVAC iteration in the time step
2934 : HVAC::CompressorOp const compressorOp, // compressor operation; 1=on, 0=off
2935 : HVAC::FanOp const fanOp, // operating mode: FanOp::Cycling | FanOp::Continuous
2936 : Real64 const QZnReq, // cooling or heating output needed by zone [W]
2937 : int const ZoneNum [[maybe_unused]], // Index to zone number
2938 : int &SpeedNum, // Speed number
2939 : Real64 &SpeedRatio, // unit speed ratio for DX coils
2940 : Real64 &PartLoadFrac, // unit part load fraction
2941 : Real64 &OnOffAirFlowRatio, // ratio of compressor ON airflow to AVERAGE airflow over timestep
2942 : Real64 &SupHeaterLoad // Supplemental heater load [W]
2943 : )
2944 : {
2945 :
2946 : // SUBROUTINE INFORMATION:
2947 : // AUTHOR Lixing Gu
2948 : // DATE WRITTEN June 2007
2949 : // RE-ENGINEERED Revised for multispeed heat pump use based on ControlPTHPOutput
2950 :
2951 : // PURPOSE OF THIS SUBROUTINE:
2952 : // Determine the part load fraction at low speed, and speed ratio at high speed for this time step.
2953 :
2954 : // METHODOLOGY EMPLOYED:
2955 : // Use RegulaFalsi technique to iterate on part-load ratio until convergence is achieved.
2956 :
2957 : // SUBROUTINE PARAMETER DEFINITIONS:
2958 8 : int constexpr MaxIte(500); // maximum number of iterations
2959 :
2960 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2961 : Real64 FullOutput; // unit full output when compressor is operating [W]
2962 : Real64 LowOutput; // unit full output at low speed [W]
2963 : Real64 TempOutput; // unit output when iteration limit exceeded [W]
2964 : Real64 NoCompOutput; // output when no active compressor [W]
2965 : Real64 ErrorToler; // error tolerance
2966 : int SolFla; // Flag of RegulaFalsi solver
2967 : Real64 CpAir; // air specific heat
2968 : Real64 OutsideDryBulbTemp; // Outside air temperature at external node height
2969 : Real64 QCoilActual; // coil load actually delivered returned to calling component
2970 : int i; // Speed index
2971 :
2972 8 : SupHeaterLoad = 0.0;
2973 8 : PartLoadFrac = 0.0;
2974 8 : SpeedRatio = 0.0;
2975 8 : SpeedNum = 1;
2976 :
2977 8 : OutsideDryBulbTemp = state.dataEnvrn->OutDryBulbTemp;
2978 :
2979 8 : auto &MSHeatPump = state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum);
2980 :
2981 : //!!LKL Discrepancy with < 0
2982 9 : if (MSHeatPump.availSched->getCurrentVal() == 0.0) return;
2983 :
2984 : // Get result when DX coil is off
2985 8 : CalcMSHeatPump(state,
2986 : MSHeatPumpNum,
2987 : FirstHVACIteration,
2988 : compressorOp,
2989 : SpeedNum,
2990 : SpeedRatio,
2991 : PartLoadFrac,
2992 : NoCompOutput,
2993 : QZnReq,
2994 : OnOffAirFlowRatio,
2995 : SupHeaterLoad);
2996 :
2997 : // If cooling and NoCompOutput < QZnReq, the coil needs to be off
2998 : // If heating and NoCompOutput > QZnReq, the coil needs to be off
2999 16 : if ((QZnReq < (-1.0 * HVAC::SmallLoad) && NoCompOutput < QZnReq) || (QZnReq > HVAC::SmallLoad && NoCompOutput > QZnReq) ||
3000 8 : std::abs(QZnReq) <= HVAC::SmallLoad) {
3001 1 : return;
3002 : }
3003 :
3004 : // Get full load result
3005 7 : PartLoadFrac = 1.0;
3006 7 : SpeedRatio = 1.0;
3007 7 : if (MSHeatPump.HeatCoolMode == ModeOfOperation::HeatingMode) {
3008 3 : SpeedNum = MSHeatPump.NumOfSpeedHeating;
3009 3 : if (MSHeatPump.Staged && std::abs(MSHeatPump.StageNum) < SpeedNum) {
3010 0 : SpeedNum = std::abs(MSHeatPump.StageNum);
3011 0 : if (SpeedNum == 1) SpeedRatio = 0.0;
3012 : }
3013 : }
3014 7 : if (MSHeatPump.HeatCoolMode == ModeOfOperation::CoolingMode) {
3015 4 : SpeedNum = MSHeatPump.NumOfSpeedCooling;
3016 4 : if (MSHeatPump.Staged && std::abs(MSHeatPump.StageNum) < SpeedNum) {
3017 0 : SpeedNum = std::abs(MSHeatPump.StageNum);
3018 0 : if (SpeedNum == 1) SpeedRatio = 0.0;
3019 : }
3020 : }
3021 :
3022 7 : CalcMSHeatPump(state,
3023 : MSHeatPumpNum,
3024 : FirstHVACIteration,
3025 : compressorOp,
3026 : SpeedNum,
3027 : SpeedRatio,
3028 : PartLoadFrac,
3029 : FullOutput,
3030 : QZnReq,
3031 : OnOffAirFlowRatio,
3032 : SupHeaterLoad);
3033 :
3034 7 : if (QZnReq < (-1.0 * HVAC::SmallLoad)) {
3035 : // Since we are cooling, we expect FullOutput to be < 0 and FullOutput < NoCompOutput
3036 : // Check that this is the case; if not set PartLoadFrac = 0.0 (off) and return
3037 4 : if (FullOutput >= 0.0 || FullOutput >= NoCompOutput) {
3038 0 : PartLoadFrac = 0.0;
3039 0 : SpeedRatio = 0.0;
3040 0 : SpeedNum = 0;
3041 0 : return;
3042 : }
3043 : // ! If the QZnReq <= FullOutput the unit needs to run full out
3044 4 : if (QZnReq <= FullOutput) {
3045 0 : PartLoadFrac = 1.0;
3046 0 : SpeedRatio = 1.0;
3047 0 : if (MSHeatPump.Staged && SpeedNum == 1) SpeedRatio = 0.0;
3048 0 : state.dataHVACMultiSpdHP->MSHeatPumpReport(MSHeatPumpNum).CycRatio = PartLoadFrac;
3049 0 : state.dataHVACMultiSpdHP->MSHeatPumpReport(MSHeatPumpNum).SpeedRatio = SpeedRatio;
3050 0 : state.dataHVACMultiSpdHP->MSHeatPumpReport(MSHeatPumpNum).SpeedNum = SpeedNum;
3051 0 : return;
3052 : }
3053 4 : ErrorToler = 0.001; // Error tolerance for convergence from input deck
3054 : } else {
3055 : // Since we are heating, we expect FullOutput to be > 0 and FullOutput > NoCompOutput
3056 : // Check that this is the case; if not set PartLoadFrac = 0.0 (off)
3057 3 : if (FullOutput <= 0.0 || FullOutput <= NoCompOutput) {
3058 0 : PartLoadFrac = 0.0;
3059 0 : SpeedRatio = 0.0;
3060 : // may need supplemental heating so don't return in heating mode
3061 : }
3062 3 : if (QZnReq >= FullOutput) {
3063 1 : PartLoadFrac = 1.0;
3064 1 : SpeedRatio = 1.0;
3065 : // may need supplemental heating so don't return in heating mode
3066 : }
3067 3 : ErrorToler = 0.001; // Error tolerance for convergence from input deck
3068 : }
3069 :
3070 : // Direct solution
3071 7 : if (state.dataGlobal->DoCoilDirectSolutions && !MSHeatPump.Staged) {
3072 3 : Real64 TempOutput0 = 0.0;
3073 3 : MSHeatPump.FullOutput = 0.0;
3074 :
3075 : // heating
3076 3 : if (QZnReq > HVAC::SmallLoad && QZnReq < FullOutput) {
3077 1 : CalcMSHeatPump(
3078 : state, MSHeatPumpNum, FirstHVACIteration, compressorOp, 1, 0.0, 0.0, TempOutput0, QZnReq, OnOffAirFlowRatio, SupHeaterLoad);
3079 :
3080 1 : for (int k = 1; k <= MSHeatPump.NumOfSpeedHeating; ++k) {
3081 1 : if (k == 1) {
3082 1 : CalcMSHeatPump(state,
3083 : MSHeatPumpNum,
3084 : FirstHVACIteration,
3085 : compressorOp,
3086 : k,
3087 : 0.0,
3088 : 1.0,
3089 1 : MSHeatPump.FullOutput(k),
3090 : QZnReq,
3091 : OnOffAirFlowRatio,
3092 : SupHeaterLoad);
3093 1 : if (QZnReq <= MSHeatPump.FullOutput(k)) {
3094 1 : SpeedNum = k;
3095 1 : PartLoadFrac = (QZnReq - TempOutput0) / (MSHeatPump.FullOutput(k) - TempOutput0);
3096 1 : CalcMSHeatPump(state,
3097 : MSHeatPumpNum,
3098 : FirstHVACIteration,
3099 : compressorOp,
3100 : k,
3101 : 0.0,
3102 : PartLoadFrac,
3103 : TempOutput,
3104 : QZnReq,
3105 : OnOffAirFlowRatio,
3106 : SupHeaterLoad);
3107 1 : break;
3108 : }
3109 : } else {
3110 0 : CalcMSHeatPump(state,
3111 : MSHeatPumpNum,
3112 : FirstHVACIteration,
3113 : compressorOp,
3114 : k,
3115 : 1.0,
3116 : 1.0,
3117 0 : MSHeatPump.FullOutput(k),
3118 : QZnReq,
3119 : OnOffAirFlowRatio,
3120 : SupHeaterLoad);
3121 0 : if (QZnReq <= MSHeatPump.FullOutput(k)) {
3122 0 : SpeedNum = k;
3123 0 : PartLoadFrac = 1.0;
3124 0 : SpeedRatio = (QZnReq - MSHeatPump.FullOutput(k - 1)) / (MSHeatPump.FullOutput(k) - MSHeatPump.FullOutput(k - 1));
3125 0 : CalcMSHeatPump(state,
3126 : MSHeatPumpNum,
3127 : FirstHVACIteration,
3128 : compressorOp,
3129 : k,
3130 : SpeedRatio,
3131 : 1.0,
3132 : TempOutput,
3133 : QZnReq,
3134 : OnOffAirFlowRatio,
3135 : SupHeaterLoad);
3136 0 : break;
3137 : }
3138 : }
3139 : }
3140 : }
3141 :
3142 : // Cooling
3143 3 : if (QZnReq < (-1.0 * HVAC::SmallLoad) && QZnReq > FullOutput) {
3144 2 : CalcMSHeatPump(
3145 : state, MSHeatPumpNum, FirstHVACIteration, compressorOp, 1, 0.0, 0.0, TempOutput0, QZnReq, OnOffAirFlowRatio, SupHeaterLoad);
3146 2 : for (int k = 1; k <= MSHeatPump.NumOfSpeedCooling; ++k) {
3147 2 : if (k == 1) {
3148 2 : CalcMSHeatPump(state,
3149 : MSHeatPumpNum,
3150 : FirstHVACIteration,
3151 : compressorOp,
3152 : k,
3153 : 0.0,
3154 : 1.0,
3155 2 : MSHeatPump.FullOutput(k),
3156 : QZnReq,
3157 : OnOffAirFlowRatio,
3158 : SupHeaterLoad);
3159 2 : if (QZnReq >= MSHeatPump.FullOutput(k)) {
3160 2 : SpeedNum = k;
3161 2 : PartLoadFrac = (QZnReq - TempOutput0) / (MSHeatPump.FullOutput(k) - TempOutput0);
3162 2 : CalcMSHeatPump(state,
3163 : MSHeatPumpNum,
3164 : FirstHVACIteration,
3165 : compressorOp,
3166 : k,
3167 : 0.0,
3168 : PartLoadFrac,
3169 : TempOutput,
3170 : QZnReq,
3171 : OnOffAirFlowRatio,
3172 : SupHeaterLoad);
3173 2 : break;
3174 : }
3175 : } else {
3176 0 : CalcMSHeatPump(state,
3177 : MSHeatPumpNum,
3178 : FirstHVACIteration,
3179 : compressorOp,
3180 : k,
3181 : 1.0,
3182 : 1.0,
3183 0 : MSHeatPump.FullOutput(k),
3184 : QZnReq,
3185 : OnOffAirFlowRatio,
3186 : SupHeaterLoad);
3187 0 : if (QZnReq >= MSHeatPump.FullOutput(k)) {
3188 0 : SpeedNum = k;
3189 0 : PartLoadFrac = 1.0;
3190 0 : SpeedRatio = (QZnReq - MSHeatPump.FullOutput(k - 1)) / (MSHeatPump.FullOutput(k) - MSHeatPump.FullOutput(k - 1));
3191 0 : CalcMSHeatPump(state,
3192 : MSHeatPumpNum,
3193 : FirstHVACIteration,
3194 : compressorOp,
3195 : k,
3196 : SpeedRatio,
3197 : 1.0,
3198 : TempOutput,
3199 : QZnReq,
3200 : OnOffAirFlowRatio,
3201 : SupHeaterLoad);
3202 0 : break;
3203 : }
3204 : }
3205 : }
3206 : }
3207 : } else {
3208 : // Calculate the part load fraction
3209 4 : if (((QZnReq > HVAC::SmallLoad && QZnReq < FullOutput) || (QZnReq < (-1.0 * HVAC::SmallLoad) && QZnReq > FullOutput)) &&
3210 3 : (!MSHeatPump.Staged)) {
3211 : // Check whether the low speed coil can meet the load or not
3212 3 : CalcMSHeatPump(
3213 : state, MSHeatPumpNum, FirstHVACIteration, compressorOp, 1, 0.0, 1.0, LowOutput, QZnReq, OnOffAirFlowRatio, SupHeaterLoad);
3214 3 : if ((QZnReq > 0.0 && QZnReq <= LowOutput) || (QZnReq < 0.0 && QZnReq >= LowOutput)) {
3215 3 : SpeedRatio = 0.0;
3216 3 : SpeedNum = 1;
3217 12 : auto f = [&state, MSHeatPumpNum, FirstHVACIteration, QZnReq, OnOffAirFlowRatio, SupHeaterLoad, compressorOp](
3218 : Real64 const PartLoadFrac) {
3219 : // Calculates residual function ((ActualOutput - QZnReq)/QZnReq); MSHP output depends on PLR which is being varied to zero
3220 : // the residual.
3221 : Real64 ActualOutput; // delivered capacity of MSHP
3222 9 : Real64 tmpAirFlowRatio = OnOffAirFlowRatio;
3223 9 : Real64 tmpHeaterLoad = SupHeaterLoad;
3224 9 : CalcMSHeatPump(state,
3225 : MSHeatPumpNum,
3226 : FirstHVACIteration,
3227 : compressorOp,
3228 : 1,
3229 : 0.0,
3230 : PartLoadFrac,
3231 : ActualOutput,
3232 : QZnReq,
3233 : tmpAirFlowRatio,
3234 : tmpHeaterLoad);
3235 9 : return (ActualOutput - QZnReq) / QZnReq;
3236 3 : };
3237 3 : General::SolveRoot(state, ErrorToler, MaxIte, SolFla, PartLoadFrac, f, 0.0, 1.0);
3238 3 : if (SolFla == -1) {
3239 0 : if (!state.dataGlobal->WarmupFlag) {
3240 0 : if (state.dataHVACMultiSpdHP->ErrCountCyc == 0) {
3241 0 : ++state.dataHVACMultiSpdHP->ErrCountCyc; // TODO: Why is the error count shared among all heat pump units?
3242 0 : ShowWarningError(state,
3243 0 : format("Iteration limit exceeded calculating DX unit cycling ratio, for unit={}", MSHeatPump.Name));
3244 0 : ShowContinueErrorTimeStamp(state, format("Cycling ratio returned={:.2R}", PartLoadFrac));
3245 : } else {
3246 0 : ++state.dataHVACMultiSpdHP->ErrCountCyc;
3247 0 : ShowRecurringWarningErrorAtEnd(
3248 : state,
3249 0 : MSHeatPump.Name + "\": Iteration limit warning exceeding calculating DX unit cycling ratio continues...",
3250 0 : MSHeatPump.ErrIndexCyc,
3251 : PartLoadFrac,
3252 : PartLoadFrac);
3253 : }
3254 : }
3255 3 : } else if (SolFla == -2) {
3256 0 : ShowFatalError(
3257 : state,
3258 0 : format("DX unit cycling ratio calculation failed: cycling limits exceeded, for unit={}", MSHeatPump.DXCoolCoilName));
3259 : }
3260 3 : } else {
3261 : // Check to see which speed to meet the load
3262 0 : PartLoadFrac = 1.0;
3263 0 : SpeedRatio = 1.0;
3264 0 : if (QZnReq < (-1.0 * HVAC::SmallLoad)) { // Cooling
3265 0 : for (i = 2; i <= MSHeatPump.NumOfSpeedCooling; ++i) {
3266 0 : CalcMSHeatPump(state,
3267 : MSHeatPumpNum,
3268 : FirstHVACIteration,
3269 : compressorOp,
3270 : i,
3271 : SpeedRatio,
3272 : PartLoadFrac,
3273 : TempOutput,
3274 : QZnReq,
3275 : OnOffAirFlowRatio,
3276 : SupHeaterLoad);
3277 0 : if (QZnReq >= TempOutput) {
3278 0 : SpeedNum = i;
3279 0 : break;
3280 : }
3281 : }
3282 : } else {
3283 0 : for (i = 2; i <= MSHeatPump.NumOfSpeedHeating; ++i) {
3284 0 : CalcMSHeatPump(state,
3285 : MSHeatPumpNum,
3286 : FirstHVACIteration,
3287 : compressorOp,
3288 : i,
3289 : SpeedRatio,
3290 : PartLoadFrac,
3291 : TempOutput,
3292 : QZnReq,
3293 : OnOffAirFlowRatio,
3294 : SupHeaterLoad);
3295 0 : if (QZnReq <= TempOutput) {
3296 0 : SpeedNum = i;
3297 0 : break;
3298 : }
3299 : }
3300 : }
3301 0 : auto f = [&state, OnOffAirFlowRatio, SupHeaterLoad, MSHeatPumpNum, FirstHVACIteration, compressorOp, SpeedNum, QZnReq](
3302 : Real64 const SpeedRatio) {
3303 : // Calculates residual function ((ActualOutput - QZnReq)/QZnReq) MSHP output depends on PLR which is being varied to zero the
3304 : // residual.
3305 0 : Real64 localAirFlowRatio = OnOffAirFlowRatio;
3306 0 : Real64 localHeaterLoad = SupHeaterLoad;
3307 : Real64 ActualOutput;
3308 0 : CalcMSHeatPump(state,
3309 : MSHeatPumpNum,
3310 : FirstHVACIteration,
3311 : compressorOp,
3312 : SpeedNum,
3313 : SpeedRatio,
3314 : 1.0,
3315 : ActualOutput,
3316 : QZnReq,
3317 : localAirFlowRatio,
3318 : localHeaterLoad);
3319 0 : return (ActualOutput - QZnReq) / QZnReq;
3320 0 : };
3321 0 : General::SolveRoot(state, ErrorToler, MaxIte, SolFla, SpeedRatio, f, 0.0, 1.0);
3322 0 : if (SolFla == -1) {
3323 0 : if (!state.dataGlobal->WarmupFlag) {
3324 0 : if (state.dataHVACMultiSpdHP->ErrCountVar == 0) {
3325 0 : ++state.dataHVACMultiSpdHP->ErrCountVar;
3326 0 : ShowWarningError(state,
3327 0 : format("Iteration limit exceeded calculating DX unit speed ratio, for unit={}", MSHeatPump.Name));
3328 0 : ShowContinueErrorTimeStamp(state, format("Speed ratio returned=[{:.2R}], Speed number ={}", SpeedRatio, SpeedNum));
3329 : } else {
3330 0 : ++state.dataHVACMultiSpdHP->ErrCountVar;
3331 0 : ShowRecurringWarningErrorAtEnd(
3332 : state,
3333 0 : MSHeatPump.Name + "\": Iteration limit warning exceeding calculating DX unit speed ratio continues...",
3334 0 : MSHeatPump.ErrIndexVar,
3335 : SpeedRatio,
3336 : SpeedRatio);
3337 : }
3338 : }
3339 0 : } else if (SolFla == -2) {
3340 0 : ShowFatalError(
3341 : state,
3342 0 : format("DX unit compressor speed calculation failed: speed limits exceeded, for unit={}", MSHeatPump.DXCoolCoilName));
3343 : }
3344 : }
3345 3 : } else {
3346 : // Staged thermostat performance
3347 1 : if (MSHeatPump.StageNum != 0) {
3348 0 : SpeedNum = std::abs(MSHeatPump.StageNum);
3349 0 : if (SpeedNum == 1) {
3350 0 : CalcMSHeatPump(
3351 : state, MSHeatPumpNum, FirstHVACIteration, compressorOp, 1, 0.0, 1.0, LowOutput, QZnReq, OnOffAirFlowRatio, SupHeaterLoad);
3352 0 : SpeedRatio = 0.0;
3353 0 : if ((QZnReq > 0.0 && QZnReq <= LowOutput) || (QZnReq < 0.0 && QZnReq >= LowOutput)) {
3354 0 : auto f = [&state, MSHeatPumpNum, FirstHVACIteration, QZnReq, OnOffAirFlowRatio, SupHeaterLoad, compressorOp](
3355 : Real64 const PartLoadFrac) {
3356 : // Calculates residual function ((ActualOutput - QZnReq)/QZnReq); MSHP output depends on PLR which is being varied to
3357 : // zero the residual.
3358 : Real64 ActualOutput; // delivered capacity of MSHP
3359 0 : Real64 tmpAirFlowRatio = OnOffAirFlowRatio;
3360 0 : Real64 tmpHeaterLoad = SupHeaterLoad;
3361 0 : CalcMSHeatPump(state,
3362 : MSHeatPumpNum,
3363 : FirstHVACIteration,
3364 : compressorOp,
3365 : 1,
3366 : 0.0,
3367 : PartLoadFrac,
3368 : ActualOutput,
3369 : QZnReq,
3370 : tmpAirFlowRatio,
3371 : tmpHeaterLoad);
3372 0 : return (ActualOutput - QZnReq) / QZnReq;
3373 0 : };
3374 0 : General::SolveRoot(state, ErrorToler, MaxIte, SolFla, PartLoadFrac, f, 0.0, 1.0);
3375 0 : if (SolFla == -1) {
3376 0 : if (!state.dataGlobal->WarmupFlag) {
3377 0 : if (state.dataHVACMultiSpdHP->ErrCountCyc == 0) {
3378 0 : ++state.dataHVACMultiSpdHP->ErrCountCyc;
3379 0 : ShowWarningError(
3380 : state,
3381 0 : format("Iteration limit exceeded calculating DX unit cycling ratio, for unit={}", MSHeatPump.Name));
3382 0 : ShowContinueErrorTimeStamp(state, format("Cycling ratio returned={:.2R}", PartLoadFrac));
3383 : } else {
3384 0 : ++state.dataHVACMultiSpdHP->ErrCountCyc;
3385 0 : ShowRecurringWarningErrorAtEnd(
3386 : state,
3387 0 : MSHeatPump.Name + "\": Iteration limit warning exceeding calculating DX unit cycling ratio continues...",
3388 0 : MSHeatPump.ErrIndexCyc,
3389 : PartLoadFrac,
3390 : PartLoadFrac);
3391 : }
3392 : }
3393 0 : } else if (SolFla == -2) {
3394 0 : ShowFatalError(state,
3395 0 : format("DX unit cycling ratio calculation failed: cycling limits exceeded, for unit={}",
3396 0 : MSHeatPump.DXCoolCoilName));
3397 : }
3398 0 : } else {
3399 0 : FullOutput = LowOutput;
3400 0 : PartLoadFrac = 1.0;
3401 : }
3402 : } else {
3403 0 : if (MSHeatPump.StageNum < 0) {
3404 0 : SpeedNum = min(MSHeatPump.NumOfSpeedCooling, std::abs(MSHeatPump.StageNum));
3405 : } else {
3406 0 : SpeedNum = min(MSHeatPump.NumOfSpeedHeating, std::abs(MSHeatPump.StageNum));
3407 : }
3408 0 : CalcMSHeatPump(state,
3409 : MSHeatPumpNum,
3410 : FirstHVACIteration,
3411 : compressorOp,
3412 : SpeedNum,
3413 : 0.0,
3414 : 1.0,
3415 : LowOutput,
3416 : QZnReq,
3417 : OnOffAirFlowRatio,
3418 : SupHeaterLoad);
3419 0 : if ((QZnReq > 0.0 && QZnReq >= LowOutput) || (QZnReq < 0.0 && QZnReq <= LowOutput)) {
3420 0 : CalcMSHeatPump(state,
3421 : MSHeatPumpNum,
3422 : FirstHVACIteration,
3423 : compressorOp,
3424 : SpeedNum,
3425 : 1.0,
3426 : 1.0,
3427 : FullOutput,
3428 : QZnReq,
3429 : OnOffAirFlowRatio,
3430 : SupHeaterLoad);
3431 0 : if ((QZnReq > 0.0 && QZnReq <= FullOutput) || (QZnReq < 0.0 && QZnReq >= FullOutput)) {
3432 : auto f = // (AUTO_OK_LAMBDA)
3433 0 : [&state, OnOffAirFlowRatio, SupHeaterLoad, MSHeatPumpNum, FirstHVACIteration, compressorOp, SpeedNum, QZnReq](
3434 : Real64 const SpeedRatio) {
3435 : // Calculates residual function ((ActualOutput - QZnReq)/QZnReq) MSHP output depends on PLR which is being
3436 : // varied to zero the residual.
3437 0 : Real64 localAirFlowRatio = OnOffAirFlowRatio;
3438 0 : Real64 localHeaterLoad = SupHeaterLoad;
3439 : Real64 ActualOutput;
3440 0 : CalcMSHeatPump(state,
3441 : MSHeatPumpNum,
3442 : FirstHVACIteration,
3443 : compressorOp,
3444 : SpeedNum,
3445 : SpeedRatio,
3446 : 1.0,
3447 : ActualOutput,
3448 : QZnReq,
3449 : localAirFlowRatio,
3450 : localHeaterLoad);
3451 0 : return (ActualOutput - QZnReq) / QZnReq;
3452 0 : };
3453 0 : General::SolveRoot(state, ErrorToler, MaxIte, SolFla, SpeedRatio, f, 0.0, 1.0);
3454 0 : if (SolFla == -1) {
3455 0 : if (!state.dataGlobal->WarmupFlag) {
3456 0 : if (state.dataHVACMultiSpdHP->ErrCountVar == 0) {
3457 0 : ++state.dataHVACMultiSpdHP->ErrCountVar;
3458 0 : ShowWarningError(
3459 : state,
3460 0 : format("Iteration limit exceeded calculating DX unit speed ratio, for unit={}", MSHeatPump.Name));
3461 0 : ShowContinueErrorTimeStamp(
3462 0 : state, format("Speed ratio returned=[{:.2R}], Speed number ={}", SpeedRatio, SpeedNum));
3463 : } else {
3464 0 : ++state.dataHVACMultiSpdHP->ErrCountVar;
3465 0 : ShowRecurringWarningErrorAtEnd(
3466 : state,
3467 0 : MSHeatPump.Name +
3468 : "\": Iteration limit warning exceeding calculating DX unit speed ratio continues...",
3469 0 : MSHeatPump.ErrIndexVar,
3470 : SpeedRatio,
3471 : SpeedRatio);
3472 : }
3473 : }
3474 0 : } else if (SolFla == -2) {
3475 0 : ShowFatalError(state,
3476 0 : format("DX unit compressor speed calculation failed: speed limits exceeded, for unit={}",
3477 0 : MSHeatPump.DXCoolCoilName));
3478 : }
3479 0 : } else {
3480 0 : SpeedRatio = 1.0;
3481 : }
3482 0 : } else { // lowOutput provides a larger capacity than needed
3483 0 : SpeedRatio = 0.0;
3484 : }
3485 : }
3486 : }
3487 : }
3488 : }
3489 :
3490 : // if the DX heating coil cannot meet the load, trim with supplemental heater
3491 : // occurs with constant fan mode when compressor is on or off
3492 : // occurs with cycling fan mode when compressor PLR is equal to 1
3493 7 : if ((QZnReq > HVAC::SmallLoad && QZnReq > FullOutput)) {
3494 1 : PartLoadFrac = 1.0;
3495 1 : SpeedRatio = 1.0;
3496 1 : if (MSHeatPump.Staged && SpeedNum == 1) SpeedRatio = 0.0;
3497 1 : if (OutsideDryBulbTemp <= MSHeatPump.SuppMaxAirTemp) {
3498 1 : SupHeaterLoad = QZnReq - FullOutput;
3499 : } else {
3500 0 : SupHeaterLoad = 0.0;
3501 : }
3502 1 : CalcMSHeatPump(state,
3503 : MSHeatPumpNum,
3504 : FirstHVACIteration,
3505 : compressorOp,
3506 : SpeedNum,
3507 : SpeedRatio,
3508 : PartLoadFrac,
3509 : TempOutput,
3510 : QZnReq,
3511 : OnOffAirFlowRatio,
3512 : SupHeaterLoad);
3513 : }
3514 :
3515 : // check the outlet of the supplemental heater to be lower than the maximum supplemental heater supply air temperature
3516 7 : if (state.dataLoopNodes->Node(MSHeatPump.AirOutletNodeNum).Temp > MSHeatPump.SuppMaxAirTemp && SupHeaterLoad > 0.0) {
3517 :
3518 : // If the supply air temperature is to high, turn off the supplemental heater to recalculate the outlet temperature
3519 0 : SupHeaterLoad = 0.0;
3520 0 : CalcNonDXHeatingCoils(state, MSHeatPumpNum, FirstHVACIteration, SupHeaterLoad, fanOp, QCoilActual);
3521 :
3522 : // If the outlet temperature is below the maximum supplemental heater supply air temperature, reduce the load passed to
3523 : // the supplemental heater, otherwise leave the supplemental heater off. If the supplemental heater is to be turned on,
3524 : // use the outlet conditions when the supplemental heater was off (CALL above) as the inlet conditions for the calculation
3525 : // of supplemental heater load to just meet the maximum supply air temperature from the supplemental heater.
3526 0 : if (state.dataLoopNodes->Node(MSHeatPump.AirOutletNodeNum).Temp < MSHeatPump.SuppMaxAirTemp) {
3527 0 : CpAir = Psychrometrics::PsyCpAirFnW(state.dataLoopNodes->Node(MSHeatPump.AirOutletNodeNum).HumRat);
3528 0 : SupHeaterLoad = state.dataLoopNodes->Node(MSHeatPump.AirInletNodeNum).MassFlowRate * CpAir *
3529 0 : (MSHeatPump.SuppMaxAirTemp - state.dataLoopNodes->Node(MSHeatPump.AirOutletNodeNum).Temp);
3530 :
3531 : } else {
3532 0 : SupHeaterLoad = 0.0;
3533 : }
3534 : }
3535 :
3536 7 : state.dataHVACMultiSpdHP->MSHeatPumpReport(MSHeatPumpNum).CycRatio = PartLoadFrac;
3537 7 : state.dataHVACMultiSpdHP->MSHeatPumpReport(MSHeatPumpNum).SpeedRatio = SpeedRatio;
3538 7 : state.dataHVACMultiSpdHP->MSHeatPumpReport(MSHeatPumpNum).SpeedNum = SpeedNum;
3539 : }
3540 :
3541 : //******************************************************************************
3542 :
3543 58 : void CalcMSHeatPump(EnergyPlusData &state,
3544 : int const MSHeatPumpNum, // Engine driven heat pump number
3545 : bool const FirstHVACIteration, // Flag for 1st HVAC iteration
3546 : HVAC::CompressorOp const compressorOp, // Compressor on/off; 1=on, 0=off
3547 : int const SpeedNum, // Speed number
3548 : Real64 const SpeedRatio, // Compressor speed ratio
3549 : Real64 const PartLoadFrac, // Compressor part load fraction
3550 : Real64 &LoadMet, // Load met by unit (W)
3551 : Real64 const QZnReq, // Zone load (W)
3552 : Real64 &OnOffAirFlowRatio, // Ratio of compressor ON airflow to AVERAGE airflow over timestep
3553 : Real64 &SupHeaterLoad // supplemental heater load (W)
3554 : )
3555 : {
3556 : // SUBROUTINE INFORMATION:
3557 : // AUTHOR: Lixing Gu, FSEC
3558 : // DATE WRITTEN: June 2007
3559 :
3560 : // PURPOSE OF THIS SUBROUTINE:
3561 : // This routine will calculates MSHP performance based on given system load
3562 :
3563 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3564 : int OutletNode; // MSHP air outlet node
3565 : int InletNode; // MSHP air inlet node
3566 : Real64 OutsideDryBulbTemp; // Outdoor dry bulb temperature [C]
3567 : Real64 AirMassFlow; // Air mass flow rate [kg/s]
3568 : Real64 SavePartloadRatio;
3569 : Real64 SaveSpeedRatio;
3570 : Real64 QCoilActual; // coil load actually delivered returned to calling component
3571 : Real64 MinWaterFlow; // minimum water flow rate
3572 : Real64 ErrorToler; // supplemental heating coil convergence tolerance
3573 :
3574 58 : auto &MSHeatPump = state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum);
3575 :
3576 58 : OutletNode = MSHeatPump.AirOutletNodeNum;
3577 58 : InletNode = MSHeatPump.AirInletNodeNum;
3578 58 : if (MSHeatPump.DXHeatCoilIndex > 0) {
3579 58 : if (state.dataDXCoils->DXCoil(MSHeatPump.DXHeatCoilIndex).IsSecondaryDXCoilInZone) {
3580 0 : OutsideDryBulbTemp =
3581 0 : state.dataZoneTempPredictorCorrector->zoneHeatBalance(state.dataDXCoils->DXCoil(MSHeatPump.DXHeatCoilIndex).SecZonePtr).ZT;
3582 : } else {
3583 58 : OutsideDryBulbTemp = state.dataEnvrn->OutDryBulbTemp;
3584 : }
3585 0 : } else if (MSHeatPump.DXCoolCoilIndex > 0) {
3586 0 : if (state.dataDXCoils->DXCoil(MSHeatPump.DXCoolCoilIndex).IsSecondaryDXCoilInZone) {
3587 0 : OutsideDryBulbTemp =
3588 0 : state.dataZoneTempPredictorCorrector->zoneHeatBalance(state.dataDXCoils->DXCoil(MSHeatPump.DXCoolCoilIndex).SecZonePtr).ZT;
3589 : } else {
3590 0 : OutsideDryBulbTemp = state.dataEnvrn->OutDryBulbTemp;
3591 : }
3592 : } else {
3593 0 : OutsideDryBulbTemp = state.dataEnvrn->OutDryBulbTemp;
3594 : }
3595 :
3596 58 : state.dataHVACMultiSpdHP->SaveCompressorPLR = 0.0;
3597 58 : SavePartloadRatio = 0.0;
3598 58 : MinWaterFlow = 0.0;
3599 58 : ErrorToler = 0.001;
3600 : // Set inlet air mass flow rate based on PLR and compressor on/off air flow rates
3601 58 : SetAverageAirFlow(state, MSHeatPumpNum, PartLoadFrac, OnOffAirFlowRatio, SpeedNum, SpeedRatio);
3602 :
3603 58 : AirMassFlow = state.dataLoopNodes->Node(InletNode).MassFlowRate;
3604 : // if blow through, simulate fan then coils
3605 58 : if (MSHeatPump.fanPlace == HVAC::FanPlace::BlowThru) {
3606 58 : state.dataFans->fans(MSHeatPump.FanNum)->simulate(state, FirstHVACIteration, state.dataHVACMultiSpdHP->FanSpeedRatio);
3607 58 : if (QZnReq < (-1.0 * HVAC::SmallLoad)) {
3608 27 : if (OutsideDryBulbTemp > MSHeatPump.MinOATCompressorCooling) {
3609 81 : DXCoils::SimDXCoilMultiSpeed(state,
3610 : MSHeatPump.DXCoolCoilName,
3611 : SpeedRatio,
3612 : PartLoadFrac,
3613 27 : MSHeatPump.DXCoolCoilIndex,
3614 : SpeedNum,
3615 27 : MSHeatPump.fanOp,
3616 : compressorOp);
3617 27 : SavePartloadRatio = PartLoadFrac;
3618 27 : SaveSpeedRatio = SpeedRatio;
3619 : } else {
3620 0 : DXCoils::SimDXCoilMultiSpeed(
3621 0 : state, MSHeatPump.DXCoolCoilName, 0.0, 0.0, MSHeatPump.DXCoolCoilIndex, SpeedNum, MSHeatPump.fanOp, compressorOp);
3622 : }
3623 27 : state.dataHVACMultiSpdHP->SaveCompressorPLR = state.dataDXCoils->DXCoilPartLoadRatio(MSHeatPump.DXCoolCoilIndex);
3624 : } else {
3625 93 : DXCoils::SimDXCoilMultiSpeed(
3626 62 : state, MSHeatPump.DXCoolCoilName, 0.0, 0.0, MSHeatPump.DXCoolCoilIndex, SpeedNum, MSHeatPump.fanOp, compressorOp);
3627 : }
3628 58 : if (MSHeatPump.HeatCoilType == MultiSpeedHeatingCoil) {
3629 58 : if (QZnReq > HVAC::SmallLoad) {
3630 29 : if (OutsideDryBulbTemp > MSHeatPump.MinOATCompressorHeating) {
3631 87 : DXCoils::SimDXCoilMultiSpeed(state,
3632 : MSHeatPump.DXHeatCoilName,
3633 : SpeedRatio,
3634 : PartLoadFrac,
3635 29 : MSHeatPump.DXHeatCoilIndex,
3636 : SpeedNum,
3637 29 : MSHeatPump.fanOp,
3638 : compressorOp);
3639 29 : SavePartloadRatio = PartLoadFrac;
3640 29 : SaveSpeedRatio = SpeedRatio;
3641 : } else {
3642 0 : DXCoils::SimDXCoilMultiSpeed(
3643 0 : state, MSHeatPump.DXHeatCoilName, 0.0, 0.0, MSHeatPump.DXHeatCoilIndex, SpeedNum, MSHeatPump.fanOp, compressorOp);
3644 : }
3645 29 : state.dataHVACMultiSpdHP->SaveCompressorPLR = state.dataDXCoils->DXCoilPartLoadRatio(MSHeatPump.DXHeatCoilIndex);
3646 : } else {
3647 87 : DXCoils::SimDXCoilMultiSpeed(
3648 58 : state, MSHeatPump.DXHeatCoilName, 0.0, 0.0, MSHeatPump.DXHeatCoilIndex, SpeedNum, MSHeatPump.fanOp, compressorOp);
3649 : }
3650 0 : } else if (MSHeatPump.HeatCoilType == HVAC::Coil_HeatingElectric_MultiStage ||
3651 0 : MSHeatPump.HeatCoilType == HVAC::Coil_HeatingGas_MultiStage) {
3652 0 : if (QZnReq > HVAC::SmallLoad) {
3653 0 : HeatingCoils::SimulateHeatingCoilComponents(
3654 0 : state, MSHeatPump.HeatCoilName, FirstHVACIteration, _, 0, _, _, MSHeatPump.fanOp, PartLoadFrac, SpeedNum, SpeedRatio);
3655 : } else {
3656 0 : HeatingCoils::SimulateHeatingCoilComponents(
3657 0 : state, MSHeatPump.HeatCoilName, FirstHVACIteration, _, 0, _, _, MSHeatPump.fanOp, 0.0, SpeedNum, 0.0);
3658 : }
3659 : } else {
3660 0 : CalcNonDXHeatingCoils(state, MSHeatPumpNum, FirstHVACIteration, QZnReq, MSHeatPump.fanOp, QCoilActual, PartLoadFrac);
3661 : }
3662 : // Call twice to ensure the fan outlet conditions are updated
3663 58 : state.dataFans->fans(MSHeatPump.FanNum)->simulate(state, FirstHVACIteration, state.dataHVACMultiSpdHP->FanSpeedRatio);
3664 58 : if (QZnReq < (-1.0 * HVAC::SmallLoad)) {
3665 27 : if (OutsideDryBulbTemp > MSHeatPump.MinOATCompressorCooling) {
3666 81 : DXCoils::SimDXCoilMultiSpeed(state,
3667 : MSHeatPump.DXCoolCoilName,
3668 : SpeedRatio,
3669 : PartLoadFrac,
3670 27 : MSHeatPump.DXCoolCoilIndex,
3671 : SpeedNum,
3672 27 : MSHeatPump.fanOp,
3673 : compressorOp);
3674 27 : SavePartloadRatio = PartLoadFrac;
3675 27 : SaveSpeedRatio = SpeedRatio;
3676 : } else {
3677 0 : DXCoils::SimDXCoilMultiSpeed(
3678 0 : state, MSHeatPump.DXCoolCoilName, 0.0, 0.0, MSHeatPump.DXCoolCoilIndex, SpeedNum, MSHeatPump.fanOp, compressorOp);
3679 : }
3680 27 : state.dataHVACMultiSpdHP->SaveCompressorPLR = state.dataDXCoils->DXCoilPartLoadRatio(MSHeatPump.DXCoolCoilIndex);
3681 : } else {
3682 93 : DXCoils::SimDXCoilMultiSpeed(
3683 62 : state, MSHeatPump.DXCoolCoilName, 0.0, 0.0, MSHeatPump.DXCoolCoilIndex, SpeedNum, MSHeatPump.fanOp, compressorOp);
3684 : }
3685 58 : if (MSHeatPump.HeatCoilType == MultiSpeedHeatingCoil) {
3686 58 : if (QZnReq > HVAC::SmallLoad) {
3687 29 : if (OutsideDryBulbTemp > MSHeatPump.MinOATCompressorHeating) {
3688 87 : DXCoils::SimDXCoilMultiSpeed(state,
3689 : MSHeatPump.DXHeatCoilName,
3690 : SpeedRatio,
3691 : PartLoadFrac,
3692 29 : MSHeatPump.DXHeatCoilIndex,
3693 : SpeedNum,
3694 29 : MSHeatPump.fanOp,
3695 : compressorOp);
3696 29 : SavePartloadRatio = PartLoadFrac;
3697 29 : SaveSpeedRatio = SpeedRatio;
3698 : } else {
3699 0 : DXCoils::SimDXCoilMultiSpeed(
3700 0 : state, MSHeatPump.DXHeatCoilName, 0.0, 0.0, MSHeatPump.DXHeatCoilIndex, SpeedNum, MSHeatPump.fanOp, compressorOp);
3701 : }
3702 29 : state.dataHVACMultiSpdHP->SaveCompressorPLR = state.dataDXCoils->DXCoilPartLoadRatio(MSHeatPump.DXHeatCoilIndex);
3703 : } else {
3704 87 : DXCoils::SimDXCoilMultiSpeed(
3705 58 : state, MSHeatPump.DXHeatCoilName, 0.0, 0.0, MSHeatPump.DXHeatCoilIndex, SpeedNum, MSHeatPump.fanOp, compressorOp);
3706 : }
3707 0 : } else if (MSHeatPump.HeatCoilType == HVAC::Coil_HeatingElectric_MultiStage ||
3708 0 : MSHeatPump.HeatCoilType == HVAC::Coil_HeatingGas_MultiStage) {
3709 0 : if (QZnReq > HVAC::SmallLoad) {
3710 0 : HeatingCoils::SimulateHeatingCoilComponents(
3711 0 : state, MSHeatPump.HeatCoilName, FirstHVACIteration, _, 0, _, _, MSHeatPump.fanOp, PartLoadFrac, SpeedNum, SpeedRatio);
3712 : } else {
3713 0 : HeatingCoils::SimulateHeatingCoilComponents(
3714 0 : state, MSHeatPump.HeatCoilName, FirstHVACIteration, _, 0, _, _, MSHeatPump.fanOp, 0.0, SpeedNum, 0.0);
3715 : }
3716 : } else {
3717 0 : CalcNonDXHeatingCoils(state, MSHeatPumpNum, FirstHVACIteration, QZnReq, MSHeatPump.fanOp, QCoilActual, PartLoadFrac);
3718 : }
3719 : // Simulate supplemental heating coil for blow through fan
3720 58 : if (MSHeatPump.SuppHeatCoilNum > 0) {
3721 58 : CalcNonDXHeatingCoils(state, MSHeatPumpNum, FirstHVACIteration, SupHeaterLoad, MSHeatPump.fanOp, QCoilActual);
3722 : }
3723 : } else { // otherwise simulate DX coils then fan then supplemental heater
3724 0 : if (QZnReq < (-1.0 * HVAC::SmallLoad)) {
3725 0 : if (OutsideDryBulbTemp > MSHeatPump.MinOATCompressorCooling) {
3726 0 : DXCoils::SimDXCoilMultiSpeed(state,
3727 : MSHeatPump.DXCoolCoilName,
3728 : SpeedRatio,
3729 : PartLoadFrac,
3730 0 : MSHeatPump.DXCoolCoilIndex,
3731 : SpeedNum,
3732 0 : MSHeatPump.fanOp,
3733 : compressorOp);
3734 0 : SavePartloadRatio = PartLoadFrac;
3735 0 : SaveSpeedRatio = SpeedRatio;
3736 : } else {
3737 0 : DXCoils::SimDXCoilMultiSpeed(
3738 0 : state, MSHeatPump.DXCoolCoilName, 0.0, 0.0, MSHeatPump.DXCoolCoilIndex, SpeedNum, MSHeatPump.fanOp, compressorOp);
3739 : }
3740 0 : state.dataHVACMultiSpdHP->SaveCompressorPLR = state.dataDXCoils->DXCoilPartLoadRatio(MSHeatPump.DXCoolCoilIndex);
3741 : } else {
3742 0 : DXCoils::SimDXCoilMultiSpeed(
3743 0 : state, MSHeatPump.DXCoolCoilName, 0.0, 0.0, MSHeatPump.DXCoolCoilIndex, SpeedNum, MSHeatPump.fanOp, compressorOp);
3744 : }
3745 0 : if (MSHeatPump.HeatCoilType == MultiSpeedHeatingCoil) {
3746 0 : if (QZnReq > HVAC::SmallLoad) {
3747 0 : if (OutsideDryBulbTemp > MSHeatPump.MinOATCompressorHeating) {
3748 0 : DXCoils::SimDXCoilMultiSpeed(state,
3749 : MSHeatPump.DXHeatCoilName,
3750 : SpeedRatio,
3751 : PartLoadFrac,
3752 0 : MSHeatPump.DXHeatCoilIndex,
3753 : SpeedNum,
3754 0 : MSHeatPump.fanOp,
3755 : compressorOp);
3756 0 : SavePartloadRatio = PartLoadFrac;
3757 0 : SaveSpeedRatio = SpeedRatio;
3758 : } else {
3759 0 : DXCoils::SimDXCoilMultiSpeed(
3760 0 : state, MSHeatPump.DXHeatCoilName, 0.0, 0.0, MSHeatPump.DXHeatCoilIndex, SpeedNum, MSHeatPump.fanOp, compressorOp);
3761 : }
3762 0 : state.dataHVACMultiSpdHP->SaveCompressorPLR = state.dataDXCoils->DXCoilPartLoadRatio(MSHeatPump.DXHeatCoilIndex);
3763 : } else {
3764 0 : DXCoils::SimDXCoilMultiSpeed(
3765 0 : state, MSHeatPump.DXHeatCoilName, 0.0, 0.0, MSHeatPump.DXHeatCoilIndex, SpeedNum, MSHeatPump.fanOp, compressorOp);
3766 : }
3767 0 : } else if (MSHeatPump.HeatCoilType == HVAC::Coil_HeatingElectric_MultiStage ||
3768 0 : MSHeatPump.HeatCoilType == HVAC::Coil_HeatingGas_MultiStage) {
3769 0 : if (QZnReq > HVAC::SmallLoad) {
3770 0 : HeatingCoils::SimulateHeatingCoilComponents(
3771 0 : state, MSHeatPump.HeatCoilName, FirstHVACIteration, _, 0, _, _, MSHeatPump.fanOp, PartLoadFrac, SpeedNum, SpeedRatio);
3772 : } else {
3773 0 : HeatingCoils::SimulateHeatingCoilComponents(
3774 0 : state, MSHeatPump.HeatCoilName, FirstHVACIteration, _, 0, _, _, MSHeatPump.fanOp, 0.0, SpeedNum, 0.0);
3775 : }
3776 : } else {
3777 0 : CalcNonDXHeatingCoils(state, MSHeatPumpNum, FirstHVACIteration, QZnReq, MSHeatPump.fanOp, QCoilActual, PartLoadFrac);
3778 : }
3779 0 : state.dataFans->fans(MSHeatPump.FanNum)->simulate(state, FirstHVACIteration, state.dataHVACMultiSpdHP->FanSpeedRatio);
3780 : // Simulate supplemental heating coil for draw through fan
3781 0 : if (MSHeatPump.SuppHeatCoilNum > 0) {
3782 0 : CalcNonDXHeatingCoils(state, MSHeatPumpNum, FirstHVACIteration, SupHeaterLoad, MSHeatPump.fanOp, QCoilActual);
3783 : }
3784 : }
3785 :
3786 : // calculate sensible load met
3787 58 : Real64 SensibleOutput(0.0); // sensible output rate
3788 : // calculate sensible load met using delta enthalpy at a constant (minimum) humidity ratio)
3789 58 : Real64 MinHumRat = state.dataLoopNodes->Node(MSHeatPump.NodeNumOfControlledZone).HumRat;
3790 58 : if (state.dataLoopNodes->Node(OutletNode).Temp < state.dataLoopNodes->Node(MSHeatPump.NodeNumOfControlledZone).Temp)
3791 22 : MinHumRat = state.dataLoopNodes->Node(OutletNode).HumRat;
3792 58 : SensibleOutput = AirMassFlow * Psychrometrics::PsyDeltaHSenFnTdb2W2Tdb1W1(state.dataLoopNodes->Node(OutletNode).Temp,
3793 : MinHumRat,
3794 58 : state.dataLoopNodes->Node(MSHeatPump.NodeNumOfControlledZone).Temp,
3795 : MinHumRat);
3796 58 : LoadMet = SensibleOutput - MSHeatPump.LoadLoss;
3797 :
3798 58 : MSHeatPump.LoadMet = LoadMet;
3799 58 : }
3800 :
3801 0 : void UpdateMSHeatPump(EnergyPlusData &state, int const MSHeatPumpNum) // Engine driven heat pump number
3802 : {
3803 : // SUBROUTINE INFORMATION:
3804 : // AUTHOR: Lixing Gu, FSEC
3805 : // DATE WRITTEN: June 2007
3806 :
3807 : // PURPOSE OF THIS SUBROUTINE:
3808 : // This routine will update MSHP performance and calculate heat recovery rate and crankcase heater power
3809 :
3810 : // Calculate heat recovery
3811 0 : if (state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).HeatRecActive) {
3812 0 : MSHPHeatRecovery(state, MSHeatPumpNum);
3813 : }
3814 :
3815 0 : if (state.afn->distribution_simulated) {
3816 0 : state.dataAirLoop->AirLoopAFNInfo(state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).AirLoopNumber).LoopSystemOnMassFlowrate =
3817 0 : state.dataHVACMultiSpdHP->CompOnMassFlow;
3818 0 : state.dataAirLoop->AirLoopAFNInfo(state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).AirLoopNumber).LoopSystemOffMassFlowrate =
3819 0 : state.dataHVACMultiSpdHP->CompOffMassFlow;
3820 0 : state.dataAirLoop->AirLoopAFNInfo(state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).AirLoopNumber).LoopFanOperationMode =
3821 0 : state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).fanOp;
3822 0 : state.dataAirLoop->AirLoopAFNInfo(state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).AirLoopNumber).LoopOnOffFanPartLoadRatio =
3823 0 : state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).FanPartLoadRatio;
3824 0 : state.dataAirLoop->AirLoopAFNInfo(state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).AirLoopNumber).LoopCompCycRatio =
3825 0 : state.dataHVACMultiSpdHP->MSHeatPumpReport(MSHeatPumpNum).CycRatio;
3826 : }
3827 0 : }
3828 :
3829 : //******************************************************************************
3830 :
3831 0 : void ReportMSHeatPump(EnergyPlusData &state, int const MSHeatPumpNum) // Engine driven heat pump number
3832 : {
3833 : // SUBROUTINE INFORMATION:
3834 : // AUTHOR: Lixing Gu, FSEC
3835 : // DATE WRITTEN: June 2007
3836 :
3837 : // PURPOSE OF THIS SUBROUTINE:
3838 : // This routine will write values to output variables in MSHP
3839 :
3840 0 : Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
3841 :
3842 0 : auto &MSHeatPump = state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum);
3843 0 : auto &MSHeatPumpReport = state.dataHVACMultiSpdHP->MSHeatPumpReport(MSHeatPumpNum);
3844 :
3845 0 : MSHeatPumpReport.ElecPowerConsumption = MSHeatPump.ElecPower * TimeStepSysSec; // + &
3846 0 : MSHeatPumpReport.HeatRecoveryEnergy = MSHeatPump.HeatRecoveryRate * TimeStepSysSec;
3847 :
3848 0 : MSHeatPumpReport.AuxElecHeatConsumption = 0.0;
3849 0 : MSHeatPumpReport.AuxElecCoolConsumption = 0.0;
3850 :
3851 0 : MSHeatPump.AuxElecPower = MSHeatPump.AuxOnCyclePower * state.dataHVACMultiSpdHP->SaveCompressorPLR +
3852 0 : MSHeatPump.AuxOffCyclePower * (1.0 - state.dataHVACMultiSpdHP->SaveCompressorPLR);
3853 0 : if (MSHeatPump.HeatCoolMode == ModeOfOperation::CoolingMode) {
3854 0 : MSHeatPumpReport.AuxElecCoolConsumption = MSHeatPump.AuxOnCyclePower * state.dataHVACMultiSpdHP->SaveCompressorPLR * TimeStepSysSec;
3855 : }
3856 0 : if (MSHeatPump.HeatCoolMode == ModeOfOperation::HeatingMode) {
3857 0 : MSHeatPumpReport.AuxElecHeatConsumption = MSHeatPump.AuxOnCyclePower * state.dataHVACMultiSpdHP->SaveCompressorPLR * TimeStepSysSec;
3858 : }
3859 0 : if (MSHeatPump.LastMode == ModeOfOperation::HeatingMode) {
3860 0 : MSHeatPumpReport.AuxElecHeatConsumption +=
3861 0 : MSHeatPump.AuxOffCyclePower * (1.0 - state.dataHVACMultiSpdHP->SaveCompressorPLR) * TimeStepSysSec;
3862 : } else {
3863 0 : MSHeatPumpReport.AuxElecCoolConsumption +=
3864 0 : MSHeatPump.AuxOffCyclePower * (1.0 - state.dataHVACMultiSpdHP->SaveCompressorPLR) * TimeStepSysSec;
3865 : }
3866 :
3867 0 : if (MSHeatPump.FirstPass) {
3868 0 : if (!state.dataGlobal->SysSizingCalc) {
3869 0 : DataSizing::resetHVACSizingGlobals(state, state.dataSize->CurZoneEqNum, state.dataSize->CurSysNum, MSHeatPump.FirstPass);
3870 : }
3871 : }
3872 :
3873 : // reset to 1 in case blow through fan configuration (fan resets to 1, but for blow thru fans coil sets back down < 1)
3874 0 : state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
3875 0 : }
3876 :
3877 3 : void MSHPHeatRecovery(EnergyPlusData &state, int const MSHeatPumpNum) // Number of the current electric MSHP being simulated
3878 : {
3879 : // SUBROUTINE INFORMATION:
3880 : // AUTHOR: Lixing Gu
3881 : // DATE WRITTEN: June 2007
3882 : // RE-ENGINEERED Revised to calculate MSHP heat recovery rate based on EIR Chiller heat recovery subroutine
3883 : // PURPOSE OF THIS SUBROUTINE:
3884 : // Calculate the heat recovered from MSHP
3885 :
3886 : // SUBROUTINE PARAMETER DEFINITIONS:
3887 : static constexpr std::string_view RoutineName("MSHPHeatRecovery");
3888 :
3889 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3890 : Real64 HeatRecOutletTemp; // Heat reclaim outlet temp [C]
3891 :
3892 3 : auto &mshp = state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum);
3893 : // Begin routine
3894 3 : int HeatRecInNode = mshp.HeatRecInletNodeNum;
3895 3 : int HeatRecOutNode = mshp.HeatRecOutletNodeNum;
3896 :
3897 : // Inlet node to the heat recovery heat exchanger
3898 3 : Real64 HeatRecInletTemp = state.dataLoopNodes->Node(HeatRecInNode).Temp;
3899 :
3900 : // Set heat recovery mass flow rates
3901 3 : Real64 HeatRecMassFlowRate = state.dataLoopNodes->Node(HeatRecInNode).MassFlowRate;
3902 :
3903 3 : Real64 QHeatRec = state.dataHVACGlobal->MSHPWasteHeat;
3904 :
3905 3 : if (HeatRecMassFlowRate > 0.0) {
3906 : // Heat reclaim water inlet specific heat [J/kg-K]
3907 2 : Real64 CpHeatRec = state.dataPlnt->PlantLoop(mshp.HRPlantLoc.loopNum).glycol->getSpecificHeat(state, HeatRecInletTemp, RoutineName);
3908 :
3909 2 : HeatRecOutletTemp = QHeatRec / (HeatRecMassFlowRate * CpHeatRec) + HeatRecInletTemp;
3910 2 : if (HeatRecOutletTemp > mshp.MaxHeatRecOutletTemp) {
3911 1 : HeatRecOutletTemp = max(HeatRecInletTemp, mshp.MaxHeatRecOutletTemp);
3912 1 : QHeatRec = HeatRecMassFlowRate * CpHeatRec * (HeatRecOutletTemp - HeatRecInletTemp);
3913 : }
3914 : } else {
3915 1 : HeatRecOutletTemp = HeatRecInletTemp;
3916 1 : QHeatRec = 0.0;
3917 : }
3918 :
3919 3 : PlantUtilities::SafeCopyPlantNode(state, HeatRecInNode, HeatRecOutNode);
3920 : // changed outputs
3921 3 : state.dataLoopNodes->Node(HeatRecOutNode).Temp = HeatRecOutletTemp;
3922 :
3923 3 : mshp.HeatRecoveryRate = QHeatRec;
3924 3 : mshp.HeatRecoveryInletTemp = HeatRecInletTemp;
3925 3 : mshp.HeatRecoveryOutletTemp = HeatRecOutletTemp;
3926 3 : mshp.HeatRecoveryMassFlowRate = HeatRecMassFlowRate;
3927 3 : }
3928 :
3929 60 : void SetAverageAirFlow(EnergyPlusData &state,
3930 : int const MSHeatPumpNum, // Unit index
3931 : Real64 const PartLoadRatio, // unit part load ratio
3932 : Real64 &OnOffAirFlowRatio, // ratio of compressor ON airflow to average airflow over timestep
3933 : ObjexxFCL::Optional_int_const SpeedNum, // Speed number
3934 : ObjexxFCL::Optional<Real64 const> SpeedRatio // Speed ratio
3935 : )
3936 : {
3937 :
3938 : // SUBROUTINE INFORMATION:
3939 : // AUTHOR Lixing
3940 : // DATE WRITTEN June 2007
3941 : // RE-ENGINEERED Resived to meet requirements of multispeed heat pump based on the same subroutine
3942 : // in PTHP module
3943 :
3944 : // PURPOSE OF THIS SUBROUTINE:
3945 : // Set the average air mass flow rates using the part load fraction of the heat pump for this time step
3946 : // Set OnOffAirFlowRatio to be used by DX coils
3947 :
3948 : // Using/Aliasing
3949 60 : auto &MSHPMassFlowRateHigh = state.dataHVACGlobal->MSHPMassFlowRateHigh;
3950 60 : auto &MSHPMassFlowRateLow = state.dataHVACGlobal->MSHPMassFlowRateLow;
3951 :
3952 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3953 : int InletNode; // inlet node number for PTHPNum
3954 : Real64 AverageUnitMassFlow; // average supply air mass flow rate over time step
3955 :
3956 60 : MSHPMassFlowRateLow = 0.0; // Mass flow rate at low speed
3957 60 : MSHPMassFlowRateHigh = 0.0; // Mass flow rate at high speed
3958 :
3959 120 : if (!state.dataZoneEnergyDemand->CurDeadBandOrSetback(state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).ControlZoneNum) &&
3960 60 : present(SpeedNum)) {
3961 58 : if (state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).HeatCoolMode == ModeOfOperation::HeatingMode) {
3962 31 : if (SpeedNum == 1) {
3963 21 : state.dataHVACMultiSpdHP->CompOnMassFlow = state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).HeatMassFlowRate(SpeedNum);
3964 21 : state.dataHVACMultiSpdHP->CompOnFlowRatio = state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).HeatingSpeedRatio(SpeedNum);
3965 21 : MSHPMassFlowRateLow = state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).HeatMassFlowRate(1);
3966 21 : MSHPMassFlowRateHigh = state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).HeatMassFlowRate(1);
3967 10 : } else if (SpeedNum > 1) {
3968 20 : state.dataHVACMultiSpdHP->CompOnMassFlow =
3969 10 : SpeedRatio * state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).HeatMassFlowRate(SpeedNum) +
3970 10 : (1.0 - SpeedRatio) * state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).HeatMassFlowRate(SpeedNum - 1);
3971 20 : state.dataHVACMultiSpdHP->CompOnFlowRatio =
3972 10 : SpeedRatio * state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).HeatingSpeedRatio(SpeedNum) +
3973 10 : (1.0 - SpeedRatio) * state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).HeatingSpeedRatio(SpeedNum - 1);
3974 10 : MSHPMassFlowRateLow = state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).HeatMassFlowRate(SpeedNum - 1);
3975 10 : MSHPMassFlowRateHigh = state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).HeatMassFlowRate(SpeedNum);
3976 : }
3977 27 : } else if (state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).HeatCoolMode == ModeOfOperation::CoolingMode) {
3978 27 : if (SpeedNum == 1) {
3979 23 : state.dataHVACMultiSpdHP->CompOnMassFlow = state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).CoolMassFlowRate(SpeedNum);
3980 23 : state.dataHVACMultiSpdHP->CompOnFlowRatio = state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).CoolingSpeedRatio(SpeedNum);
3981 23 : MSHPMassFlowRateLow = state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).CoolMassFlowRate(1);
3982 23 : MSHPMassFlowRateHigh = state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).CoolMassFlowRate(1);
3983 4 : } else if (SpeedNum > 1) {
3984 8 : state.dataHVACMultiSpdHP->CompOnMassFlow =
3985 4 : SpeedRatio * state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).CoolMassFlowRate(SpeedNum) +
3986 4 : (1.0 - SpeedRatio) * state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).CoolMassFlowRate(SpeedNum - 1);
3987 8 : state.dataHVACMultiSpdHP->CompOnFlowRatio =
3988 4 : SpeedRatio * state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).CoolingSpeedRatio(SpeedNum) +
3989 4 : (1.0 - SpeedRatio) * state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).CoolingSpeedRatio(SpeedNum - 1);
3990 4 : MSHPMassFlowRateLow = state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).CoolMassFlowRate(SpeedNum - 1);
3991 4 : MSHPMassFlowRateHigh = state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).CoolMassFlowRate(SpeedNum);
3992 : }
3993 : }
3994 : }
3995 60 : InletNode = state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).AirInletNodeNum;
3996 :
3997 : // Set up fan flow rate during compressor off time
3998 60 : if (state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).fanOp == HVAC::FanOp::Continuous && present(SpeedNum)) {
3999 58 : if (state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).AirFlowControl == AirflowControl::UseCompressorOnFlow &&
4000 0 : state.dataHVACMultiSpdHP->CompOnMassFlow > 0.0) {
4001 0 : if (state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).LastMode == ModeOfOperation::HeatingMode) {
4002 0 : state.dataHVACMultiSpdHP->CompOffMassFlow = state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).HeatMassFlowRate(SpeedNum);
4003 0 : state.dataHVACMultiSpdHP->CompOffFlowRatio = state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).HeatingSpeedRatio(SpeedNum);
4004 : } else {
4005 0 : state.dataHVACMultiSpdHP->CompOffMassFlow = state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).CoolMassFlowRate(SpeedNum);
4006 0 : state.dataHVACMultiSpdHP->CompOffFlowRatio = state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).CoolingSpeedRatio(SpeedNum);
4007 : }
4008 : }
4009 : }
4010 :
4011 60 : if (present(SpeedNum)) {
4012 58 : if (SpeedNum > 1) {
4013 14 : AverageUnitMassFlow = state.dataHVACMultiSpdHP->CompOnMassFlow;
4014 14 : state.dataHVACMultiSpdHP->FanSpeedRatio = state.dataHVACMultiSpdHP->CompOnFlowRatio;
4015 : } else {
4016 44 : AverageUnitMassFlow =
4017 44 : (PartLoadRatio * state.dataHVACMultiSpdHP->CompOnMassFlow) + ((1 - PartLoadRatio) * state.dataHVACMultiSpdHP->CompOffMassFlow);
4018 44 : if (state.dataHVACMultiSpdHP->CompOffFlowRatio > 0.0) {
4019 88 : state.dataHVACMultiSpdHP->FanSpeedRatio = (PartLoadRatio * state.dataHVACMultiSpdHP->CompOnFlowRatio) +
4020 44 : ((1 - PartLoadRatio) * state.dataHVACMultiSpdHP->CompOffFlowRatio);
4021 : } else {
4022 0 : state.dataHVACMultiSpdHP->FanSpeedRatio = state.dataHVACMultiSpdHP->CompOnFlowRatio;
4023 : }
4024 : }
4025 : } else {
4026 2 : AverageUnitMassFlow =
4027 2 : (PartLoadRatio * state.dataHVACMultiSpdHP->CompOnMassFlow) + ((1 - PartLoadRatio) * state.dataHVACMultiSpdHP->CompOffMassFlow);
4028 2 : if (state.dataHVACMultiSpdHP->CompOffFlowRatio > 0.0) {
4029 2 : state.dataHVACMultiSpdHP->FanSpeedRatio =
4030 2 : (PartLoadRatio * state.dataHVACMultiSpdHP->CompOnFlowRatio) + ((1 - PartLoadRatio) * state.dataHVACMultiSpdHP->CompOffFlowRatio);
4031 : } else {
4032 0 : state.dataHVACMultiSpdHP->FanSpeedRatio = state.dataHVACMultiSpdHP->CompOnFlowRatio;
4033 : }
4034 : }
4035 :
4036 : //!!LKL Discrepancy with > 0
4037 60 : if (state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum).availSched->getCurrentVal() == 0.0) {
4038 0 : state.dataLoopNodes->Node(InletNode).MassFlowRate = 0.0;
4039 0 : OnOffAirFlowRatio = 0.0;
4040 : } else {
4041 60 : state.dataLoopNodes->Node(InletNode).MassFlowRate = AverageUnitMassFlow;
4042 60 : state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail = AverageUnitMassFlow;
4043 60 : if (AverageUnitMassFlow > 0.0) {
4044 60 : OnOffAirFlowRatio = state.dataHVACMultiSpdHP->CompOnMassFlow / AverageUnitMassFlow;
4045 : } else {
4046 0 : OnOffAirFlowRatio = 0.0;
4047 : }
4048 : }
4049 60 : }
4050 :
4051 58 : void CalcNonDXHeatingCoils(EnergyPlusData &state,
4052 : int const MSHeatPumpNum, // multispeed heatpump index
4053 : bool const FirstHVACIteration, // flag for first HVAC iteration in the time step
4054 : Real64 const HeatingLoad, // supplemental coil load to be met by unit (watts)
4055 : HVAC::FanOp const fanOp, // fan operation mode
4056 : Real64 &HeatCoilLoadmet, // Heating Load Met
4057 : ObjexxFCL::Optional<Real64 const> PartLoadFrac)
4058 : {
4059 :
4060 : // SUBROUTINE INFORMATION:
4061 : // AUTHOR Bereket Nigusse, FSEC/UCF
4062 : // DATE WRITTEN January 2012
4063 :
4064 : // PURPOSE OF THIS SUBROUTINE:
4065 : // This subroutine simulates the four non dx heating coil types: Gas, Electric, hot water and steam.
4066 :
4067 : // METHODOLOGY EMPLOYED:
4068 : // Simply calls the different heating coil component. The hot water flow rate matching the coil load
4069 : // is calculated iteratively.
4070 :
4071 : // Locals
4072 : static constexpr std::string_view CurrentModuleObject("AirLoopHVAC:UnitaryHeatPump:AirToAir:MultiSpeed");
4073 :
4074 : // SUBROUTINE PARAMETER DEFINITIONS:
4075 58 : Real64 constexpr ErrTolerance(0.001); // convergence limit for hotwater coil
4076 58 : int constexpr SolveMaxIter(50);
4077 :
4078 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4079 : Real64 QCoilActual; // actual heating load met
4080 : Real64 mdot; // heating coil steam or hot water mass flow rate
4081 : Real64 MinWaterFlow; // coil minimum hot water mass flow rate, kg/s
4082 : Real64 MaxHotWaterFlow; // coil maximum hot water mass flow rate, kg/s
4083 : Real64 HotWaterMdot; // actual hot water mass flow rate
4084 :
4085 : int HeatCoilType;
4086 : int HeatCoilNum;
4087 : Real64 MaxCoilFluidFlow;
4088 : Real64 SteamCoilHeatingLoad;
4089 : int CoilControlNode;
4090 : int CoilOutletNode;
4091 58 : PlantLocation plantLoc{};
4092 :
4093 58 : QCoilActual = 0.0;
4094 :
4095 58 : auto &MSHeatPump = state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum);
4096 :
4097 58 : if (present(PartLoadFrac)) {
4098 0 : HeatCoilType = MSHeatPump.HeatCoilType;
4099 0 : state.dataHVACMultiSpdHP->HeatCoilName = MSHeatPump.HeatCoilName;
4100 0 : HeatCoilNum = MSHeatPump.HeatCoilNum;
4101 0 : MaxCoilFluidFlow = MSHeatPump.MaxCoilFluidFlow;
4102 0 : CoilControlNode = MSHeatPump.CoilControlNode;
4103 0 : CoilOutletNode = MSHeatPump.CoilOutletNode;
4104 0 : plantLoc = MSHeatPump.plantLoc;
4105 : } else {
4106 58 : HeatCoilType = MSHeatPump.SuppHeatCoilType;
4107 58 : state.dataHVACMultiSpdHP->HeatCoilName = MSHeatPump.SuppHeatCoilName;
4108 58 : HeatCoilNum = MSHeatPump.SuppHeatCoilNum;
4109 58 : MaxCoilFluidFlow = MSHeatPump.MaxSuppCoilFluidFlow;
4110 58 : CoilControlNode = MSHeatPump.SuppCoilControlNode;
4111 58 : CoilOutletNode = MSHeatPump.SuppCoilOutletNode;
4112 58 : plantLoc = MSHeatPump.SuppPlantLoc;
4113 : }
4114 :
4115 58 : MSHeatPump.HotWaterPlantLoc = plantLoc;
4116 58 : MSHeatPump.HotWaterCoilControlNode = CoilControlNode;
4117 58 : MSHeatPump.HotWaterCoilOutletNode = CoilOutletNode;
4118 58 : MSHeatPump.HotWaterCoilName = state.dataHVACMultiSpdHP->HeatCoilName;
4119 58 : MSHeatPump.HotWaterCoilNum = HeatCoilNum;
4120 :
4121 58 : if (HeatingLoad > HVAC::SmallLoad) {
4122 :
4123 6 : switch (HeatCoilType) {
4124 6 : case SuppHeatingCoilGas:
4125 : case SuppHeatingCoilElec: {
4126 24 : HeatingCoils::SimulateHeatingCoilComponents(
4127 18 : state, state.dataHVACMultiSpdHP->HeatCoilName, FirstHVACIteration, HeatingLoad, HeatCoilNum, QCoilActual, true, fanOp);
4128 6 : } break;
4129 0 : case HVAC::Coil_HeatingWater: {
4130 0 : if (present(PartLoadFrac)) {
4131 0 : MaxHotWaterFlow = MaxCoilFluidFlow * PartLoadFrac;
4132 0 : PlantUtilities::SetComponentFlowRate(state, MaxHotWaterFlow, CoilControlNode, CoilOutletNode, plantLoc);
4133 0 : WaterCoils::SimulateWaterCoilComponents(
4134 0 : state, state.dataHVACMultiSpdHP->HeatCoilName, FirstHVACIteration, HeatCoilNum, QCoilActual, fanOp);
4135 : } else {
4136 0 : MaxHotWaterFlow = MaxCoilFluidFlow;
4137 0 : PlantUtilities::SetComponentFlowRate(state, MaxHotWaterFlow, CoilControlNode, CoilOutletNode, plantLoc);
4138 0 : WaterCoils::SimulateWaterCoilComponents(
4139 0 : state, state.dataHVACMultiSpdHP->HeatCoilName, FirstHVACIteration, HeatCoilNum, QCoilActual, fanOp);
4140 0 : if (QCoilActual > (HeatingLoad + HVAC::SmallLoad)) {
4141 : // control water flow to obtain output matching HeatingLoad
4142 0 : int SolFlag = 0;
4143 0 : MinWaterFlow = 0.0;
4144 0 : auto f = [&state, MSHeatPumpNum, FirstHVACIteration, HeatingLoad](Real64 const HWFlow) {
4145 : // Calculates residual function (QCoilActual - SupHeatCoilLoad) / SupHeatCoilLoad
4146 : // coil actual output depends on the hot water flow rate which is varied to minimize the residual.
4147 0 : Real64 targetHeatingCoilLoad = HeatingLoad;
4148 0 : Real64 calcHeatingCoilLoad = targetHeatingCoilLoad;
4149 0 : Real64 mdot = HWFlow;
4150 0 : auto &hp = state.dataHVACMultiSpdHP->MSHeatPump(MSHeatPumpNum);
4151 0 : PlantUtilities::SetComponentFlowRate(
4152 0 : state, mdot, hp.HotWaterCoilControlNode, hp.HotWaterCoilOutletNode, hp.HotWaterPlantLoc);
4153 : // simulate the hot water supplemental heating coil
4154 0 : WaterCoils::SimulateWaterCoilComponents(
4155 0 : state, hp.HotWaterCoilName, FirstHVACIteration, hp.HotWaterCoilNum, calcHeatingCoilLoad, hp.fanOp);
4156 0 : if (targetHeatingCoilLoad != 0.0) {
4157 0 : return (calcHeatingCoilLoad - targetHeatingCoilLoad) / targetHeatingCoilLoad;
4158 : } else { // Autodesk:Return Condition added to assure return value is set
4159 0 : return 0.0;
4160 : }
4161 0 : };
4162 0 : General::SolveRoot(state, ErrTolerance, SolveMaxIter, SolFlag, HotWaterMdot, f, MinWaterFlow, MaxHotWaterFlow);
4163 0 : if (SolFlag == -1) {
4164 0 : if (MSHeatPump.HotWaterCoilMaxIterIndex == 0) {
4165 0 : ShowWarningMessage(state,
4166 0 : format("CalcNonDXHeatingCoils: Hot water coil control failed for {}=\"{}\"",
4167 : CurrentModuleObject,
4168 0 : MSHeatPump.Name));
4169 0 : ShowContinueErrorTimeStamp(state, "");
4170 0 : ShowContinueError(state,
4171 0 : format(" Iteration limit [{}] exceeded in calculating hot water mass flow rate", SolveMaxIter));
4172 : }
4173 0 : ShowRecurringWarningErrorAtEnd(
4174 : state,
4175 0 : format("CalcNonDXHeatingCoils: Hot water coil control failed (iteration limit [{}]) for {}=\"{}",
4176 : SolveMaxIter,
4177 : CurrentModuleObject,
4178 0 : MSHeatPump.Name),
4179 0 : MSHeatPump.HotWaterCoilMaxIterIndex);
4180 0 : } else if (SolFlag == -2) {
4181 0 : if (MSHeatPump.HotWaterCoilMaxIterIndex2 == 0) {
4182 0 : ShowWarningMessage(state,
4183 0 : format("CalcNonDXHeatingCoils: Hot water coil control failed (maximum flow limits) for {}=\"{}\"",
4184 : CurrentModuleObject,
4185 0 : MSHeatPump.Name));
4186 0 : ShowContinueErrorTimeStamp(state, "");
4187 0 : ShowContinueError(state, "...Bad hot water maximum flow rate limits");
4188 0 : ShowContinueError(state, format("...Given minimum water flow rate={:.3R} kg/s", MinWaterFlow));
4189 0 : ShowContinueError(state, format("...Given maximum water flow rate={:.3R} kg/s", MaxHotWaterFlow));
4190 : }
4191 0 : ShowRecurringWarningErrorAtEnd(state,
4192 0 : "CalcNonDXHeatingCoils: Hot water coil control failed (flow limits) for " +
4193 0 : std::string{CurrentModuleObject} + "=\"" + MSHeatPump.Name + "\"",
4194 0 : MSHeatPump.HotWaterCoilMaxIterIndex2,
4195 : MaxHotWaterFlow,
4196 : MinWaterFlow,
4197 : _,
4198 : "[kg/s]",
4199 : "[kg/s]");
4200 : }
4201 : // simulate hot water supplemental heating coil
4202 0 : WaterCoils::SimulateWaterCoilComponents(
4203 0 : state, state.dataHVACMultiSpdHP->HeatCoilName, FirstHVACIteration, HeatCoilNum, QCoilActual, fanOp);
4204 : }
4205 : }
4206 0 : } break;
4207 0 : case HVAC::Coil_HeatingSteam: {
4208 0 : if (present(PartLoadFrac)) {
4209 0 : mdot = MSHeatPump.MaxCoilFluidFlow * PartLoadFrac;
4210 0 : SteamCoilHeatingLoad = HeatingLoad * PartLoadFrac;
4211 : } else {
4212 0 : mdot = MSHeatPump.MaxCoilFluidFlow;
4213 0 : SteamCoilHeatingLoad = HeatingLoad;
4214 : }
4215 0 : PlantUtilities::SetComponentFlowRate(state, mdot, CoilControlNode, CoilOutletNode, plantLoc);
4216 : // simulate steam supplemental heating coil
4217 0 : SteamCoils::SimulateSteamCoilComponents(
4218 0 : state, state.dataHVACMultiSpdHP->HeatCoilName, FirstHVACIteration, HeatCoilNum, SteamCoilHeatingLoad, QCoilActual, fanOp);
4219 0 : } break;
4220 0 : default:
4221 0 : break;
4222 : }
4223 :
4224 : } else { // end of IF (HeatingLoad > SmallLoad) THEN
4225 :
4226 52 : switch (HeatCoilType) {
4227 52 : case SuppHeatingCoilGas:
4228 : case SuppHeatingCoilElec: {
4229 208 : HeatingCoils::SimulateHeatingCoilComponents(
4230 156 : state, state.dataHVACMultiSpdHP->HeatCoilName, FirstHVACIteration, HeatingLoad, HeatCoilNum, QCoilActual, true, fanOp);
4231 52 : } break;
4232 0 : case HVAC::Coil_HeatingWater: {
4233 0 : mdot = 0.0;
4234 0 : PlantUtilities::SetComponentFlowRate(state, mdot, CoilControlNode, CoilOutletNode, plantLoc);
4235 0 : WaterCoils::SimulateWaterCoilComponents(
4236 0 : state, state.dataHVACMultiSpdHP->HeatCoilName, FirstHVACIteration, HeatCoilNum, QCoilActual, fanOp);
4237 0 : } break;
4238 0 : case HVAC::Coil_HeatingSteam: {
4239 0 : mdot = 0.0;
4240 0 : PlantUtilities::SetComponentFlowRate(state, mdot, CoilControlNode, CoilOutletNode, plantLoc);
4241 : // simulate the steam supplemental heating coil
4242 0 : SteamCoils::SimulateSteamCoilComponents(
4243 0 : state, state.dataHVACMultiSpdHP->HeatCoilName, FirstHVACIteration, HeatCoilNum, HeatingLoad, QCoilActual, fanOp);
4244 0 : } break;
4245 0 : default:
4246 0 : break;
4247 : }
4248 : }
4249 58 : HeatCoilLoadmet = QCoilActual;
4250 58 : }
4251 :
4252 : } // namespace HVACMultiSpeedHeatPump
4253 :
4254 : } // namespace EnergyPlus
|