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 19040 : 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 19040 : 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 19040 : auto &DXHeatPumpSystem(state.dataHVACDXHeatPumpSys->DXHeatPumpSystem);
131 :
132 : // Obtains and Allocates DX Cooling System related parameters from input file
133 19040 : if (state.dataHVACDXHeatPumpSys->GetInputFlag) { // First time subroutine has been entered
134 : // Get the DXCoolingSystem input
135 3 : GetDXHeatPumpSystemInput(state);
136 3 : state.dataHVACDXHeatPumpSys->GetInputFlag = false;
137 : }
138 :
139 19040 : int NumDXHeatPumpSystems = state.dataHVACDXHeatPumpSys->NumDXHeatPumpSystems;
140 :
141 : // Find the correct DXSystemNumber
142 19040 : if (CompIndex == 0) {
143 10868 : DXSystemNum = Util::FindItemInList(DXHeatPumpSystemName, DXHeatPumpSystem);
144 10868 : if (DXSystemNum == 0) {
145 0 : ShowFatalError(state, format("SimDXHeatPumpSystem: DXUnit not found={}", DXHeatPumpSystemName));
146 : }
147 10868 : CompIndex = DXSystemNum;
148 : } else {
149 8172 : DXSystemNum = CompIndex;
150 8172 : 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 8172 : if (state.dataHVACDXHeatPumpSys->CheckEquipName(DXSystemNum)) {
158 2 : 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 2 : state.dataHVACDXHeatPumpSys->CheckEquipName(DXSystemNum) = false;
166 : }
167 : }
168 :
169 19040 : if (present(OAUnitNum)) {
170 10866 : InitDXHeatPumpSystem(state, DXSystemNum, AirLoopNum, OAUnitNum, OAUCoilOutTemp);
171 : } else {
172 8174 : 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 19040 : ControlDXHeatingSystem(state, DXSystemNum, FirstHVACIteration);
178 :
179 : // simulate DX Heating System
180 19040 : CompName = DXHeatPumpSystem(DXSystemNum).HeatPumpCoilName;
181 :
182 19040 : switch (DXHeatPumpSystem(DXSystemNum).HeatPumpCoilType_Num) {
183 14953 : case HVAC::CoilDX_HeatingEmpirical: { // COIL:DX:COOLINGBYPASSFACTOREMPIRICAL
184 29906 : SimDXCoil(state,
185 : CompName,
186 : HVAC::CompressorOp::On,
187 : FirstHVACIteration,
188 14953 : DXHeatPumpSystem(DXSystemNum).HeatPumpCoilIndex,
189 14953 : DXHeatPumpSystem(DXSystemNum).fanOp,
190 14953 : DXHeatPumpSystem(DXSystemNum).PartLoadFrac);
191 14953 : } break;
192 4087 : case HVAC::Coil_HeatingAirToAirVariableSpeed: { // Coil:Heating:DX:VariableSpeed
193 4087 : SimVariableSpeedCoils(state,
194 : CompName,
195 4087 : DXHeatPumpSystem(DXSystemNum).HeatPumpCoilIndex,
196 4087 : DXHeatPumpSystem(DXSystemNum).fanOp,
197 : HVAC::CompressorOp::On,
198 4087 : DXHeatPumpSystem(DXSystemNum).PartLoadFrac,
199 4087 : DXHeatPumpSystem(DXSystemNum).SpeedNum,
200 4087 : DXHeatPumpSystem(DXSystemNum).SpeedRatio,
201 4087 : state.dataHVACDXHeatPumpSys->QZnReq,
202 4087 : state.dataHVACDXHeatPumpSys->QLatReq,
203 4087 : state.dataHVACDXHeatPumpSys->OnOffAirFlowRatio);
204 4087 : } 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 19040 : if (AirLoopNum != -1) { // IF the sysem is not an equipment of outdoor air unit
212 :
213 12244 : if ((DXHeatPumpSystem(DXSystemNum).PartLoadFrac > 0.0) &&
214 4070 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).CanLockoutEconoWithCompressor) {
215 0 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).ReqstEconoLockoutWithCompressor = true;
216 : } else {
217 8174 : state.dataAirLoop->AirLoopControlInfo(AirLoopNum).ReqstEconoLockoutWithCompressor = false;
218 : }
219 : }
220 :
221 19040 : if (present(QTotOut)) {
222 8174 : int InletNodeNum = DXHeatPumpSystem(DXSystemNum).DXHeatPumpCoilInletNodeNum;
223 8174 : int OutletNodeNum = DXHeatPumpSystem(DXSystemNum).DXHeatPumpCoilOutletNodeNum;
224 8174 : AirMassFlow = state.dataLoopNodes->Node(OutletNodeNum).MassFlowRate;
225 8174 : QTotOut = AirMassFlow * (state.dataLoopNodes->Node(InletNodeNum).Enthalpy - state.dataLoopNodes->Node(OutletNodeNum).Enthalpy);
226 : }
227 19040 : }
228 :
229 : // Get Input Section of the Module
230 : //******************************************************************************
231 :
232 3 : 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 3 : std::string CurrentModuleObject; // for ease in getting objects
266 3 : Array1D_string Alphas; // Alpha input items for object
267 3 : Array1D_string cAlphaFields; // Alpha field names
268 3 : Array1D_string cNumericFields; // Numeric field names
269 3 : Array1D<Real64> Numbers; // Numeric input items for object
270 3 : Array1D_bool lAlphaBlanks; // Logical array, alpha field input BLANK = .TRUE.
271 3 : Array1D_bool lNumericBlanks; // Logical array, numeric field input BLANK = .TRUE.
272 :
273 3 : auto &DXHeatPumpSystem(state.dataHVACDXHeatPumpSys->DXHeatPumpSystem);
274 :
275 3 : CurrentModuleObject = "CoilSystem:Heating:DX";
276 : // Update Num in state and make local convenience copy
277 6 : int NumDXHeatPumpSystems = state.dataHVACDXHeatPumpSys->NumDXHeatPumpSystems =
278 3 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
279 :
280 3 : DXHeatPumpSystem.allocate(NumDXHeatPumpSystems);
281 3 : state.dataHVACDXHeatPumpSys->CheckEquipName.dimension(NumDXHeatPumpSystems, true);
282 :
283 6 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
284 3 : state, "CoilSystem:Heating:DX", state.dataHVACDXHeatPumpSys->TotalArgs, NumAlphas, NumNums);
285 :
286 3 : Alphas.allocate(NumAlphas);
287 3 : cAlphaFields.allocate(NumAlphas);
288 3 : cNumericFields.allocate(NumNums);
289 3 : Numbers.dimension(NumNums, 0.0);
290 3 : lAlphaBlanks.dimension(NumAlphas, true);
291 3 : lNumericBlanks.dimension(NumNums, true);
292 :
293 : // Get the data for the DX Cooling System
294 6 : for (DXHeatSysNum = 1; DXHeatSysNum <= NumDXHeatPumpSystems; ++DXHeatSysNum) {
295 :
296 3 : 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 3 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
310 3 : DXHeatPumpSystem(DXHeatSysNum).DXHeatPumpSystemType = CurrentModuleObject; // push Object Name into data array
311 3 : DXHeatPumpSystem(DXHeatSysNum).Name = Alphas(1);
312 :
313 3 : if (lAlphaBlanks(2)) {
314 0 : DXHeatPumpSystem(DXHeatSysNum).availSched = Sched::GetScheduleAlwaysOn(state);
315 3 : } 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 3 : if (Util::SameString(Alphas(3), "Coil:Heating:DX:SingleSpeed")) {
321 :
322 2 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilType = Alphas(3);
323 2 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilType_Num = HVAC::CoilDX_HeatingEmpirical;
324 :
325 2 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilName = Alphas(4);
326 1 : } else if (Util::SameString(Alphas(3), "Coil:Heating:DX:VariableSpeed")) {
327 :
328 1 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilType = Alphas(3);
329 1 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilType_Num = HVAC::Coil_HeatingAirToAirVariableSpeed;
330 :
331 1 : 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 3 : if (DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilType_Num == HVAC::Coil_HeatingAirToAirVariableSpeed) {
340 2 : DXHeatPumpSystem(DXHeatSysNum).DXHeatPumpCoilInletNodeNum =
341 1 : GetCoilInletNodeVariableSpeed(state,
342 1 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilType,
343 1 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilName,
344 1 : state.dataHVACDXHeatPumpSys->ErrorsFound);
345 1 : DXHeatPumpSystem(DXHeatSysNum).DXHeatPumpCoilOutletNodeNum =
346 1 : GetCoilOutletNodeVariableSpeed(state,
347 1 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilType,
348 1 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilName,
349 1 : state.dataHVACDXHeatPumpSys->ErrorsFound);
350 : } else {
351 2 : DXHeatPumpSystem(DXHeatSysNum).DXHeatPumpCoilInletNodeNum = GetCoilInletNode(state,
352 2 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilType,
353 2 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilName,
354 2 : state.dataHVACDXHeatPumpSys->ErrorsFound);
355 :
356 2 : DXHeatPumpSystem(DXHeatSysNum).DXHeatPumpCoilOutletNodeNum = GetCoilOutletNode(state,
357 2 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilType,
358 2 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilName,
359 2 : state.dataHVACDXHeatPumpSys->ErrorsFound);
360 : }
361 :
362 : // Coil air-side outlet node is the control node
363 3 : DXHeatPumpSystem(DXHeatSysNum).DXSystemControlNodeNum = DXHeatPumpSystem(DXHeatSysNum).DXHeatPumpCoilOutletNodeNum;
364 :
365 6 : TestCompSet(state,
366 : CurrentModuleObject,
367 3 : DXHeatPumpSystem(DXHeatSysNum).Name,
368 3 : state.dataLoopNodes->NodeID(DXHeatPumpSystem(DXHeatSysNum).DXHeatPumpCoilInletNodeNum),
369 3 : state.dataLoopNodes->NodeID(DXHeatPumpSystem(DXHeatSysNum).DXHeatPumpCoilOutletNodeNum),
370 : "Air Nodes");
371 :
372 6 : ValidateComponent(state,
373 3 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilType,
374 3 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilName,
375 : IsNotOK,
376 : CurrentModuleObject);
377 3 : if (IsNotOK) {
378 0 : ShowContinueError(state, format("In {} = \"{}\".", CurrentModuleObject, DXHeatPumpSystem(DXHeatSysNum).Name));
379 0 : state.dataHVACDXHeatPumpSys->ErrorsFound = true;
380 : }
381 :
382 6 : SetUpCompSets(state,
383 3 : DXHeatPumpSystem(DXHeatSysNum).DXHeatPumpSystemType,
384 3 : DXHeatPumpSystem(DXHeatSysNum).Name,
385 3 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilType,
386 3 : DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilName,
387 3 : state.dataLoopNodes->NodeID(DXHeatPumpSystem(DXHeatSysNum).DXHeatPumpCoilInletNodeNum),
388 3 : state.dataLoopNodes->NodeID(DXHeatPumpSystem(DXHeatSysNum).DXHeatPumpCoilOutletNodeNum));
389 :
390 : // Supply air fan operating mode defaulted to constant fan cycling coil/compressor
391 3 : DXHeatPumpSystem(DXHeatSysNum).fanOp = HVAC::FanOp::Continuous;
392 :
393 3 : if (DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilType_Num != HVAC::Coil_HeatingAirToAirVariableSpeed) {
394 2 : SetCoilSystemHeatingDXFlag(state, DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilType, DXHeatPumpSystem(DXHeatSysNum).HeatPumpCoilName);
395 : }
396 :
397 : } // End of the DX System Loop
398 :
399 3 : if (state.dataHVACDXHeatPumpSys->ErrorsFound) {
400 0 : ShowFatalError(state, format("{}Errors found in input. Program terminates.", RoutineName));
401 : }
402 :
403 6 : for (DXHeatSysNum = 1; DXHeatSysNum <= NumDXHeatPumpSystems; ++DXHeatSysNum) {
404 : // Setup Report variables for the DXHeatingSystem that is not reported in the components themselves
405 6 : SetupOutputVariable(state,
406 : "Coil System Part Load Ratio",
407 : Constant::Units::None,
408 3 : DXHeatPumpSystem(DXHeatSysNum).PartLoadFrac,
409 : OutputProcessor::TimeStepType::System,
410 : OutputProcessor::StoreType::Average,
411 3 : DXHeatPumpSystem(DXHeatSysNum).Name);
412 : }
413 :
414 3 : Alphas.deallocate();
415 3 : cAlphaFields.deallocate();
416 3 : cNumericFields.deallocate();
417 3 : Numbers.deallocate();
418 3 : lAlphaBlanks.deallocate();
419 3 : lNumericBlanks.deallocate();
420 3 : }
421 :
422 : // End of Get Input subroutines for the Module
423 : //******************************************************************************
424 :
425 : // Beginning of Initialization subroutines for the Module
426 : // *****************************************************************************
427 :
428 19040 : 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 19040 : bool DoSetPointTest = state.dataHVACGlobal->DoSetPointTest;
452 : using EMSManager::CheckIfNodeSetPointManagedByEMS;
453 :
454 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
455 : int ControlNode; // control node number
456 19040 : Real64 OAUCoilOutletTemp = 0.0; // "ONLY" for zoneHVAC:OutdoorAirUnit
457 :
458 19040 : int NumDXHeatPumpSystems = state.dataHVACDXHeatPumpSys->NumDXHeatPumpSystems;
459 :
460 : // IF (MyOneTimeFlag) THEN
461 : // MyOneTimeFlag = .FALSE.
462 : // END IF
463 19040 : if (present(OAUnitNum)) { // This Dx system is component of ZoneHVAC:OutdoorAirUnit
464 10866 : OAUCoilOutletTemp = OAUCoilOutTemp;
465 : }
466 :
467 19040 : if (!state.dataGlobal->SysSizingCalc && state.dataHVACDXHeatPumpSys->MySetPointCheckFlag && DoSetPointTest) {
468 6 : for (int DXSysIndex = 1; DXSysIndex <= NumDXHeatPumpSystems; ++DXSysIndex) {
469 3 : auto &DXHeatPumpSystem = state.dataHVACDXHeatPumpSys->DXHeatPumpSystem(DXSysIndex);
470 3 : ControlNode = DXHeatPumpSystem.DXSystemControlNodeNum;
471 3 : if (ControlNode > 0) {
472 3 : if (AirLoopNum == -1) { // Outdoor Air Unit
473 1 : state.dataLoopNodes->Node(ControlNode).TempSetPoint = OAUCoilOutletTemp; // Set the coil outlet temperature
474 : } else { // Not an outdoor air unit
475 :
476 2 : 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 3 : state.dataHVACDXHeatPumpSys->MySetPointCheckFlag = false;
501 : }
502 :
503 : // These initializations are done every iteration
504 19040 : if (AirLoopNum == -1) { // This IF-Then routine is just for ZoneHVAC:OUTDOORAIRUNIT
505 :
506 10866 : state.dataHVACDXHeatPumpSys->DXHeatPumpSystem(DXSystemNum).DesiredOutletTemp = OAUCoilOutletTemp;
507 :
508 : } else { // Not Outdoor Air Unit
509 8174 : ControlNode = state.dataHVACDXHeatPumpSys->DXHeatPumpSystem(DXSystemNum).DXSystemControlNodeNum;
510 8174 : state.dataHVACDXHeatPumpSys->EconomizerFlag = state.dataAirLoop->AirLoopControlInfo(AirLoopNum).EconoActive;
511 8174 : state.dataHVACDXHeatPumpSys->DXHeatPumpSystem(DXSystemNum).DesiredOutletTemp = state.dataLoopNodes->Node(ControlNode).TempSetPoint;
512 : }
513 19040 : }
514 :
515 : // End of Initialization subroutines for the Module
516 : // *****************************************************************************
517 :
518 : // Beginning of Calculation subroutines for the DXCoolingSystem Module
519 : // *****************************************************************************
520 :
521 19040 : 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 19040 : int constexpr MaxIte(500); // Maximum number of iterations for solver
553 19040 : Real64 constexpr Acc(1.e-3); // Accuracy of solver result
554 :
555 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
556 19040 : 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 19040 : auto &DXHeatPumpSystem = state.dataHVACDXHeatPumpSys->DXHeatPumpSystem(DXSystemNum);
583 :
584 : // Set local variables
585 : // Retrieve the load on the controlled zone
586 19040 : OutletNode = DXHeatPumpSystem.DXHeatPumpCoilOutletNodeNum;
587 19040 : InletNode = DXHeatPumpSystem.DXHeatPumpCoilInletNodeNum;
588 19040 : ControlNode = DXHeatPumpSystem.DXSystemControlNodeNum;
589 19040 : DesOutTemp = DXHeatPumpSystem.DesiredOutletTemp;
590 19040 : CompName = DXHeatPumpSystem.HeatPumpCoilName;
591 19040 : fanOp = DXHeatPumpSystem.fanOp;
592 :
593 19040 : PartLoadFrac = 0.0;
594 :
595 19040 : SensibleLoad = false;
596 :
597 19040 : SpeedNum = 1;
598 19040 : QZnReq = 0.0;
599 19040 : QLatReq = 0.0;
600 19040 : OnOffAirFlowRatio = 1.0;
601 19040 : TempSpeedOut = 0.0;
602 19040 : TempSpeedReqst = 0.0;
603 19040 : NumOfSpeeds = 0;
604 19040 : VSCoilIndex = 0;
605 19040 : I = 1;
606 19040 : SpeedRatio = 0.0;
607 :
608 : // If there is a fault of coil SAT Sensor
609 19040 : 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 19040 : 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 19022 : if ((state.dataLoopNodes->Node(InletNode).Temp < state.dataLoopNodes->Node(ControlNode).TempSetPoint) &&
623 25022 : (state.dataLoopNodes->Node(InletNode).Temp < DesOutTemp) &&
624 6000 : (std::abs(state.dataLoopNodes->Node(InletNode).Temp - DesOutTemp) > TempControlTol)) {
625 4070 : SensibleLoad = true;
626 : }
627 :
628 : // If DXHeatingSystem runs with a heating load then set PartLoadFrac on Heating System
629 19022 : if (SensibleLoad) {
630 : {
631 : Real64 TempOut1;
632 :
633 4070 : switch (DXHeatPumpSystem.HeatPumpCoilType_Num) {
634 2035 : case HVAC::CoilDX_HeatingEmpirical: { // Coil:Heating:DX:SingleSpeed
635 :
636 : // Get no load result
637 2035 : PartLoadFrac = 0.0;
638 4070 : SimDXCoil(
639 2035 : state, CompName, HVAC::CompressorOp::On, FirstHVACIteration, DXHeatPumpSystem.HeatPumpCoilIndex, fanOp, PartLoadFrac);
640 2035 : NoOutput = state.dataLoopNodes->Node(InletNode).MassFlowRate *
641 2035 : (PsyHFnTdbW(state.dataLoopNodes->Node(OutletNode).Temp, state.dataLoopNodes->Node(OutletNode).HumRat) -
642 2035 : PsyHFnTdbW(state.dataLoopNodes->Node(InletNode).Temp, state.dataLoopNodes->Node(OutletNode).HumRat));
643 :
644 : // Get full load result
645 2035 : PartLoadFrac = 1.0;
646 4070 : SimDXCoil(
647 2035 : state, CompName, HVAC::CompressorOp::On, FirstHVACIteration, DXHeatPumpSystem.HeatPumpCoilIndex, fanOp, PartLoadFrac);
648 :
649 2035 : FullOutput = state.dataLoopNodes->Node(InletNode).MassFlowRate *
650 2035 : (PsyHFnTdbW(state.dataLoopNodes->Node(OutletNode).Temp, state.dataLoopNodes->Node(InletNode).HumRat) -
651 2035 : PsyHFnTdbW(state.dataLoopNodes->Node(InletNode).Temp, state.dataLoopNodes->Node(InletNode).HumRat));
652 :
653 2035 : ReqOutput = state.dataLoopNodes->Node(InletNode).MassFlowRate *
654 2035 : (PsyHFnTdbW(DesOutTemp, state.dataLoopNodes->Node(InletNode).HumRat) -
655 2035 : PsyHFnTdbW(state.dataLoopNodes->Node(InletNode).Temp, state.dataLoopNodes->Node(InletNode).HumRat));
656 2035 : TempOut1 = state.dataLoopNodes->Node(OutletNode).Temp;
657 : // IF NoOutput is higher than (more heating than required) or very near the ReqOutput, do not run the compressor
658 2035 : if ((NoOutput - ReqOutput) > Acc) {
659 0 : PartLoadFrac = 0.0;
660 : // If the FullOutput is greater than (insufficient heating) or very near the ReqOutput,
661 : // run the compressor at PartLoadFrac = 1.
662 2035 : } else if ((FullOutput - ReqOutput) < Acc) {
663 2033 : PartLoadFrac = 1.0;
664 : // Else find the PLR to meet the load
665 : } else {
666 : // OutletTempDXCoil is the full capacity outlet temperature at PartLoadFrac = 1 from the CALL above. If this
667 : // temp is greater than the desired outlet temp, then run the compressor at PartLoadFrac = 1, otherwise find the
668 : // operating PLR.
669 2 : OutletTempDXCoil = state.dataDXCoils->DXCoilOutletTemp(DXHeatPumpSystem.HeatPumpCoilIndex);
670 2 : if (OutletTempDXCoil < DesOutTemp) {
671 0 : PartLoadFrac = 1.0;
672 : } else {
673 2 : if (state.dataGlobal->DoCoilDirectSolutions) {
674 0 : PartLoadFrac = (DesOutTemp - state.dataLoopNodes->Node(InletNode).Temp) /
675 0 : (TempOut1 - state.dataLoopNodes->Node(InletNode).Temp);
676 0 : SimDXCoil(state,
677 : CompName,
678 : HVAC::CompressorOp::On,
679 : FirstHVACIteration,
680 0 : DXHeatPumpSystem.HeatPumpCoilIndex,
681 : fanOp,
682 : PartLoadFrac);
683 : } else {
684 2 : int coilIndex = DXHeatPumpSystem.HeatPumpCoilIndex;
685 6 : auto f = [&state, coilIndex, DesOutTemp](Real64 const PartLoadFrac) {
686 6 : DXCoils::CalcDXHeatingCoil(state, coilIndex, PartLoadFrac, HVAC::FanOp::Continuous, 1.0);
687 6 : Real64 OutletAirTemp = state.dataDXCoils->DXCoilOutletTemp(coilIndex);
688 6 : return DesOutTemp - OutletAirTemp;
689 2 : };
690 2 : int SolFla = 0;
691 2 : SolveRoot(state, Acc, MaxIte, SolFla, PartLoadFrac, f, 0.0, 1.0);
692 2 : if (SolFla == -1) {
693 0 : if (!state.dataGlobal->WarmupFlag) {
694 0 : if (DXHeatPumpSystem.DXCoilSensPLRIter < 1) {
695 0 : ++DXHeatPumpSystem.DXCoilSensPLRIter;
696 0 : ShowWarningError(
697 : state,
698 0 : format("{} - Iteration limit exceeded calculating DX unit sensible part-load ratio for unit = {}",
699 0 : DXHeatPumpSystem.DXHeatPumpSystemType,
700 0 : DXHeatPumpSystem.Name));
701 0 : ShowContinueError(state, format("Estimated part-load ratio = {:.3R}", (ReqOutput / FullOutput)));
702 0 : ShowContinueError(state, format("Calculated part-load ratio = {:.3R}", PartLoadFrac));
703 0 : ShowContinueErrorTimeStamp(
704 : state,
705 : "The calculated part-load ratio will be used and the simulation continues. Occurrence info:");
706 : } else {
707 0 : ShowRecurringWarningErrorAtEnd(state,
708 0 : DXHeatPumpSystem.DXHeatPumpSystemType + " \"" + DXHeatPumpSystem.Name +
709 : "\" - Iteration limit exceeded calculating sensible part-load "
710 : "ratio error continues. Sensible "
711 : "PLR statistics follow.",
712 0 : DXHeatPumpSystem.DXCoilSensPLRIterIndex,
713 : PartLoadFrac,
714 : PartLoadFrac);
715 : }
716 : }
717 2 : } else if (SolFla == -2) {
718 0 : PartLoadFrac = ReqOutput / FullOutput;
719 0 : if (!state.dataGlobal->WarmupFlag) {
720 0 : if (DXHeatPumpSystem.DXCoilSensPLRFail < 1) {
721 0 : ++DXHeatPumpSystem.DXCoilSensPLRFail;
722 0 : ShowWarningError(state,
723 0 : format("{} - DX unit sensible part-load ratio calculation failed: part-load ratio "
724 : "limits exceeded, for unit = {}",
725 0 : DXHeatPumpSystem.DXHeatPumpSystemType,
726 0 : DXHeatPumpSystem.Name));
727 0 : ShowContinueError(state, format("Estimated part-load ratio = {:.3R}", PartLoadFrac));
728 0 : ShowContinueErrorTimeStamp(
729 : state,
730 : "The estimated part-load ratio will be used and the simulation continues. Occurrence info:");
731 : } else {
732 0 : ShowRecurringWarningErrorAtEnd(
733 : state,
734 0 : DXHeatPumpSystem.DXHeatPumpSystemType + " \"" + DXHeatPumpSystem.Name +
735 : "\" - DX unit sensible part-load ratio calculation failed error continues. Sensible PLR "
736 : "statistics follow.",
737 0 : DXHeatPumpSystem.DXCoilSensPLRFailIndex,
738 : PartLoadFrac,
739 : PartLoadFrac);
740 : }
741 : }
742 : }
743 : }
744 : }
745 : }
746 :
747 2035 : if (PartLoadFrac > 1.0) {
748 0 : PartLoadFrac = 1.0;
749 2035 : } else if (PartLoadFrac < 0.0) {
750 0 : PartLoadFrac = 0.0;
751 : }
752 2035 : } break;
753 2035 : case HVAC::Coil_HeatingAirToAirVariableSpeed: {
754 : // variable-speed air-to-air heating coil, begin -------------------------
755 : // Get no load result
756 2035 : PartLoadFrac = 0.0;
757 2035 : SpeedNum = 1;
758 2035 : QZnReq = 0.0;
759 2035 : QLatReq = 0.0;
760 2035 : OnOffAirFlowRatio = 1.0;
761 2035 : SpeedRatio = 0.0;
762 :
763 2035 : SimVariableSpeedCoils(state,
764 : CompName,
765 2035 : DXHeatPumpSystem.HeatPumpCoilIndex,
766 : fanOp,
767 : HVAC::CompressorOp::On,
768 : PartLoadFrac,
769 : SpeedNum,
770 : SpeedRatio,
771 : QZnReq,
772 : QLatReq,
773 : OnOffAirFlowRatio);
774 :
775 2035 : VSCoilIndex = DXHeatPumpSystem.HeatPumpCoilIndex;
776 2035 : NumOfSpeeds = state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilIndex).NumOfSpeeds;
777 :
778 2035 : NoOutput = state.dataLoopNodes->Node(InletNode).MassFlowRate *
779 2035 : (PsyHFnTdbW(state.dataLoopNodes->Node(OutletNode).Temp, state.dataLoopNodes->Node(OutletNode).HumRat) -
780 2035 : PsyHFnTdbW(state.dataLoopNodes->Node(InletNode).Temp, state.dataLoopNodes->Node(OutletNode).HumRat));
781 :
782 : // Get full load result
783 2035 : PartLoadFrac = 1.0;
784 :
785 2035 : SpeedNum = NumOfSpeeds;
786 2035 : SpeedRatio = 1.0;
787 2035 : QZnReq = 0.001; // to indicate the coil is running
788 2035 : SimVariableSpeedCoils(state,
789 : CompName,
790 : VSCoilIndex,
791 : fanOp,
792 : HVAC::CompressorOp::On,
793 : PartLoadFrac,
794 : SpeedNum,
795 : SpeedRatio,
796 : QZnReq,
797 : QLatReq,
798 : OnOffAirFlowRatio);
799 :
800 2035 : FullOutput = state.dataLoopNodes->Node(InletNode).MassFlowRate *
801 2035 : (PsyHFnTdbW(state.dataLoopNodes->Node(OutletNode).Temp, state.dataLoopNodes->Node(InletNode).HumRat) -
802 2035 : PsyHFnTdbW(state.dataLoopNodes->Node(InletNode).Temp, state.dataLoopNodes->Node(InletNode).HumRat));
803 :
804 2035 : ReqOutput = state.dataLoopNodes->Node(InletNode).MassFlowRate *
805 2035 : (PsyHFnTdbW(DesOutTemp, state.dataLoopNodes->Node(InletNode).HumRat) -
806 2035 : PsyHFnTdbW(state.dataLoopNodes->Node(InletNode).Temp, state.dataLoopNodes->Node(InletNode).HumRat));
807 : // IF NoOutput is higher than (more heating than required) or very near the ReqOutput, do not run the compressor
808 2035 : if ((NoOutput - ReqOutput) > Acc) {
809 0 : PartLoadFrac = 0.0;
810 0 : SpeedNum = 1;
811 0 : SpeedRatio = 0.0;
812 : // If the FullOutput is greater than (insufficient heating) or very near the ReqOutput,
813 : // run the compressor at PartLoadFrac = 1.
814 2035 : } else if ((FullOutput - ReqOutput) < Acc) {
815 2035 : PartLoadFrac = 1.0;
816 2035 : SpeedNum = NumOfSpeeds;
817 2035 : SpeedRatio = 1.0;
818 : // Else find the PLR to meet the load
819 : } else {
820 : // OutletTempDXCoil is the full capacity outlet temperature at PartLoadFrac = 1 from the CALL above. If this
821 : // temp is greater than the desired outlet temp, then run the compressor at PartLoadFrac = 1, otherwise find the
822 : // operating PLR.
823 0 : OutletTempDXCoil = state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilIndex).OutletAirDBTemp;
824 0 : if (OutletTempDXCoil < DesOutTemp) {
825 0 : PartLoadFrac = 1.0;
826 0 : SpeedNum = NumOfSpeeds;
827 0 : SpeedRatio = 1.0;
828 : } else {
829 0 : PartLoadFrac = 1.0;
830 0 : SpeedNum = 1;
831 0 : SpeedRatio = 1.0;
832 0 : QZnReq = 0.001; // to indicate the coil is running
833 0 : SimVariableSpeedCoils(state,
834 : CompName,
835 : VSCoilIndex,
836 : fanOp,
837 : HVAC::CompressorOp::On,
838 : PartLoadFrac,
839 : SpeedNum,
840 : SpeedRatio,
841 : QZnReq,
842 : QLatReq,
843 : OnOffAirFlowRatio);
844 :
845 0 : TempSpeedOut = state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilIndex).OutletAirDBTemp;
846 :
847 0 : if ((TempSpeedOut - DesOutTemp) < Acc) {
848 : // Check to see which speed to meet the load
849 0 : PartLoadFrac = 1.0;
850 0 : SpeedRatio = 1.0;
851 0 : TempOut1 = TempSpeedOut;
852 0 : for (I = 2; I <= NumOfSpeeds; ++I) {
853 0 : SpeedNum = I;
854 0 : SimVariableSpeedCoils(state,
855 : CompName,
856 : VSCoilIndex,
857 : fanOp,
858 : HVAC::CompressorOp::On,
859 : PartLoadFrac,
860 : SpeedNum,
861 : SpeedRatio,
862 : QZnReq,
863 : QLatReq,
864 : OnOffAirFlowRatio);
865 :
866 0 : TempSpeedOut = state.dataVariableSpeedCoils->VarSpeedCoil(VSCoilIndex).OutletAirDBTemp;
867 :
868 0 : if ((TempSpeedOut - DesOutTemp) > Acc) {
869 0 : SpeedNum = I;
870 0 : break;
871 : }
872 0 : TempOut1 = TempSpeedOut;
873 : }
874 0 : if (state.dataGlobal->DoCoilDirectSolutions) {
875 0 : SpeedRatio = (DesOutTemp - TempOut1) / (TempSpeedOut - TempOut1);
876 0 : SimVariableSpeedCoils(state,
877 : CompName,
878 : VSCoilIndex,
879 : fanOp,
880 : HVAC::CompressorOp::On,
881 : PartLoadFrac,
882 : SpeedNum,
883 : SpeedRatio,
884 : QZnReq,
885 : QLatReq,
886 : OnOffAirFlowRatio);
887 : } else {
888 0 : auto f = [&state, VSCoilIndex, DesOutTemp, SpeedNum, fanOp](Real64 const x) {
889 0 : return VSCoilSpeedResidual(state, x, VSCoilIndex, DesOutTemp, SpeedNum, fanOp);
890 0 : };
891 0 : int SolFla = 0;
892 0 : General::SolveRoot(state, Acc, MaxIte, SolFla, SpeedRatio, f, 1.0e-10, 1.0);
893 :
894 0 : if (SolFla == -1) {
895 0 : if (!state.dataGlobal->WarmupFlag) {
896 0 : if (DXHeatPumpSystem.DXCoilSensPLRIter < 1) {
897 0 : ++DXHeatPumpSystem.DXCoilSensPLRIter;
898 0 : ShowWarningError(state,
899 0 : format("{} - Iteration limit exceeded calculating DX unit sensible part-load "
900 : "ratio for unit = {}",
901 0 : DXHeatPumpSystem.DXHeatPumpSystemType,
902 0 : DXHeatPumpSystem.Name));
903 0 : ShowContinueError(state, format("Estimated part-load ratio = {:.3R}", (ReqOutput / FullOutput)));
904 0 : ShowContinueError(state, format("Calculated part-load ratio = {:.3R}", PartLoadFrac));
905 0 : ShowContinueErrorTimeStamp(
906 : state,
907 : "The calculated part-load ratio will be used and the simulation continues. Occurrence info:");
908 : } else {
909 0 : ShowRecurringWarningErrorAtEnd(
910 : state,
911 0 : DXHeatPumpSystem.DXHeatPumpSystemType + " \"" + DXHeatPumpSystem.Name +
912 : "\" - Iteration limit exceeded calculating sensible part-load ratio error continues. "
913 : "Sensible PLR statistics follow.",
914 0 : DXHeatPumpSystem.DXCoilSensPLRIterIndex,
915 : PartLoadFrac,
916 : PartLoadFrac);
917 : }
918 : }
919 0 : } else if (SolFla == -2) {
920 0 : PartLoadFrac = ReqOutput / FullOutput;
921 0 : if (!state.dataGlobal->WarmupFlag) {
922 0 : if (DXHeatPumpSystem.DXCoilSensPLRFail < 1) {
923 0 : ++DXHeatPumpSystem.DXCoilSensPLRFail;
924 0 : ShowWarningError(state,
925 0 : format("{} - DX unit sensible part-load ratio calculation failed: part-load "
926 : "ratio limits exceeded, for unit = {}",
927 0 : DXHeatPumpSystem.DXHeatPumpSystemType,
928 0 : DXHeatPumpSystem.Name));
929 0 : ShowContinueError(state, format("Estimated part-load ratio = {:.3R}", PartLoadFrac));
930 0 : ShowContinueErrorTimeStamp(
931 : state,
932 : "The estimated part-load ratio will be used and the simulation continues. Occurrence info:");
933 : } else {
934 0 : ShowRecurringWarningErrorAtEnd(
935 : state,
936 0 : DXHeatPumpSystem.DXHeatPumpSystemType + " \"" + DXHeatPumpSystem.Name +
937 : "\" - DX unit sensible part-load ratio calculation failed error continues. Sensible PLR "
938 : "statistics follow.",
939 0 : DXHeatPumpSystem.DXCoilSensPLRFailIndex,
940 : PartLoadFrac,
941 : PartLoadFrac);
942 : }
943 : }
944 : }
945 : }
946 : } else {
947 0 : if (state.dataGlobal->DoCoilDirectSolutions) {
948 0 : PartLoadFrac = (DesOutTemp - state.dataLoopNodes->Node(InletNode).Temp) /
949 0 : (TempSpeedOut - state.dataLoopNodes->Node(InletNode).Temp);
950 0 : SimVariableSpeedCoils(state,
951 : CompName,
952 : VSCoilIndex,
953 : fanOp,
954 : HVAC::CompressorOp::On,
955 : PartLoadFrac,
956 : SpeedNum,
957 : SpeedRatio,
958 : QZnReq,
959 : QLatReq,
960 : OnOffAirFlowRatio);
961 : } else {
962 0 : auto f = [&state, VSCoilIndex, DesOutTemp, fanOp](Real64 const x) {
963 0 : return VSCoilCyclingResidual(state, x, VSCoilIndex, DesOutTemp, fanOp);
964 0 : };
965 0 : int SolFla = 0;
966 0 : General::SolveRoot(state, Acc, MaxIte, SolFla, PartLoadFrac, f, 1.0e-10, 1.0);
967 0 : if (SolFla == -1) {
968 0 : if (!state.dataGlobal->WarmupFlag) {
969 0 : if (DXHeatPumpSystem.DXCoilSensPLRIter < 1) {
970 0 : ++DXHeatPumpSystem.DXCoilSensPLRIter;
971 0 : ShowWarningError(state,
972 0 : format("{} - Iteration limit exceeded calculating DX unit sensible part-load "
973 : "ratio for unit = {}",
974 0 : DXHeatPumpSystem.DXHeatPumpSystemType,
975 0 : DXHeatPumpSystem.Name));
976 0 : ShowContinueError(state, format("Estimated part-load ratio = {:.3R}", (ReqOutput / FullOutput)));
977 0 : ShowContinueError(state, format("Calculated part-load ratio = {:.3R}", PartLoadFrac));
978 0 : ShowContinueErrorTimeStamp(
979 : state,
980 : "The calculated part-load ratio will be used and the simulation continues. Occurrence info:");
981 : } else {
982 0 : ShowRecurringWarningErrorAtEnd(
983 : state,
984 0 : DXHeatPumpSystem.DXHeatPumpSystemType + " \"" + DXHeatPumpSystem.Name +
985 : "\" - Iteration limit exceeded calculating sensible part-load ratio error continues. "
986 : "Sensible PLR statistics follow.",
987 0 : DXHeatPumpSystem.DXCoilSensPLRIterIndex,
988 : PartLoadFrac,
989 : PartLoadFrac);
990 : }
991 : }
992 0 : } else if (SolFla == -2) {
993 0 : PartLoadFrac = ReqOutput / FullOutput;
994 0 : if (!state.dataGlobal->WarmupFlag) {
995 0 : if (DXHeatPumpSystem.DXCoilSensPLRFail < 1) {
996 0 : ++DXHeatPumpSystem.DXCoilSensPLRFail;
997 0 : ShowWarningError(state,
998 0 : format("{} - DX unit sensible part-load ratio calculation failed: part-load "
999 : "ratio limits exceeded, for unit = {}",
1000 0 : DXHeatPumpSystem.DXHeatPumpSystemType,
1001 0 : DXHeatPumpSystem.Name));
1002 0 : ShowContinueError(state, format("Estimated part-load ratio = {:.3R}", PartLoadFrac));
1003 0 : ShowContinueErrorTimeStamp(
1004 : state,
1005 : "The estimated part-load ratio will be used and the simulation continues. Occurrence info:");
1006 : } else {
1007 0 : ShowRecurringWarningErrorAtEnd(
1008 : state,
1009 0 : DXHeatPumpSystem.DXHeatPumpSystemType + " \"" + DXHeatPumpSystem.Name +
1010 : "\" - DX unit sensible part-load ratio calculation failed error continues. Sensible PLR "
1011 : "statistics follow.",
1012 0 : DXHeatPumpSystem.DXCoilSensPLRFailIndex,
1013 : PartLoadFrac,
1014 : PartLoadFrac);
1015 : }
1016 : }
1017 : }
1018 : }
1019 : }
1020 : }
1021 : }
1022 :
1023 2035 : if (PartLoadFrac > 1.0) {
1024 0 : PartLoadFrac = 1.0;
1025 2035 : } else if (PartLoadFrac < 0.0) {
1026 0 : PartLoadFrac = 0.0;
1027 : }
1028 2035 : } break;
1029 0 : default: {
1030 0 : ShowFatalError(state,
1031 0 : format("ControlDXHeatingSystem: Invalid DXHeatPumpSystem coil type = {}", DXHeatPumpSystem.HeatPumpCoilType));
1032 0 : } break;
1033 : }
1034 : }
1035 : } // End of cooling load type (sensible or latent) if block
1036 : } // End of If DXheatingSystem is scheduled on and there is flow
1037 :
1038 : // Set the final results
1039 19040 : DXHeatPumpSystem.PartLoadFrac = PartLoadFrac;
1040 19040 : DXHeatPumpSystem.SpeedRatio = SpeedRatio;
1041 19040 : DXHeatPumpSystem.SpeedNum = SpeedNum;
1042 19040 : }
1043 :
1044 : //******************************************************************************
1045 :
1046 16974 : Real64 VSCoilCyclingResidual(EnergyPlusData &state,
1047 : Real64 const PartLoadRatio, // compressor cycling ratio (1.0 is continuous, 0.0 is off)
1048 : int CoilIndex,
1049 : Real64 desiredTemp,
1050 : HVAC::FanOp fanOp)
1051 : {
1052 : // FUNCTION INFORMATION:
1053 : // AUTHOR Bo Shen
1054 : // DATE WRITTEN Feb, 2013
1055 : // MODIFIED na
1056 : // RE-ENGINEERED na
1057 :
1058 : // PURPOSE OF THIS FUNCTION:
1059 : // Calculates residual function, iterate part-load ratio
1060 : // compare the desired temperature value with exit temperature from a variable-speed heating coil
1061 :
1062 16974 : VariableSpeedCoils::SimVariableSpeedCoils(state,
1063 : "",
1064 : CoilIndex,
1065 : fanOp,
1066 : HVAC::CompressorOp::On,
1067 : PartLoadRatio,
1068 16974 : state.dataHVACDXHeatPumpSys->SpeedNum,
1069 16974 : state.dataHVACDXHeatPumpSys->SpeedRatio,
1070 16974 : state.dataHVACDXHeatPumpSys->QZnReqr,
1071 16974 : state.dataHVACDXHeatPumpSys->QLatReqr,
1072 16974 : state.dataHVACDXHeatPumpSys->OnandOffAirFlowRatio);
1073 :
1074 16974 : Real64 OutletAirTemp = state.dataVariableSpeedCoils->VarSpeedCoil(CoilIndex).OutletAirDBTemp;
1075 16974 : return desiredTemp - OutletAirTemp;
1076 : }
1077 :
1078 : //******************************************************************************
1079 :
1080 3 : Real64 VSCoilSpeedResidual(EnergyPlusData &state,
1081 : Real64 const SpeedRatio, // compressor cycling ratio (1.0 is continuous, 0.0 is off)
1082 : int CoilIndex,
1083 : Real64 desiredTemp,
1084 : int speedNumber,
1085 : HVAC::FanOp const fanOp)
1086 : {
1087 : // FUNCTION INFORMATION:
1088 : // AUTHOR Bo Shen
1089 : // DATE WRITTEN Feb, 2013
1090 : // MODIFIED na
1091 : // RE-ENGINEERED na
1092 :
1093 : // PURPOSE OF THIS FUNCTION:
1094 : // Calculates residual function, iterate speed ratio
1095 : // compare the desired temperature value with exit temperature from a variable-speed heating coil
1096 3 : state.dataHVACDXHeatPumpSys->SpeedNumber = speedNumber;
1097 3 : VariableSpeedCoils::SimVariableSpeedCoils(state,
1098 : "",
1099 : CoilIndex,
1100 : fanOp,
1101 : HVAC::CompressorOp::On,
1102 3 : state.dataHVACDXHeatPumpSys->SpeedPartLoadRatio,
1103 3 : state.dataHVACDXHeatPumpSys->SpeedNumber,
1104 : SpeedRatio,
1105 3 : state.dataHVACDXHeatPumpSys->QZoneReq,
1106 3 : state.dataHVACDXHeatPumpSys->QLatentReq,
1107 3 : state.dataHVACDXHeatPumpSys->AirFlowOnOffRatio);
1108 3 : Real64 OutletAirTemp = state.dataVariableSpeedCoils->VarSpeedCoil(CoilIndex).OutletAirDBTemp;
1109 3 : return desiredTemp - OutletAirTemp;
1110 : }
1111 :
1112 0 : int GetHeatingCoilInletNodeNum(EnergyPlusData &state, std::string const &DXHeatCoilSysName, bool &InletNodeErrFlag)
1113 : {
1114 : // SUBROUTINE INFORMATION:
1115 : // AUTHOR Lixing Gu, FSEC
1116 : // DATE WRITTEN Apr. 2019
1117 : // PURPOSE OF THIS SUBROUTINE:
1118 : // Get inlet node number
1119 :
1120 0 : if (state.dataHVACDXHeatPumpSys->GetInputFlag) { // First time subroutine has been entered
1121 0 : GetDXHeatPumpSystemInput(state);
1122 0 : state.dataHVACDXHeatPumpSys->GetInputFlag = false;
1123 : }
1124 :
1125 0 : int NodeNum = 0;
1126 0 : if (state.dataHVACDXHeatPumpSys->NumDXHeatPumpSystems > 0) {
1127 0 : int DXHeatSysNum = Util::FindItemInList(DXHeatCoilSysName, state.dataHVACDXHeatPumpSys->DXHeatPumpSystem);
1128 0 : if (DXHeatSysNum > 0 && DXHeatSysNum <= state.dataHVACDXHeatPumpSys->NumDXHeatPumpSystems) {
1129 0 : NodeNum = state.dataHVACDXHeatPumpSys->DXHeatPumpSystem(DXHeatSysNum).DXHeatPumpCoilInletNodeNum;
1130 : }
1131 : }
1132 0 : if (NodeNum == 0) {
1133 0 : InletNodeErrFlag = true;
1134 : }
1135 :
1136 0 : return NodeNum;
1137 : }
1138 :
1139 0 : int GetHeatingCoilOutletNodeNum(EnergyPlusData &state, std::string const &DXHeatCoilSysName, bool &OutletNodeErrFlag)
1140 : {
1141 : // SUBROUTINE INFORMATION:
1142 : // AUTHOR Lixing Gu, FSEC
1143 : // DATE WRITTEN Apr. 2019
1144 : // PURPOSE OF THIS SUBROUTINE:
1145 : // Get Outlet node number
1146 :
1147 0 : if (state.dataHVACDXHeatPumpSys->GetInputFlag) { // First time subroutine has been entered
1148 0 : GetDXHeatPumpSystemInput(state);
1149 0 : state.dataHVACDXHeatPumpSys->GetInputFlag = false;
1150 : }
1151 :
1152 0 : int NodeNum = 0;
1153 0 : if (state.dataHVACDXHeatPumpSys->NumDXHeatPumpSystems > 0) {
1154 0 : int DXHeatSysNum = Util::FindItemInList(DXHeatCoilSysName, state.dataHVACDXHeatPumpSys->DXHeatPumpSystem);
1155 0 : if (DXHeatSysNum > 0 && DXHeatSysNum <= state.dataHVACDXHeatPumpSys->NumDXHeatPumpSystems) {
1156 0 : NodeNum = state.dataHVACDXHeatPumpSys->DXHeatPumpSystem(DXHeatSysNum).DXHeatPumpCoilOutletNodeNum;
1157 : }
1158 : }
1159 0 : if (NodeNum == 0) {
1160 0 : OutletNodeErrFlag = true;
1161 : }
1162 :
1163 0 : return NodeNum;
1164 : }
1165 :
1166 : } // namespace HVACDXHeatPumpSystem
1167 :
1168 : } // namespace EnergyPlus
|