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