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 1 : if (state.dataWaterToAirHeatPump->initialQSource_calc == 0.0) state.dataWaterToAirHeatPump->initialQSource_calc = heatPump.CoolingCapacity;
1287 :
1288 : // Loop the calculation at least twice depending whether the latent degradation model
1289 : // is enabled. 1st iteration to calculate the QLatent(rated) at (TDB,TWB)indoorair=(26.7C,19.4C)
1290 : // and 2nd iteration to calculate the QLatent(actual)
1291 :
1292 : // Calculate Part Load Factor and Runtime Fraction
1293 1 : Real64 PLF = 1.0; // part load factor as a function of PLR, RTF = PLR / PLF
1294 1 : if (heatPump.PLFCurveIndex > 0) {
1295 1 : PLF = Curve::CurveValue(state, heatPump.PLFCurveIndex, PartLoadRatio); // Calculate part-load factor
1296 : }
1297 1 : if (fanOp == HVAC::FanOp::Cycling) {
1298 1 : state.dataHVACGlobal->OnOffFanPartLoadFraction = PLF;
1299 : }
1300 1 : heatPump.RunFrac = PartLoadRatio / PLF;
1301 :
1302 1 : QLatRated = 0.0;
1303 1 : QLatActual = 0.0;
1304 : // IF((RuntimeFrac .GE. 1.0) .OR. (Twet_rated .LE. 0.0) .OR. (Gamma_rated .LE. 0.0)) THEN
1305 : // Cycling fan does not required latent degradation model, only the constant fan case
1306 1 : if ((heatPump.RunFrac >= 1.0) || (heatPump.Twet_Rated <= 0.0) || (heatPump.Gamma_Rated <= 0.0) || (fanOp == HVAC::FanOp::Cycling)) {
1307 1 : LatDegradModelSimFlag = false;
1308 : // Set NumIteration4=1 so that latent model would quit after 1 simulation with the actual condition
1309 1 : NumIteration4 = 1;
1310 : } else {
1311 0 : LatDegradModelSimFlag = true;
1312 : // Set NumIteration4=0 so that latent model would simulate twice with rated and actual condition
1313 0 : NumIteration4 = 0;
1314 : }
1315 :
1316 : // Tuned Hoisted quantities out of nested loop that don't change
1317 1 : Real64 const LoadSideMassFlowRate_CpAir_inv(1.0 / (heatPump.InletAirMassFlowRate * CpAir));
1318 : Real64 const LoadSideEffec(1.0 -
1319 1 : std::exp(-heatPump.LoadSideOutsideUACoeff *
1320 1 : LoadSideMassFlowRate_CpAir_inv)); // Load Side Effectiveness based on Outside Heat Transfer Coefficient
1321 1 : Real64 const LoadSideEffec_MassFlowRate_inv(1.0 / (LoadSideEffec * heatPump.InletAirMassFlowRate));
1322 1 : ANTUWET = heatPump.LoadSideTotalUACoeff * LoadSideMassFlowRate_CpAir_inv;
1323 1 : EffectWET = 1.0 - std::exp(-ANTUWET);
1324 :
1325 : while (true) {
1326 1 : ++NumIteration4;
1327 1 : if (NumIteration4 == 1) {
1328 : // Set indoor air conditions to the rated condition
1329 0 : LoadSideInletDBTemp = state.dataWaterToAirHeatPump->LoadSideInletDBTemp_Init;
1330 0 : LoadSideInletHumRat = state.dataWaterToAirHeatPump->LoadSideInletHumRat_Init;
1331 0 : LoadSideAirInletEnth = state.dataWaterToAirHeatPump->LoadSideAirInletEnth_Init;
1332 : } else {
1333 : // Set indoor air conditions to the actual condition
1334 1 : LoadSideInletDBTemp = heatPump.InletAirDBTemp;
1335 1 : LoadSideInletHumRat = heatPump.InletAirHumRat;
1336 1 : LoadSideAirInletEnth = LoadSideAirInletEnth_Unit;
1337 : }
1338 :
1339 : // Outerloop: Calculate source side heat transfer
1340 1 : int NumIteration2 = 0;
1341 1 : Converged = false;
1342 1 : StillSimulatingFlag = true;
1343 1 : SourceResidual = 1.0;
1344 17 : while (StillSimulatingFlag) {
1345 16 : if (Converged) StillSimulatingFlag = false;
1346 :
1347 16 : ++NumIteration2;
1348 16 : if (NumIteration2 == 1) RelaxParam = 0.5;
1349 :
1350 16 : if (NumIteration2 > STOP2) {
1351 0 : heatPump.SimFlag = false;
1352 0 : return;
1353 : }
1354 :
1355 : // Innerloop: Calculate load side heat transfer
1356 16 : NumIteration3 = 0;
1357 16 : LoadResidual = 1.0;
1358 59 : while (LoadResidual > ERR) {
1359 :
1360 43 : ++NumIteration3;
1361 :
1362 43 : if (NumIteration3 > STOP3) {
1363 0 : heatPump.SimFlag = false;
1364 0 : return;
1365 : }
1366 :
1367 : // Determine Effectiveness of Source Side
1368 43 : CpFluid = state.dataPlnt->PlantLoop(heatPump.plantLoc.loopNum)
1369 43 : .glycol->getSpecificHeat(state, heatPump.InletWaterTemp, RoutineNameSourceSideInletTemp);
1370 :
1371 43 : if (state.dataPlnt->PlantLoop(heatPump.plantLoc.loopNum).glycol->Num == Fluid::GlycolNum_Water) {
1372 43 : SourceSideEffect = 1.0 - std::exp(-heatPump.SourceSideUACoeff / (CpFluid * heatPump.InletWaterMassFlowRate));
1373 : } else {
1374 0 : DegradFactor = DegradF(state, state.dataPlnt->PlantLoop(heatPump.plantLoc.loopNum).glycol, heatPump.InletWaterTemp);
1375 0 : SourceSideEffect =
1376 0 : 1.0 / ((heatPump.SourceSideHTR1 * std::pow(SourceSideVolFlowRate, -0.8)) / DegradFactor + heatPump.SourceSideHTR2);
1377 : }
1378 :
1379 : // Determine Source Side Tempertaure (Condensing Temp in this case)
1380 43 : SourceSideTemp = heatPump.InletWaterTemp + state.dataWaterToAirHeatPump->initialQSource_calc /
1381 43 : (SourceSideEffect * CpFluid * heatPump.InletWaterMassFlowRate);
1382 :
1383 : // Compute the Effective Surface Temperature
1384 43 : EffectiveSatEnth = LoadSideAirInletEnth - state.dataWaterToAirHeatPump->initialQLoadTotal_calc * LoadSideEffec_MassFlowRate_inv;
1385 :
1386 43 : EffectiveSurfaceTemp = Psychrometrics::PsyTsatFnHPb(state, EffectiveSatEnth, PB, RoutineNameLoadSideSurfaceTemp);
1387 :
1388 43 : QSensible = heatPump.InletAirMassFlowRate * CpAir * (LoadSideInletDBTemp - EffectiveSurfaceTemp) * LoadSideEffec;
1389 43 : EvapSatEnth =
1390 43 : LoadSideAirInletEnth - state.dataWaterToAirHeatPump->initialQLoadTotal_calc / (EffectWET * heatPump.InletAirMassFlowRate);
1391 :
1392 43 : EvapTemp = Psychrometrics::PsyTsatFnHPb(state, EvapSatEnth, PB, RoutineNameLoadSideEvapTemp);
1393 :
1394 : // Load Side Saturated Temperature (Evaporating Temp in this case)
1395 43 : LoadSideTemp = EvapTemp;
1396 :
1397 : // Determine the Load Side and Source Side Saturated Temp (evaporating and condensing pressures)
1398 43 : SourceSidePressure = heatPump.refrig->getSatPressure(state, SourceSideTemp, RoutineNameSourceSideTemp);
1399 43 : LoadSidePressure = heatPump.refrig->getSatPressure(state, LoadSideTemp, RoutineNameLoadSideTemp);
1400 :
1401 43 : if (LoadSidePressure < heatPump.LowPressCutoff && !FirstHVACIteration) {
1402 0 : if (!state.dataGlobal->WarmupFlag) {
1403 0 : ShowRecurringWarningErrorAtEnd(
1404 : state,
1405 0 : format("WaterToAir Heat pump:cooling [{}] shut off on low pressure < {:.0R}", heatPump.Name, heatPump.LowPressCutoff),
1406 0 : heatPump.LowPressClgError,
1407 : LoadSidePressure,
1408 : LoadSidePressure,
1409 : _,
1410 : "[Pa]",
1411 : "[Pa]");
1412 : }
1413 0 : heatPump.SimFlag = false;
1414 0 : return;
1415 : }
1416 :
1417 43 : if (SourceSidePressure > heatPump.HighPressCutoff && !FirstHVACIteration) {
1418 0 : if (!state.dataGlobal->WarmupFlag) {
1419 0 : ShowRecurringWarningErrorAtEnd(state,
1420 0 : format("WaterToAir Heat pump:cooling [{}] shut off on high pressure > {:.0R}",
1421 0 : heatPump.Name,
1422 0 : heatPump.HighPressCutoff),
1423 0 : heatPump.HighPressClgError,
1424 0 : heatPump.InletWaterTemp,
1425 0 : heatPump.InletWaterTemp,
1426 : _,
1427 : "SourceSideInletTemp[C]",
1428 : "SourceSideInletTemp[C]");
1429 : }
1430 0 : heatPump.SimFlag = false;
1431 0 : return;
1432 : }
1433 :
1434 : // Determine Suction Pressure & Discharge Pressure at Compressor Exit
1435 43 : if (heatPump.compressorType == CompressorType::Reciprocating) { // RECIPROCATING
1436 0 : SuctionPr = LoadSidePressure - heatPump.CompSucPressDrop;
1437 0 : DischargePr = SourceSidePressure + heatPump.CompSucPressDrop;
1438 43 : } else if (heatPump.compressorType == CompressorType::Rotary) { // ROTARY
1439 0 : SuctionPr = LoadSidePressure;
1440 0 : DischargePr = SourceSidePressure + heatPump.CompSucPressDrop;
1441 43 : } else if (heatPump.compressorType == CompressorType::Scroll) { // SCROLL
1442 43 : SuctionPr = LoadSidePressure;
1443 43 : DischargePr = SourceSidePressure;
1444 : }
1445 :
1446 : // Determine the Load Side Outlet Enthalpy (Saturated Gas)
1447 43 : Quality = 1.0;
1448 43 : LoadSideOutletEnth = heatPump.refrig->getSatEnthalpy(state, LoadSideTemp, Quality, RoutineNameLoadSideTemp);
1449 :
1450 : // Determine Source Side Outlet Enthalpy (Saturated Liquid)
1451 43 : Quality = 0.0;
1452 43 : SourceSideOutletEnth = heatPump.refrig->getSatEnthalpy(state, SourceSideTemp, Quality, RoutineNameSourceSideTemp);
1453 : // Determine Superheated Temperature of the Load Side outlet/compressor Inlet
1454 43 : CompressInletTemp = LoadSideTemp + heatPump.SuperheatTemp;
1455 :
1456 : // Determine the Enthalpy of the Superheated Fluid at Load Side Outlet/Compressor Inlet
1457 43 : SuperHeatEnth = heatPump.refrig->getSupHeatEnthalpy(state, CompressInletTemp, LoadSidePressure, RoutineNameCompressInletTemp);
1458 :
1459 : // Determining the suction state of the fluid from inlet state involves interation
1460 : // Method employed...
1461 : // Determine the saturated temp at suction pressure, shoot out into the superheated region find the enthalpy
1462 : // check that with the inlet enthalpy ( as suction loss is isenthalpic). Iterate till desired accuracy is reached
1463 43 : if (!Converged) {
1464 42 : CompSuctionSatTemp = heatPump.refrig->getSatTemperature(state, SuctionPr, RoutineNameSuctionPr);
1465 42 : CompSuctionTemp1 = CompSuctionSatTemp;
1466 :
1467 : // Shoot into the Superheated Region
1468 42 : CompSuctionTemp2 = CompSuctionSatTemp + DegreeofSuperheat;
1469 : }
1470 :
1471 129 : auto f = [&state, &heatPump, SuctionPr, SuperHeatEnth](Real64 const CompSuctionTemp) {
1472 : static constexpr std::string_view RoutineName("CalcWaterToAirHPHeating:CalcCompSuctionTemp");
1473 129 : Real64 compSuctionEnth = heatPump.refrig->getSupHeatEnthalpy(state, CompSuctionTemp, SuctionPr, RoutineName);
1474 129 : return (compSuctionEnth - SuperHeatEnth) / SuperHeatEnth;
1475 43 : };
1476 :
1477 86 : General::SolveRoot(
1478 43 : state, ERR, STOP1, SolFlag, state.dataWaterToAirHeatPump->CompSuctionTemp, f, CompSuctionTemp1, CompSuctionTemp2);
1479 43 : if (SolFlag == -1) {
1480 0 : heatPump.SimFlag = false;
1481 0 : return;
1482 : }
1483 43 : CompSuctionEnth = heatPump.refrig->getSupHeatEnthalpy(
1484 43 : state, state.dataWaterToAirHeatPump->CompSuctionTemp, SuctionPr, RoutineNameCompSuctionTemp);
1485 43 : CompSuctionDensity = heatPump.refrig->getSupHeatDensity(
1486 43 : state, state.dataWaterToAirHeatPump->CompSuctionTemp, SuctionPr, RoutineNameCompSuctionTemp);
1487 :
1488 : // Find Refrigerant Flow Rate
1489 43 : switch (heatPump.compressorType) {
1490 0 : case CompressorType::Reciprocating: {
1491 0 : MassRef =
1492 0 : heatPump.CompPistonDisp * CompSuctionDensity *
1493 0 : (1.0 + heatPump.CompClearanceFactor - heatPump.CompClearanceFactor * std::pow(DischargePr / SuctionPr, 1.0 / gamma));
1494 0 : break;
1495 : }
1496 0 : case CompressorType::Rotary: {
1497 0 : MassRef = heatPump.CompPistonDisp * CompSuctionDensity;
1498 0 : break;
1499 : }
1500 43 : case CompressorType::Scroll: {
1501 43 : MassRef = heatPump.RefVolFlowRate * CompSuctionDensity - heatPump.LeakRateCoeff * (DischargePr / SuctionPr);
1502 43 : break;
1503 : }
1504 0 : default:
1505 0 : break;
1506 : }
1507 43 : MassRef = max(0.0, MassRef);
1508 :
1509 : // Find the Load Side Heat Transfer
1510 43 : QLoadTotal = MassRef * (LoadSideOutletEnth - SourceSideOutletEnth);
1511 43 : LoadResidual = std::abs(QLoadTotal - state.dataWaterToAirHeatPump->initialQLoadTotal_calc) /
1512 43 : state.dataWaterToAirHeatPump->initialQLoadTotal_calc;
1513 86 : state.dataWaterToAirHeatPump->initialQLoadTotal_calc +=
1514 43 : RelaxParam * (QLoadTotal - state.dataWaterToAirHeatPump->initialQLoadTotal_calc);
1515 43 : if (NumIteration3 > 8) RelaxParam = 0.3;
1516 : }
1517 :
1518 : // Determine the Power Consumption
1519 16 : switch (heatPump.compressorType) {
1520 0 : case CompressorType::Reciprocating:
1521 : case CompressorType::Rotary: {
1522 0 : Power = heatPump.PowerLosses + (1.0 / heatPump.LossFactor) * (MassRef * gamma / (gamma - 1.0) * SuctionPr / CompSuctionDensity *
1523 0 : (std::pow(DischargePr / SuctionPr, (gamma - 1.0) / gamma) - 1.0));
1524 0 : break;
1525 : }
1526 16 : case CompressorType::Scroll: {
1527 16 : Power = heatPump.PowerLosses + (1.0 / heatPump.LossFactor) * (gamma / (gamma - 1.0)) * SuctionPr * heatPump.RefVolFlowRate *
1528 16 : (((gamma - 1.0) / gamma) * ((DischargePr / SuctionPr) / heatPump.VolumeRatio) +
1529 16 : ((1.0 / gamma) * std::pow(heatPump.VolumeRatio, gamma - 1.0)) - 1.0);
1530 16 : break;
1531 : }
1532 0 : default:
1533 0 : break;
1534 : }
1535 :
1536 : // Determine the Sourceside Heat Rate
1537 16 : QSource = Power + QLoadTotal;
1538 16 : SourceResidual =
1539 16 : std::abs(QSource - state.dataWaterToAirHeatPump->initialQSource_calc) / state.dataWaterToAirHeatPump->initialQSource_calc;
1540 16 : if (SourceResidual < ERR) Converged = true;
1541 16 : state.dataWaterToAirHeatPump->initialQSource_calc += RelaxParam * (QSource - state.dataWaterToAirHeatPump->initialQSource_calc);
1542 16 : if (NumIteration2 > 8) RelaxParam = 0.2;
1543 : }
1544 :
1545 1 : if (SuctionPr < heatPump.LowPressCutoff) {
1546 0 : ShowWarningError(state, "Heat pump:cooling shut down on low pressure");
1547 0 : heatPump.SimFlag = false;
1548 : }
1549 :
1550 1 : if (DischargePr > heatPump.HighPressCutoff && !FirstHVACIteration) {
1551 0 : ShowWarningError(state, "Heat pump:cooling shut down on high pressure");
1552 0 : heatPump.SimFlag = false;
1553 : }
1554 :
1555 1 : if (QSensible > QLoadTotal) {
1556 1 : QSensible = QLoadTotal;
1557 : }
1558 :
1559 1 : if (LatDegradModelSimFlag) {
1560 0 : if (NumIteration4 == 1) {
1561 0 : QLatRated = QLoadTotal - QSensible;
1562 :
1563 0 : } else if (NumIteration4 == 2) {
1564 0 : QLatActual = QLoadTotal - QSensible;
1565 0 : SHRss = QSensible / QLoadTotal;
1566 0 : LoadSideInletWBTemp = Psychrometrics::PsyTwbFnTdbWPb(state, LoadSideInletDBTemp, LoadSideInletHumRat, PB);
1567 0 : SHReff = CalcEffectiveSHR(
1568 : state, HPNum, SHRss, fanOp, heatPump.RunFrac, QLatRated, QLatActual, LoadSideInletDBTemp, LoadSideInletWBTemp);
1569 : // Update sensible capacity based on effective SHR
1570 0 : QSensible = QLoadTotal * SHReff;
1571 0 : goto LOOPLatentDegradationModel_exit;
1572 : }
1573 : } else {
1574 :
1575 1 : SHReff = QSensible / QLoadTotal;
1576 1 : goto LOOPLatentDegradationModel_exit;
1577 : }
1578 0 : }
1579 1 : LOOPLatentDegradationModel_exit:;
1580 :
1581 : // calculate coil outlet state variables
1582 1 : LoadSideAirOutletEnth = LoadSideAirInletEnth - QLoadTotal / heatPump.InletAirMassFlowRate;
1583 1 : LoadSideOutletDBTemp = LoadSideInletDBTemp - QSensible * LoadSideMassFlowRate_CpAir_inv;
1584 1 : LoadSideOutletHumRat = Psychrometrics::PsyWFnTdbH(state, LoadSideOutletDBTemp, LoadSideAirOutletEnth, RoutineNameLoadSideOutletEnthalpy);
1585 1 : SourceSideOutletTemp = heatPump.InletWaterTemp + QSource / (heatPump.InletWaterMassFlowRate * CpWater);
1586 :
1587 : // Actual outlet conditions are "average" for time step
1588 1 : if (fanOp == HVAC::FanOp::Continuous) {
1589 : // continuous fan, cycling compressor
1590 0 : heatPump.OutletAirEnthalpy = PartLoadRatio * LoadSideAirOutletEnth + (1.0 - PartLoadRatio) * LoadSideAirInletEnth;
1591 0 : heatPump.OutletAirHumRat = PartLoadRatio * LoadSideOutletHumRat + (1.0 - PartLoadRatio) * LoadSideInletHumRat;
1592 0 : heatPump.OutletAirDBTemp = Psychrometrics::PsyTdbFnHW(heatPump.OutletAirEnthalpy, heatPump.OutletAirHumRat);
1593 : } else {
1594 : // default to cycling fan, cycling compressor
1595 1 : heatPump.OutletAirEnthalpy = LoadSideAirOutletEnth;
1596 1 : heatPump.OutletAirHumRat = LoadSideOutletHumRat;
1597 1 : heatPump.OutletAirDBTemp = LoadSideOutletDBTemp;
1598 : }
1599 :
1600 : // scale heat transfer rates and power to run time
1601 1 : QLoadTotal *= PartLoadRatio;
1602 1 : QSensible *= PartLoadRatio;
1603 1 : Power *= heatPump.RunFrac;
1604 1 : QSource *= PartLoadRatio;
1605 :
1606 : // Update heat pump data structure
1607 1 : state.dataHVACGlobal->DXElecCoolingPower = Power;
1608 1 : heatPump.Power = Power;
1609 1 : heatPump.QLoadTotal = QLoadTotal;
1610 1 : heatPump.QSensible = QSensible;
1611 1 : heatPump.QLatent = QLoadTotal - QSensible;
1612 1 : heatPump.QSource = QSource;
1613 1 : heatPump.PartLoadRatio = PartLoadRatio;
1614 :
1615 : // Air-side outlet conditions are already calculated above
1616 1 : heatPump.OutletAirMassFlowRate = heatPump.InletAirMassFlowRate;
1617 1 : heatPump.OutletWaterTemp = SourceSideOutletTemp;
1618 1 : heatPump.OutletWaterMassFlowRate = heatPump.InletWaterMassFlowRate;
1619 1 : heatPump.OutletWaterEnthalpy = heatPump.InletWaterEnthalpy + QSource / heatPump.InletWaterMassFlowRate;
1620 : }
1621 :
1622 1 : void CalcWatertoAirHPHeating(EnergyPlusData &state,
1623 : int const HPNum, // heat pump number
1624 : HVAC::FanOp const fanOp, // fan/compressor cycling scheme indicator
1625 : bool const FirstHVACIteration, // first iteration flag
1626 : [[maybe_unused]] bool const InitFlag, // first iteration flag
1627 : Real64 const SensDemand,
1628 : HVAC::CompressorOp const compressorOp,
1629 : Real64 const PartLoadRatio)
1630 : {
1631 :
1632 : // SUBROUTINE INFORMATION:
1633 : // AUTHOR Hui Jin
1634 : // DATE WRITTEN Oct 2000
1635 : // MODIFIED R. Raustad (Oct 2006) Revised iteration technique
1636 :
1637 : // PURPOSE OF THIS SUBROUTINE:
1638 : // Simulates a parameter estimation based water to air heat pump model
1639 :
1640 : // Using/Aliasing
1641 1 : auto &heatPump = state.dataWaterToAirHeatPump->WatertoAirHP(HPNum);
1642 :
1643 : // SUBROUTINE PARAMETER DEFINITIONS:
1644 1 : Real64 constexpr CpWater(4210.0); // Specific heat of water J/kg_C
1645 1 : Real64 constexpr DegreeofSuperheat(80.0); // Initial guess of degree of superheat
1646 1 : Real64 constexpr gamma(1.114); // Expnasion Coefficient
1647 1 : Real64 RelaxParam(0.5); // Relaxation Parameter
1648 1 : Real64 constexpr ERR(0.01); // Error Value
1649 1 : int constexpr STOP1(1000); // Iteration stopper1
1650 1 : int constexpr STOP2(1000); // Iteration stopper2
1651 1 : int constexpr STOP3(1000); // Iteration stopper3
1652 :
1653 : static constexpr std::string_view RoutineNameSourceSideInletTemp("CalcWatertoAirHPHeating:SourceSideInletTemp");
1654 : static constexpr std::string_view RoutineNameSourceSideTemp("CalcWatertoAirHPHeating:SourceSideTemp");
1655 : static constexpr std::string_view RoutineNameLoadSideTemp("CalcWatertoAirHPHeating:LoadSideTemp");
1656 : static constexpr std::string_view RoutineNameLoadSideOutletEnthalpy("CalcWatertoAirHPHeating:LoadSideOutletEnthalpy");
1657 : static constexpr std::string_view RoutineNameCompressInletTemp("CalcWatertoAirHPHeating:CompressInletTemp");
1658 : static constexpr std::string_view RoutineNameSuctionPr("CalcWatertoAirHPHeating:SuctionPr");
1659 : static constexpr std::string_view RoutineNameCompSuctionTemp("CalcWatertoAirHPHeating:CompSuctionTemp");
1660 :
1661 : int NumIteration3; // Number of Iteration3
1662 : Real64 Quality;
1663 : Real64 SourceSideOutletTemp; // Source Side Outlet Temperature [C]
1664 : Real64 SourceSideVolFlowRate; // Source Side Volumetric Flow Rate [m3/s]
1665 : Real64 CpFluid; // Specific heat of source side fluid(J/kg)
1666 : Real64 LoadSideOutletDBTemp; // Load Side Outlet Dry Bulb Temperature [C]
1667 : Real64 LoadSideOutletHumRat; // Load Side Outlet Humidity Ratio [kg/kg]
1668 : Real64 LoadSideAirOutletEnth; // Load Side Outlet Enthalpy [J/kg]
1669 : Real64 CpAir; // Specific Heat of Air [J/kg_C]
1670 : Real64 DegradFactor; // Degradation Factor [~]
1671 : Real64 QSource; // Source Side Heat Transfer Rate [W]
1672 : Real64 QLoadTotal; // Load Side Heat Transfer Rate [W]
1673 : Real64 Power; // Power Consumption [W]
1674 :
1675 : Real64 SourceSideEffect; // Source Side Heat Exchanger Effectiveness
1676 : Real64 SourceSideTemp; // Source Side Saturated Refrigerant Temperature [C]
1677 : Real64 LoadSideTemp; // Load Side Saturated Refrigerant Temperature [C]
1678 : Real64 SourceSidePressure; // Source Side Saturated Refrigerant Pressure [Pa]
1679 : Real64 LoadSidePressure; // Load Side Saturated Refrigerant Pressure [Pa]
1680 : Real64 SuctionPr; // Compressor Suction Pressure [Pa]
1681 : Real64 DischargePr; // Compressor Discharge Pressure [Pa]
1682 : Real64 CompressInletTemp; // Temperature of the Refrigerant Entering the Compressor [C]
1683 : Real64 MassRef; // Mass Flow Rate of Refrigerant [kg/s]
1684 : Real64 SourceSideOutletEnth; // Enthalpy of Refrigerant leaving the Source Side Heat Exchanger [J/kg]
1685 : Real64 LoadSideOutletEnth; // Enthalpy of Refrigerant leaving the Load Side Heat Exchanger [J/kg]
1686 : Real64 SuperHeatEnth; // Enthalpy of the Superheated Refrigerant [J/kg]
1687 : Real64 CompSuctionTemp1; // Guess of the Temperature of the Refrigerant Entering the
1688 : // Compressor #1 [C]
1689 : Real64 CompSuctionTemp2; // Guess of the Temperature of the Refrigerant Entering the
1690 : // Compressor #2 [C]
1691 : Real64 CompSuctionTemp; // Temperature of the Refrigerant Entering the Compressor [C]
1692 : Real64 CompSuctionEnth; // Enthalpy of the Refrigerant Entering the Compressor [J/kg]
1693 : Real64 CompSuctionDensity; // Density of the Refrigerant Entering the Compressorkg/m3
1694 : Real64 CompSuctionSatTemp; // Temperature of Saturated Refrigerant at Compressor Suction Pressure [C]
1695 : bool StillSimulatingFlag; // Final Simulation Flag
1696 : bool Converged; // Overall convergence Flag
1697 : int SolFlag; // Solution flag returned from RegulaFalsi function
1698 : Real64 LoadResidual; // loop convergence criteria
1699 : Real64 SourceResidual; // loop convergence criteria
1700 :
1701 : // LOAD LOCAL VARIABLES FROM DATA STRUCTURE (for code readability)
1702 :
1703 1 : CpAir = Psychrometrics::PsyCpAirFnW(heatPump.InletAirHumRat);
1704 1 : SourceSideVolFlowRate =
1705 1 : heatPump.InletWaterMassFlowRate /
1706 1 : state.dataPlnt->PlantLoop(heatPump.plantLoc.loopNum).glycol->getDensity(state, heatPump.InletWaterTemp, RoutineNameSourceSideInletTemp);
1707 :
1708 : // If heat pump is not operating, return
1709 1 : if (SensDemand == 0.0 || heatPump.InletAirMassFlowRate <= 0.0 || heatPump.InletWaterMassFlowRate <= 0.0) {
1710 0 : heatPump.SimFlag = false;
1711 0 : return;
1712 : } else {
1713 1 : heatPump.SimFlag = true;
1714 : }
1715 :
1716 1 : if (compressorOp == HVAC::CompressorOp::Off) {
1717 0 : heatPump.SimFlag = false;
1718 0 : return;
1719 : }
1720 :
1721 1 : if (FirstHVACIteration) {
1722 1 : state.dataWaterToAirHeatPump->initialQLoad = heatPump.HeatingCapacity;
1723 1 : state.dataWaterToAirHeatPump->initialQSource = heatPump.HeatingCapacity;
1724 : }
1725 :
1726 1 : if (state.dataWaterToAirHeatPump->initialQLoad == 0.0) state.dataWaterToAirHeatPump->initialQLoad = heatPump.HeatingCapacity;
1727 1 : if (state.dataWaterToAirHeatPump->initialQSource == 0.0) state.dataWaterToAirHeatPump->initialQSource = heatPump.HeatingCapacity;
1728 :
1729 : // Tuned Hoisted quantities out of nested loop that don't change
1730 1 : Real64 const LoadSideMassFlowRate_CpAir_inv(1.0 / (heatPump.InletAirMassFlowRate * CpAir));
1731 : Real64 const LoadSideEffect(1.0 -
1732 1 : std::exp(-heatPump.LoadSideTotalUACoeff *
1733 1 : LoadSideMassFlowRate_CpAir_inv)); // Load Side Effectiveness based on Outside Heat Transfer Coefficient
1734 1 : Real64 const LoadSideEffect_CpAir_MassFlowRate_inv(1.0 / (LoadSideEffect * CpAir * heatPump.InletAirMassFlowRate));
1735 :
1736 : // Outerloop: calculate load side heat transfer
1737 1 : NumIteration3 = 0;
1738 1 : Converged = false;
1739 1 : StillSimulatingFlag = true;
1740 1 : LoadResidual = 1.0;
1741 18 : while (StillSimulatingFlag) {
1742 17 : if (Converged) StillSimulatingFlag = false;
1743 :
1744 17 : ++NumIteration3;
1745 17 : if (NumIteration3 == 1) RelaxParam = 0.5;
1746 :
1747 17 : if (NumIteration3 > STOP3) {
1748 0 : heatPump.SimFlag = false;
1749 0 : return;
1750 : }
1751 :
1752 : // Innerloop: calculate load side heat transfer
1753 17 : int NumIteration2 = 0;
1754 17 : SourceResidual = 1.0;
1755 64 : while (SourceResidual > ERR) {
1756 :
1757 47 : ++NumIteration2;
1758 :
1759 47 : if (NumIteration2 > STOP2) {
1760 0 : heatPump.SimFlag = false;
1761 0 : return;
1762 : }
1763 :
1764 : // Determine Effectiveness of Source Side
1765 47 : CpFluid = state.dataPlnt->PlantLoop(heatPump.plantLoc.loopNum)
1766 47 : .glycol->getSpecificHeat(state, heatPump.InletWaterTemp, RoutineNameSourceSideInletTemp);
1767 :
1768 47 : if (state.dataPlnt->PlantLoop(heatPump.plantLoc.loopNum).glycol->Num == Fluid::GlycolNum_Water) {
1769 47 : SourceSideEffect = 1.0 - std::exp(-heatPump.SourceSideUACoeff / (CpFluid * heatPump.InletWaterMassFlowRate));
1770 : } else {
1771 0 : DegradFactor = DegradF(state, state.dataPlnt->PlantLoop(heatPump.plantLoc.loopNum).glycol, heatPump.InletWaterTemp);
1772 0 : SourceSideEffect =
1773 0 : 1.0 / ((heatPump.SourceSideHTR1 * std::pow(SourceSideVolFlowRate, -0.8)) / DegradFactor + heatPump.SourceSideHTR2);
1774 : }
1775 :
1776 : // Determine Source Side Tempertaure (Evap. Temp for this mode)
1777 94 : SourceSideTemp = heatPump.InletWaterTemp -
1778 47 : state.dataWaterToAirHeatPump->initialQSource / (SourceSideEffect * CpFluid * heatPump.InletWaterMassFlowRate);
1779 :
1780 : // Determine Load Side Tempertaure (Condensing Temp for this mode)
1781 47 : LoadSideTemp = heatPump.InletAirDBTemp + state.dataWaterToAirHeatPump->initialQLoad * LoadSideEffect_CpAir_MassFlowRate_inv;
1782 :
1783 : // Determine the Load Side and Source Side Saturated Temp (evaporating and condensing pressures)
1784 47 : SourceSidePressure = heatPump.refrig->getSatPressure(state, SourceSideTemp, RoutineNameSourceSideTemp);
1785 47 : LoadSidePressure = heatPump.refrig->getSatPressure(state, LoadSideTemp, RoutineNameLoadSideTemp);
1786 47 : if (SourceSidePressure < heatPump.LowPressCutoff && !FirstHVACIteration) {
1787 0 : if (!state.dataGlobal->WarmupFlag) {
1788 0 : ShowRecurringWarningErrorAtEnd(
1789 : state,
1790 0 : format("WaterToAir Heat pump:heating [{}] shut off on low pressure < {:.0R}", heatPump.Name, heatPump.LowPressCutoff),
1791 0 : heatPump.LowPressHtgError,
1792 : SourceSidePressure,
1793 : SourceSidePressure,
1794 : _,
1795 : "[Pa]",
1796 : "[Pa]");
1797 : }
1798 0 : heatPump.SimFlag = false;
1799 0 : return;
1800 : }
1801 :
1802 47 : if (LoadSidePressure > heatPump.HighPressCutoff && !FirstHVACIteration) {
1803 0 : if (!state.dataGlobal->WarmupFlag) {
1804 0 : ShowRecurringWarningErrorAtEnd(
1805 : state,
1806 0 : format("WaterToAir Heat pump:heating [{}] shut off on high pressure > {:.0R}", heatPump.Name, heatPump.HighPressCutoff),
1807 0 : heatPump.HighPressHtgError,
1808 0 : heatPump.InletWaterTemp,
1809 0 : heatPump.InletWaterTemp,
1810 : _,
1811 : "SourceSideInletTemp[C]",
1812 : "SourceSideInletTemp[C]");
1813 : }
1814 : // CALL ShowWarningError(state, 'Heat pump:heating shut off on high pressure')
1815 : // WRITE(CErrCount,*) SourceSideInletTemp
1816 : // CErrCount=ADJUSTL(CErrCount)
1817 : // CALL ShowContinueError(state, 'Source side inlet temperature too low, T='//TRIM(CErrCount))
1818 : // CALL ShowContinueError(state, 'Heat pump heating demand not met by plant side')
1819 0 : heatPump.SimFlag = false;
1820 0 : return;
1821 : }
1822 :
1823 : // Determine Suction Pressure at Compressor Entrance & Discharge Pressure at Compressor Exit
1824 47 : switch (heatPump.compressorType) {
1825 0 : case CompressorType::Reciprocating: {
1826 0 : SuctionPr = SourceSidePressure - heatPump.CompSucPressDrop;
1827 0 : DischargePr = LoadSidePressure + heatPump.CompSucPressDrop;
1828 0 : break;
1829 : }
1830 0 : case CompressorType::Rotary: {
1831 0 : SuctionPr = SourceSidePressure;
1832 0 : DischargePr = LoadSidePressure + heatPump.CompSucPressDrop;
1833 0 : break;
1834 : }
1835 47 : case CompressorType::Scroll: {
1836 47 : SuctionPr = SourceSidePressure;
1837 47 : DischargePr = LoadSidePressure;
1838 47 : break;
1839 : }
1840 0 : default:
1841 0 : break;
1842 : }
1843 :
1844 : // Determine the Source Side Outlet Enthalpy
1845 : // Quality of the refrigerant leaving the evaporator is saturated gas
1846 47 : Quality = 1.0;
1847 47 : SourceSideOutletEnth = heatPump.refrig->getSatEnthalpy(state, SourceSideTemp, Quality, RoutineNameSourceSideTemp);
1848 :
1849 : // Determine Load Side Outlet Enthalpy
1850 : // Quality of the refrigerant leaving the condenser is saturated liguid
1851 47 : Quality = 0.0;
1852 47 : LoadSideOutletEnth = heatPump.refrig->getSatEnthalpy(state, LoadSideTemp, Quality, RoutineNameLoadSideTemp);
1853 :
1854 : // Determine Superheated Temperature of the Source Side outlet/compressor Inlet
1855 47 : CompressInletTemp = SourceSideTemp + heatPump.SuperheatTemp;
1856 :
1857 : // Determine the Enathalpy of the Superheated Fluid at Source Side Outlet/Compressor Inlet
1858 47 : SuperHeatEnth = heatPump.refrig->getSupHeatEnthalpy(state, CompressInletTemp, SourceSidePressure, RoutineNameCompressInletTemp);
1859 :
1860 : // Determining the suction state of the fluid from inlet state involves interation
1861 : // Method employed...
1862 : // Determine the saturated temp at suction pressure, shoot out into the superheated region find the enthalpy
1863 : // check that with the inlet enthalpy ( as suction loss is isenthalpic). Iterate till desired accuracy is reached
1864 :
1865 47 : if (!Converged) {
1866 46 : CompSuctionSatTemp = heatPump.refrig->getSatTemperature(state, SuctionPr, RoutineNameSuctionPr);
1867 46 : CompSuctionTemp1 = CompSuctionSatTemp;
1868 :
1869 : // Shoot into the Superheated Region
1870 46 : CompSuctionTemp2 = CompSuctionSatTemp + DegreeofSuperheat;
1871 : }
1872 :
1873 141 : auto f = [&state, &heatPump, SuctionPr, SuperHeatEnth](Real64 const CompSuctionTemp) {
1874 : static constexpr std::string_view RoutineName("CalcWaterToAirHPHeating:CalcCompSuctionTemp");
1875 141 : Real64 compSuctionEnth = heatPump.refrig->getSupHeatEnthalpy(state, CompSuctionTemp, SuctionPr, RoutineName);
1876 141 : return (compSuctionEnth - SuperHeatEnth) / SuperHeatEnth;
1877 47 : };
1878 :
1879 47 : General::SolveRoot(state, ERR, STOP1, SolFlag, CompSuctionTemp, f, CompSuctionTemp1, CompSuctionTemp2);
1880 47 : if (SolFlag == -1) {
1881 0 : heatPump.SimFlag = false;
1882 0 : return;
1883 : }
1884 47 : CompSuctionEnth = heatPump.refrig->getSupHeatEnthalpy(state, CompSuctionTemp, SuctionPr, RoutineNameCompSuctionTemp);
1885 47 : CompSuctionDensity = heatPump.refrig->getSupHeatDensity(state, CompSuctionTemp, SuctionPr, RoutineNameCompSuctionTemp);
1886 :
1887 : // Find Refrigerant Flow Rate
1888 47 : switch (heatPump.compressorType) {
1889 0 : case CompressorType::Reciprocating: {
1890 0 : MassRef = heatPump.CompPistonDisp * CompSuctionDensity *
1891 0 : (1 + heatPump.CompClearanceFactor - heatPump.CompClearanceFactor * std::pow(DischargePr / SuctionPr, 1 / gamma));
1892 0 : break;
1893 : }
1894 0 : case CompressorType::Rotary: {
1895 0 : MassRef = heatPump.CompPistonDisp * CompSuctionDensity;
1896 0 : break;
1897 : }
1898 47 : case CompressorType::Scroll: {
1899 47 : MassRef = heatPump.RefVolFlowRate * CompSuctionDensity - heatPump.LeakRateCoeff * (DischargePr / SuctionPr);
1900 47 : break;
1901 : }
1902 0 : default:
1903 0 : break;
1904 : }
1905 47 : MassRef = max(0.0, MassRef);
1906 :
1907 : // Find the Source Side Heat Transfer
1908 47 : QSource = MassRef * (SourceSideOutletEnth - LoadSideOutletEnth);
1909 47 : SourceResidual = std::abs(QSource - state.dataWaterToAirHeatPump->initialQSource) / state.dataWaterToAirHeatPump->initialQSource;
1910 47 : state.dataWaterToAirHeatPump->initialQSource += RelaxParam * (QSource - state.dataWaterToAirHeatPump->initialQSource);
1911 47 : if (NumIteration2 > 8) RelaxParam = 0.3;
1912 : }
1913 :
1914 : // Determine the Power Consumption
1915 17 : switch (heatPump.compressorType) {
1916 0 : case CompressorType::Reciprocating:
1917 : case CompressorType::Rotary: {
1918 0 : Power = heatPump.PowerLosses + (1 / heatPump.LossFactor) * (MassRef * gamma / (gamma - 1) * SuctionPr / CompSuctionDensity *
1919 0 : (std::pow(DischargePr / SuctionPr, (gamma - 1) / gamma) - 1));
1920 0 : break;
1921 : }
1922 17 : case CompressorType::Scroll: {
1923 17 : Power = heatPump.PowerLosses + (1 / heatPump.LossFactor) * (gamma / (gamma - 1)) * SuctionPr * heatPump.RefVolFlowRate *
1924 17 : (((gamma - 1) / gamma) * ((DischargePr / SuctionPr) / heatPump.VolumeRatio) +
1925 17 : ((1 / gamma) * std::pow(heatPump.VolumeRatio, gamma - 1)) - 1);
1926 17 : break;
1927 : }
1928 0 : default:
1929 0 : break;
1930 : }
1931 :
1932 : // Determine the Load Side Heat Rate
1933 17 : QLoadTotal = Power + QSource;
1934 17 : LoadResidual = std::abs(QLoadTotal - state.dataWaterToAirHeatPump->initialQLoad) / state.dataWaterToAirHeatPump->initialQLoad;
1935 17 : if (LoadResidual < ERR) Converged = true;
1936 17 : state.dataWaterToAirHeatPump->initialQLoad += RelaxParam * (QLoadTotal - state.dataWaterToAirHeatPump->initialQLoad);
1937 17 : if (NumIteration3 > 8) RelaxParam = 0.2;
1938 : }
1939 :
1940 1 : if (SuctionPr < heatPump.LowPressCutoff && !FirstHVACIteration) {
1941 0 : ShowWarningError(state, "Heat pump:heating shut down on low pressure");
1942 0 : heatPump.SimFlag = false;
1943 0 : return;
1944 : }
1945 :
1946 1 : if (DischargePr > heatPump.HighPressCutoff && !FirstHVACIteration) {
1947 0 : ShowWarningError(state, "Heat pump:heating shut down on high pressure");
1948 0 : heatPump.SimFlag = false;
1949 0 : return;
1950 : }
1951 :
1952 : // calculate coil outlet state variables
1953 1 : LoadSideAirOutletEnth = heatPump.InletAirEnthalpy + QLoadTotal / heatPump.InletAirMassFlowRate;
1954 1 : LoadSideOutletDBTemp = heatPump.InletAirDBTemp + QLoadTotal / (heatPump.InletAirMassFlowRate * CpAir);
1955 1 : LoadSideOutletHumRat = Psychrometrics::PsyWFnTdbH(state, LoadSideOutletDBTemp, LoadSideAirOutletEnth, RoutineNameLoadSideOutletEnthalpy);
1956 1 : SourceSideOutletTemp = heatPump.InletWaterTemp - QSource / (heatPump.InletWaterMassFlowRate * CpWater);
1957 :
1958 : // Calculate actual outlet conditions for the run time fraction
1959 : // Actual outlet conditions are "average" for time step
1960 1 : if (fanOp == HVAC::FanOp::Continuous) {
1961 : // continuous fan, cycling compressor
1962 0 : heatPump.OutletAirEnthalpy = PartLoadRatio * LoadSideAirOutletEnth + (1.0 - PartLoadRatio) * heatPump.InletAirEnthalpy;
1963 0 : heatPump.OutletAirHumRat = PartLoadRatio * LoadSideOutletHumRat + (1.0 - PartLoadRatio) * heatPump.InletAirHumRat;
1964 0 : heatPump.OutletAirDBTemp = Psychrometrics::PsyTdbFnHW(heatPump.OutletAirEnthalpy, heatPump.OutletAirHumRat);
1965 : } else {
1966 : // default to cycling fan, cycling compressor
1967 1 : heatPump.OutletAirEnthalpy = LoadSideAirOutletEnth;
1968 1 : heatPump.OutletAirHumRat = LoadSideOutletHumRat;
1969 1 : heatPump.OutletAirDBTemp = LoadSideOutletDBTemp;
1970 : }
1971 :
1972 : // Calculate Part Load Factor and Runtime Fraction
1973 1 : Real64 PLF = 1.0; // part load factor as a function of PLR, RTF = PLR / PLF
1974 1 : if (heatPump.PLFCurveIndex > 0) {
1975 1 : PLF = Curve::CurveValue(state, heatPump.PLFCurveIndex, PartLoadRatio); // Calculate part-load factor
1976 : }
1977 1 : if (fanOp == HVAC::FanOp::Cycling) {
1978 1 : state.dataHVACGlobal->OnOffFanPartLoadFraction = PLF;
1979 : }
1980 1 : heatPump.RunFrac = PartLoadRatio / PLF;
1981 :
1982 : // scale heat transfer rates and power to run time
1983 1 : QLoadTotal *= PartLoadRatio;
1984 1 : Power *= heatPump.RunFrac;
1985 1 : QSource *= PartLoadRatio;
1986 :
1987 : // Update heat pump data structure
1988 1 : state.dataHVACGlobal->DXElecHeatingPower = Power;
1989 1 : heatPump.Power = Power;
1990 1 : heatPump.QLoadTotal = QLoadTotal;
1991 1 : heatPump.QSensible = QLoadTotal;
1992 :
1993 1 : heatPump.QSource = QSource;
1994 1 : heatPump.PartLoadRatio = PartLoadRatio;
1995 1 : heatPump.OutletAirMassFlowRate = heatPump.InletAirMassFlowRate;
1996 1 : heatPump.OutletWaterTemp = SourceSideOutletTemp;
1997 1 : heatPump.OutletWaterMassFlowRate = heatPump.InletWaterMassFlowRate;
1998 1 : heatPump.OutletWaterEnthalpy = heatPump.InletWaterEnthalpy - QSource / heatPump.InletWaterMassFlowRate;
1999 : }
2000 :
2001 0 : void UpdateWatertoAirHP(EnergyPlusData &state, int const HPNum)
2002 : {
2003 : // SUBROUTINE INFORMATION:
2004 : // AUTHOR Hui Jin
2005 : // DATE WRITTEN Oct 2000
2006 :
2007 : // PURPOSE OF THIS SUBROUTINE:
2008 : // This subroutine updates the Water to Air Heat Pump outlet nodes.
2009 :
2010 : // METHODOLOGY EMPLOYED:
2011 : // Data is moved from the HP data structure to the HP outlet nodes.
2012 :
2013 : // Using/Aliasing
2014 0 : Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
2015 0 : auto &heatPump = state.dataWaterToAirHeatPump->WatertoAirHP(HPNum);
2016 :
2017 : // WatertoAirHP(HPNum)%SimFlag=.FALSE.
2018 0 : if (!heatPump.SimFlag) {
2019 : // Heatpump is off; just pass through conditions
2020 0 : heatPump.Power = 0.0;
2021 0 : heatPump.Energy = 0.0;
2022 0 : heatPump.QLoadTotal = 0.0;
2023 0 : heatPump.QSensible = 0.0;
2024 0 : heatPump.QLatent = 0.0;
2025 0 : heatPump.QSource = 0.0;
2026 0 : heatPump.RunFrac = 0.0;
2027 0 : heatPump.PartLoadRatio = 0.0;
2028 0 : heatPump.OutletAirDBTemp = heatPump.InletAirDBTemp;
2029 0 : heatPump.OutletAirHumRat = heatPump.InletAirHumRat;
2030 0 : heatPump.OutletWaterTemp = heatPump.InletWaterTemp;
2031 0 : heatPump.OutletAirMassFlowRate = heatPump.InletAirMassFlowRate;
2032 0 : heatPump.OutletWaterMassFlowRate = heatPump.InletWaterMassFlowRate;
2033 0 : heatPump.OutletAirEnthalpy = heatPump.InletAirEnthalpy;
2034 0 : heatPump.OutletWaterEnthalpy = heatPump.InletWaterEnthalpy;
2035 : }
2036 :
2037 : // Set the outlet air nodes of the WatertoAirHP
2038 0 : state.dataLoopNodes->Node(heatPump.AirOutletNodeNum).MassFlowRate = state.dataLoopNodes->Node(heatPump.AirInletNodeNum).MassFlowRate;
2039 0 : state.dataLoopNodes->Node(heatPump.AirOutletNodeNum).Temp = heatPump.OutletAirDBTemp;
2040 0 : state.dataLoopNodes->Node(heatPump.AirOutletNodeNum).HumRat = heatPump.OutletAirHumRat;
2041 0 : state.dataLoopNodes->Node(heatPump.AirOutletNodeNum).Enthalpy = heatPump.OutletAirEnthalpy;
2042 :
2043 : // Set the outlet nodes for properties that just pass through & not used
2044 0 : PlantUtilities::SafeCopyPlantNode(state, heatPump.WaterInletNodeNum, heatPump.WaterOutletNodeNum);
2045 : // Set the outlet water nodes for the heat pump
2046 0 : state.dataLoopNodes->Node(heatPump.WaterOutletNodeNum).Temp = heatPump.OutletWaterTemp;
2047 0 : state.dataLoopNodes->Node(heatPump.WaterOutletNodeNum).Enthalpy = heatPump.OutletWaterEnthalpy;
2048 :
2049 : // Set the outlet nodes for properties that just pass through & not used
2050 0 : state.dataLoopNodes->Node(heatPump.AirOutletNodeNum).Quality = state.dataLoopNodes->Node(heatPump.AirInletNodeNum).Quality;
2051 0 : state.dataLoopNodes->Node(heatPump.AirOutletNodeNum).Press = state.dataLoopNodes->Node(heatPump.AirInletNodeNum).Press;
2052 0 : state.dataLoopNodes->Node(heatPump.AirOutletNodeNum).MassFlowRateMin = state.dataLoopNodes->Node(heatPump.AirInletNodeNum).MassFlowRateMin;
2053 0 : state.dataLoopNodes->Node(heatPump.AirOutletNodeNum).MassFlowRateMax = state.dataLoopNodes->Node(heatPump.AirInletNodeNum).MassFlowRateMax;
2054 0 : state.dataLoopNodes->Node(heatPump.AirOutletNodeNum).MassFlowRateMinAvail =
2055 0 : state.dataLoopNodes->Node(heatPump.AirInletNodeNum).MassFlowRateMinAvail;
2056 0 : state.dataLoopNodes->Node(heatPump.AirOutletNodeNum).MassFlowRateMaxAvail =
2057 0 : state.dataLoopNodes->Node(heatPump.AirInletNodeNum).MassFlowRateMaxAvail;
2058 :
2059 : // Pass through the load side mass flow rates
2060 0 : heatPump.InletAirMassFlowRate = state.dataLoopNodes->Node(heatPump.AirInletNodeNum).MassFlowRate;
2061 0 : heatPump.OutletAirMassFlowRate = heatPump.InletAirMassFlowRate;
2062 :
2063 0 : heatPump.Energy = heatPump.Power * TimeStepSysSec;
2064 0 : heatPump.EnergyLoadTotal = heatPump.QLoadTotal * TimeStepSysSec;
2065 0 : heatPump.EnergySensible = heatPump.QSensible * TimeStepSysSec;
2066 0 : heatPump.EnergyLatent = heatPump.QLatent * TimeStepSysSec;
2067 0 : heatPump.EnergySource = heatPump.QSource * TimeStepSysSec;
2068 :
2069 0 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
2070 0 : state.dataLoopNodes->Node(heatPump.AirOutletNodeNum).CO2 = state.dataLoopNodes->Node(heatPump.AirInletNodeNum).CO2;
2071 : }
2072 0 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
2073 0 : state.dataLoopNodes->Node(heatPump.AirOutletNodeNum).GenContam = state.dataLoopNodes->Node(heatPump.AirInletNodeNum).GenContam;
2074 : }
2075 0 : }
2076 :
2077 : // End of Update subroutines for the WatertoAirHP Module
2078 : // *****************************************************************************
2079 :
2080 0 : Real64 CalcEffectiveSHR(EnergyPlusData &state,
2081 : int const HPNum, // Index number for cooling coil
2082 : Real64 const SHRss, // Steady-state sensible heat ratio
2083 : HVAC::FanOp const fanOp, // fan/compressor cycling scheme indicator
2084 : Real64 const RTF, // Compressor run-time fraction
2085 : Real64 const QLatRated, // Rated latent capacity
2086 : Real64 const QLatActual, // Actual latent capacity
2087 : Real64 const EnteringDB, // Entering air dry-bulb temperature
2088 : Real64 const EnteringWB // Entering air wet-bulb temperature
2089 : )
2090 : {
2091 :
2092 : // FUNCTION INFORMATION:
2093 : // AUTHOR Richard Raustad, FSEC
2094 : // DATE WRITTEN September 2003
2095 : // MODIFIED Kenneth Tang (Aug 2004) Added capability for simulating FanOp::Cycling
2096 :
2097 : // PURPOSE OF THIS FUNCTION:
2098 : // Adjust sensible heat ratio to account for degradation of DX coil latent
2099 : // capacity at part-load (cycling) conditions.
2100 :
2101 : // METHODOLOGY EMPLOYED:
2102 : // With model parameters entered by the user, the part-load latent performance
2103 : // of a DX cooling coil is determined for a constant air flow system with
2104 : // a cooling coil that cycles on/off. The model calculates the time
2105 : // required for condensate to begin falling from the cooling coil.
2106 : // Runtimes greater than this are integrated to a "part-load" latent
2107 : // capacity which is used to determine the "part-load" sensible heat ratio.
2108 : // See reference below for additional details (linear decay model, Eq. 8b).
2109 : // REFERENCES:
2110 : // "A Model to Predict the Latent Capacity of Air Conditioners and
2111 : // Heat Pumps at Part-Load Conditions with Constant Fan Operation"
2112 : // 1996 ASHRAE Transactions, Volume 102, Part 1, Pp. 266 - 274,
2113 : // Hugh I. Henderson, Jr., P.E., Kannan Rengarajan, P.E.
2114 :
2115 : // Using/Aliasing
2116 0 : auto const &heatPump = state.dataWaterToAirHeatPump->WatertoAirHP(HPNum);
2117 :
2118 : // Return value
2119 : Real64 SHReff; // Effective sensible heat ratio, includes degradation due to cycling effects
2120 :
2121 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
2122 : Real64 Twet; // Nominal time for condensate to begin leaving the coil's condensate drain line
2123 : // at the current operating conditions (sec)
2124 : Real64 Gamma; // Initial moisture evaporation rate divided by steady-state AC latent capacity
2125 : // at the current operating conditions
2126 : Real64 Twet_max; // Maximum allowed value for Twet
2127 : // shut off after compressor cycle off [s]
2128 :
2129 : Real64 Ton; // Coil on time (sec)
2130 : Real64 Toff; // Coil off time (sec)
2131 : Real64 Toffa; // Actual coil off time (sec). Equations valid for Toff <= (2.0 * Twet/Gamma)
2132 : Real64 aa; // Intermediate variable
2133 : Real64 To1; // Intermediate variable (first guess at To). To = time to the start of moisture removal
2134 : Real64 To2; // Intermediate variable (second guess at To). To = time to the start of moisture removal
2135 : Real64 Error; // Error for iteration (DO) loop
2136 : Real64 LHRmult; // Latent Heat Ratio (LHR) multiplier. The effective latent heat ratio LHR = (1-SHRss)*LHRmult
2137 :
2138 : // No moisture evaporation (latent degradation) occurs for runtime fraction of 1.0
2139 : // All latent degradation model parameters cause divide by 0.0 if not greater than 0.0
2140 : // Latent degradation model parameters initialize to 0.0 meaning no evaporation model used.
2141 0 : if ((RTF >= 1.0) || (QLatRated == 0.0) || (QLatActual == 0.0) || (heatPump.Twet_Rated <= 0.0) || (heatPump.Gamma_Rated <= 0.0) ||
2142 0 : (heatPump.MaxONOFFCyclesperHour <= 0.0) || (heatPump.LatentCapacityTimeConstant <= 0.0) || (RTF <= 0.0)) {
2143 0 : SHReff = SHRss;
2144 0 : return SHReff;
2145 : }
2146 :
2147 0 : Twet_max = 9999.0; // high limit for Twet
2148 :
2149 : // Calculate the model parameters at the actual operating conditions
2150 0 : Twet = min(heatPump.Twet_Rated * QLatRated / (QLatActual + 1.e-10), Twet_max);
2151 0 : Gamma = heatPump.Gamma_Rated * QLatRated * (EnteringDB - EnteringWB) / ((26.7 - 19.4) * QLatActual + 1.e-10);
2152 :
2153 : // Calculate the compressor on and off times using a conventional thermostat curve
2154 0 : Ton = 3600.0 / (4.0 * heatPump.MaxONOFFCyclesperHour * (1.0 - RTF)); // duration of cooling coil on-cycle (sec)
2155 :
2156 0 : if ((fanOp == HVAC::FanOp::Cycling) && (heatPump.FanDelayTime != 0.0)) {
2157 : // For FanOp::Cycling, moisture is evaporated from the cooling coil back to the air stream
2158 : // until the fan cycle off. Assume no evaporation from the coil after the fan shuts off.
2159 0 : Toff = heatPump.FanDelayTime;
2160 : } else {
2161 : // For FanOp::Continuous, moisture is evaporated from the cooling coil back to the air stream
2162 : // for the entire heat pump off-cycle.
2163 0 : Toff = 3600.0 / (4.0 * heatPump.MaxONOFFCyclesperHour * RTF); // duration of cooling coil off-cycle (sec)
2164 : }
2165 :
2166 : // Cap Toff to meet the equation restriction
2167 0 : if (Gamma > 0.0) {
2168 0 : Toffa = min(Toff, 2.0 * Twet / Gamma);
2169 : } else {
2170 0 : Toffa = Toff;
2171 : }
2172 :
2173 : // Use sucessive substitution to solve for To
2174 0 : aa = (Gamma * Toffa) - (0.25 / Twet) * pow_2(Gamma) * pow_2(Toffa);
2175 :
2176 0 : To1 = aa + heatPump.LatentCapacityTimeConstant;
2177 0 : Error = 1.0;
2178 0 : while (Error > 0.001) {
2179 0 : To2 = aa - heatPump.LatentCapacityTimeConstant * std::expm1(-To1 / heatPump.LatentCapacityTimeConstant);
2180 0 : Error = std::abs((To2 - To1) / To1);
2181 0 : To1 = To2;
2182 : }
2183 :
2184 : // Adjust Sensible Heat Ratio (SHR) using Latent Heat Ratio (LHR) multiplier
2185 : // Floating underflow errors occur when -Ton/LatentCapacityTimeConstant is a large negative number.
2186 : // Cap lower limit at -700 to avoid the underflow errors.
2187 0 : aa = std::exp(max(-700.0, -Ton / heatPump.LatentCapacityTimeConstant));
2188 : // Calculate latent heat ratio multiplier
2189 0 : LHRmult = max(((Ton - To2) / (Ton + heatPump.LatentCapacityTimeConstant * (aa - 1.0))), 0.0);
2190 :
2191 : // Calculate part-load or "effective" sensible heat ratio
2192 0 : SHReff = 1.0 - (1.0 - SHRss) * LHRmult;
2193 :
2194 0 : if (SHReff < SHRss) SHReff = SHRss; // Effective SHR can be less than the steady-state SHR
2195 0 : if (SHReff > 1.0) SHReff = 1.0; // Effective sensible heat ratio can't be greater than 1.0
2196 :
2197 0 : return SHReff;
2198 : }
2199 :
2200 0 : Real64 DegradF(EnergyPlusData &state,
2201 : Fluid::GlycolProps *glycol,
2202 : Real64 &Temp // Temperature of the fluid
2203 : )
2204 : {
2205 : // FUNCTION INFORMATION:
2206 : // AUTHOR Kenneth Tang
2207 : // DATE WRITTEN October 2004
2208 :
2209 : // PURPOSE OF THIS FUNCTION:
2210 : // Calculate the degradation factor to predict the heat pump performance
2211 : // when antifreeze is used.
2212 : // METHODOLOGY EMPLOYED:
2213 : // Use FluidProperties to calculate the properties of water and glycol
2214 : // at the given temperature. Then substitute the properties into the equation.
2215 : // REFERENCES:
2216 : // Jin, H. 2002. Parameter Estimation Based Models of Water Source Heat Pumps. Phd Thesis.
2217 : // Oklahoma State University.
2218 :
2219 : // Return value
2220 : Real64 DegradF;
2221 :
2222 : // FUNCTION PARAMETER DEFINITIONS:
2223 : static constexpr std::string_view CalledFrom("HVACWaterToAir:DegradF");
2224 :
2225 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
2226 : Real64 VisWater; // Viscosity of water [mPa-s]
2227 : Real64 DensityWater; // Density of water [kg/m3]
2228 : Real64 CpWater; // Specific heat of water [J/kg-K]
2229 : Real64 CondWater; // Conductivity of water [W/m-K]
2230 : Real64 VisCoolant; // Viscosity of water [mPa-s]
2231 : Real64 DensityCoolant; // Density of water [kg/m3]
2232 : Real64 CpCoolant; // Specific heat of water [J/kg-K]
2233 : Real64 CondCoolant; // Conductivity of water [W/m-K]
2234 :
2235 0 : auto *water = Fluid::GetWater(state);
2236 :
2237 0 : VisWater = water->getViscosity(state, Temp, CalledFrom);
2238 0 : DensityWater = water->getDensity(state, Temp, CalledFrom);
2239 0 : CpWater = water->getSpecificHeat(state, Temp, CalledFrom);
2240 0 : CondWater = water->getConductivity(state, Temp, CalledFrom);
2241 0 : VisCoolant = glycol->getViscosity(state, Temp, CalledFrom);
2242 0 : DensityCoolant = glycol->getDensity(state, Temp, CalledFrom);
2243 0 : CpCoolant = glycol->getSpecificHeat(state, Temp, CalledFrom);
2244 0 : CondCoolant = glycol->getConductivity(state, Temp, CalledFrom);
2245 :
2246 0 : DegradF = std::pow(VisCoolant / VisWater, -0.47) * std::pow(DensityCoolant / DensityWater, 0.8) * std::pow(CpCoolant / CpWater, 0.33) *
2247 0 : std::pow(CondCoolant / CondWater, 0.67);
2248 :
2249 0 : return DegradF;
2250 : }
2251 :
2252 0 : int GetCoilIndex(EnergyPlusData &state,
2253 : std::string const &CoilType, // must match coil types in this module
2254 : std::string const &CoilName, // must match coil names for the coil type
2255 : bool &ErrorsFound // set to true if problem
2256 : )
2257 : {
2258 :
2259 : // FUNCTION INFORMATION:
2260 : // AUTHOR R. Raustad
2261 : // DATE WRITTEN August 2007
2262 :
2263 : // PURPOSE OF THIS FUNCTION:
2264 : // This function looks up the given coil and returns the index. If
2265 : // incorrect coil type or name is given, ErrorsFound is returned as true and value is returned
2266 : // as zero.
2267 :
2268 : // Obtains and Allocates WatertoAirHP related parameters from input file
2269 0 : if (state.dataWaterToAirHeatPump->GetCoilsInputFlag) { // First time subroutine has been entered
2270 0 : GetWatertoAirHPInput(state);
2271 0 : state.dataWaterToAirHeatPump->GetCoilsInputFlag = false;
2272 : }
2273 :
2274 0 : int IndexNum = Util::FindItemInList(CoilName, state.dataWaterToAirHeatPump->WatertoAirHP);
2275 :
2276 0 : if (IndexNum == 0) {
2277 0 : ShowSevereError(state, format("Could not find CoilType=\"{}\" with Name=\"{}\"", CoilType, CoilName));
2278 0 : ErrorsFound = true;
2279 : }
2280 :
2281 0 : return IndexNum;
2282 : }
2283 :
2284 0 : Real64 GetCoilCapacity(EnergyPlusData &state,
2285 : std::string const &CoilType, // must match coil types in this module
2286 : std::string const &CoilName, // must match coil names for the coil type
2287 : bool &ErrorsFound // set to true if problem
2288 : )
2289 : {
2290 :
2291 : // FUNCTION INFORMATION:
2292 : // AUTHOR Linda Lawrie
2293 : // DATE WRITTEN February 2006
2294 :
2295 : // PURPOSE OF THIS FUNCTION:
2296 : // This function looks up the coil capacity for the given coil and returns it. If
2297 : // incorrect coil type or name is given, ErrorsFound is returned as true and capacity is returned
2298 : // as negative.
2299 :
2300 : // Return value
2301 : Real64 CoilCapacity; // returned capacity of matched coil
2302 :
2303 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
2304 : int WhichCoil;
2305 :
2306 : // Obtains and Allocates WatertoAirHP related parameters from input file
2307 0 : if (state.dataWaterToAirHeatPump->GetCoilsInputFlag) { // First time subroutine has been entered
2308 0 : GetWatertoAirHPInput(state);
2309 0 : state.dataWaterToAirHeatPump->GetCoilsInputFlag = false;
2310 : }
2311 :
2312 0 : if (Util::SameString(CoilType, "COIL:HEATING:WATERTOAIRHEATPUMP:PARAMETERESTIMATION") ||
2313 0 : Util::SameString(CoilType, "COIL:COOLING:WATERTOAIRHEATPUMP:PARAMETERESTIMATION")) {
2314 0 : WhichCoil = Util::FindItemInList(CoilName, state.dataWaterToAirHeatPump->WatertoAirHP);
2315 0 : if (WhichCoil != 0) {
2316 0 : if (Util::SameString(CoilType, "COIL:HEATING:WATERTOAIRHEATPUMP:PARAMETERESTIMATION")) {
2317 0 : CoilCapacity = state.dataWaterToAirHeatPump->WatertoAirHP(WhichCoil).HeatingCapacity;
2318 : } else {
2319 0 : CoilCapacity = state.dataWaterToAirHeatPump->WatertoAirHP(WhichCoil).CoolingCapacity;
2320 : }
2321 : }
2322 : } else {
2323 0 : WhichCoil = 0;
2324 : }
2325 :
2326 0 : if (WhichCoil == 0) {
2327 0 : ShowSevereError(state, format("Could not find CoilType=\"{}\" with Name=\"{}\"", CoilType, CoilName));
2328 0 : ErrorsFound = true;
2329 0 : CoilCapacity = -1000.0;
2330 : }
2331 :
2332 0 : return CoilCapacity;
2333 : }
2334 :
2335 0 : int GetCoilInletNode(EnergyPlusData &state,
2336 : std::string const &CoilType, // must match coil types in this module
2337 : std::string const &CoilName, // must match coil names for the coil type
2338 : bool &ErrorsFound // set to true if problem
2339 : )
2340 : {
2341 :
2342 : // FUNCTION INFORMATION:
2343 : // AUTHOR Linda Lawrie
2344 : // DATE WRITTEN February 2006
2345 :
2346 : // PURPOSE OF THIS FUNCTION:
2347 : // This function looks up the given coil and returns the inlet node. If
2348 : // incorrect coil type or name is given, ErrorsFound is returned as true and value is returned
2349 : // as zero.
2350 :
2351 : // Return value
2352 : int NodeNumber; // returned outlet node of matched coil
2353 :
2354 : // Obtains and Allocates WatertoAirHP related parameters from input file
2355 0 : if (state.dataWaterToAirHeatPump->GetCoilsInputFlag) { // First time subroutine has been entered
2356 0 : GetWatertoAirHPInput(state);
2357 0 : state.dataWaterToAirHeatPump->GetCoilsInputFlag = false;
2358 : }
2359 :
2360 0 : int WhichCoil = Util::FindItemInList(CoilName, state.dataWaterToAirHeatPump->WatertoAirHP);
2361 0 : if (WhichCoil != 0) {
2362 0 : NodeNumber = state.dataWaterToAirHeatPump->WatertoAirHP(WhichCoil).AirInletNodeNum;
2363 : }
2364 :
2365 0 : if (WhichCoil == 0) {
2366 0 : ShowSevereError(state, format("Could not find CoilType=\"{}\" with Name=\"{}\"", CoilType, CoilName));
2367 0 : ErrorsFound = true;
2368 0 : NodeNumber = 0;
2369 : }
2370 :
2371 0 : return NodeNumber;
2372 : }
2373 :
2374 0 : int GetCoilOutletNode(EnergyPlusData &state,
2375 : std::string const &CoilType, // must match coil types in this module
2376 : std::string const &CoilName, // must match coil names for the coil type
2377 : bool &ErrorsFound // set to true if problem
2378 : )
2379 : {
2380 :
2381 : // FUNCTION INFORMATION:
2382 : // AUTHOR R. Raustad
2383 : // DATE WRITTEN July 2007
2384 :
2385 : // PURPOSE OF THIS FUNCTION:
2386 : // This function looks up the given coil and returns the outlet node. If
2387 : // incorrect coil type or name is given, ErrorsFound is returned as true and value is returned
2388 : // as zero.
2389 :
2390 : // Return value
2391 : int NodeNumber; // returned outlet node of matched coil
2392 :
2393 : // Obtains and Allocates WatertoAirHP related parameters from input file
2394 0 : if (state.dataWaterToAirHeatPump->GetCoilsInputFlag) { // First time subroutine has been entered
2395 0 : GetWatertoAirHPInput(state);
2396 0 : state.dataWaterToAirHeatPump->GetCoilsInputFlag = false;
2397 : }
2398 :
2399 0 : int WhichCoil = Util::FindItemInList(CoilName, state.dataWaterToAirHeatPump->WatertoAirHP);
2400 0 : if (WhichCoil != 0) {
2401 0 : NodeNumber = state.dataWaterToAirHeatPump->WatertoAirHP(WhichCoil).AirOutletNodeNum;
2402 : }
2403 :
2404 0 : if (WhichCoil == 0) {
2405 0 : ShowSevereError(state, format("Could not find CoilType=\"{}\" with Name=\"{}\"", CoilType, CoilName));
2406 0 : ErrorsFound = true;
2407 0 : NodeNumber = 0;
2408 : }
2409 :
2410 0 : return NodeNumber;
2411 : }
2412 :
2413 : } // namespace WaterToAirHeatPump
2414 :
2415 : } // namespace EnergyPlus
|