Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2023, 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 : // EnergyPlus Headers
52 : #include <EnergyPlus/BranchNodeConnections.hh>
53 : #include <EnergyPlus/DXCoils.hh>
54 : #include <EnergyPlus/Data/EnergyPlusData.hh>
55 : #include <EnergyPlus/DataAirLoop.hh>
56 : #include <EnergyPlus/DataHVACGlobals.hh>
57 : #include <EnergyPlus/DataLoopNode.hh>
58 : #include <EnergyPlus/EMSManager.hh>
59 : #include <EnergyPlus/FaultsManager.hh>
60 : #include <EnergyPlus/General.hh>
61 : #include <EnergyPlus/GeneralRoutines.hh>
62 : #include <EnergyPlus/HVACDXHeatPumpSystem.hh>
63 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
64 : #include <EnergyPlus/OutputProcessor.hh>
65 : #include <EnergyPlus/Psychrometrics.hh>
66 : #include <EnergyPlus/ScheduleManager.hh>
67 : #include <EnergyPlus/UtilityRoutines.hh>
68 : #include <EnergyPlus/VariableSpeedCoils.hh>
69 :
70 : namespace EnergyPlus {
71 :
72 : namespace HVACDXHeatPumpSystem {
73 : // Module containing the DXHeatPumpSystem simulation routines
74 :
75 : // MODULE INFORMATION:
76 : // AUTHOR Brent Griffith (derived by R.Liesen)
77 : // DATE WRITTEN May 2011
78 : // Feb 2013, Bo Shen, Oak Ridge National Lab
79 : // Add Coil:Heating:DX:VariableSpeed
80 : // RE-ENGINEERED na
81 :
82 : // PURPOSE OF THIS MODULE:
83 : // To encapsulate the data and algorithms required to
84 : // manage the DX Heat Pump System System Component
85 : // this wraps heat pump air-heating coils in coil-only wrapper with no fans.
86 :
87 : // METHODOLOGY EMPLOYED:
88 :
89 : // REFERENCES:
90 :
91 : // OTHER NOTES:
92 :
93 : // USE STATEMENTS:
94 : // Use statements for data only modules
95 : // Using/Aliasing
96 : using namespace DataLoopNode;
97 : using namespace DataHVACGlobals;
98 : using namespace ScheduleManager;
99 :
100 19316 : void SimDXHeatPumpSystem(EnergyPlusData &state,
101 : std::string_view DXHeatPumpSystemName, // Name of DXSystem:Airloop object
102 : bool const FirstHVACIteration, // True when first HVAC iteration
103 : int const AirLoopNum, // Primary air loop number
104 : int &CompIndex, // Index to CoilSystem:Heating:DX object
105 : Optional_int_const OAUnitNum, // If the system is an equipment of OutdoorAirUnit
106 : Optional<Real64 const> OAUCoilOutTemp, // the coil inlet temperature of OutdoorAirUnit
107 : Optional<Real64> QTotOut // the total cooling output of unit
108 : )
109 : {
110 :
111 : // SUBROUTINE INFORMATION:
112 : // AUTHOR Brent Griffith (derived by R.Liesen)
113 : // DATE WRITTEN May 2011
114 : // Feb 2013, Bo Shen, Oak Ridge National Lab
115 : // Add Coil:Heating:DX:VariableSpeed
116 :
117 : // RE-ENGINEERED na
118 :
119 : // PURPOSE OF THIS SUBROUTINE:
120 : // This subroutine manages DXHeatPumpSystem component simulation.
121 :
122 : // Using/Aliasing
123 : using DXCoils::SimDXCoil;
124 :
125 : using VariableSpeedCoils::SimVariableSpeedCoils;
126 :
127 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
128 38632 : std::string CompName; // Name of CoilSystem:Heating:DX object
129 : int DXSystemNum; // Index to CoilSystem:Heating:DX object
130 : Real64 AirMassFlow; // DX System air mass flow rate
131 : int InletNodeNum; // DX System inlet node number
132 : int OutletNodeNum; // DX System outlet node number
133 :
134 19316 : auto &NumDXHeatPumpSystems(state.dataHVACDXHeatPumpSys->NumDXHeatPumpSystems);
135 19316 : auto &DXHeatPumpSystem(state.dataHVACDXHeatPumpSys->DXHeatPumpSystem);
136 :
137 : // Obtains and Allocates DX Cooling System related parameters from input file
138 19316 : if (state.dataHVACDXHeatPumpSys->GetInputFlag) { // First time subroutine has been entered
139 : // Get the DXCoolingSystem input
140 3 : GetDXHeatPumpSystemInput(state);
141 3 : state.dataHVACDXHeatPumpSys->GetInputFlag = false;
142 : }
143 :
144 : // Find the correct DXSystemNumber
145 19316 : if (CompIndex == 0) {
146 11136 : DXSystemNum = UtilityRoutines::FindItemInList(DXHeatPumpSystemName, DXHeatPumpSystem);
147 11136 : if (DXSystemNum == 0) {
148 0 : ShowFatalError(state, "SimDXHeatPumpSystem: DXUnit not found=" + std::string{DXHeatPumpSystemName});
149 : }
150 11136 : CompIndex = DXSystemNum;
151 : } else {
152 8180 : DXSystemNum = CompIndex;
153 8180 : if (DXSystemNum > NumDXHeatPumpSystems || DXSystemNum < 1) {
154 0 : ShowFatalError(state,
155 0 : format("SimDXHeatPumpSystem: Invalid CompIndex passed={}, Number of DX Units={}, DX Unit name={}",
156 : DXSystemNum,
157 : NumDXHeatPumpSystems,
158 0 : DXHeatPumpSystemName));
159 : }
160 8180 : if (state.dataHVACDXHeatPumpSys->CheckEquipName(DXSystemNum)) {
161 2 : if (DXHeatPumpSystemName != DXHeatPumpSystem(DXSystemNum).Name) {
162 0 : ShowFatalError(state,
163 0 : format("SimDXHeatPumpSystem: Invalid CompIndex passed={}, DX Unit name={}, stored DX Unit Name for that index={}",
164 : DXSystemNum,
165 : DXHeatPumpSystemName,
166 0 : DXHeatPumpSystem(DXSystemNum).Name));
167 : }
168 2 : state.dataHVACDXHeatPumpSys->CheckEquipName(DXSystemNum) = false;
169 : }
170 : }
171 :
172 19316 : if (present(OAUnitNum)) {
173 11134 : InitDXHeatPumpSystem(state, DXSystemNum, AirLoopNum, OAUnitNum, OAUCoilOutTemp);
174 : } else {
175 8182 : InitDXHeatPumpSystem(state, DXSystemNum, AirLoopNum);
176 : }
177 :
178 : // Call the series of components that simulate a DX Heating System
179 : // Control the DX Heating System
180 19316 : ControlDXHeatingSystem(state, DXSystemNum, FirstHVACIteration);
181 :
182 : // simulate DX Heating System
183 19316 : CompName = DXHeatPumpSystem(DXSystemNum).HeatPumpCoilName;
184 :
185 19316 : switch (DXHeatPumpSystem(DXSystemNum).HeatPumpCoilType_Num) {
186 15225 : case CoilDX_HeatingEmpirical: { // COIL:DX:COOLINGBYPASSFACTOREMPIRICAL
187 60900 : SimDXCoil(state,
188 : CompName,
189 : CompressorOperation::On,
190 : FirstHVACIteration,
191 15225 : DXHeatPumpSystem(DXSystemNum).HeatPumpCoilIndex,
192 15225 : DXHeatPumpSystem(DXSystemNum).FanOpMode,
193 15225 : DXHeatPumpSystem(DXSystemNum).PartLoadFrac);
194 15225 : } break;
195 4091 : case Coil_HeatingAirToAirVariableSpeed: { // Coil:Heating:DX:VariableSpeed
196 45001 : SimVariableSpeedCoils(state,
197 : CompName,
198 4091 : DXHeatPumpSystem(DXSystemNum).HeatPumpCoilIndex,
199 4091 : DXHeatPumpSystem(DXSystemNum).FanOpMode,
200 4091 : state.dataHVACDXHeatPumpSys->MaxONOFFCyclesperHour,
201 4091 : state.dataHVACDXHeatPumpSys->HPTimeConstant,
202 4091 : state.dataHVACDXHeatPumpSys->FanDelayTime,
203 : CompressorOperation::On,
204 4091 : DXHeatPumpSystem(DXSystemNum).PartLoadFrac,
205 4091 : DXHeatPumpSystem(DXSystemNum).SpeedNum,
206 4091 : DXHeatPumpSystem(DXSystemNum).SpeedRatio,
207 4091 : state.dataHVACDXHeatPumpSys->QZnReq,
208 4091 : state.dataHVACDXHeatPumpSys->QLatReq,
209 4091 : state.dataHVACDXHeatPumpSys->OnOffAirFlowRatio);
210 4091 : } break;
211 0 : default: {
212 0 : ShowFatalError(state, "SimDXCoolingSystem: Invalid DX Heating System/Coil=" + DXHeatPumpSystem(DXSystemNum).HeatPumpCoilType);
213 0 : } break;
214 : }
215 : // set econo lockout flag
216 : // set econo lockout flag
217 19316 : if (AirLoopNum != -1) { // IF the sysem is not an equipment of outdoor air unit
218 :
219 12260 : if ((DXHeatPumpSystem(DXSystemNum).PartLoadFrac > 0.0) &&
220 4078 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).CanLockoutEconoWithCompressor) {
221 0 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).ReqstEconoLockoutWithCompressor = true;
222 : } else {
223 8182 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).ReqstEconoLockoutWithCompressor = false;
224 : }
225 : }
226 :
227 19316 : if (present(QTotOut)) {
228 8182 : InletNodeNum = DXHeatPumpSystem(DXSystemNum).DXHeatPumpCoilInletNodeNum;
229 8182 : OutletNodeNum = DXHeatPumpSystem(DXSystemNum).DXHeatPumpCoilOutletNodeNum;
230 8182 : AirMassFlow = state.dataLoopNodes->Node(OutletNodeNum).MassFlowRate;
231 8182 : QTotOut = AirMassFlow * (state.dataLoopNodes->Node(InletNodeNum).Enthalpy - state.dataLoopNodes->Node(OutletNodeNum).Enthalpy);
232 : }
233 19316 : }
234 :
235 : // Get Input Section of the Module
236 : //******************************************************************************
237 :
238 3 : void GetDXHeatPumpSystemInput(EnergyPlusData &state)
239 : {
240 :
241 : // SUBROUTINE INFORMATION:
242 : // AUTHOR Brent Griffith (derived by R.Liesen)
243 : // DATE WRITTEN May 2011
244 : // Feb 2013, Bo Shen, Oak Ridge National Lab
245 : // Add Coil:Heating:DX:VariableSpeed
246 : // RE-ENGINEERED na
247 :
248 : // PURPOSE OF THIS SUBROUTINE:
249 : // Obtains input data for system and stores it in System data structures
250 :
251 : // METHODOLOGY EMPLOYED:
252 : // Uses "Get" routines to read in data.
253 :
254 : // REFERENCES:
255 :
256 : // Using/Aliasing
257 : using BranchNodeConnections::SetUpCompSets;
258 : using BranchNodeConnections::TestCompSet;
259 : using DXCoils::GetCoilInletNode;
260 : using DXCoils::GetCoilOutletNode;
261 : using DXCoils::SetCoilSystemHeatingDXFlag;
262 : using VariableSpeedCoils::GetCoilInletNodeVariableSpeed;
263 : using VariableSpeedCoils::GetCoilOutletNodeVariableSpeed;
264 :
265 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
266 : int NumAlphas;
267 : int NumNums;
268 : int IOStat;
269 : static constexpr std::string_view RoutineName("GetDXHeatPumpSystemInput: "); // include trailing blank space
270 : bool IsNotOK; // Flag to verify name
271 : int DXHeatSysNum;
272 6 : std::string CurrentModuleObject; // for ease in getting objects
273 6 : Array1D_string Alphas; // Alpha input items for object
274 6 : Array1D_string cAlphaFields; // Alpha field names
275 6 : Array1D_string cNumericFields; // Numeric field names
276 6 : Array1D<Real64> Numbers; // Numeric input items for object
277 6 : Array1D_bool lAlphaBlanks; // Logical array, alpha field input BLANK = .TRUE.
278 6 : Array1D_bool lNumericBlanks; // Logical array, numeric field input BLANK = .TRUE.
279 :
280 3 : auto &NumDXHeatPumpSystems(state.dataHVACDXHeatPumpSys->NumDXHeatPumpSystems);
281 3 : auto &DXHeatPumpSystem(state.dataHVACDXHeatPumpSys->DXHeatPumpSystem);
282 :
283 3 : CurrentModuleObject = "CoilSystem:Heating:DX";
284 3 : NumDXHeatPumpSystems = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
285 :
286 3 : DXHeatPumpSystem.allocate(NumDXHeatPumpSystems);
287 3 : state.dataHVACDXHeatPumpSys->CheckEquipName.dimension(NumDXHeatPumpSystems, true);
288 :
289 9 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
290 6 : state, "CoilSystem:Heating:DX", state.dataHVACDXHeatPumpSys->TotalArgs, NumAlphas, NumNums);
291 :
292 3 : Alphas.allocate(NumAlphas);
293 3 : cAlphaFields.allocate(NumAlphas);
294 3 : cNumericFields.allocate(NumNums);
295 3 : Numbers.dimension(NumNums, 0.0);
296 3 : lAlphaBlanks.dimension(NumAlphas, true);
297 3 : lNumericBlanks.dimension(NumNums, true);
298 :
299 : // Get the data for the DX Cooling System
300 6 : for (DXHeatSysNum = 1; DXHeatSysNum <= NumDXHeatPumpSystems; ++DXHeatSysNum) {
301 :
302 3 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
303 : CurrentModuleObject,
304 : DXHeatSysNum,
305 : Alphas,
306 : NumAlphas,
307 : Numbers,
308 : NumNums,
309 : IOStat,
310 : lNumericBlanks,
311 : lAlphaBlanks,
312 : cAlphaFields,
313 : cNumericFields);
314 3 : UtilityRoutines::IsNameEmpty(state, Alphas(1), CurrentModuleObject, state.dataHVACDXHeatPumpSys->ErrorsFound);
315 3 : DXHeatPumpSystem(DXHeatSysNum).DXHeatPumpSystemType = CurrentModuleObject; // push Object Name into data array
316 3 : DXHeatPumpSystem(DXHeatSysNum).Name = Alphas(1);
317 3 : if (lAlphaBlanks(2)) {
318 0 : DXHeatPumpSystem(DXHeatSysNum).SchedPtr = DataGlobalConstants::ScheduleAlwaysOn;
319 : } else {
320 3 : DXHeatPumpSystem(DXHeatSysNum).SchedPtr = GetScheduleIndex(state, Alphas(2));
321 3 : if (DXHeatPumpSystem(DXHeatSysNum).SchedPtr == 0) {
322 0 : ShowSevereError(state,
323 0 : std::string{RoutineName} + CurrentModuleObject + ": invalid " + cAlphaFields(2) + " entered =" + Alphas(2) +
324 0 : " for " + cAlphaFields(1) + '=' + Alphas(1));
325 0 : state.dataHVACDXHeatPumpSys->ErrorsFound = true;
326 : }
327 : }
328 :
329 3 : if (UtilityRoutines::SameString(Alphas(3), "Coil:Heating:DX:SingleSpeed")) {
330 :
331 2 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilType = Alphas(3);
332 2 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilType_Num = CoilDX_HeatingEmpirical;
333 :
334 2 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilName = Alphas(4);
335 1 : } else if (UtilityRoutines::SameString(Alphas(3), "Coil:Heating:DX:VariableSpeed")) {
336 :
337 1 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilType = Alphas(3);
338 1 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilType_Num = Coil_HeatingAirToAirVariableSpeed;
339 :
340 1 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilName = Alphas(4);
341 :
342 : } else {
343 0 : ShowSevereError(state, "Invalid entry for " + cAlphaFields(3) + " :" + Alphas(3));
344 0 : ShowContinueError(state, "In " + CurrentModuleObject + "=\"" + DXHeatPumpSystem(DXHeatSysNum).Name + "\".");
345 0 : state.dataHVACDXHeatPumpSys->ErrorsFound = true;
346 : }
347 :
348 3 : if (DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilType_Num == Coil_HeatingAirToAirVariableSpeed) {
349 1 : DXHeatPumpSystem(DXHeatSysNum).DXHeatPumpCoilInletNodeNum =
350 3 : GetCoilInletNodeVariableSpeed(state,
351 1 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilType,
352 1 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilName,
353 1 : state.dataHVACDXHeatPumpSys->ErrorsFound);
354 1 : DXHeatPumpSystem(DXHeatSysNum).DXHeatPumpCoilOutletNodeNum =
355 3 : GetCoilOutletNodeVariableSpeed(state,
356 1 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilType,
357 1 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilName,
358 1 : state.dataHVACDXHeatPumpSys->ErrorsFound);
359 : } else {
360 6 : DXHeatPumpSystem(DXHeatSysNum).DXHeatPumpCoilInletNodeNum = GetCoilInletNode(state,
361 2 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilType,
362 2 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilName,
363 2 : state.dataHVACDXHeatPumpSys->ErrorsFound);
364 :
365 6 : DXHeatPumpSystem(DXHeatSysNum).DXHeatPumpCoilOutletNodeNum = GetCoilOutletNode(state,
366 2 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilType,
367 2 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilName,
368 2 : state.dataHVACDXHeatPumpSys->ErrorsFound);
369 : }
370 :
371 : // Coil air-side outlet node is the control node
372 3 : DXHeatPumpSystem(DXHeatSysNum).DXSystemControlNodeNum = DXHeatPumpSystem(DXHeatSysNum).DXHeatPumpCoilOutletNodeNum;
373 :
374 6 : TestCompSet(state,
375 : CurrentModuleObject,
376 3 : DXHeatPumpSystem(DXHeatSysNum).Name,
377 3 : state.dataLoopNodes->NodeID(DXHeatPumpSystem(DXHeatSysNum).DXHeatPumpCoilInletNodeNum),
378 3 : state.dataLoopNodes->NodeID(DXHeatPumpSystem(DXHeatSysNum).DXHeatPumpCoilOutletNodeNum),
379 : "Air Nodes");
380 :
381 6 : ValidateComponent(state,
382 3 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilType,
383 3 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilName,
384 : IsNotOK,
385 : CurrentModuleObject);
386 3 : if (IsNotOK) {
387 0 : ShowContinueError(state, "In " + CurrentModuleObject + " = \"" + DXHeatPumpSystem(DXHeatSysNum).Name + "\".");
388 0 : state.dataHVACDXHeatPumpSys->ErrorsFound = true;
389 : }
390 :
391 18 : SetUpCompSets(state,
392 3 : DXHeatPumpSystem(DXHeatSysNum).DXHeatPumpSystemType,
393 3 : DXHeatPumpSystem(DXHeatSysNum).Name,
394 3 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilType,
395 3 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilName,
396 3 : state.dataLoopNodes->NodeID(DXHeatPumpSystem(DXHeatSysNum).DXHeatPumpCoilInletNodeNum),
397 3 : state.dataLoopNodes->NodeID(DXHeatPumpSystem(DXHeatSysNum).DXHeatPumpCoilOutletNodeNum));
398 :
399 : // Supply air fan operating mode defaulted to constant fan cycling coil/compressor
400 3 : DXHeatPumpSystem(DXHeatSysNum).FanOpMode = ContFanCycCoil;
401 :
402 3 : if (DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilType_Num != Coil_HeatingAirToAirVariableSpeed) {
403 2 : SetCoilSystemHeatingDXFlag(state, DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilType, DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilName);
404 : }
405 :
406 : } // End of the DX System Loop
407 :
408 3 : if (state.dataHVACDXHeatPumpSys->ErrorsFound) {
409 0 : ShowFatalError(state, std::string{RoutineName} + "Errors found in input. Program terminates.");
410 : }
411 :
412 6 : for (DXHeatSysNum = 1; DXHeatSysNum <= NumDXHeatPumpSystems; ++DXHeatSysNum) {
413 : // Setup Report variables for the DXHeatingSystem that is not reported in the components themselves
414 12 : SetupOutputVariable(state,
415 : "Coil System Part Load Ratio",
416 : OutputProcessor::Unit::None,
417 3 : DXHeatPumpSystem(DXHeatSysNum).PartLoadFrac,
418 : OutputProcessor::SOVTimeStepType::System,
419 : OutputProcessor::SOVStoreType::Average,
420 6 : DXHeatPumpSystem(DXHeatSysNum).Name);
421 : }
422 :
423 3 : Alphas.deallocate();
424 3 : cAlphaFields.deallocate();
425 3 : cNumericFields.deallocate();
426 3 : Numbers.deallocate();
427 3 : lAlphaBlanks.deallocate();
428 3 : lNumericBlanks.deallocate();
429 3 : }
430 :
431 : // End of Get Input subroutines for the Module
432 : //******************************************************************************
433 :
434 : // Beginning of Initialization subroutines for the Module
435 : // *****************************************************************************
436 :
437 19316 : void InitDXHeatPumpSystem(EnergyPlusData &state,
438 : int const DXSystemNum, // number of the current DX Sys being simulated
439 : int const AirLoopNum, // number of the current air loop being simulated
440 : Optional_int_const OAUnitNum, // number of the current outdoor air unit being simulated
441 : Optional<Real64 const> OAUCoilOutTemp // the coil inlet temperature of OutdoorAirUnit
442 : )
443 : {
444 :
445 : // SUBROUTINE INFORMATION:
446 : // AUTHOR Brent Griffith (derived by R.Liesen)
447 : // DATE WRITTEN May 2011
448 : // RE-ENGINEERED na
449 :
450 : // PURPOSE OF THIS SUBROUTINE:
451 : // This subroutine is for initializations of the DX heat pump Systems.
452 :
453 : // METHODOLOGY EMPLOYED:
454 : // Uses the status flags to trigger initializations.
455 :
456 : // REFERENCES:
457 : // na
458 :
459 : // Using/Aliasing
460 19316 : auto &DoSetPointTest = state.dataHVACGlobal->DoSetPointTest;
461 : using EMSManager::CheckIfNodeSetPointManagedByEMS;
462 :
463 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
464 : int ControlNode; // control node number
465 : int DXSysIndex;
466 : int OutdoorAirUnitNum; // "ONLY" for ZoneHVAC:OutdoorAirUnit
467 : Real64 OAUCoilOutletTemp; // "ONLY" for zoneHVAC:OutdoorAirUnit
468 :
469 19316 : auto &NumDXHeatPumpSystems(state.dataHVACDXHeatPumpSys->NumDXHeatPumpSystems);
470 19316 : auto &DXHeatPumpSystem(state.dataHVACDXHeatPumpSys->DXHeatPumpSystem);
471 :
472 : // IF (MyOneTimeFlag) THEN
473 : // MyOneTimeFlag = .FALSE.
474 : // END IF
475 19316 : if (present(OAUnitNum)) { // This Dx system is component of ZoneHVAC:OutdoorAirUnit
476 11134 : OutdoorAirUnitNum = OAUnitNum;
477 11134 : OAUCoilOutletTemp = OAUCoilOutTemp;
478 : }
479 :
480 19316 : if (!state.dataGlobal->SysSizingCalc && state.dataHVACDXHeatPumpSys->MySetPointCheckFlag && DoSetPointTest) {
481 6 : for (DXSysIndex = 1; DXSysIndex <= NumDXHeatPumpSystems; ++DXSysIndex) {
482 3 : ControlNode = DXHeatPumpSystem(DXSysIndex).DXSystemControlNodeNum;
483 3 : if (ControlNode > 0) {
484 3 : if (AirLoopNum == -1) { // Outdoor Air Unit
485 1 : state.dataLoopNodes->Node(ControlNode).TempSetPoint = OAUCoilOutletTemp; // Set the coil outlet temperature
486 2 : } else if (AirLoopNum != -1) { // Not an outdoor air unit
487 :
488 2 : if (state.dataLoopNodes->Node(ControlNode).TempSetPoint == SensedNodeFlagValue) {
489 0 : if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
490 0 : ShowSevereError(state,
491 0 : DXHeatPumpSystem(DXSysIndex).DXHeatPumpSystemType +
492 0 : ": Missing temperature setpoint for DX unit= " + DXHeatPumpSystem(DXSysIndex).Name);
493 0 : ShowContinueError(state, " use a Set Point Manager to establish a setpoint at the unit control node.");
494 0 : state.dataHVACGlobal->SetPointErrorFlag = true;
495 : } else {
496 0 : CheckIfNodeSetPointManagedByEMS(
497 0 : state, ControlNode, EMSManager::SPControlType::TemperatureSetPoint, state.dataHVACGlobal->SetPointErrorFlag);
498 0 : if (state.dataHVACGlobal->SetPointErrorFlag) {
499 0 : ShowSevereError(state,
500 0 : DXHeatPumpSystem(DXSysIndex).DXHeatPumpSystemType +
501 0 : ": Missing temperature setpoint for DX unit= " + DXHeatPumpSystem(DXSysIndex).Name);
502 0 : ShowContinueError(state, " use a Set Point Manager to establish a setpoint at the unit control node.");
503 0 : ShowContinueError(state,
504 : " or use an EMS actuator to establish a temperature setpoint at the unit control node.");
505 : }
506 : }
507 : }
508 : }
509 : }
510 : }
511 3 : state.dataHVACDXHeatPumpSys->MySetPointCheckFlag = false;
512 : }
513 :
514 : // These initializations are done every iteration
515 19316 : if (AirLoopNum == -1) { // This IF-Then routine is just for ZoneHVAC:OUTDOORAIRUNIT
516 :
517 11134 : DXHeatPumpSystem(DXSystemNum).DesiredOutletTemp = OAUCoilOutletTemp;
518 :
519 8182 : } else if (AirLoopNum != -1) { // Not Outdoor Air Unit
520 8182 : ControlNode = DXHeatPumpSystem(DXSystemNum).DXSystemControlNodeNum;
521 8182 : state.dataHVACDXHeatPumpSys->EconomizerFlag = state.dataAirLoop->AirLoopControlInfo(AirLoopNum).EconoActive;
522 8182 : DXHeatPumpSystem(DXSystemNum).DesiredOutletTemp = state.dataLoopNodes->Node(ControlNode).TempSetPoint;
523 : }
524 19316 : }
525 :
526 : // End of Initialization subroutines for the Module
527 : // *****************************************************************************
528 :
529 : // Beginning of Calculation subroutines for the DXCoolingSystem Module
530 : // *****************************************************************************
531 :
532 19316 : void ControlDXHeatingSystem(EnergyPlusData &state,
533 : int const DXSystemNum, // index to DXSystem
534 : bool const FirstHVACIteration // First HVAC iteration flag
535 : )
536 : {
537 : // SUBROUTINE INFORMATION:
538 : // AUTHOR Brent Griffith (derived from ControlDXSystem by Richard Liesen)
539 : // DATE WRITTEN Jan 2012
540 : // MODIFIED Nov. 2003, R. Raustad, FSEC
541 : // Feb. 2005, M. J. Witte, GARD. Add dehumidification controls and support for multimode DX coil
542 : // Jan. 2008, R. Raustad, FSEC. Added coolreheat to all coil types
543 : // Feb. 2013, B. Shen, ORNL. Add Coil:Heating:DX:VariableSpeed
544 : // Nov. 2016, R. Zhang, LBNL. Applied the coil supply air temperature sensor offset fault model
545 : // RE-ENGINEERED na
546 :
547 : // PURPOSE OF THIS SUBROUTINE:
548 : // This subroutine updates the System outlet nodes.
549 :
550 : // METHODOLOGY EMPLOYED:
551 : // Data is moved from the System data structure to the System outlet nodes.
552 :
553 : // Using/Aliasing
554 : using namespace ScheduleManager;
555 : using DataHVACGlobals::TempControlTol;
556 : using DXCoils::SimDXCoil;
557 :
558 : using General::SolveRoot;
559 : using Psychrometrics::PsyHFnTdbW;
560 : using Psychrometrics::PsyTdpFnWPb;
561 : using VariableSpeedCoils::SimVariableSpeedCoils;
562 :
563 : // SUBROUTINE PARAMETER DEFINITIONS:
564 19316 : int constexpr MaxIte(500); // Maximum number of iterations for solver
565 19316 : Real64 constexpr Acc(1.e-3); // Accuracy of solver result
566 :
567 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
568 38632 : std::string CompName; // Name of the DX cooling coil
569 : Real64 NoOutput; // Sensible capacity (outlet - inlet) when the compressor is off
570 : Real64 FullOutput; // Sensible capacity (outlet - inlet) when the compressor is on
571 : Real64 ReqOutput; // Sensible capacity (outlet - inlet) required to meet load or set point temperature
572 : int InletNode; // Inlet node number of the DX cooling coil
573 : int OutletNode; // Outlet node number of the DX cooling coil
574 : int ControlNode; // The node number where a set point is placed to control the DX cooling coil
575 : Real64 PartLoadFrac; // The part-load fraction of the compressor
576 :
577 : Real64 DesOutTemp; // Desired outlet temperature of the DX cooling coil
578 : Real64 OutletTempDXCoil; // Actual outlet temperature of the DX cooling coil
579 :
580 : int SolFla; // Flag of solver
581 : bool SensibleLoad; // True if there is a sensible cooling load on this system
582 : int FanOpMode; // Supply air fan operating mode
583 : // added variables to call variable speed DX coils
584 : int SpeedNum; // speed number of variable speed DX cooling coil
585 : Real64 QZnReq; // Zone load (W), input to variable-speed DX coil
586 : Real64 QLatReq; // Zone latent load, input to variable-speed DX coil
587 : Real64 MaxONOFFCyclesperHour; // Maximum cycling rate of heat pump [cycles/hr]
588 : Real64 HPTimeConstant; // Heat pump time constant [s]
589 : Real64 FanDelayTime; // Fan delay time, time delay for the HP's fan to
590 : Real64 OnOffAirFlowRatio; // ratio of compressor on flow to average flow over time step
591 : Real64 TempSpeedOut; // output at one speed level
592 : Real64 TempSpeedReqst; // request capacity at one speed level
593 : int NumOfSpeeds; // maximum number of speed
594 : int VSCoilIndex; // variable-speed coil index
595 : int I; // interation increment
596 : Real64 SpeedRatio; // speed ratio between two neighboring speeds
597 :
598 19316 : auto &DXHeatPumpSystem(state.dataHVACDXHeatPumpSys->DXHeatPumpSystem);
599 :
600 : // Set local variables
601 : // Retrieve the load on the controlled zone
602 19316 : OutletNode = DXHeatPumpSystem(DXSystemNum).DXHeatPumpCoilOutletNodeNum;
603 19316 : InletNode = DXHeatPumpSystem(DXSystemNum).DXHeatPumpCoilInletNodeNum;
604 19316 : ControlNode = DXHeatPumpSystem(DXSystemNum).DXSystemControlNodeNum;
605 19316 : DesOutTemp = DXHeatPumpSystem(DXSystemNum).DesiredOutletTemp;
606 19316 : CompName = DXHeatPumpSystem(DXSystemNum).HeatPumpCoilName;
607 19316 : FanOpMode = DXHeatPumpSystem(DXSystemNum).FanOpMode;
608 :
609 19316 : PartLoadFrac = 0.0;
610 :
611 19316 : SensibleLoad = false;
612 :
613 19316 : SpeedNum = 1;
614 19316 : QZnReq = 0.0;
615 19316 : QLatReq = 0.0;
616 19316 : MaxONOFFCyclesperHour = 4.0; // default number
617 19316 : HPTimeConstant = 0.0;
618 19316 : FanDelayTime = 0.0;
619 19316 : OnOffAirFlowRatio = 1.0;
620 19316 : TempSpeedOut = 0.0;
621 19316 : TempSpeedReqst = 0.0;
622 19316 : NumOfSpeeds = 0;
623 19316 : VSCoilIndex = 0;
624 19316 : I = 1;
625 19316 : SpeedRatio = 0.0;
626 :
627 : // If there is a fault of coil SAT Sensor
628 19316 : if (DXHeatPumpSystem(DXSystemNum).FaultyCoilSATFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
629 0 : (!state.dataGlobal->KickOffSimulation)) {
630 : // calculate the sensor offset using fault information
631 0 : int FaultIndex = DXHeatPumpSystem(DXSystemNum).FaultyCoilSATIndex;
632 0 : DXHeatPumpSystem(DXSystemNum).FaultyCoilSATOffset = state.dataFaultsMgr->FaultsCoilSATSensor(FaultIndex).CalFaultOffsetAct(state);
633 : // update the DesOutTemp
634 0 : DesOutTemp -= DXHeatPumpSystem(DXSystemNum).FaultyCoilSATOffset;
635 : }
636 :
637 : // If DXHeatingSystem is scheduled on and there is flow
638 38614 : if ((GetCurrentScheduleValue(state, DXHeatPumpSystem(DXSystemNum).SchedPtr) > 0.0) &&
639 19298 : (state.dataLoopNodes->Node(InletNode).MassFlowRate > MinAirMassFlow)) {
640 :
641 : // Determine if there is a sensible load on this system
642 44615 : if ((state.dataLoopNodes->Node(InletNode).Temp < state.dataLoopNodes->Node(ControlNode).TempSetPoint) &&
643 25317 : (state.dataLoopNodes->Node(InletNode).Temp < DesOutTemp) &&
644 6019 : (std::abs(state.dataLoopNodes->Node(InletNode).Temp - DesOutTemp) > TempControlTol))
645 4078 : SensibleLoad = true;
646 :
647 : // If DXHeatingSystem runs with a heating load then set PartLoadFrac on Heating System
648 19298 : if (SensibleLoad) {
649 : {
650 : Real64 TempOut1;
651 :
652 4078 : switch (DXHeatPumpSystem(DXSystemNum).HeatPumpCoilType_Num) {
653 2039 : case CoilDX_HeatingEmpirical: { // Coil:Heating:DX:SingleSpeed
654 :
655 : // Get no load result
656 2039 : PartLoadFrac = 0.0;
657 4078 : SimDXCoil(state,
658 : CompName,
659 : CompressorOperation::On,
660 : FirstHVACIteration,
661 2039 : DXHeatPumpSystem(DXSystemNum).HeatPumpCoilIndex,
662 : FanOpMode,
663 : PartLoadFrac);
664 4078 : NoOutput = state.dataLoopNodes->Node(InletNode).MassFlowRate *
665 4078 : (PsyHFnTdbW(state.dataLoopNodes->Node(OutletNode).Temp, state.dataLoopNodes->Node(OutletNode).HumRat) -
666 2039 : PsyHFnTdbW(state.dataLoopNodes->Node(InletNode).Temp, state.dataLoopNodes->Node(OutletNode).HumRat));
667 :
668 : // Get full load result
669 2039 : PartLoadFrac = 1.0;
670 4078 : SimDXCoil(state,
671 : CompName,
672 : CompressorOperation::On,
673 : FirstHVACIteration,
674 2039 : DXHeatPumpSystem(DXSystemNum).HeatPumpCoilIndex,
675 : FanOpMode,
676 : PartLoadFrac);
677 :
678 4078 : FullOutput = state.dataLoopNodes->Node(InletNode).MassFlowRate *
679 4078 : (PsyHFnTdbW(state.dataLoopNodes->Node(OutletNode).Temp, state.dataLoopNodes->Node(InletNode).HumRat) -
680 2039 : PsyHFnTdbW(state.dataLoopNodes->Node(InletNode).Temp, state.dataLoopNodes->Node(InletNode).HumRat));
681 :
682 4078 : ReqOutput = state.dataLoopNodes->Node(InletNode).MassFlowRate *
683 4078 : (PsyHFnTdbW(DesOutTemp, state.dataLoopNodes->Node(InletNode).HumRat) -
684 2039 : PsyHFnTdbW(state.dataLoopNodes->Node(InletNode).Temp, state.dataLoopNodes->Node(InletNode).HumRat));
685 2039 : TempOut1 = state.dataLoopNodes->Node(OutletNode).Temp;
686 : // IF NoOutput is higher than (more heating than required) or very near the ReqOutput, do not run the compressor
687 2039 : if ((NoOutput - ReqOutput) > Acc) {
688 0 : PartLoadFrac = 0.0;
689 : // If the FullOutput is greater than (insufficient heating) or very near the ReqOutput,
690 : // run the compressor at PartLoadFrac = 1.
691 2039 : } else if ((FullOutput - ReqOutput) < Acc) {
692 2037 : PartLoadFrac = 1.0;
693 : // Else find the PLR to meet the load
694 : } else {
695 : // OutletTempDXCoil is the full capacity outlet temperature at PartLoadFrac = 1 from the CALL above. If this
696 : // temp is greater than the desired outlet temp, then run the compressor at PartLoadFrac = 1, otherwise find the
697 : // operating PLR.
698 2 : OutletTempDXCoil = state.dataDXCoils->DXCoilOutletTemp(DXHeatPumpSystem(DXSystemNum).HeatPumpCoilIndex);
699 2 : if (OutletTempDXCoil < DesOutTemp) {
700 0 : PartLoadFrac = 1.0;
701 : } else {
702 2 : if (state.dataGlobal->DoCoilDirectSolutions) {
703 0 : PartLoadFrac = (DesOutTemp - state.dataLoopNodes->Node(InletNode).Temp) /
704 0 : (TempOut1 - state.dataLoopNodes->Node(InletNode).Temp);
705 0 : SimDXCoil(state,
706 : CompName,
707 : CompressorOperation::On,
708 : FirstHVACIteration,
709 0 : DXHeatPumpSystem(DXSystemNum).HeatPumpCoilIndex,
710 : FanOpMode,
711 : PartLoadFrac);
712 : } else {
713 2 : int coilIndex = DXHeatPumpSystem(DXSystemNum).HeatPumpCoilIndex;
714 30 : auto f = [&state, coilIndex, DesOutTemp](Real64 const PartLoadFrac) {
715 12 : DXCoils::CalcDXHeatingCoil(state, coilIndex, PartLoadFrac, ContFanCycCoil, 1.0);
716 12 : Real64 OutletAirTemp = state.dataDXCoils->DXCoilOutletTemp(coilIndex);
717 6 : return DesOutTemp - OutletAirTemp;
718 2 : };
719 2 : SolveRoot(state, Acc, MaxIte, SolFla, PartLoadFrac, f, 0.0, 1.0);
720 2 : if (SolFla == -1) {
721 0 : if (!state.dataGlobal->WarmupFlag) {
722 0 : if (DXHeatPumpSystem(DXSystemNum).DXCoilSensPLRIter < 1) {
723 0 : ++DXHeatPumpSystem(DXSystemNum).DXCoilSensPLRIter;
724 0 : ShowWarningError(
725 : state,
726 0 : DXHeatPumpSystem(DXSystemNum).DXHeatPumpSystemType +
727 0 : " - Iteration limit exceeded calculating DX unit sensible part-load ratio for unit = " +
728 0 : DXHeatPumpSystem(DXSystemNum).Name);
729 0 : ShowContinueError(state, format("Estimated part-load ratio = {:.3R}", (ReqOutput / FullOutput)));
730 0 : ShowContinueError(state, format("Calculated part-load ratio = {:.3R}", PartLoadFrac));
731 0 : ShowContinueErrorTimeStamp(
732 : state,
733 : "The calculated part-load ratio will be used and the simulation continues. Occurrence info:");
734 : } else {
735 0 : ShowRecurringWarningErrorAtEnd(state,
736 0 : DXHeatPumpSystem(DXSystemNum).DXHeatPumpSystemType + " \"" +
737 0 : DXHeatPumpSystem(DXSystemNum).Name +
738 : "\" - Iteration limit exceeded calculating sensible part-load "
739 : "ratio error continues. Sensible "
740 : "PLR statistics follow.",
741 0 : DXHeatPumpSystem(DXSystemNum).DXCoilSensPLRIterIndex,
742 : PartLoadFrac,
743 : PartLoadFrac);
744 : }
745 : }
746 2 : } else if (SolFla == -2) {
747 0 : PartLoadFrac = ReqOutput / FullOutput;
748 0 : if (!state.dataGlobal->WarmupFlag) {
749 0 : if (DXHeatPumpSystem(DXSystemNum).DXCoilSensPLRFail < 1) {
750 0 : ++DXHeatPumpSystem(DXSystemNum).DXCoilSensPLRFail;
751 0 : ShowWarningError(state,
752 0 : DXHeatPumpSystem(DXSystemNum).DXHeatPumpSystemType +
753 : " - DX unit sensible part-load ratio calculation failed: part-load ratio limits "
754 0 : "exceeded, for unit = " +
755 0 : DXHeatPumpSystem(DXSystemNum).Name);
756 0 : ShowContinueError(state, format("Estimated part-load ratio = {:.3R}", PartLoadFrac));
757 0 : ShowContinueErrorTimeStamp(
758 : state,
759 : "The estimated part-load ratio will be used and the simulation continues. Occurrence info:");
760 : } else {
761 0 : ShowRecurringWarningErrorAtEnd(
762 : state,
763 0 : DXHeatPumpSystem(DXSystemNum).DXHeatPumpSystemType + " \"" + DXHeatPumpSystem(DXSystemNum).Name +
764 : "\" - DX unit sensible part-load ratio calculation failed error continues. Sensible PLR "
765 : "statistics follow.",
766 0 : DXHeatPumpSystem(DXSystemNum).DXCoilSensPLRFailIndex,
767 : PartLoadFrac,
768 : PartLoadFrac);
769 : }
770 : }
771 : }
772 : }
773 : }
774 : }
775 :
776 2039 : if (PartLoadFrac > 1.0) {
777 0 : PartLoadFrac = 1.0;
778 2039 : } else if (PartLoadFrac < 0.0) {
779 0 : PartLoadFrac = 0.0;
780 : }
781 2039 : } break;
782 2039 : case Coil_HeatingAirToAirVariableSpeed: {
783 : // variable-speed air-to-air heating coil, begin -------------------------
784 : // Get no load result
785 2039 : PartLoadFrac = 0.0;
786 2039 : SpeedNum = 1;
787 2039 : QZnReq = 0.0;
788 2039 : QLatReq = 0.0;
789 2039 : MaxONOFFCyclesperHour = 4.0; // default number
790 2039 : HPTimeConstant = 0.0;
791 2039 : FanDelayTime = 0.0;
792 2039 : OnOffAirFlowRatio = 1.0;
793 2039 : SpeedRatio = 0.0;
794 :
795 4078 : SimVariableSpeedCoils(state,
796 : CompName,
797 2039 : DXHeatPumpSystem(DXSystemNum).HeatPumpCoilIndex,
798 : FanOpMode,
799 : MaxONOFFCyclesperHour,
800 : HPTimeConstant,
801 : FanDelayTime,
802 : CompressorOperation::On,
803 : PartLoadFrac,
804 : SpeedNum,
805 : SpeedRatio,
806 : QZnReq,
807 : QLatReq,
808 : OnOffAirFlowRatio);
809 :
810 2039 : VSCoilIndex = DXHeatPumpSystem(DXSystemNum).HeatPumpCoilIndex;
811 2039 : NumOfSpeeds = state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilIndex).NumOfSpeeds;
812 :
813 4078 : NoOutput = state.dataLoopNodes->Node(InletNode).MassFlowRate *
814 4078 : (PsyHFnTdbW(state.dataLoopNodes->Node(OutletNode).Temp, state.dataLoopNodes->Node(OutletNode).HumRat) -
815 2039 : PsyHFnTdbW(state.dataLoopNodes->Node(InletNode).Temp, state.dataLoopNodes->Node(OutletNode).HumRat));
816 :
817 : // Get full load result
818 2039 : PartLoadFrac = 1.0;
819 :
820 2039 : SpeedNum = NumOfSpeeds;
821 2039 : SpeedRatio = 1.0;
822 2039 : QZnReq = 0.001; // to indicate the coil is running
823 2039 : SimVariableSpeedCoils(state,
824 : CompName,
825 : VSCoilIndex,
826 : FanOpMode,
827 : MaxONOFFCyclesperHour,
828 : HPTimeConstant,
829 : FanDelayTime,
830 : CompressorOperation::On,
831 : PartLoadFrac,
832 : SpeedNum,
833 : SpeedRatio,
834 : QZnReq,
835 : QLatReq,
836 : OnOffAirFlowRatio);
837 :
838 4078 : FullOutput = state.dataLoopNodes->Node(InletNode).MassFlowRate *
839 4078 : (PsyHFnTdbW(state.dataLoopNodes->Node(OutletNode).Temp, state.dataLoopNodes->Node(InletNode).HumRat) -
840 2039 : PsyHFnTdbW(state.dataLoopNodes->Node(InletNode).Temp, state.dataLoopNodes->Node(InletNode).HumRat));
841 :
842 4078 : ReqOutput = state.dataLoopNodes->Node(InletNode).MassFlowRate *
843 4078 : (PsyHFnTdbW(DesOutTemp, state.dataLoopNodes->Node(InletNode).HumRat) -
844 2039 : PsyHFnTdbW(state.dataLoopNodes->Node(InletNode).Temp, state.dataLoopNodes->Node(InletNode).HumRat));
845 : // IF NoOutput is higher than (more heating than required) or very near the ReqOutput, do not run the compressor
846 2039 : if ((NoOutput - ReqOutput) > Acc) {
847 0 : PartLoadFrac = 0.0;
848 0 : SpeedNum = 1;
849 0 : SpeedRatio = 0.0;
850 : // If the FullOutput is greater than (insufficient heating) or very near the ReqOutput,
851 : // run the compressor at PartLoadFrac = 1.
852 2039 : } else if ((FullOutput - ReqOutput) < Acc) {
853 2039 : PartLoadFrac = 1.0;
854 2039 : SpeedNum = NumOfSpeeds;
855 2039 : SpeedRatio = 1.0;
856 : // Else find the PLR to meet the load
857 : } else {
858 : // OutletTempDXCoil is the full capacity outlet temperature at PartLoadFrac = 1 from the CALL above. If this
859 : // temp is greater than the desired outlet temp, then run the compressor at PartLoadFrac = 1, otherwise find the
860 : // operating PLR.
861 0 : OutletTempDXCoil = state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilIndex).OutletAirDBTemp;
862 0 : if (OutletTempDXCoil < DesOutTemp) {
863 0 : PartLoadFrac = 1.0;
864 0 : SpeedNum = NumOfSpeeds;
865 0 : SpeedRatio = 1.0;
866 : } else {
867 0 : PartLoadFrac = 1.0;
868 0 : SpeedNum = 1;
869 0 : SpeedRatio = 1.0;
870 0 : QZnReq = 0.001; // to indicate the coil is running
871 0 : SimVariableSpeedCoils(state,
872 : CompName,
873 : VSCoilIndex,
874 : FanOpMode,
875 : MaxONOFFCyclesperHour,
876 : HPTimeConstant,
877 : FanDelayTime,
878 : CompressorOperation::On,
879 : PartLoadFrac,
880 : SpeedNum,
881 : SpeedRatio,
882 : QZnReq,
883 : QLatReq,
884 : OnOffAirFlowRatio);
885 :
886 0 : TempSpeedOut = state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilIndex).OutletAirDBTemp;
887 :
888 0 : if ((TempSpeedOut - DesOutTemp) < Acc) {
889 : // Check to see which speed to meet the load
890 0 : PartLoadFrac = 1.0;
891 0 : SpeedRatio = 1.0;
892 0 : TempOut1 = TempSpeedOut;
893 0 : for (I = 2; I <= NumOfSpeeds; ++I) {
894 0 : SpeedNum = I;
895 0 : SimVariableSpeedCoils(state,
896 : CompName,
897 : VSCoilIndex,
898 : FanOpMode,
899 : MaxONOFFCyclesperHour,
900 : HPTimeConstant,
901 : FanDelayTime,
902 : CompressorOperation::On,
903 : PartLoadFrac,
904 : SpeedNum,
905 : SpeedRatio,
906 : QZnReq,
907 : QLatReq,
908 : OnOffAirFlowRatio);
909 :
910 0 : TempSpeedOut = state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilIndex).OutletAirDBTemp;
911 :
912 0 : if ((TempSpeedOut - DesOutTemp) > Acc) {
913 0 : SpeedNum = I;
914 0 : break;
915 : }
916 0 : TempOut1 = TempSpeedOut;
917 : }
918 0 : if (state.dataGlobal->DoCoilDirectSolutions) {
919 0 : SpeedRatio = (DesOutTemp - TempOut1) / (TempSpeedOut - TempOut1);
920 0 : SimVariableSpeedCoils(state,
921 : CompName,
922 : VSCoilIndex,
923 : FanOpMode,
924 : MaxONOFFCyclesperHour,
925 : HPTimeConstant,
926 : FanDelayTime,
927 : CompressorOperation::On,
928 : PartLoadFrac,
929 : SpeedNum,
930 : SpeedRatio,
931 : QZnReq,
932 : QLatReq,
933 : OnOffAirFlowRatio);
934 : } else {
935 0 : auto f = [&state, VSCoilIndex, DesOutTemp, SpeedNum, FanOpMode](Real64 const x) {
936 : return VSCoilSpeedResidual(state, x, VSCoilIndex, DesOutTemp, SpeedNum, FanOpMode);
937 0 : };
938 0 : General::SolveRoot(state, Acc, MaxIte, SolFla, SpeedRatio, f, 1.0e-10, 1.0);
939 :
940 0 : if (SolFla == -1) {
941 0 : if (!state.dataGlobal->WarmupFlag) {
942 0 : if (DXHeatPumpSystem(DXSystemNum).DXCoilSensPLRIter < 1) {
943 0 : ++DXHeatPumpSystem(DXSystemNum).DXCoilSensPLRIter;
944 0 : ShowWarningError(
945 : state,
946 0 : DXHeatPumpSystem(DXSystemNum).DXHeatPumpSystemType +
947 0 : " - Iteration limit exceeded calculating DX unit sensible part-load ratio for unit = " +
948 0 : DXHeatPumpSystem(DXSystemNum).Name);
949 0 : ShowContinueError(state, format("Estimated part-load ratio = {:.3R}", (ReqOutput / FullOutput)));
950 0 : ShowContinueError(state, format("Calculated part-load ratio = {:.3R}", PartLoadFrac));
951 0 : ShowContinueErrorTimeStamp(
952 : state,
953 : "The calculated part-load ratio will be used and the simulation continues. Occurrence info:");
954 : } else {
955 0 : ShowRecurringWarningErrorAtEnd(
956 : state,
957 0 : DXHeatPumpSystem(DXSystemNum).DXHeatPumpSystemType + " \"" +
958 0 : DXHeatPumpSystem(DXSystemNum).Name +
959 : "\" - Iteration limit exceeded calculating sensible part-load ratio error continues. "
960 : "Sensible PLR statistics follow.",
961 0 : DXHeatPumpSystem(DXSystemNum).DXCoilSensPLRIterIndex,
962 : PartLoadFrac,
963 : PartLoadFrac);
964 : }
965 : }
966 0 : } else if (SolFla == -2) {
967 0 : PartLoadFrac = ReqOutput / FullOutput;
968 0 : if (!state.dataGlobal->WarmupFlag) {
969 0 : if (DXHeatPumpSystem(DXSystemNum).DXCoilSensPLRFail < 1) {
970 0 : ++DXHeatPumpSystem(DXSystemNum).DXCoilSensPLRFail;
971 0 : ShowWarningError(
972 : state,
973 0 : DXHeatPumpSystem(DXSystemNum).DXHeatPumpSystemType +
974 : " - DX unit sensible part-load ratio calculation failed: part-load ratio limits "
975 0 : "exceeded, for unit = " +
976 0 : DXHeatPumpSystem(DXSystemNum).Name);
977 0 : ShowContinueError(state, format("Estimated part-load ratio = {:.3R}", PartLoadFrac));
978 0 : ShowContinueErrorTimeStamp(
979 : state,
980 : "The estimated part-load ratio will be used and the simulation continues. Occurrence info:");
981 : } else {
982 0 : ShowRecurringWarningErrorAtEnd(
983 : state,
984 0 : DXHeatPumpSystem(DXSystemNum).DXHeatPumpSystemType + " \"" +
985 0 : DXHeatPumpSystem(DXSystemNum).Name +
986 : "\" - DX unit sensible part-load ratio calculation failed error continues. Sensible PLR "
987 : "statistics follow.",
988 0 : DXHeatPumpSystem(DXSystemNum).DXCoilSensPLRFailIndex,
989 : PartLoadFrac,
990 : PartLoadFrac);
991 : }
992 : }
993 : }
994 : }
995 : } else {
996 0 : if (state.dataGlobal->DoCoilDirectSolutions) {
997 0 : PartLoadFrac = (DesOutTemp - state.dataLoopNodes->Node(InletNode).Temp) /
998 0 : (TempSpeedOut - state.dataLoopNodes->Node(InletNode).Temp);
999 0 : SimVariableSpeedCoils(state,
1000 : CompName,
1001 : VSCoilIndex,
1002 : FanOpMode,
1003 : MaxONOFFCyclesperHour,
1004 : HPTimeConstant,
1005 : FanDelayTime,
1006 : CompressorOperation::On,
1007 : PartLoadFrac,
1008 : SpeedNum,
1009 : SpeedRatio,
1010 : QZnReq,
1011 : QLatReq,
1012 : OnOffAirFlowRatio);
1013 : } else {
1014 0 : auto f = [&state, VSCoilIndex, DesOutTemp, FanOpMode](Real64 const x) {
1015 : return VSCoilCyclingResidual(state, x, VSCoilIndex, DesOutTemp, FanOpMode);
1016 0 : };
1017 0 : General::SolveRoot(state, Acc, MaxIte, SolFla, PartLoadFrac, f, 1.0e-10, 1.0);
1018 0 : if (SolFla == -1) {
1019 0 : if (!state.dataGlobal->WarmupFlag) {
1020 0 : if (DXHeatPumpSystem(DXSystemNum).DXCoilSensPLRIter < 1) {
1021 0 : ++DXHeatPumpSystem(DXSystemNum).DXCoilSensPLRIter;
1022 0 : ShowWarningError(
1023 : state,
1024 0 : DXHeatPumpSystem(DXSystemNum).DXHeatPumpSystemType +
1025 0 : " - Iteration limit exceeded calculating DX unit sensible part-load ratio for unit = " +
1026 0 : DXHeatPumpSystem(DXSystemNum).Name);
1027 0 : ShowContinueError(state, format("Estimated part-load ratio = {:.3R}", (ReqOutput / FullOutput)));
1028 0 : ShowContinueError(state, format("Calculated part-load ratio = {:.3R}", PartLoadFrac));
1029 0 : ShowContinueErrorTimeStamp(
1030 : state,
1031 : "The calculated part-load ratio will be used and the simulation continues. Occurrence info:");
1032 : } else {
1033 0 : ShowRecurringWarningErrorAtEnd(
1034 : state,
1035 0 : DXHeatPumpSystem(DXSystemNum).DXHeatPumpSystemType + " \"" +
1036 0 : DXHeatPumpSystem(DXSystemNum).Name +
1037 : "\" - Iteration limit exceeded calculating sensible part-load ratio error continues. "
1038 : "Sensible PLR statistics follow.",
1039 0 : DXHeatPumpSystem(DXSystemNum).DXCoilSensPLRIterIndex,
1040 : PartLoadFrac,
1041 : PartLoadFrac);
1042 : }
1043 : }
1044 0 : } else if (SolFla == -2) {
1045 0 : PartLoadFrac = ReqOutput / FullOutput;
1046 0 : if (!state.dataGlobal->WarmupFlag) {
1047 0 : if (DXHeatPumpSystem(DXSystemNum).DXCoilSensPLRFail < 1) {
1048 0 : ++DXHeatPumpSystem(DXSystemNum).DXCoilSensPLRFail;
1049 0 : ShowWarningError(
1050 : state,
1051 0 : DXHeatPumpSystem(DXSystemNum).DXHeatPumpSystemType +
1052 : " - DX unit sensible part-load ratio calculation failed: part-load ratio limits "
1053 0 : "exceeded, for unit = " +
1054 0 : DXHeatPumpSystem(DXSystemNum).Name);
1055 0 : ShowContinueError(state, format("Estimated part-load ratio = {:.3R}", PartLoadFrac));
1056 0 : ShowContinueErrorTimeStamp(
1057 : state,
1058 : "The estimated part-load ratio will be used and the simulation continues. Occurrence info:");
1059 : } else {
1060 0 : ShowRecurringWarningErrorAtEnd(
1061 : state,
1062 0 : DXHeatPumpSystem(DXSystemNum).DXHeatPumpSystemType + " \"" +
1063 0 : DXHeatPumpSystem(DXSystemNum).Name +
1064 : "\" - DX unit sensible part-load ratio calculation failed error continues. Sensible PLR "
1065 : "statistics follow.",
1066 0 : DXHeatPumpSystem(DXSystemNum).DXCoilSensPLRFailIndex,
1067 : PartLoadFrac,
1068 : PartLoadFrac);
1069 : }
1070 : }
1071 : }
1072 : }
1073 : }
1074 : }
1075 : }
1076 :
1077 2039 : if (PartLoadFrac > 1.0) {
1078 0 : PartLoadFrac = 1.0;
1079 2039 : } else if (PartLoadFrac < 0.0) {
1080 0 : PartLoadFrac = 0.0;
1081 : }
1082 2039 : } break;
1083 0 : default: {
1084 0 : ShowFatalError(
1085 0 : state, "ControlDXHeatingSystem: Invalid DXHeatPumpSystem coil type = " + DXHeatPumpSystem(DXSystemNum).HeatPumpCoilType);
1086 0 : } break;
1087 : }
1088 : }
1089 : } // End of cooling load type (sensible or latent) if block
1090 : } // End of If DXheatingSystem is scheduled on and there is flow
1091 :
1092 : // Set the final results
1093 19316 : DXHeatPumpSystem(DXSystemNum).PartLoadFrac = PartLoadFrac;
1094 19316 : DXHeatPumpSystem(DXSystemNum).SpeedRatio = SpeedRatio;
1095 19316 : DXHeatPumpSystem(DXSystemNum).SpeedNum = SpeedNum;
1096 19316 : }
1097 :
1098 : //******************************************************************************
1099 :
1100 16860 : Real64 VSCoilCyclingResidual(EnergyPlusData &state,
1101 : Real64 const PartLoadRatio, // compressor cycling ratio (1.0 is continuous, 0.0 is off)
1102 : int CoilIndex,
1103 : Real64 desiredTemp,
1104 : int FanOpMode)
1105 : {
1106 : // FUNCTION INFORMATION:
1107 : // AUTHOR Bo Shen
1108 : // DATE WRITTEN Feb, 2013
1109 : // MODIFIED na
1110 : // RE-ENGINEERED na
1111 :
1112 : // PURPOSE OF THIS FUNCTION:
1113 : // Calculates residual function, iterate part-load ratio
1114 : // compare the desired temperature value with exit temperature from a variable-speed heating coil
1115 :
1116 151740 : VariableSpeedCoils::SimVariableSpeedCoils(state,
1117 : "",
1118 : CoilIndex,
1119 : FanOpMode,
1120 16860 : state.dataHVACDXHeatPumpSys->MaximumONOFFCyclesperHour,
1121 16860 : state.dataHVACDXHeatPumpSys->TimeConstant,
1122 16860 : state.dataHVACDXHeatPumpSys->HeatPumpFanDelayTime,
1123 : CompressorOperation::On,
1124 : PartLoadRatio,
1125 16860 : state.dataHVACDXHeatPumpSys->SpeedNum,
1126 16860 : state.dataHVACDXHeatPumpSys->SpeedRatio,
1127 16860 : state.dataHVACDXHeatPumpSys->QZnReqr,
1128 16860 : state.dataHVACDXHeatPumpSys->QLatReqr,
1129 33720 : state.dataHVACDXHeatPumpSys->OnandOffAirFlowRatio);
1130 :
1131 16860 : Real64 OutletAirTemp = state.dataVariableSpeedCoils->VarSpeedCoil(CoilIndex).OutletAirDBTemp;
1132 16860 : return desiredTemp - OutletAirTemp;
1133 : }
1134 :
1135 : //******************************************************************************
1136 :
1137 3 : Real64 VSCoilSpeedResidual(EnergyPlusData &state,
1138 : Real64 const SpeedRatio, // compressor cycling ratio (1.0 is continuous, 0.0 is off)
1139 : int CoilIndex,
1140 : Real64 desiredTemp,
1141 : int speedNumber,
1142 : int FanOpMode)
1143 : {
1144 : // FUNCTION INFORMATION:
1145 : // AUTHOR Bo Shen
1146 : // DATE WRITTEN Feb, 2013
1147 : // MODIFIED na
1148 : // RE-ENGINEERED na
1149 :
1150 : // PURPOSE OF THIS FUNCTION:
1151 : // Calculates residual function, iterate speed ratio
1152 : // compare the desired temperature value with exit temperature from a variable-speed heating coil
1153 3 : state.dataHVACDXHeatPumpSys->SpeedNumber = speedNumber;
1154 27 : VariableSpeedCoils::SimVariableSpeedCoils(state,
1155 : "",
1156 : CoilIndex,
1157 : FanOpMode,
1158 3 : state.dataHVACDXHeatPumpSys->MaxONOFFCyclesperHr,
1159 3 : state.dataHVACDXHeatPumpSys->HPTimeConst,
1160 3 : state.dataHVACDXHeatPumpSys->HPFanDelayTime,
1161 : CompressorOperation::On,
1162 3 : state.dataHVACDXHeatPumpSys->SpeedPartLoadRatio,
1163 3 : state.dataHVACDXHeatPumpSys->SpeedNumber,
1164 : SpeedRatio,
1165 3 : state.dataHVACDXHeatPumpSys->QZoneReq,
1166 3 : state.dataHVACDXHeatPumpSys->QLatentReq,
1167 6 : state.dataHVACDXHeatPumpSys->AirFlowOnOffRatio);
1168 3 : Real64 OutletAirTemp = state.dataVariableSpeedCoils->VarSpeedCoil(CoilIndex).OutletAirDBTemp;
1169 3 : return desiredTemp - OutletAirTemp;
1170 : }
1171 :
1172 0 : int GetHeatingCoilInletNodeNum(EnergyPlusData &state, std::string const &DXHeatCoilSysName, bool &InletNodeErrFlag)
1173 : {
1174 : // SUBROUTINE INFORMATION:
1175 : // AUTHOR Lixing Gu, FSEC
1176 : // DATE WRITTEN Apr. 2019
1177 : // PURPOSE OF THIS SUBROUTINE:
1178 : // Get inlet node number
1179 :
1180 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1181 : int NodeNum;
1182 : int DXHeatSysNum;
1183 :
1184 0 : if (state.dataHVACDXHeatPumpSys->GetInputFlag) { // First time subroutine has been entered
1185 0 : GetDXHeatPumpSystemInput(state);
1186 0 : state.dataHVACDXHeatPumpSys->GetInputFlag = false;
1187 : }
1188 :
1189 0 : NodeNum = 0;
1190 0 : if (state.dataHVACDXHeatPumpSys->NumDXHeatPumpSystems > 0) {
1191 0 : DXHeatSysNum = UtilityRoutines::FindItemInList(DXHeatCoilSysName, state.dataHVACDXHeatPumpSys->DXHeatPumpSystem);
1192 0 : if (DXHeatSysNum > 0 && DXHeatSysNum <= state.dataHVACDXHeatPumpSys->NumDXHeatPumpSystems) {
1193 0 : NodeNum = state.dataHVACDXHeatPumpSys->DXHeatPumpSystem(DXHeatSysNum).DXHeatPumpCoilInletNodeNum;
1194 : }
1195 : }
1196 0 : if (NodeNum == 0) InletNodeErrFlag = true;
1197 :
1198 0 : return NodeNum;
1199 : }
1200 :
1201 0 : int GetHeatingCoilOutletNodeNum(EnergyPlusData &state, std::string const &DXHeatCoilSysName, bool &OutletNodeErrFlag)
1202 : {
1203 : // SUBROUTINE INFORMATION:
1204 : // AUTHOR Lixing Gu, FSEC
1205 : // DATE WRITTEN Apr. 2019
1206 : // PURPOSE OF THIS SUBROUTINE:
1207 : // Get Outlet node number
1208 :
1209 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1210 : int NodeNum;
1211 : int DXHeatSysNum;
1212 :
1213 0 : if (state.dataHVACDXHeatPumpSys->GetInputFlag) { // First time subroutine has been entered
1214 0 : GetDXHeatPumpSystemInput(state);
1215 0 : state.dataHVACDXHeatPumpSys->GetInputFlag = false;
1216 : }
1217 :
1218 0 : NodeNum = 0;
1219 0 : if (state.dataHVACDXHeatPumpSys->NumDXHeatPumpSystems > 0) {
1220 0 : DXHeatSysNum = UtilityRoutines::FindItemInList(DXHeatCoilSysName, state.dataHVACDXHeatPumpSys->DXHeatPumpSystem);
1221 0 : if (DXHeatSysNum > 0 && DXHeatSysNum <= state.dataHVACDXHeatPumpSys->NumDXHeatPumpSystems) {
1222 0 : NodeNum = state.dataHVACDXHeatPumpSys->DXHeatPumpSystem(DXHeatSysNum).DXHeatPumpCoilOutletNodeNum;
1223 : }
1224 : }
1225 0 : if (NodeNum == 0) OutletNodeErrFlag = true;
1226 :
1227 0 : return NodeNum;
1228 : }
1229 :
1230 : } // namespace HVACDXHeatPumpSystem
1231 :
1232 2313 : } // namespace EnergyPlus
|