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/string.functions.hh>
53 :
54 : // EnergyPlus Headers
55 : #include <EnergyPlus/BranchNodeConnections.hh>
56 : #include <EnergyPlus/Data/EnergyPlusData.hh>
57 : #include <EnergyPlus/DataBranchAirLoopPlant.hh>
58 : #include <EnergyPlus/DataHVACGlobals.hh>
59 : #include <EnergyPlus/DataLoopNode.hh>
60 : #include <EnergyPlus/FluidProperties.hh>
61 : #include <EnergyPlus/General.hh>
62 : #include <EnergyPlus/HeatPumpWaterToWaterHEATING.hh>
63 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
64 : #include <EnergyPlus/NodeInputManager.hh>
65 : #include <EnergyPlus/OutputProcessor.hh>
66 : #include <EnergyPlus/Plant/DataPlant.hh>
67 : #include <EnergyPlus/Plant/PlantLocation.hh>
68 : #include <EnergyPlus/PlantUtilities.hh>
69 : #include <EnergyPlus/UtilityRoutines.hh>
70 :
71 : namespace EnergyPlus::HeatPumpWaterToWaterHEATING {
72 :
73 : // Module containing the routines dealing with the Water to Water Heat Pump (Heating)
74 :
75 : // MODULE INFORMATION:
76 : // AUTHOR ARUN
77 : // DATE WRITTEN 7/18/2000
78 : // MODIFIED ARUN: 6/27/2002: Cycle Time
79 : // L Lawrie: V1.1.1 (5/20/2003) add meters and energy to several reporting variables
80 : // L Lawrie: V1.1.1 (5/20/2003) restructure modules to comply with standard templates
81 : // B. Griffith, Sept 2010, plant upgrades, generalize fluid properties
82 :
83 : // PURPOSE OF THIS MODULE:
84 : // This module simulates a water to Water Heat Pump (Heating)
85 :
86 : // METHODOLOGY EMPLOYED:
87 : // This simulation is based on a set of selected parameters,
88 : // Which are obtained using Parameter Estimation technique.
89 :
90 : // MODULE PARAMETER DEFINITIONS
91 : std::string const ModuleCompName("HeatPump:WaterToWater:ParameterEstimation:Heating");
92 : std::string const ModuleCompNameUC("HEATPUMP:WATERTOWATER:PARAMETERESTIMATION:HEATING");
93 : std::string const GSHPRefrigerant("R22");
94 :
95 6 : GshpPeHeatingSpecs *GshpPeHeatingSpecs::factory(EnergyPlusData &state, const std::string &objectName)
96 : {
97 6 : if (state.dataHPWaterToWaterHtg->GetWWHPHeatingInput) {
98 3 : GetGshpInput(state);
99 3 : state.dataHPWaterToWaterHtg->GetWWHPHeatingInput = false;
100 : }
101 6 : auto thisObj = std::find_if(state.dataHPWaterToWaterHtg->GSHP.begin(),
102 6 : state.dataHPWaterToWaterHtg->GSHP.end(),
103 6 : [&objectName](const GshpPeHeatingSpecs &myObj) { return myObj.Name == objectName; });
104 6 : if (thisObj != state.dataHPWaterToWaterHtg->GSHP.end()) {
105 6 : return thisObj;
106 : }
107 : // If we didn't find it, fatal
108 : ShowFatalError(state, format("WWHPHeatingFactory: Error getting inputs for heat pump named: {}", objectName)); // LCOV_EXCL_LINE
109 : // Shut up the compiler
110 : return nullptr; // LCOV_EXCL_LINE
111 : }
112 :
113 93022 : void GshpPeHeatingSpecs::simulate(
114 : EnergyPlusData &state, const PlantLocation &calledFromLocation, bool FirstHVACIteration, Real64 &CurLoad, [[maybe_unused]] bool RunFlag)
115 : {
116 :
117 : // Simulate the model for the Demand "MyLoad"
118 93022 : if (calledFromLocation.loopNum == this->LoadPlantLoc.loopNum) { // chilled water loop
119 46511 : this->initialize(state);
120 46511 : this->calculate(state, CurLoad);
121 46511 : this->update(state);
122 46511 : } else if (calledFromLocation.loopNum == this->SourcePlantLoc.loopNum) { // condenser loop
123 46511 : PlantUtilities::UpdateChillerComponentCondenserSide(state,
124 : this->SourcePlantLoc.loopNum,
125 : this->SourcePlantLoc.loopSideNum,
126 : DataPlant::PlantEquipmentType::HPWaterEFHeating,
127 : this->SourceSideInletNodeNum,
128 : this->SourceSideOutletNodeNum,
129 46511 : -this->QSource,
130 : this->SourceSideWaterInletTemp,
131 : this->SourceSideWaterOutletTemp,
132 : this->SourceSideWaterMassFlowRate,
133 : FirstHVACIteration);
134 : } else {
135 0 : ShowFatalError(state, format("SimHPWatertoWaterHEATING:: Invalid loop connection {}, Requested Unit={}", ModuleCompName, this->Name));
136 : }
137 93022 : }
138 :
139 30 : void GshpPeHeatingSpecs::getDesignCapacities([[maybe_unused]] EnergyPlusData &state,
140 : [[maybe_unused]] const PlantLocation &calledFromLocation,
141 : Real64 &MaxLoad,
142 : Real64 &MinLoad,
143 : Real64 &OptLoad)
144 : {
145 30 : MinLoad = this->NomCap * this->MinPartLoadRat;
146 30 : MaxLoad = this->NomCap * this->MaxPartLoadRat;
147 30 : OptLoad = this->NomCap * this->OptPartLoadRat;
148 30 : }
149 :
150 30 : void GshpPeHeatingSpecs::onInitLoopEquip(EnergyPlusData &state, [[maybe_unused]] const PlantLocation &calledFromLocation)
151 : {
152 30 : if (this->plantScanFlag) {
153 : // Locate the heating on the plant loops for later usage
154 3 : bool errFlag = false;
155 9 : PlantUtilities::ScanPlantLoopsForObject(state,
156 : this->Name,
157 : DataPlant::PlantEquipmentType::HPWaterPEHeating,
158 3 : this->SourcePlantLoc,
159 : errFlag,
160 : _,
161 : _,
162 : _,
163 3 : this->SourceSideInletNodeNum,
164 : _);
165 9 : PlantUtilities::ScanPlantLoopsForObject(
166 6 : state, this->Name, DataPlant::PlantEquipmentType::HPWaterPEHeating, this->LoadPlantLoc, errFlag, _, _, _, this->LoadSideInletNodeNum, _);
167 3 : if (errFlag) {
168 0 : ShowFatalError(state, "InitGshp: Program terminated due to previous condition(s).");
169 : }
170 :
171 3 : PlantUtilities::InterConnectTwoPlantLoopSides(state, this->LoadPlantLoc, this->SourcePlantLoc, this->WWHPPlantType, true);
172 3 : this->plantScanFlag = false;
173 : }
174 30 : }
175 :
176 : #pragma clang diagnostic push
177 : #pragma ide diagnostic ignored "readability-magic-numbers"
178 3 : void GetGshpInput(EnergyPlusData &state)
179 : {
180 : // SUBROUTINE INFORMATION:
181 : // DATE WRITTEN: April 1998
182 :
183 : // PURPOSE OF THIS SUBROUTINE:
184 : // This routine will get the input
185 : // required by the GSHP models. As such
186 : // it will interact with the Input Scanner to retrieve
187 : // information from the input file, count the number of
188 : // GSHPs and begin to fill the
189 : // arrays associated with the type GSHP.
190 :
191 : static constexpr std::string_view routineName = "GetGshpInput";
192 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
193 : int NumAlphas; // Number of elements in the alpha array
194 : int NumNums; // Number of elements in the numeric array
195 : int IOStat; // IO Status when calling get input subroutine
196 3 : Array1D_string AlphArray(5); // character string data
197 3 : Array1D<Real64> NumArray(23); // numeric data
198 :
199 3 : bool ErrorsFound(false);
200 :
201 3 : state.dataHPWaterToWaterHtg->NumGSHPs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ModuleCompName);
202 :
203 3 : if (state.dataHPWaterToWaterHtg->NumGSHPs <= 0) {
204 0 : ShowSevereError(state, format("{}: No Equipment found", ModuleCompName));
205 0 : ErrorsFound = true;
206 : }
207 :
208 : // Allocate Arrays
209 3 : state.dataHPWaterToWaterHtg->GSHP.allocate(state.dataHPWaterToWaterHtg->NumGSHPs);
210 :
211 6 : for (int GSHPNum = 1; GSHPNum <= state.dataHPWaterToWaterHtg->NumGSHPs; ++GSHPNum) {
212 3 : auto &thisGSHP = state.dataHPWaterToWaterHtg->GSHP(GSHPNum);
213 3 : state.dataInputProcessing->inputProcessor->getObjectItem(state, ModuleCompNameUC, GSHPNum, AlphArray, NumAlphas, NumArray, NumNums, IOStat);
214 :
215 3 : ErrorObjectHeader eoh{routineName, ModuleCompNameUC, AlphArray(1)};
216 :
217 3 : thisGSHP.Name = AlphArray(1);
218 :
219 3 : thisGSHP.WWHPPlantType = DataPlant::PlantEquipmentType::HPWaterPEHeating;
220 :
221 3 : thisGSHP.COP = NumArray(1);
222 3 : if (NumArray(1) == 0.0) {
223 0 : ShowSevereError(state, format("{}:COP = 0.0, Heatpump={}", ModuleCompName, thisGSHP.Name));
224 0 : ErrorsFound = true;
225 : }
226 :
227 : // zero values for NumArray 3 - 6 checked in input - idd
228 3 : thisGSHP.NomCap = NumArray(2);
229 :
230 3 : thisGSHP.MinPartLoadRat = NumArray(3);
231 :
232 3 : thisGSHP.MaxPartLoadRat = NumArray(4);
233 :
234 3 : thisGSHP.OptPartLoadRat = NumArray(5);
235 :
236 3 : thisGSHP.LoadSideVolFlowRate = NumArray(6);
237 3 : if (NumArray(6) == 0.0) {
238 0 : ShowSevereError(state, format("{}:Load Side Flow Rate = 0.0, Heatpump={}", ModuleCompName, thisGSHP.Name));
239 0 : ErrorsFound = true;
240 : }
241 :
242 3 : thisGSHP.SourceSideVolFlowRate = NumArray(7);
243 3 : if (NumArray(7) == 0.0) {
244 0 : ShowSevereError(state, format("{}:Source Side Flow Rate = 0.0, Heatpump={}", ModuleCompName, thisGSHP.Name));
245 0 : ErrorsFound = true;
246 : }
247 :
248 3 : thisGSHP.LoadSideUACoeff = NumArray(8);
249 3 : if (NumArray(8) == 0.0) {
250 0 : ShowSevereError(state, format("{}:Load Side Heat Transfer Coeffcient = 0.0, Heatpump={}", ModuleCompName, thisGSHP.Name));
251 0 : ErrorsFound = true;
252 : }
253 :
254 3 : thisGSHP.SourceSideUACoeff = NumArray(9);
255 3 : if (NumArray(9) == 0.0) {
256 0 : ShowSevereError(state, format("{}:Source Side Heat Transfer Coeffcient = 0.0, Heatpump={}", ModuleCompName, thisGSHP.Name));
257 0 : ErrorsFound = true;
258 : }
259 :
260 3 : thisGSHP.CompPistonDisp = NumArray(10);
261 3 : if (NumArray(10) == 0.0) {
262 0 : ShowSevereError(state, format("{}:Compressor Piston displacement/Storke = 0.0, Heatpump={}", ModuleCompName, thisGSHP.Name));
263 0 : ErrorsFound = true;
264 : }
265 :
266 3 : thisGSHP.CompClearanceFactor = NumArray(11);
267 3 : if (NumArray(11) == 0.0) {
268 0 : ShowSevereError(state, format("{}:Compressor Clearance Factor = 0.0, Heatpump={}", ModuleCompName, thisGSHP.Name));
269 0 : ErrorsFound = true;
270 : }
271 :
272 3 : thisGSHP.CompSucPressDrop = NumArray(12);
273 3 : if (NumArray(12) == 0.0) {
274 0 : ShowSevereError(state, format("{}: Pressure Drop = 0.0, Heatpump={}", ModuleCompName, thisGSHP.Name));
275 0 : ErrorsFound = true;
276 : }
277 :
278 3 : thisGSHP.SuperheatTemp = NumArray(13);
279 3 : if (NumArray(13) == 0.0) {
280 0 : ShowSevereError(state, format("{}:Source Side SuperHeat = 0.0, Heatpump={}", ModuleCompName, thisGSHP.Name));
281 0 : ErrorsFound = true;
282 : }
283 :
284 3 : thisGSHP.PowerLosses = NumArray(14);
285 3 : if (NumArray(14) == 0.0) {
286 0 : ShowSevereError(state, format("{}:Compressor Power Loss = 0.0, Heatpump={}", ModuleCompName, thisGSHP.Name));
287 0 : ErrorsFound = true;
288 : }
289 3 : thisGSHP.LossFactor = NumArray(15);
290 3 : if (NumArray(15) == 0.0) {
291 0 : ShowSevereError(state, format("{}:Efficiency = 0.0, Heatpump={}", ModuleCompName, thisGSHP.Name));
292 0 : ErrorsFound = true;
293 : }
294 :
295 3 : thisGSHP.HighPressCutoff = NumArray(16);
296 3 : if (NumArray(16) == 0.0) {
297 3 : thisGSHP.HighPressCutoff = 500000000.0;
298 : }
299 :
300 3 : thisGSHP.LowPressCutoff = NumArray(17);
301 3 : if (NumArray(17) == 0.0) {
302 3 : thisGSHP.LowPressCutoff = 0.0;
303 : }
304 :
305 3 : thisGSHP.SourceSideInletNodeNum = GetOnlySingleNode(state,
306 3 : AlphArray(2),
307 : ErrorsFound,
308 : DataLoopNode::ConnectionObjectType::HeatPumpWaterToWaterParameterEstimationHeating,
309 3 : thisGSHP.Name,
310 : DataLoopNode::NodeFluidType::Water,
311 : DataLoopNode::ConnectionType::Inlet,
312 : NodeInputManager::CompFluidStream::Primary,
313 : DataLoopNode::ObjectIsNotParent);
314 :
315 3 : thisGSHP.SourceSideOutletNodeNum = GetOnlySingleNode(state,
316 3 : AlphArray(3),
317 : ErrorsFound,
318 : DataLoopNode::ConnectionObjectType::HeatPumpWaterToWaterParameterEstimationHeating,
319 3 : thisGSHP.Name,
320 : DataLoopNode::NodeFluidType::Water,
321 : DataLoopNode::ConnectionType::Outlet,
322 : NodeInputManager::CompFluidStream::Primary,
323 : DataLoopNode::ObjectIsNotParent);
324 :
325 3 : thisGSHP.LoadSideInletNodeNum = GetOnlySingleNode(state,
326 3 : AlphArray(4),
327 : ErrorsFound,
328 : DataLoopNode::ConnectionObjectType::HeatPumpWaterToWaterParameterEstimationHeating,
329 3 : thisGSHP.Name,
330 : DataLoopNode::NodeFluidType::Water,
331 : DataLoopNode::ConnectionType::Inlet,
332 : NodeInputManager::CompFluidStream::Secondary,
333 : DataLoopNode::ObjectIsNotParent);
334 :
335 6 : thisGSHP.LoadSideOutletNodeNum = GetOnlySingleNode(state,
336 3 : AlphArray(5),
337 : ErrorsFound,
338 : DataLoopNode::ConnectionObjectType::HeatPumpWaterToWaterParameterEstimationHeating,
339 3 : thisGSHP.Name,
340 : DataLoopNode::NodeFluidType::Water,
341 : DataLoopNode::ConnectionType::Outlet,
342 : NodeInputManager::CompFluidStream::Secondary,
343 : DataLoopNode::ObjectIsNotParent);
344 :
345 : // Test node sets
346 6 : BranchNodeConnections::TestCompSet(state, ModuleCompNameUC, thisGSHP.Name, AlphArray(2), AlphArray(3), "Condenser Water Nodes");
347 3 : BranchNodeConnections::TestCompSet(state, ModuleCompNameUC, thisGSHP.Name, AlphArray(4), AlphArray(5), "Hot Water Nodes");
348 :
349 : // save the design source side flow rate for use by plant loop sizing algorithms
350 3 : PlantUtilities::RegisterPlantCompDesignFlow(state, thisGSHP.SourceSideInletNodeNum, 0.5 * thisGSHP.SourceSideVolFlowRate);
351 :
352 3 : if ((thisGSHP.refrig = Fluid::GetRefrig(state, GSHPRefrigerant)) == nullptr) {
353 0 : ShowSevereItemNotFound(state, eoh, "Refrigerant", GSHPRefrigerant);
354 0 : ErrorsFound = true;
355 : }
356 : }
357 :
358 3 : if (ErrorsFound) {
359 0 : ShowFatalError(state, format("Errors Found in getting {} Input", ModuleCompNameUC));
360 : }
361 :
362 : // CurrentModuleObject='HeatPump:WaterToWater:ParameterEstimation:Heating'
363 6 : for (int GSHPNum = 1; GSHPNum <= state.dataHPWaterToWaterHtg->NumGSHPs; ++GSHPNum) {
364 3 : auto &thisGSHP = state.dataHPWaterToWaterHtg->GSHP(GSHPNum);
365 6 : SetupOutputVariable(state,
366 : "Heat Pump Electricity Rate",
367 : Constant::Units::W,
368 3 : thisGSHP.Power,
369 : OutputProcessor::TimeStepType::System,
370 : OutputProcessor::StoreType::Average,
371 3 : thisGSHP.Name);
372 6 : SetupOutputVariable(state,
373 : "Heat Pump Electricity Energy",
374 : Constant::Units::J,
375 3 : thisGSHP.Energy,
376 : OutputProcessor::TimeStepType::System,
377 : OutputProcessor::StoreType::Sum,
378 3 : thisGSHP.Name,
379 : Constant::eResource::Electricity,
380 : OutputProcessor::Group::Plant,
381 : OutputProcessor::EndUseCat::Heating);
382 :
383 6 : SetupOutputVariable(state,
384 : "Heat Pump Load Side Heat Transfer Rate",
385 : Constant::Units::W,
386 3 : thisGSHP.QLoad,
387 : OutputProcessor::TimeStepType::System,
388 : OutputProcessor::StoreType::Average,
389 3 : thisGSHP.Name);
390 6 : SetupOutputVariable(state,
391 : "Heat Pump Load Side Heat Transfer Energy",
392 : Constant::Units::J,
393 3 : thisGSHP.QLoadEnergy,
394 : OutputProcessor::TimeStepType::System,
395 : OutputProcessor::StoreType::Sum,
396 3 : thisGSHP.Name);
397 :
398 6 : SetupOutputVariable(state,
399 : "Heat Pump Source Side Heat Transfer Rate",
400 : Constant::Units::W,
401 3 : thisGSHP.QSource,
402 : OutputProcessor::TimeStepType::System,
403 : OutputProcessor::StoreType::Average,
404 3 : thisGSHP.Name);
405 6 : SetupOutputVariable(state,
406 : "Heat Pump Source Side Heat Transfer Energy",
407 : Constant::Units::J,
408 3 : thisGSHP.QSourceEnergy,
409 : OutputProcessor::TimeStepType::System,
410 : OutputProcessor::StoreType::Sum,
411 3 : thisGSHP.Name);
412 :
413 6 : SetupOutputVariable(state,
414 : "Heat Pump Load Side Outlet Temperature",
415 : Constant::Units::C,
416 3 : thisGSHP.LoadSideWaterOutletTemp,
417 : OutputProcessor::TimeStepType::System,
418 : OutputProcessor::StoreType::Average,
419 3 : thisGSHP.Name);
420 6 : SetupOutputVariable(state,
421 : "Heat Pump Load Side Inlet Temperature",
422 : Constant::Units::C,
423 3 : thisGSHP.LoadSideWaterInletTemp,
424 : OutputProcessor::TimeStepType::System,
425 : OutputProcessor::StoreType::Average,
426 3 : thisGSHP.Name);
427 6 : SetupOutputVariable(state,
428 : "Heat Pump Source Side Outlet Temperature",
429 : Constant::Units::C,
430 3 : thisGSHP.SourceSideWaterOutletTemp,
431 : OutputProcessor::TimeStepType::System,
432 : OutputProcessor::StoreType::Average,
433 3 : thisGSHP.Name);
434 6 : SetupOutputVariable(state,
435 : "Heat Pump Source Side Inlet Temperature",
436 : Constant::Units::C,
437 3 : thisGSHP.SourceSideWaterInletTemp,
438 : OutputProcessor::TimeStepType::System,
439 : OutputProcessor::StoreType::Average,
440 3 : thisGSHP.Name);
441 6 : SetupOutputVariable(state,
442 : "Heat Pump Load Side Mass Flow Rate",
443 : Constant::Units::kg_s,
444 3 : thisGSHP.LoadSideWaterMassFlowRate,
445 : OutputProcessor::TimeStepType::System,
446 : OutputProcessor::StoreType::Average,
447 3 : thisGSHP.Name);
448 6 : SetupOutputVariable(state,
449 : "Heat Pump Source Side Mass Flow Rate",
450 : Constant::Units::kg_s,
451 3 : thisGSHP.SourceSideWaterMassFlowRate,
452 : OutputProcessor::TimeStepType::System,
453 : OutputProcessor::StoreType::Average,
454 3 : thisGSHP.Name);
455 : }
456 3 : }
457 : #pragma clang diagnostic pop
458 :
459 46511 : void GshpPeHeatingSpecs::initialize(EnergyPlusData &state)
460 : {
461 :
462 : // SUBROUTINE INFORMATION:
463 : // AUTHOR: Dan Fisher
464 : // DATE WRITTEN: July 2007
465 :
466 : // SUBROUTINE PARAMETER DEFINITIONS:
467 : static constexpr std::string_view RoutineName("InitGshp");
468 :
469 : // For each new environment
470 46511 : if (state.dataGlobal->BeginEnvrnFlag && this->beginEnvironFlag) {
471 18 : this->QLoad = 0.0;
472 18 : this->QSource = 0.0;
473 18 : this->Power = 0.0;
474 18 : this->QLoadEnergy = 0.0;
475 18 : this->QSourceEnergy = 0.0;
476 18 : this->Energy = 0.0;
477 18 : this->LoadSideWaterInletTemp = 0.0;
478 18 : this->SourceSideWaterInletTemp = 0.0;
479 18 : this->LoadSideWaterOutletTemp = 0.0;
480 18 : this->SourceSideWaterOutletTemp = 0.0;
481 18 : this->SourceSideWaterMassFlowRate = 0.0;
482 18 : this->LoadSideWaterMassFlowRate = 0.0;
483 18 : this->IsOn = false;
484 18 : this->MustRun = true;
485 :
486 18 : this->beginEnvironFlag = false;
487 18 : Real64 rho = state.dataPlnt->PlantLoop(this->LoadPlantLoc.loopNum).glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
488 18 : this->LoadSideDesignMassFlow = this->LoadSideVolFlowRate * rho;
489 :
490 18 : PlantUtilities::InitComponentNodes(state, 0.0, this->LoadSideDesignMassFlow, this->LoadSideInletNodeNum, this->LoadSideOutletNodeNum);
491 :
492 18 : rho = state.dataPlnt->PlantLoop(this->SourcePlantLoc.loopNum).glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
493 18 : this->SourceSideDesignMassFlow = this->SourceSideVolFlowRate * rho;
494 :
495 18 : PlantUtilities::InitComponentNodes(state, 0.0, this->SourceSideDesignMassFlow, this->SourceSideInletNodeNum, this->SourceSideOutletNodeNum);
496 18 : if (state.dataLoopNodes->Node(this->SourceSideOutletNodeNum).TempSetPoint == DataLoopNode::SensedNodeFlagValue) {
497 12 : state.dataLoopNodes->Node(this->SourceSideOutletNodeNum).TempSetPoint = 0.0;
498 : }
499 18 : state.dataLoopNodes->Node(this->SourceSideInletNodeNum).Temp = state.dataLoopNodes->Node(this->SourceSideOutletNodeNum).TempSetPoint + 30.0;
500 : }
501 :
502 46511 : if (!state.dataGlobal->BeginEnvrnFlag) {
503 46184 : this->beginEnvironFlag = true;
504 : }
505 :
506 : // On every call
507 46511 : this->Running = 0;
508 46511 : this->MustRun = true; // Reset MustRun Flag to TRUE
509 46511 : this->LoadSideWaterMassFlowRate = 0.0; // Load Side mass flow rate, water side
510 46511 : this->SourceSideWaterMassFlowRate = 0.0; // Source Side mass flow rate, water side
511 46511 : this->Power = 0.0; // power consumption
512 46511 : this->QLoad = 0.0; // heat rejection from Load Side coil
513 46511 : this->QSource = 0.0;
514 46511 : }
515 :
516 46511 : void GshpPeHeatingSpecs::calculate(EnergyPlusData &state, Real64 &MyLoad)
517 : {
518 : // SUBROUTINE INFORMATION:
519 : // AUTHOR
520 : // DATE WRITTEN Sept. 1998
521 : // MODIFIED April 1999
522 : // September 2002, SJR
523 : // RE-ENGINEERED Mar2000
524 :
525 : // SUBROUTINE PARAMETER DEFINITIONS:
526 46511 : constexpr Real64 gamma(1.114); // Expansion Coefficient
527 46511 : constexpr Real64 HeatBalTol(0.0005);
528 46511 : constexpr Real64 RelaxParam(0.6);
529 46511 : constexpr Real64 SmallNum(1.0e-20);
530 46511 : constexpr int IterationLimit(500);
531 46511 : constexpr const char *RoutineName("CalcGshpModel");
532 46511 : constexpr const char *RoutineNameLoadSideTemp("CalcGSHPModel:LoadSideTemp");
533 46511 : constexpr const char *RoutineNameSourceSideTemp("CalcGSHPModel:SourceSideTemp");
534 46511 : constexpr const char *RoutineNameCompressInletTemp("CalcGSHPModel:CompressInletTemp");
535 46511 : constexpr const char *RoutineNameSuctionPr("CalcGSHPModel:SuctionPr");
536 46511 : constexpr const char *RoutineNameCompSuctionTemp("CalcGSHPModel:CompSuctionTemp");
537 :
538 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
539 : Real64 CompSuctionTemp;
540 : Real64 CompSuctionEnth;
541 : Real64 CompSuctionDensity;
542 : Real64 CompSuctionSatTemp;
543 : Real64 DutyFactor;
544 :
545 46511 : if (MyLoad > 0.0) {
546 14824 : this->MustRun = true;
547 14824 : this->IsOn = true;
548 : } else {
549 31687 : this->MustRun = false;
550 31687 : this->IsOn = false;
551 : }
552 46511 : this->LoadSideWaterInletTemp = state.dataLoopNodes->Node(this->LoadSideInletNodeNum).Temp;
553 46511 : this->SourceSideWaterInletTemp = state.dataLoopNodes->Node(this->SourceSideInletNodeNum).Temp;
554 :
555 : //*******Set flow based on "run" flags**********
556 : // Set flows if the heat pump is not running
557 46511 : if (!this->MustRun) {
558 31687 : this->LoadSideWaterMassFlowRate = 0.0;
559 31687 : PlantUtilities::SetComponentFlowRate(
560 31687 : state, this->LoadSideWaterMassFlowRate, this->LoadSideInletNodeNum, this->LoadSideOutletNodeNum, this->LoadPlantLoc);
561 31687 : this->SourceSideWaterMassFlowRate = 0.0;
562 31687 : PlantUtilities::SetComponentFlowRate(
563 31687 : state, this->SourceSideWaterMassFlowRate, this->SourceSideInletNodeNum, this->SourceSideOutletNodeNum, this->SourcePlantLoc);
564 31687 : PlantUtilities::PullCompInterconnectTrigger(state,
565 31687 : this->LoadPlantLoc,
566 31687 : this->CondMassFlowIndex,
567 31687 : this->SourcePlantLoc,
568 : DataPlant::CriteriaType::MassFlowRate,
569 : this->SourceSideWaterMassFlowRate);
570 : // now initialize simulation variables for "heat pump off"
571 31687 : this->LoadSideWaterOutletTemp = this->LoadSideWaterInletTemp;
572 31687 : this->SourceSideWaterOutletTemp = this->SourceSideWaterInletTemp;
573 31687 : return; // if heat pump is not running return without simulation, power, Q already zeroed in init
574 : } else { // the heat pump must run, request design flow
575 :
576 14824 : this->LoadSideWaterMassFlowRate = this->LoadSideDesignMassFlow;
577 14824 : PlantUtilities::SetComponentFlowRate(
578 14824 : state, this->LoadSideWaterMassFlowRate, this->LoadSideInletNodeNum, this->LoadSideOutletNodeNum, this->LoadPlantLoc);
579 :
580 14824 : this->SourceSideWaterMassFlowRate = this->SourceSideDesignMassFlow;
581 14824 : PlantUtilities::SetComponentFlowRate(
582 14824 : state, this->SourceSideWaterMassFlowRate, this->SourceSideInletNodeNum, this->SourceSideOutletNodeNum, this->SourcePlantLoc);
583 : // if there's no flow, turn the "heat pump off"
584 14824 : if (this->LoadSideWaterMassFlowRate < DataBranchAirLoopPlant::MassFlowTolerance ||
585 14823 : this->SourceSideWaterMassFlowRate < DataBranchAirLoopPlant::MassFlowTolerance) {
586 2 : this->LoadSideWaterMassFlowRate = 0.0;
587 2 : PlantUtilities::SetComponentFlowRate(
588 2 : state, this->LoadSideWaterMassFlowRate, this->LoadSideInletNodeNum, this->LoadSideOutletNodeNum, this->LoadPlantLoc);
589 2 : this->SourceSideWaterMassFlowRate = 0.0;
590 2 : PlantUtilities::SetComponentFlowRate(
591 2 : state, this->SourceSideWaterMassFlowRate, this->SourceSideInletNodeNum, this->SourceSideOutletNodeNum, this->SourcePlantLoc);
592 2 : PlantUtilities::PullCompInterconnectTrigger(state,
593 2 : this->LoadPlantLoc,
594 2 : this->CondMassFlowIndex,
595 2 : this->SourcePlantLoc,
596 : DataPlant::CriteriaType::MassFlowRate,
597 : this->SourceSideWaterMassFlowRate);
598 2 : this->LoadSideWaterOutletTemp = this->LoadSideWaterInletTemp;
599 2 : this->SourceSideWaterOutletTemp = this->SourceSideWaterInletTemp;
600 2 : return;
601 : }
602 14822 : PlantUtilities::PullCompInterconnectTrigger(state,
603 14822 : this->LoadPlantLoc,
604 14822 : this->CondMassFlowIndex,
605 14822 : this->SourcePlantLoc,
606 : DataPlant::CriteriaType::MassFlowRate,
607 : this->SourceSideWaterMassFlowRate);
608 : }
609 :
610 : //***********BEGIN CALCULATION****************
611 : // initialize the source and load side heat transfer rates for the simulation
612 14822 : Real64 initialQSource = 0.0;
613 14822 : Real64 initialQLoad = 0.0;
614 14822 : int IterationCount = 0;
615 :
616 : Real64 CpSourceSide =
617 14822 : state.dataPlnt->PlantLoop(this->SourcePlantLoc.loopNum).glycol->getSpecificHeat(state, this->SourceSideWaterInletTemp, RoutineName);
618 :
619 : Real64 CpLoadSide =
620 14822 : state.dataPlnt->PlantLoop(this->LoadPlantLoc.loopNum).glycol->getSpecificHeat(state, this->LoadSideWaterInletTemp, RoutineName);
621 :
622 : // Determine effectiveness of Source Side (the Evaporator in heating mode)
623 14822 : Real64 SourceSideEffect = 1.0 - std::exp(-this->SourceSideUACoeff / (CpSourceSide * this->SourceSideWaterMassFlowRate));
624 : // Determine effectiveness of Load Side the condenser in heating mode
625 14822 : Real64 LoadSideEffect = 1.0 - std::exp(-this->LoadSideUACoeff / (CpLoadSide * this->LoadSideWaterMassFlowRate));
626 :
627 : while (true) { // main loop to solve model equations
628 133398 : ++IterationCount;
629 : // Determine Source Side temperature
630 133398 : Real64 SourceSideTemp =
631 133398 : this->SourceSideWaterInletTemp - initialQSource / (SourceSideEffect * CpSourceSide * this->SourceSideWaterMassFlowRate);
632 :
633 : // To determine Load Side temperature condenser
634 133398 : Real64 LoadSideTemp = this->LoadSideWaterInletTemp + initialQLoad / (LoadSideEffect * CpLoadSide * this->LoadSideWaterMassFlowRate);
635 :
636 : // Determine the evaporating and condensing pressures
637 133398 : Real64 SourceSidePressure = this->refrig->getSatPressure(state, SourceSideTemp, RoutineNameSourceSideTemp);
638 133398 : Real64 LoadSidePressure = this->refrig->getSatPressure(state, LoadSideTemp, RoutineNameLoadSideTemp);
639 :
640 : // check cutoff pressures
641 133398 : if (SourceSidePressure < this->LowPressCutoff) {
642 0 : ShowSevereError(state, format("{}=\"{}\" Heating Source Side Pressure Less than the Design Minimum", ModuleCompName, this->Name));
643 0 : ShowContinueError(
644 : state,
645 0 : format("Source Side Pressure={:.2T} and user specified Design Minimum Pressure={:.2T}", SourceSidePressure, this->LowPressCutoff));
646 0 : ShowFatalError(state, "Preceding Conditions cause termination.");
647 : }
648 133398 : if (LoadSidePressure > this->HighPressCutoff) {
649 0 : ShowSevereError(state, format("{}=\"{}\" Heating Load Side Pressure greater than the Design Maximum", ModuleCompName, this->Name));
650 0 : ShowContinueError(
651 : state,
652 0 : format("Load Side Pressure={:.2T} and user specified Design Maximum Pressure={:.2T}", LoadSidePressure, this->HighPressCutoff));
653 0 : ShowFatalError(state, "Preceding Conditions cause termination.");
654 : }
655 :
656 : // Determine Suction Pressure at compressor inlet
657 133398 : Real64 SuctionPr = SourceSidePressure - this->CompSucPressDrop;
658 : // Determine Discharge Pressure at compressor exit
659 133398 : Real64 DischargePr = LoadSidePressure + this->CompSucPressDrop;
660 : // check cutoff pressures
661 133398 : if (SuctionPr < this->LowPressCutoff) {
662 0 : ShowSevereError(state, format("{}=\"{}\" Heating Suction Pressure Less than the Design Minimum", ModuleCompName, this->Name));
663 0 : ShowContinueError(
664 0 : state, format("Heating Suction Pressure={:.2T} and user specified Design Minimum Pressure={:.2T}", SuctionPr, this->LowPressCutoff));
665 0 : ShowFatalError(state, "Preceding Conditions cause termination.");
666 : }
667 133398 : if (DischargePr > this->HighPressCutoff) {
668 0 : ShowSevereError(state, format("{}=\"{}\" Heating Discharge Pressure greater than the Design Maximum", ModuleCompName, this->Name));
669 0 : ShowContinueError(
670 : state,
671 0 : format("Heating Discharge Pressure={:.2T} and user specified Design Maximum Pressure={:.2T}", DischargePr, this->HighPressCutoff));
672 0 : ShowFatalError(state, "Preceding Conditions cause termination.");
673 : }
674 :
675 : // Determine the Source Side Outlet Enthalpy
676 133398 : Real64 qualOne = 1.0;
677 133398 : Real64 SourceSideOutletEnth = this->refrig->getSatEnthalpy(state, SourceSideTemp, qualOne, RoutineNameSourceSideTemp);
678 :
679 : // Determine Load Side Outlet Enthalpy
680 133398 : Real64 qualZero = 0.0;
681 133398 : Real64 LoadSideOutletEnth = this->refrig->getSatEnthalpy(state, LoadSideTemp, qualZero, RoutineNameLoadSideTemp);
682 :
683 : // Determine superheated temperature of the Source Side outlet/compressor inlet
684 133398 : Real64 CompressInletTemp = SourceSideTemp + this->SuperheatTemp;
685 : // Determine the enathalpy of the super heated fluid at Source Side outlet
686 133398 : Real64 SuperHeatEnth = this->refrig->getSupHeatEnthalpy(state, CompressInletTemp, SourceSidePressure, RoutineNameCompressInletTemp);
687 :
688 : // Determining the suction state of the fluid from inlet state involves interation
689 : // Method employed...
690 : // Determine the saturated temp at suction pressure, shoot out into the superheated region find the enthalpy
691 : // check that with the inlet enthalpy ( as suction loss is isenthalpic). Iterate till desired accuracy is reached
692 :
693 133398 : CompSuctionSatTemp = this->refrig->getSatTemperature(state, SuctionPr, RoutineNameSuctionPr);
694 :
695 133398 : Real64 T110 = CompSuctionSatTemp;
696 : // Shoot into the super heated region
697 133398 : Real64 T111 = CompSuctionSatTemp + 80;
698 :
699 : // Iterate to find the Suction State - given suction pressure and superheat enthalpy
700 : while (true) {
701 1250552 : CompSuctionTemp = 0.5 * (T110 + T111);
702 :
703 1250552 : CompSuctionEnth = this->refrig->getSupHeatEnthalpy(state, CompSuctionTemp, SuctionPr, RoutineNameCompSuctionTemp);
704 1250552 : if (std::abs(CompSuctionEnth - SuperHeatEnth) / SuperHeatEnth < 0.0001) {
705 133398 : break;
706 : }
707 :
708 1117154 : if (CompSuctionEnth < SuperHeatEnth) {
709 486246 : T110 = CompSuctionTemp;
710 : } else {
711 630908 : T111 = CompSuctionTemp;
712 : }
713 : }
714 :
715 : // Determine the Mass flow rate of refrigerant
716 133398 : CompSuctionDensity = this->refrig->getSupHeatDensity(state, CompSuctionTemp, SuctionPr, RoutineNameCompSuctionTemp);
717 133398 : Real64 MassRef = this->CompPistonDisp * CompSuctionDensity *
718 133398 : (1.0 + this->CompClearanceFactor - this->CompClearanceFactor * std::pow(DischargePr / SuctionPr, 1.0 / gamma));
719 :
720 : // Find the Source Side Heat Transfer
721 133398 : this->QSource = MassRef * (SourceSideOutletEnth - LoadSideOutletEnth);
722 :
723 : // Determine the theoretical power
724 133398 : this->Power = this->PowerLosses + (MassRef * gamma / (gamma - 1) * SuctionPr / CompSuctionDensity / this->LossFactor *
725 133398 : (std::pow(DischargePr / SuctionPr, (gamma - 1) / gamma) - 1));
726 :
727 : // Determine the Loadside HeatRate (QLoad)
728 133398 : this->QLoad = this->Power + this->QSource;
729 :
730 : // convergence and iteration limit check
731 133398 : if (std::abs((this->QLoad - initialQLoad) / (initialQLoad + SmallNum)) < HeatBalTol || IterationCount > IterationLimit) {
732 14822 : if (IterationCount > IterationLimit) {
733 0 : ShowWarningError(state, format("{} did not converge", ModuleCompName));
734 0 : ShowContinueErrorTimeStamp(state, "");
735 0 : ShowContinueError(state, format("Heatpump Name = {}", this->Name));
736 0 : ShowContinueError(
737 : state,
738 0 : format("Heat Inbalance (%) = {:S}", std::abs(100.0 * (this->QLoad - initialQLoad) / (initialQLoad + SmallNum))));
739 0 : ShowContinueError(state, format("Load-side heat transfer rate = {:S}", this->QLoad));
740 0 : ShowContinueError(state, format("Source-side heat transfer rate = {:S}", this->QSource));
741 0 : ShowContinueError(state, format("Source-side mass flow rate = {:S}", this->SourceSideWaterMassFlowRate));
742 0 : ShowContinueError(state, format("Load-side mass flow rate = {:S}", this->LoadSideWaterMassFlowRate));
743 0 : ShowContinueError(state, format("Source-side inlet temperature = {:S}", this->SourceSideWaterInletTemp));
744 0 : ShowContinueError(state, format("Load-side inlet temperature = {:S}", this->LoadSideWaterInletTemp));
745 : }
746 14822 : goto LOOPLoadEnth_exit;
747 :
748 : } else { // update load
749 118576 : initialQLoad += RelaxParam * (this->QLoad - initialQLoad);
750 118576 : initialQSource += RelaxParam * (this->QSource - initialQSource);
751 : }
752 118576 : }
753 14822 : LOOPLoadEnth_exit:;
754 :
755 : // Control Strategy
756 14822 : if (std::abs(MyLoad) < this->QLoad) {
757 14822 : DutyFactor = std::abs(MyLoad) / this->QLoad;
758 14822 : this->QLoad = std::abs(MyLoad);
759 14822 : this->Power *= DutyFactor;
760 14822 : this->QSource *= DutyFactor;
761 :
762 : // Determine the Exterior fluid temperature at the Load Side oulet and eveporator outlet...
763 : // Refrigerant = "Steam"
764 14822 : this->LoadSideWaterOutletTemp = this->LoadSideWaterInletTemp + this->QLoad / (this->LoadSideWaterMassFlowRate * CpLoadSide);
765 14822 : this->SourceSideWaterOutletTemp = this->SourceSideWaterInletTemp - this->QSource / (this->SourceSideWaterMassFlowRate * CpSourceSide);
766 14822 : return;
767 : }
768 :
769 0 : this->LoadSideWaterOutletTemp = this->LoadSideWaterInletTemp + this->QLoad / (this->LoadSideWaterMassFlowRate * CpLoadSide);
770 0 : this->SourceSideWaterOutletTemp = this->SourceSideWaterInletTemp - this->QSource / (this->SourceSideWaterMassFlowRate * CpSourceSide);
771 : // REPORT VAR
772 0 : this->Running = 1;
773 : }
774 :
775 46511 : void GshpPeHeatingSpecs::update(EnergyPlusData &state)
776 : {
777 : // SUBROUTINE INFORMATION:
778 : // AUTHOR: Dan Fisher
779 : // DATE WRITTEN: October 1998
780 :
781 46511 : if (!this->MustRun) {
782 : // set node temperatures
783 31687 : state.dataLoopNodes->Node(this->SourceSideOutletNodeNum).Temp = state.dataLoopNodes->Node(this->SourceSideInletNodeNum).Temp;
784 31687 : state.dataLoopNodes->Node(this->LoadSideOutletNodeNum).Temp = state.dataLoopNodes->Node(this->LoadSideInletNodeNum).Temp;
785 31687 : this->Power = 0.0;
786 31687 : this->Energy = 0.0;
787 31687 : this->QSource = 0.0;
788 31687 : this->QLoad = 0.0;
789 31687 : this->QSourceEnergy = 0.0;
790 31687 : this->QLoadEnergy = 0.0;
791 31687 : this->SourceSideWaterInletTemp = state.dataLoopNodes->Node(this->SourceSideInletNodeNum).Temp;
792 31687 : this->SourceSideWaterOutletTemp = state.dataLoopNodes->Node(this->SourceSideOutletNodeNum).Temp;
793 31687 : this->LoadSideWaterInletTemp = state.dataLoopNodes->Node(this->LoadSideInletNodeNum).Temp;
794 31687 : this->LoadSideWaterOutletTemp = state.dataLoopNodes->Node(this->LoadSideOutletNodeNum).Temp;
795 :
796 : } else {
797 : // set node temperatures
798 14824 : state.dataLoopNodes->Node(this->LoadSideOutletNodeNum).Temp = this->LoadSideWaterOutletTemp;
799 14824 : state.dataLoopNodes->Node(this->SourceSideOutletNodeNum).Temp = this->SourceSideWaterOutletTemp;
800 :
801 : // set node flow rates; for these load based models
802 : // assume that the sufficient Source Side flow rate available
803 :
804 14824 : Real64 const ReportingConstant = state.dataHVACGlobal->TimeStepSysSec;
805 :
806 14824 : this->Energy = this->Power * ReportingConstant;
807 14824 : this->QSourceEnergy = QSource * ReportingConstant;
808 14824 : this->QLoadEnergy = QLoad * ReportingConstant;
809 : }
810 46511 : }
811 0 : void GshpPeHeatingSpecs::oneTimeInit([[maybe_unused]] EnergyPlusData &state)
812 : {
813 0 : }
814 3 : void GshpPeHeatingSpecs::oneTimeInit_new([[maybe_unused]] EnergyPlusData &state)
815 : {
816 3 : }
817 :
818 : } // namespace EnergyPlus::HeatPumpWaterToWaterHEATING
|