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