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