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