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