LCOV - code coverage report
Current view: top level - EnergyPlus - ChillerExhaustAbsorption.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 31.1 % 1005 313
Test Date: 2025-05-22 16:09:37 Functions: 27.8 % 18 5

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

Generated by: LCOV version 2.0-1