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