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 <cassert>
50 : #include <cmath>
51 :
52 : // ObjexxFCL Headers
53 : #include <ObjexxFCL/Array.functions.hh>
54 : #include <ObjexxFCL/Fmath.hh>
55 :
56 : // EnergyPlus Headers
57 : #include <EnergyPlus/Autosizing/Base.hh>
58 : #include <EnergyPlus/BranchNodeConnections.hh>
59 : #include <EnergyPlus/ChillerExhaustAbsorption.hh>
60 : #include <EnergyPlus/CurveManager.hh>
61 : #include <EnergyPlus/Data/EnergyPlusData.hh>
62 : #include <EnergyPlus/DataBranchAirLoopPlant.hh>
63 : #include <EnergyPlus/DataGlobalConstants.hh>
64 : #include <EnergyPlus/DataHVACGlobals.hh>
65 : #include <EnergyPlus/DataIPShortCuts.hh>
66 : #include <EnergyPlus/DataLoopNode.hh>
67 : #include <EnergyPlus/DataSizing.hh>
68 : #include <EnergyPlus/EMSManager.hh>
69 : #include <EnergyPlus/FluidProperties.hh>
70 : #include <EnergyPlus/GlobalNames.hh>
71 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
72 : #include <EnergyPlus/MicroturbineElectricGenerator.hh>
73 : #include <EnergyPlus/NodeInputManager.hh>
74 : #include <EnergyPlus/OutAirNodeManager.hh>
75 : #include <EnergyPlus/OutputProcessor.hh>
76 : #include <EnergyPlus/OutputReportPredefined.hh>
77 : #include <EnergyPlus/Plant/DataPlant.hh>
78 : #include <EnergyPlus/PlantUtilities.hh>
79 : #include <EnergyPlus/Psychrometrics.hh>
80 : #include <EnergyPlus/UtilityRoutines.hh>
81 :
82 : namespace EnergyPlus::ChillerExhaustAbsorption {
83 :
84 : // MODULE INFORMATION:
85 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
86 : // for Gas Research Institute (Original module GasAbsoptionChiller)
87 : // DATE WRITTEN March 2001
88 : // MODIFIED Brent Griffith, Nov 2010 plant upgrades, generalize fluid properties
89 : // Mahabir Bhandari, ORNL, Aug 2011, modified to accommodate Exhaust Fired Absorption Chiller
90 :
91 : // PURPOSE OF THIS MODULE:
92 : // This module simulates the performance of the Exhaust fired double effect
93 : // absorption chiller.
94 : // METHODOLOGY EMPLOYED:
95 : // Once the PlantLoopManager determines that the exhaust fired absorber chiller
96 : // is available to meet a loop cooling demand, it calls SimExhaustAbsorption
97 : // which in turn calls the appropriate Exhaust Fired Absorption Chiller model.
98 : // REFERENCES:
99 : // DOE-2.1e Supplement
100 : // PG&E CoolToolsGas Mod
101 : // Performance curves obtained from manufacturer
102 : // OTHER NOTES:
103 : // The curves on this model follow the DOE-2 approach of using
104 : // electric and heat input ratios. In addition, the temperature
105 : // correction curve has two independent variables for the
106 : // chilled water temperature and either the entering or leaving
107 : // condenser water temperature.
108 : // The code was originally adopted from the ChillerAbsorption
109 : // routine but has been extensively modified.
110 : // Development of the original(GasAbsoptionChiller) module was funded by the Gas Research Institute.
111 : // (Please see copyright and disclaimer information at end of module)
112 :
113 0 : ExhaustAbsorberSpecs *ExhaustAbsorberSpecs::factory(EnergyPlusData &state, std::string const &objectName)
114 : {
115 : // Process the input data if it hasn't been done already
116 0 : if (state.dataChillerExhaustAbsorption->Sim_GetInput) {
117 0 : GetExhaustAbsorberInput(state);
118 0 : state.dataChillerExhaustAbsorption->Sim_GetInput = false;
119 : }
120 : // Now look for this particular pipe in the list
121 0 : auto thisObj = std::find_if(state.dataChillerExhaustAbsorption->ExhaustAbsorber.begin(),
122 0 : state.dataChillerExhaustAbsorption->ExhaustAbsorber.end(),
123 0 : [&objectName](const ExhaustAbsorberSpecs &myObj) { return myObj.Name == objectName; });
124 0 : if (thisObj != state.dataChillerExhaustAbsorption->ExhaustAbsorber.end()) {
125 0 : return thisObj;
126 : }
127 : // If we didn't find it, fatal
128 : ShowFatalError(state, format("LocalExhaustAbsorberFactory: Error getting inputs for comp named: {}", objectName)); // LCOV_EXCL_LINE
129 : // Shut up the compiler
130 : return nullptr; // LCOV_EXCL_LINE
131 : }
132 :
133 0 : void ExhaustAbsorberSpecs::simulate(
134 : EnergyPlusData &state, const PlantLocation &calledFromLocation, bool FirstHVACIteration, Real64 &CurLoad, bool RunFlag)
135 : {
136 0 : DataPlant::BrLoopType brIdentity(DataPlant::BrLoopType::NoMatch);
137 :
138 0 : int branchTotalComp = state.dataPlnt->PlantLoop(calledFromLocation.loopNum)
139 0 : .LoopSide(calledFromLocation.loopSideNum)
140 0 : .Branch(calledFromLocation.branchNum)
141 0 : .TotalComponents;
142 :
143 0 : for (int iComp = 1; iComp <= branchTotalComp; iComp++) {
144 : // kind of a hacky way to find the location of this, but it's what plantloopequip was doing
145 0 : int compInletNodeNum = state.dataPlnt->PlantLoop(calledFromLocation.loopNum)
146 0 : .LoopSide(calledFromLocation.loopSideNum)
147 0 : .Branch(calledFromLocation.branchNum)
148 0 : .Comp(iComp)
149 0 : .NodeNumIn;
150 :
151 : // Match inlet node name of calling branch to determine if this call is for heating or cooling
152 0 : if (compInletNodeNum == this->ChillReturnNodeNum) { // Operate as chiller
153 0 : brIdentity = DataPlant::BrLoopType::Chiller; // chiller
154 0 : break;
155 0 : } else if (compInletNodeNum == this->HeatReturnNodeNum) { // Operate as heater
156 0 : brIdentity = DataPlant::BrLoopType::Heater; // heater
157 0 : break;
158 0 : } else if (compInletNodeNum == this->CondReturnNodeNum) { // called from condenser loop
159 0 : brIdentity = DataPlant::BrLoopType::Condenser; // condenser
160 0 : break;
161 : } else {
162 0 : brIdentity = DataPlant::BrLoopType::NoMatch;
163 : }
164 : }
165 :
166 0 : if (brIdentity == DataPlant::BrLoopType::Chiller) {
167 0 : this->InCoolingMode = RunFlag != 0;
168 0 : this->initialize(state);
169 0 : this->calcChiller(state, CurLoad);
170 0 : this->updateCoolRecords(state, CurLoad, RunFlag);
171 0 : } else if (brIdentity == DataPlant::BrLoopType::Heater) {
172 0 : this->InHeatingMode = RunFlag != 0;
173 0 : this->initialize(state);
174 0 : this->calcHeater(state, CurLoad, RunFlag);
175 0 : this->updateHeatRecords(state, CurLoad, RunFlag);
176 0 : } else if (brIdentity == DataPlant::BrLoopType::Condenser) {
177 0 : if (this->CDPlantLoc.loopNum > 0) {
178 0 : PlantUtilities::UpdateChillerComponentCondenserSide(state,
179 : this->CDPlantLoc.loopNum,
180 : this->CDPlantLoc.loopSideNum,
181 : DataPlant::PlantEquipmentType::Chiller_ExhFiredAbsorption,
182 : this->CondReturnNodeNum,
183 : this->CondSupplyNodeNum,
184 : this->TowerLoad,
185 : this->CondReturnTemp,
186 : this->CondSupplyTemp,
187 : this->CondWaterFlowRate,
188 : FirstHVACIteration);
189 : }
190 : } else {
191 : // Error, nodes do not match
192 0 : ShowSevereError(state, format("Invalid call to Exhaust Absorber Chiller {}", this->Name));
193 0 : ShowContinueError(state, "Node connections in branch are not consistent with object nodes.");
194 0 : ShowFatalError(state, "Preceding conditions cause termination.");
195 : }
196 0 : }
197 :
198 3 : void ExhaustAbsorberSpecs::getDesignCapacities(
199 : EnergyPlusData &state, const PlantLocation &calledFromLocation, Real64 &MaxLoad, Real64 &MinLoad, Real64 &OptLoad)
200 : {
201 3 : bool matchfound(false);
202 :
203 3 : int branchTotalComp = state.dataPlnt->PlantLoop(calledFromLocation.loopNum)
204 3 : .LoopSide(calledFromLocation.loopSideNum)
205 3 : .Branch(calledFromLocation.branchNum)
206 3 : .TotalComponents;
207 :
208 6 : for (int iComp = 1; iComp <= branchTotalComp; iComp++) {
209 : // kind of a hacky way to find the location of this, but it's what plantloopequip was doing
210 6 : int compInletNodeNum = state.dataPlnt->PlantLoop(calledFromLocation.loopNum)
211 6 : .LoopSide(calledFromLocation.loopSideNum)
212 6 : .Branch(calledFromLocation.branchNum)
213 6 : .Comp(iComp)
214 6 : .NodeNumIn;
215 :
216 : // Match inlet node name of calling branch to determine if this call is for heating or cooling
217 6 : if (compInletNodeNum == this->ChillReturnNodeNum) { // Operate as chiller
218 1 : MinLoad = this->NomCoolingCap * this->MinPartLoadRat;
219 1 : MaxLoad = this->NomCoolingCap * this->MaxPartLoadRat;
220 1 : OptLoad = this->NomCoolingCap * this->OptPartLoadRat;
221 1 : matchfound = true;
222 1 : break;
223 5 : } else if (compInletNodeNum == this->HeatReturnNodeNum) { // Operate as heater
224 1 : Real64 Sim_HeatCap = this->NomCoolingCap * this->NomHeatCoolRatio; // W - nominal heating capacity
225 1 : MinLoad = Sim_HeatCap * this->MinPartLoadRat;
226 1 : MaxLoad = Sim_HeatCap * this->MaxPartLoadRat;
227 1 : OptLoad = Sim_HeatCap * this->OptPartLoadRat;
228 1 : matchfound = true;
229 1 : break;
230 4 : } else if (compInletNodeNum == this->CondReturnNodeNum) { // called from condenser loop
231 1 : MinLoad = 0.0;
232 1 : MaxLoad = 0.0;
233 1 : OptLoad = 0.0;
234 1 : matchfound = true;
235 1 : break;
236 : } else {
237 3 : matchfound = false;
238 : }
239 : }
240 :
241 3 : if (!matchfound) {
242 : // Error, nodes do not match
243 0 : ShowSevereError(state, format("SimExhaustAbsorber: Invalid call to Exhaust Absorption Chiller-Heater {}", this->Name));
244 0 : ShowContinueError(state, "Node connections in branch are not consistent with object nodes.");
245 0 : ShowFatalError(state, "Preceding conditions cause termination.");
246 : } // Operate as Chiller or Heater
247 3 : }
248 :
249 0 : void ExhaustAbsorberSpecs::getSizingFactor(Real64 &_SizFac)
250 : {
251 0 : _SizFac = this->SizFac;
252 0 : }
253 :
254 0 : void ExhaustAbsorberSpecs::onInitLoopEquip(EnergyPlusData &state, const PlantLocation &calledFromLocation)
255 : {
256 0 : this->initialize(state);
257 :
258 : // kind of a hacky way to find the location of this, but it's what plantloopequip was doing
259 : int BranchInletNodeNum =
260 0 : state.dataPlnt->PlantLoop(calledFromLocation.loopNum).LoopSide(calledFromLocation.loopSideNum).Branch(calledFromLocation.branchNum).NodeNumIn;
261 :
262 0 : if (BranchInletNodeNum == this->ChillReturnNodeNum) { // Operate as chiller
263 0 : this->size(state); // only call from chilled water loop
264 : } else {
265 : // don't do anything here
266 : }
267 0 : }
268 :
269 0 : void ExhaustAbsorberSpecs::getDesignTemperatures(Real64 &TempDesCondIn, Real64 &TempDesEvapOut)
270 : {
271 0 : TempDesEvapOut = this->TempDesCHWSupply;
272 0 : TempDesCondIn = this->TempDesCondReturn;
273 0 : }
274 :
275 4 : void GetExhaustAbsorberInput(EnergyPlusData &state)
276 : {
277 : // SUBROUTINE INFORMATION:
278 : // AUTHOR: Jason Glazer
279 : // DATE WRITTEN: March 2001
280 : // MODIFIED Mahabir Bhandari, ORNL, Aug 2011, modified to accommodate Exhaust Fired Double Effect Absorption Chiller
281 :
282 : // PURPOSE OF THIS SUBROUTINE:
283 : // This routine will get the input
284 : // required by the Exhaust Fired Absorption chiller model in the object ChillerHeater:Absorption:DoubleEffect
285 :
286 : // METHODOLOGY EMPLOYED:
287 : // EnergyPlus input processor
288 : static constexpr std::string_view routineName = "GetExhaustAbsorberInput";
289 :
290 : // LOCAL VARIABLES
291 : int NumAlphas; // Number of elements in the alpha array
292 : int NumNums; // Number of elements in the numeric array
293 : int IOStat; // IO Status when calling get input subroutine
294 : bool Okay;
295 4 : bool Get_ErrorsFound(false);
296 :
297 4 : auto &s_ipsc = state.dataIPShortCut;
298 :
299 4 : std::string_view cCurrentModuleObject = "ChillerHeater:Absorption:DoubleEffect";
300 4 : int NumExhaustAbsorbers = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
301 :
302 4 : if (NumExhaustAbsorbers <= 0) {
303 0 : ShowSevereError(state, format("No {} equipment found in input file", cCurrentModuleObject));
304 0 : Get_ErrorsFound = true;
305 : }
306 :
307 4 : if (allocated(state.dataChillerExhaustAbsorption->ExhaustAbsorber)) {
308 0 : return;
309 : }
310 :
311 : // ALLOCATE ARRAYS
312 4 : state.dataChillerExhaustAbsorption->ExhaustAbsorber.allocate(NumExhaustAbsorbers);
313 :
314 : // LOAD ARRAYS
315 :
316 10 : for (int AbsorberNum = 1; AbsorberNum <= NumExhaustAbsorbers; ++AbsorberNum) {
317 18 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
318 : cCurrentModuleObject,
319 : AbsorberNum,
320 6 : s_ipsc->cAlphaArgs,
321 : NumAlphas,
322 6 : s_ipsc->rNumericArgs,
323 : NumNums,
324 : IOStat,
325 : _,
326 6 : s_ipsc->lAlphaFieldBlanks,
327 6 : s_ipsc->cAlphaFieldNames,
328 6 : s_ipsc->cNumericFieldNames);
329 :
330 6 : ErrorObjectHeader eoh{routineName, cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
331 :
332 : // Get_ErrorsFound will be set to True if problem was found, left untouched otherwise
333 6 : GlobalNames::VerifyUniqueChillerName(
334 6 : state, cCurrentModuleObject, s_ipsc->cAlphaArgs(1), Get_ErrorsFound, fmt::format("{} Name", cCurrentModuleObject));
335 :
336 6 : auto &thisChiller = state.dataChillerExhaustAbsorption->ExhaustAbsorber(AbsorberNum);
337 6 : thisChiller.Name = s_ipsc->cAlphaArgs(1);
338 6 : std::string ChillerName = fmt::format("{} Named {}", cCurrentModuleObject, thisChiller.Name);
339 :
340 : // Assign capacities
341 6 : thisChiller.NomCoolingCap = s_ipsc->rNumericArgs(1);
342 6 : if (thisChiller.NomCoolingCap == DataSizing::AutoSize) {
343 0 : thisChiller.NomCoolingCapWasAutoSized = true;
344 : }
345 6 : thisChiller.NomHeatCoolRatio = s_ipsc->rNumericArgs(2);
346 : // Assign efficiencies
347 6 : thisChiller.ThermalEnergyCoolRatio = s_ipsc->rNumericArgs(3);
348 6 : thisChiller.ThermalEnergyHeatRatio = s_ipsc->rNumericArgs(4);
349 6 : thisChiller.ElecCoolRatio = s_ipsc->rNumericArgs(5);
350 6 : thisChiller.ElecHeatRatio = s_ipsc->rNumericArgs(6);
351 :
352 : // Assign Node Numbers to specified nodes
353 6 : thisChiller.ChillReturnNodeNum = NodeInputManager::GetOnlySingleNode(state,
354 6 : s_ipsc->cAlphaArgs(2),
355 : Get_ErrorsFound,
356 : DataLoopNode::ConnectionObjectType::ChillerHeaterAbsorptionDoubleEffect,
357 6 : s_ipsc->cAlphaArgs(1),
358 : DataLoopNode::NodeFluidType::Water,
359 : DataLoopNode::ConnectionType::Inlet,
360 : NodeInputManager::CompFluidStream::Primary,
361 : DataLoopNode::ObjectIsNotParent);
362 12 : thisChiller.ChillSupplyNodeNum = NodeInputManager::GetOnlySingleNode(state,
363 6 : s_ipsc->cAlphaArgs(3),
364 : Get_ErrorsFound,
365 : DataLoopNode::ConnectionObjectType::ChillerHeaterAbsorptionDoubleEffect,
366 6 : s_ipsc->cAlphaArgs(1),
367 : DataLoopNode::NodeFluidType::Water,
368 : DataLoopNode::ConnectionType::Outlet,
369 : NodeInputManager::CompFluidStream::Primary,
370 : DataLoopNode::ObjectIsNotParent);
371 12 : BranchNodeConnections::TestCompSet(
372 6 : state, cCurrentModuleObject, s_ipsc->cAlphaArgs(1), s_ipsc->cAlphaArgs(2), s_ipsc->cAlphaArgs(3), "Chilled Water Nodes");
373 : // Condenser node processing depends on condenser type, see below
374 6 : thisChiller.HeatReturnNodeNum = NodeInputManager::GetOnlySingleNode(state,
375 6 : s_ipsc->cAlphaArgs(6),
376 : Get_ErrorsFound,
377 : DataLoopNode::ConnectionObjectType::ChillerHeaterAbsorptionDoubleEffect,
378 6 : s_ipsc->cAlphaArgs(1),
379 : DataLoopNode::NodeFluidType::Water,
380 : DataLoopNode::ConnectionType::Inlet,
381 : NodeInputManager::CompFluidStream::Tertiary,
382 : DataLoopNode::ObjectIsNotParent);
383 12 : thisChiller.HeatSupplyNodeNum = NodeInputManager::GetOnlySingleNode(state,
384 6 : s_ipsc->cAlphaArgs(7),
385 : Get_ErrorsFound,
386 : DataLoopNode::ConnectionObjectType::ChillerHeaterAbsorptionDoubleEffect,
387 6 : s_ipsc->cAlphaArgs(1),
388 : DataLoopNode::NodeFluidType::Water,
389 : DataLoopNode::ConnectionType::Outlet,
390 : NodeInputManager::CompFluidStream::Tertiary,
391 : DataLoopNode::ObjectIsNotParent);
392 12 : BranchNodeConnections::TestCompSet(
393 6 : state, cCurrentModuleObject, s_ipsc->cAlphaArgs(1), s_ipsc->cAlphaArgs(6), s_ipsc->cAlphaArgs(7), "Hot Water Nodes");
394 6 : if (Get_ErrorsFound) {
395 0 : ShowFatalError(state, format("Errors found in processing node input for {}={}", cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
396 0 : Get_ErrorsFound = false;
397 : }
398 :
399 : // Assign Part Load Ratios
400 6 : thisChiller.MinPartLoadRat = s_ipsc->rNumericArgs(7);
401 6 : thisChiller.MaxPartLoadRat = s_ipsc->rNumericArgs(8);
402 6 : thisChiller.OptPartLoadRat = s_ipsc->rNumericArgs(9);
403 : // Assign Design Conditions
404 6 : thisChiller.TempDesCondReturn = s_ipsc->rNumericArgs(10);
405 6 : thisChiller.TempDesCHWSupply = s_ipsc->rNumericArgs(11);
406 6 : thisChiller.EvapVolFlowRate = s_ipsc->rNumericArgs(12);
407 6 : if (thisChiller.EvapVolFlowRate == DataSizing::AutoSize) {
408 0 : thisChiller.EvapVolFlowRateWasAutoSized = true;
409 : }
410 6 : if (Util::SameString(s_ipsc->cAlphaArgs(16), "AirCooled")) {
411 6 : thisChiller.CondVolFlowRate = 0.0011; // Condenser flow rate not used for this cond type
412 : } else {
413 0 : thisChiller.CondVolFlowRate = s_ipsc->rNumericArgs(13);
414 0 : if (thisChiller.CondVolFlowRate == DataSizing::AutoSize) {
415 0 : thisChiller.CondVolFlowRateWasAutoSized = true;
416 : }
417 : }
418 6 : thisChiller.HeatVolFlowRate = s_ipsc->rNumericArgs(14);
419 6 : if (thisChiller.HeatVolFlowRate == DataSizing::AutoSize) {
420 0 : thisChiller.HeatVolFlowRateWasAutoSized = true;
421 : }
422 : // Assign Curve Numbers
423 6 : if (s_ipsc->lAlphaFieldBlanks(8)) {
424 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(8));
425 0 : Get_ErrorsFound = true;
426 6 : } else if ((thisChiller.CoolCapFTCurve = Curve::GetCurve(state, s_ipsc->cAlphaArgs(8))) == nullptr) {
427 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(8), s_ipsc->cAlphaArgs(8));
428 0 : Get_ErrorsFound = true;
429 : }
430 :
431 6 : if (s_ipsc->lAlphaFieldBlanks(9)) {
432 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(9));
433 0 : Get_ErrorsFound = true;
434 6 : } else if ((thisChiller.ThermalEnergyCoolFTCurve = Curve::GetCurve(state, s_ipsc->cAlphaArgs(9))) == nullptr) {
435 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(9), s_ipsc->cAlphaArgs(9));
436 0 : Get_ErrorsFound = true;
437 : }
438 :
439 6 : if (s_ipsc->lAlphaFieldBlanks(10)) {
440 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(10));
441 0 : Get_ErrorsFound = true;
442 6 : } else if ((thisChiller.ThermalEnergyCoolFPLRCurve = Curve::GetCurve(state, s_ipsc->cAlphaArgs(10))) == nullptr) {
443 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(10), s_ipsc->cAlphaArgs(10));
444 0 : Get_ErrorsFound = true;
445 : }
446 :
447 6 : if (s_ipsc->lAlphaFieldBlanks(11)) {
448 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(11));
449 0 : Get_ErrorsFound = true;
450 6 : } else if ((thisChiller.ElecCoolFTCurve = Curve::GetCurve(state, s_ipsc->cAlphaArgs(11))) == nullptr) {
451 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(11), s_ipsc->cAlphaArgs(11));
452 0 : Get_ErrorsFound = true;
453 : }
454 :
455 6 : if (s_ipsc->lAlphaFieldBlanks(12)) {
456 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(12));
457 0 : Get_ErrorsFound = true;
458 6 : } else if ((thisChiller.ElecCoolFPLRCurve = Curve::GetCurve(state, s_ipsc->cAlphaArgs(12))) == nullptr) {
459 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(12), s_ipsc->cAlphaArgs(12));
460 0 : Get_ErrorsFound = true;
461 : }
462 :
463 6 : if (s_ipsc->lAlphaFieldBlanks(13)) {
464 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(13));
465 0 : Get_ErrorsFound = true;
466 6 : } else if ((thisChiller.HeatCapFCoolCurve = Curve::GetCurve(state, s_ipsc->cAlphaArgs(13))) == nullptr) {
467 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(13), s_ipsc->cAlphaArgs(13));
468 0 : Get_ErrorsFound = true;
469 : }
470 :
471 6 : if (s_ipsc->lAlphaFieldBlanks(14)) {
472 0 : ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(14));
473 0 : Get_ErrorsFound = true;
474 6 : } else if ((thisChiller.ThermalEnergyHeatFHPLRCurve = Curve::GetCurve(state, s_ipsc->cAlphaArgs(14))) == nullptr) {
475 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(14), s_ipsc->cAlphaArgs(14));
476 0 : Get_ErrorsFound = true;
477 : }
478 :
479 6 : if (Get_ErrorsFound) {
480 0 : ShowFatalError(state, format("Errors found in processing curve input for {}={}", cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
481 0 : Get_ErrorsFound = false;
482 : }
483 6 : if (Util::SameString(s_ipsc->cAlphaArgs(15), "LeavingCondenser")) {
484 0 : thisChiller.isEnterCondensTemp = false;
485 6 : } else if (Util::SameString(s_ipsc->cAlphaArgs(15), "EnteringCondenser")) {
486 6 : thisChiller.isEnterCondensTemp = true;
487 : } else {
488 0 : thisChiller.isEnterCondensTemp = true;
489 0 : ShowWarningError(state, format("Invalid {}={}", s_ipsc->cAlphaFieldNames(15), s_ipsc->cAlphaArgs(15)));
490 0 : ShowContinueError(state, format("Entered in {}={}", cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
491 0 : ShowContinueError(state, "resetting to ENTERING-CONDENSER, simulation continues");
492 : }
493 : // Assign Other Parameters
494 6 : if (Util::SameString(s_ipsc->cAlphaArgs(16), "AirCooled")) {
495 6 : thisChiller.isWaterCooled = false;
496 0 : } else if (Util::SameString(s_ipsc->cAlphaArgs(16), "WaterCooled")) {
497 0 : thisChiller.isWaterCooled = true;
498 : } else {
499 0 : thisChiller.isWaterCooled = true;
500 0 : ShowWarningError(state, format("Invalid {}={}", s_ipsc->cAlphaFieldNames(16), s_ipsc->cAlphaArgs(16)));
501 0 : ShowContinueError(state, format("Entered in {}={}", cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
502 0 : ShowContinueError(state, "resetting to WATER-COOLED, simulation continues");
503 : }
504 6 : if (!thisChiller.isEnterCondensTemp && !thisChiller.isWaterCooled) {
505 0 : thisChiller.isEnterCondensTemp = true;
506 0 : ShowWarningError(state, format("{}=\"{}\", invalid value", cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
507 0 : ShowContinueError(state, "Invalid to have both LeavingCondenser and AirCooled.");
508 0 : ShowContinueError(state, "resetting to EnteringCondenser, simulation continues");
509 : }
510 6 : if (thisChiller.isWaterCooled) {
511 0 : if (s_ipsc->lAlphaFieldBlanks(5)) {
512 0 : ShowSevereError(state, format("{}=\"{}\", invalid value", cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
513 0 : ShowContinueError(state, "For WaterCooled chiller the condenser outlet node is required.");
514 0 : Get_ErrorsFound = true;
515 : }
516 0 : thisChiller.CondReturnNodeNum =
517 0 : NodeInputManager::GetOnlySingleNode(state,
518 0 : s_ipsc->cAlphaArgs(4),
519 : Get_ErrorsFound,
520 : DataLoopNode::ConnectionObjectType::ChillerHeaterAbsorptionDoubleEffect,
521 0 : s_ipsc->cAlphaArgs(1),
522 : DataLoopNode::NodeFluidType::Water,
523 : DataLoopNode::ConnectionType::Inlet,
524 : NodeInputManager::CompFluidStream::Secondary,
525 : DataLoopNode::ObjectIsNotParent);
526 0 : thisChiller.CondSupplyNodeNum =
527 0 : NodeInputManager::GetOnlySingleNode(state,
528 0 : s_ipsc->cAlphaArgs(5),
529 : Get_ErrorsFound,
530 : DataLoopNode::ConnectionObjectType::ChillerHeaterAbsorptionDoubleEffect,
531 0 : s_ipsc->cAlphaArgs(1),
532 : DataLoopNode::NodeFluidType::Water,
533 : DataLoopNode::ConnectionType::Outlet,
534 : NodeInputManager::CompFluidStream::Secondary,
535 : DataLoopNode::ObjectIsNotParent);
536 0 : BranchNodeConnections::TestCompSet(
537 0 : state, cCurrentModuleObject, s_ipsc->cAlphaArgs(1), s_ipsc->cAlphaArgs(4), s_ipsc->cAlphaArgs(5), "Condenser Water Nodes");
538 : } else {
539 6 : thisChiller.CondReturnNodeNum =
540 6 : NodeInputManager::GetOnlySingleNode(state,
541 6 : s_ipsc->cAlphaArgs(4),
542 : Get_ErrorsFound,
543 : DataLoopNode::ConnectionObjectType::ChillerHeaterAbsorptionDoubleEffect,
544 6 : s_ipsc->cAlphaArgs(1),
545 : DataLoopNode::NodeFluidType::Air,
546 : DataLoopNode::ConnectionType::OutsideAirReference,
547 : NodeInputManager::CompFluidStream::Secondary,
548 : DataLoopNode::ObjectIsNotParent);
549 : // Condenser outlet node not used for air or evap cooled condenser so ignore cAlphaArgs( 5 )
550 : // Connection not required for air or evap cooled condenser so no call to TestCompSet here
551 6 : OutAirNodeManager::CheckAndAddAirNodeNumber(state, thisChiller.CondReturnNodeNum, Okay);
552 6 : if (!Okay) {
553 0 : ShowWarningError(state, format("{}, Adding OutdoorAir:Node={}", cCurrentModuleObject, s_ipsc->cAlphaArgs(4)));
554 : }
555 : }
556 :
557 6 : thisChiller.CHWLowLimitTemp = s_ipsc->rNumericArgs(15);
558 6 : thisChiller.SizFac = s_ipsc->rNumericArgs(16);
559 6 : thisChiller.TypeOf = s_ipsc->cAlphaArgs(17);
560 :
561 6 : if (Util::SameString(s_ipsc->cAlphaArgs(17), "Generator:MicroTurbine")) {
562 6 : thisChiller.CompType_Num = GeneratorType::Microturbine;
563 6 : thisChiller.ExhaustSourceName = s_ipsc->cAlphaArgs(18);
564 :
565 6 : auto *thisMTG = MicroturbineElectricGenerator::MTGeneratorSpecs::factory(state, thisChiller.ExhaustSourceName);
566 6 : thisChiller.ExhaustAirInletNodeNum = dynamic_cast<MicroturbineElectricGenerator::MTGeneratorSpecs *>(thisMTG)->CombustionAirOutletNodeNum;
567 : }
568 6 : }
569 :
570 4 : if (Get_ErrorsFound) {
571 0 : ShowFatalError(state, format("Errors found in processing input for {}", cCurrentModuleObject));
572 : }
573 : }
574 :
575 0 : void ExhaustAbsorberSpecs::setupOutputVariables(EnergyPlusData &state)
576 : {
577 0 : std::string const ChillerName = this->Name;
578 :
579 0 : SetupOutputVariable(state,
580 : "Chiller Heater Evaporator Cooling Rate",
581 : Constant::Units::W,
582 0 : this->CoolingLoad,
583 : OutputProcessor::TimeStepType::System,
584 : OutputProcessor::StoreType::Average,
585 : ChillerName);
586 0 : SetupOutputVariable(state,
587 : "Chiller Heater Evaporator Cooling Energy",
588 : Constant::Units::J,
589 0 : this->CoolingEnergy,
590 : OutputProcessor::TimeStepType::System,
591 : OutputProcessor::StoreType::Sum,
592 : ChillerName,
593 : Constant::eResource::EnergyTransfer,
594 : OutputProcessor::Group::Plant,
595 : OutputProcessor::EndUseCat::Chillers);
596 :
597 0 : SetupOutputVariable(state,
598 : "Chiller Heater Heating Rate",
599 : Constant::Units::W,
600 0 : this->HeatingLoad,
601 : OutputProcessor::TimeStepType::System,
602 : OutputProcessor::StoreType::Average,
603 : ChillerName);
604 0 : SetupOutputVariable(state,
605 : "Chiller Heater Heating Energy",
606 : Constant::Units::J,
607 0 : this->HeatingEnergy,
608 : OutputProcessor::TimeStepType::System,
609 : OutputProcessor::StoreType::Sum,
610 : ChillerName,
611 : Constant::eResource::EnergyTransfer,
612 : OutputProcessor::Group::Plant,
613 : OutputProcessor::EndUseCat::Boilers);
614 :
615 0 : SetupOutputVariable(state,
616 : "Chiller Heater Condenser Heat Transfer Rate",
617 : Constant::Units::W,
618 0 : this->TowerLoad,
619 : OutputProcessor::TimeStepType::System,
620 : OutputProcessor::StoreType::Average,
621 : ChillerName);
622 0 : SetupOutputVariable(state,
623 : "Chiller Heater Condenser Heat Transfer Energy",
624 : Constant::Units::J,
625 0 : this->TowerEnergy,
626 : OutputProcessor::TimeStepType::System,
627 : OutputProcessor::StoreType::Sum,
628 : ChillerName,
629 : Constant::eResource::EnergyTransfer,
630 : OutputProcessor::Group::Plant,
631 : OutputProcessor::EndUseCat::HeatRejection);
632 :
633 0 : SetupOutputVariable(state,
634 : "Chiller Heater Cooling Source Heat COP",
635 : Constant::Units::W_W,
636 0 : this->ThermalEnergyCOP,
637 : OutputProcessor::TimeStepType::System,
638 : OutputProcessor::StoreType::Average,
639 : ChillerName);
640 :
641 0 : SetupOutputVariable(state,
642 : "Chiller Heater Electricity Rate",
643 : Constant::Units::W,
644 0 : this->ElectricPower,
645 : OutputProcessor::TimeStepType::System,
646 : OutputProcessor::StoreType::Average,
647 : ChillerName);
648 : // Do not include this on meters, this would duplicate the cool electric and heat electric
649 0 : SetupOutputVariable(state,
650 : "Chiller Heater Electricity Energy",
651 : Constant::Units::J,
652 0 : this->ElectricEnergy,
653 : OutputProcessor::TimeStepType::System,
654 : OutputProcessor::StoreType::Sum,
655 : ChillerName);
656 :
657 0 : SetupOutputVariable(state,
658 : "Chiller Heater Cooling Electricity Rate",
659 : Constant::Units::W,
660 0 : this->CoolElectricPower,
661 : OutputProcessor::TimeStepType::System,
662 : OutputProcessor::StoreType::Average,
663 : ChillerName);
664 0 : SetupOutputVariable(state,
665 : "Chiller Heater Cooling Electricity Energy",
666 : Constant::Units::J,
667 0 : this->CoolElectricEnergy,
668 : OutputProcessor::TimeStepType::System,
669 : OutputProcessor::StoreType::Sum,
670 : ChillerName,
671 : Constant::eResource::Electricity,
672 : OutputProcessor::Group::Plant,
673 : OutputProcessor::EndUseCat::Cooling);
674 :
675 0 : SetupOutputVariable(state,
676 : "Chiller Heater Heating Electricity Rate",
677 : Constant::Units::W,
678 0 : this->HeatElectricPower,
679 : OutputProcessor::TimeStepType::System,
680 : OutputProcessor::StoreType::Average,
681 : ChillerName);
682 0 : SetupOutputVariable(state,
683 : "Chiller Heater Heating Electricity Energy",
684 : Constant::Units::J,
685 0 : this->HeatElectricEnergy,
686 : OutputProcessor::TimeStepType::System,
687 : OutputProcessor::StoreType::Sum,
688 : ChillerName,
689 : Constant::eResource::Electricity,
690 : OutputProcessor::Group::Plant,
691 : OutputProcessor::EndUseCat::Heating);
692 :
693 0 : SetupOutputVariable(state,
694 : "Chiller Heater Evaporator Inlet Temperature",
695 : Constant::Units::C,
696 0 : this->ChillReturnTemp,
697 : OutputProcessor::TimeStepType::System,
698 : OutputProcessor::StoreType::Average,
699 : ChillerName);
700 0 : SetupOutputVariable(state,
701 : "Chiller Heater Evaporator Outlet Temperature",
702 : Constant::Units::C,
703 0 : this->ChillSupplyTemp,
704 : OutputProcessor::TimeStepType::System,
705 : OutputProcessor::StoreType::Average,
706 : ChillerName);
707 0 : SetupOutputVariable(state,
708 : "Chiller Heater Evaporator Mass Flow Rate",
709 : Constant::Units::kg_s,
710 0 : this->ChillWaterFlowRate,
711 : OutputProcessor::TimeStepType::System,
712 : OutputProcessor::StoreType::Average,
713 : ChillerName);
714 :
715 0 : if (this->isWaterCooled) {
716 0 : SetupOutputVariable(state,
717 : "Chiller Heater Condenser Inlet Temperature",
718 : Constant::Units::C,
719 0 : this->CondReturnTemp,
720 : OutputProcessor::TimeStepType::System,
721 : OutputProcessor::StoreType::Average,
722 : ChillerName);
723 0 : SetupOutputVariable(state,
724 : "Chiller Heater Condenser Outlet Temperature",
725 : Constant::Units::C,
726 0 : this->CondSupplyTemp,
727 : OutputProcessor::TimeStepType::System,
728 : OutputProcessor::StoreType::Average,
729 : ChillerName);
730 0 : SetupOutputVariable(state,
731 : "Chiller Heater Condenser Mass Flow Rate",
732 : Constant::Units::kg_s,
733 0 : this->CondWaterFlowRate,
734 : OutputProcessor::TimeStepType::System,
735 : OutputProcessor::StoreType::Average,
736 : ChillerName);
737 : } else {
738 0 : SetupOutputVariable(state,
739 : "Chiller Heater Condenser Inlet Temperature",
740 : Constant::Units::C,
741 0 : this->CondReturnTemp,
742 : OutputProcessor::TimeStepType::System,
743 : OutputProcessor::StoreType::Average,
744 : ChillerName);
745 : }
746 :
747 0 : SetupOutputVariable(state,
748 : "Chiller Heater Heating Inlet Temperature",
749 : Constant::Units::C,
750 0 : this->HotWaterReturnTemp,
751 : OutputProcessor::TimeStepType::System,
752 : OutputProcessor::StoreType::Average,
753 : ChillerName);
754 0 : SetupOutputVariable(state,
755 : "Chiller Heater Heating Outlet Temperature",
756 : Constant::Units::C,
757 0 : this->HotWaterSupplyTemp,
758 : OutputProcessor::TimeStepType::System,
759 : OutputProcessor::StoreType::Average,
760 : ChillerName);
761 0 : SetupOutputVariable(state,
762 : "Chiller Heater Heating Mass Flow Rate",
763 : Constant::Units::kg_s,
764 0 : this->HotWaterFlowRate,
765 : OutputProcessor::TimeStepType::System,
766 : OutputProcessor::StoreType::Average,
767 : ChillerName);
768 :
769 0 : SetupOutputVariable(state,
770 : "Chiller Heater Cooling Part Load Ratio",
771 : Constant::Units::None,
772 0 : this->CoolPartLoadRatio,
773 : OutputProcessor::TimeStepType::System,
774 : OutputProcessor::StoreType::Average,
775 : ChillerName);
776 0 : SetupOutputVariable(state,
777 : "Chiller Heater Maximum Cooling Rate",
778 : Constant::Units::W,
779 0 : this->CoolingCapacity,
780 : OutputProcessor::TimeStepType::System,
781 : OutputProcessor::StoreType::Average,
782 : ChillerName);
783 0 : SetupOutputVariable(state,
784 : "Chiller Heater Heating Part Load Ratio",
785 : Constant::Units::None,
786 0 : this->HeatPartLoadRatio,
787 : OutputProcessor::TimeStepType::System,
788 : OutputProcessor::StoreType::Average,
789 : ChillerName);
790 0 : SetupOutputVariable(state,
791 : "Chiller Heater Maximum Heating Rate",
792 : Constant::Units::W,
793 0 : this->HeatingCapacity,
794 : OutputProcessor::TimeStepType::System,
795 : OutputProcessor::StoreType::Average,
796 : ChillerName);
797 :
798 0 : SetupOutputVariable(state,
799 : "Chiller Heater Runtime Fraction",
800 : Constant::Units::None,
801 0 : this->FractionOfPeriodRunning,
802 : OutputProcessor::TimeStepType::System,
803 : OutputProcessor::StoreType::Average,
804 : ChillerName);
805 :
806 0 : SetupOutputVariable(state,
807 : "Chiller Heater Source Exhaust Inlet Temperature",
808 : Constant::Units::C,
809 0 : this->ExhaustInTemp,
810 : OutputProcessor::TimeStepType::System,
811 : OutputProcessor::StoreType::Average,
812 : ChillerName);
813 0 : SetupOutputVariable(state,
814 : "Chiller Heater Source Exhaust Inlet Mass Flow Rate",
815 : Constant::Units::kg_s,
816 0 : this->ExhaustInFlow,
817 : OutputProcessor::TimeStepType::System,
818 : OutputProcessor::StoreType::Average,
819 : ChillerName);
820 :
821 0 : SetupOutputVariable(state,
822 : "Chiller Heater Heating Heat Recovery Potential Rate",
823 : Constant::Units::W,
824 0 : this->ExhHeatRecPotentialHeat,
825 : OutputProcessor::TimeStepType::System,
826 : OutputProcessor::StoreType::Average,
827 : ChillerName);
828 0 : SetupOutputVariable(state,
829 : "Chiller Heater Cooling Heat Recovery Potential Rate",
830 : Constant::Units::W,
831 0 : this->ExhHeatRecPotentialCool,
832 : OutputProcessor::TimeStepType::System,
833 : OutputProcessor::StoreType::Average,
834 : ChillerName);
835 :
836 0 : SetupOutputVariable(state,
837 : "Chiller Heater Cooling Source Heat Transfer Rate",
838 : Constant::Units::W,
839 0 : this->CoolThermalEnergyUseRate,
840 : OutputProcessor::TimeStepType::System,
841 : OutputProcessor::StoreType::Average,
842 : ChillerName);
843 0 : SetupOutputVariable(state,
844 : "Chiller Heater Heating Source Heat Transfer Rate",
845 : Constant::Units::W,
846 0 : this->HeatThermalEnergyUseRate,
847 : OutputProcessor::TimeStepType::System,
848 : OutputProcessor::StoreType::Average,
849 : ChillerName);
850 0 : }
851 :
852 0 : void ExhaustAbsorberSpecs::oneTimeInit_new(EnergyPlusData &state)
853 : {
854 0 : this->setupOutputVariables(state);
855 :
856 0 : bool errFlag = false;
857 0 : PlantUtilities::ScanPlantLoopsForObject(state,
858 : this->Name,
859 : DataPlant::PlantEquipmentType::Chiller_ExhFiredAbsorption,
860 0 : this->CWPlantLoc,
861 : errFlag,
862 0 : this->CHWLowLimitTemp,
863 : _,
864 : _,
865 0 : this->ChillReturnNodeNum,
866 : _);
867 0 : if (errFlag) {
868 0 : ShowFatalError(state, "InitExhaustAbsorber: Program terminated due to previous condition(s).");
869 : }
870 :
871 0 : PlantUtilities::ScanPlantLoopsForObject(
872 0 : state, this->Name, DataPlant::PlantEquipmentType::Chiller_ExhFiredAbsorption, this->HWPlantLoc, errFlag, _, _, _, this->HeatReturnNodeNum, _);
873 0 : if (errFlag) {
874 0 : ShowFatalError(state, "InitExhaustAbsorber: Program terminated due to previous condition(s).");
875 : }
876 :
877 0 : if (this->isWaterCooled) {
878 0 : PlantUtilities::ScanPlantLoopsForObject(state,
879 : this->Name,
880 : DataPlant::PlantEquipmentType::Chiller_ExhFiredAbsorption,
881 0 : this->CDPlantLoc,
882 : errFlag,
883 : _,
884 : _,
885 : _,
886 0 : this->CondReturnNodeNum,
887 : _);
888 0 : if (errFlag) {
889 0 : ShowFatalError(state, "InitExhaustAbsorber: Program terminated due to previous condition(s).");
890 : }
891 0 : PlantUtilities::InterConnectTwoPlantLoopSides(
892 0 : state, this->CWPlantLoc, this->CDPlantLoc, DataPlant::PlantEquipmentType::Chiller_ExhFiredAbsorption, true);
893 0 : PlantUtilities::InterConnectTwoPlantLoopSides(
894 0 : state, this->HWPlantLoc, this->CDPlantLoc, DataPlant::PlantEquipmentType::Chiller_ExhFiredAbsorption, true);
895 : }
896 :
897 0 : PlantUtilities::InterConnectTwoPlantLoopSides(
898 0 : state, this->CWPlantLoc, this->HWPlantLoc, DataPlant::PlantEquipmentType::Chiller_ExhFiredAbsorption, true);
899 :
900 : // check if outlet node of chilled water side has a setpoint.
901 0 : if ((state.dataLoopNodes->Node(this->ChillSupplyNodeNum).TempSetPoint == DataLoopNode::SensedNodeFlagValue) &&
902 0 : (state.dataLoopNodes->Node(this->ChillSupplyNodeNum).TempSetPointHi == DataLoopNode::SensedNodeFlagValue)) {
903 0 : if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
904 0 : if (!this->ChillSetPointErrDone) {
905 0 : ShowWarningError(state, format("Missing temperature setpoint on cool side for chiller heater named {}", this->Name));
906 0 : ShowContinueError(state, " A temperature setpoint is needed at the outlet node of this chiller, use a SetpointManager");
907 0 : ShowContinueError(state, " The overall loop setpoint will be assumed for chiller. The simulation continues ... ");
908 0 : this->ChillSetPointErrDone = true;
909 : }
910 : } else {
911 : // need call to EMS to check node
912 0 : errFlag = false; // but not really fatal yet, but should be.
913 0 : EMSManager::CheckIfNodeSetPointManagedByEMS(state, this->ChillSupplyNodeNum, HVAC::CtrlVarType::Temp, errFlag);
914 0 : state.dataLoopNodes->NodeSetpointCheck(this->ChillSupplyNodeNum).needsSetpointChecking = false;
915 0 : if (errFlag) {
916 0 : if (!this->ChillSetPointErrDone) {
917 0 : ShowWarningError(state, format("Missing temperature setpoint on cool side for chiller heater named {}", this->Name));
918 0 : ShowContinueError(state, " A temperature setpoint is needed at the outlet node of this chiller evaporator ");
919 0 : ShowContinueError(state, " use a Setpoint Manager to establish a setpoint at the chiller evaporator outlet node ");
920 0 : ShowContinueError(state, " or use an EMS actuator to establish a setpoint at the outlet node ");
921 0 : ShowContinueError(state, " The overall loop setpoint will be assumed for chiller. The simulation continues ... ");
922 0 : this->ChillSetPointErrDone = true;
923 : }
924 : }
925 : }
926 0 : this->ChillSetPointSetToLoop = true;
927 0 : state.dataLoopNodes->Node(this->ChillSupplyNodeNum).TempSetPoint =
928 0 : state.dataLoopNodes->Node(state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).TempSetPointNodeNum).TempSetPoint;
929 0 : state.dataLoopNodes->Node(this->ChillSupplyNodeNum).TempSetPointHi =
930 0 : state.dataLoopNodes->Node(state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).TempSetPointNodeNum).TempSetPointHi;
931 : }
932 : // check if outlet node of hot water side has a setpoint.
933 0 : if ((state.dataLoopNodes->Node(this->HeatSupplyNodeNum).TempSetPoint == DataLoopNode::SensedNodeFlagValue) &&
934 0 : (state.dataLoopNodes->Node(this->HeatSupplyNodeNum).TempSetPointLo == DataLoopNode::SensedNodeFlagValue)) {
935 0 : if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
936 0 : if (!this->HeatSetPointErrDone) {
937 0 : ShowWarningError(state, format("Missing temperature setpoint on heat side for chiller heater named {}", this->Name));
938 0 : ShowContinueError(state, " A temperature setpoint is needed at the outlet node of this chiller, use a SetpointManager");
939 0 : ShowContinueError(state, " The overall loop setpoint will be assumed for chiller. The simulation continues ... ");
940 0 : this->HeatSetPointErrDone = true;
941 : }
942 : } else {
943 : // need call to EMS to check node
944 0 : errFlag = false; // but not really fatal yet, but should be.
945 0 : EMSManager::CheckIfNodeSetPointManagedByEMS(state, this->HeatSupplyNodeNum, HVAC::CtrlVarType::Temp, errFlag);
946 0 : state.dataLoopNodes->NodeSetpointCheck(this->HeatSupplyNodeNum).needsSetpointChecking = false;
947 0 : if (errFlag) {
948 0 : if (!this->HeatSetPointErrDone) {
949 0 : ShowWarningError(state, format("Missing temperature setpoint on heat side for chiller heater named {}", this->Name));
950 0 : ShowContinueError(state, " A temperature setpoint is needed at the outlet node of this chiller heater ");
951 0 : ShowContinueError(state, " use a Setpoint Manager to establish a setpoint at the heater side outlet node ");
952 0 : ShowContinueError(state, " or use an EMS actuator to establish a setpoint at the outlet node ");
953 0 : ShowContinueError(state, " The overall loop setpoint will be assumed for heater side. The simulation continues ... ");
954 0 : this->HeatSetPointErrDone = true;
955 : }
956 : }
957 : }
958 0 : this->HeatSetPointSetToLoop = true;
959 0 : state.dataLoopNodes->Node(this->HeatSupplyNodeNum).TempSetPoint =
960 0 : state.dataLoopNodes->Node(state.dataPlnt->PlantLoop(this->HWPlantLoc.loopNum).TempSetPointNodeNum).TempSetPoint;
961 0 : state.dataLoopNodes->Node(this->HeatSupplyNodeNum).TempSetPointLo =
962 0 : state.dataLoopNodes->Node(state.dataPlnt->PlantLoop(this->HWPlantLoc.loopNum).TempSetPointNodeNum).TempSetPointLo;
963 : }
964 0 : }
965 :
966 0 : void ExhaustAbsorberSpecs::initialize(EnergyPlusData &state)
967 : {
968 :
969 : // SUBROUTINE INFORMATION:
970 : // AUTHOR Fred Buhl
971 : // DATE WRITTEN June 2003
972 :
973 : // PURPOSE OF THIS SUBROUTINE:
974 : // This subroutine is for initializations of Exhaust Fired absorption chiller components.
975 :
976 : // METHODOLOGY EMPLOYED:
977 : // Uses the status flags to trigger initializations.
978 :
979 : // SUBROUTINE PARAMETER DEFINITIONS:
980 : static constexpr std::string_view RoutineName("InitExhaustAbsorber");
981 :
982 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
983 : Real64 rho; // local fluid density
984 : Real64 mdot; // local fluid mass flow rate
985 :
986 0 : int CondInletNode = this->CondReturnNodeNum;
987 0 : int CondOutletNode = this->CondSupplyNodeNum;
988 0 : int HeatInletNode = this->HeatReturnNodeNum;
989 0 : int HeatOutletNode = this->HeatSupplyNodeNum;
990 :
991 0 : if (this->envrnInit && state.dataGlobal->BeginEnvrnFlag && (state.dataPlnt->PlantFirstSizesOkayToFinalize)) {
992 :
993 0 : if (this->isWaterCooled) {
994 : // init max available condenser water flow rate
995 0 : if (this->CDPlantLoc.loopNum > 0) {
996 0 : rho = state.dataPlnt->PlantLoop(this->CDPlantLoc.loopNum).glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
997 : } else {
998 0 : rho = Psychrometrics::RhoH2O(Constant::InitConvTemp);
999 : }
1000 :
1001 0 : this->DesCondMassFlowRate = rho * this->CondVolFlowRate;
1002 0 : PlantUtilities::InitComponentNodes(state, 0.0, this->DesCondMassFlowRate, CondInletNode, CondOutletNode);
1003 : }
1004 :
1005 0 : if (this->HWPlantLoc.loopNum > 0) {
1006 0 : rho = state.dataPlnt->PlantLoop(this->HWPlantLoc.loopNum).glycol->getDensity(state, Constant::HWInitConvTemp, RoutineName);
1007 : } else {
1008 0 : rho = Psychrometrics::RhoH2O(Constant::InitConvTemp);
1009 : }
1010 0 : this->DesHeatMassFlowRate = rho * this->HeatVolFlowRate;
1011 : // init available hot water flow rate
1012 0 : PlantUtilities::InitComponentNodes(state, 0.0, this->DesHeatMassFlowRate, HeatInletNode, HeatOutletNode);
1013 :
1014 0 : if (this->CWPlantLoc.loopNum > 0) {
1015 0 : rho = state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
1016 : } else {
1017 0 : rho = Psychrometrics::RhoH2O(Constant::InitConvTemp);
1018 : }
1019 0 : this->DesEvapMassFlowRate = rho * this->EvapVolFlowRate;
1020 : // init available hot water flow rate
1021 0 : PlantUtilities::InitComponentNodes(state, 0.0, this->DesEvapMassFlowRate, this->ChillReturnNodeNum, this->ChillSupplyNodeNum);
1022 :
1023 0 : this->envrnInit = false;
1024 : }
1025 :
1026 0 : if (!state.dataGlobal->BeginEnvrnFlag) {
1027 0 : this->envrnInit = true;
1028 : }
1029 :
1030 : // this component model works off setpoints on the leaving node
1031 : // fill from plant if needed
1032 0 : if (this->ChillSetPointSetToLoop) {
1033 0 : state.dataLoopNodes->Node(this->ChillSupplyNodeNum).TempSetPoint =
1034 0 : state.dataLoopNodes->Node(state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).TempSetPointNodeNum).TempSetPoint;
1035 0 : state.dataLoopNodes->Node(this->ChillSupplyNodeNum).TempSetPointHi =
1036 0 : state.dataLoopNodes->Node(state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).TempSetPointNodeNum).TempSetPointHi;
1037 : }
1038 :
1039 0 : if (this->HeatSetPointSetToLoop) {
1040 0 : state.dataLoopNodes->Node(this->HeatSupplyNodeNum).TempSetPoint =
1041 0 : state.dataLoopNodes->Node(state.dataPlnt->PlantLoop(this->HWPlantLoc.loopNum).TempSetPointNodeNum).TempSetPoint;
1042 0 : state.dataLoopNodes->Node(this->HeatSupplyNodeNum).TempSetPointLo =
1043 0 : state.dataLoopNodes->Node(state.dataPlnt->PlantLoop(this->HWPlantLoc.loopNum).TempSetPointNodeNum).TempSetPointLo;
1044 : }
1045 :
1046 0 : if ((this->isWaterCooled) &&
1047 0 : ((this->InHeatingMode) || (this->InCoolingMode))) { // combining oneTimeInit and plantScanInit could cause a diff here
1048 0 : mdot = this->DesCondMassFlowRate;
1049 :
1050 0 : PlantUtilities::SetComponentFlowRate(state, mdot, this->CondReturnNodeNum, this->CondSupplyNodeNum, this->CDPlantLoc);
1051 :
1052 : } else {
1053 0 : mdot = 0.0;
1054 0 : if (this->CDPlantLoc.loopNum > 0) {
1055 0 : PlantUtilities::SetComponentFlowRate(state, mdot, this->CondReturnNodeNum, this->CondSupplyNodeNum, this->CDPlantLoc);
1056 : }
1057 : }
1058 0 : }
1059 :
1060 0 : void ExhaustAbsorberSpecs::size(EnergyPlusData &state)
1061 : {
1062 :
1063 : // SUBROUTINE INFORMATION:
1064 : // AUTHOR Fred Buhl
1065 : // DATE WRITTEN June 2003
1066 : // MODIFIED November 2013 Daeho Kang, add component sizing table entries
1067 :
1068 : // PURPOSE OF THIS SUBROUTINE:
1069 : // This subroutine is for sizing Exhaust Fired absorption chiller components for which
1070 : // capacities and flow rates have not been specified in the input.
1071 :
1072 : // METHODOLOGY EMPLOYED:
1073 : // Obtains evaporator flow rate from the plant sizing array. Calculates nominal capacity from
1074 : // the evaporator flow rate and the chilled water loop design delta T. The condenser flow rate
1075 : // is calculated from the nominal capacity, the COP, and the condenser loop design delta T.
1076 :
1077 : // SUBROUTINE PARAMETER DEFINITIONS:
1078 : static constexpr std::string_view RoutineName("SizeExhaustAbsorber");
1079 :
1080 : Real64 Cp; // local fluid specific heat
1081 : Real64 rho; // local fluid density
1082 : Real64 NomCapUser; // Hardsized nominal capacity for reporting
1083 : Real64 EvapVolFlowRateUser; // Hardsized evaporator volume flow rate for reporting
1084 : Real64 CondVolFlowRateUser; // Hardsized condenser flow rate for reporting
1085 : Real64 HeatRecVolFlowRateUser; // Hardsized generator flow rate for reporting
1086 :
1087 0 : bool ErrorsFound = false;
1088 0 : Real64 tmpNomCap = this->NomCoolingCap;
1089 0 : Real64 tmpEvapVolFlowRate = this->EvapVolFlowRate;
1090 0 : Real64 tmpCondVolFlowRate = this->CondVolFlowRate;
1091 0 : Real64 tmpHeatRecVolFlowRate = this->HeatVolFlowRate;
1092 :
1093 0 : int PltSizCondNum = 0; // Plant Sizing index for condenser loop
1094 0 : if (this->isWaterCooled) {
1095 0 : PltSizCondNum = state.dataPlnt->PlantLoop(this->CDPlantLoc.loopNum).PlantSizNum;
1096 : }
1097 :
1098 0 : int PltSizHeatNum = state.dataPlnt->PlantLoop(this->HWPlantLoc.loopNum).PlantSizNum;
1099 0 : int PltSizCoolNum = state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).PlantSizNum;
1100 :
1101 0 : if (PltSizCoolNum > 0) {
1102 0 : if (state.dataSize->PlantSizData(PltSizCoolNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
1103 0 : Cp = state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).glycol->getSpecificHeat(state, Constant::CWInitConvTemp, RoutineName);
1104 0 : rho = state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
1105 0 : tmpNomCap = Cp * rho * state.dataSize->PlantSizData(PltSizCoolNum).DeltaT * state.dataSize->PlantSizData(PltSizCoolNum).DesVolFlowRate *
1106 0 : this->SizFac;
1107 0 : if (!this->NomCoolingCapWasAutoSized) {
1108 0 : tmpNomCap = this->NomCoolingCap;
1109 : }
1110 : } else {
1111 0 : if (this->NomCoolingCapWasAutoSized) {
1112 0 : tmpNomCap = 0.0;
1113 : }
1114 : }
1115 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1116 0 : if (this->NomCoolingCapWasAutoSized) {
1117 0 : this->NomCoolingCap = tmpNomCap;
1118 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1119 0 : BaseSizer::reportSizerOutput(
1120 : state, "ChillerHeater:Absorption:DoubleEffect", this->Name, "Design Size Nominal Cooling Capacity [W]", tmpNomCap);
1121 : }
1122 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
1123 0 : BaseSizer::reportSizerOutput(
1124 : state, "ChillerHeater:Absorption:DoubleEffect", this->Name, "Initial Design Size Nominal Cooling Capacity [W]", tmpNomCap);
1125 : }
1126 : } else {
1127 0 : if (this->NomCoolingCap > 0.0 && tmpNomCap > 0.0) {
1128 0 : NomCapUser = this->NomCoolingCap;
1129 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1130 0 : BaseSizer::reportSizerOutput(state,
1131 : "ChillerHeater:Absorption:DoubleEffect",
1132 : this->Name,
1133 : "Design Size Nominal Cooling Capacity [W]",
1134 : tmpNomCap,
1135 : "User-Specified Nominal Cooling Capacity [W]",
1136 : NomCapUser);
1137 0 : if (state.dataGlobal->DisplayExtraWarnings) {
1138 0 : if ((std::abs(tmpNomCap - NomCapUser) / NomCapUser) > state.dataSize->AutoVsHardSizingThreshold) {
1139 0 : ShowMessage(
1140 : state,
1141 0 : format("SizeChillerHeaterAbsorptionDoubleEffect: Potential issue with equipment sizing for {}", this->Name));
1142 0 : ShowContinueError(state, format("User-Specified Nominal Capacity of {:.2R} [W]", NomCapUser));
1143 0 : ShowContinueError(state, format("differs from Design Size Nominal Capacity of {:.2R} [W]", tmpNomCap));
1144 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1145 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1146 : }
1147 : }
1148 : }
1149 0 : tmpNomCap = NomCapUser;
1150 : }
1151 : }
1152 : }
1153 : } else {
1154 0 : if (this->NomCoolingCapWasAutoSized) {
1155 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1156 0 : ShowSevereError(state, format("SizeExhaustAbsorber: ChillerHeater:Absorption:DoubleEffect=\"{}\", autosize error.", this->Name));
1157 0 : ShowContinueError(state, "Autosizing of Exhaust Fired Absorption Chiller nominal cooling capacity requires");
1158 0 : ShowContinueError(state, "a cooling loop Sizing:Plant object.");
1159 0 : ErrorsFound = true;
1160 : }
1161 : } else {
1162 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1163 0 : if (this->NomCoolingCap > 0.0) {
1164 0 : BaseSizer::reportSizerOutput(
1165 : state, "Chiller:Absorption:DoubleEffect", this->Name, "User-Specified Nominal Capacity [W]", this->NomCoolingCap);
1166 : }
1167 : }
1168 : }
1169 : }
1170 :
1171 0 : if (PltSizCoolNum > 0) {
1172 0 : if (state.dataSize->PlantSizData(PltSizCoolNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
1173 0 : tmpEvapVolFlowRate = state.dataSize->PlantSizData(PltSizCoolNum).DesVolFlowRate * this->SizFac;
1174 0 : if (!this->EvapVolFlowRateWasAutoSized) {
1175 0 : tmpEvapVolFlowRate = this->EvapVolFlowRate;
1176 : }
1177 :
1178 : } else {
1179 0 : if (this->EvapVolFlowRateWasAutoSized) {
1180 0 : tmpEvapVolFlowRate = 0.0;
1181 : }
1182 : }
1183 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1184 0 : if (this->EvapVolFlowRateWasAutoSized) {
1185 0 : this->EvapVolFlowRate = tmpEvapVolFlowRate;
1186 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1187 0 : BaseSizer::reportSizerOutput(state,
1188 : "ChillerHeater:Absorption:DoubleEffect",
1189 : this->Name,
1190 : "Design Size Design Chilled Water Flow Rate [m3/s]",
1191 : tmpEvapVolFlowRate);
1192 : }
1193 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
1194 0 : BaseSizer::reportSizerOutput(state,
1195 : "ChillerHeater:Absorption:DoubleEffect",
1196 : this->Name,
1197 : "Initial Design Size Design Chilled Water Flow Rate [m3/s]",
1198 : tmpEvapVolFlowRate);
1199 : }
1200 : } else {
1201 0 : if (this->EvapVolFlowRate > 0.0 && tmpEvapVolFlowRate > 0.0) {
1202 0 : EvapVolFlowRateUser = this->EvapVolFlowRate;
1203 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1204 0 : BaseSizer::reportSizerOutput(state,
1205 : "ChillerHeater:Absorption:DoubleEffect",
1206 : this->Name,
1207 : "Design Size Design Chilled Water Flow Rate [m3/s]",
1208 : tmpEvapVolFlowRate,
1209 : "User-Specified Design Chilled Water Flow Rate [m3/s]",
1210 : EvapVolFlowRateUser);
1211 0 : if (state.dataGlobal->DisplayExtraWarnings) {
1212 0 : if ((std::abs(tmpEvapVolFlowRate - EvapVolFlowRateUser) / EvapVolFlowRateUser) >
1213 0 : state.dataSize->AutoVsHardSizingThreshold) {
1214 0 : ShowMessage(state,
1215 0 : format("SizeChillerAbsorptionDoubleEffect: Potential issue with equipment sizing for {}", this->Name));
1216 0 : ShowContinueError(state,
1217 0 : format("User-Specified Design Chilled Water Flow Rate of {:.5R} [m3/s]", EvapVolFlowRateUser));
1218 0 : ShowContinueError(
1219 0 : state, format("differs from Design Size Design Chilled Water Flow Rate of {:.5R} [m3/s]", tmpEvapVolFlowRate));
1220 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1221 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1222 : }
1223 : }
1224 : }
1225 0 : tmpEvapVolFlowRate = EvapVolFlowRateUser;
1226 : }
1227 : }
1228 : }
1229 : } else {
1230 0 : if (this->EvapVolFlowRateWasAutoSized) {
1231 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1232 0 : ShowSevereError(state, format("SizeExhaustAbsorber: ChillerHeater:Absorption:DoubleEffect=\"{}\", autosize error.", this->Name));
1233 0 : ShowContinueError(state, "Autosizing of Exhaust Fired Absorption Chiller evap flow rate requires");
1234 0 : ShowContinueError(state, "a cooling loop Sizing:Plant object.");
1235 0 : ErrorsFound = true;
1236 : }
1237 : } else {
1238 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1239 0 : if (this->EvapVolFlowRate > 0.0) {
1240 0 : BaseSizer::reportSizerOutput(state,
1241 : "ChillerHeater:Absorption:DoubleEffect",
1242 : this->Name,
1243 : "User-Specified Design Chilled Water Flow Rate [m3/s]",
1244 : this->EvapVolFlowRate);
1245 : }
1246 : }
1247 : }
1248 : }
1249 :
1250 0 : PlantUtilities::RegisterPlantCompDesignFlow(state, this->ChillReturnNodeNum, tmpEvapVolFlowRate);
1251 :
1252 0 : if (PltSizHeatNum > 0) {
1253 0 : if (state.dataSize->PlantSizData(PltSizHeatNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
1254 0 : tmpHeatRecVolFlowRate = state.dataSize->PlantSizData(PltSizHeatNum).DesVolFlowRate * this->SizFac;
1255 0 : if (!this->HeatVolFlowRateWasAutoSized) {
1256 0 : tmpHeatRecVolFlowRate = this->HeatVolFlowRate;
1257 : }
1258 :
1259 : } else {
1260 0 : if (this->HeatVolFlowRateWasAutoSized) {
1261 0 : tmpHeatRecVolFlowRate = 0.0;
1262 : }
1263 : }
1264 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1265 0 : if (this->HeatVolFlowRateWasAutoSized) {
1266 0 : this->HeatVolFlowRate = tmpHeatRecVolFlowRate;
1267 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1268 0 : BaseSizer::reportSizerOutput(state,
1269 : "ChillerHeater:Absorption:DoubleEffect",
1270 : this->Name,
1271 : "Design Size Design Hot Water Flow Rate [m3/s]",
1272 : tmpHeatRecVolFlowRate);
1273 : }
1274 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
1275 0 : BaseSizer::reportSizerOutput(state,
1276 : "ChillerHeater:Absorption:DoubleEffect",
1277 : this->Name,
1278 : "Initial Design Size Design Hot Water Flow Rate [m3/s]",
1279 : tmpHeatRecVolFlowRate);
1280 : }
1281 : } else {
1282 0 : if (this->HeatVolFlowRate > 0.0 && tmpHeatRecVolFlowRate > 0.0) {
1283 0 : HeatRecVolFlowRateUser = this->HeatVolFlowRate;
1284 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1285 0 : BaseSizer::reportSizerOutput(state,
1286 : "ChillerHeater:Absorption:DoubleEffect",
1287 : this->Name,
1288 : "Design Size Design Hot Water Flow Rate [m3/s]",
1289 : tmpHeatRecVolFlowRate,
1290 : "User-Specified Design Hot Water Flow Rate [m3/s]",
1291 : HeatRecVolFlowRateUser);
1292 0 : if (state.dataGlobal->DisplayExtraWarnings) {
1293 0 : if ((std::abs(tmpHeatRecVolFlowRate - HeatRecVolFlowRateUser) / HeatRecVolFlowRateUser) >
1294 0 : state.dataSize->AutoVsHardSizingThreshold) {
1295 0 : ShowMessage(
1296 : state,
1297 0 : format("SizeChillerHeaterAbsorptionDoubleEffect: Potential issue with equipment sizing for {}", this->Name));
1298 0 : ShowContinueError(state,
1299 0 : format("User-Specified Design Hot Water Flow Rate of {:.5R} [m3/s]", HeatRecVolFlowRateUser));
1300 0 : ShowContinueError(
1301 0 : state, format("differs from Design Size Design Hot Water Flow Rate of {:.5R} [m3/s]", tmpHeatRecVolFlowRate));
1302 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1303 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1304 : }
1305 : }
1306 : }
1307 0 : tmpHeatRecVolFlowRate = HeatRecVolFlowRateUser;
1308 : }
1309 : }
1310 : }
1311 : } else {
1312 0 : if (this->HeatVolFlowRateWasAutoSized) {
1313 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1314 0 : ShowSevereError(state, format("SizeExhaustAbsorber: ChillerHeater:Absorption:DoubleEffect=\"{}\", autosize error.", this->Name));
1315 0 : ShowContinueError(state, "Autosizing of Exhaust Fired Absorption Chiller hot water flow rate requires");
1316 0 : ShowContinueError(state, "a heating loop Sizing:Plant object.");
1317 0 : ErrorsFound = true;
1318 : }
1319 : } else {
1320 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1321 0 : if (this->HeatVolFlowRate > 0.0) {
1322 0 : BaseSizer::reportSizerOutput(state,
1323 : "ChillerHeater:Absorption:DoubleEffect",
1324 : this->Name,
1325 : "User-Specified Design Hot Water Flow Rate [m3/s]",
1326 : this->HeatVolFlowRate);
1327 : }
1328 : }
1329 : }
1330 : }
1331 :
1332 0 : PlantUtilities::RegisterPlantCompDesignFlow(state, this->HeatReturnNodeNum, tmpHeatRecVolFlowRate);
1333 :
1334 0 : if (PltSizCondNum > 0 && PltSizCoolNum > 0) {
1335 0 : if (state.dataSize->PlantSizData(PltSizCoolNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow && tmpNomCap > 0.0) {
1336 :
1337 0 : Cp = state.dataPlnt->PlantLoop(this->CDPlantLoc.loopNum).glycol->getSpecificHeat(state, this->TempDesCondReturn, RoutineName);
1338 0 : rho = state.dataPlnt->PlantLoop(this->CDPlantLoc.loopNum).glycol->getDensity(state, this->TempDesCondReturn, RoutineName);
1339 0 : tmpCondVolFlowRate = tmpNomCap * (1.0 + this->ThermalEnergyCoolRatio) / (state.dataSize->PlantSizData(PltSizCondNum).DeltaT * Cp * rho);
1340 0 : if (!this->CondVolFlowRateWasAutoSized) {
1341 0 : tmpCondVolFlowRate = this->CondVolFlowRate;
1342 : }
1343 :
1344 : } else {
1345 0 : if (this->CondVolFlowRateWasAutoSized) {
1346 0 : tmpCondVolFlowRate = 0.0;
1347 : }
1348 : }
1349 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1350 0 : if (this->CondVolFlowRateWasAutoSized) {
1351 0 : this->CondVolFlowRate = tmpCondVolFlowRate;
1352 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1353 0 : BaseSizer::reportSizerOutput(state,
1354 : "ChillerHeater:Absorption:DoubleEffect",
1355 : this->Name,
1356 : "Design Size Design Condenser Water Flow Rate [m3/s]",
1357 : tmpCondVolFlowRate);
1358 : }
1359 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
1360 0 : BaseSizer::reportSizerOutput(state,
1361 : "ChillerHeater:Absorption:DoubleEffect",
1362 : this->Name,
1363 : "Initial Design Size Design Condenser Water Flow Rate [m3/s]",
1364 : tmpCondVolFlowRate);
1365 : }
1366 : } else {
1367 0 : if (this->CondVolFlowRate > 0.0 && tmpCondVolFlowRate > 0.0) {
1368 0 : CondVolFlowRateUser = this->CondVolFlowRate;
1369 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1370 0 : BaseSizer::reportSizerOutput(state,
1371 : "ChillerHeater:Absorption:DoubleEffect",
1372 : this->Name,
1373 : "Design Size Design Condenser Water Flow Rate [m3/s]",
1374 : tmpCondVolFlowRate,
1375 : "User-Specified Design Condenser Water Flow Rate [m3/s]",
1376 : CondVolFlowRateUser);
1377 0 : if (state.dataGlobal->DisplayExtraWarnings) {
1378 0 : if ((std::abs(tmpCondVolFlowRate - CondVolFlowRateUser) / CondVolFlowRateUser) >
1379 0 : state.dataSize->AutoVsHardSizingThreshold) {
1380 0 : ShowMessage(state,
1381 0 : format("SizeChillerAbsorptionDoubleEffect: Potential issue with equipment sizing for {}", this->Name));
1382 0 : ShowContinueError(state,
1383 0 : format("User-Specified Design Condenser Water Flow Rate of {:.5R} [m3/s]", CondVolFlowRateUser));
1384 0 : ShowContinueError(
1385 0 : state, format("differs from Design Size Design Condenser Water Flow Rate of {:.5R} [m3/s]", tmpCondVolFlowRate));
1386 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1387 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1388 : }
1389 : }
1390 : }
1391 0 : tmpCondVolFlowRate = CondVolFlowRateUser;
1392 : }
1393 : }
1394 : }
1395 : } else {
1396 0 : if (this->CondVolFlowRateWasAutoSized) {
1397 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1398 0 : ShowSevereError(state, format("SizeExhaustAbsorber: ChillerHeater:Absorption:DoubleEffect=\"{}\", autosize error.", this->Name));
1399 0 : ShowContinueError(state, "Autosizing of Exhaust Fired Absorption Chiller condenser flow rate requires a condenser");
1400 0 : ShowContinueError(state, "loop Sizing:Plant object.");
1401 0 : ErrorsFound = true;
1402 : }
1403 : } else {
1404 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1405 0 : if (this->CondVolFlowRate > 0.0) {
1406 0 : BaseSizer::reportSizerOutput(state,
1407 : "ChillerHeater:Absorption:DoubleEffect",
1408 : this->Name,
1409 : "User-Specified Design Condenser Water Flow Rate [m3/s]",
1410 : this->CondVolFlowRate);
1411 : }
1412 : }
1413 : }
1414 : }
1415 :
1416 : // save the design condenser water volumetric flow rate for use by the condenser water loop sizing algorithms
1417 0 : if (this->isWaterCooled) {
1418 0 : PlantUtilities::RegisterPlantCompDesignFlow(state, this->CondReturnNodeNum, tmpCondVolFlowRate);
1419 : }
1420 :
1421 0 : if (ErrorsFound) {
1422 0 : ShowFatalError(state, "Preceding sizing errors cause program termination");
1423 : }
1424 :
1425 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1426 : // create predefined report
1427 0 : OutputReportPredefined::PreDefTableEntry(
1428 0 : state, state.dataOutRptPredefined->pdchMechType, this->Name, "ChillerHeater:Absorption:DoubleEffect");
1429 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchMechNomEff, this->Name, this->ThermalEnergyCoolRatio);
1430 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchMechNomCap, this->Name, this->NomCoolingCap);
1431 :
1432 : // std 229 new Chillers table
1433 0 : OutputReportPredefined::PreDefTableEntry(
1434 0 : state, state.dataOutRptPredefined->pdchChillerType, this->Name, "ChillerHeater:Absorption:DoubleEffect");
1435 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerRefCap, this->Name, this->NomCoolingCap);
1436 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerRefEff, this->Name, this->ThermalEnergyCoolRatio);
1437 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerRatedCap, this->Name, this->NomCoolingCap);
1438 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerRatedEff, this->Name, this->ThermalEnergyCoolRatio);
1439 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerIPLVinSI, this->Name, "N/A");
1440 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerIPLVinIP, this->Name, "N/A");
1441 0 : OutputReportPredefined::PreDefTableEntry(state,
1442 0 : state.dataOutRptPredefined->pdchChillerPlantloopName,
1443 : this->Name,
1444 0 : this->CWPlantLoc.loopNum > 0 ? state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).Name : "N/A");
1445 0 : OutputReportPredefined::PreDefTableEntry(
1446 : state,
1447 0 : state.dataOutRptPredefined->pdchChillerPlantloopBranchName,
1448 : this->Name,
1449 0 : this->CWPlantLoc.loopNum > 0
1450 0 : ? state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).LoopSide(this->CWPlantLoc.loopSideNum).Branch(this->CWPlantLoc.branchNum).Name
1451 : : "N/A");
1452 0 : OutputReportPredefined::PreDefTableEntry(state,
1453 0 : state.dataOutRptPredefined->pdchChillerCondLoopName,
1454 : this->Name,
1455 0 : this->CDPlantLoc.loopNum > 0 ? state.dataPlnt->PlantLoop(this->CDPlantLoc.loopNum).Name : "N/A");
1456 0 : OutputReportPredefined::PreDefTableEntry(
1457 : state,
1458 0 : state.dataOutRptPredefined->pdchChillerCondLoopBranchName,
1459 : this->Name,
1460 0 : this->CDPlantLoc.loopNum > 0
1461 0 : ? state.dataPlnt->PlantLoop(this->CDPlantLoc.loopNum).LoopSide(this->CDPlantLoc.loopSideNum).Branch(this->CDPlantLoc.branchNum).Name
1462 : : "N/A");
1463 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerMinPLR, this->Name, this->MinPartLoadRat);
1464 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerFuelType, this->Name, this->ExhaustSourceName);
1465 0 : OutputReportPredefined::PreDefTableEntry(
1466 0 : state, state.dataOutRptPredefined->pdchChillerRatedEntCondTemp, this->Name, this->TempDesCondReturn); // Rated==Ref?
1467 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerRatedLevEvapTemp, this->Name, "N/A");
1468 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerRefEntCondTemp, this->Name, this->TempDesCondReturn);
1469 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerRefLevEvapTemp, this->Name, "N/A");
1470 :
1471 0 : OutputReportPredefined::PreDefTableEntry(
1472 0 : state, state.dataOutRptPredefined->pdchChillerDesSizeRefCHWFlowRate, this->Name, this->DesEvapMassFlowRate);
1473 0 : OutputReportPredefined::PreDefTableEntry(
1474 0 : state, state.dataOutRptPredefined->pdchChillerDesSizeRefCondFluidFlowRate, this->Name, this->DesCondMassFlowRate);
1475 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerHeatRecPlantloopName, this->Name, "N/A");
1476 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerHeatRecPlantloopBranchName, this->Name, "N/A");
1477 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerRecRelCapFrac, this->Name, "N/A");
1478 : }
1479 0 : }
1480 :
1481 2 : void ExhaustAbsorberSpecs::calcChiller(EnergyPlusData &state, Real64 &MyLoad)
1482 : {
1483 :
1484 : // SUBROUTINE INFORMATION:
1485 : // AUTHOR Jason Glazer
1486 : // DATE WRITTEN March 2001
1487 : // MODIFIED Mahabir Bhandari, ORNL, Aug 2011, modified to accommodate exhaust fired chiller
1488 :
1489 : // PURPOSE OF THIS SUBROUTINE:
1490 : // Simulate a Exhaust fired (Exhaust consuming) absorption chiller using
1491 : // curves and inputs similar to DOE-2.1e
1492 :
1493 : // METHODOLOGY EMPLOYED:
1494 : // Curve fit of performance data
1495 :
1496 : // REFERENCES:
1497 : // 1. DOE-2.1e Supplement and source code
1498 : // 2. CoolTools GasMod work
1499 :
1500 : // FlowLock = 0 if mass flow rates may be changed by loop components
1501 : // FlowLock = 1 if mass flow rates may not be changed by loop components
1502 :
1503 : // SUBROUTINE PARAMETER DEFINITIONS:
1504 2 : Real64 constexpr AbsLeavingTemp(176.667); // C - Minimum temperature leaving the Chiller absorber (350 F)
1505 : static constexpr std::string_view RoutineName("CalcExhaustAbsorberChillerModel");
1506 :
1507 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1508 : // Local copies of ExhaustAbsorberSpecs Type
1509 : // all variables that are local copies of data structure
1510 : // variables are prefaced with an "l" for local.
1511 : // Local copies of ExhaustAbsorberReportVars Type
1512 2 : Real64 lCoolingLoad(0.0); // cooling load on the chiller (previously called QEvap)
1513 2 : Real64 lTowerLoad(0.0); // load on the cooling tower/condenser (previously called QCond)
1514 2 : Real64 lCoolThermalEnergyUseRate(0.0); // instantaneous use of exhaust for period for cooling
1515 2 : Real64 lCoolElectricPower(0.0); // parasitic electric power used for cooling
1516 2 : Real64 lChillSupplyTemp(0.0); // reporting: evaporator outlet temperature (was EvapOutletTemp)
1517 2 : Real64 lCondSupplyTemp(0.0); // reporting: condenser outlet temperature (was CondOutletTemp)
1518 2 : Real64 lCondWaterMassFlowRate(0.0); // reporting: condenser mass flow rate (was Condmdot)
1519 2 : Real64 lCoolPartLoadRatio(0.0); // operating part load ratio (load/capacity for cooling)
1520 2 : Real64 lAvailableCoolingCapacity(0.0); // current capacity after temperature adjustment
1521 2 : Real64 lFractionOfPeriodRunning(0.0);
1522 2 : Real64 PartLoadRat(0.0); // actual operating part load ratio of unit (ranges from minplr to 1)
1523 2 : Real64 lChillWaterMassflowratemax(0.0); // Maximum flow rate through the evaporator
1524 2 : Real64 lExhHeatRecPotentialCool(0.0); // Exhaust heat recovery potential during cooling
1525 : // other local variables
1526 2 : Real64 ChillSupplySetPointTemp(0.0);
1527 : Real64 calcCondTemp; // the condenser temperature used for curve calculation
1528 : // either return or supply depending on user input
1529 : Real64 revisedEstimateAvailCap; // final estimate of available capacity if using leaving
1530 : // condenser water temperature
1531 : Real64 errorAvailCap; // error fraction on final estimate of AvailableCoolingCapacity
1532 : DataPlant::LoopSideLocation LoopSideNum;
1533 2 : Real64 Cp_CD = -1; // local fluid specific heat for condenser water -- initializing to negative to ensure it isn't used uninitialized
1534 : Real64 CpAir; // specific heat of exhaust air
1535 :
1536 : // set node values to data structure values for nodes
1537 2 : int lChillReturnNodeNum = this->ChillReturnNodeNum; // Node number on the inlet side of the plant
1538 2 : int lChillSupplyNodeNum = this->ChillSupplyNodeNum; // Node number on the outlet side of the plant
1539 2 : int lCondReturnNodeNum = this->CondReturnNodeNum; // Node number on the inlet side of the condenser
1540 2 : int lExhaustAirInletNodeNum = this->ExhaustAirInletNodeNum; // Combustion Air Inlet Node number
1541 :
1542 : // set local copies of data from rest of input structure
1543 2 : Real64 lNomCoolingCap = this->NomCoolingCap; // W - design nominal capacity of Absorber
1544 2 : Real64 lThermalEnergyCoolRatio = this->ThermalEnergyCoolRatio; // ratio of ThermalEnergy input to cooling output
1545 2 : Real64 lThermalEnergyHeatRatio = this->ThermalEnergyHeatRatio; // ratio of ThermalEnergy input to heating output
1546 2 : Real64 lElecCoolRatio = this->ElecCoolRatio; // ratio of electricity input to cooling output
1547 2 : Real64 lMinPartLoadRat = this->MinPartLoadRat; // min allowed operating frac full load
1548 2 : Real64 lMaxPartLoadRat = this->MaxPartLoadRat; // max allowed operating frac full load
1549 2 : bool lIsEnterCondensTemp = this->isEnterCondensTemp; // if using entering condenser water temperature is TRUE, exiting is FALSE
1550 2 : bool lIsWaterCooled = this->isWaterCooled; // if water cooled it is TRUE
1551 2 : Real64 lCHWLowLimitTemp = this->CHWLowLimitTemp;
1552 2 : Real64 lHeatElectricPower = this->HeatElectricPower; // parasitic electric power used for heating
1553 2 : Real64 lHeatThermalEnergyUseRate = this->HeatThermalEnergyUseRate; // instantaneous use of exhaust for period for heating
1554 2 : Real64 lHeatPartLoadRatio = this->HeatPartLoadRatio; // operating part load ratio (load/capacity for heating)
1555 :
1556 : // initialize entering conditions
1557 2 : Real64 lChillReturnTemp = state.dataLoopNodes->Node(lChillReturnNodeNum).Temp;
1558 2 : Real64 lChillWaterMassFlowRate = state.dataLoopNodes->Node(lChillReturnNodeNum).MassFlowRate;
1559 2 : Real64 lCondReturnTemp = state.dataLoopNodes->Node(lCondReturnNodeNum).Temp;
1560 2 : switch (state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).LoopDemandCalcScheme) {
1561 2 : case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
1562 2 : ChillSupplySetPointTemp = state.dataLoopNodes->Node(lChillSupplyNodeNum).TempSetPoint;
1563 2 : } break;
1564 0 : case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
1565 0 : ChillSupplySetPointTemp = state.dataLoopNodes->Node(lChillSupplyNodeNum).TempSetPointHi;
1566 0 : } break;
1567 0 : default: {
1568 0 : assert(false);
1569 : } break;
1570 : }
1571 2 : Real64 ChillDeltaTemp = std::abs(lChillReturnTemp - ChillSupplySetPointTemp);
1572 2 : Real64 lExhaustInTemp = state.dataLoopNodes->Node(lExhaustAirInletNodeNum).Temp;
1573 2 : Real64 lExhaustInFlow = state.dataLoopNodes->Node(lExhaustAirInletNodeNum).MassFlowRate;
1574 2 : Real64 lExhaustAirHumRat = state.dataLoopNodes->Node(lExhaustAirInletNodeNum).HumRat;
1575 :
1576 2 : Real64 Cp_CW = state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).glycol->getSpecificHeat(state, lChillReturnTemp, RoutineName);
1577 2 : if (this->CDPlantLoc.loopNum > 0) {
1578 0 : Cp_CD = state.dataPlnt->PlantLoop(this->CDPlantLoc.loopNum).glycol->getSpecificHeat(state, lChillReturnTemp, RoutineName);
1579 : }
1580 :
1581 : // If no loop demand or Absorber OFF, return
1582 : // will need to modify when absorber can act as a boiler
1583 2 : if (MyLoad >= 0 || !((this->InHeatingMode) || (this->InCoolingMode))) {
1584 : // set node temperatures
1585 0 : lChillSupplyTemp = lChillReturnTemp;
1586 0 : lCondSupplyTemp = lCondReturnTemp;
1587 0 : lCondWaterMassFlowRate = 0.0;
1588 0 : if (lIsWaterCooled) {
1589 0 : PlantUtilities::SetComponentFlowRate(state, lCondWaterMassFlowRate, this->CondReturnNodeNum, this->CondSupplyNodeNum, this->CDPlantLoc);
1590 : }
1591 0 : lFractionOfPeriodRunning = min(1.0, max(lHeatPartLoadRatio, lCoolPartLoadRatio) / lMinPartLoadRat);
1592 :
1593 : } else {
1594 :
1595 : // if water cooled use the input node otherwise just use outside air temperature
1596 2 : if (lIsWaterCooled) {
1597 : // most manufacturers rate have tables of entering condenser water temperature
1598 : // but a few use leaving condenser water temperature so we have a flag
1599 : // when leaving is used it uses the previous iterations value of the value
1600 2 : lCondReturnTemp = state.dataLoopNodes->Node(lCondReturnNodeNum).Temp;
1601 2 : if (lIsEnterCondensTemp) {
1602 2 : calcCondTemp = lCondReturnTemp;
1603 : } else {
1604 0 : if (this->oldCondSupplyTemp == 0) {
1605 0 : this->oldCondSupplyTemp = lCondReturnTemp + 8.0; // if not previously estimated assume 8C greater than return
1606 : }
1607 0 : calcCondTemp = this->oldCondSupplyTemp;
1608 : }
1609 : // Set mass flow rates
1610 2 : lCondWaterMassFlowRate = this->DesCondMassFlowRate;
1611 2 : PlantUtilities::SetComponentFlowRate(state, lCondWaterMassFlowRate, this->CondReturnNodeNum, this->CondSupplyNodeNum, this->CDPlantLoc);
1612 : } else {
1613 : // air cooled
1614 0 : state.dataLoopNodes->Node(lCondReturnNodeNum).Temp = state.dataLoopNodes->Node(lCondReturnNodeNum).OutAirDryBulb;
1615 0 : calcCondTemp = state.dataLoopNodes->Node(lCondReturnNodeNum).OutAirDryBulb;
1616 0 : lCondReturnTemp = state.dataLoopNodes->Node(lCondReturnNodeNum).Temp;
1617 0 : lCondWaterMassFlowRate = 0.0;
1618 0 : if (this->CDPlantLoc.loopNum > 0) {
1619 0 : PlantUtilities::SetComponentFlowRate(
1620 0 : state, lCondWaterMassFlowRate, this->CondReturnNodeNum, this->CondSupplyNodeNum, this->CDPlantLoc);
1621 : }
1622 : }
1623 :
1624 : // Determine available cooling capacity using the setpoint temperature
1625 2 : lAvailableCoolingCapacity = lNomCoolingCap * this->CoolCapFTCurve->value(state, ChillSupplySetPointTemp, calcCondTemp);
1626 :
1627 : // Calculate current load for cooling
1628 2 : MyLoad = sign(max(std::abs(MyLoad), lAvailableCoolingCapacity * lMinPartLoadRat), MyLoad);
1629 2 : MyLoad = sign(min(std::abs(MyLoad), lAvailableCoolingCapacity * lMaxPartLoadRat), MyLoad);
1630 :
1631 : // Determine the following variables depending on if the flow has been set in
1632 : // the nodes (flowlock=1 to 2) or if the amount of load is still be determined (flowlock=0)
1633 : // chilled water flow,
1634 : // cooling load taken by the chiller, and
1635 : // supply temperature
1636 2 : lChillWaterMassflowratemax = this->DesEvapMassFlowRate;
1637 :
1638 2 : int LoopNum = this->CWPlantLoc.loopNum;
1639 2 : LoopSideNum = this->CWPlantLoc.loopSideNum;
1640 2 : switch (state.dataPlnt->PlantLoop(LoopNum).LoopSide(LoopSideNum).FlowLock) {
1641 0 : case DataPlant::FlowLock::Unlocked: { // mass flow rates may be changed by loop components
1642 0 : this->PossibleSubcooling = false;
1643 0 : lCoolingLoad = std::abs(MyLoad);
1644 0 : if (ChillDeltaTemp != 0.0) {
1645 0 : lChillWaterMassFlowRate = std::abs(lCoolingLoad / (Cp_CW * ChillDeltaTemp));
1646 0 : if (lChillWaterMassFlowRate - lChillWaterMassflowratemax > DataBranchAirLoopPlant::MassFlowTolerance) {
1647 0 : this->PossibleSubcooling = true;
1648 : }
1649 :
1650 0 : PlantUtilities::SetComponentFlowRate(
1651 0 : state, lChillWaterMassFlowRate, this->ChillReturnNodeNum, this->ChillSupplyNodeNum, this->CWPlantLoc);
1652 : } else {
1653 0 : lChillWaterMassFlowRate = 0.0;
1654 0 : ShowRecurringWarningErrorAtEnd(state,
1655 0 : "ExhaustAbsorberChillerModel:Cooling\"" + this->Name + "\", DeltaTemp = 0 in mass flow calculation",
1656 0 : this->DeltaTempCoolErrCount);
1657 : }
1658 0 : lChillSupplyTemp = ChillSupplySetPointTemp;
1659 0 : } break;
1660 2 : case DataPlant::FlowLock::Locked: { // mass flow rates may not be changed by loop components
1661 2 : lChillWaterMassFlowRate = state.dataLoopNodes->Node(lChillReturnNodeNum).MassFlowRate;
1662 2 : if (this->PossibleSubcooling) {
1663 0 : lCoolingLoad = std::abs(MyLoad);
1664 :
1665 0 : ChillDeltaTemp = lCoolingLoad / lChillWaterMassFlowRate / Cp_CW;
1666 0 : lChillSupplyTemp = state.dataLoopNodes->Node(lChillReturnNodeNum).Temp - ChillDeltaTemp;
1667 : } else {
1668 :
1669 2 : ChillDeltaTemp = state.dataLoopNodes->Node(lChillReturnNodeNum).Temp - ChillSupplySetPointTemp;
1670 2 : lCoolingLoad = std::abs(lChillWaterMassFlowRate * Cp_CW * ChillDeltaTemp);
1671 2 : lChillSupplyTemp = ChillSupplySetPointTemp;
1672 : }
1673 : // Check that the Chiller Supply outlet temp honors both plant loop temp low limit and also the chiller low limit
1674 2 : if (lChillSupplyTemp < lCHWLowLimitTemp) {
1675 2 : if ((state.dataLoopNodes->Node(lChillReturnNodeNum).Temp - lCHWLowLimitTemp) > DataPlant::DeltaTempTol) {
1676 0 : lChillSupplyTemp = lCHWLowLimitTemp;
1677 0 : ChillDeltaTemp = state.dataLoopNodes->Node(lChillReturnNodeNum).Temp - lChillSupplyTemp;
1678 0 : lCoolingLoad = lChillWaterMassFlowRate * Cp_CW * ChillDeltaTemp;
1679 : } else {
1680 2 : lChillSupplyTemp = state.dataLoopNodes->Node(lChillReturnNodeNum).Temp;
1681 2 : ChillDeltaTemp = state.dataLoopNodes->Node(lChillReturnNodeNum).Temp - lChillSupplyTemp;
1682 2 : lCoolingLoad = lChillWaterMassFlowRate * Cp_CW * ChillDeltaTemp;
1683 : }
1684 : }
1685 2 : if (lChillSupplyTemp < state.dataLoopNodes->Node(lChillSupplyNodeNum).TempMin) {
1686 0 : if ((state.dataLoopNodes->Node(lChillReturnNodeNum).Temp - state.dataLoopNodes->Node(lChillSupplyNodeNum).TempMin) >
1687 : DataPlant::DeltaTempTol) {
1688 0 : lChillSupplyTemp = state.dataLoopNodes->Node(lChillSupplyNodeNum).TempMin;
1689 0 : ChillDeltaTemp = state.dataLoopNodes->Node(lChillReturnNodeNum).Temp - lChillSupplyTemp;
1690 0 : lCoolingLoad = lChillWaterMassFlowRate * Cp_CW * ChillDeltaTemp;
1691 : } else {
1692 0 : lChillSupplyTemp = state.dataLoopNodes->Node(lChillReturnNodeNum).Temp;
1693 0 : ChillDeltaTemp = state.dataLoopNodes->Node(lChillReturnNodeNum).Temp - lChillSupplyTemp;
1694 0 : lCoolingLoad = lChillWaterMassFlowRate * Cp_CW * ChillDeltaTemp;
1695 : }
1696 : }
1697 :
1698 : // Checks Coolingload on the basis of the machine limits.
1699 2 : if (lCoolingLoad > std::abs(MyLoad)) {
1700 0 : if (lChillWaterMassFlowRate > DataBranchAirLoopPlant::MassFlowTolerance) {
1701 0 : lCoolingLoad = std::abs(MyLoad);
1702 0 : ChillDeltaTemp = lCoolingLoad / lChillWaterMassFlowRate / Cp_CW;
1703 0 : lChillSupplyTemp = state.dataLoopNodes->Node(lChillReturnNodeNum).Temp - ChillDeltaTemp;
1704 : } else {
1705 0 : lChillSupplyTemp = state.dataLoopNodes->Node(lChillReturnNodeNum).Temp;
1706 0 : ChillDeltaTemp = state.dataLoopNodes->Node(lChillReturnNodeNum).Temp - lChillSupplyTemp;
1707 0 : lCoolingLoad = lChillWaterMassFlowRate * Cp_CW * ChillDeltaTemp;
1708 : }
1709 : }
1710 2 : } break;
1711 0 : default:
1712 0 : break;
1713 : }
1714 :
1715 : // Calculate operating part load ratio for cooling
1716 2 : PartLoadRat = min(std::abs(MyLoad) / lAvailableCoolingCapacity, lMaxPartLoadRat);
1717 2 : PartLoadRat = max(lMinPartLoadRat, PartLoadRat);
1718 :
1719 2 : if (lAvailableCoolingCapacity > 0.0) {
1720 2 : if (std::abs(MyLoad) / lAvailableCoolingCapacity < lMinPartLoadRat) {
1721 0 : lCoolPartLoadRatio = MyLoad / lAvailableCoolingCapacity;
1722 : } else {
1723 2 : lCoolPartLoadRatio = PartLoadRat;
1724 : }
1725 : } else { // Else if AvailableCoolingCapacity < 0.0
1726 0 : lCoolPartLoadRatio = 0.0;
1727 : }
1728 :
1729 : // calculate the fraction of the time period that the chiller would be running
1730 : // use maximum from heating and cooling sides
1731 2 : if (lCoolPartLoadRatio < lMinPartLoadRat || lHeatPartLoadRatio < lMinPartLoadRat) {
1732 2 : lFractionOfPeriodRunning = min(1.0, max(lHeatPartLoadRatio, lCoolPartLoadRatio) / lMinPartLoadRat);
1733 : } else {
1734 0 : lFractionOfPeriodRunning = 1.0;
1735 : }
1736 :
1737 : // Calculate thermal energy consumption for cooling
1738 : // Thermal Energy used for cooling availCap * TeFIR * TeFIR-FT * TeFIR-FPLR
1739 6 : lCoolThermalEnergyUseRate = lAvailableCoolingCapacity * lThermalEnergyCoolRatio *
1740 2 : this->ThermalEnergyCoolFTCurve->value(state, lChillSupplyTemp, calcCondTemp) *
1741 2 : this->ThermalEnergyCoolFPLRCurve->value(state, lCoolPartLoadRatio) * lFractionOfPeriodRunning;
1742 :
1743 : // Calculate electric parasitics used
1744 : // based on nominal capacity, not available capacity,
1745 : // electric used for cooling nomCap * %OP * EIR * EIR-FT * EIR-FPLR
1746 6 : lCoolElectricPower = lNomCoolingCap * lElecCoolRatio * lFractionOfPeriodRunning *
1747 2 : this->ElecCoolFTCurve->value(state, lChillSupplyTemp, calcCondTemp) *
1748 2 : this->ElecCoolFPLRCurve->value(state, lCoolPartLoadRatio);
1749 :
1750 : // determine condenser load which is cooling load plus the
1751 : // ThermalEnergy used for cooling plus
1752 : // the electricity used
1753 2 : lTowerLoad = lCoolingLoad + lCoolThermalEnergyUseRate / lThermalEnergyHeatRatio + lCoolElectricPower;
1754 :
1755 2 : lExhaustInTemp = state.dataLoopNodes->Node(lExhaustAirInletNodeNum).Temp;
1756 2 : lExhaustInFlow = state.dataLoopNodes->Node(lExhaustAirInletNodeNum).MassFlowRate;
1757 2 : CpAir = Psychrometrics::PsyCpAirFnW(lExhaustAirHumRat);
1758 2 : lExhHeatRecPotentialCool = lExhaustInFlow * CpAir * (lExhaustInTemp - AbsLeavingTemp);
1759 : // If Microturbine Exhaust temperature and flow rate is not sufficient to run the chiller, then chiller will not run
1760 : // lCoolThermalEnergyUseRate , lTowerLoad and lCoolElectricPower will be set to 0.0
1761 :
1762 2 : if (lExhHeatRecPotentialCool < lCoolThermalEnergyUseRate) {
1763 0 : if (this->ExhTempLTAbsLeavingTempIndex == 0) {
1764 0 : ShowWarningError(state, format("ChillerHeater:Absorption:DoubleEffect \"{}\"", this->Name));
1765 0 : ShowContinueError(state,
1766 : "...Exhaust temperature and flow input from Micro Turbine is not sufficient during cooling to run the chiller ");
1767 0 : ShowContinueError(state, format("...Value of Exhaust air inlet temp ={:.4T} C.", lExhaustInTemp));
1768 0 : ShowContinueError(state, format("... and Exhaust air flow rate of {:.2T} kg/s.", lExhaustInFlow));
1769 0 : ShowContinueError(state, format("...Value of minimum absorber leaving temp ={:.4T} C.", AbsLeavingTemp));
1770 0 : ShowContinueError(state,
1771 : "...Either increase the Exhaust temperature (min required = 350 C ) or flow or both of Micro Turbine to meet "
1772 : "the min available potential criteria.");
1773 0 : ShowContinueErrorTimeStamp(state, "... Simulation will continue.");
1774 : }
1775 0 : ShowRecurringWarningErrorAtEnd(
1776 : state,
1777 0 : "ChillerHeater:Absorption:DoubleEffect \"" + this->Name +
1778 : "\": Exhaust temperature from Micro Turbine is not sufficient to run the chiller during cooling warning continues...",
1779 0 : this->ExhTempLTAbsLeavingTempIndex,
1780 : lExhaustInTemp,
1781 : AbsLeavingTemp);
1782 : // If exhaust is not available, it means the available thermal energy is 0.0 and Chiller is not available
1783 0 : lCoolThermalEnergyUseRate = 0.0;
1784 0 : lTowerLoad = 0.0;
1785 0 : lCoolElectricPower = 0.0;
1786 0 : lChillSupplyTemp = lChillReturnTemp;
1787 0 : lCondSupplyTemp = lCondReturnTemp;
1788 0 : lFractionOfPeriodRunning = min(1.0, max(lHeatPartLoadRatio, lCoolPartLoadRatio) / lMinPartLoadRat);
1789 : }
1790 : // for water cooled condenser make sure enough flow rate
1791 : // for air cooled condenser just set supply to return temperature
1792 2 : if (lIsWaterCooled) {
1793 2 : if (lCondWaterMassFlowRate > DataBranchAirLoopPlant::MassFlowTolerance) {
1794 0 : lCondSupplyTemp = lCondReturnTemp + lTowerLoad / (lCondWaterMassFlowRate * Cp_CD);
1795 : } else {
1796 2 : if (this->lCondWaterMassFlowRate_Index == 0) {
1797 2 : ShowSevereError(state,
1798 2 : format("CalcExhaustAbsorberChillerModel: Condenser flow = 0, for Exhaust Absorber Chiller={}", this->Name));
1799 3 : ShowContinueErrorTimeStamp(state, "");
1800 : // ShowFatalError(state, "Program Terminates due to previous error condition.");
1801 : }
1802 16 : ShowRecurringSevereErrorAtEnd(state,
1803 4 : format("CalcExhaustAbsorberChillerModel: Condenser flow = 0, for Exhaust Absorber Chiller={}: "
1804 : "Condenser flow rate = 0 severe error warning continues...",
1805 2 : this->Name), // Message automatically written to "error file" at end of simulation
1806 2 : this->lCondWaterMassFlowRate_Index // Recurring message index, if zero, next available index is assigned
1807 : );
1808 : }
1809 : } else {
1810 0 : lCondSupplyTemp = lCondReturnTemp; // if air cooled condenser just set supply and return to same temperature
1811 : }
1812 :
1813 : // save the condenser water supply temperature for next iteration if that is used in lookup
1814 : // and if capacity is large enough error than report problem
1815 2 : this->oldCondSupplyTemp = lCondSupplyTemp;
1816 2 : if (!lIsEnterCondensTemp) {
1817 : // calculate the fraction of the estimated error between the capacity based on the previous
1818 : // iteration's value of condenser supply temperature and the actual calculated condenser supply
1819 : // temperature. If this becomes too common then may need to iterate a solution instead of
1820 : // relying on previous iteration method.
1821 0 : revisedEstimateAvailCap = lNomCoolingCap * this->CoolCapFTCurve->value(state, ChillSupplySetPointTemp, lCondSupplyTemp);
1822 0 : if (revisedEstimateAvailCap > 0.0) {
1823 0 : errorAvailCap = std::abs((revisedEstimateAvailCap - lAvailableCoolingCapacity) / revisedEstimateAvailCap);
1824 0 : if (errorAvailCap > 0.05) { // if more than 5% error in estimate
1825 0 : ShowRecurringWarningErrorAtEnd(state,
1826 0 : "ExhaustAbsorberChillerModel:\"" + this->Name + "\", poor Condenser Supply Estimate",
1827 0 : this->CondErrCount,
1828 : errorAvailCap,
1829 : errorAvailCap);
1830 : }
1831 : }
1832 : }
1833 : } // IF(MyLoad>=0 .OR. .NOT. RunFlag)
1834 : // Write into the Report Variables except for nodes
1835 2 : this->CoolingLoad = lCoolingLoad;
1836 2 : this->TowerLoad = lTowerLoad;
1837 2 : this->CoolThermalEnergyUseRate = lCoolThermalEnergyUseRate;
1838 2 : this->CoolElectricPower = lCoolElectricPower;
1839 2 : this->CondReturnTemp = lCondReturnTemp;
1840 2 : this->ChillReturnTemp = lChillReturnTemp;
1841 2 : this->CondSupplyTemp = lCondSupplyTemp;
1842 2 : this->ChillSupplyTemp = lChillSupplyTemp;
1843 2 : this->ChillWaterFlowRate = lChillWaterMassFlowRate;
1844 2 : this->CondWaterFlowRate = lCondWaterMassFlowRate;
1845 2 : this->CoolPartLoadRatio = lCoolPartLoadRatio;
1846 2 : this->CoolingCapacity = lAvailableCoolingCapacity;
1847 2 : this->FractionOfPeriodRunning = lFractionOfPeriodRunning;
1848 2 : this->ExhaustInTemp = lExhaustInTemp;
1849 2 : this->ExhaustInFlow = lExhaustInFlow;
1850 2 : this->ExhHeatRecPotentialCool = lExhHeatRecPotentialCool;
1851 :
1852 : // write the combined heating and cooling ThermalEnergy used and electric used
1853 2 : this->ThermalEnergyUseRate = lCoolThermalEnergyUseRate + lHeatThermalEnergyUseRate;
1854 2 : this->ElectricPower = lCoolElectricPower + lHeatElectricPower;
1855 2 : }
1856 :
1857 1 : void ExhaustAbsorberSpecs::calcHeater(EnergyPlusData &state, Real64 &MyLoad, bool RunFlag)
1858 : {
1859 :
1860 : // SUBROUTINE INFORMATION:
1861 : // AUTHOR Jason Glazer and Michael J. Witte
1862 : // DATE WRITTEN March 2001
1863 : // MODIFIED Mahabir Bhandari, ORNL, Aug 2011, modified to accommodate exhaust fired double effect absorption chiller
1864 :
1865 : // PURPOSE OF THIS SUBROUTINE:
1866 : // Simulate a Exhaust fired (Exhaust consuming) absorption chiller using
1867 : // curves and inputs similar to DOE-2.1e
1868 :
1869 : // METHODOLOGY EMPLOYED:
1870 : // Curve fit of performance data
1871 :
1872 : // REFERENCES:
1873 : // 1. DOE-2.1e Supplement and source code
1874 : // 2. CoolTools GasMod work
1875 :
1876 : // Locals
1877 : // SUBROUTINE ARGUMENT DEFINITIONS:
1878 : // FlowLock = 0 if mass flow rates may be changed by loop components
1879 : // FlowLock = 1 if mass flow rates may not be changed by loop components
1880 : // FlowLock = 2 if overloaded and mass flow rates has changed to a small amount and Tout drops
1881 : // below Setpoint
1882 :
1883 : // SUBROUTINE PARAMETER DEFINITIONS:
1884 1 : Real64 constexpr AbsLeavingTemp(176.667); // C - Minimum temperature leaving the Chiller absorber (350 F)
1885 : static constexpr std::string_view RoutineName("CalcExhaustAbsorberHeaterModel");
1886 :
1887 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1888 : // Local copies of ExhaustAbsorberSpecs Type
1889 : // all variables that are local copies of data structure
1890 : // variables are prefaced with an "l" for local.
1891 : // Local copies of ExhaustAbsorberReportVars Type
1892 1 : Real64 lHeatingLoad(0.0); // heating load on the chiller
1893 1 : Real64 lHeatThermalEnergyUseRate(0.0); // instantaneous use of thermal energy for period for heating
1894 1 : Real64 lHeatElectricPower(0.0); // parasitic electric power used for heating
1895 1 : Real64 lHotWaterSupplyTemp(0.0); // reporting: hot water supply (outlet) temperature
1896 1 : Real64 lHeatPartLoadRatio(0.0); // operating part load ratio (load/capacity for heating)
1897 1 : Real64 lAvailableHeatingCapacity(0.0); // current heating capacity
1898 1 : Real64 lFractionOfPeriodRunning(0.0);
1899 1 : Real64 lExhaustInTemp(0.0); // Exhaust inlet temperature
1900 1 : Real64 lExhaustInFlow(0.0); // Exhaust inlet flow rate
1901 1 : Real64 lExhHeatRecPotentialHeat(0.0); // Exhaust heat recovery potential
1902 :
1903 : // initialize entering conditions
1904 1 : auto &hwPlantLoop = state.dataPlnt->PlantLoop(this->HWPlantLoc.loopNum);
1905 0 : const Real64 HeatSupplySetPointTemp = [this, &hwPlantLoop, &state]() {
1906 1 : switch (hwPlantLoop.LoopDemandCalcScheme) {
1907 1 : case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
1908 1 : return state.dataLoopNodes->Node(this->HeatSupplyNodeNum).TempSetPoint;
1909 : }
1910 0 : case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
1911 0 : return state.dataLoopNodes->Node(this->HeatSupplyNodeNum).TempSetPointLo;
1912 : }
1913 0 : default: {
1914 0 : assert(false);
1915 : return 0.0;
1916 : }
1917 : }
1918 1 : }();
1919 :
1920 1 : auto const &heatReturnNode = state.dataLoopNodes->Node(this->HeatReturnNodeNum);
1921 1 : Real64 const HeatDeltaTemp = std::abs(heatReturnNode.Temp - HeatSupplySetPointTemp);
1922 : // reporting: hot water mass flow rate
1923 1 : Real64 lHotWaterMassFlowRate = heatReturnNode.MassFlowRate;
1924 :
1925 : // If no loop demand or Absorber OFF, return
1926 : // will need to modify when absorber can act as a boiler
1927 1 : if (MyLoad <= 0 || !RunFlag) {
1928 : // set node temperatures
1929 0 : lHotWaterSupplyTemp = heatReturnNode.Temp;
1930 0 : lFractionOfPeriodRunning = min(1.0, max(lHeatPartLoadRatio, this->CoolPartLoadRatio) / this->MinPartLoadRat);
1931 : } else {
1932 :
1933 1 : Real64 const Cp_HW = hwPlantLoop.glycol->getSpecificHeat(state, heatReturnNode.Temp, RoutineName);
1934 :
1935 : // Determine available heating capacity using the current cooling load
1936 1 : lAvailableHeatingCapacity =
1937 1 : this->NomHeatCoolRatio * this->NomCoolingCap * this->HeatCapFCoolCurve->value(state, (this->CoolingLoad / this->NomCoolingCap));
1938 :
1939 : // Calculate current load for heating
1940 1 : MyLoad = sign(max(std::abs(MyLoad), this->HeatingCapacity * this->MinPartLoadRat), MyLoad);
1941 1 : MyLoad = sign(min(std::abs(MyLoad), this->HeatingCapacity * this->MaxPartLoadRat), MyLoad);
1942 :
1943 : // Determine the following variables depending on if the flow has been set in
1944 : // the nodes (flowlock=1 to 2) or if the amount of load is still be determined (flowlock=0)
1945 : // chilled water flow,
1946 : // cooling load taken by the chiller, and
1947 : // supply temperature
1948 1 : switch (hwPlantLoop.LoopSide(this->HWPlantLoc.loopSideNum).FlowLock) {
1949 0 : case DataPlant::FlowLock::Unlocked: { // mass flow rates may be changed by loop components
1950 0 : lHeatingLoad = std::abs(MyLoad);
1951 0 : if (HeatDeltaTemp != 0) {
1952 0 : lHotWaterMassFlowRate = std::abs(lHeatingLoad / (Cp_HW * HeatDeltaTemp));
1953 :
1954 0 : PlantUtilities::SetComponentFlowRate(
1955 0 : state, lHotWaterMassFlowRate, this->HeatReturnNodeNum, this->HeatSupplyNodeNum, this->HWPlantLoc);
1956 :
1957 : } else {
1958 0 : lHotWaterMassFlowRate = 0.0;
1959 0 : ShowRecurringWarningErrorAtEnd(
1960 : state,
1961 0 : format("ExhaustAbsorberChillerModel:Heating\"{}\", DeltaTemp = 0 in mass flow calculation", this->Name),
1962 0 : this->DeltaTempHeatErrCount);
1963 : }
1964 0 : lHotWaterSupplyTemp = HeatSupplySetPointTemp;
1965 0 : } break;
1966 1 : case DataPlant::FlowLock::Locked: { // mass flow rates may not be changed by loop components
1967 1 : lHotWaterSupplyTemp = HeatSupplySetPointTemp;
1968 1 : lHeatingLoad = std::abs(lHotWaterMassFlowRate * Cp_HW * HeatDeltaTemp);
1969 1 : } break;
1970 0 : default:
1971 0 : break;
1972 : }
1973 :
1974 : // Calculate operating part load ratio for cooling
1975 1 : if (lAvailableHeatingCapacity <= 0.0) {
1976 1 : lAvailableHeatingCapacity = 0.0;
1977 1 : lHeatPartLoadRatio = 0.0;
1978 : } else {
1979 0 : lHeatPartLoadRatio = lHeatingLoad / lAvailableHeatingCapacity;
1980 : }
1981 :
1982 : // Calculate ThermalEnergy consumption for heating
1983 : // ThermalEnergy used for heating availCap * HIR * HIR-FT * HIR-FPLR
1984 1 : lHeatThermalEnergyUseRate =
1985 1 : lAvailableHeatingCapacity * this->ThermalEnergyHeatRatio * this->ThermalEnergyHeatFHPLRCurve->value(state, lHeatPartLoadRatio);
1986 :
1987 : // calculate the fraction of the time period that the chiller would be running
1988 : // use maximum from heating and cooling sides
1989 1 : lFractionOfPeriodRunning = min(1.0, max(lHeatPartLoadRatio, this->CoolPartLoadRatio) / this->MinPartLoadRat);
1990 :
1991 : // Calculate electric parasitics used
1992 : // for heating based on nominal capacity not available capacity
1993 1 : lHeatElectricPower = this->NomCoolingCap * this->NomHeatCoolRatio * this->ElecHeatRatio * lFractionOfPeriodRunning;
1994 : // Coordinate electric parasitics for heating and cooling to avoid double counting
1995 : // Total electric is the max of heating electric or cooling electric
1996 : // If heating electric is greater, leave cooling electric and subtract if off of heating elec
1997 : // If cooling electric is greater, set heating electric to zero
1998 :
1999 1 : lExhaustInTemp = state.dataLoopNodes->Node(this->ExhaustAirInletNodeNum).Temp;
2000 1 : lExhaustInFlow = state.dataLoopNodes->Node(this->ExhaustAirInletNodeNum).MassFlowRate;
2001 1 : Real64 const lExhaustAirHumRat = state.dataLoopNodes->Node(this->ExhaustAirInletNodeNum).HumRat;
2002 1 : Real64 const CpAir = Psychrometrics::PsyCpAirFnW(lExhaustAirHumRat);
2003 1 : lExhHeatRecPotentialHeat = lExhaustInFlow * CpAir * (lExhaustInTemp - AbsLeavingTemp);
2004 1 : if (lExhHeatRecPotentialHeat < lHeatThermalEnergyUseRate) {
2005 0 : if (this->ExhTempLTAbsLeavingHeatingTempIndex == 0) {
2006 0 : ShowWarningError(state, format("ChillerHeater:Absorption:DoubleEffect \"{}\"", this->Name));
2007 0 : ShowContinueError(state,
2008 : "...Exhaust temperature and flow input from Micro Turbine is not sufficient to run the chiller during heating .");
2009 0 : ShowContinueError(state, format("...Value of Exhaust air inlet temp ={:.4T} C.", lExhaustInTemp));
2010 0 : ShowContinueError(state, format("... and Exhaust air flow rate of {:.2T} kg/s.", lExhaustInFlow));
2011 0 : ShowContinueError(state, format("...Value of minimum absorber leaving temp ={:.4T} C.", AbsLeavingTemp));
2012 0 : ShowContinueError(state,
2013 : "...Either increase the Exhaust temperature (min required = 350 C) or flow or both of Micro Turbine to meet "
2014 : "the min available potential criteria.");
2015 0 : ShowContinueErrorTimeStamp(state, "... Simulation will continue.");
2016 : }
2017 0 : ShowRecurringWarningErrorAtEnd(state,
2018 0 : format("ChillerHeater:Absorption:DoubleEffect \"{}\": Exhaust temperature from Micro Turbine is not "
2019 : "sufficient to run the chiller during heating warning continues...",
2020 0 : this->Name),
2021 0 : this->ExhTempLTAbsLeavingHeatingTempIndex,
2022 : lExhaustInTemp,
2023 : AbsLeavingTemp);
2024 : // If exhaust is not available, it means the available thermal energy is 0.0 and Chiller is not available
2025 0 : lHeatThermalEnergyUseRate = 0.0;
2026 0 : lHeatElectricPower = 0.0;
2027 0 : lHotWaterSupplyTemp = heatReturnNode.Temp;
2028 0 : lFractionOfPeriodRunning = min(1.0, max(lHeatPartLoadRatio, this->CoolPartLoadRatio) / this->MinPartLoadRat);
2029 : }
2030 :
2031 1 : if (lHeatElectricPower <= this->CoolElectricPower) {
2032 0 : lHeatElectricPower = 0.0;
2033 : } else {
2034 1 : lHeatElectricPower -= this->CoolElectricPower;
2035 : }
2036 :
2037 : } // IF(MyLoad==0 .OR. .NOT. RunFlag)
2038 : // Write into the Report Variables except for nodes
2039 1 : this->HeatingLoad = lHeatingLoad;
2040 1 : this->HeatThermalEnergyUseRate = lHeatThermalEnergyUseRate;
2041 1 : this->HeatElectricPower = lHeatElectricPower;
2042 1 : this->HotWaterReturnTemp = heatReturnNode.Temp;
2043 1 : this->HotWaterSupplyTemp = lHotWaterSupplyTemp;
2044 1 : this->HotWaterFlowRate = lHotWaterMassFlowRate;
2045 1 : this->HeatPartLoadRatio = lHeatPartLoadRatio;
2046 1 : this->HeatingCapacity = lAvailableHeatingCapacity;
2047 1 : this->FractionOfPeriodRunning = lFractionOfPeriodRunning;
2048 :
2049 : // write the combined heating and cooling ThermalEnergy used and electric used
2050 1 : this->ThermalEnergyUseRate = this->CoolThermalEnergyUseRate + lHeatThermalEnergyUseRate;
2051 1 : this->ElectricPower = this->CoolElectricPower + lHeatElectricPower;
2052 1 : this->ExhaustInTemp = lExhaustInTemp;
2053 1 : this->ExhaustInFlow = lExhaustInFlow;
2054 1 : this->ExhHeatRecPotentialHeat = lExhHeatRecPotentialHeat;
2055 1 : }
2056 :
2057 0 : void ExhaustAbsorberSpecs::updateCoolRecords(EnergyPlusData &state, Real64 MyLoad, bool RunFlag)
2058 : {
2059 :
2060 : // SUBROUTINE INFORMATION:
2061 : // AUTHOR Jason Glazer
2062 : // DATE WRITTEN March 2001
2063 :
2064 0 : if (MyLoad == 0 || !RunFlag) {
2065 0 : state.dataLoopNodes->Node(this->ChillSupplyNodeNum).Temp = state.dataLoopNodes->Node(this->ChillReturnNodeNum).Temp;
2066 0 : if (this->isWaterCooled) {
2067 0 : state.dataLoopNodes->Node(this->CondSupplyNodeNum).Temp = state.dataLoopNodes->Node(this->CondReturnNodeNum).Temp;
2068 : }
2069 0 : state.dataLoopNodes->Node(this->ExhaustAirInletNodeNum).Temp = state.dataLoopNodes->Node(this->ExhaustAirInletNodeNum).Temp;
2070 0 : state.dataLoopNodes->Node(this->ExhaustAirInletNodeNum).MassFlowRate = this->ExhaustInFlow;
2071 : } else {
2072 0 : state.dataLoopNodes->Node(this->ChillSupplyNodeNum).Temp = this->ChillSupplyTemp;
2073 0 : if (this->isWaterCooled) {
2074 0 : state.dataLoopNodes->Node(this->CondSupplyNodeNum).Temp = this->CondSupplyTemp;
2075 : }
2076 0 : state.dataLoopNodes->Node(this->ExhaustAirInletNodeNum).Temp = this->ExhaustInTemp;
2077 0 : state.dataLoopNodes->Node(this->ExhaustAirInletNodeNum).MassFlowRate = this->ExhaustInFlow;
2078 : }
2079 :
2080 : // convert power to energy and instantaneous use to use over the time step
2081 0 : Real64 RptConstant = state.dataHVACGlobal->TimeStepSysSec;
2082 0 : this->CoolingEnergy = this->CoolingLoad * RptConstant;
2083 0 : this->TowerEnergy = this->TowerLoad * RptConstant;
2084 0 : this->ThermalEnergy = this->ThermalEnergyUseRate * RptConstant;
2085 0 : this->CoolThermalEnergy = this->CoolThermalEnergyUseRate * RptConstant;
2086 0 : this->ElectricEnergy = this->ElectricPower * RptConstant;
2087 0 : this->CoolElectricEnergy = this->CoolElectricPower * RptConstant;
2088 0 : if (this->CoolThermalEnergyUseRate != 0.0) {
2089 0 : this->ThermalEnergyCOP = this->CoolingLoad / this->CoolThermalEnergyUseRate;
2090 : } else {
2091 0 : this->ThermalEnergyCOP = 0.0;
2092 : }
2093 0 : }
2094 :
2095 0 : void ExhaustAbsorberSpecs::updateHeatRecords(EnergyPlusData &state, Real64 MyLoad, bool RunFlag)
2096 : {
2097 :
2098 : // SUBROUTINE INFORMATION:
2099 : // AUTHOR Jason Glazer
2100 : // DATE WRITTEN March 2001
2101 :
2102 0 : if (MyLoad == 0 || !RunFlag) {
2103 0 : state.dataLoopNodes->Node(this->HeatSupplyNodeNum).Temp = state.dataLoopNodes->Node(this->HeatReturnNodeNum).Temp;
2104 : } else {
2105 0 : state.dataLoopNodes->Node(this->HeatSupplyNodeNum).Temp = this->HotWaterSupplyTemp;
2106 : }
2107 :
2108 : // convert power to energy and instantaneous use to use over the time step
2109 0 : Real64 RptConstant = state.dataHVACGlobal->TimeStepSysSec;
2110 0 : this->HeatingEnergy = this->HeatingLoad * RptConstant;
2111 0 : this->ThermalEnergy = this->ThermalEnergyUseRate * RptConstant;
2112 0 : this->HeatThermalEnergy = this->HeatThermalEnergyUseRate * RptConstant;
2113 0 : this->ElectricEnergy = this->ElectricPower * RptConstant;
2114 0 : this->HeatElectricEnergy = this->HeatElectricPower * RptConstant;
2115 0 : }
2116 :
2117 0 : void ExhaustAbsorberSpecs::oneTimeInit([[maybe_unused]] EnergyPlusData &state)
2118 : {
2119 0 : }
2120 :
2121 : } // namespace EnergyPlus::ChillerExhaustAbsorption
|