Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // C++ Headers
49 : #include <cmath>
50 :
51 : // ObjexxFCL Headers
52 : #include <ObjexxFCL/Array.functions.hh>
53 :
54 : // EnergyPlus Headers
55 : #include <EnergyPlus/BranchNodeConnections.hh>
56 : #include <EnergyPlus/CurveManager.hh>
57 : #include <EnergyPlus/Data/EnergyPlusData.hh>
58 : #include <EnergyPlus/DataContaminantBalance.hh>
59 : #include <EnergyPlus/DataHVACGlobals.hh>
60 : #include <EnergyPlus/DataLoopNode.hh>
61 : #include <EnergyPlus/FluidProperties.hh>
62 : #include <EnergyPlus/General.hh>
63 : #include <EnergyPlus/GlobalNames.hh>
64 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
65 : #include <EnergyPlus/NodeInputManager.hh>
66 : #include <EnergyPlus/OutputProcessor.hh>
67 : #include <EnergyPlus/OutputReportPredefined.hh>
68 : #include <EnergyPlus/Plant/DataPlant.hh>
69 : #include <EnergyPlus/PlantUtilities.hh>
70 : #include <EnergyPlus/Psychrometrics.hh>
71 : #include <EnergyPlus/UtilityRoutines.hh>
72 : #include <EnergyPlus/WaterToAirHeatPump.hh>
73 :
74 : namespace EnergyPlus {
75 :
76 : namespace WaterToAirHeatPump {
77 : // Module containing the Water to Air Heat Pump simulation routines
78 :
79 : // MODULE INFORMATION:
80 : // AUTHOR Hui Jin
81 : // DATE WRITTEN Oct 2000
82 : // MODIFIED Dan Fisher, Kenneth Tang (Jan 2004)
83 : // Brent Griffith, plant upgrades, fluid props
84 :
85 : // PURPOSE OF THIS MODULE:
86 : // To encapsulate the data and algorithms required to
87 : // manage the Water to Air Heat Pump Component
88 :
89 : // METHODOLOGY EMPLOYED:
90 :
91 : // REFERENCES:
92 : // Jin, H. 2002. Parameter Estimation Based Models of Water Source Heat Pumps. Phd Thesis.
93 : // Oklahoma State University.
94 :
95 0 : void SimWatertoAirHP(EnergyPlusData &state,
96 : std::string_view CompName, // component name
97 : int &CompIndex, // Index for Component name
98 : Real64 const DesignAirflow, // design air flow rate
99 : HVAC::FanOp const fanOp, // cycling scheme--either continuous fan/cycling compressor or
100 : bool const FirstHVACIteration, // first iteration flag
101 : bool const InitFlag, // initialization flag used to suppress property routine errors
102 : Real64 const SensLoad, // sensible load
103 : Real64 const LatentLoad, // latent load
104 : HVAC::CompressorOp const compressorOp,
105 : Real64 const PartLoadRatio)
106 : {
107 :
108 : // SUBROUTINE INFORMATION:
109 : // AUTHOR Hui Jin
110 : // DATE WRITTEN Oct 2000
111 : // MODIFIED Dan Fisher, Kenneth Tang (Jan 2004)
112 :
113 : // PURPOSE OF THIS SUBROUTINE:
114 : // This subroutine manages Water to Air Heat Pump component simulation.
115 :
116 : // shut off after compressor cycle off [s]
117 : // cycling fan/cycling compressor
118 :
119 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
120 : int HPNum; // The WatertoAirHP that you are currently loading input into
121 :
122 : // Obtains and Allocates WatertoAirHP related parameters from input file
123 0 : if (state.dataWaterToAirHeatPump->GetCoilsInputFlag) { // First time subroutine has been entered
124 0 : GetWatertoAirHPInput(state);
125 0 : state.dataWaterToAirHeatPump->GetCoilsInputFlag = false;
126 : }
127 :
128 0 : if (CompIndex == 0) {
129 0 : HPNum = Util::FindItemInList(CompName, state.dataWaterToAirHeatPump->WatertoAirHP);
130 0 : if (HPNum == 0) {
131 0 : ShowFatalError(state, format("WaterToAir HP not found={}", CompName));
132 : }
133 0 : CompIndex = HPNum;
134 : } else {
135 0 : HPNum = CompIndex;
136 0 : if (HPNum > state.dataWaterToAirHeatPump->NumWatertoAirHPs || HPNum < 1) {
137 0 : ShowFatalError(state,
138 0 : format("SimWatertoAirHP: Invalid CompIndex passed={}, Number of Water to Air HPs={}, WaterToAir HP name={}",
139 : HPNum,
140 0 : state.dataWaterToAirHeatPump->NumWatertoAirHPs,
141 : CompName));
142 : }
143 0 : if (state.dataWaterToAirHeatPump->CheckEquipName(HPNum)) {
144 0 : if (!CompName.empty() && CompName != state.dataWaterToAirHeatPump->WatertoAirHP(HPNum).Name) {
145 0 : ShowFatalError(
146 : state,
147 0 : format("SimWatertoAirHP: Invalid CompIndex passed={}, WaterToAir HP name={}, stored WaterToAir HP Name for that index={}",
148 : HPNum,
149 : CompName,
150 0 : state.dataWaterToAirHeatPump->WatertoAirHP(HPNum).Name));
151 : }
152 0 : state.dataWaterToAirHeatPump->CheckEquipName(HPNum) = false;
153 : }
154 : }
155 : // Calculate the Correct Water to Air HP Model with the current HPNum
156 :
157 0 : if (state.dataWaterToAirHeatPump->WatertoAirHP(HPNum).WAHPType == DataPlant::PlantEquipmentType::CoilWAHPCoolingParamEst) {
158 0 : InitWatertoAirHP(state, HPNum, InitFlag, SensLoad, LatentLoad, DesignAirflow, PartLoadRatio);
159 0 : CalcWatertoAirHPCooling(state, HPNum, fanOp, FirstHVACIteration, InitFlag, SensLoad, compressorOp, PartLoadRatio);
160 :
161 0 : UpdateWatertoAirHP(state, HPNum);
162 :
163 0 : } else if (state.dataWaterToAirHeatPump->WatertoAirHP(HPNum).WAHPType == DataPlant::PlantEquipmentType::CoilWAHPHeatingParamEst) {
164 0 : InitWatertoAirHP(state, HPNum, InitFlag, SensLoad, LatentLoad, DesignAirflow, PartLoadRatio);
165 0 : CalcWatertoAirHPHeating(state, HPNum, fanOp, FirstHVACIteration, InitFlag, SensLoad, compressorOp, PartLoadRatio);
166 :
167 0 : UpdateWatertoAirHP(state, HPNum);
168 :
169 : } else {
170 0 : ShowFatalError(state, "SimWatertoAirHP: AirtoAir heatpump not in either HEATING or COOLING");
171 : }
172 0 : }
173 :
174 : // Get Input Section of the Module
175 : //******************************************************************************
176 :
177 1 : void GetWatertoAirHPInput(EnergyPlusData &state)
178 : {
179 :
180 : // SUBROUTINE INFORMATION:
181 : // AUTHOR Hui Jin
182 : // DATE WRITTEN Oct 2000
183 : // MODIFIED Dan Fisher, Kenneth Tang (Jan 2004)
184 :
185 : // PURPOSE OF THIS SUBROUTINE:
186 : // Obtains input data for HPs and stores it in HP data structures
187 :
188 : // METHODOLOGY EMPLOYED:
189 : // Uses "Get" routines to read in data.
190 :
191 : // SUBROUTINE PARAMETER DEFINITIONS:
192 : static constexpr std::string_view RoutineName("GetWatertoAirHPInput: "); // include trailing blank space
193 : static constexpr std::string_view routineName = "GetWatertoAirHPInput";
194 :
195 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
196 : int HPNum; // The Water to Air HP that you are currently loading input into
197 : int NumCool;
198 : int NumHeat;
199 : int WatertoAirHPNum;
200 : int NumAlphas;
201 : int NumParams;
202 : int NumNums;
203 1 : int MaxNums(0); // Maximum number of numeric input fields
204 1 : int MaxAlphas(0); // Maximum number of alpha input fields
205 : int IOStat;
206 1 : bool ErrorsFound(false); // If errors detected in input
207 1 : std::string CurrentModuleObject; // for ease in getting objects
208 1 : Array1D_string AlphArray; // Alpha input items for object
209 1 : Array1D_string cAlphaFields; // Alpha field names
210 1 : Array1D_string cNumericFields; // Numeric field names
211 1 : Array1D<Real64> NumArray; // Numeric input items for object
212 1 : Array1D_bool lAlphaBlanks; // Logical array, alpha field input BLANK = .TRUE.
213 1 : Array1D_bool lNumericBlanks; // Logical array, numeric field input BLANK = .TRUE.
214 :
215 1 : constexpr std::array<std::string_view, static_cast<int>(CompressorType::Num)> CompressTypeNamesUC{"RECIPROCATING", "ROTARY", "SCROLL"};
216 :
217 1 : NumCool = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Coil:Cooling:WaterToAirHeatPump:ParameterEstimation");
218 1 : NumHeat = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Coil:Heating:WaterToAirHeatPump:ParameterEstimation");
219 1 : state.dataWaterToAirHeatPump->NumWatertoAirHPs = NumCool + NumHeat;
220 1 : HPNum = 0;
221 :
222 1 : if (state.dataWaterToAirHeatPump->NumWatertoAirHPs <= 0) {
223 0 : ShowSevereError(state, "No Equipment found in SimWatertoAirHP");
224 0 : ErrorsFound = true;
225 : }
226 :
227 : // Allocate Arrays
228 1 : if (state.dataWaterToAirHeatPump->NumWatertoAirHPs > 0) {
229 1 : state.dataWaterToAirHeatPump->WatertoAirHP.allocate(state.dataWaterToAirHeatPump->NumWatertoAirHPs);
230 1 : state.dataWaterToAirHeatPump->CheckEquipName.dimension(state.dataWaterToAirHeatPump->NumWatertoAirHPs, true);
231 : }
232 :
233 1 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
234 : state, "Coil:Cooling:WaterToAirHeatPump:ParameterEstimation", NumParams, NumAlphas, NumNums);
235 1 : MaxNums = max(MaxNums, NumNums);
236 1 : MaxAlphas = max(MaxAlphas, NumAlphas);
237 1 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
238 : state, "Coil:Heating:WaterToAirHeatPump:ParameterEstimation", NumParams, NumAlphas, NumNums);
239 1 : MaxNums = max(MaxNums, NumNums);
240 1 : MaxAlphas = max(MaxAlphas, NumAlphas);
241 1 : AlphArray.allocate(MaxAlphas);
242 1 : cAlphaFields.allocate(MaxAlphas);
243 1 : lAlphaBlanks.dimension(MaxAlphas, true);
244 1 : cNumericFields.allocate(MaxNums);
245 1 : lNumericBlanks.dimension(MaxNums, true);
246 1 : NumArray.dimension(MaxNums, 0.0);
247 :
248 : // Get the data for detailed cooling Heat Pump
249 1 : CurrentModuleObject = "Coil:Cooling:WaterToAirHeatPump:ParameterEstimation";
250 :
251 2 : for (WatertoAirHPNum = 1; WatertoAirHPNum <= NumCool; ++WatertoAirHPNum) {
252 :
253 1 : ++HPNum;
254 :
255 1 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
256 : CurrentModuleObject,
257 : HPNum,
258 : AlphArray,
259 : NumAlphas,
260 : NumArray,
261 : NumNums,
262 : IOStat,
263 : lNumericBlanks,
264 : lAlphaBlanks,
265 : cAlphaFields,
266 : cNumericFields);
267 :
268 1 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphArray(1)};
269 : // ErrorsFound will be set to True if problem was found, left untouched otherwise
270 1 : GlobalNames::VerifyUniqueCoilName(state, CurrentModuleObject, AlphArray(1), ErrorsFound, CurrentModuleObject + " Name");
271 :
272 1 : auto &heatPump = state.dataWaterToAirHeatPump->WatertoAirHP(HPNum);
273 :
274 1 : heatPump.Name = AlphArray(1);
275 1 : heatPump.WatertoAirHPType = "COOLING";
276 1 : heatPump.WAHPType = DataPlant::PlantEquipmentType::CoilWAHPCoolingParamEst;
277 1 : heatPump.Refrigerant = AlphArray(3);
278 1 : if (heatPump.Refrigerant.empty()) {
279 0 : ShowSevereEmptyField(state, eoh, cAlphaFields(3));
280 0 : ErrorsFound = true;
281 1 : } else if ((heatPump.refrig = Fluid::GetRefrig(state, heatPump.Refrigerant)) == nullptr) {
282 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(3), AlphArray(3));
283 0 : ErrorsFound = true;
284 : }
285 1 : heatPump.DesignWaterVolFlowRate = NumArray(1);
286 1 : heatPump.CoolingCapacity = NumArray(2);
287 1 : heatPump.Twet_Rated = NumArray(3);
288 1 : heatPump.Gamma_Rated = NumArray(4);
289 :
290 1 : heatPump.HighPressCutoff = NumArray(5);
291 1 : heatPump.LowPressCutoff = NumArray(6);
292 :
293 1 : heatPump.WaterInletNodeNum = GetOnlySingleNode(state,
294 1 : AlphArray(4),
295 : ErrorsFound,
296 : DataLoopNode::ConnectionObjectType::CoilCoolingWaterToAirHeatPumpParameterEstimation,
297 1 : AlphArray(1),
298 : DataLoopNode::NodeFluidType::Water,
299 : DataLoopNode::ConnectionType::Inlet,
300 : NodeInputManager::CompFluidStream::Secondary,
301 : DataLoopNode::ObjectIsNotParent);
302 1 : heatPump.WaterOutletNodeNum = GetOnlySingleNode(state,
303 1 : AlphArray(5),
304 : ErrorsFound,
305 : DataLoopNode::ConnectionObjectType::CoilCoolingWaterToAirHeatPumpParameterEstimation,
306 1 : AlphArray(1),
307 : DataLoopNode::NodeFluidType::Water,
308 : DataLoopNode::ConnectionType::Outlet,
309 : NodeInputManager::CompFluidStream::Secondary,
310 : DataLoopNode::ObjectIsNotParent);
311 1 : heatPump.AirInletNodeNum = GetOnlySingleNode(state,
312 1 : AlphArray(6),
313 : ErrorsFound,
314 : DataLoopNode::ConnectionObjectType::CoilCoolingWaterToAirHeatPumpParameterEstimation,
315 1 : AlphArray(1),
316 : DataLoopNode::NodeFluidType::Air,
317 : DataLoopNode::ConnectionType::Inlet,
318 : NodeInputManager::CompFluidStream::Primary,
319 : DataLoopNode::ObjectIsNotParent);
320 1 : heatPump.AirOutletNodeNum = GetOnlySingleNode(state,
321 1 : AlphArray(7),
322 : ErrorsFound,
323 : DataLoopNode::ConnectionObjectType::CoilCoolingWaterToAirHeatPumpParameterEstimation,
324 1 : AlphArray(1),
325 : DataLoopNode::NodeFluidType::Air,
326 : DataLoopNode::ConnectionType::Outlet,
327 : NodeInputManager::CompFluidStream::Primary,
328 : DataLoopNode::ObjectIsNotParent);
329 :
330 : // 2010-01-13 ESL: Jason Glazer noted that these were out of order previously, but they are good now
331 1 : heatPump.LoadSideTotalUACoeff = NumArray(7);
332 1 : heatPump.LoadSideOutsideUACoeff = NumArray(8);
333 :
334 1 : if ((heatPump.LoadSideOutsideUACoeff < Constant::rTinyValue) || (heatPump.LoadSideTotalUACoeff < Constant::rTinyValue)) {
335 0 : ShowSevereError(state, format("Input problem for {}={}", CurrentModuleObject, heatPump.Name));
336 0 : ShowContinueError(state, " One or both load side UA values entered are below tolerance, likely zero or blank.");
337 0 : ShowContinueError(state, " Verify inputs, as the parameter syntax for this object went through a change with");
338 0 : ShowContinueError(state, " the release of EnergyPlus version 5.");
339 0 : ErrorsFound = true;
340 : }
341 :
342 1 : heatPump.SuperheatTemp = NumArray(9);
343 1 : heatPump.PowerLosses = NumArray(10);
344 1 : heatPump.LossFactor = NumArray(11);
345 :
346 1 : heatPump.compressorType = static_cast<CompressorType>(getEnumValue(CompressTypeNamesUC, Util::makeUPPER(AlphArray(2))));
347 :
348 1 : switch (heatPump.compressorType) {
349 0 : case CompressorType::Reciprocating: {
350 0 : heatPump.CompPistonDisp = NumArray(12);
351 0 : heatPump.CompSucPressDrop = NumArray(13);
352 0 : heatPump.CompClearanceFactor = NumArray(14);
353 0 : break;
354 : }
355 0 : case CompressorType::Rotary: {
356 0 : heatPump.CompPistonDisp = NumArray(12);
357 0 : heatPump.CompSucPressDrop = NumArray(13);
358 0 : break;
359 : }
360 1 : case CompressorType::Scroll: {
361 1 : heatPump.RefVolFlowRate = NumArray(15);
362 1 : heatPump.VolumeRatio = NumArray(16);
363 1 : heatPump.LeakRateCoeff = NumArray(17);
364 1 : break;
365 : }
366 0 : default: {
367 0 : ShowSevereError(
368 : state,
369 0 : format("{}Invalid {} ({}) entered. {}={}", RoutineName, cAlphaFields(2), AlphArray(2), CurrentModuleObject, heatPump.Name));
370 0 : ErrorsFound = true;
371 0 : break;
372 : }
373 : }
374 :
375 1 : heatPump.SourceSideUACoeff = NumArray(18);
376 1 : heatPump.SourceSideHTR1 = NumArray(19);
377 1 : heatPump.SourceSideHTR2 = NumArray(20);
378 1 : heatPump.PLFCurveIndex = Curve::GetCurveIndex(state, AlphArray(8)); // convert curve name to number
379 :
380 1 : if (heatPump.PLFCurveIndex == 0) {
381 0 : if (lAlphaBlanks(8)) {
382 0 : ShowSevereError(state, format("{}{}=\"{}\", missing", RoutineName, CurrentModuleObject, heatPump.Name));
383 0 : ShowContinueError(state, format("...required {} is blank.", cAlphaFields(8)));
384 : } else {
385 0 : ShowSevereError(state, format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, heatPump.Name));
386 0 : ShowContinueError(state, format("...not found {}=\"{}\".", cAlphaFields(8), AlphArray(8)));
387 : }
388 0 : ErrorsFound = true;
389 : } else {
390 : // Verify Curve Object, only legal types are Quadratic or Cubic
391 2 : ErrorsFound |= Curve::CheckCurveDims(state,
392 : heatPump.PLFCurveIndex, // Curve index
393 : {1}, // Valid dimensions
394 : RoutineName, // Routine name
395 : CurrentModuleObject, // Object Type
396 : heatPump.Name, // Object Name
397 1 : cAlphaFields(8)); // Field Name
398 :
399 1 : if (!ErrorsFound) {
400 : // Test PLF curve minimum and maximum. Cap if less than 0.7 or greater than 1.0.
401 1 : Real64 MinCurveVal = 999.0;
402 1 : Real64 MaxCurveVal = -999.0;
403 1 : Real64 CurveInput = 0.0;
404 1 : Real64 MinCurvePLR{0.0};
405 1 : Real64 MaxCurvePLR{0.0};
406 :
407 101 : while (CurveInput <= 1.0) {
408 100 : Real64 CurveVal = Curve::CurveValue(state, heatPump.PLFCurveIndex, CurveInput);
409 100 : if (CurveVal < MinCurveVal) {
410 1 : MinCurveVal = CurveVal;
411 1 : MinCurvePLR = CurveInput;
412 : }
413 100 : if (CurveVal > MaxCurveVal) {
414 20 : MaxCurveVal = CurveVal;
415 20 : MaxCurvePLR = CurveInput;
416 : }
417 100 : CurveInput += 0.01;
418 : }
419 1 : if (MinCurveVal < 0.7) {
420 0 : ShowWarningError(state, format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, heatPump.Name));
421 0 : ShowContinueError(state, format("...{}=\"{}\" has out of range values.", cAlphaFields(8), AlphArray(8)));
422 0 : ShowContinueError(state,
423 0 : format("...Curve minimum must be >= 0.7, curve min at PLR = {:.2T} is {:.3T}", MinCurvePLR, MinCurveVal));
424 0 : ShowContinueError(state, "...Setting curve minimum to 0.7 and simulation continues.");
425 0 : Curve::SetCurveOutputMinValue(state, heatPump.PLFCurveIndex, ErrorsFound, 0.7);
426 : }
427 :
428 1 : if (MaxCurveVal > 1.0) {
429 0 : ShowWarningError(state, format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, heatPump.Name));
430 0 : ShowContinueError(state, format("...{} = {} has out of range value.", cAlphaFields(8), AlphArray(8)));
431 0 : ShowContinueError(state,
432 0 : format("...Curve maximum must be <= 1.0, curve max at PLR = {:.2T} is {:.3T}", MaxCurvePLR, MaxCurveVal));
433 0 : ShowContinueError(state, "...Setting curve maximum to 1.0 and simulation continues.");
434 0 : Curve::SetCurveOutputMaxValue(state, heatPump.PLFCurveIndex, ErrorsFound, 1.0);
435 : }
436 : }
437 : }
438 :
439 1 : heatPump.MaxONOFFCyclesperHour = NumArray(21);
440 1 : heatPump.LatentCapacityTimeConstant = NumArray(22);
441 1 : heatPump.FanDelayTime = NumArray(23);
442 :
443 2 : BranchNodeConnections::TestCompSet(state, CurrentModuleObject, AlphArray(1), AlphArray(4), AlphArray(5), "Water Nodes");
444 1 : BranchNodeConnections::TestCompSet(state, CurrentModuleObject, AlphArray(1), AlphArray(6), AlphArray(7), "Air Nodes");
445 :
446 : // Setup Report variables for the detailed cooling Heat Pump
447 : // CurrentModuleObject = "Coil:Cooling:WaterToAirHeatPump:ParameterEstimation"
448 2 : SetupOutputVariable(state,
449 : "Cooling Coil Electricity Energy",
450 : Constant::Units::J,
451 1 : heatPump.Energy,
452 : OutputProcessor::TimeStepType::System,
453 : OutputProcessor::StoreType::Sum,
454 1 : heatPump.Name,
455 : Constant::eResource::Electricity,
456 : OutputProcessor::Group::HVAC,
457 : OutputProcessor::EndUseCat::Cooling);
458 2 : SetupOutputVariable(state,
459 : "Cooling Coil Total Cooling Energy",
460 : Constant::Units::J,
461 1 : heatPump.EnergyLoadTotal,
462 : OutputProcessor::TimeStepType::System,
463 : OutputProcessor::StoreType::Sum,
464 1 : heatPump.Name,
465 : Constant::eResource::EnergyTransfer,
466 : OutputProcessor::Group::HVAC,
467 : OutputProcessor::EndUseCat::CoolingCoils);
468 2 : SetupOutputVariable(state,
469 : "Cooling Coil Sensible Cooling Energy",
470 : Constant::Units::J,
471 1 : heatPump.EnergySensible,
472 : OutputProcessor::TimeStepType::System,
473 : OutputProcessor::StoreType::Sum,
474 1 : heatPump.Name);
475 2 : SetupOutputVariable(state,
476 : "Cooling Coil Latent Cooling Energy",
477 : Constant::Units::J,
478 1 : heatPump.EnergyLatent,
479 : OutputProcessor::TimeStepType::System,
480 : OutputProcessor::StoreType::Sum,
481 1 : heatPump.Name);
482 2 : SetupOutputVariable(state,
483 : "Cooling Coil Source Side Heat Transfer Energy",
484 : Constant::Units::J,
485 1 : heatPump.EnergySource,
486 : OutputProcessor::TimeStepType::System,
487 : OutputProcessor::StoreType::Sum,
488 1 : heatPump.Name,
489 : Constant::eResource::PlantLoopCoolingDemand,
490 : OutputProcessor::Group::HVAC,
491 : OutputProcessor::EndUseCat::CoolingCoils);
492 :
493 : // save the design source side flow rate for use by plant loop sizing algorithms
494 1 : PlantUtilities::RegisterPlantCompDesignFlow(state, heatPump.WaterInletNodeNum, 0.5 * heatPump.DesignWaterVolFlowRate);
495 :
496 : // create predefined report entries
497 1 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchCoolCoilType, heatPump.Name, CurrentModuleObject);
498 1 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchCoolCoilTotCap, heatPump.Name, heatPump.CoolingCapacity);
499 1 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchCoolCoilSensCap, heatPump.Name, "-");
500 1 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchCoolCoilLatCap, heatPump.Name, "-");
501 1 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchCoolCoilSHR, heatPump.Name, "-");
502 1 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchCoolCoilNomEff, heatPump.Name, "-");
503 : }
504 :
505 1 : CurrentModuleObject = "Coil:Heating:WaterToAirHeatPump:ParameterEstimation";
506 :
507 2 : for (WatertoAirHPNum = 1; WatertoAirHPNum <= NumHeat; ++WatertoAirHPNum) {
508 :
509 1 : ++HPNum;
510 :
511 1 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
512 : CurrentModuleObject,
513 : WatertoAirHPNum,
514 : AlphArray,
515 : NumAlphas,
516 : NumArray,
517 : NumNums,
518 : IOStat,
519 : lNumericBlanks,
520 : lAlphaBlanks,
521 : cAlphaFields,
522 : cNumericFields);
523 :
524 1 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, AlphArray(1)};
525 :
526 : // ErrorsFound will be set to True if problem was found, left untouched otherwise
527 1 : GlobalNames::VerifyUniqueCoilName(state, CurrentModuleObject, AlphArray(1), ErrorsFound, CurrentModuleObject + " Name");
528 1 : auto &heatPump = state.dataWaterToAirHeatPump->WatertoAirHP(HPNum);
529 :
530 1 : heatPump.Name = AlphArray(1);
531 1 : heatPump.WatertoAirHPType = "HEATING";
532 1 : heatPump.WAHPType = DataPlant::PlantEquipmentType::CoilWAHPHeatingParamEst;
533 1 : heatPump.Refrigerant = AlphArray(3);
534 1 : if (heatPump.Refrigerant.empty()) {
535 0 : ShowSevereEmptyField(state, eoh, cAlphaFields(3));
536 0 : ErrorsFound = true;
537 1 : } else if ((heatPump.refrig = Fluid::GetRefrig(state, heatPump.Refrigerant)) == nullptr) {
538 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(3), AlphArray(3));
539 0 : ErrorsFound = true;
540 : }
541 1 : heatPump.DesignWaterVolFlowRate = NumArray(1);
542 1 : heatPump.HeatingCapacity = NumArray(2);
543 :
544 1 : heatPump.HighPressCutoff = NumArray(3);
545 1 : heatPump.LowPressCutoff = NumArray(4);
546 :
547 1 : heatPump.WaterInletNodeNum = GetOnlySingleNode(state,
548 1 : AlphArray(4),
549 : ErrorsFound,
550 : DataLoopNode::ConnectionObjectType::CoilHeatingWaterToAirHeatPumpParameterEstimation,
551 1 : AlphArray(1),
552 : DataLoopNode::NodeFluidType::Water,
553 : DataLoopNode::ConnectionType::Inlet,
554 : NodeInputManager::CompFluidStream::Secondary,
555 : DataLoopNode::ObjectIsNotParent);
556 1 : heatPump.WaterOutletNodeNum = GetOnlySingleNode(state,
557 1 : AlphArray(5),
558 : ErrorsFound,
559 : DataLoopNode::ConnectionObjectType::CoilHeatingWaterToAirHeatPumpParameterEstimation,
560 1 : AlphArray(1),
561 : DataLoopNode::NodeFluidType::Water,
562 : DataLoopNode::ConnectionType::Outlet,
563 : NodeInputManager::CompFluidStream::Secondary,
564 : DataLoopNode::ObjectIsNotParent);
565 1 : heatPump.AirInletNodeNum = GetOnlySingleNode(state,
566 1 : AlphArray(6),
567 : ErrorsFound,
568 : DataLoopNode::ConnectionObjectType::CoilHeatingWaterToAirHeatPumpParameterEstimation,
569 1 : AlphArray(1),
570 : DataLoopNode::NodeFluidType::Air,
571 : DataLoopNode::ConnectionType::Inlet,
572 : NodeInputManager::CompFluidStream::Primary,
573 : DataLoopNode::ObjectIsNotParent);
574 1 : heatPump.AirOutletNodeNum = GetOnlySingleNode(state,
575 1 : AlphArray(7),
576 : ErrorsFound,
577 : DataLoopNode::ConnectionObjectType::CoilHeatingWaterToAirHeatPumpParameterEstimation,
578 1 : AlphArray(1),
579 : DataLoopNode::NodeFluidType::Air,
580 : DataLoopNode::ConnectionType::Outlet,
581 : NodeInputManager::CompFluidStream::Primary,
582 : DataLoopNode::ObjectIsNotParent);
583 :
584 1 : heatPump.LoadSideTotalUACoeff = NumArray(5);
585 1 : if (heatPump.LoadSideTotalUACoeff < Constant::rTinyValue) {
586 0 : ShowSevereError(state, format("Input problem for {}={}", CurrentModuleObject, heatPump.Name));
587 0 : ShowContinueError(state, " Load side UA value is less than tolerance, likely zero or blank.");
588 0 : ShowContinueError(state, " Verify inputs, as the parameter syntax for this object went through a change with");
589 0 : ShowContinueError(state, " the release of EnergyPlus version 5.");
590 0 : ErrorsFound = true;
591 : }
592 :
593 1 : heatPump.SuperheatTemp = NumArray(6);
594 1 : heatPump.PowerLosses = NumArray(7);
595 1 : heatPump.LossFactor = NumArray(8);
596 :
597 1 : heatPump.compressorType = static_cast<CompressorType>(getEnumValue(CompressTypeNamesUC, Util::makeUPPER(AlphArray(2))));
598 :
599 1 : switch (heatPump.compressorType) {
600 0 : case CompressorType::Reciprocating: {
601 0 : heatPump.CompPistonDisp = NumArray(9);
602 0 : heatPump.CompSucPressDrop = NumArray(10);
603 0 : heatPump.CompClearanceFactor = NumArray(11);
604 0 : break;
605 : }
606 0 : case CompressorType::Rotary: {
607 0 : heatPump.CompPistonDisp = NumArray(9);
608 0 : heatPump.CompSucPressDrop = NumArray(10);
609 0 : break;
610 : }
611 1 : case CompressorType::Scroll: {
612 1 : heatPump.RefVolFlowRate = NumArray(12);
613 1 : heatPump.VolumeRatio = NumArray(13);
614 1 : heatPump.LeakRateCoeff = NumArray(14);
615 1 : break;
616 : }
617 0 : default: {
618 0 : ShowSevereError(
619 : state,
620 0 : format("{}Invalid {} ({}) entered. {}={}", RoutineName, cAlphaFields(2), AlphArray(2), CurrentModuleObject, heatPump.Name));
621 0 : ErrorsFound = true;
622 0 : break;
623 : }
624 : }
625 :
626 1 : heatPump.SourceSideUACoeff = NumArray(15);
627 1 : heatPump.SourceSideHTR1 = NumArray(16);
628 1 : heatPump.SourceSideHTR2 = NumArray(17);
629 :
630 1 : heatPump.PLFCurveIndex = Curve::GetCurveIndex(state, AlphArray(8)); // convert curve name to number
631 :
632 1 : if (heatPump.PLFCurveIndex == 0) {
633 0 : if (lAlphaBlanks(8)) {
634 0 : ShowSevereError(state, format("{}{}=\"{}\", missing", RoutineName, CurrentModuleObject, heatPump.Name));
635 0 : ShowContinueError(state, format("...required {} is blank.", cAlphaFields(8)));
636 : } else {
637 0 : ShowSevereError(state, format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, heatPump.Name));
638 0 : ShowContinueError(state, format("...not found {}=\"{}\".", cAlphaFields(8), AlphArray(8)));
639 : }
640 0 : ErrorsFound = true;
641 : } else {
642 : // Verify Curve Object, only legal types are Quadratic or Cubic
643 2 : ErrorsFound |= Curve::CheckCurveDims(state,
644 : heatPump.PLFCurveIndex, // Curve index
645 : {1}, // Valid dimensions
646 : RoutineName, // Routine name
647 : CurrentModuleObject, // Object Type
648 : heatPump.Name, // Object Name
649 1 : cAlphaFields(8)); // Field Name
650 :
651 1 : if (!ErrorsFound) {
652 : // Test PLF curve minimum and maximum. Cap if less than 0.7 or greater than 1.0.
653 1 : Real64 MinCurveVal = 999.0;
654 1 : Real64 MaxCurveVal = -999.0;
655 1 : Real64 CurveInput = 0.0;
656 1 : Real64 MinCurvePLR{0.0};
657 1 : Real64 MaxCurvePLR{0.0};
658 :
659 101 : while (CurveInput <= 1.0) {
660 100 : Real64 CurveVal = Curve::CurveValue(state, heatPump.PLFCurveIndex, CurveInput);
661 100 : if (CurveVal < MinCurveVal) {
662 1 : MinCurveVal = CurveVal;
663 1 : MinCurvePLR = CurveInput;
664 : }
665 100 : if (CurveVal > MaxCurveVal) {
666 20 : MaxCurveVal = CurveVal;
667 20 : MaxCurvePLR = CurveInput;
668 : }
669 100 : CurveInput += 0.01;
670 : }
671 1 : if (MinCurveVal < 0.7) {
672 0 : ShowWarningError(state, format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, heatPump.Name));
673 0 : ShowContinueError(state, format("...{}=\"{}\" has out of range values.", cAlphaFields(9), AlphArray(9)));
674 0 : ShowContinueError(state,
675 0 : format("...Curve minimum must be >= 0.7, curve min at PLR = {:.2T} is {:.3T}", MinCurvePLR, MinCurveVal));
676 0 : ShowContinueError(state, "...Setting curve minimum to 0.7 and simulation continues.");
677 0 : Curve::SetCurveOutputMinValue(state, heatPump.PLFCurveIndex, ErrorsFound, 0.7);
678 : }
679 :
680 1 : if (MaxCurveVal > 1.0) {
681 0 : ShowWarningError(state, format("{}{}=\"{}\", invalid", RoutineName, CurrentModuleObject, heatPump.Name));
682 0 : ShowContinueError(state, format("...{} = {} has out of range value.", cAlphaFields(9), AlphArray(9)));
683 0 : ShowContinueError(state,
684 0 : format("...Curve maximum must be <= 1.0, curve max at PLR = {:.2T} is {:.3T}", MaxCurvePLR, MaxCurveVal));
685 0 : ShowContinueError(state, "...Setting curve maximum to 1.0 and simulation continues.");
686 0 : Curve::SetCurveOutputMaxValue(state, heatPump.PLFCurveIndex, ErrorsFound, 1.0);
687 : }
688 : }
689 : }
690 :
691 2 : BranchNodeConnections::TestCompSet(state, CurrentModuleObject, AlphArray(1), AlphArray(4), AlphArray(5), "Water Nodes");
692 1 : BranchNodeConnections::TestCompSet(state, CurrentModuleObject, AlphArray(1), AlphArray(6), AlphArray(7), "Air Nodes");
693 :
694 : // CurrentModuleObject = "Coil:Heating:WaterToAirHeatPump:ParameterEstimation"
695 2 : SetupOutputVariable(state,
696 : "Heating Coil Electricity Energy",
697 : Constant::Units::J,
698 1 : heatPump.Energy,
699 : OutputProcessor::TimeStepType::System,
700 : OutputProcessor::StoreType::Sum,
701 1 : heatPump.Name,
702 : Constant::eResource::Electricity,
703 : OutputProcessor::Group::HVAC,
704 : OutputProcessor::EndUseCat::Heating);
705 2 : SetupOutputVariable(state,
706 : "Heating Coil Heating Energy",
707 : Constant::Units::J,
708 1 : heatPump.EnergyLoadTotal,
709 : OutputProcessor::TimeStepType::System,
710 : OutputProcessor::StoreType::Sum,
711 1 : heatPump.Name,
712 : Constant::eResource::EnergyTransfer,
713 : OutputProcessor::Group::HVAC,
714 : OutputProcessor::EndUseCat::HeatingCoils);
715 2 : SetupOutputVariable(state,
716 : "Heating Coil Source Side Heat Transfer Energy",
717 : Constant::Units::J,
718 1 : heatPump.EnergySource,
719 : OutputProcessor::TimeStepType::System,
720 : OutputProcessor::StoreType::Sum,
721 1 : heatPump.Name,
722 : Constant::eResource::PlantLoopHeatingDemand,
723 : OutputProcessor::Group::HVAC,
724 : OutputProcessor::EndUseCat::HeatingCoils);
725 :
726 : // save the design source side flow rate for use by plant loop sizing algorithms
727 1 : PlantUtilities::RegisterPlantCompDesignFlow(state, heatPump.WaterInletNodeNum, 0.5 * heatPump.DesignWaterVolFlowRate);
728 :
729 : // create predefined report entries
730 1 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchHeatCoilType, heatPump.Name, CurrentModuleObject);
731 1 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchHeatCoilNomCap, heatPump.Name, heatPump.HeatingCapacity);
732 1 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchHeatCoilNomEff, heatPump.Name, "-");
733 : }
734 :
735 1 : AlphArray.deallocate();
736 1 : cAlphaFields.deallocate();
737 1 : lAlphaBlanks.deallocate();
738 1 : cNumericFields.deallocate();
739 1 : lNumericBlanks.deallocate();
740 1 : NumArray.deallocate();
741 :
742 1 : if (ErrorsFound) {
743 0 : ShowFatalError(state, format("{}Errors found getting input. Program terminates.", RoutineName));
744 : }
745 :
746 3 : for (HPNum = 1; HPNum <= state.dataWaterToAirHeatPump->NumWatertoAirHPs; ++HPNum) {
747 :
748 2 : auto &heatPump = state.dataWaterToAirHeatPump->WatertoAirHP(HPNum);
749 2 : if (heatPump.WAHPType == DataPlant::PlantEquipmentType::CoilWAHPCoolingParamEst) {
750 : // COOLING COIL: Setup Report variables for the Heat Pump
751 2 : SetupOutputVariable(state,
752 : "Cooling Coil Electricity Rate",
753 : Constant::Units::W,
754 1 : heatPump.Power,
755 : OutputProcessor::TimeStepType::System,
756 : OutputProcessor::StoreType::Average,
757 1 : heatPump.Name);
758 :
759 2 : SetupOutputVariable(state,
760 : "Cooling Coil Total Cooling Rate",
761 : Constant::Units::W,
762 1 : heatPump.QLoadTotal,
763 : OutputProcessor::TimeStepType::System,
764 : OutputProcessor::StoreType::Average,
765 1 : heatPump.Name);
766 :
767 2 : SetupOutputVariable(state,
768 : "Cooling Coil Sensible Cooling Rate",
769 : Constant::Units::W,
770 1 : heatPump.QSensible,
771 : OutputProcessor::TimeStepType::System,
772 : OutputProcessor::StoreType::Average,
773 1 : heatPump.Name);
774 :
775 2 : SetupOutputVariable(state,
776 : "Cooling Coil Latent Cooling Rate",
777 : Constant::Units::W,
778 1 : heatPump.QLatent,
779 : OutputProcessor::TimeStepType::System,
780 : OutputProcessor::StoreType::Average,
781 1 : heatPump.Name);
782 :
783 2 : SetupOutputVariable(state,
784 : "Cooling Coil Source Side Heat Transfer Rate",
785 : Constant::Units::W,
786 1 : heatPump.QSource,
787 : OutputProcessor::TimeStepType::System,
788 : OutputProcessor::StoreType::Average,
789 1 : heatPump.Name);
790 :
791 2 : SetupOutputVariable(state,
792 : "Cooling Coil Part Load Ratio",
793 : Constant::Units::None,
794 1 : heatPump.PartLoadRatio,
795 : OutputProcessor::TimeStepType::System,
796 : OutputProcessor::StoreType::Average,
797 1 : heatPump.Name);
798 2 : SetupOutputVariable(state,
799 : "Cooling Coil Runtime Fraction",
800 : Constant::Units::None,
801 1 : heatPump.RunFrac,
802 : OutputProcessor::TimeStepType::System,
803 : OutputProcessor::StoreType::Average,
804 1 : heatPump.Name);
805 :
806 2 : SetupOutputVariable(state,
807 : "Cooling Coil Air Mass Flow Rate",
808 : Constant::Units::kg_s,
809 1 : heatPump.OutletAirMassFlowRate,
810 : OutputProcessor::TimeStepType::System,
811 : OutputProcessor::StoreType::Average,
812 1 : heatPump.Name);
813 2 : SetupOutputVariable(state,
814 : "Cooling Coil Air Inlet Temperature",
815 : Constant::Units::C,
816 1 : heatPump.InletAirDBTemp,
817 : OutputProcessor::TimeStepType::System,
818 : OutputProcessor::StoreType::Average,
819 1 : heatPump.Name);
820 2 : SetupOutputVariable(state,
821 : "Cooling Coil Air Inlet Humidity Ratio",
822 : Constant::Units::kgWater_kgDryAir,
823 1 : heatPump.InletAirHumRat,
824 : OutputProcessor::TimeStepType::System,
825 : OutputProcessor::StoreType::Average,
826 1 : heatPump.Name);
827 2 : SetupOutputVariable(state,
828 : "Cooling Coil Air Outlet Temperature",
829 : Constant::Units::C,
830 1 : heatPump.OutletAirDBTemp,
831 : OutputProcessor::TimeStepType::System,
832 : OutputProcessor::StoreType::Average,
833 1 : heatPump.Name);
834 2 : SetupOutputVariable(state,
835 : "Cooling Coil Air Outlet Humidity Ratio",
836 : Constant::Units::kgWater_kgDryAir,
837 1 : heatPump.OutletAirHumRat,
838 : OutputProcessor::TimeStepType::System,
839 : OutputProcessor::StoreType::Average,
840 1 : heatPump.Name);
841 :
842 2 : SetupOutputVariable(state,
843 : "Cooling Coil Source Side Mass Flow Rate",
844 : Constant::Units::kg_s,
845 1 : heatPump.OutletWaterMassFlowRate,
846 : OutputProcessor::TimeStepType::System,
847 : OutputProcessor::StoreType::Average,
848 1 : heatPump.Name);
849 2 : SetupOutputVariable(state,
850 : "Cooling Coil Source Side Inlet Temperature",
851 : Constant::Units::C,
852 1 : heatPump.InletWaterTemp,
853 : OutputProcessor::TimeStepType::System,
854 : OutputProcessor::StoreType::Average,
855 1 : heatPump.Name);
856 2 : SetupOutputVariable(state,
857 : "Cooling Coil Source Side Outlet Temperature",
858 : Constant::Units::C,
859 1 : heatPump.OutletWaterTemp,
860 : OutputProcessor::TimeStepType::System,
861 : OutputProcessor::StoreType::Average,
862 1 : heatPump.Name);
863 1 : } else if (heatPump.WAHPType == DataPlant::PlantEquipmentType::CoilWAHPHeatingParamEst) {
864 : // HEATING COIL Setup Report variables for the Heat Pump
865 2 : SetupOutputVariable(state,
866 : "Heating Coil Electricity Rate",
867 : Constant::Units::W,
868 1 : heatPump.Power,
869 : OutputProcessor::TimeStepType::System,
870 : OutputProcessor::StoreType::Average,
871 1 : heatPump.Name);
872 :
873 2 : SetupOutputVariable(state,
874 : "Heating Coil Heating Rate",
875 : Constant::Units::W,
876 1 : heatPump.QLoadTotal,
877 : OutputProcessor::TimeStepType::System,
878 : OutputProcessor::StoreType::Average,
879 1 : heatPump.Name);
880 :
881 2 : SetupOutputVariable(state,
882 : "Heating Coil Sensible Heating Rate",
883 : Constant::Units::W,
884 1 : heatPump.QSensible,
885 : OutputProcessor::TimeStepType::System,
886 : OutputProcessor::StoreType::Average,
887 1 : heatPump.Name);
888 :
889 2 : SetupOutputVariable(state,
890 : "Heating Coil Source Side Heat Transfer Rate",
891 : Constant::Units::W,
892 1 : heatPump.QSource,
893 : OutputProcessor::TimeStepType::System,
894 : OutputProcessor::StoreType::Average,
895 1 : heatPump.Name);
896 :
897 2 : SetupOutputVariable(state,
898 : "Heating Coil Part Load Ratio",
899 : Constant::Units::None,
900 1 : heatPump.PartLoadRatio,
901 : OutputProcessor::TimeStepType::System,
902 : OutputProcessor::StoreType::Average,
903 1 : heatPump.Name);
904 2 : SetupOutputVariable(state,
905 : "Heating Coil Runtime Fraction",
906 : Constant::Units::None,
907 1 : heatPump.RunFrac,
908 : OutputProcessor::TimeStepType::System,
909 : OutputProcessor::StoreType::Average,
910 1 : heatPump.Name);
911 :
912 2 : SetupOutputVariable(state,
913 : "Heating Coil Air Mass Flow Rate",
914 : Constant::Units::kg_s,
915 1 : heatPump.OutletAirMassFlowRate,
916 : OutputProcessor::TimeStepType::System,
917 : OutputProcessor::StoreType::Average,
918 1 : heatPump.Name);
919 2 : SetupOutputVariable(state,
920 : "Heating Coil Air Inlet Temperature",
921 : Constant::Units::C,
922 1 : heatPump.InletAirDBTemp,
923 : OutputProcessor::TimeStepType::System,
924 : OutputProcessor::StoreType::Average,
925 1 : heatPump.Name);
926 2 : SetupOutputVariable(state,
927 : "Heating Coil Air Inlet Humidity Ratio",
928 : Constant::Units::kgWater_kgDryAir,
929 1 : heatPump.InletAirHumRat,
930 : OutputProcessor::TimeStepType::System,
931 : OutputProcessor::StoreType::Average,
932 1 : heatPump.Name);
933 2 : SetupOutputVariable(state,
934 : "Heating Coil Air Outlet Temperature",
935 : Constant::Units::C,
936 1 : heatPump.OutletAirDBTemp,
937 : OutputProcessor::TimeStepType::System,
938 : OutputProcessor::StoreType::Average,
939 1 : heatPump.Name);
940 2 : SetupOutputVariable(state,
941 : "Heating Coil Air Outlet Humidity Ratio",
942 : Constant::Units::kgWater_kgDryAir,
943 1 : heatPump.OutletAirHumRat,
944 : OutputProcessor::TimeStepType::System,
945 : OutputProcessor::StoreType::Average,
946 1 : heatPump.Name);
947 :
948 2 : SetupOutputVariable(state,
949 : "Heating Coil Source Side Mass Flow Rate",
950 : Constant::Units::kg_s,
951 1 : heatPump.OutletWaterMassFlowRate,
952 : OutputProcessor::TimeStepType::System,
953 : OutputProcessor::StoreType::Average,
954 1 : heatPump.Name);
955 2 : SetupOutputVariable(state,
956 : "Heating Coil Source Side Inlet Temperature",
957 : Constant::Units::C,
958 1 : heatPump.InletWaterTemp,
959 : OutputProcessor::TimeStepType::System,
960 : OutputProcessor::StoreType::Average,
961 1 : heatPump.Name);
962 2 : SetupOutputVariable(state,
963 : "Heating Coil Source Side Outlet Temperature",
964 : Constant::Units::C,
965 1 : heatPump.OutletWaterTemp,
966 : OutputProcessor::TimeStepType::System,
967 : OutputProcessor::StoreType::Average,
968 1 : heatPump.Name);
969 : }
970 : }
971 1 : }
972 :
973 2 : void InitWatertoAirHP(EnergyPlusData &state,
974 : int const HPNum, // index to main heat pump data structure
975 : bool const InitFlag,
976 : Real64 const SensLoad,
977 : Real64 const LatentLoad,
978 : Real64 const DesignAirFlow,
979 : Real64 const PartLoadRatio)
980 : {
981 :
982 : // SUBROUTINE INFORMATION:
983 : // AUTHOR Hui Jin
984 : // DATE WRITTEN Oct 2000
985 : // MODIFIED Dan Fisher, Kenneth Tang (Jan 2004)
986 : // Brent Griffith, Sept 2010, plant upgrades, general fluid properties
987 :
988 : // PURPOSE OF THIS SUBROUTINE:
989 : // This subroutine is for initializations of the Water to Air HP Components.
990 :
991 : // METHODOLOGY EMPLOYED:
992 : // Uses the status flags to trigger initializations.
993 :
994 : // Using/Aliasing
995 2 : auto &heatPump = state.dataWaterToAirHeatPump->WatertoAirHP(HPNum);
996 :
997 : static constexpr std::string_view RoutineName("InitWatertoAirHP");
998 2 : int WaterInletNode = heatPump.WaterInletNodeNum;
999 :
1000 2 : if (state.dataWaterToAirHeatPump->MyOneTimeFlag) {
1001 1 : state.dataWaterToAirHeatPump->MyEnvrnFlag.allocate(state.dataWaterToAirHeatPump->NumWatertoAirHPs);
1002 1 : state.dataWaterToAirHeatPump->MyPlantScanFlag.allocate(state.dataWaterToAirHeatPump->NumWatertoAirHPs);
1003 1 : state.dataWaterToAirHeatPump->MyEnvrnFlag = true;
1004 1 : state.dataWaterToAirHeatPump->MyPlantScanFlag = true;
1005 1 : state.dataWaterToAirHeatPump->MyOneTimeFlag = false;
1006 : }
1007 :
1008 2 : if (state.dataWaterToAirHeatPump->MyPlantScanFlag(HPNum) && allocated(state.dataPlnt->PlantLoop)) {
1009 2 : bool errFlag = false;
1010 2 : PlantUtilities::ScanPlantLoopsForObject(state, heatPump.Name, heatPump.WAHPType, heatPump.plantLoc, errFlag, _, _, _, _, _);
1011 :
1012 2 : if (state.dataPlnt->PlantLoop(heatPump.plantLoc.loopNum).FluidName == "WATER") {
1013 2 : if (heatPump.SourceSideUACoeff < Constant::rTinyValue) {
1014 0 : ShowSevereError(state, format("Input problem for water to air heat pump, \"{}\".", heatPump.Name));
1015 0 : ShowContinueError(state, " Source side UA value is less than tolerance, likely zero or blank.");
1016 0 : ShowContinueError(state, " Verify inputs, as the parameter syntax for this object went through a change with");
1017 0 : ShowContinueError(state, " the release of EnergyPlus version 5.");
1018 0 : errFlag = true;
1019 : }
1020 : } else {
1021 0 : if ((heatPump.SourceSideHTR1 < Constant::rTinyValue) || (heatPump.SourceSideHTR2 < Constant::rTinyValue)) {
1022 0 : ShowSevereError(state, format("Input problem for water to air heat pump, \"{}\".", heatPump.Name));
1023 0 : ShowContinueError(state, " A source side heat transfer resistance value is less than tolerance, likely zero or blank.");
1024 0 : ShowContinueError(state, " Verify inputs, as the parameter syntax for this object went through a change with");
1025 0 : ShowContinueError(state, " the release of EnergyPlus version 5.");
1026 0 : errFlag = true;
1027 : }
1028 : }
1029 :
1030 2 : if (errFlag) {
1031 0 : ShowFatalError(state, "InitWatertoAirHP: Program terminated for previous conditions.");
1032 : }
1033 :
1034 2 : state.dataWaterToAirHeatPump->MyPlantScanFlag(HPNum) = false;
1035 : }
1036 :
1037 : // Do the Begin Environment initializations
1038 2 : if (state.dataGlobal->BeginEnvrnFlag && state.dataWaterToAirHeatPump->MyEnvrnFlag(HPNum) &&
1039 0 : !state.dataWaterToAirHeatPump->MyPlantScanFlag(HPNum)) {
1040 :
1041 : // Initialize all report variables to a known state at beginning of simulation
1042 0 : heatPump.Power = 0.0;
1043 0 : heatPump.Energy = 0.0;
1044 0 : heatPump.QLoadTotal = 0.0;
1045 0 : heatPump.QSensible = 0.0;
1046 0 : heatPump.QLatent = 0.0;
1047 0 : heatPump.QSource = 0.0;
1048 0 : heatPump.EnergyLoadTotal = 0.0;
1049 0 : heatPump.EnergySensible = 0.0;
1050 0 : heatPump.EnergyLatent = 0.0;
1051 0 : heatPump.EnergySource = 0.0;
1052 0 : heatPump.RunFrac = 0.0;
1053 0 : heatPump.PartLoadRatio = 0.0;
1054 0 : heatPump.OutletAirDBTemp = 0.0;
1055 0 : heatPump.OutletAirHumRat = 0.0;
1056 0 : heatPump.InletAirDBTemp = 0.0;
1057 0 : heatPump.InletAirHumRat = 0.0;
1058 0 : heatPump.OutletWaterTemp = 0.0;
1059 0 : heatPump.InletWaterTemp = 0.0;
1060 0 : heatPump.InletAirMassFlowRate = 0.0;
1061 0 : heatPump.InletWaterMassFlowRate = 0.0;
1062 0 : heatPump.OutletAirEnthalpy = 0.0;
1063 0 : heatPump.OutletWaterEnthalpy = 0.0;
1064 :
1065 : // The rest of the one time initializations
1066 0 : Real64 rho = state.dataPlnt->PlantLoop(heatPump.plantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
1067 0 : Real64 Cp = state.dataPlnt->PlantLoop(heatPump.plantLoc.loopNum).glycol->getSpecificHeat(state, Constant::InitConvTemp, RoutineName);
1068 :
1069 0 : heatPump.DesignWaterMassFlowRate = rho * heatPump.DesignWaterVolFlowRate;
1070 :
1071 0 : int PlantOutletNode = DataPlant::CompData::getPlantComponent(state, heatPump.plantLoc).NodeNumOut;
1072 0 : PlantUtilities::InitComponentNodes(state, 0.0, heatPump.DesignWaterMassFlowRate, WaterInletNode, PlantOutletNode);
1073 :
1074 0 : state.dataLoopNodes->Node(WaterInletNode).Temp = 5.0;
1075 0 : state.dataLoopNodes->Node(WaterInletNode).Enthalpy = Cp * state.dataLoopNodes->Node(WaterInletNode).Temp;
1076 0 : state.dataLoopNodes->Node(WaterInletNode).Quality = 0.0;
1077 0 : state.dataLoopNodes->Node(WaterInletNode).Press = 0.0;
1078 0 : state.dataLoopNodes->Node(WaterInletNode).HumRat = 0.0;
1079 :
1080 0 : state.dataLoopNodes->Node(PlantOutletNode).Temp = 5.0;
1081 0 : state.dataLoopNodes->Node(PlantOutletNode).Enthalpy = Cp * state.dataLoopNodes->Node(WaterInletNode).Temp;
1082 0 : state.dataLoopNodes->Node(PlantOutletNode).Quality = 0.0;
1083 0 : state.dataLoopNodes->Node(PlantOutletNode).Press = 0.0;
1084 0 : state.dataLoopNodes->Node(PlantOutletNode).HumRat = 0.0;
1085 :
1086 0 : heatPump.SimFlag = true;
1087 :
1088 0 : state.dataWaterToAirHeatPump->MyEnvrnFlag(HPNum) = false;
1089 : } // End If for the Begin Environment initializations
1090 :
1091 2 : if (!state.dataGlobal->BeginEnvrnFlag) {
1092 2 : state.dataWaterToAirHeatPump->MyEnvrnFlag(HPNum) = true;
1093 : }
1094 :
1095 : // Do the following initializations (every time step): This should be the info from
1096 : // the previous components outlets or the node data in this section.
1097 : // First set the conditions for the air into the heat pump model
1098 :
1099 : // Set water and air inlet nodes
1100 2 : int AirInletNode = heatPump.AirInletNodeNum;
1101 :
1102 2 : if (((SensLoad != 0.0 || LatentLoad != 0.0) || (SensLoad == 0.0 && InitFlag)) && state.dataLoopNodes->Node(AirInletNode).MassFlowRate > 0.0 &&
1103 : PartLoadRatio > 0.0) {
1104 : // set the water side flow rate to the design flow rate unless constrained by
1105 : // the demand side manager (MIN/MAX available). now done by call to setcomponentFlowRate
1106 2 : heatPump.InletWaterMassFlowRate = heatPump.DesignWaterMassFlowRate;
1107 2 : heatPump.InletAirMassFlowRate = DesignAirFlow; // This is required instead of the node temperature
1108 : // because the air loop operates handles part load for
1109 : // cycling equipment by modulating the air flow rate
1110 : // the heat pump model requires an accurate (i.e. full load
1111 : // flow rate for accurate simulation.
1112 : } else { // heat pump is off
1113 0 : heatPump.InletWaterMassFlowRate = 0.0;
1114 :
1115 0 : heatPump.InletAirMassFlowRate = 0.0;
1116 : }
1117 : // constrain water flow provided by plant
1118 2 : PlantUtilities::SetComponentFlowRate(
1119 2 : state, heatPump.InletWaterMassFlowRate, heatPump.WaterInletNodeNum, heatPump.WaterOutletNodeNum, heatPump.plantLoc);
1120 :
1121 2 : heatPump.InletWaterTemp = state.dataLoopNodes->Node(WaterInletNode).Temp;
1122 : // IF (WatertoAirHP(HPNum)%InletWaterTemp < 0.0) THEN ! Debug trap
1123 : // Temptemp = Node(WaterInletNode)%Temp
1124 : // ENDIF
1125 2 : heatPump.InletWaterEnthalpy = state.dataLoopNodes->Node(WaterInletNode).Enthalpy;
1126 :
1127 2 : heatPump.InletAirDBTemp = state.dataLoopNodes->Node(AirInletNode).Temp;
1128 2 : heatPump.InletAirHumRat = state.dataLoopNodes->Node(AirInletNode).HumRat;
1129 2 : heatPump.InletAirEnthalpy = state.dataLoopNodes->Node(AirInletNode).Enthalpy;
1130 :
1131 2 : heatPump.Power = 0.0;
1132 2 : heatPump.Energy = 0.0;
1133 2 : heatPump.QLoadTotal = 0.0;
1134 2 : heatPump.QSensible = 0.0;
1135 2 : heatPump.QLatent = 0.0;
1136 2 : heatPump.QSource = 0.0;
1137 2 : heatPump.EnergyLoadTotal = 0.0;
1138 2 : heatPump.EnergySensible = 0.0;
1139 2 : heatPump.EnergyLatent = 0.0;
1140 2 : heatPump.EnergySource = 0.0;
1141 2 : heatPump.RunFrac = 0.0;
1142 2 : heatPump.OutletAirDBTemp = 0.0;
1143 2 : heatPump.OutletAirHumRat = 0.0;
1144 2 : heatPump.OutletWaterTemp = 0.0;
1145 2 : heatPump.OutletAirEnthalpy = 0.0;
1146 2 : heatPump.OutletWaterEnthalpy = 0.0;
1147 2 : }
1148 :
1149 1 : void CalcWatertoAirHPCooling(EnergyPlusData &state,
1150 : int const HPNum, // heat pump number
1151 : HVAC::FanOp const fanOp, // fan/compressor cycling scheme indicator
1152 : bool const FirstHVACIteration, // first iteration flag
1153 : [[maybe_unused]] bool const InitFlag, // suppress property errors if true
1154 : Real64 const SensDemand,
1155 : HVAC::CompressorOp const compressorOp,
1156 : Real64 const PartLoadRatio)
1157 : {
1158 :
1159 : // SUBROUTINE INFORMATION:
1160 : // AUTHOR Hui Jin
1161 : // DATE WRITTEN Oct 2000
1162 : // MODIFIED Dan Fisher, Kenneth Tang (Jan 2004), R. Raustad (Oct 2006) Revised iteration technique
1163 :
1164 : // PURPOSE OF THIS SUBROUTINE:
1165 : // Simulates a parameter estimation based water to air heat pump model
1166 :
1167 : // Using/Aliasing
1168 1 : auto &heatPump = state.dataWaterToAirHeatPump->WatertoAirHP(HPNum);
1169 :
1170 : // SUBROUTINE PARAMETER DEFINITIONS:
1171 1 : constexpr Real64 CpWater(4210.0); // Specific heat of water J/kg_C
1172 1 : constexpr Real64 DegreeofSuperheat(80.0); // Initial guess of degree of superheat
1173 1 : constexpr Real64 gamma(1.114); // Expansion Coefficient
1174 1 : constexpr Real64 ERR(0.01); // Error Value
1175 1 : constexpr Real64 PB(1.013e5); // Barometric Pressure (Pa)
1176 :
1177 1 : constexpr int STOP1(1000); // Iteration stopper1
1178 1 : constexpr int STOP2(1000); // Iteration stopper2
1179 1 : constexpr int STOP3(1000); // Iteration stopper3
1180 :
1181 : static constexpr std::string_view RoutineNameSourceSideInletTemp("CalcWatertoAirHPCooling:SourceSideInletTemp");
1182 : static constexpr std::string_view RoutineNameSourceSideTemp("CalcWatertoAirHPCooling:SourceSideTemp");
1183 : static constexpr std::string_view RoutineNameLoadSideTemp("CalcWatertoAirHPCooling:LoadSideTemp");
1184 : static constexpr std::string_view RoutineNameLoadSideSurfaceTemp("CalcWatertoAirHPCooling:LoadSideSurfaceTemp");
1185 : static constexpr std::string_view RoutineNameLoadSideEvapTemp("CalcWatertoAirHPCooling:LoadSideEvapTemp");
1186 : static constexpr std::string_view RoutineNameLoadSideOutletEnthalpy("CalcWatertoAirHPCooling:LoadSideOutletEnthalpy");
1187 : static constexpr std::string_view RoutineNameCompressInletTemp("CalcWatertoAirHPCooling:CompressInletTemp");
1188 : static constexpr std::string_view RoutineNameSuctionPr("CalcWatertoAirHPCooling:SuctionPr");
1189 : static constexpr std::string_view RoutineNameCompSuctionTemp("CalcWatertoAirHPCooling:CompSuctionTemp");
1190 :
1191 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1192 : int NumIteration3; // Number of Iteration3
1193 : int NumIteration4; // Number of Iteration4 (use of latent degradation model ONLY)
1194 : Real64 Quality; // Quality of Refrigerant
1195 : Real64 SourceSideOutletTemp; // Source Side Outlet Temperature [C]
1196 : Real64 SourceSideVolFlowRate; // Source Side Volumetric Flow Rate [m3/s]
1197 : Real64 DegradFactor; // Degradation Factor [~]
1198 : Real64 CpFluid; // Specific heat of source side fluid(J/kg)
1199 : Real64 LoadSideInletWBTemp; // Wet-bulb temperature of indoor inlet air [C]
1200 : Real64 LoadSideInletDBTemp; // Load Side Inlet Dry Bulb Temp [C]
1201 : Real64 LoadSideInletHumRat; // Load Side Inlet Humidity Ratio [kg/kg]
1202 : Real64 LoadSideOutletDBTemp; // Load Side Outlet Dry Bulb Temperature [C]
1203 : Real64 LoadSideOutletHumRat; // Load Side Outlet Humidity Ratio [kg/kg]
1204 : Real64 LoadSideAirInletEnth; // Load Side Inlet Enthalpy [J/kg]
1205 : Real64 LoadSideAirOutletEnth; // Load Side Outlet Enthalpy [J/kg]
1206 : Real64 EffectiveSurfaceTemp; // Effective Surface Temperature [C]
1207 : Real64 EffectiveSatEnth; // Saturated Enthalpy of Air Corresponding to the Effective Surface Temperature [J/kg]
1208 : Real64 QSource; // Source Side Heat Transfer Rate [W]
1209 : Real64 QLoadTotal; // Load Side Total Heat Transfer Rate [W]
1210 : Real64 QSensible; // Load Side Sensible Heat Transfer Rate [W]
1211 : Real64 Power; // Power Consumption [W]
1212 : Real64 EvapTemp; // Evaporating Temperature [C]
1213 : Real64 ANTUWET; // Number of Transfer Unit for Wet Condition
1214 : Real64 EffectWET; // Load Side Heat Exchanger Effectiveness
1215 : Real64 EvapSatEnth; // Saturated Enthalpy of Air Corresponding to the Evaporating Temperature [J/kg]
1216 : Real64 SourceSideEffect; // Source Side Heat Exchanger Effectiveness
1217 : Real64 SourceSideTemp; // Source Side Saturated Refrigerant Temperature [C]
1218 : Real64 LoadSideTemp; // Load Side Saturated Refrigerant Temperature [C]
1219 : Real64 SourceSidePressure; // Source Side Saturated Refrigerant Pressure [Pa]
1220 : Real64 LoadSidePressure; // Load Side Saturated Refrigerant Pressure [Pa]
1221 : Real64 SuctionPr; // Compressor Suction Pressure [Pa]
1222 : Real64 DischargePr; // Compressor Discharge Pressure [Pa]
1223 : Real64 CompressInletTemp; // Temperature of the Refrigerant Entering the Compressor [C]
1224 : Real64 MassRef; // Mass Flow Rate of Refrigerant [kg/s]
1225 : Real64 SourceSideOutletEnth; // Enthalpy of Refrigerant leaving the Source Side Heat Exchanger [J/kg]
1226 : Real64 LoadSideOutletEnth; // Enthalpy of Refrigerant leaving the Load Side Heat Exchanger [J/kg]
1227 : Real64 CpAir; // Specific Heat of Air [J/kg_C]
1228 : Real64 SuperHeatEnth; // Enthalpy of the Superheated Refrigerant [J/kg]
1229 : Real64 CompSuctionTemp1; // Guess of the Temperature of the Refrigerant Entering the Compressor #1 [C]
1230 : Real64 CompSuctionTemp2; // Guess of the Temperature of the Refrigerant Entering the Compressor #2 [C]
1231 : Real64 CompSuctionEnth; // Enthalpy of the Refrigerant Entering the Compressor [J/kg]
1232 : Real64 CompSuctionDensity; // Density of the Refrigerant Entering the Compressor [kg/m3]
1233 : Real64 CompSuctionSatTemp; // Temperature of Saturated Refrigerant at Compressor Suction Pressure [C]
1234 : bool LatDegradModelSimFlag; // Latent degradation model simulation flag
1235 : bool StillSimulatingFlag; // Final Simulation Flag
1236 : bool Converged; // overall convergence Flag
1237 : Real64 QLatRated; // Qlatent at rated conditions of indoor(TDB,TWB)=(26.7C,19.4C)
1238 : Real64 QLatActual; // Qlatent at actual operating conditions
1239 : Real64 SHRss; // Sensible heat ratio at steady state
1240 : Real64 SHReff; // Effective sensible heat ratio at part-load condition
1241 : int SolFlag; // Solution flag returned from RegulaFalsi function
1242 : Real64 LoadSideAirInletEnth_Unit; // calc conditions for unit
1243 : Real64 LoadResidual; // loop convergence criteria
1244 : Real64 SourceResidual; // loop convergence criteria
1245 1 : Real64 RelaxParam(0.5); // Relaxation Parameter
1246 :
1247 1 : if (state.dataWaterToAirHeatPump->firstTime) {
1248 : // Set indoor air conditions to the rated condition
1249 1 : state.dataWaterToAirHeatPump->LoadSideInletDBTemp_Init = 26.7;
1250 1 : state.dataWaterToAirHeatPump->LoadSideInletHumRat_Init = 0.0111;
1251 1 : state.dataWaterToAirHeatPump->LoadSideAirInletEnth_Init = Psychrometrics::PsyHFnTdbW(
1252 1 : state.dataWaterToAirHeatPump->LoadSideInletDBTemp_Init, state.dataWaterToAirHeatPump->LoadSideInletHumRat_Init);
1253 1 : state.dataWaterToAirHeatPump->firstTime = false;
1254 : }
1255 :
1256 : // SET LOCAL VARIABLES FROM DATA STRUCTURE (for code readability)
1257 : // Set indoor air conditions to the actual condition
1258 1 : CpAir = Psychrometrics::PsyCpAirFnW(heatPump.InletAirHumRat);
1259 1 : LoadSideAirInletEnth_Unit = Psychrometrics::PsyHFnTdbW(heatPump.InletAirDBTemp, heatPump.InletAirHumRat);
1260 1 : SourceSideVolFlowRate =
1261 1 : heatPump.InletWaterMassFlowRate /
1262 1 : state.dataPlnt->PlantLoop(heatPump.plantLoc.loopNum).glycol->getDensity(state, heatPump.InletWaterTemp, RoutineNameSourceSideInletTemp);
1263 :
1264 1 : StillSimulatingFlag = true;
1265 :
1266 : // If heat pump is not operating, return
1267 1 : if (SensDemand == 0.0 || heatPump.InletAirMassFlowRate <= 0.0 || heatPump.InletWaterMassFlowRate <= 0.0) {
1268 0 : heatPump.SimFlag = false;
1269 0 : return;
1270 : } else {
1271 1 : heatPump.SimFlag = true;
1272 : }
1273 :
1274 1 : if (compressorOp == HVAC::CompressorOp::Off) {
1275 0 : heatPump.SimFlag = false;
1276 0 : return;
1277 : }
1278 :
1279 1 : if (FirstHVACIteration) {
1280 1 : state.dataWaterToAirHeatPump->initialQSource_calc = heatPump.CoolingCapacity;
1281 1 : state.dataWaterToAirHeatPump->initialQLoadTotal_calc = heatPump.CoolingCapacity;
1282 : }
1283 :
1284 1 : if (state.dataWaterToAirHeatPump->initialQLoadTotal_calc == 0.0) {
1285 0 : state.dataWaterToAirHeatPump->initialQLoadTotal_calc = heatPump.CoolingCapacity;
1286 : }
1287 1 : if (state.dataWaterToAirHeatPump->initialQSource_calc == 0.0) {
1288 0 : state.dataWaterToAirHeatPump->initialQSource_calc = heatPump.CoolingCapacity;
1289 : }
1290 :
1291 : // Loop the calculation at least twice depending whether the latent degradation model
1292 : // is enabled. 1st iteration to calculate the QLatent(rated) at (TDB,TWB)indoorair=(26.7C,19.4C)
1293 : // and 2nd iteration to calculate the QLatent(actual)
1294 :
1295 : // Calculate Part Load Factor and Runtime Fraction
1296 1 : Real64 PLF = 1.0; // part load factor as a function of PLR, RTF = PLR / PLF
1297 1 : if (heatPump.PLFCurveIndex > 0) {
1298 1 : PLF = Curve::CurveValue(state, heatPump.PLFCurveIndex, PartLoadRatio); // Calculate part-load factor
1299 : }
1300 1 : if (fanOp == HVAC::FanOp::Cycling) {
1301 1 : state.dataHVACGlobal->OnOffFanPartLoadFraction = PLF;
1302 : }
1303 1 : heatPump.RunFrac = PartLoadRatio / PLF;
1304 :
1305 1 : QLatRated = 0.0;
1306 1 : QLatActual = 0.0;
1307 : // IF((RuntimeFrac .GE. 1.0) .OR. (Twet_rated .LE. 0.0) .OR. (Gamma_rated .LE. 0.0)) THEN
1308 : // Cycling fan does not required latent degradation model, only the constant fan case
1309 1 : if ((heatPump.RunFrac >= 1.0) || (heatPump.Twet_Rated <= 0.0) || (heatPump.Gamma_Rated <= 0.0) || (fanOp == HVAC::FanOp::Cycling)) {
1310 1 : LatDegradModelSimFlag = false;
1311 : // Set NumIteration4=1 so that latent model would quit after 1 simulation with the actual condition
1312 1 : NumIteration4 = 1;
1313 : } else {
1314 0 : LatDegradModelSimFlag = true;
1315 : // Set NumIteration4=0 so that latent model would simulate twice with rated and actual condition
1316 0 : NumIteration4 = 0;
1317 : }
1318 :
1319 : // Tuned Hoisted quantities out of nested loop that don't change
1320 1 : Real64 const LoadSideMassFlowRate_CpAir_inv(1.0 / (heatPump.InletAirMassFlowRate * CpAir));
1321 : Real64 const LoadSideEffec(1.0 -
1322 1 : std::exp(-heatPump.LoadSideOutsideUACoeff *
1323 1 : LoadSideMassFlowRate_CpAir_inv)); // Load Side Effectiveness based on Outside Heat Transfer Coefficient
1324 1 : Real64 const LoadSideEffec_MassFlowRate_inv(1.0 / (LoadSideEffec * heatPump.InletAirMassFlowRate));
1325 1 : ANTUWET = heatPump.LoadSideTotalUACoeff * LoadSideMassFlowRate_CpAir_inv;
1326 1 : EffectWET = 1.0 - std::exp(-ANTUWET);
1327 :
1328 : while (true) {
1329 1 : ++NumIteration4;
1330 1 : if (NumIteration4 == 1) {
1331 : // Set indoor air conditions to the rated condition
1332 0 : LoadSideInletDBTemp = state.dataWaterToAirHeatPump->LoadSideInletDBTemp_Init;
1333 0 : LoadSideInletHumRat = state.dataWaterToAirHeatPump->LoadSideInletHumRat_Init;
1334 0 : LoadSideAirInletEnth = state.dataWaterToAirHeatPump->LoadSideAirInletEnth_Init;
1335 : } else {
1336 : // Set indoor air conditions to the actual condition
1337 1 : LoadSideInletDBTemp = heatPump.InletAirDBTemp;
1338 1 : LoadSideInletHumRat = heatPump.InletAirHumRat;
1339 1 : LoadSideAirInletEnth = LoadSideAirInletEnth_Unit;
1340 : }
1341 :
1342 : // Outerloop: Calculate source side heat transfer
1343 1 : int NumIteration2 = 0;
1344 1 : Converged = false;
1345 1 : StillSimulatingFlag = true;
1346 1 : SourceResidual = 1.0;
1347 17 : while (StillSimulatingFlag) {
1348 16 : if (Converged) {
1349 1 : StillSimulatingFlag = false;
1350 : }
1351 :
1352 16 : ++NumIteration2;
1353 16 : if (NumIteration2 == 1) {
1354 1 : RelaxParam = 0.5;
1355 : }
1356 :
1357 16 : if (NumIteration2 > STOP2) {
1358 0 : heatPump.SimFlag = false;
1359 0 : return;
1360 : }
1361 :
1362 : // Innerloop: Calculate load side heat transfer
1363 16 : NumIteration3 = 0;
1364 16 : LoadResidual = 1.0;
1365 59 : while (LoadResidual > ERR) {
1366 :
1367 43 : ++NumIteration3;
1368 :
1369 43 : if (NumIteration3 > STOP3) {
1370 0 : heatPump.SimFlag = false;
1371 0 : return;
1372 : }
1373 :
1374 : // Determine Effectiveness of Source Side
1375 43 : CpFluid = state.dataPlnt->PlantLoop(heatPump.plantLoc.loopNum)
1376 43 : .glycol->getSpecificHeat(state, heatPump.InletWaterTemp, RoutineNameSourceSideInletTemp);
1377 :
1378 43 : if (state.dataPlnt->PlantLoop(heatPump.plantLoc.loopNum).glycol->Num == Fluid::GlycolNum_Water) {
1379 43 : SourceSideEffect = 1.0 - std::exp(-heatPump.SourceSideUACoeff / (CpFluid * heatPump.InletWaterMassFlowRate));
1380 : } else {
1381 0 : DegradFactor = DegradF(state, state.dataPlnt->PlantLoop(heatPump.plantLoc.loopNum).glycol, heatPump.InletWaterTemp);
1382 0 : SourceSideEffect =
1383 0 : 1.0 / ((heatPump.SourceSideHTR1 * std::pow(SourceSideVolFlowRate, -0.8)) / DegradFactor + heatPump.SourceSideHTR2);
1384 : }
1385 :
1386 : // Determine Source Side Tempertaure (Condensing Temp in this case)
1387 43 : SourceSideTemp = heatPump.InletWaterTemp + state.dataWaterToAirHeatPump->initialQSource_calc /
1388 43 : (SourceSideEffect * CpFluid * heatPump.InletWaterMassFlowRate);
1389 :
1390 : // Compute the Effective Surface Temperature
1391 43 : EffectiveSatEnth = LoadSideAirInletEnth - state.dataWaterToAirHeatPump->initialQLoadTotal_calc * LoadSideEffec_MassFlowRate_inv;
1392 :
1393 43 : EffectiveSurfaceTemp = Psychrometrics::PsyTsatFnHPb(state, EffectiveSatEnth, PB, RoutineNameLoadSideSurfaceTemp);
1394 :
1395 43 : QSensible = heatPump.InletAirMassFlowRate * CpAir * (LoadSideInletDBTemp - EffectiveSurfaceTemp) * LoadSideEffec;
1396 43 : EvapSatEnth =
1397 43 : LoadSideAirInletEnth - state.dataWaterToAirHeatPump->initialQLoadTotal_calc / (EffectWET * heatPump.InletAirMassFlowRate);
1398 :
1399 43 : EvapTemp = Psychrometrics::PsyTsatFnHPb(state, EvapSatEnth, PB, RoutineNameLoadSideEvapTemp);
1400 :
1401 : // Load Side Saturated Temperature (Evaporating Temp in this case)
1402 43 : LoadSideTemp = EvapTemp;
1403 :
1404 : // Determine the Load Side and Source Side Saturated Temp (evaporating and condensing pressures)
1405 43 : SourceSidePressure = heatPump.refrig->getSatPressure(state, SourceSideTemp, RoutineNameSourceSideTemp);
1406 43 : LoadSidePressure = heatPump.refrig->getSatPressure(state, LoadSideTemp, RoutineNameLoadSideTemp);
1407 :
1408 43 : if (LoadSidePressure < heatPump.LowPressCutoff && !FirstHVACIteration) {
1409 0 : if (!state.dataGlobal->WarmupFlag) {
1410 0 : ShowRecurringWarningErrorAtEnd(
1411 : state,
1412 0 : format("WaterToAir Heat pump:cooling [{}] shut off on low pressure < {:.0R}", heatPump.Name, heatPump.LowPressCutoff),
1413 0 : heatPump.LowPressClgError,
1414 : LoadSidePressure,
1415 : LoadSidePressure,
1416 : _,
1417 : "[Pa]",
1418 : "[Pa]");
1419 : }
1420 0 : heatPump.SimFlag = false;
1421 0 : return;
1422 : }
1423 :
1424 43 : if (SourceSidePressure > heatPump.HighPressCutoff && !FirstHVACIteration) {
1425 0 : if (!state.dataGlobal->WarmupFlag) {
1426 0 : ShowRecurringWarningErrorAtEnd(state,
1427 0 : format("WaterToAir Heat pump:cooling [{}] shut off on high pressure > {:.0R}",
1428 0 : heatPump.Name,
1429 0 : heatPump.HighPressCutoff),
1430 0 : heatPump.HighPressClgError,
1431 0 : heatPump.InletWaterTemp,
1432 0 : heatPump.InletWaterTemp,
1433 : _,
1434 : "SourceSideInletTemp[C]",
1435 : "SourceSideInletTemp[C]");
1436 : }
1437 0 : heatPump.SimFlag = false;
1438 0 : return;
1439 : }
1440 :
1441 : // Determine Suction Pressure & Discharge Pressure at Compressor Exit
1442 43 : if (heatPump.compressorType == CompressorType::Reciprocating) { // RECIPROCATING
1443 0 : SuctionPr = LoadSidePressure - heatPump.CompSucPressDrop;
1444 0 : DischargePr = SourceSidePressure + heatPump.CompSucPressDrop;
1445 43 : } else if (heatPump.compressorType == CompressorType::Rotary) { // ROTARY
1446 0 : SuctionPr = LoadSidePressure;
1447 0 : DischargePr = SourceSidePressure + heatPump.CompSucPressDrop;
1448 43 : } else if (heatPump.compressorType == CompressorType::Scroll) { // SCROLL
1449 43 : SuctionPr = LoadSidePressure;
1450 43 : DischargePr = SourceSidePressure;
1451 : }
1452 :
1453 : // Determine the Load Side Outlet Enthalpy (Saturated Gas)
1454 43 : Quality = 1.0;
1455 43 : LoadSideOutletEnth = heatPump.refrig->getSatEnthalpy(state, LoadSideTemp, Quality, RoutineNameLoadSideTemp);
1456 :
1457 : // Determine Source Side Outlet Enthalpy (Saturated Liquid)
1458 43 : Quality = 0.0;
1459 43 : SourceSideOutletEnth = heatPump.refrig->getSatEnthalpy(state, SourceSideTemp, Quality, RoutineNameSourceSideTemp);
1460 : // Determine Superheated Temperature of the Load Side outlet/compressor Inlet
1461 43 : CompressInletTemp = LoadSideTemp + heatPump.SuperheatTemp;
1462 :
1463 : // Determine the Enthalpy of the Superheated Fluid at Load Side Outlet/Compressor Inlet
1464 43 : SuperHeatEnth = heatPump.refrig->getSupHeatEnthalpy(state, CompressInletTemp, LoadSidePressure, RoutineNameCompressInletTemp);
1465 :
1466 : // Determining the suction state of the fluid from inlet state involves interation
1467 : // Method employed...
1468 : // Determine the saturated temp at suction pressure, shoot out into the superheated region find the enthalpy
1469 : // check that with the inlet enthalpy ( as suction loss is isenthalpic). Iterate till desired accuracy is reached
1470 43 : if (!Converged) {
1471 42 : CompSuctionSatTemp = heatPump.refrig->getSatTemperature(state, SuctionPr, RoutineNameSuctionPr);
1472 42 : CompSuctionTemp1 = CompSuctionSatTemp;
1473 :
1474 : // Shoot into the Superheated Region
1475 42 : CompSuctionTemp2 = CompSuctionSatTemp + DegreeofSuperheat;
1476 : }
1477 :
1478 129 : auto f = [&state, &heatPump, SuctionPr, SuperHeatEnth](Real64 const CompSuctionTemp) {
1479 : static constexpr std::string_view RoutineName("CalcWaterToAirHPHeating:CalcCompSuctionTemp");
1480 129 : Real64 compSuctionEnth = heatPump.refrig->getSupHeatEnthalpy(state, CompSuctionTemp, SuctionPr, RoutineName);
1481 129 : return (compSuctionEnth - SuperHeatEnth) / SuperHeatEnth;
1482 43 : };
1483 :
1484 86 : General::SolveRoot(
1485 43 : state, ERR, STOP1, SolFlag, state.dataWaterToAirHeatPump->CompSuctionTemp, f, CompSuctionTemp1, CompSuctionTemp2);
1486 43 : if (SolFlag == -1) {
1487 0 : heatPump.SimFlag = false;
1488 0 : return;
1489 : }
1490 43 : CompSuctionEnth = heatPump.refrig->getSupHeatEnthalpy(
1491 43 : state, state.dataWaterToAirHeatPump->CompSuctionTemp, SuctionPr, RoutineNameCompSuctionTemp);
1492 43 : CompSuctionDensity = heatPump.refrig->getSupHeatDensity(
1493 43 : state, state.dataWaterToAirHeatPump->CompSuctionTemp, SuctionPr, RoutineNameCompSuctionTemp);
1494 :
1495 : // Find Refrigerant Flow Rate
1496 43 : switch (heatPump.compressorType) {
1497 0 : case CompressorType::Reciprocating: {
1498 0 : MassRef =
1499 0 : heatPump.CompPistonDisp * CompSuctionDensity *
1500 0 : (1.0 + heatPump.CompClearanceFactor - heatPump.CompClearanceFactor * std::pow(DischargePr / SuctionPr, 1.0 / gamma));
1501 0 : break;
1502 : }
1503 0 : case CompressorType::Rotary: {
1504 0 : MassRef = heatPump.CompPistonDisp * CompSuctionDensity;
1505 0 : break;
1506 : }
1507 43 : case CompressorType::Scroll: {
1508 43 : MassRef = heatPump.RefVolFlowRate * CompSuctionDensity - heatPump.LeakRateCoeff * (DischargePr / SuctionPr);
1509 43 : break;
1510 : }
1511 0 : default:
1512 0 : break;
1513 : }
1514 43 : MassRef = max(0.0, MassRef);
1515 :
1516 : // Find the Load Side Heat Transfer
1517 43 : QLoadTotal = MassRef * (LoadSideOutletEnth - SourceSideOutletEnth);
1518 43 : LoadResidual = std::abs(QLoadTotal - state.dataWaterToAirHeatPump->initialQLoadTotal_calc) /
1519 43 : state.dataWaterToAirHeatPump->initialQLoadTotal_calc;
1520 86 : state.dataWaterToAirHeatPump->initialQLoadTotal_calc +=
1521 43 : RelaxParam * (QLoadTotal - state.dataWaterToAirHeatPump->initialQLoadTotal_calc);
1522 43 : if (NumIteration3 > 8) {
1523 4 : RelaxParam = 0.3;
1524 : }
1525 : }
1526 :
1527 : // Determine the Power Consumption
1528 16 : switch (heatPump.compressorType) {
1529 0 : case CompressorType::Reciprocating:
1530 : case CompressorType::Rotary: {
1531 0 : Power = heatPump.PowerLosses + (1.0 / heatPump.LossFactor) * (MassRef * gamma / (gamma - 1.0) * SuctionPr / CompSuctionDensity *
1532 0 : (std::pow(DischargePr / SuctionPr, (gamma - 1.0) / gamma) - 1.0));
1533 0 : break;
1534 : }
1535 16 : case CompressorType::Scroll: {
1536 16 : Power = heatPump.PowerLosses + (1.0 / heatPump.LossFactor) * (gamma / (gamma - 1.0)) * SuctionPr * heatPump.RefVolFlowRate *
1537 16 : (((gamma - 1.0) / gamma) * ((DischargePr / SuctionPr) / heatPump.VolumeRatio) +
1538 16 : ((1.0 / gamma) * std::pow(heatPump.VolumeRatio, gamma - 1.0)) - 1.0);
1539 16 : break;
1540 : }
1541 0 : default:
1542 0 : break;
1543 : }
1544 :
1545 : // Determine the Sourceside Heat Rate
1546 16 : QSource = Power + QLoadTotal;
1547 16 : SourceResidual =
1548 16 : std::abs(QSource - state.dataWaterToAirHeatPump->initialQSource_calc) / state.dataWaterToAirHeatPump->initialQSource_calc;
1549 16 : if (SourceResidual < ERR) {
1550 2 : Converged = true;
1551 : }
1552 16 : state.dataWaterToAirHeatPump->initialQSource_calc += RelaxParam * (QSource - state.dataWaterToAirHeatPump->initialQSource_calc);
1553 16 : if (NumIteration2 > 8) {
1554 8 : RelaxParam = 0.2;
1555 : }
1556 : }
1557 :
1558 1 : if (SuctionPr < heatPump.LowPressCutoff) {
1559 0 : ShowWarningError(state, "Heat pump:cooling shut down on low pressure");
1560 0 : heatPump.SimFlag = false;
1561 : }
1562 :
1563 1 : if (DischargePr > heatPump.HighPressCutoff && !FirstHVACIteration) {
1564 0 : ShowWarningError(state, "Heat pump:cooling shut down on high pressure");
1565 0 : heatPump.SimFlag = false;
1566 : }
1567 :
1568 1 : if (QSensible > QLoadTotal) {
1569 1 : QSensible = QLoadTotal;
1570 : }
1571 :
1572 1 : if (LatDegradModelSimFlag) {
1573 0 : if (NumIteration4 == 1) {
1574 0 : QLatRated = QLoadTotal - QSensible;
1575 :
1576 0 : } else if (NumIteration4 == 2) {
1577 0 : QLatActual = QLoadTotal - QSensible;
1578 0 : SHRss = QSensible / QLoadTotal;
1579 0 : LoadSideInletWBTemp = Psychrometrics::PsyTwbFnTdbWPb(state, LoadSideInletDBTemp, LoadSideInletHumRat, PB);
1580 0 : SHReff = CalcEffectiveSHR(
1581 : state, HPNum, SHRss, fanOp, heatPump.RunFrac, QLatRated, QLatActual, LoadSideInletDBTemp, LoadSideInletWBTemp);
1582 : // Update sensible capacity based on effective SHR
1583 0 : QSensible = QLoadTotal * SHReff;
1584 0 : goto LOOPLatentDegradationModel_exit;
1585 : }
1586 : } else {
1587 :
1588 1 : SHReff = QSensible / QLoadTotal;
1589 1 : goto LOOPLatentDegradationModel_exit;
1590 : }
1591 0 : }
1592 1 : LOOPLatentDegradationModel_exit:;
1593 :
1594 : // calculate coil outlet state variables
1595 1 : LoadSideAirOutletEnth = LoadSideAirInletEnth - QLoadTotal / heatPump.InletAirMassFlowRate;
1596 1 : LoadSideOutletDBTemp = LoadSideInletDBTemp - QSensible * LoadSideMassFlowRate_CpAir_inv;
1597 1 : LoadSideOutletHumRat = Psychrometrics::PsyWFnTdbH(state, LoadSideOutletDBTemp, LoadSideAirOutletEnth, RoutineNameLoadSideOutletEnthalpy);
1598 1 : SourceSideOutletTemp = heatPump.InletWaterTemp + QSource / (heatPump.InletWaterMassFlowRate * CpWater);
1599 :
1600 : // Actual outlet conditions are "average" for time step
1601 1 : if (fanOp == HVAC::FanOp::Continuous) {
1602 : // continuous fan, cycling compressor
1603 0 : heatPump.OutletAirEnthalpy = PartLoadRatio * LoadSideAirOutletEnth + (1.0 - PartLoadRatio) * LoadSideAirInletEnth;
1604 0 : heatPump.OutletAirHumRat = PartLoadRatio * LoadSideOutletHumRat + (1.0 - PartLoadRatio) * LoadSideInletHumRat;
1605 0 : heatPump.OutletAirDBTemp = Psychrometrics::PsyTdbFnHW(heatPump.OutletAirEnthalpy, heatPump.OutletAirHumRat);
1606 : } else {
1607 : // default to cycling fan, cycling compressor
1608 1 : heatPump.OutletAirEnthalpy = LoadSideAirOutletEnth;
1609 1 : heatPump.OutletAirHumRat = LoadSideOutletHumRat;
1610 1 : heatPump.OutletAirDBTemp = LoadSideOutletDBTemp;
1611 : }
1612 :
1613 : // scale heat transfer rates and power to run time
1614 1 : QLoadTotal *= PartLoadRatio;
1615 1 : QSensible *= PartLoadRatio;
1616 1 : Power *= heatPump.RunFrac;
1617 1 : QSource *= PartLoadRatio;
1618 :
1619 : // Update heat pump data structure
1620 1 : state.dataHVACGlobal->DXElecCoolingPower = Power;
1621 1 : heatPump.Power = Power;
1622 1 : heatPump.QLoadTotal = QLoadTotal;
1623 1 : heatPump.QSensible = QSensible;
1624 1 : heatPump.QLatent = QLoadTotal - QSensible;
1625 1 : heatPump.QSource = QSource;
1626 1 : heatPump.PartLoadRatio = PartLoadRatio;
1627 :
1628 : // Air-side outlet conditions are already calculated above
1629 1 : heatPump.OutletAirMassFlowRate = heatPump.InletAirMassFlowRate;
1630 1 : heatPump.OutletWaterTemp = SourceSideOutletTemp;
1631 1 : heatPump.OutletWaterMassFlowRate = heatPump.InletWaterMassFlowRate;
1632 1 : heatPump.OutletWaterEnthalpy = heatPump.InletWaterEnthalpy + QSource / heatPump.InletWaterMassFlowRate;
1633 : }
1634 :
1635 1 : void CalcWatertoAirHPHeating(EnergyPlusData &state,
1636 : int const HPNum, // heat pump number
1637 : HVAC::FanOp const fanOp, // fan/compressor cycling scheme indicator
1638 : bool const FirstHVACIteration, // first iteration flag
1639 : [[maybe_unused]] bool const InitFlag, // first iteration flag
1640 : Real64 const SensDemand,
1641 : HVAC::CompressorOp const compressorOp,
1642 : Real64 const PartLoadRatio)
1643 : {
1644 :
1645 : // SUBROUTINE INFORMATION:
1646 : // AUTHOR Hui Jin
1647 : // DATE WRITTEN Oct 2000
1648 : // MODIFIED R. Raustad (Oct 2006) Revised iteration technique
1649 :
1650 : // PURPOSE OF THIS SUBROUTINE:
1651 : // Simulates a parameter estimation based water to air heat pump model
1652 :
1653 : // Using/Aliasing
1654 1 : auto &heatPump = state.dataWaterToAirHeatPump->WatertoAirHP(HPNum);
1655 :
1656 : // SUBROUTINE PARAMETER DEFINITIONS:
1657 1 : Real64 constexpr CpWater(4210.0); // Specific heat of water J/kg_C
1658 1 : Real64 constexpr DegreeofSuperheat(80.0); // Initial guess of degree of superheat
1659 1 : Real64 constexpr gamma(1.114); // Expnasion Coefficient
1660 1 : Real64 RelaxParam(0.5); // Relaxation Parameter
1661 1 : Real64 constexpr ERR(0.01); // Error Value
1662 1 : int constexpr STOP1(1000); // Iteration stopper1
1663 1 : int constexpr STOP2(1000); // Iteration stopper2
1664 1 : int constexpr STOP3(1000); // Iteration stopper3
1665 :
1666 : static constexpr std::string_view RoutineNameSourceSideInletTemp("CalcWatertoAirHPHeating:SourceSideInletTemp");
1667 : static constexpr std::string_view RoutineNameSourceSideTemp("CalcWatertoAirHPHeating:SourceSideTemp");
1668 : static constexpr std::string_view RoutineNameLoadSideTemp("CalcWatertoAirHPHeating:LoadSideTemp");
1669 : static constexpr std::string_view RoutineNameLoadSideOutletEnthalpy("CalcWatertoAirHPHeating:LoadSideOutletEnthalpy");
1670 : static constexpr std::string_view RoutineNameCompressInletTemp("CalcWatertoAirHPHeating:CompressInletTemp");
1671 : static constexpr std::string_view RoutineNameSuctionPr("CalcWatertoAirHPHeating:SuctionPr");
1672 : static constexpr std::string_view RoutineNameCompSuctionTemp("CalcWatertoAirHPHeating:CompSuctionTemp");
1673 :
1674 : int NumIteration3; // Number of Iteration3
1675 : Real64 Quality;
1676 : Real64 SourceSideOutletTemp; // Source Side Outlet Temperature [C]
1677 : Real64 SourceSideVolFlowRate; // Source Side Volumetric Flow Rate [m3/s]
1678 : Real64 CpFluid; // Specific heat of source side fluid(J/kg)
1679 : Real64 LoadSideOutletDBTemp; // Load Side Outlet Dry Bulb Temperature [C]
1680 : Real64 LoadSideOutletHumRat; // Load Side Outlet Humidity Ratio [kg/kg]
1681 : Real64 LoadSideAirOutletEnth; // Load Side Outlet Enthalpy [J/kg]
1682 : Real64 CpAir; // Specific Heat of Air [J/kg_C]
1683 : Real64 DegradFactor; // Degradation Factor [~]
1684 : Real64 QSource; // Source Side Heat Transfer Rate [W]
1685 : Real64 QLoadTotal; // Load Side Heat Transfer Rate [W]
1686 : Real64 Power; // Power Consumption [W]
1687 :
1688 : Real64 SourceSideEffect; // Source Side Heat Exchanger Effectiveness
1689 : Real64 SourceSideTemp; // Source Side Saturated Refrigerant Temperature [C]
1690 : Real64 LoadSideTemp; // Load Side Saturated Refrigerant Temperature [C]
1691 : Real64 SourceSidePressure; // Source Side Saturated Refrigerant Pressure [Pa]
1692 : Real64 LoadSidePressure; // Load Side Saturated Refrigerant Pressure [Pa]
1693 : Real64 SuctionPr; // Compressor Suction Pressure [Pa]
1694 : Real64 DischargePr; // Compressor Discharge Pressure [Pa]
1695 : Real64 CompressInletTemp; // Temperature of the Refrigerant Entering the Compressor [C]
1696 : Real64 MassRef; // Mass Flow Rate of Refrigerant [kg/s]
1697 : Real64 SourceSideOutletEnth; // Enthalpy of Refrigerant leaving the Source Side Heat Exchanger [J/kg]
1698 : Real64 LoadSideOutletEnth; // Enthalpy of Refrigerant leaving the Load Side Heat Exchanger [J/kg]
1699 : Real64 SuperHeatEnth; // Enthalpy of the Superheated Refrigerant [J/kg]
1700 : Real64 CompSuctionTemp1; // Guess of the Temperature of the Refrigerant Entering the
1701 : // Compressor #1 [C]
1702 : Real64 CompSuctionTemp2; // Guess of the Temperature of the Refrigerant Entering the
1703 : // Compressor #2 [C]
1704 : Real64 CompSuctionTemp; // Temperature of the Refrigerant Entering the Compressor [C]
1705 : Real64 CompSuctionEnth; // Enthalpy of the Refrigerant Entering the Compressor [J/kg]
1706 : Real64 CompSuctionDensity; // Density of the Refrigerant Entering the Compressorkg/m3
1707 : Real64 CompSuctionSatTemp; // Temperature of Saturated Refrigerant at Compressor Suction Pressure [C]
1708 : bool StillSimulatingFlag; // Final Simulation Flag
1709 : bool Converged; // Overall convergence Flag
1710 : int SolFlag; // Solution flag returned from RegulaFalsi function
1711 : Real64 LoadResidual; // loop convergence criteria
1712 : Real64 SourceResidual; // loop convergence criteria
1713 :
1714 : // LOAD LOCAL VARIABLES FROM DATA STRUCTURE (for code readability)
1715 :
1716 1 : CpAir = Psychrometrics::PsyCpAirFnW(heatPump.InletAirHumRat);
1717 1 : SourceSideVolFlowRate =
1718 1 : heatPump.InletWaterMassFlowRate /
1719 1 : state.dataPlnt->PlantLoop(heatPump.plantLoc.loopNum).glycol->getDensity(state, heatPump.InletWaterTemp, RoutineNameSourceSideInletTemp);
1720 :
1721 : // If heat pump is not operating, return
1722 1 : if (SensDemand == 0.0 || heatPump.InletAirMassFlowRate <= 0.0 || heatPump.InletWaterMassFlowRate <= 0.0) {
1723 0 : heatPump.SimFlag = false;
1724 0 : return;
1725 : } else {
1726 1 : heatPump.SimFlag = true;
1727 : }
1728 :
1729 1 : if (compressorOp == HVAC::CompressorOp::Off) {
1730 0 : heatPump.SimFlag = false;
1731 0 : return;
1732 : }
1733 :
1734 1 : if (FirstHVACIteration) {
1735 1 : state.dataWaterToAirHeatPump->initialQLoad = heatPump.HeatingCapacity;
1736 1 : state.dataWaterToAirHeatPump->initialQSource = heatPump.HeatingCapacity;
1737 : }
1738 :
1739 1 : if (state.dataWaterToAirHeatPump->initialQLoad == 0.0) {
1740 0 : state.dataWaterToAirHeatPump->initialQLoad = heatPump.HeatingCapacity;
1741 : }
1742 1 : if (state.dataWaterToAirHeatPump->initialQSource == 0.0) {
1743 0 : state.dataWaterToAirHeatPump->initialQSource = heatPump.HeatingCapacity;
1744 : }
1745 :
1746 : // Tuned Hoisted quantities out of nested loop that don't change
1747 1 : Real64 const LoadSideMassFlowRate_CpAir_inv(1.0 / (heatPump.InletAirMassFlowRate * CpAir));
1748 : Real64 const LoadSideEffect(1.0 -
1749 1 : std::exp(-heatPump.LoadSideTotalUACoeff *
1750 1 : LoadSideMassFlowRate_CpAir_inv)); // Load Side Effectiveness based on Outside Heat Transfer Coefficient
1751 1 : Real64 const LoadSideEffect_CpAir_MassFlowRate_inv(1.0 / (LoadSideEffect * CpAir * heatPump.InletAirMassFlowRate));
1752 :
1753 : // Outerloop: calculate load side heat transfer
1754 1 : NumIteration3 = 0;
1755 1 : Converged = false;
1756 1 : StillSimulatingFlag = true;
1757 1 : LoadResidual = 1.0;
1758 18 : while (StillSimulatingFlag) {
1759 17 : if (Converged) {
1760 1 : StillSimulatingFlag = false;
1761 : }
1762 :
1763 17 : ++NumIteration3;
1764 17 : if (NumIteration3 == 1) {
1765 1 : RelaxParam = 0.5;
1766 : }
1767 :
1768 17 : if (NumIteration3 > STOP3) {
1769 0 : heatPump.SimFlag = false;
1770 0 : return;
1771 : }
1772 :
1773 : // Innerloop: calculate load side heat transfer
1774 17 : int NumIteration2 = 0;
1775 17 : SourceResidual = 1.0;
1776 64 : while (SourceResidual > ERR) {
1777 :
1778 47 : ++NumIteration2;
1779 :
1780 47 : if (NumIteration2 > STOP2) {
1781 0 : heatPump.SimFlag = false;
1782 0 : return;
1783 : }
1784 :
1785 : // Determine Effectiveness of Source Side
1786 47 : CpFluid = state.dataPlnt->PlantLoop(heatPump.plantLoc.loopNum)
1787 47 : .glycol->getSpecificHeat(state, heatPump.InletWaterTemp, RoutineNameSourceSideInletTemp);
1788 :
1789 47 : if (state.dataPlnt->PlantLoop(heatPump.plantLoc.loopNum).glycol->Num == Fluid::GlycolNum_Water) {
1790 47 : SourceSideEffect = 1.0 - std::exp(-heatPump.SourceSideUACoeff / (CpFluid * heatPump.InletWaterMassFlowRate));
1791 : } else {
1792 0 : DegradFactor = DegradF(state, state.dataPlnt->PlantLoop(heatPump.plantLoc.loopNum).glycol, heatPump.InletWaterTemp);
1793 0 : SourceSideEffect =
1794 0 : 1.0 / ((heatPump.SourceSideHTR1 * std::pow(SourceSideVolFlowRate, -0.8)) / DegradFactor + heatPump.SourceSideHTR2);
1795 : }
1796 :
1797 : // Determine Source Side Tempertaure (Evap. Temp for this mode)
1798 94 : SourceSideTemp = heatPump.InletWaterTemp -
1799 47 : state.dataWaterToAirHeatPump->initialQSource / (SourceSideEffect * CpFluid * heatPump.InletWaterMassFlowRate);
1800 :
1801 : // Determine Load Side Tempertaure (Condensing Temp for this mode)
1802 47 : LoadSideTemp = heatPump.InletAirDBTemp + state.dataWaterToAirHeatPump->initialQLoad * LoadSideEffect_CpAir_MassFlowRate_inv;
1803 :
1804 : // Determine the Load Side and Source Side Saturated Temp (evaporating and condensing pressures)
1805 47 : SourceSidePressure = heatPump.refrig->getSatPressure(state, SourceSideTemp, RoutineNameSourceSideTemp);
1806 47 : LoadSidePressure = heatPump.refrig->getSatPressure(state, LoadSideTemp, RoutineNameLoadSideTemp);
1807 47 : if (SourceSidePressure < heatPump.LowPressCutoff && !FirstHVACIteration) {
1808 0 : if (!state.dataGlobal->WarmupFlag) {
1809 0 : ShowRecurringWarningErrorAtEnd(
1810 : state,
1811 0 : format("WaterToAir Heat pump:heating [{}] shut off on low pressure < {:.0R}", heatPump.Name, heatPump.LowPressCutoff),
1812 0 : heatPump.LowPressHtgError,
1813 : SourceSidePressure,
1814 : SourceSidePressure,
1815 : _,
1816 : "[Pa]",
1817 : "[Pa]");
1818 : }
1819 0 : heatPump.SimFlag = false;
1820 0 : return;
1821 : }
1822 :
1823 47 : if (LoadSidePressure > heatPump.HighPressCutoff && !FirstHVACIteration) {
1824 0 : if (!state.dataGlobal->WarmupFlag) {
1825 0 : ShowRecurringWarningErrorAtEnd(
1826 : state,
1827 0 : format("WaterToAir Heat pump:heating [{}] shut off on high pressure > {:.0R}", heatPump.Name, heatPump.HighPressCutoff),
1828 0 : heatPump.HighPressHtgError,
1829 0 : heatPump.InletWaterTemp,
1830 0 : heatPump.InletWaterTemp,
1831 : _,
1832 : "SourceSideInletTemp[C]",
1833 : "SourceSideInletTemp[C]");
1834 : }
1835 : // CALL ShowWarningError(state, 'Heat pump:heating shut off on high pressure')
1836 : // WRITE(CErrCount,*) SourceSideInletTemp
1837 : // CErrCount=ADJUSTL(CErrCount)
1838 : // CALL ShowContinueError(state, 'Source side inlet temperature too low, T='//TRIM(CErrCount))
1839 : // CALL ShowContinueError(state, 'Heat pump heating demand not met by plant side')
1840 0 : heatPump.SimFlag = false;
1841 0 : return;
1842 : }
1843 :
1844 : // Determine Suction Pressure at Compressor Entrance & Discharge Pressure at Compressor Exit
1845 47 : switch (heatPump.compressorType) {
1846 0 : case CompressorType::Reciprocating: {
1847 0 : SuctionPr = SourceSidePressure - heatPump.CompSucPressDrop;
1848 0 : DischargePr = LoadSidePressure + heatPump.CompSucPressDrop;
1849 0 : break;
1850 : }
1851 0 : case CompressorType::Rotary: {
1852 0 : SuctionPr = SourceSidePressure;
1853 0 : DischargePr = LoadSidePressure + heatPump.CompSucPressDrop;
1854 0 : break;
1855 : }
1856 47 : case CompressorType::Scroll: {
1857 47 : SuctionPr = SourceSidePressure;
1858 47 : DischargePr = LoadSidePressure;
1859 47 : break;
1860 : }
1861 0 : default:
1862 0 : break;
1863 : }
1864 :
1865 : // Determine the Source Side Outlet Enthalpy
1866 : // Quality of the refrigerant leaving the evaporator is saturated gas
1867 47 : Quality = 1.0;
1868 47 : SourceSideOutletEnth = heatPump.refrig->getSatEnthalpy(state, SourceSideTemp, Quality, RoutineNameSourceSideTemp);
1869 :
1870 : // Determine Load Side Outlet Enthalpy
1871 : // Quality of the refrigerant leaving the condenser is saturated liguid
1872 47 : Quality = 0.0;
1873 47 : LoadSideOutletEnth = heatPump.refrig->getSatEnthalpy(state, LoadSideTemp, Quality, RoutineNameLoadSideTemp);
1874 :
1875 : // Determine Superheated Temperature of the Source Side outlet/compressor Inlet
1876 47 : CompressInletTemp = SourceSideTemp + heatPump.SuperheatTemp;
1877 :
1878 : // Determine the Enathalpy of the Superheated Fluid at Source Side Outlet/Compressor Inlet
1879 47 : SuperHeatEnth = heatPump.refrig->getSupHeatEnthalpy(state, CompressInletTemp, SourceSidePressure, RoutineNameCompressInletTemp);
1880 :
1881 : // Determining the suction state of the fluid from inlet state involves interation
1882 : // Method employed...
1883 : // Determine the saturated temp at suction pressure, shoot out into the superheated region find the enthalpy
1884 : // check that with the inlet enthalpy ( as suction loss is isenthalpic). Iterate till desired accuracy is reached
1885 :
1886 47 : if (!Converged) {
1887 46 : CompSuctionSatTemp = heatPump.refrig->getSatTemperature(state, SuctionPr, RoutineNameSuctionPr);
1888 46 : CompSuctionTemp1 = CompSuctionSatTemp;
1889 :
1890 : // Shoot into the Superheated Region
1891 46 : CompSuctionTemp2 = CompSuctionSatTemp + DegreeofSuperheat;
1892 : }
1893 :
1894 141 : auto f = [&state, &heatPump, SuctionPr, SuperHeatEnth](Real64 const CompSuctionTemp) {
1895 : static constexpr std::string_view RoutineName("CalcWaterToAirHPHeating:CalcCompSuctionTemp");
1896 141 : Real64 compSuctionEnth = heatPump.refrig->getSupHeatEnthalpy(state, CompSuctionTemp, SuctionPr, RoutineName);
1897 141 : return (compSuctionEnth - SuperHeatEnth) / SuperHeatEnth;
1898 47 : };
1899 :
1900 47 : General::SolveRoot(state, ERR, STOP1, SolFlag, CompSuctionTemp, f, CompSuctionTemp1, CompSuctionTemp2);
1901 47 : if (SolFlag == -1) {
1902 0 : heatPump.SimFlag = false;
1903 0 : return;
1904 : }
1905 47 : CompSuctionEnth = heatPump.refrig->getSupHeatEnthalpy(state, CompSuctionTemp, SuctionPr, RoutineNameCompSuctionTemp);
1906 47 : CompSuctionDensity = heatPump.refrig->getSupHeatDensity(state, CompSuctionTemp, SuctionPr, RoutineNameCompSuctionTemp);
1907 :
1908 : // Find Refrigerant Flow Rate
1909 47 : switch (heatPump.compressorType) {
1910 0 : case CompressorType::Reciprocating: {
1911 0 : MassRef = heatPump.CompPistonDisp * CompSuctionDensity *
1912 0 : (1 + heatPump.CompClearanceFactor - heatPump.CompClearanceFactor * std::pow(DischargePr / SuctionPr, 1 / gamma));
1913 0 : break;
1914 : }
1915 0 : case CompressorType::Rotary: {
1916 0 : MassRef = heatPump.CompPistonDisp * CompSuctionDensity;
1917 0 : break;
1918 : }
1919 47 : case CompressorType::Scroll: {
1920 47 : MassRef = heatPump.RefVolFlowRate * CompSuctionDensity - heatPump.LeakRateCoeff * (DischargePr / SuctionPr);
1921 47 : break;
1922 : }
1923 0 : default:
1924 0 : break;
1925 : }
1926 47 : MassRef = max(0.0, MassRef);
1927 :
1928 : // Find the Source Side Heat Transfer
1929 47 : QSource = MassRef * (SourceSideOutletEnth - LoadSideOutletEnth);
1930 47 : SourceResidual = std::abs(QSource - state.dataWaterToAirHeatPump->initialQSource) / state.dataWaterToAirHeatPump->initialQSource;
1931 47 : state.dataWaterToAirHeatPump->initialQSource += RelaxParam * (QSource - state.dataWaterToAirHeatPump->initialQSource);
1932 47 : if (NumIteration2 > 8) {
1933 10 : RelaxParam = 0.3;
1934 : }
1935 : }
1936 :
1937 : // Determine the Power Consumption
1938 17 : switch (heatPump.compressorType) {
1939 0 : case CompressorType::Reciprocating:
1940 : case CompressorType::Rotary: {
1941 0 : Power = heatPump.PowerLosses + (1 / heatPump.LossFactor) * (MassRef * gamma / (gamma - 1) * SuctionPr / CompSuctionDensity *
1942 0 : (std::pow(DischargePr / SuctionPr, (gamma - 1) / gamma) - 1));
1943 0 : break;
1944 : }
1945 17 : case CompressorType::Scroll: {
1946 17 : Power = heatPump.PowerLosses + (1 / heatPump.LossFactor) * (gamma / (gamma - 1)) * SuctionPr * heatPump.RefVolFlowRate *
1947 17 : (((gamma - 1) / gamma) * ((DischargePr / SuctionPr) / heatPump.VolumeRatio) +
1948 17 : ((1 / gamma) * std::pow(heatPump.VolumeRatio, gamma - 1)) - 1);
1949 17 : break;
1950 : }
1951 0 : default:
1952 0 : break;
1953 : }
1954 :
1955 : // Determine the Load Side Heat Rate
1956 17 : QLoadTotal = Power + QSource;
1957 17 : LoadResidual = std::abs(QLoadTotal - state.dataWaterToAirHeatPump->initialQLoad) / state.dataWaterToAirHeatPump->initialQLoad;
1958 17 : if (LoadResidual < ERR) {
1959 2 : Converged = true;
1960 : }
1961 17 : state.dataWaterToAirHeatPump->initialQLoad += RelaxParam * (QLoadTotal - state.dataWaterToAirHeatPump->initialQLoad);
1962 17 : if (NumIteration3 > 8) {
1963 9 : RelaxParam = 0.2;
1964 : }
1965 : }
1966 :
1967 1 : if (SuctionPr < heatPump.LowPressCutoff && !FirstHVACIteration) {
1968 0 : ShowWarningError(state, "Heat pump:heating shut down on low pressure");
1969 0 : heatPump.SimFlag = false;
1970 0 : return;
1971 : }
1972 :
1973 1 : if (DischargePr > heatPump.HighPressCutoff && !FirstHVACIteration) {
1974 0 : ShowWarningError(state, "Heat pump:heating shut down on high pressure");
1975 0 : heatPump.SimFlag = false;
1976 0 : return;
1977 : }
1978 :
1979 : // calculate coil outlet state variables
1980 1 : LoadSideAirOutletEnth = heatPump.InletAirEnthalpy + QLoadTotal / heatPump.InletAirMassFlowRate;
1981 1 : LoadSideOutletDBTemp = heatPump.InletAirDBTemp + QLoadTotal / (heatPump.InletAirMassFlowRate * CpAir);
1982 1 : LoadSideOutletHumRat = Psychrometrics::PsyWFnTdbH(state, LoadSideOutletDBTemp, LoadSideAirOutletEnth, RoutineNameLoadSideOutletEnthalpy);
1983 1 : SourceSideOutletTemp = heatPump.InletWaterTemp - QSource / (heatPump.InletWaterMassFlowRate * CpWater);
1984 :
1985 : // Calculate actual outlet conditions for the run time fraction
1986 : // Actual outlet conditions are "average" for time step
1987 1 : if (fanOp == HVAC::FanOp::Continuous) {
1988 : // continuous fan, cycling compressor
1989 0 : heatPump.OutletAirEnthalpy = PartLoadRatio * LoadSideAirOutletEnth + (1.0 - PartLoadRatio) * heatPump.InletAirEnthalpy;
1990 0 : heatPump.OutletAirHumRat = PartLoadRatio * LoadSideOutletHumRat + (1.0 - PartLoadRatio) * heatPump.InletAirHumRat;
1991 0 : heatPump.OutletAirDBTemp = Psychrometrics::PsyTdbFnHW(heatPump.OutletAirEnthalpy, heatPump.OutletAirHumRat);
1992 : } else {
1993 : // default to cycling fan, cycling compressor
1994 1 : heatPump.OutletAirEnthalpy = LoadSideAirOutletEnth;
1995 1 : heatPump.OutletAirHumRat = LoadSideOutletHumRat;
1996 1 : heatPump.OutletAirDBTemp = LoadSideOutletDBTemp;
1997 : }
1998 :
1999 : // Calculate Part Load Factor and Runtime Fraction
2000 1 : Real64 PLF = 1.0; // part load factor as a function of PLR, RTF = PLR / PLF
2001 1 : if (heatPump.PLFCurveIndex > 0) {
2002 1 : PLF = Curve::CurveValue(state, heatPump.PLFCurveIndex, PartLoadRatio); // Calculate part-load factor
2003 : }
2004 1 : if (fanOp == HVAC::FanOp::Cycling) {
2005 1 : state.dataHVACGlobal->OnOffFanPartLoadFraction = PLF;
2006 : }
2007 1 : heatPump.RunFrac = PartLoadRatio / PLF;
2008 :
2009 : // scale heat transfer rates and power to run time
2010 1 : QLoadTotal *= PartLoadRatio;
2011 1 : Power *= heatPump.RunFrac;
2012 1 : QSource *= PartLoadRatio;
2013 :
2014 : // Update heat pump data structure
2015 1 : state.dataHVACGlobal->DXElecHeatingPower = Power;
2016 1 : heatPump.Power = Power;
2017 1 : heatPump.QLoadTotal = QLoadTotal;
2018 1 : heatPump.QSensible = QLoadTotal;
2019 :
2020 1 : heatPump.QSource = QSource;
2021 1 : heatPump.PartLoadRatio = PartLoadRatio;
2022 1 : heatPump.OutletAirMassFlowRate = heatPump.InletAirMassFlowRate;
2023 1 : heatPump.OutletWaterTemp = SourceSideOutletTemp;
2024 1 : heatPump.OutletWaterMassFlowRate = heatPump.InletWaterMassFlowRate;
2025 1 : heatPump.OutletWaterEnthalpy = heatPump.InletWaterEnthalpy - QSource / heatPump.InletWaterMassFlowRate;
2026 : }
2027 :
2028 0 : void UpdateWatertoAirHP(EnergyPlusData &state, int const HPNum)
2029 : {
2030 : // SUBROUTINE INFORMATION:
2031 : // AUTHOR Hui Jin
2032 : // DATE WRITTEN Oct 2000
2033 :
2034 : // PURPOSE OF THIS SUBROUTINE:
2035 : // This subroutine updates the Water to Air Heat Pump outlet nodes.
2036 :
2037 : // METHODOLOGY EMPLOYED:
2038 : // Data is moved from the HP data structure to the HP outlet nodes.
2039 :
2040 : // Using/Aliasing
2041 0 : Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
2042 0 : auto &heatPump = state.dataWaterToAirHeatPump->WatertoAirHP(HPNum);
2043 :
2044 : // WatertoAirHP(HPNum)%SimFlag=.FALSE.
2045 0 : if (!heatPump.SimFlag) {
2046 : // Heatpump is off; just pass through conditions
2047 0 : heatPump.Power = 0.0;
2048 0 : heatPump.Energy = 0.0;
2049 0 : heatPump.QLoadTotal = 0.0;
2050 0 : heatPump.QSensible = 0.0;
2051 0 : heatPump.QLatent = 0.0;
2052 0 : heatPump.QSource = 0.0;
2053 0 : heatPump.RunFrac = 0.0;
2054 0 : heatPump.PartLoadRatio = 0.0;
2055 0 : heatPump.OutletAirDBTemp = heatPump.InletAirDBTemp;
2056 0 : heatPump.OutletAirHumRat = heatPump.InletAirHumRat;
2057 0 : heatPump.OutletWaterTemp = heatPump.InletWaterTemp;
2058 0 : heatPump.OutletAirMassFlowRate = heatPump.InletAirMassFlowRate;
2059 0 : heatPump.OutletWaterMassFlowRate = heatPump.InletWaterMassFlowRate;
2060 0 : heatPump.OutletAirEnthalpy = heatPump.InletAirEnthalpy;
2061 0 : heatPump.OutletWaterEnthalpy = heatPump.InletWaterEnthalpy;
2062 : }
2063 :
2064 : // Set the outlet air nodes of the WatertoAirHP
2065 0 : state.dataLoopNodes->Node(heatPump.AirOutletNodeNum).MassFlowRate = state.dataLoopNodes->Node(heatPump.AirInletNodeNum).MassFlowRate;
2066 0 : state.dataLoopNodes->Node(heatPump.AirOutletNodeNum).Temp = heatPump.OutletAirDBTemp;
2067 0 : state.dataLoopNodes->Node(heatPump.AirOutletNodeNum).HumRat = heatPump.OutletAirHumRat;
2068 0 : state.dataLoopNodes->Node(heatPump.AirOutletNodeNum).Enthalpy = heatPump.OutletAirEnthalpy;
2069 :
2070 : // Set the outlet nodes for properties that just pass through & not used
2071 0 : PlantUtilities::SafeCopyPlantNode(state, heatPump.WaterInletNodeNum, heatPump.WaterOutletNodeNum);
2072 : // Set the outlet water nodes for the heat pump
2073 0 : state.dataLoopNodes->Node(heatPump.WaterOutletNodeNum).Temp = heatPump.OutletWaterTemp;
2074 0 : state.dataLoopNodes->Node(heatPump.WaterOutletNodeNum).Enthalpy = heatPump.OutletWaterEnthalpy;
2075 :
2076 : // Set the outlet nodes for properties that just pass through & not used
2077 0 : state.dataLoopNodes->Node(heatPump.AirOutletNodeNum).Quality = state.dataLoopNodes->Node(heatPump.AirInletNodeNum).Quality;
2078 0 : state.dataLoopNodes->Node(heatPump.AirOutletNodeNum).Press = state.dataLoopNodes->Node(heatPump.AirInletNodeNum).Press;
2079 0 : state.dataLoopNodes->Node(heatPump.AirOutletNodeNum).MassFlowRateMin = state.dataLoopNodes->Node(heatPump.AirInletNodeNum).MassFlowRateMin;
2080 0 : state.dataLoopNodes->Node(heatPump.AirOutletNodeNum).MassFlowRateMax = state.dataLoopNodes->Node(heatPump.AirInletNodeNum).MassFlowRateMax;
2081 0 : state.dataLoopNodes->Node(heatPump.AirOutletNodeNum).MassFlowRateMinAvail =
2082 0 : state.dataLoopNodes->Node(heatPump.AirInletNodeNum).MassFlowRateMinAvail;
2083 0 : state.dataLoopNodes->Node(heatPump.AirOutletNodeNum).MassFlowRateMaxAvail =
2084 0 : state.dataLoopNodes->Node(heatPump.AirInletNodeNum).MassFlowRateMaxAvail;
2085 :
2086 : // Pass through the load side mass flow rates
2087 0 : heatPump.InletAirMassFlowRate = state.dataLoopNodes->Node(heatPump.AirInletNodeNum).MassFlowRate;
2088 0 : heatPump.OutletAirMassFlowRate = heatPump.InletAirMassFlowRate;
2089 :
2090 0 : heatPump.Energy = heatPump.Power * TimeStepSysSec;
2091 0 : heatPump.EnergyLoadTotal = heatPump.QLoadTotal * TimeStepSysSec;
2092 0 : heatPump.EnergySensible = heatPump.QSensible * TimeStepSysSec;
2093 0 : heatPump.EnergyLatent = heatPump.QLatent * TimeStepSysSec;
2094 0 : heatPump.EnergySource = heatPump.QSource * TimeStepSysSec;
2095 :
2096 0 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
2097 0 : state.dataLoopNodes->Node(heatPump.AirOutletNodeNum).CO2 = state.dataLoopNodes->Node(heatPump.AirInletNodeNum).CO2;
2098 : }
2099 0 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
2100 0 : state.dataLoopNodes->Node(heatPump.AirOutletNodeNum).GenContam = state.dataLoopNodes->Node(heatPump.AirInletNodeNum).GenContam;
2101 : }
2102 0 : }
2103 :
2104 : // End of Update subroutines for the WatertoAirHP Module
2105 : // *****************************************************************************
2106 :
2107 0 : Real64 CalcEffectiveSHR(EnergyPlusData &state,
2108 : int const HPNum, // Index number for cooling coil
2109 : Real64 const SHRss, // Steady-state sensible heat ratio
2110 : HVAC::FanOp const fanOp, // fan/compressor cycling scheme indicator
2111 : Real64 const RTF, // Compressor run-time fraction
2112 : Real64 const QLatRated, // Rated latent capacity
2113 : Real64 const QLatActual, // Actual latent capacity
2114 : Real64 const EnteringDB, // Entering air dry-bulb temperature
2115 : Real64 const EnteringWB // Entering air wet-bulb temperature
2116 : )
2117 : {
2118 :
2119 : // FUNCTION INFORMATION:
2120 : // AUTHOR Richard Raustad, FSEC
2121 : // DATE WRITTEN September 2003
2122 : // MODIFIED Kenneth Tang (Aug 2004) Added capability for simulating FanOp::Cycling
2123 :
2124 : // PURPOSE OF THIS FUNCTION:
2125 : // Adjust sensible heat ratio to account for degradation of DX coil latent
2126 : // capacity at part-load (cycling) conditions.
2127 :
2128 : // METHODOLOGY EMPLOYED:
2129 : // With model parameters entered by the user, the part-load latent performance
2130 : // of a DX cooling coil is determined for a constant air flow system with
2131 : // a cooling coil that cycles on/off. The model calculates the time
2132 : // required for condensate to begin falling from the cooling coil.
2133 : // Runtimes greater than this are integrated to a "part-load" latent
2134 : // capacity which is used to determine the "part-load" sensible heat ratio.
2135 : // See reference below for additional details (linear decay model, Eq. 8b).
2136 : // REFERENCES:
2137 : // "A Model to Predict the Latent Capacity of Air Conditioners and
2138 : // Heat Pumps at Part-Load Conditions with Constant Fan Operation"
2139 : // 1996 ASHRAE Transactions, Volume 102, Part 1, Pp. 266 - 274,
2140 : // Hugh I. Henderson, Jr., P.E., Kannan Rengarajan, P.E.
2141 :
2142 : // Using/Aliasing
2143 0 : auto const &heatPump = state.dataWaterToAirHeatPump->WatertoAirHP(HPNum);
2144 :
2145 : // Return value
2146 : Real64 SHReff; // Effective sensible heat ratio, includes degradation due to cycling effects
2147 :
2148 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
2149 : Real64 Twet; // Nominal time for condensate to begin leaving the coil's condensate drain line
2150 : // at the current operating conditions (sec)
2151 : Real64 Gamma; // Initial moisture evaporation rate divided by steady-state AC latent capacity
2152 : // at the current operating conditions
2153 : Real64 Twet_max; // Maximum allowed value for Twet
2154 : // shut off after compressor cycle off [s]
2155 :
2156 : Real64 Ton; // Coil on time (sec)
2157 : Real64 Toff; // Coil off time (sec)
2158 : Real64 Toffa; // Actual coil off time (sec). Equations valid for Toff <= (2.0 * Twet/Gamma)
2159 : Real64 aa; // Intermediate variable
2160 : Real64 To1; // Intermediate variable (first guess at To). To = time to the start of moisture removal
2161 : Real64 To2; // Intermediate variable (second guess at To). To = time to the start of moisture removal
2162 : Real64 Error; // Error for iteration (DO) loop
2163 : Real64 LHRmult; // Latent Heat Ratio (LHR) multiplier. The effective latent heat ratio LHR = (1-SHRss)*LHRmult
2164 :
2165 : // No moisture evaporation (latent degradation) occurs for runtime fraction of 1.0
2166 : // All latent degradation model parameters cause divide by 0.0 if not greater than 0.0
2167 : // Latent degradation model parameters initialize to 0.0 meaning no evaporation model used.
2168 0 : if ((RTF >= 1.0) || (QLatRated == 0.0) || (QLatActual == 0.0) || (heatPump.Twet_Rated <= 0.0) || (heatPump.Gamma_Rated <= 0.0) ||
2169 0 : (heatPump.MaxONOFFCyclesperHour <= 0.0) || (heatPump.LatentCapacityTimeConstant <= 0.0) || (RTF <= 0.0)) {
2170 0 : SHReff = SHRss;
2171 0 : return SHReff;
2172 : }
2173 :
2174 0 : Twet_max = 9999.0; // high limit for Twet
2175 :
2176 : // Calculate the model parameters at the actual operating conditions
2177 0 : Twet = min(heatPump.Twet_Rated * QLatRated / (QLatActual + 1.e-10), Twet_max);
2178 0 : Gamma = heatPump.Gamma_Rated * QLatRated * (EnteringDB - EnteringWB) / ((26.7 - 19.4) * QLatActual + 1.e-10);
2179 :
2180 : // Calculate the compressor on and off times using a conventional thermostat curve
2181 0 : Ton = 3600.0 / (4.0 * heatPump.MaxONOFFCyclesperHour * (1.0 - RTF)); // duration of cooling coil on-cycle (sec)
2182 :
2183 0 : if ((fanOp == HVAC::FanOp::Cycling) && (heatPump.FanDelayTime != 0.0)) {
2184 : // For FanOp::Cycling, moisture is evaporated from the cooling coil back to the air stream
2185 : // until the fan cycle off. Assume no evaporation from the coil after the fan shuts off.
2186 0 : Toff = heatPump.FanDelayTime;
2187 : } else {
2188 : // For FanOp::Continuous, moisture is evaporated from the cooling coil back to the air stream
2189 : // for the entire heat pump off-cycle.
2190 0 : Toff = 3600.0 / (4.0 * heatPump.MaxONOFFCyclesperHour * RTF); // duration of cooling coil off-cycle (sec)
2191 : }
2192 :
2193 : // Cap Toff to meet the equation restriction
2194 0 : if (Gamma > 0.0) {
2195 0 : Toffa = min(Toff, 2.0 * Twet / Gamma);
2196 : } else {
2197 0 : Toffa = Toff;
2198 : }
2199 :
2200 : // Use sucessive substitution to solve for To
2201 0 : aa = (Gamma * Toffa) - (0.25 / Twet) * pow_2(Gamma) * pow_2(Toffa);
2202 :
2203 0 : To1 = aa + heatPump.LatentCapacityTimeConstant;
2204 0 : Error = 1.0;
2205 0 : while (Error > 0.001) {
2206 0 : To2 = aa - heatPump.LatentCapacityTimeConstant * std::expm1(-To1 / heatPump.LatentCapacityTimeConstant);
2207 0 : Error = std::abs((To2 - To1) / To1);
2208 0 : To1 = To2;
2209 : }
2210 :
2211 : // Adjust Sensible Heat Ratio (SHR) using Latent Heat Ratio (LHR) multiplier
2212 : // Floating underflow errors occur when -Ton/LatentCapacityTimeConstant is a large negative number.
2213 : // Cap lower limit at -700 to avoid the underflow errors.
2214 0 : aa = std::exp(max(-700.0, -Ton / heatPump.LatentCapacityTimeConstant));
2215 : // Calculate latent heat ratio multiplier
2216 0 : LHRmult = max(((Ton - To2) / (Ton + heatPump.LatentCapacityTimeConstant * (aa - 1.0))), 0.0);
2217 :
2218 : // Calculate part-load or "effective" sensible heat ratio
2219 0 : SHReff = 1.0 - (1.0 - SHRss) * LHRmult;
2220 :
2221 0 : if (SHReff < SHRss) {
2222 0 : SHReff = SHRss; // Effective SHR can be less than the steady-state SHR
2223 : }
2224 0 : if (SHReff > 1.0) {
2225 0 : SHReff = 1.0; // Effective sensible heat ratio can't be greater than 1.0
2226 : }
2227 :
2228 0 : return SHReff;
2229 : }
2230 :
2231 0 : Real64 DegradF(EnergyPlusData &state,
2232 : Fluid::GlycolProps *glycol,
2233 : Real64 &Temp // Temperature of the fluid
2234 : )
2235 : {
2236 : // FUNCTION INFORMATION:
2237 : // AUTHOR Kenneth Tang
2238 : // DATE WRITTEN October 2004
2239 :
2240 : // PURPOSE OF THIS FUNCTION:
2241 : // Calculate the degradation factor to predict the heat pump performance
2242 : // when antifreeze is used.
2243 : // METHODOLOGY EMPLOYED:
2244 : // Use FluidProperties to calculate the properties of water and glycol
2245 : // at the given temperature. Then substitute the properties into the equation.
2246 : // REFERENCES:
2247 : // Jin, H. 2002. Parameter Estimation Based Models of Water Source Heat Pumps. Phd Thesis.
2248 : // Oklahoma State University.
2249 :
2250 : // Return value
2251 : Real64 DegradF;
2252 :
2253 : // FUNCTION PARAMETER DEFINITIONS:
2254 : static constexpr std::string_view CalledFrom("HVACWaterToAir:DegradF");
2255 :
2256 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
2257 : Real64 VisWater; // Viscosity of water [mPa-s]
2258 : Real64 DensityWater; // Density of water [kg/m3]
2259 : Real64 CpWater; // Specific heat of water [J/kg-K]
2260 : Real64 CondWater; // Conductivity of water [W/m-K]
2261 : Real64 VisCoolant; // Viscosity of water [mPa-s]
2262 : Real64 DensityCoolant; // Density of water [kg/m3]
2263 : Real64 CpCoolant; // Specific heat of water [J/kg-K]
2264 : Real64 CondCoolant; // Conductivity of water [W/m-K]
2265 :
2266 0 : auto *water = Fluid::GetWater(state);
2267 :
2268 0 : VisWater = water->getViscosity(state, Temp, CalledFrom);
2269 0 : DensityWater = water->getDensity(state, Temp, CalledFrom);
2270 0 : CpWater = water->getSpecificHeat(state, Temp, CalledFrom);
2271 0 : CondWater = water->getConductivity(state, Temp, CalledFrom);
2272 0 : VisCoolant = glycol->getViscosity(state, Temp, CalledFrom);
2273 0 : DensityCoolant = glycol->getDensity(state, Temp, CalledFrom);
2274 0 : CpCoolant = glycol->getSpecificHeat(state, Temp, CalledFrom);
2275 0 : CondCoolant = glycol->getConductivity(state, Temp, CalledFrom);
2276 :
2277 0 : DegradF = std::pow(VisCoolant / VisWater, -0.47) * std::pow(DensityCoolant / DensityWater, 0.8) * std::pow(CpCoolant / CpWater, 0.33) *
2278 0 : std::pow(CondCoolant / CondWater, 0.67);
2279 :
2280 0 : return DegradF;
2281 : }
2282 :
2283 0 : int GetCoilIndex(EnergyPlusData &state,
2284 : std::string const &CoilType, // must match coil types in this module
2285 : std::string const &CoilName, // must match coil names for the coil type
2286 : bool &ErrorsFound // set to true if problem
2287 : )
2288 : {
2289 :
2290 : // FUNCTION INFORMATION:
2291 : // AUTHOR R. Raustad
2292 : // DATE WRITTEN August 2007
2293 :
2294 : // PURPOSE OF THIS FUNCTION:
2295 : // This function looks up the given coil and returns the index. If
2296 : // incorrect coil type or name is given, ErrorsFound is returned as true and value is returned
2297 : // as zero.
2298 :
2299 : // Obtains and Allocates WatertoAirHP related parameters from input file
2300 0 : if (state.dataWaterToAirHeatPump->GetCoilsInputFlag) { // First time subroutine has been entered
2301 0 : GetWatertoAirHPInput(state);
2302 0 : state.dataWaterToAirHeatPump->GetCoilsInputFlag = false;
2303 : }
2304 :
2305 0 : int IndexNum = Util::FindItemInList(CoilName, state.dataWaterToAirHeatPump->WatertoAirHP);
2306 :
2307 0 : if (IndexNum == 0) {
2308 0 : ShowSevereError(state, format("Could not find CoilType=\"{}\" with Name=\"{}\"", CoilType, CoilName));
2309 0 : ErrorsFound = true;
2310 : }
2311 :
2312 0 : return IndexNum;
2313 : }
2314 :
2315 0 : Real64 GetCoilCapacity(EnergyPlusData &state,
2316 : std::string const &CoilType, // must match coil types in this module
2317 : std::string const &CoilName, // must match coil names for the coil type
2318 : bool &ErrorsFound // set to true if problem
2319 : )
2320 : {
2321 :
2322 : // FUNCTION INFORMATION:
2323 : // AUTHOR Linda Lawrie
2324 : // DATE WRITTEN February 2006
2325 :
2326 : // PURPOSE OF THIS FUNCTION:
2327 : // This function looks up the coil capacity for the given coil and returns it. If
2328 : // incorrect coil type or name is given, ErrorsFound is returned as true and capacity is returned
2329 : // as negative.
2330 :
2331 : // Return value
2332 : Real64 CoilCapacity; // returned capacity of matched coil
2333 :
2334 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
2335 : int WhichCoil;
2336 :
2337 : // Obtains and Allocates WatertoAirHP related parameters from input file
2338 0 : if (state.dataWaterToAirHeatPump->GetCoilsInputFlag) { // First time subroutine has been entered
2339 0 : GetWatertoAirHPInput(state);
2340 0 : state.dataWaterToAirHeatPump->GetCoilsInputFlag = false;
2341 : }
2342 :
2343 0 : if (Util::SameString(CoilType, "COIL:HEATING:WATERTOAIRHEATPUMP:PARAMETERESTIMATION") ||
2344 0 : Util::SameString(CoilType, "COIL:COOLING:WATERTOAIRHEATPUMP:PARAMETERESTIMATION")) {
2345 0 : WhichCoil = Util::FindItemInList(CoilName, state.dataWaterToAirHeatPump->WatertoAirHP);
2346 0 : if (WhichCoil != 0) {
2347 0 : if (Util::SameString(CoilType, "COIL:HEATING:WATERTOAIRHEATPUMP:PARAMETERESTIMATION")) {
2348 0 : CoilCapacity = state.dataWaterToAirHeatPump->WatertoAirHP(WhichCoil).HeatingCapacity;
2349 : } else {
2350 0 : CoilCapacity = state.dataWaterToAirHeatPump->WatertoAirHP(WhichCoil).CoolingCapacity;
2351 : }
2352 : }
2353 : } else {
2354 0 : WhichCoil = 0;
2355 : }
2356 :
2357 0 : if (WhichCoil == 0) {
2358 0 : ShowSevereError(state, format("Could not find CoilType=\"{}\" with Name=\"{}\"", CoilType, CoilName));
2359 0 : ErrorsFound = true;
2360 0 : CoilCapacity = -1000.0;
2361 : }
2362 :
2363 0 : return CoilCapacity;
2364 : }
2365 :
2366 0 : int GetCoilInletNode(EnergyPlusData &state,
2367 : std::string const &CoilType, // must match coil types in this module
2368 : std::string const &CoilName, // must match coil names for the coil type
2369 : bool &ErrorsFound // set to true if problem
2370 : )
2371 : {
2372 :
2373 : // FUNCTION INFORMATION:
2374 : // AUTHOR Linda Lawrie
2375 : // DATE WRITTEN February 2006
2376 :
2377 : // PURPOSE OF THIS FUNCTION:
2378 : // This function looks up the given coil and returns the inlet node. If
2379 : // incorrect coil type or name is given, ErrorsFound is returned as true and value is returned
2380 : // as zero.
2381 :
2382 : // Return value
2383 : int NodeNumber; // returned outlet node of matched coil
2384 :
2385 : // Obtains and Allocates WatertoAirHP related parameters from input file
2386 0 : if (state.dataWaterToAirHeatPump->GetCoilsInputFlag) { // First time subroutine has been entered
2387 0 : GetWatertoAirHPInput(state);
2388 0 : state.dataWaterToAirHeatPump->GetCoilsInputFlag = false;
2389 : }
2390 :
2391 0 : int WhichCoil = Util::FindItemInList(CoilName, state.dataWaterToAirHeatPump->WatertoAirHP);
2392 0 : if (WhichCoil != 0) {
2393 0 : NodeNumber = state.dataWaterToAirHeatPump->WatertoAirHP(WhichCoil).AirInletNodeNum;
2394 : }
2395 :
2396 0 : if (WhichCoil == 0) {
2397 0 : ShowSevereError(state, format("Could not find CoilType=\"{}\" with Name=\"{}\"", CoilType, CoilName));
2398 0 : ErrorsFound = true;
2399 0 : NodeNumber = 0;
2400 : }
2401 :
2402 0 : return NodeNumber;
2403 : }
2404 :
2405 0 : int GetCoilOutletNode(EnergyPlusData &state,
2406 : std::string const &CoilType, // must match coil types in this module
2407 : std::string const &CoilName, // must match coil names for the coil type
2408 : bool &ErrorsFound // set to true if problem
2409 : )
2410 : {
2411 :
2412 : // FUNCTION INFORMATION:
2413 : // AUTHOR R. Raustad
2414 : // DATE WRITTEN July 2007
2415 :
2416 : // PURPOSE OF THIS FUNCTION:
2417 : // This function looks up the given coil and returns the outlet node. If
2418 : // incorrect coil type or name is given, ErrorsFound is returned as true and value is returned
2419 : // as zero.
2420 :
2421 : // Return value
2422 : int NodeNumber; // returned outlet node of matched coil
2423 :
2424 : // Obtains and Allocates WatertoAirHP related parameters from input file
2425 0 : if (state.dataWaterToAirHeatPump->GetCoilsInputFlag) { // First time subroutine has been entered
2426 0 : GetWatertoAirHPInput(state);
2427 0 : state.dataWaterToAirHeatPump->GetCoilsInputFlag = false;
2428 : }
2429 :
2430 0 : int WhichCoil = Util::FindItemInList(CoilName, state.dataWaterToAirHeatPump->WatertoAirHP);
2431 0 : if (WhichCoil != 0) {
2432 0 : NodeNumber = state.dataWaterToAirHeatPump->WatertoAirHP(WhichCoil).AirOutletNodeNum;
2433 : }
2434 :
2435 0 : if (WhichCoil == 0) {
2436 0 : ShowSevereError(state, format("Could not find CoilType=\"{}\" with Name=\"{}\"", CoilType, CoilName));
2437 0 : ErrorsFound = true;
2438 0 : NodeNumber = 0;
2439 : }
2440 :
2441 0 : return NodeNumber;
2442 : }
2443 :
2444 : } // namespace WaterToAirHeatPump
2445 :
2446 : } // namespace EnergyPlus
|