LCOV - code coverage report
Current view: top level - EnergyPlus - FuelCellElectricGenerator.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 61.1 % 1734 1059
Test Date: 2025-05-22 16:09:37 Functions: 96.8 % 31 30

            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/BranchNodeConnections.hh>
      58              : #include <EnergyPlus/CurveManager.hh>
      59              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      60              : #include <EnergyPlus/DataEnvironment.hh>
      61              : #include <EnergyPlus/DataGenerators.hh>
      62              : #include <EnergyPlus/DataHVACGlobals.hh>
      63              : #include <EnergyPlus/DataHeatBalance.hh>
      64              : #include <EnergyPlus/DataIPShortCuts.hh>
      65              : #include <EnergyPlus/DataLoopNode.hh>
      66              : #include <EnergyPlus/FluidProperties.hh>
      67              : #include <EnergyPlus/FuelCellElectricGenerator.hh>
      68              : #include <EnergyPlus/General.hh>
      69              : #include <EnergyPlus/GeneratorFuelSupply.hh>
      70              : #include <EnergyPlus/HeatBalanceInternalHeatGains.hh>
      71              : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      72              : #include <EnergyPlus/NodeInputManager.hh>
      73              : #include <EnergyPlus/OutputProcessor.hh>
      74              : #include <EnergyPlus/Plant/DataPlant.hh>
      75              : #include <EnergyPlus/PlantUtilities.hh>
      76              : #include <EnergyPlus/ScheduleManager.hh>
      77              : #include <EnergyPlus/UtilityRoutines.hh>
      78              : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
      79              : 
      80              : namespace EnergyPlus {
      81              : 
      82              : namespace FuelCellElectricGenerator {
      83              : 
      84              :     // MODULE INFORMATION:
      85              :     //       AUTHOR         Brent Griffith
      86              :     //       DATE WRITTEN   August. 2005
      87              : 
      88              :     // PURPOSE OF THIS MODULE:
      89              :     // This module simulates the operation of Solid oxide fuel cell Generators.
      90              : 
      91              :     // METHODOLOGY EMPLOYED:
      92              :     // Once the ElectricPowerManager determines that the FuelCell Generator
      93              :     // is available to meet an electric load demand, it calls SimFuelCellGenerator
      94              :     // which in turn calls the FuelCell model.
      95              :     // See DataGenerators.cc for structures and variables
      96              : 
      97              :     // REFERENCES:
      98              :     // IEA/ECBCS Annex 42 model specification for Solid oxide and proton exchange membrane fuel cells
      99              :     constexpr std::array<std::string_view, (int)DataGenerators::CurveMode::Num> curveModeNamesUC = {"NORMALIZED", "ANNEX42"};
     100              : 
     101              :     constexpr std::array<std::string_view, (int)DataGenerators::SkinLoss::Num> skinLossNamesUC = {
     102              :         "CONSTANTRATE", "UAFORPROCESSGASTEMPERATURE", "QUADRATIC FUNCTION OF FUEL RATE"}; // Seriously with this last one?
     103              : 
     104              :     constexpr std::array<std::string_view, (int)DataGenerators::AirSupRateMode::Num> airSupRateModeNamesUC = {
     105              :         "QUADRATIC FUNCTION OF FUEL RATE", "AIRRATIOBYSTOICS", "QUADRATICFUNCTIONOFELECTRICPOWER"}; // Seriously with the first one?
     106              : 
     107              :     constexpr std::array<std::string_view, (int)DataGenerators::RecoverMode::Num> recoverModeNames = {"NoRecovery",
     108              :                                                                                                       "RecoverBurnerInverterStorage",
     109              :                                                                                                       "RecoverAuxiliaryBurner",
     110              :                                                                                                       "RecoverInverterandStorage",
     111              :                                                                                                       "RecoverInverter",
     112              :                                                                                                       "RecoverElectricalStorage"};
     113              :     constexpr std::array<std::string_view, (int)DataGenerators::RecoverMode::Num> recoverModeNamesUC = {"NORECOVERY",
     114              :                                                                                                         "RECOVERBURNERINVERTERSTORAGE",
     115              :                                                                                                         "RECOVERAUXILIARYBURNER",
     116              :                                                                                                         "RECOVERINVERTERANDSTORAGE",
     117              :                                                                                                         "RECOVERINVERTER",
     118              :                                                                                                         "RECOVERELECTRICALSTORAGE"};
     119              : 
     120              :     constexpr std::array<std::string_view, (int)DataGenerators::ConstituentMode::Num> constituentModeNames = {"AmbientAir",
     121              :                                                                                                               "UserDefinedConstituents"};
     122              :     constexpr std::array<std::string_view, (int)DataGenerators::ConstituentMode::Num> constituentModeNamesUC = {"AMBIENTAIR",
     123              :                                                                                                                 "USERDEFINEDCONSTITUENTS"};
     124              : 
     125              :     constexpr std::array<std::string_view, (int)DataGenerators::WaterTempMode::Num> waterTempModeNames = {
     126              :         "MainsWaterTemperature", "TemperatureFromAirNode", "TemperatureFromWaterNode", "TemperatureFromSchedule"};
     127              :     constexpr std::array<std::string_view, (int)DataGenerators::WaterTempMode::Num> waterTempModeNamesUC = {
     128              :         "MAINSWATERTEMPERATURE", "TEMPERATUREFROMAIRNODE", "TEMPERATUREFROMWATERNODE", "TEMPERATUREFROMSCHEDULE"};
     129              : 
     130              :     constexpr std::array<std::string_view, (int)DataGenerators::InverterEfficiencyMode::Num> inverterEfficiencyModeNames = {"Constant", "Quadratic"};
     131              :     constexpr std::array<std::string_view, (int)DataGenerators::InverterEfficiencyMode::Num> inverterEfficiencyModeNamesUC = {"CONSTANT",
     132              :                                                                                                                               "QUADRATIC"};
     133              : 
     134              :     constexpr std::array<std::string_view, (int)DataGenerators::ExhaustGasHX::Num> exhaustGasHXNames = {
     135              :         "FixedEffectiveness", "EmpiricalUAeff", "FundementalUAeff", "Condensing"};
     136              :     constexpr std::array<std::string_view, (int)DataGenerators::ExhaustGasHX::Num> exhaustGasHXNamesUC = {
     137              :         "FIXEDEFFECTIVENESS", "EMPIRICALUAEFF", "FUNDEMENTALUAEFF", "CONDENSING"};
     138              : 
     139              :     constexpr std::array<std::string_view, (int)DataGenerators::LossDestination::Num> lossDestinationNames = {"SurroundingZone",
     140              :                                                                                                               "AirInletForFuelCell"};
     141              :     constexpr std::array<std::string_view, (int)DataGenerators::LossDestination::Num> lossDestinationNamesUC = {"SURROUNDINGZONE",
     142              :                                                                                                                 "AIRINLETFORFUELCELL"};
     143              : 
     144         2237 :     PlantComponent *FCDataStruct::factory(EnergyPlusData &state, std::string const &objectName)
     145              :     {
     146              :         // Process the input data
     147         2237 :         if (state.dataFuelCellElectGen->getFuelCellInputFlag) {
     148            0 :             getFuelCellInput(state);
     149            0 :             state.dataFuelCellElectGen->getFuelCellInputFlag = false;
     150              :         }
     151              : 
     152              :         // Now look for this object
     153         2237 :         auto thisObj = std::find_if(state.dataFuelCellElectGen->FuelCell.begin(),
     154         2237 :                                     state.dataFuelCellElectGen->FuelCell.end(),
     155         2237 :                                     [&objectName](const FCDataStruct &myObj) { return myObj.Name == objectName; });
     156         2237 :         if (thisObj != state.dataFuelCellElectGen->FuelCell.end()) return thisObj;
     157              : 
     158              :         // If we didn't find it, fatal
     159              :         ShowFatalError(state, format("LocalFuelCellGenFactory: Error getting inputs for object named: {}", objectName)); // LCOV_EXCL_LINE
     160              :         // Shut up the compiler
     161              :         return nullptr; // LCOV_EXCL_LINE
     162              :     }
     163              : 
     164            1 :     PlantComponent *FCDataStruct::factory_exhaust(EnergyPlusData &state, std::string const &objectName)
     165              :     {
     166              :         // Process the input data
     167            1 :         if (state.dataFuelCellElectGen->getFuelCellInputFlag) {
     168            1 :             getFuelCellInput(state);
     169            1 :             state.dataFuelCellElectGen->getFuelCellInputFlag = false;
     170              :         }
     171              : 
     172              :         // Now look for this object
     173            1 :         for (auto &thisFC : state.dataFuelCellElectGen->FuelCell) {
     174            1 :             if (Util::makeUPPER(thisFC.NameExhaustHX) == Util::makeUPPER(objectName)) {
     175            1 :                 return &thisFC;
     176              :             }
     177              :         }
     178              :         // If we didn't find it, fatal
     179              :         ShowFatalError(state, format("LocalFuelCellGenFactory: Error getting inputs for object named: {}", objectName)); // LCOV_EXCL_LINE
     180              :         // Shut up the compiler
     181              :         return nullptr; // LCOV_EXCL_LINE
     182              :     }
     183              : 
     184         2235 :     void FCDataStruct::SimFuelCellGenerator(EnergyPlusData &state,
     185              :                                             bool const RunFlag,  // simulate Generator when TRUE
     186              :                                             Real64 const MyLoad, // demand on electric generator
     187              :                                             bool const FirstHVACIteration)
     188              :     {
     189              :         // SUBROUTINE INFORMATION:
     190              :         //       AUTHOR         Brent Griffith
     191              :         //       DATE WRITTEN   March 2005
     192              : 
     193              :         // PURPOSE OF THIS SUBROUTINE: This is the Solid oxide fuel cell Generator model driver.  It
     194              :         // gets the input for the models, initializes simulation variables, call
     195              :         // the appropriate model and sets up reporting variables.
     196              : 
     197         2235 :         this->initialize(state);
     198         2235 :         this->CalcFuelCellGeneratorModel(state, RunFlag, MyLoad, FirstHVACIteration);
     199         2235 :         this->CalcUpdateHeatRecovery(state, FirstHVACIteration);
     200         2235 :         this->UpdateFuelCellGeneratorRecords(state);
     201         2235 :     }
     202              : 
     203            1 :     void getFuelCellInput(EnergyPlusData &state)
     204              :     {
     205              :         // SUBROUTINE INFORMATION:
     206              :         //       AUTHOR:          Brent Griffith
     207              :         //       DATE WRITTEN:    April 2005
     208              : 
     209              :         // PURPOSE OF THIS SUBROUTINE:
     210              :         // This routine will get the input
     211              :         // required by the FuelCell Generator models.
     212              : 
     213              :         // METHODOLOGY EMPLOYED:
     214              :         // EnergyPlus input processor
     215              :         static constexpr std::string_view routineName = "getFuelCellInput";
     216              : 
     217              :         int NumAlphas;                 // Number of elements in the alpha array
     218              :         int NumNums;                   // Number of elements in the numeric array
     219              :         int IOStat;                    // IO Status when calling get input subroutine
     220            1 :         Array1D_string AlphArray(25);  // character string data
     221            1 :         Array1D<Real64> NumArray(200); // numeric data TODO deal with allocatable for extensible
     222            1 :         bool ErrorsFound(false);       // error flag
     223              : 
     224            1 :         auto &s_ipsc = state.dataIPShortCut;
     225              : 
     226            1 :         s_ipsc->cCurrentModuleObject = "Generator:FuelCell";
     227            2 :         state.dataFuelCellElectGen->NumFuelCellGenerators =
     228            1 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
     229              : 
     230            1 :         if (state.dataFuelCellElectGen->NumFuelCellGenerators <= 0) {
     231            0 :             ShowSevereError(state, format("No {} equipment specified in input file", s_ipsc->cCurrentModuleObject));
     232            0 :             ErrorsFound = true;
     233              :         }
     234              : 
     235              :         // ALLOCATE ARRAYS
     236            1 :         state.dataFuelCellElectGen->FuelCell.allocate(state.dataFuelCellElectGen->NumFuelCellGenerators); // inits handled in derived type definitions
     237              : 
     238              :         // first load in FuelCell names
     239            2 :         for (int GeneratorNum = 1; GeneratorNum <= state.dataFuelCellElectGen->NumFuelCellGenerators; ++GeneratorNum) {
     240            3 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     241            1 :                                                                      s_ipsc->cCurrentModuleObject,
     242              :                                                                      GeneratorNum,
     243              :                                                                      AlphArray,
     244              :                                                                      NumAlphas,
     245              :                                                                      NumArray,
     246              :                                                                      NumNums,
     247              :                                                                      IOStat,
     248              :                                                                      _,
     249              :                                                                      _,
     250            1 :                                                                      s_ipsc->cAlphaFieldNames,
     251            1 :                                                                      s_ipsc->cNumericFieldNames);
     252              : 
     253            1 :             state.dataFuelCellElectGen->FuelCell(GeneratorNum).Name = AlphArray(1);
     254            1 :             state.dataFuelCellElectGen->FuelCell(GeneratorNum).NameFCPM = AlphArray(2);
     255            1 :             state.dataFuelCellElectGen->FuelCell(GeneratorNum).NameFCAirSup = AlphArray(3);
     256            1 :             state.dataFuelCellElectGen->FuelCell(GeneratorNum).NameFCFuelSup = AlphArray(4);
     257            1 :             state.dataFuelCellElectGen->FuelCell(GeneratorNum).NameFCWaterSup = AlphArray(5);
     258            1 :             state.dataFuelCellElectGen->FuelCell(GeneratorNum).NameFCAuxilHeat = AlphArray(6);
     259            1 :             state.dataFuelCellElectGen->FuelCell(GeneratorNum).NameExhaustHX = AlphArray(7);
     260            1 :             state.dataFuelCellElectGen->FuelCell(GeneratorNum).NameElecStorage = AlphArray(8);
     261            1 :             state.dataFuelCellElectGen->FuelCell(GeneratorNum).NameInverter = AlphArray(9);
     262            1 :             if (NumAlphas == 10) {
     263            0 :                 state.dataFuelCellElectGen->FuelCell(GeneratorNum).NameStackCooler = AlphArray(10);
     264              :             }
     265              :         }
     266              : 
     267            1 :         s_ipsc->cCurrentModuleObject = "Generator:FuelCell:PowerModule";
     268            1 :         int NumFuelCellPMs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
     269              : 
     270            1 :         if (NumFuelCellPMs <= 0) {
     271            0 :             ShowSevereError(state, format("No {} equipment specified in input file", s_ipsc->cCurrentModuleObject));
     272            0 :             ErrorsFound = true;
     273              :         }
     274              : 
     275            2 :         for (int FCPMNum = 1; FCPMNum <= NumFuelCellPMs; ++FCPMNum) {
     276            3 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     277            1 :                                                                      s_ipsc->cCurrentModuleObject,
     278              :                                                                      FCPMNum,
     279              :                                                                      AlphArray,
     280              :                                                                      NumAlphas,
     281              :                                                                      NumArray,
     282              :                                                                      NumNums,
     283              :                                                                      IOStat,
     284              :                                                                      _,
     285            1 :                                                                      s_ipsc->lAlphaFieldBlanks,
     286            1 :                                                                      s_ipsc->cAlphaFieldNames,
     287            1 :                                                                      s_ipsc->cNumericFieldNames);
     288              : 
     289            1 :             ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, AlphArray(1)};
     290              : 
     291            1 :             int fuelCellNum = Util::FindItemInList(AlphArray(1), state.dataFuelCellElectGen->FuelCell, &FCDataStruct::NameFCPM);
     292            1 :             if (fuelCellNum > 0) {
     293              : 
     294            1 :                 auto &fuelCell = state.dataFuelCellElectGen->FuelCell(fuelCellNum);
     295              : 
     296            1 :                 fuelCell.FCPM.Name = AlphArray(1);
     297            1 :                 fuelCell.FCPM.EffMode = static_cast<DataGenerators::CurveMode>(getEnumValue(curveModeNamesUC, AlphArray(2)));
     298            1 :                 if (fuelCell.FCPM.EffMode == DataGenerators::CurveMode::Invalid) {
     299            0 :                     ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(2), AlphArray(2));
     300            0 :                     ErrorsFound = true;
     301              :                 }
     302              : 
     303            1 :                 if (s_ipsc->lAlphaFieldBlanks(3)) {
     304            0 :                     ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(3));
     305            0 :                     ErrorsFound = true;
     306            1 :                 } else if ((fuelCell.FCPM.EffCurve = Curve::GetCurve(state, AlphArray(3))) == nullptr) {
     307            0 :                     ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), AlphArray(3));
     308            0 :                     ErrorsFound = true;
     309              :                 }
     310              : 
     311            1 :                 fuelCell.FCPM.NomEff = NumArray(1);
     312            1 :                 fuelCell.FCPM.NomPel = NumArray(2);
     313            1 :                 fuelCell.FCPM.NumCyclesAtStart = NumArray(3);
     314            1 :                 fuelCell.FCPM.NumCycles = fuelCell.FCPM.NumCyclesAtStart;
     315            1 :                 fuelCell.FCPM.CyclingDegradRat = NumArray(4);
     316            1 :                 fuelCell.FCPM.NumRunHours = NumArray(5);
     317            1 :                 fuelCell.FCPM.OperateDegradRat = NumArray(6);
     318            1 :                 fuelCell.FCPM.ThreshRunHours = NumArray(7);
     319            1 :                 fuelCell.FCPM.UpTranLimit = NumArray(8);
     320            1 :                 fuelCell.FCPM.DownTranLimit = NumArray(9);
     321            1 :                 fuelCell.FCPM.StartUpTime = NumArray(10) / Constant::rSecsInHour; // convert to hours from seconds
     322            1 :                 fuelCell.FCPM.StartUpFuel = NumArray(11);
     323            1 :                 fuelCell.FCPM.StartUpElectConsum = NumArray(12);
     324            1 :                 fuelCell.FCPM.StartUpElectProd = NumArray(13);
     325            1 :                 fuelCell.FCPM.ShutDownTime = NumArray(14) / Constant::rSecsInHour; // convert to hours from seconds
     326            1 :                 fuelCell.FCPM.ShutDownFuel = NumArray(15);
     327            1 :                 fuelCell.FCPM.ShutDownElectConsum = NumArray(16);
     328            1 :                 fuelCell.FCPM.ANC0 = NumArray(17);
     329            1 :                 fuelCell.FCPM.ANC1 = NumArray(18);
     330            1 :                 fuelCell.FCPM.SkinLossMode = static_cast<DataGenerators::SkinLoss>(getEnumValue(skinLossNamesUC, AlphArray(4)));
     331            1 :                 if (fuelCell.FCPM.SkinLossMode == DataGenerators::SkinLoss::Invalid) {
     332            0 :                     ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(4), AlphArray(4));
     333            0 :                     ErrorsFound = true;
     334              :                 }
     335              : 
     336            1 :                 fuelCell.FCPM.ZoneName = AlphArray(5);
     337            1 :                 fuelCell.FCPM.ZoneID = Util::FindItemInList(fuelCell.FCPM.ZoneName, state.dataHeatBal->Zone);
     338            1 :                 if (fuelCell.FCPM.ZoneID == 0 && !s_ipsc->lAlphaFieldBlanks(5)) {
     339            0 :                     ShowSevereError(state, format("Invalid, {} = {}", s_ipsc->cAlphaFieldNames(5), AlphArray(5)));
     340            0 :                     ShowContinueError(state, format("Entered in {}={}", s_ipsc->cCurrentModuleObject, AlphArray(1)));
     341            0 :                     ShowContinueError(state, "Zone Name was not found ");
     342            0 :                     ErrorsFound = true;
     343              :                 }
     344              : 
     345            1 :                 fuelCell.FCPM.RadiativeFract = NumArray(19);
     346            1 :                 fuelCell.FCPM.QdotSkin = NumArray(20);
     347            1 :                 fuelCell.FCPM.UAskin = NumArray(21);
     348              : 
     349            1 :                 if (s_ipsc->lAlphaFieldBlanks(6)) {
     350            0 :                     if (fuelCell.FCPM.SkinLossMode == DataGenerators::SkinLoss::QuadraticFuelNdot) {
     351            0 :                         ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(6));
     352            0 :                         ErrorsFound = true;
     353              :                     }
     354            1 :                 } else if ((fuelCell.FCPM.SkinLossCurve = Curve::GetCurve(state, AlphArray(6))) == nullptr) {
     355            0 :                     if (fuelCell.FCPM.SkinLossMode == DataGenerators::SkinLoss::QuadraticFuelNdot) {
     356            0 :                         ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(6), AlphArray(6));
     357            0 :                         ErrorsFound = true;
     358              :                     }
     359              :                 }
     360              : 
     361            1 :                 fuelCell.FCPM.NdotDilutionAir = NumArray(22);
     362            1 :                 fuelCell.FCPM.StackHeatLossToDilution = NumArray(23);
     363            1 :                 fuelCell.FCPM.DilutionInletNodeName = AlphArray(7);
     364            1 :                 fuelCell.FCPM.DilutionInletNode =
     365            1 :                     NodeInputManager::GetOnlySingleNode(state,
     366            1 :                                                         AlphArray(7),
     367              :                                                         ErrorsFound,
     368              :                                                         DataLoopNode::ConnectionObjectType::GeneratorFuelCellPowerModule,
     369            1 :                                                         AlphArray(1),
     370              :                                                         DataLoopNode::NodeFluidType::Air,
     371              :                                                         DataLoopNode::ConnectionType::Inlet,
     372              :                                                         NodeInputManager::CompFluidStream::Primary,
     373              :                                                         DataLoopNode::ObjectIsNotParent);
     374            1 :                 fuelCell.FCPM.DilutionExhaustNodeName = AlphArray(8);
     375            1 :                 fuelCell.FCPM.DilutionExhaustNode =
     376            1 :                     NodeInputManager::GetOnlySingleNode(state,
     377            1 :                                                         AlphArray(8),
     378              :                                                         ErrorsFound,
     379              :                                                         DataLoopNode::ConnectionObjectType::GeneratorFuelCellPowerModule,
     380            1 :                                                         AlphArray(1),
     381              :                                                         DataLoopNode::NodeFluidType::Air,
     382              :                                                         DataLoopNode::ConnectionType::Outlet,
     383              :                                                         NodeInputManager::CompFluidStream::Primary,
     384              :                                                         DataLoopNode::ObjectIsNotParent);
     385              : 
     386            1 :                 fuelCell.FCPM.PelMin = NumArray(24);
     387            1 :                 fuelCell.FCPM.PelMax = NumArray(25);
     388              : 
     389              :                 // check for other FuelCell using the same power module and fill
     390            1 :                 for (int otherFuelCell = fuelCellNum + 1; otherFuelCell <= state.dataFuelCellElectGen->NumFuelCellGenerators; ++otherFuelCell) {
     391            0 :                     if (Util::SameString(state.dataFuelCellElectGen->FuelCell(otherFuelCell).FCPM.Name, fuelCell.FCPM.Name)) {
     392            0 :                         state.dataFuelCellElectGen->FuelCell(otherFuelCell).FCPM = fuelCell.FCPM;
     393              :                     }
     394              :                 }
     395              :             } else { // throw warning, did not find power module input
     396            0 :                 ShowSevereError(state, format("Invalid, {} = {}", s_ipsc->cAlphaFieldNames(1), AlphArray(1)));
     397            0 :                 ShowContinueError(state, format("Entered in {}={}", s_ipsc->cCurrentModuleObject, AlphArray(1)));
     398            0 :                 ErrorsFound = true;
     399              :             }
     400              :         } // loop over NumFuelCellPMs
     401              : 
     402            1 :         GeneratorFuelSupply::GetGeneratorFuelSupplyInput(state);
     403              : 
     404            2 :         for (int FuelSupNum = 1; FuelSupNum <= (int)state.dataGenerator->FuelSupply.size(); ++FuelSupNum) {
     405            1 :             GeneratorFuelSupply::SetupFuelConstituentData(state, FuelSupNum, ErrorsFound);
     406              :         }
     407              : 
     408              :         // set fuel supply ID in Fuel cell structure
     409            2 :         for (int GeneratorNum = 1; GeneratorNum <= state.dataFuelCellElectGen->NumFuelCellGenerators; ++GeneratorNum) {
     410            1 :             state.dataFuelCellElectGen->FuelCell(GeneratorNum).FuelSupNum = Util::FindItemInList(
     411            1 :                 state.dataFuelCellElectGen->FuelCell(GeneratorNum).NameFCFuelSup, state.dataGenerator->FuelSupply); // Fuel Supply ID
     412            1 :             if (state.dataFuelCellElectGen->FuelCell(GeneratorNum).FuelSupNum == 0) {
     413            0 :                 ShowSevereError(state,
     414            0 :                                 format("Fuel Supply Name: {} not found in {}",
     415            0 :                                        state.dataFuelCellElectGen->FuelCell(GeneratorNum).NameFCFuelSup,
     416            0 :                                        state.dataFuelCellElectGen->FuelCell(GeneratorNum).Name));
     417            0 :                 ErrorsFound = true;
     418              :             }
     419              :         }
     420              : 
     421            1 :         s_ipsc->cCurrentModuleObject = "Generator:FuelCell:AirSupply";
     422            1 :         int NumFuelCellAirSups = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
     423              : 
     424            1 :         if (NumFuelCellAirSups <= 0) { // Autodesk:Uninit thisFuelCell was possibly uninitialized past this condition
     425            0 :             ShowSevereError(state, format("No {} equipment specified in input file", s_ipsc->cCurrentModuleObject));
     426            0 :             ErrorsFound = true;
     427              :         }
     428              : 
     429            2 :         for (int FCAirSupNum = 1; FCAirSupNum <= NumFuelCellAirSups; ++FCAirSupNum) {
     430            3 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     431            1 :                                                                      s_ipsc->cCurrentModuleObject,
     432              :                                                                      FCAirSupNum,
     433              :                                                                      AlphArray,
     434              :                                                                      NumAlphas,
     435              :                                                                      NumArray,
     436              :                                                                      NumNums,
     437              :                                                                      IOStat,
     438              :                                                                      _,
     439            1 :                                                                      s_ipsc->lAlphaFieldBlanks,
     440            1 :                                                                      s_ipsc->cAlphaFieldNames,
     441            1 :                                                                      s_ipsc->cNumericFieldNames);
     442              : 
     443            1 :             ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, AlphArray(1)};
     444              : 
     445            1 :             int fuelCellNum = Util::FindItemInList(AlphArray(1), state.dataFuelCellElectGen->FuelCell, &FCDataStruct::NameFCAirSup);
     446              : 
     447            1 :             if (fuelCellNum > 0) {
     448              : 
     449            1 :                 auto &fuelCell = state.dataFuelCellElectGen->FuelCell(fuelCellNum);
     450            1 :                 fuelCell.AirSup.Name = AlphArray(1);
     451            1 :                 fuelCell.AirSup.NodeName = AlphArray(2);
     452              : 
     453              :                 // check the node connections
     454            1 :                 fuelCell.AirSup.SupNodeNum = NodeInputManager::GetOnlySingleNode(state,
     455            1 :                                                                                  AlphArray(2),
     456              :                                                                                  ErrorsFound,
     457              :                                                                                  DataLoopNode::ConnectionObjectType::GeneratorFuelCellAirSupply,
     458            1 :                                                                                  AlphArray(1),
     459              :                                                                                  DataLoopNode::NodeFluidType::Air,
     460              :                                                                                  DataLoopNode::ConnectionType::Inlet,
     461              :                                                                                  NodeInputManager::CompFluidStream::Primary,
     462              :                                                                                  DataLoopNode::ObjectIsNotParent);
     463              : 
     464            1 :                 if (s_ipsc->lAlphaFieldBlanks(3)) {
     465            0 :                     ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(3));
     466            0 :                     ErrorsFound = true;
     467            1 :                 } else if ((fuelCell.AirSup.BlowerPowerCurve = Curve::GetCurve(state, AlphArray(3))) == nullptr) {
     468            0 :                     ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), AlphArray(3));
     469            0 :                     ErrorsFound = true;
     470              :                 }
     471            1 :                 fuelCell.AirSup.BlowerHeatLossFactor = NumArray(1);
     472              : 
     473            1 :                 fuelCell.AirSup.AirSupRateMode = static_cast<DataGenerators::AirSupRateMode>(getEnumValue(airSupRateModeNamesUC, AlphArray(4)));
     474            1 :                 if (fuelCell.AirSup.AirSupRateMode == DataGenerators::AirSupRateMode::Invalid) {
     475            0 :                     ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(4), AlphArray(4));
     476            0 :                     ErrorsFound = true;
     477              :                 }
     478              : 
     479            1 :                 fuelCell.AirSup.Stoics = NumArray(2) + 1.0;
     480              : 
     481            1 :                 if (s_ipsc->lAlphaFieldBlanks(5)) {
     482            0 :                     if (fuelCell.AirSup.AirSupRateMode == DataGenerators::AirSupRateMode::QuadraticFuncofPel) {
     483            0 :                         ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(5));
     484            0 :                         ErrorsFound = true;
     485              :                     }
     486            1 :                 } else if ((fuelCell.AirSup.AirFuncPelCurve = Curve::GetCurve(state, AlphArray(5))) == nullptr) {
     487            0 :                     if (fuelCell.AirSup.AirSupRateMode == DataGenerators::AirSupRateMode::QuadraticFuncofPel) {
     488            0 :                         ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(5), AlphArray(5));
     489            0 :                         ErrorsFound = true;
     490              :                     }
     491              :                 }
     492              : 
     493            1 :                 fuelCell.AirSup.AirTempCoeff = NumArray(3);
     494              : 
     495            1 :                 if (s_ipsc->lAlphaFieldBlanks(6)) {
     496            1 :                     if (fuelCell.AirSup.AirSupRateMode == DataGenerators::AirSupRateMode::QuadraticFuncofNdot) {
     497            0 :                         ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(6));
     498            0 :                         ErrorsFound = true;
     499              :                     }
     500            0 :                 } else if ((fuelCell.AirSup.AirFuncNdotCurve = Curve::GetCurve(state, AlphArray(6))) == nullptr) {
     501            0 :                     if (fuelCell.AirSup.AirSupRateMode == DataGenerators::AirSupRateMode::QuadraticFuncofNdot) {
     502            0 :                         ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(6), AlphArray(6));
     503            0 :                         ErrorsFound = true;
     504              :                     }
     505              :                 }
     506              : 
     507            1 :                 fuelCell.AirSup.IntakeRecoveryMode = static_cast<DataGenerators::RecoverMode>(getEnumValue(recoverModeNamesUC, AlphArray(7)));
     508            1 :                 if (fuelCell.AirSup.IntakeRecoveryMode == DataGenerators::RecoverMode::Invalid) {
     509            0 :                     ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(7), AlphArray(7));
     510            0 :                     ErrorsFound = true;
     511              :                 }
     512              : 
     513            1 :                 fuelCell.AirSup.ConstituentMode = static_cast<DataGenerators::ConstituentMode>(getEnumValue(constituentModeNamesUC, AlphArray(8)));
     514            1 :                 if (fuelCell.AirSup.ConstituentMode == DataGenerators::ConstituentMode::Invalid) {
     515            0 :                     ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(8), AlphArray(8));
     516            0 :                     ErrorsFound = true;
     517              :                 }
     518              : 
     519              :                 int NumAirConstit;
     520              : 
     521            1 :                 if (fuelCell.AirSup.ConstituentMode == DataGenerators::ConstituentMode::UserDefinedConstituents) {
     522            0 :                     NumAirConstit = NumArray(4);
     523            0 :                     fuelCell.AirSup.NumConstituents = NumAirConstit;
     524              : 
     525            0 :                     if (NumAirConstit > 5) {
     526            0 :                         ShowSevereError(state, format("Invalid {}={:.2R}", s_ipsc->cNumericFieldNames(4), NumArray(4)));
     527            0 :                         ShowContinueError(state, format("Entered in {}={}", s_ipsc->cCurrentModuleObject, AlphArray(1)));
     528            0 :                         ShowContinueError(state, "Fuel Cell model not set up for more than 5 air constituents");
     529            0 :                         ErrorsFound = true;
     530              :                     }
     531              : 
     532            0 :                     for (int ConstitNum = 1; ConstitNum <= NumAirConstit; ++ConstitNum) {
     533            0 :                         fuelCell.AirSup.ConstitName(ConstitNum) = AlphArray(ConstitNum + 8);
     534            0 :                         fuelCell.AirSup.ConstitMolalFract(ConstitNum) = NumArray(ConstitNum + 4);
     535              :                     }
     536              : 
     537              :                 } else { // regular air
     538            1 :                     NumAirConstit = 5;
     539              : 
     540            1 :                     fuelCell.AirSup.NumConstituents = NumAirConstit;
     541              : 
     542            1 :                     fuelCell.AirSup.ConstitName(1) = "Nitrogen";
     543            1 :                     fuelCell.AirSup.ConstitMolalFract(1) = 0.7728;
     544              : 
     545            1 :                     fuelCell.AirSup.ConstitName(2) = "Oxygen";
     546            1 :                     fuelCell.AirSup.ConstitMolalFract(2) = 0.2073;
     547              : 
     548            1 :                     fuelCell.AirSup.ConstitName(3) = "Water";
     549            1 :                     fuelCell.AirSup.ConstitMolalFract(3) = 0.0104;
     550              : 
     551            1 :                     fuelCell.AirSup.ConstitName(4) = "Argon";
     552            1 :                     fuelCell.AirSup.ConstitMolalFract(4) = 0.0092;
     553              : 
     554            1 :                     fuelCell.AirSup.ConstitName(5) = "CarbonDioxide";
     555            1 :                     fuelCell.AirSup.ConstitMolalFract(5) = 0.0003;
     556              :                 }
     557              : 
     558              :                 // check for molar fractions summing to 1.0.
     559            1 :                 if (std::abs(sum(fuelCell.AirSup.ConstitMolalFract) - 1.0) > 0.0001) {
     560              : 
     561            0 :                     ShowSevereError(state, format("{} molar fractions do not sum to 1.0", s_ipsc->cCurrentModuleObject));
     562            0 :                     ShowContinueError(state, format("..Sum was={:.1R}", sum(fuelCell.AirSup.ConstitMolalFract)));
     563            0 :                     ShowContinueError(state, format("Entered in {} = {}", s_ipsc->cCurrentModuleObject, AlphArray(1)));
     564            0 :                     ErrorsFound = true;
     565              :                 }
     566              : 
     567              :                 // check for other FuelCell using the same Air Supply module and fill
     568            1 :                 for (int otherFuelCell = fuelCellNum + 1; otherFuelCell <= state.dataFuelCellElectGen->NumFuelCellGenerators; ++otherFuelCell) {
     569            0 :                     if (Util::SameString(state.dataFuelCellElectGen->FuelCell(otherFuelCell).AirSup.Name, fuelCell.AirSup.Name)) {
     570            0 :                         state.dataFuelCellElectGen->FuelCell(otherFuelCell).AirSup = fuelCell.AirSup;
     571              :                     }
     572              :                 }
     573              :             } else {
     574            0 :                 ShowSevereError(state, format("Invalid, {} = {}", s_ipsc->cAlphaFieldNames(1), AlphArray(1)));
     575            0 :                 ShowContinueError(state, format("Entered in {}={}", s_ipsc->cCurrentModuleObject, AlphArray(1)));
     576            0 :                 ErrorsFound = true;
     577              :             }
     578              :         }
     579              : 
     580            2 :         for (int GeneratorNum = 1; GeneratorNum <= state.dataFuelCellElectGen->NumFuelCellGenerators; ++GeneratorNum) {
     581              :             // find molar fraction of oxygen in air supply
     582            1 :             int thisConstituent = Util::FindItem("Oxygen",
     583            1 :                                                  state.dataFuelCellElectGen->FuelCell(GeneratorNum).AirSup.ConstitName,
     584            1 :                                                  state.dataFuelCellElectGen->FuelCell(GeneratorNum).AirSup.NumConstituents);
     585            1 :             if (thisConstituent > 0)
     586            1 :                 state.dataFuelCellElectGen->FuelCell(GeneratorNum).AirSup.O2fraction =
     587            1 :                     state.dataFuelCellElectGen->FuelCell(GeneratorNum).AirSup.ConstitMolalFract(thisConstituent);
     588              : 
     589              :             // Loop over air constituents and do one-time setup
     590            6 :             for (int i = 1; i <= state.dataFuelCellElectGen->FuelCell(GeneratorNum).AirSup.NumConstituents; ++i) {
     591              : 
     592            5 :                 std::string thisName = state.dataFuelCellElectGen->FuelCell(GeneratorNum).AirSup.ConstitName(i);
     593              : 
     594            5 :                 int thisGasID = Util::FindItem(
     595            5 :                     thisName, state.dataGenerator->GasPhaseThermoChemistryData, &DataGenerators::GasPropertyDataStruct::ConstituentName);
     596              : 
     597            5 :                 state.dataFuelCellElectGen->FuelCell(GeneratorNum).AirSup.GasLibID(i) = static_cast<GasID>(thisGasID);
     598            5 :             }
     599              : 
     600              :             // set up gas constituents for product gases
     601            1 :             state.dataFuelCellElectGen->FuelCell(GeneratorNum).FCPM.GasLibID(1) = GasID::CarbonDioxide;
     602            1 :             state.dataFuelCellElectGen->FuelCell(GeneratorNum).FCPM.GasLibID(2) = GasID::Nitrogen;
     603            1 :             state.dataFuelCellElectGen->FuelCell(GeneratorNum).FCPM.GasLibID(3) = GasID::Oxygen;
     604            1 :             state.dataFuelCellElectGen->FuelCell(GeneratorNum).FCPM.GasLibID(4) = GasID::Water;
     605            1 :             state.dataFuelCellElectGen->FuelCell(GeneratorNum).FCPM.GasLibID(5) = GasID::Argon;
     606              :         }
     607              : 
     608            1 :         s_ipsc->cCurrentModuleObject = "Generator:FuelCell:WaterSupply";
     609            1 :         int NumFCWaterSups = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
     610              : 
     611            1 :         if (NumFCWaterSups <= 0) {
     612            0 :             ShowSevereError(state, format("No {} equipment specified in input file", s_ipsc->cCurrentModuleObject));
     613            0 :             ErrorsFound = true;
     614              :         }
     615              : 
     616            2 :         for (int FCWaterSupNum = 1; FCWaterSupNum <= NumFCWaterSups; ++FCWaterSupNum) {
     617            3 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     618            1 :                                                                      s_ipsc->cCurrentModuleObject,
     619              :                                                                      FCWaterSupNum,
     620              :                                                                      AlphArray,
     621              :                                                                      NumAlphas,
     622              :                                                                      NumArray,
     623              :                                                                      NumNums,
     624              :                                                                      IOStat,
     625              :                                                                      _,
     626            1 :                                                                      s_ipsc->lAlphaFieldBlanks,
     627            1 :                                                                      s_ipsc->cAlphaFieldNames,
     628            1 :                                                                      s_ipsc->cNumericFieldNames);
     629              : 
     630            1 :             ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, AlphArray(1)};
     631            1 :             int fuelCellNum = Util::FindItemInList(AlphArray(1), state.dataFuelCellElectGen->FuelCell, &FCDataStruct::NameFCWaterSup);
     632              : 
     633            1 :             if (fuelCellNum > 0) {
     634              : 
     635            1 :                 auto &fuelCell = state.dataFuelCellElectGen->FuelCell(fuelCellNum);
     636              : 
     637              :                 //  this is only the first instance of a FuelCell generator using this type of Water supply module
     638            1 :                 fuelCell.WaterSup.Name = AlphArray(1);
     639              : 
     640            1 :                 if (s_ipsc->lAlphaFieldBlanks(2)) {
     641            0 :                     ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(2));
     642            0 :                     ErrorsFound = true;
     643            1 :                 } else if ((fuelCell.WaterSup.WaterSupRateCurve = Curve::GetCurve(state, AlphArray(2))) == nullptr) {
     644            0 :                     ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(2), AlphArray(2));
     645            0 :                     ErrorsFound = true;
     646              :                 }
     647              : 
     648            1 :                 if (s_ipsc->lAlphaFieldBlanks(3)) {
     649            0 :                     ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(2));
     650            0 :                     ErrorsFound = true;
     651            1 :                 } else if ((fuelCell.WaterSup.PmpPowerCurve = Curve::GetCurve(state, AlphArray(3))) == nullptr) {
     652            0 :                     ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), AlphArray(3));
     653            0 :                     ErrorsFound = true;
     654              :                 }
     655              : 
     656            1 :                 fuelCell.WaterSup.PmpPowerLossFactor = NumArray(1);
     657              : 
     658            1 :                 fuelCell.WaterSup.waterTempMode = static_cast<DataGenerators::WaterTempMode>(getEnumValue(waterTempModeNamesUC, AlphArray(4)));
     659              : 
     660            1 :                 if (fuelCell.WaterSup.waterTempMode == DataGenerators::WaterTempMode::Invalid) {
     661            0 :                     ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(4), AlphArray(4));
     662            0 :                     ErrorsFound = true;
     663              : 
     664            1 :                 } else if (fuelCell.WaterSup.waterTempMode == DataGenerators::WaterTempMode::AirNode) {
     665            0 :                     fuelCell.WaterSup.NodeName = AlphArray(5);
     666            0 :                     fuelCell.WaterSup.NodeNum = NodeInputManager::GetOnlySingleNode(state,
     667            0 :                                                                                     AlphArray(5),
     668              :                                                                                     ErrorsFound,
     669              :                                                                                     DataLoopNode::ConnectionObjectType::GeneratorFuelCellWaterSupply,
     670            0 :                                                                                     AlphArray(1),
     671              :                                                                                     DataLoopNode::NodeFluidType::Air,
     672              :                                                                                     DataLoopNode::ConnectionType::Sensor,
     673              :                                                                                     NodeInputManager::CompFluidStream::Primary,
     674              :                                                                                     DataLoopNode::ObjectIsNotParent);
     675              : 
     676            1 :                 } else if (fuelCell.WaterSup.waterTempMode == DataGenerators::WaterTempMode::WaterNode) {
     677            0 :                     fuelCell.WaterSup.NodeName = AlphArray(5);
     678            0 :                     fuelCell.WaterSup.NodeNum = NodeInputManager::GetOnlySingleNode(state,
     679            0 :                                                                                     AlphArray(5),
     680              :                                                                                     ErrorsFound,
     681              :                                                                                     DataLoopNode::ConnectionObjectType::GeneratorFuelCellWaterSupply,
     682            0 :                                                                                     AlphArray(1),
     683              :                                                                                     DataLoopNode::NodeFluidType::Water,
     684              :                                                                                     DataLoopNode::ConnectionType::Sensor,
     685              :                                                                                     NodeInputManager::CompFluidStream::Primary,
     686              :                                                                                     DataLoopNode::ObjectIsNotParent);
     687              :                 }
     688              : 
     689            1 :                 fuelCell.WaterSup.sched = Sched::GetSchedule(state, AlphArray(6));
     690            1 :                 if ((fuelCell.WaterSup.sched == nullptr) && (fuelCell.WaterSup.waterTempMode == DataGenerators::WaterTempMode::Schedule)) {
     691            0 :                     ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(6), AlphArray(6));
     692            0 :                     ErrorsFound = true;
     693              :                 }
     694              : 
     695              :                 // check for other FuelCell using the same Water Supply module and fill
     696            1 :                 for (int otherFuelCell = fuelCellNum + 1; otherFuelCell <= state.dataFuelCellElectGen->NumFuelCellGenerators; ++otherFuelCell) {
     697            0 :                     if (Util::SameString(state.dataFuelCellElectGen->FuelCell(otherFuelCell).WaterSup.Name, fuelCell.WaterSup.Name)) {
     698            0 :                         state.dataFuelCellElectGen->FuelCell(otherFuelCell).WaterSup = fuelCell.WaterSup;
     699              :                     }
     700              :                 }
     701              :             } else {
     702            0 :                 ShowSevereError(state, format("Invalid, {} = {}", s_ipsc->cAlphaFieldNames(1), AlphArray(1)));
     703            0 :                 ShowContinueError(state, format("Entered in {}={}", s_ipsc->cCurrentModuleObject, AlphArray(1)));
     704            0 :                 ErrorsFound = true;
     705              :             }
     706              :         }
     707              : 
     708            1 :         s_ipsc->cCurrentModuleObject = "Generator:FuelCell:AuxiliaryHeater";
     709            1 :         int NumFuelCellAuxilHeaters = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
     710              : 
     711            1 :         if (NumFuelCellAuxilHeaters <= 0) {
     712            0 :             ShowSevereError(state, format("No {} equipment specified in input file", s_ipsc->cCurrentModuleObject));
     713            0 :             ErrorsFound = true;
     714              :         }
     715              : 
     716            2 :         for (int FCAuxHeatNum = 1; FCAuxHeatNum <= NumFuelCellAuxilHeaters; ++FCAuxHeatNum) {
     717            3 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     718            1 :                                                                      s_ipsc->cCurrentModuleObject,
     719              :                                                                      FCAuxHeatNum,
     720              :                                                                      AlphArray,
     721              :                                                                      NumAlphas,
     722              :                                                                      NumArray,
     723              :                                                                      NumNums,
     724              :                                                                      IOStat,
     725              :                                                                      _,
     726            1 :                                                                      s_ipsc->lAlphaFieldBlanks,
     727            1 :                                                                      s_ipsc->cAlphaFieldNames,
     728            1 :                                                                      s_ipsc->cNumericFieldNames);
     729              : 
     730            1 :             ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, AlphArray(1)};
     731              : 
     732            1 :             int fuelCellNum = Util::FindItemInList(AlphArray(1), state.dataFuelCellElectGen->FuelCell, &FCDataStruct::NameFCAuxilHeat);
     733              : 
     734            1 :             if (fuelCellNum > 0) {
     735            1 :                 auto &fuelCell = state.dataFuelCellElectGen->FuelCell(fuelCellNum);
     736              : 
     737            1 :                 fuelCell.AuxilHeat.Name = AlphArray(1);
     738            1 :                 fuelCell.AuxilHeat.ExcessAirRAT = NumArray(1);
     739            1 :                 fuelCell.AuxilHeat.ANC0 = NumArray(2);
     740            1 :                 fuelCell.AuxilHeat.ANC1 = NumArray(3);
     741            1 :                 fuelCell.AuxilHeat.UASkin = NumArray(4);
     742              : 
     743            1 :                 fuelCell.AuxilHeat.SkinLossDestination =
     744            1 :                     static_cast<DataGenerators::LossDestination>(getEnumValue(lossDestinationNamesUC, AlphArray(2)));
     745            1 :                 if (fuelCell.AuxilHeat.SkinLossDestination == DataGenerators::LossDestination::Invalid) {
     746            0 :                     ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(2), AlphArray(2));
     747            0 :                     ErrorsFound = true;
     748            1 :                 } else if (fuelCell.AuxilHeat.SkinLossDestination == DataGenerators::LossDestination::SurroundingZone) {
     749            0 :                     fuelCell.AuxilHeat.ZoneName = AlphArray(3);
     750            0 :                     fuelCell.AuxilHeat.ZoneID = Util::FindItemInList(AlphArray(3), state.dataHeatBal->Zone);
     751            0 :                     if (fuelCell.AuxilHeat.ZoneID == 0) {
     752            0 :                         ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), AlphArray(3));
     753            0 :                         ErrorsFound = true;
     754              :                     }
     755              :                 }
     756              : 
     757            1 :                 fuelCell.AuxilHeat.MaxPowerW = NumArray(5);
     758            1 :                 fuelCell.AuxilHeat.MinPowerW = NumArray(6);
     759            1 :                 fuelCell.AuxilHeat.MaxPowerkmolperSec = NumArray(7);
     760            1 :                 fuelCell.AuxilHeat.MinPowerkmolperSec = NumArray(8);
     761              : 
     762              :                 // TODO finish Auxiliary heater
     763              : 
     764              :                 // check for other FuelCell using the same Auxiliary Heating module and fill
     765            1 :                 for (int otherFuelCell = fuelCellNum + 1; otherFuelCell <= state.dataFuelCellElectGen->NumFuelCellGenerators; ++otherFuelCell) {
     766            0 :                     if (Util::SameString(state.dataFuelCellElectGen->FuelCell(otherFuelCell).AuxilHeat.Name, fuelCell.AuxilHeat.Name)) {
     767            0 :                         state.dataFuelCellElectGen->FuelCell(otherFuelCell).AuxilHeat = fuelCell.AuxilHeat;
     768              :                     }
     769              :                 }
     770              :             } else {
     771            0 :                 ShowSevereError(state, format("Invalid, {} = {}", s_ipsc->cAlphaFieldNames(1), AlphArray(1)));
     772            0 :                 ShowContinueError(state, format("Entered in {}={}", s_ipsc->cCurrentModuleObject, AlphArray(1)));
     773            0 :                 ErrorsFound = true;
     774              :             }
     775              :         }
     776              : 
     777              :         // exhaust gas heat exchanger
     778            1 :         s_ipsc->cCurrentModuleObject = "Generator:FuelCell:ExhaustGasToWaterHeatExchanger";
     779            1 :         int NumFCExhaustGasHXs = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
     780            1 :         if (NumFCExhaustGasHXs <= 0) {
     781            0 :             ShowWarningError(state, format("No {} equipment specified in input file", s_ipsc->cCurrentModuleObject));
     782            0 :             ShowContinueError(state, format("Fuel Cell model requires an {} object", s_ipsc->cCurrentModuleObject));
     783            0 :             ErrorsFound = true;
     784              :         }
     785              : 
     786            2 :         for (int FCHXNum = 1; FCHXNum <= NumFCExhaustGasHXs; ++FCHXNum) {
     787            3 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     788            1 :                                                                      s_ipsc->cCurrentModuleObject,
     789              :                                                                      FCHXNum,
     790              :                                                                      AlphArray,
     791              :                                                                      NumAlphas,
     792              :                                                                      NumArray,
     793              :                                                                      NumNums,
     794              :                                                                      IOStat,
     795              :                                                                      _,
     796            1 :                                                                      s_ipsc->lAlphaFieldBlanks,
     797            1 :                                                                      s_ipsc->cAlphaFieldNames,
     798            1 :                                                                      s_ipsc->cNumericFieldNames);
     799              : 
     800            1 :             ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, AlphArray(1)};
     801              : 
     802            1 :             int fuelCellNum = Util::FindItemInList(AlphArray(1), state.dataFuelCellElectGen->FuelCell, &FCDataStruct::NameExhaustHX);
     803              : 
     804            1 :             if (fuelCellNum > 0) {
     805            1 :                 auto &fuelCell = state.dataFuelCellElectGen->FuelCell(fuelCellNum);
     806              : 
     807            1 :                 fuelCell.Type = DataPlant::PlantEquipmentType::Generator_FCExhaust;
     808            1 :                 fuelCell.ExhaustHX.Name = AlphArray(1);
     809            1 :                 fuelCell.ExhaustHX.WaterInNodeName = AlphArray(2);
     810            1 :                 fuelCell.ExhaustHX.WaterOutNodeName = AlphArray(3);
     811              :                 // find node ids for water path
     812            1 :                 fuelCell.ExhaustHX.WaterInNode =
     813            1 :                     NodeInputManager::GetOnlySingleNode(state,
     814            1 :                                                         AlphArray(2),
     815              :                                                         ErrorsFound,
     816              :                                                         DataLoopNode::ConnectionObjectType::GeneratorFuelCellExhaustGasToWaterHeatExchanger,
     817            1 :                                                         AlphArray(1),
     818              :                                                         DataLoopNode::NodeFluidType::Water,
     819              :                                                         DataLoopNode::ConnectionType::Inlet,
     820              :                                                         NodeInputManager::CompFluidStream::Primary,
     821              :                                                         DataLoopNode::ObjectIsNotParent);
     822            1 :                 fuelCell.ExhaustHX.WaterOutNode =
     823            2 :                     NodeInputManager::GetOnlySingleNode(state,
     824            1 :                                                         AlphArray(3),
     825              :                                                         ErrorsFound,
     826              :                                                         DataLoopNode::ConnectionObjectType::GeneratorFuelCellExhaustGasToWaterHeatExchanger,
     827            1 :                                                         AlphArray(1),
     828              :                                                         DataLoopNode::NodeFluidType::Water,
     829              :                                                         DataLoopNode::ConnectionType::Outlet,
     830              :                                                         NodeInputManager::CompFluidStream::Primary,
     831              :                                                         DataLoopNode::ObjectIsNotParent);
     832            2 :                 BranchNodeConnections::TestCompSet(
     833            1 :                     state, s_ipsc->cCurrentModuleObject, AlphArray(1), AlphArray(2), AlphArray(3), "Heat Recovery Nodes");
     834              : 
     835            1 :                 fuelCell.ExhaustHX.ExhaustOutNodeName = AlphArray(4);
     836            1 :                 fuelCell.ExhaustHX.ExhaustOutNode =
     837            1 :                     NodeInputManager::GetOnlySingleNode(state,
     838            1 :                                                         AlphArray(4),
     839              :                                                         ErrorsFound,
     840              :                                                         DataLoopNode::ConnectionObjectType::GeneratorFuelCellExhaustGasToWaterHeatExchanger,
     841            1 :                                                         AlphArray(1),
     842              :                                                         DataLoopNode::NodeFluidType::Air,
     843              :                                                         DataLoopNode::ConnectionType::Outlet,
     844              :                                                         NodeInputManager::CompFluidStream::Secondary,
     845              :                                                         DataLoopNode::ObjectIsNotParent);
     846              : 
     847            1 :                 fuelCell.ExhaustHX.HXmodelMode = static_cast<DataGenerators::ExhaustGasHX>(getEnumValue(exhaustGasHXNamesUC, AlphArray(5)));
     848            1 :                 if (fuelCell.ExhaustHX.HXmodelMode == DataGenerators::ExhaustGasHX::Invalid) {
     849            0 :                     ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(5), AlphArray(5));
     850            0 :                     ErrorsFound = true;
     851              :                 }
     852            1 :                 fuelCell.ExhaustHX.WaterVolumeFlowMax = NumArray(1);
     853            1 :                 fuelCell.ExhaustHX.HXEffect = NumArray(2);
     854            1 :                 fuelCell.ExhaustHX.hxs0 = NumArray(3);
     855            1 :                 fuelCell.ExhaustHX.hxs1 = NumArray(4);
     856            1 :                 fuelCell.ExhaustHX.hxs2 = NumArray(5);
     857            1 :                 fuelCell.ExhaustHX.hxs3 = NumArray(6);
     858            1 :                 fuelCell.ExhaustHX.hxs4 = NumArray(7);
     859            1 :                 fuelCell.ExhaustHX.h0gas = NumArray(8);
     860            1 :                 fuelCell.ExhaustHX.NdotGasRef = NumArray(9);
     861            1 :                 fuelCell.ExhaustHX.nCoeff = NumArray(10);
     862            1 :                 fuelCell.ExhaustHX.AreaGas = NumArray(11);
     863            1 :                 fuelCell.ExhaustHX.h0Water = NumArray(12);
     864            1 :                 fuelCell.ExhaustHX.NdotWaterRef = NumArray(13);
     865            1 :                 fuelCell.ExhaustHX.mCoeff = NumArray(14);
     866            1 :                 fuelCell.ExhaustHX.AreaWater = NumArray(15);
     867            1 :                 fuelCell.ExhaustHX.Fadjust = NumArray(16);
     868            1 :                 fuelCell.ExhaustHX.l1Coeff = NumArray(17);
     869            1 :                 fuelCell.ExhaustHX.l2Coeff = NumArray(18);
     870            1 :                 fuelCell.ExhaustHX.CondensationThresholdTemp = NumArray(19);
     871              : 
     872              :                 // store cooling water volume flow rate for autosizing system
     873            1 :                 PlantUtilities::RegisterPlantCompDesignFlow(state, fuelCell.ExhaustHX.WaterInNode, fuelCell.ExhaustHX.WaterVolumeFlowMax);
     874              :             } else {
     875            0 :                 ShowSevereError(state, format("Invalid, {} = {}", s_ipsc->cAlphaFieldNames(1), AlphArray(1)));
     876            0 :                 ShowContinueError(state, format("Entered in {}={}", s_ipsc->cCurrentModuleObject, AlphArray(1)));
     877            0 :                 ErrorsFound = true;
     878              :             }
     879              :         }
     880              : 
     881            1 :         s_ipsc->cCurrentModuleObject = "Generator:FuelCell:ElectricalStorage";
     882            1 :         int NumFCElecStorageUnits = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
     883              : 
     884            1 :         if (NumFCElecStorageUnits <= 0) {
     885            0 :             ShowWarningError(state, format("No {} equipment specified in input file", s_ipsc->cCurrentModuleObject));
     886            0 :             ShowContinueError(state, format("Fuel Cell model requires an {} object", s_ipsc->cCurrentModuleObject));
     887            0 :             ErrorsFound = true;
     888              :         }
     889              : 
     890            2 :         for (int StorageNum = 1; StorageNum <= NumFCElecStorageUnits; ++StorageNum) {
     891            3 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     892            1 :                                                                      s_ipsc->cCurrentModuleObject,
     893              :                                                                      StorageNum,
     894              :                                                                      AlphArray,
     895              :                                                                      NumAlphas,
     896              :                                                                      NumArray,
     897              :                                                                      NumNums,
     898              :                                                                      IOStat,
     899              :                                                                      _,
     900              :                                                                      _,
     901            1 :                                                                      s_ipsc->cAlphaFieldNames,
     902            1 :                                                                      s_ipsc->cNumericFieldNames);
     903              : 
     904            1 :             ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, AlphArray(1)};
     905              : 
     906            1 :             int fuelCellNum = Util::FindItemInList(AlphArray(1), state.dataFuelCellElectGen->FuelCell, &FCDataStruct::NameElecStorage);
     907              : 
     908            1 :             if (fuelCellNum > 0) {
     909            1 :                 auto &fuelCell = state.dataFuelCellElectGen->FuelCell(fuelCellNum);
     910            1 :                 fuelCell.ElecStorage.Name = AlphArray(1);
     911              : 
     912            1 :                 if (Util::SameString(AlphArray(2), "SimpleEfficiencyWithConstraints")) {
     913            1 :                     fuelCell.ElecStorage.StorageModelMode = DataGenerators::ElectricalStorage::SimpleEffConstraints;
     914              :                 } else {
     915            0 :                     ShowSevereError(state, format("Invalid, {} = {}", s_ipsc->cAlphaFieldNames(2), AlphArray(2)));
     916            0 :                     ShowContinueError(state, format("Entered in {}={}", s_ipsc->cCurrentModuleObject, AlphArray(1)));
     917            0 :                     ErrorsFound = true;
     918              :                 }
     919              : 
     920            1 :                 fuelCell.ElecStorage.EnergeticEfficCharge = NumArray(1);
     921            1 :                 fuelCell.ElecStorage.EnergeticEfficDischarge = NumArray(2);
     922            1 :                 fuelCell.ElecStorage.NominalEnergyCapacity = NumArray(3);
     923            1 :                 fuelCell.ElecStorage.MaxPowerDraw = NumArray(4);
     924            1 :                 fuelCell.ElecStorage.MaxPowerStore = NumArray(5);
     925            1 :                 fuelCell.ElecStorage.StartingEnergyStored = NumArray(6);
     926              : 
     927              :                 // check for other FuelCell using the same Electrical Storage and fill
     928            1 :                 for (int otherFuelCell = fuelCellNum + 1; otherFuelCell <= state.dataFuelCellElectGen->NumFuelCellGenerators; ++otherFuelCell) {
     929            0 :                     if (Util::SameString(state.dataFuelCellElectGen->FuelCell(otherFuelCell).ElecStorage.Name, fuelCell.ElecStorage.Name)) {
     930            0 :                         state.dataFuelCellElectGen->FuelCell(otherFuelCell).ElecStorage = fuelCell.ElecStorage;
     931              :                     }
     932              :                 }
     933              :             } else {
     934            0 :                 ShowSevereError(state, format("Invalid, {} = {}", s_ipsc->cAlphaFieldNames(1), AlphArray(1)));
     935            0 :                 ShowContinueError(state, format("Entered in {}={}", s_ipsc->cCurrentModuleObject, AlphArray(1)));
     936            0 :                 ErrorsFound = true;
     937              :             }
     938              :         }
     939              : 
     940            1 :         s_ipsc->cCurrentModuleObject = "Generator:FuelCell:Inverter";
     941            1 :         int NumFCPowerCondUnits = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
     942              : 
     943            1 :         if (NumFCPowerCondUnits <= 0) {
     944            0 :             ShowWarningError(state, format("No {} equipment specified in input file", s_ipsc->cCurrentModuleObject));
     945            0 :             ShowContinueError(state, format("Fuel Cell model requires a {} object", s_ipsc->cCurrentModuleObject));
     946              : 
     947            0 :             ErrorsFound = true;
     948              :         }
     949              : 
     950            2 :         for (int FCPCUNum = 1; FCPCUNum <= NumFCPowerCondUnits; ++FCPCUNum) {
     951            3 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     952            1 :                                                                      s_ipsc->cCurrentModuleObject,
     953              :                                                                      FCPCUNum,
     954              :                                                                      AlphArray,
     955              :                                                                      NumAlphas,
     956              :                                                                      NumArray,
     957              :                                                                      NumNums,
     958              :                                                                      IOStat,
     959              :                                                                      _,
     960            1 :                                                                      s_ipsc->lAlphaFieldBlanks,
     961            1 :                                                                      s_ipsc->cAlphaFieldNames,
     962            1 :                                                                      s_ipsc->cNumericFieldNames);
     963              : 
     964            1 :             ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, AlphArray(1)};
     965              : 
     966            1 :             int fuelCellNum = Util::FindItemInList(AlphArray(1), state.dataFuelCellElectGen->FuelCell, &FCDataStruct::NameInverter);
     967              : 
     968            1 :             if (fuelCellNum > 0) {
     969            1 :                 auto &fuelCell = state.dataFuelCellElectGen->FuelCell(fuelCellNum);
     970            1 :                 fuelCell.Inverter.Name = AlphArray(1);
     971              : 
     972            1 :                 fuelCell.Inverter.EffMode =
     973            1 :                     static_cast<DataGenerators::InverterEfficiencyMode>(getEnumValue(inverterEfficiencyModeNamesUC, AlphArray(2)));
     974            1 :                 if (fuelCell.Inverter.EffMode == DataGenerators::InverterEfficiencyMode::Invalid) {
     975            0 :                     ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(2), AlphArray(2));
     976            0 :                     ErrorsFound = true;
     977              :                 }
     978              : 
     979            1 :                 fuelCell.Inverter.ConstEff = NumArray(1);
     980              : 
     981            1 :                 if (s_ipsc->lAlphaFieldBlanks(3)) {
     982            0 :                     if (fuelCell.Inverter.EffMode == DataGenerators::InverterEfficiencyMode::Quadratic) {
     983            0 :                         ShowSevereEmptyField(state, eoh, s_ipsc->cAlphaFieldNames(3));
     984            0 :                         ErrorsFound = true;
     985              :                     }
     986            1 :                 } else if ((fuelCell.Inverter.EffQuadraticCurve = Curve::GetCurve(state, AlphArray(3))) == nullptr) {
     987            0 :                     if (fuelCell.Inverter.EffMode == DataGenerators::InverterEfficiencyMode::Quadratic) {
     988            0 :                         ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(3), AlphArray(3));
     989            0 :                         ErrorsFound = true;
     990              :                     }
     991              :                 }
     992              : 
     993              :                 // check for other FuelCell using the same Inverter and fill
     994            1 :                 for (int otherFuelCell = fuelCellNum + 1; otherFuelCell <= state.dataFuelCellElectGen->NumFuelCellGenerators; ++otherFuelCell) {
     995            0 :                     if (Util::SameString(state.dataFuelCellElectGen->FuelCell(otherFuelCell).Inverter.Name, fuelCell.Inverter.Name)) {
     996            0 :                         state.dataFuelCellElectGen->FuelCell(otherFuelCell).Inverter = fuelCell.Inverter;
     997              :                     }
     998              :                 }
     999              :             } else {
    1000            0 :                 ShowSevereError(state, format("Invalid, {} = {}", s_ipsc->cAlphaFieldNames(1), AlphArray(1)));
    1001            0 :                 ShowContinueError(state, format("Entered in {}={}", s_ipsc->cCurrentModuleObject, AlphArray(1)));
    1002            0 :                 ErrorsFound = true;
    1003              :             }
    1004              :         }
    1005              : 
    1006            1 :         s_ipsc->cCurrentModuleObject = "Generator:FuelCell:StackCooler";
    1007            1 :         int NumFCStackCoolers = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
    1008              : 
    1009            1 :         if (NumFCStackCoolers > 0) { // get stack cooler input data
    1010            0 :             for (int FCScoolNum = 1; FCScoolNum <= NumFCStackCoolers; ++FCScoolNum) {
    1011            0 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1012            0 :                                                                          s_ipsc->cCurrentModuleObject,
    1013              :                                                                          FCScoolNum,
    1014              :                                                                          AlphArray,
    1015              :                                                                          NumAlphas,
    1016              :                                                                          NumArray,
    1017              :                                                                          NumNums,
    1018              :                                                                          IOStat,
    1019              :                                                                          _,
    1020            0 :                                                                          s_ipsc->lAlphaFieldBlanks,
    1021            0 :                                                                          s_ipsc->cAlphaFieldNames,
    1022            0 :                                                                          s_ipsc->cNumericFieldNames);
    1023              : 
    1024            0 :                 ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, AlphArray(1)};
    1025              : 
    1026            0 :                 int fuelCellNum = Util::FindItemInList(AlphArray(1), state.dataFuelCellElectGen->FuelCell, &FCDataStruct::NameStackCooler);
    1027              : 
    1028            0 :                 if (fuelCellNum > 0) {
    1029            0 :                     auto &fuelCell = state.dataFuelCellElectGen->FuelCell(fuelCellNum);
    1030            0 :                     fuelCell.Type = DataPlant::PlantEquipmentType::Generator_FCStackCooler;
    1031            0 :                     fuelCell.StackCooler.Name = AlphArray(1);
    1032            0 :                     fuelCell.StackCooler.WaterInNodeName = AlphArray(2);
    1033              : 
    1034            0 :                     fuelCell.StackCooler.WaterOutNodeName = AlphArray(3);
    1035              : 
    1036            0 :                     fuelCell.StackCooler.WaterInNode =
    1037            0 :                         NodeInputManager::GetOnlySingleNode(state,
    1038            0 :                                                             AlphArray(2),
    1039              :                                                             ErrorsFound,
    1040              :                                                             DataLoopNode::ConnectionObjectType::GeneratorFuelCellStackCooler,
    1041            0 :                                                             AlphArray(1),
    1042              :                                                             DataLoopNode::NodeFluidType::Water,
    1043              :                                                             DataLoopNode::ConnectionType::Inlet,
    1044              :                                                             NodeInputManager::CompFluidStream::Primary,
    1045              :                                                             DataLoopNode::ObjectIsNotParent);
    1046            0 :                     fuelCell.StackCooler.WaterOutNode =
    1047            0 :                         NodeInputManager::GetOnlySingleNode(state,
    1048            0 :                                                             AlphArray(3),
    1049              :                                                             ErrorsFound,
    1050              :                                                             DataLoopNode::ConnectionObjectType::GeneratorFuelCellStackCooler,
    1051            0 :                                                             AlphArray(1),
    1052              :                                                             DataLoopNode::NodeFluidType::Water,
    1053              :                                                             DataLoopNode::ConnectionType::Outlet,
    1054              :                                                             NodeInputManager::CompFluidStream::Primary,
    1055              :                                                             DataLoopNode::ObjectIsNotParent);
    1056            0 :                     BranchNodeConnections::TestCompSet(
    1057            0 :                         state, s_ipsc->cCurrentModuleObject, AlphArray(1), AlphArray(2), AlphArray(3), "Heat Recovery Nodes");
    1058              : 
    1059            0 :                     fuelCell.StackCooler.TstackNom = NumArray(1);
    1060            0 :                     fuelCell.StackCooler.TstackActual = NumArray(2);
    1061            0 :                     fuelCell.StackCooler.r0 = NumArray(3);
    1062            0 :                     fuelCell.StackCooler.r1 = NumArray(4);
    1063            0 :                     fuelCell.StackCooler.r2 = NumArray(5);
    1064            0 :                     fuelCell.StackCooler.r3 = NumArray(6);
    1065            0 :                     fuelCell.StackCooler.MdotStackCoolant = NumArray(7);
    1066            0 :                     fuelCell.StackCooler.UAs_cool = NumArray(8);
    1067            0 :                     fuelCell.StackCooler.Fs_cogen = NumArray(9);
    1068            0 :                     fuelCell.StackCooler.As_cogen = NumArray(10);
    1069            0 :                     fuelCell.StackCooler.MdotCogenNom = NumArray(11);
    1070            0 :                     fuelCell.StackCooler.hCogenNom = NumArray(12);
    1071            0 :                     fuelCell.StackCooler.ns = NumArray(13);
    1072            0 :                     fuelCell.StackCooler.PstackPumpEl = NumArray(14);
    1073            0 :                     fuelCell.StackCooler.PmpPowerLossFactor = NumArray(15);
    1074            0 :                     fuelCell.StackCooler.f0 = NumArray(16);
    1075            0 :                     fuelCell.StackCooler.f1 = NumArray(17);
    1076            0 :                     fuelCell.StackCooler.f1 = NumArray(18);
    1077              : 
    1078            0 :                     fuelCell.StackCooler.StackCoolerPresent = true;
    1079              : 
    1080              :                 } else {
    1081            0 :                     ShowSevereError(state, format("Invalid, {} = {}", s_ipsc->cAlphaFieldNames(1), AlphArray(1)));
    1082            0 :                     ShowContinueError(state, format("Entered in {}={}", s_ipsc->cCurrentModuleObject, AlphArray(1)));
    1083            0 :                     ErrorsFound = true;
    1084              :                 }
    1085              :             }
    1086              :         }
    1087              : 
    1088            1 :         if (ErrorsFound) {
    1089            0 :             ShowFatalError(state, "Errors found in getting input for fuel cell model ");
    1090              :         }
    1091              : 
    1092            2 :         for (int genNum = 1; genNum <= state.dataFuelCellElectGen->NumFuelCellGenerators; ++genNum) {
    1093            1 :             auto &thisGen = state.dataFuelCellElectGen->FuelCell(genNum);
    1094            1 :             thisGen.setupOutputVars(state);
    1095              :         }
    1096            1 :     }
    1097              : 
    1098            1 :     void FCDataStruct::setupOutputVars(EnergyPlusData &state)
    1099              :     {
    1100            2 :         SetupOutputVariable(state,
    1101              :                             "Generator Produced AC Electricity Rate",
    1102              :                             Constant::Units::W,
    1103            1 :                             this->Report.ACPowerGen,
    1104              :                             OutputProcessor::TimeStepType::System,
    1105              :                             OutputProcessor::StoreType::Average,
    1106            1 :                             this->Name);
    1107              : 
    1108            2 :         SetupOutputVariable(state,
    1109              :                             "Generator Produced AC Electricity Energy",
    1110              :                             Constant::Units::J,
    1111            1 :                             this->Report.ACEnergyGen,
    1112              :                             OutputProcessor::TimeStepType::System,
    1113              :                             OutputProcessor::StoreType::Sum,
    1114            1 :                             this->Name,
    1115              :                             Constant::eResource::ElectricityProduced,
    1116              :                             OutputProcessor::Group::Plant,
    1117              :                             OutputProcessor::EndUseCat::Cogeneration);
    1118              : 
    1119            2 :         SetupOutputVariable(state,
    1120              :                             "Generator Produced Thermal Rate",
    1121              :                             Constant::Units::W,
    1122            1 :                             this->Report.qHX,
    1123              :                             OutputProcessor::TimeStepType::System,
    1124              :                             OutputProcessor::StoreType::Average,
    1125            1 :                             this->Name);
    1126              : 
    1127            2 :         SetupOutputVariable(state,
    1128              :                             "Generator Produced Thermal Energy",
    1129              :                             Constant::Units::J,
    1130            1 :                             this->Report.HXenergy,
    1131              :                             OutputProcessor::TimeStepType::System,
    1132              :                             OutputProcessor::StoreType::Sum,
    1133            1 :                             this->Name,
    1134              :                             Constant::eResource::EnergyTransfer,
    1135              :                             OutputProcessor::Group::Plant,
    1136              :                             OutputProcessor::EndUseCat::Cogeneration);
    1137              : 
    1138            2 :         SetupOutputVariable(state,
    1139              :                             "Generator Fuel HHV Basis Energy",
    1140              :                             Constant::Units::J,
    1141            1 :                             this->Report.FuelEnergyHHV,
    1142              :                             OutputProcessor::TimeStepType::System,
    1143              :                             OutputProcessor::StoreType::Sum,
    1144            1 :                             this->Name,
    1145              :                             Constant::eResource::NaturalGas,
    1146              :                             OutputProcessor::Group::Plant,
    1147              :                             OutputProcessor::EndUseCat::Cogeneration);
    1148              : 
    1149            2 :         SetupOutputVariable(state,
    1150              :                             "Generator Fuel HHV Basis Rate",
    1151              :                             Constant::Units::W,
    1152            1 :                             this->Report.FuelEnergyUseRateHHV,
    1153              :                             OutputProcessor::TimeStepType::System,
    1154              :                             OutputProcessor::StoreType::Average,
    1155            1 :                             this->Name);
    1156              : 
    1157            2 :         SetupOutputVariable(state,
    1158              :                             "Generator Zone Sensible Heat Transfer Rate",
    1159              :                             Constant::Units::W,
    1160            1 :                             this->Report.SkinLossPower,
    1161              :                             OutputProcessor::TimeStepType::System,
    1162              :                             OutputProcessor::StoreType::Average,
    1163            1 :                             this->Name);
    1164              : 
    1165            2 :         SetupOutputVariable(state,
    1166              :                             "Generator Zone Sensible Heat Transfer Energy",
    1167              :                             Constant::Units::J,
    1168            1 :                             this->Report.SkinLossEnergy,
    1169              :                             OutputProcessor::TimeStepType::System,
    1170              :                             OutputProcessor::StoreType::Sum,
    1171            1 :                             this->Name);
    1172              : 
    1173            2 :         SetupOutputVariable(state,
    1174              :                             "Generator Zone Convection Heat Transfer Rate",
    1175              :                             Constant::Units::W,
    1176            1 :                             this->Report.SkinLossConvect,
    1177              :                             OutputProcessor::TimeStepType::System,
    1178              :                             OutputProcessor::StoreType::Average,
    1179            1 :                             this->Name);
    1180              : 
    1181            2 :         SetupOutputVariable(state,
    1182              :                             "Generator Zone Radiation Heat Transfer Rate",
    1183              :                             Constant::Units::W,
    1184            1 :                             this->Report.SkinLossRadiat,
    1185              :                             OutputProcessor::TimeStepType::System,
    1186              :                             OutputProcessor::StoreType::Average,
    1187            1 :                             this->Name);
    1188              : 
    1189            1 :         if (this->FCPM.ZoneID > 0) {
    1190            1 :             SetupZoneInternalGain(state,
    1191              :                                   this->FCPM.ZoneID,
    1192              :                                   this->Name,
    1193              :                                   DataHeatBalance::IntGainType::GeneratorFuelCell,
    1194              :                                   &this->Report.SkinLossConvect,
    1195              :                                   nullptr,
    1196              :                                   &this->Report.SkinLossRadiat);
    1197              :         }
    1198              : 
    1199            1 :         if (state.dataGlobal->DisplayAdvancedReportVariables) { // show extra data originally needed for detailed comparative testing
    1200            0 :             SetupOutputVariable(state,
    1201              :                                 "Generator Air Inlet Temperature",
    1202              :                                 Constant::Units::C,
    1203            0 :                                 this->Report.TairInlet,
    1204              :                                 OutputProcessor::TimeStepType::System,
    1205              :                                 OutputProcessor::StoreType::Average,
    1206            0 :                                 this->Name);
    1207              : 
    1208            0 :             SetupOutputVariable(state,
    1209              :                                 "Generator Power Module Entering Air Temperature",
    1210              :                                 Constant::Units::C,
    1211            0 :                                 this->Report.TairIntoFCPM,
    1212              :                                 OutputProcessor::TimeStepType::System,
    1213              :                                 OutputProcessor::StoreType::Average,
    1214            0 :                                 this->Name);
    1215              : 
    1216            0 :             SetupOutputVariable(state,
    1217              :                                 "Generator Air Molar Flow Rate",
    1218              :                                 Constant::Units::kmol_s,
    1219            0 :                                 this->Report.NdotAir,
    1220              :                                 OutputProcessor::TimeStepType::System,
    1221              :                                 OutputProcessor::StoreType::Average,
    1222            0 :                                 this->Name);
    1223              : 
    1224            0 :             SetupOutputVariable(state,
    1225              :                                 "Generator Power Module Entering Air Enthalpy",
    1226              :                                 Constant::Units::W,
    1227            0 :                                 this->Report.TotAirInEnthalpy,
    1228              :                                 OutputProcessor::TimeStepType::System,
    1229              :                                 OutputProcessor::StoreType::Average,
    1230            0 :                                 this->Name);
    1231              : 
    1232            0 :             SetupOutputVariable(state,
    1233              :                                 "Generator Blower Electricity Rate",
    1234              :                                 Constant::Units::W,
    1235            0 :                                 this->Report.BlowerPower,
    1236              :                                 OutputProcessor::TimeStepType::System,
    1237              :                                 OutputProcessor::StoreType::Average,
    1238            0 :                                 this->Name);
    1239              : 
    1240            0 :             SetupOutputVariable(state,
    1241              :                                 "Generator Blower Electricity Energy",
    1242              :                                 Constant::Units::J,
    1243            0 :                                 this->Report.BlowerEnergy,
    1244              :                                 OutputProcessor::TimeStepType::System,
    1245              :                                 OutputProcessor::StoreType::Sum,
    1246            0 :                                 this->Name);
    1247              : 
    1248            0 :             SetupOutputVariable(state,
    1249              :                                 "Generator Blower Skin Heat Loss Rate",
    1250              :                                 Constant::Units::W,
    1251            0 :                                 this->Report.BlowerSkinLoss,
    1252              :                                 OutputProcessor::TimeStepType::System,
    1253              :                                 OutputProcessor::StoreType::Average,
    1254            0 :                                 this->Name);
    1255              : 
    1256            0 :             SetupOutputVariable(state,
    1257              :                                 "Generator Fuel Inlet Temperature",
    1258              :                                 Constant::Units::C,
    1259            0 :                                 this->Report.TfuelInlet,
    1260              :                                 OutputProcessor::TimeStepType::System,
    1261              :                                 OutputProcessor::StoreType::Average,
    1262            0 :                                 this->Name);
    1263              : 
    1264            0 :             SetupOutputVariable(state,
    1265              :                                 "Generator Power Module Entering Fuel Temperature",
    1266              :                                 Constant::Units::C,
    1267            0 :                                 this->Report.TfuelIntoFCPM,
    1268              :                                 OutputProcessor::TimeStepType::System,
    1269              :                                 OutputProcessor::StoreType::Average,
    1270            0 :                                 this->Name);
    1271              : 
    1272            0 :             SetupOutputVariable(state,
    1273              :                                 "Generator Fuel Molar Flow Rate",
    1274              :                                 Constant::Units::kmol_s,
    1275            0 :                                 this->Report.NdotFuel,
    1276              :                                 OutputProcessor::TimeStepType::System,
    1277              :                                 OutputProcessor::StoreType::Average,
    1278            0 :                                 this->Name);
    1279              : 
    1280            0 :             SetupOutputVariable(state,
    1281              :                                 "Generator Fuel Consumption LHV Basis Energy",
    1282              :                                 Constant::Units::J,
    1283            0 :                                 this->Report.FuelEnergyLHV,
    1284              :                                 OutputProcessor::TimeStepType::System,
    1285              :                                 OutputProcessor::StoreType::Sum,
    1286            0 :                                 this->Name);
    1287              : 
    1288            0 :             SetupOutputVariable(state,
    1289              :                                 "Generator Fuel Consumption Rate LHV Basis",
    1290              :                                 Constant::Units::W,
    1291            0 :                                 this->Report.FuelEnergyUseRateLHV,
    1292              :                                 OutputProcessor::TimeStepType::System,
    1293              :                                 OutputProcessor::StoreType::Average,
    1294            0 :                                 this->Name);
    1295              : 
    1296            0 :             SetupOutputVariable(state,
    1297              :                                 "Generator Power Module Entering Fuel Enthalpy",
    1298              :                                 Constant::Units::W,
    1299            0 :                                 this->Report.TotFuelInEnthalpy,
    1300              :                                 OutputProcessor::TimeStepType::System,
    1301              :                                 OutputProcessor::StoreType::Average,
    1302            0 :                                 this->Name);
    1303              : 
    1304            0 :             SetupOutputVariable(state,
    1305              :                                 "Generator Fuel Compressor Electricity Rate",
    1306              :                                 Constant::Units::W,
    1307            0 :                                 this->Report.FuelCompressPower,
    1308              :                                 OutputProcessor::TimeStepType::System,
    1309              :                                 OutputProcessor::StoreType::Average,
    1310            0 :                                 this->Name);
    1311              : 
    1312            0 :             SetupOutputVariable(state,
    1313              :                                 "Generator Fuel Compressor Electricity Energy",
    1314              :                                 Constant::Units::J,
    1315            0 :                                 this->Report.FuelCompressEnergy,
    1316              :                                 OutputProcessor::TimeStepType::System,
    1317              :                                 OutputProcessor::StoreType::Sum,
    1318            0 :                                 this->Name);
    1319              : 
    1320            0 :             SetupOutputVariable(state,
    1321              :                                 "Generator Fuel Compressor Skin Heat Loss Rate",
    1322              :                                 Constant::Units::W,
    1323            0 :                                 this->Report.FuelCompressSkinLoss,
    1324              :                                 OutputProcessor::TimeStepType::System,
    1325              :                                 OutputProcessor::StoreType::Average,
    1326            0 :                                 this->Name);
    1327              : 
    1328            0 :             SetupOutputVariable(state,
    1329              :                                 "Generator Fuel Reformer Water Inlet Temperature",
    1330              :                                 Constant::Units::C,
    1331            0 :                                 this->Report.TwaterInlet,
    1332              :                                 OutputProcessor::TimeStepType::System,
    1333              :                                 OutputProcessor::StoreType::Average,
    1334            0 :                                 this->Name);
    1335              : 
    1336            0 :             SetupOutputVariable(state,
    1337              :                                 "Generator Power Module Entering Reforming Water Temperature",
    1338              :                                 Constant::Units::C,
    1339            0 :                                 this->Report.TwaterIntoFCPM,
    1340              :                                 OutputProcessor::TimeStepType::System,
    1341              :                                 OutputProcessor::StoreType::Average,
    1342            0 :                                 this->Name);
    1343              : 
    1344            0 :             SetupOutputVariable(state,
    1345              :                                 "Generator Fuel Reformer Water Molar Flow Rate",
    1346              :                                 Constant::Units::kmol_s,
    1347            0 :                                 this->Report.NdotWater,
    1348              :                                 OutputProcessor::TimeStepType::System,
    1349              :                                 OutputProcessor::StoreType::Average,
    1350            0 :                                 this->Name);
    1351              : 
    1352            0 :             SetupOutputVariable(state,
    1353              :                                 "Generator Fuel Reformer Water Pump Electricity Rate",
    1354              :                                 Constant::Units::W,
    1355            0 :                                 this->Report.WaterPumpPower,
    1356              :                                 OutputProcessor::TimeStepType::System,
    1357              :                                 OutputProcessor::StoreType::Average,
    1358            0 :                                 this->Name);
    1359              : 
    1360            0 :             SetupOutputVariable(state,
    1361              :                                 "Generator Fuel Reformer Water Pump Electricity Energy",
    1362              :                                 Constant::Units::J,
    1363            0 :                                 this->Report.WaterPumpEnergy,
    1364              :                                 OutputProcessor::TimeStepType::System,
    1365              :                                 OutputProcessor::StoreType::Sum,
    1366            0 :                                 this->Name);
    1367              : 
    1368            0 :             SetupOutputVariable(state,
    1369              :                                 "Generator Power Module Entering Reforming Water Enthalpy",
    1370              :                                 Constant::Units::W,
    1371            0 :                                 this->Report.WaterIntoFCPMEnthalpy,
    1372              :                                 OutputProcessor::TimeStepType::System,
    1373              :                                 OutputProcessor::StoreType::Average,
    1374            0 :                                 this->Name);
    1375              : 
    1376            0 :             SetupOutputVariable(state,
    1377              :                                 "Generator Product Gas Temperature",
    1378              :                                 Constant::Units::C,
    1379            0 :                                 this->Report.TprodGas,
    1380              :                                 OutputProcessor::TimeStepType::System,
    1381              :                                 OutputProcessor::StoreType::Average,
    1382            0 :                                 this->Name);
    1383              : 
    1384            0 :             SetupOutputVariable(state,
    1385              :                                 "Generator Product Gas Enthalpy",
    1386              :                                 Constant::Units::W,
    1387            0 :                                 this->Report.EnthalProdGas,
    1388              :                                 OutputProcessor::TimeStepType::System,
    1389              :                                 OutputProcessor::StoreType::Average,
    1390            0 :                                 this->Name);
    1391              : 
    1392            0 :             SetupOutputVariable(state,
    1393              :                                 "Generator Product Gas Molar Flow Rate",
    1394              :                                 Constant::Units::kmol_s,
    1395            0 :                                 this->Report.NdotProdGas,
    1396              :                                 OutputProcessor::TimeStepType::System,
    1397              :                                 OutputProcessor::StoreType::Average,
    1398            0 :                                 this->Name);
    1399              : 
    1400            0 :             SetupOutputVariable(state,
    1401              :                                 "Generator Product Gas Ar Molar Flow Rate",
    1402              :                                 Constant::Units::kmol_s,
    1403            0 :                                 this->Report.NdotProdAr,
    1404              :                                 OutputProcessor::TimeStepType::System,
    1405              :                                 OutputProcessor::StoreType::Average,
    1406            0 :                                 this->Name);
    1407              : 
    1408            0 :             SetupOutputVariable(state,
    1409              :                                 "Generator Product Gas CO2 Molar Flow Rate",
    1410              :                                 Constant::Units::kmol_s,
    1411            0 :                                 this->Report.NdotProdCO2,
    1412              :                                 OutputProcessor::TimeStepType::System,
    1413              :                                 OutputProcessor::StoreType::Average,
    1414            0 :                                 this->Name);
    1415              : 
    1416            0 :             SetupOutputVariable(state,
    1417              :                                 "Generator Product Gas H2O Vapor Molar Flow Rate",
    1418              :                                 Constant::Units::kmol_s,
    1419            0 :                                 this->Report.NdotProdH2O,
    1420              :                                 OutputProcessor::TimeStepType::System,
    1421              :                                 OutputProcessor::StoreType::Average,
    1422            0 :                                 this->Name);
    1423              : 
    1424            0 :             SetupOutputVariable(state,
    1425              :                                 "Generator Product Gas N2 Molar Flow Rate",
    1426              :                                 Constant::Units::kmol_s,
    1427            0 :                                 this->Report.NdotProdN2,
    1428              :                                 OutputProcessor::TimeStepType::System,
    1429              :                                 OutputProcessor::StoreType::Average,
    1430            0 :                                 this->Name);
    1431              : 
    1432            0 :             SetupOutputVariable(state,
    1433              :                                 "Generator Product Gas O2 Molar Flow Rate",
    1434              :                                 Constant::Units::kmol_s,
    1435            0 :                                 this->Report.NdotProdO2,
    1436              :                                 OutputProcessor::TimeStepType::System,
    1437              :                                 OutputProcessor::StoreType::Average,
    1438            0 :                                 this->Name);
    1439              : 
    1440            0 :             SetupOutputVariable(state,
    1441              :                                 "Generator Heat Recovery Exit Gas Temperature",
    1442              :                                 Constant::Units::C,
    1443            0 :                                 this->Report.THXexh,
    1444              :                                 OutputProcessor::TimeStepType::System,
    1445              :                                 OutputProcessor::StoreType::Average,
    1446            0 :                                 this->Name);
    1447              : 
    1448            0 :             SetupOutputVariable(state,
    1449              :                                 "Generator Heat Recovery Exit Gas H2O Vapor Fraction",
    1450              :                                 Constant::Units::None,
    1451            0 :                                 this->Report.WaterVaporFractExh,
    1452              :                                 OutputProcessor::TimeStepType::System,
    1453              :                                 OutputProcessor::StoreType::Average,
    1454            0 :                                 this->Name);
    1455              : 
    1456            0 :             SetupOutputVariable(state,
    1457              :                                 "Generator Heat Recovery Water Condensate Molar Flow Rate",
    1458              :                                 Constant::Units::kmol_s,
    1459            0 :                                 this->Report.CondensateRate,
    1460              :                                 OutputProcessor::TimeStepType::System,
    1461              :                                 OutputProcessor::StoreType::Average,
    1462            0 :                                 this->Name);
    1463              : 
    1464            0 :             SetupOutputVariable(state,
    1465              :                                 "Generator Inverter Loss Power",
    1466              :                                 Constant::Units::W,
    1467            0 :                                 this->Report.PCUlosses,
    1468              :                                 OutputProcessor::TimeStepType::System,
    1469              :                                 OutputProcessor::StoreType::Average,
    1470            0 :                                 this->Name);
    1471              : 
    1472            0 :             SetupOutputVariable(state,
    1473              :                                 "Generator Produced DC Electricity Rate",
    1474              :                                 Constant::Units::W,
    1475            0 :                                 this->Report.DCPowerGen,
    1476              :                                 OutputProcessor::TimeStepType::System,
    1477              :                                 OutputProcessor::StoreType::Average,
    1478            0 :                                 this->Name);
    1479              : 
    1480            0 :             SetupOutputVariable(state,
    1481              :                                 "Generator DC Power Efficiency",
    1482              :                                 Constant::Units::None,
    1483            0 :                                 this->Report.DCPowerEff,
    1484              :                                 OutputProcessor::TimeStepType::System,
    1485              :                                 OutputProcessor::StoreType::Average,
    1486            0 :                                 this->Name);
    1487              : 
    1488            0 :             SetupOutputVariable(state,
    1489              :                                 "Generator Electric Storage Charge State",
    1490              :                                 Constant::Units::J,
    1491            0 :                                 this->Report.ElectEnergyinStorage,
    1492              :                                 OutputProcessor::TimeStepType::System,
    1493              :                                 OutputProcessor::StoreType::Average,
    1494            0 :                                 this->Name);
    1495              : 
    1496            0 :             SetupOutputVariable(state,
    1497              :                                 "Generator DC Storage Charging Power",
    1498              :                                 Constant::Units::W,
    1499            0 :                                 this->Report.StoredPower,
    1500              :                                 OutputProcessor::TimeStepType::System,
    1501              :                                 OutputProcessor::StoreType::Average,
    1502            0 :                                 this->Name);
    1503              : 
    1504            0 :             SetupOutputVariable(state,
    1505              :                                 "Generator DC Storage Charging Energy",
    1506              :                                 Constant::Units::J,
    1507            0 :                                 this->Report.StoredEnergy,
    1508              :                                 OutputProcessor::TimeStepType::System,
    1509              :                                 OutputProcessor::StoreType::Sum,
    1510            0 :                                 this->Name);
    1511              : 
    1512            0 :             SetupOutputVariable(state,
    1513              :                                 "Generator DC Storage Discharging Power",
    1514              :                                 Constant::Units::W,
    1515            0 :                                 this->Report.DrawnPower,
    1516              :                                 OutputProcessor::TimeStepType::System,
    1517              :                                 OutputProcessor::StoreType::Average,
    1518            0 :                                 this->Name);
    1519              : 
    1520            0 :             SetupOutputVariable(state,
    1521              :                                 "Generator DC Storage Discharging Energy",
    1522              :                                 Constant::Units::J,
    1523            0 :                                 this->Report.DrawnEnergy,
    1524              :                                 OutputProcessor::TimeStepType::System,
    1525              :                                 OutputProcessor::StoreType::Sum,
    1526            0 :                                 this->Name);
    1527              : 
    1528            0 :             SetupOutputVariable(state,
    1529              :                                 "Generator Ancillary AC Electricity Rate",
    1530              :                                 Constant::Units::W,
    1531            0 :                                 this->Report.ACancillariesPower,
    1532              :                                 OutputProcessor::TimeStepType::System,
    1533              :                                 OutputProcessor::StoreType::Average,
    1534            0 :                                 this->Name);
    1535              : 
    1536            0 :             SetupOutputVariable(state,
    1537              :                                 "Generator Ancillary AC Electricity Energy",
    1538              :                                 Constant::Units::J,
    1539            0 :                                 this->Report.ACancillariesEnergy,
    1540              :                                 OutputProcessor::TimeStepType::System,
    1541              :                                 OutputProcessor::StoreType::Sum,
    1542            0 :                                 this->Name);
    1543              : 
    1544            0 :             SetupOutputVariable(state,
    1545              :                                 "Generator Fuel Cell Model Iteration Count",
    1546              :                                 Constant::Units::None,
    1547            0 :                                 this->Report.SeqSubstIterations,
    1548              :                                 OutputProcessor::TimeStepType::System,
    1549              :                                 OutputProcessor::StoreType::Sum,
    1550            0 :                                 this->Name);
    1551              : 
    1552            0 :             SetupOutputVariable(state,
    1553              :                                 "Generator Root Solver Iteration Count",
    1554              :                                 Constant::Units::None,
    1555            0 :                                 this->Report.RegulaFalsiIterations,
    1556              :                                 OutputProcessor::TimeStepType::System,
    1557              :                                 OutputProcessor::StoreType::Sum,
    1558            0 :                                 this->Name);
    1559              : 
    1560            0 :             SetupOutputVariable(state,
    1561              :                                 "Generator Number of Cycles",
    1562              :                                 Constant::Units::None,
    1563            0 :                                 this->Report.NumCycles,
    1564              :                                 OutputProcessor::TimeStepType::System,
    1565              :                                 OutputProcessor::StoreType::Average,
    1566            0 :                                 this->Name);
    1567              : 
    1568            0 :             SetupOutputVariable(state,
    1569              :                                 "Generator Power Module Skin Heat Loss Rate",
    1570              :                                 Constant::Units::W,
    1571            0 :                                 this->Report.FCPMSkinLoss,
    1572              :                                 OutputProcessor::TimeStepType::System,
    1573              :                                 OutputProcessor::StoreType::Average,
    1574            0 :                                 this->Name);
    1575              :         }
    1576            1 :     }
    1577              : 
    1578         2235 :     void FCDataStruct::CalcFuelCellGeneratorModel(EnergyPlusData &state,
    1579              :                                                   bool const RunFlag,
    1580              :                                                   Real64 const MyLoad,
    1581              :                                                   [[maybe_unused]] bool const FirstHVACIteration)
    1582              :     {
    1583              :         // SUBROUTINE INFORMATION:
    1584              :         //       AUTHOR         Brent Griffith
    1585              :         //       DATE WRITTEN   Aug 2005
    1586              : 
    1587              :         // PURPOSE OF THIS SUBROUTINE:
    1588              :         // simulate a FuelCell generator using the Annex 42 model
    1589              : 
    1590              :         // METHODOLOGY EMPLOYED:
    1591              :         // curve fit of performance data:
    1592              :         // many subdomains such as fuel and air compressors, wa
    1593              : 
    1594              :         // REFERENCES: IEA/ECBCS Annex 42....
    1595              : 
    1596              :         // begin controls block to be moved out to GeneratorDynamics module
    1597              :         // If no loop demand or Generator OFF, return
    1598         2235 :         if (!RunFlag) {
    1599              : 
    1600              :             // TODO zero out terms as appropriate
    1601              : 
    1602            0 :             if (this->FCPM.HasBeenOn) {
    1603              :                 // FuelCell just now beginning to shut down,
    1604              : 
    1605              :                 // set Day and Time of Last Shut Down
    1606            0 :                 this->FCPM.FractionalDayofLastShutDown =
    1607            0 :                     double(state.dataGlobal->DayOfSim) +
    1608            0 :                     (int(state.dataGlobal->CurrentTime) +
    1609            0 :                      (state.dataHVACGlobal->SysTimeElapsed + (state.dataGlobal->CurrentTime - int(state.dataGlobal->CurrentTime)))) /
    1610              :                         Constant::rHoursInDay;
    1611            0 :                 this->FCPM.HasBeenOn = false;
    1612              : 
    1613            0 :                 if (this->FCPM.ShutDownTime > 0.0) this->FCPM.DuringShutDown = true;
    1614              :             }
    1615              : 
    1616              :             // TODO  check to see if still in shut down mode and using fuel.
    1617            0 :             if (this->FCPM.DuringShutDown) {
    1618              :             }
    1619              : 
    1620            0 :             return;
    1621              :         }
    1622              : 
    1623         2235 :         if (!this->FCPM.HasBeenOn) {
    1624              :             // fuel cell just turned on
    1625              :             // set Day and Time of Last STart Up
    1626              : 
    1627            0 :             this->FCPM.FractionalDayofLastStartUp =
    1628            0 :                 double(state.dataGlobal->DayOfSim) +
    1629            0 :                 (int(state.dataGlobal->CurrentTime) +
    1630            0 :                  (state.dataHVACGlobal->SysTimeElapsed + (state.dataGlobal->CurrentTime - int(state.dataGlobal->CurrentTime)))) /
    1631              :                     Constant::rHoursInDay;
    1632              : 
    1633            0 :             this->FCPM.HasBeenOn = true;
    1634            0 :             ++this->FCPM.NumCycles; // increment cycling counter
    1635              : 
    1636            0 :             if (this->FCPM.StartUpTime > 0.0) this->FCPM.DuringStartUp = true;
    1637              :         }
    1638              : 
    1639              :         // TODO deal with things when jump out if not running?
    1640         2235 :         if (!RunFlag) {
    1641            0 :             return;
    1642              :         }
    1643              : 
    1644              :         // Note: MyLoad (input) is Pdemand (electrical Power requested)
    1645         2235 :         Real64 Pdemand = MyLoad;
    1646         2235 :         Real64 PacAncillariesTotal = 0.0;
    1647         2235 :         Real64 PpcuLosses = 0.0;
    1648         2235 :         Real64 Pstorage = 0.0;
    1649         2235 :         Real64 PgridExtra = 0.0;
    1650         2235 :         Real64 PoutofInverter = 0.0;
    1651         2235 :         bool ConstrainedFCPM = false;
    1652              :         int SolverFlag;
    1653              :         int iter;
    1654              :         Real64 Pel;
    1655              : 
    1656              :         // BEGIN SEQUENTIAL SUBSTITUTION to handle a lot of inter-related calcs
    1657         6705 :         for (iter = 1; iter <= 20; ++iter) {
    1658         6705 :             if (iter > 1) {
    1659         4470 :                 this->FigurePowerConditioningLosses(state, PoutofInverter, PpcuLosses);
    1660         4470 :                 this->FigureACAncillaries(state, PacAncillariesTotal);
    1661         4470 :                 Pdemand = MyLoad + PacAncillariesTotal + PpcuLosses;
    1662              :             } else {
    1663              :                 // control Step 1a: Figure ancillary AC power draws
    1664         2235 :                 this->FigureACAncillaries(state, PacAncillariesTotal);
    1665         2235 :                 Pdemand = MyLoad + PacAncillariesTotal;
    1666              :                 // Control Step 1b: Calculate losses associated with Power conditioning
    1667         2235 :                 this->FigurePowerConditioningLosses(state, Pdemand, PpcuLosses);
    1668         2235 :                 Pdemand += PpcuLosses;
    1669         2235 :                 Pel = Pdemand;
    1670              :             }
    1671              : 
    1672         6705 :             this->Inverter.PCUlosses = PpcuLosses;
    1673              : 
    1674              :             // Control step 2: adjust for transient and startup/shut down constraints
    1675              : 
    1676              :             Real64 PelDiff;
    1677         6705 :             bool ConstrainedFCPMTrans = false;
    1678         6705 :             this->FigureTransientConstraints(state, Pel, ConstrainedFCPMTrans, PelDiff);
    1679              : 
    1680              :             // Control step 3: adjust for max and min limits on Pel
    1681              : 
    1682         6705 :             if (Pel < this->FCPM.PelMin) {
    1683           27 :                 PelDiff += (this->FCPM.PelMin - Pel);
    1684           27 :                 Pel = this->FCPM.PelMin;
    1685              : 
    1686           27 :                 ConstrainedFCPM = true;
    1687              :             }
    1688         6705 :             if (Pel > this->FCPM.PelMax) {
    1689            0 :                 PelDiff += (this->FCPM.PelMax - Pel);
    1690            0 :                 Pel = this->FCPM.PelMax;
    1691            0 :                 ConstrainedFCPM = true;
    1692              :             }
    1693              :             if (ConstrainedFCPM) {
    1694              :             }
    1695              : 
    1696         6705 :             this->FCPM.Pel = Pel;
    1697              :             // Now calculate FC models.  return to controls and batter after
    1698              : 
    1699              :             // Calculation Step 1. Determine electrical Efficiency Eel
    1700              : 
    1701         6705 :             Real64 Eel = 0.0;
    1702         6705 :             if (this->FCPM.EffMode == DataGenerators::CurveMode::Normalized) {
    1703              :                 // Equation (8) in FuelCell Spec modified for normalized curve
    1704              : 
    1705            0 :                 Eel = this->FCPM.EffCurve->value(state, Pel / this->FCPM.NomPel) * this->FCPM.NomEff *
    1706            0 :                       (1.0 - this->FCPM.NumCycles * this->FCPM.CyclingDegradRat) *
    1707            0 :                       (1.0 - max((this->FCPM.NumRunHours - this->FCPM.ThreshRunHours), 0.0) * this->FCPM.OperateDegradRat);
    1708              : 
    1709         6705 :             } else if (this->FCPM.EffMode == DataGenerators::CurveMode::Direct) {
    1710              :                 // Equation (8) in FuelCell Spec
    1711         6705 :                 Eel = this->FCPM.EffCurve->value(state, Pel) * (1.0 - this->FCPM.NumCycles * this->FCPM.CyclingDegradRat) *
    1712         6705 :                       (1.0 - max((this->FCPM.NumRunHours - this->FCPM.ThreshRunHours), 0.0) * this->FCPM.OperateDegradRat);
    1713              :             }
    1714              : 
    1715         6705 :             this->FCPM.Eel = Eel;
    1716              :             // Calculation Step 2. Determine fuel rate
    1717              : 
    1718              :             // fuel flow rate
    1719         6705 :             Real64 NdotFuel = Pel / (Eel * state.dataGenerator->FuelSupply(this->FuelSupNum).LHV * 1000000.0); // Eq. 10 solved for Ndot
    1720              : 
    1721         6705 :             this->FCPM.NdotFuel = NdotFuel;
    1722         6705 :             if (Pel <= 0.0) {
    1723              :                 // TODO zero stuff before leaving
    1724            0 :                 Pel = 0.0;
    1725            0 :                 this->FCPM.Pel = 0.0;
    1726            0 :                 return;
    1727              :             } else {
    1728              : 
    1729         6705 :                 this->FCPM.Pel = Pel;
    1730              :             }
    1731              : 
    1732              :             // Calculation Step 3. Determine Air rate
    1733              : 
    1734         6705 :             if (this->AirSup.AirSupRateMode == DataGenerators::AirSupRateMode::ConstantStoicsAirRat) { // MEthod 1
    1735              :                 // molar rate coeff working variable
    1736         6705 :                 Real64 NdotO2 = state.dataGenerator->FuelSupply(this->FuelSupNum).StoicOxygenRate * this->FCPM.NdotFuel * this->AirSup.Stoics;
    1737              : 
    1738         6705 :                 this->FCPM.NdotAir = NdotO2 / this->AirSup.O2fraction;
    1739              : 
    1740            0 :             } else if (this->AirSup.AirSupRateMode == DataGenerators::AirSupRateMode::QuadraticFuncofPel) { // MEthod 2
    1741              : 
    1742            0 :                 this->FCPM.NdotAir = this->AirSup.AirFuncPelCurve->value(state, Pel) * (1 + this->AirSup.AirTempCoeff * this->AirSup.TairIntoFCPM);
    1743              : 
    1744            0 :             } else if (this->AirSup.AirSupRateMode == DataGenerators::AirSupRateMode::QuadraticFuncofNdot) { // method 3
    1745            0 :                 this->FCPM.NdotAir =
    1746            0 :                     this->AirSup.AirFuncNdotCurve->value(state, this->FCPM.NdotFuel) * (1 + this->AirSup.AirTempCoeff * this->AirSup.TairIntoFCPM);
    1747              :             }
    1748              : 
    1749              :             // Calculation Step 4. fuel compressor power
    1750              : 
    1751         6705 :             state.dataGenerator->FuelSupply(this->FuelSupNum).PfuelCompEl =
    1752         6705 :                 Curve::CurveValue(state, state.dataGenerator->FuelSupply(this->FuelSupNum).CompPowerCurveID, this->FCPM.NdotFuel);
    1753              : 
    1754              :             // calculation Step 5, Fuel Compressor (need outlet temperature)
    1755              : 
    1756         6705 :             if (state.dataGenerator->FuelSupply(this->FuelSupNum).FuelTempMode == DataGenerators::FuelTemperatureMode::FuelInTempFromNode) {
    1757              : 
    1758            0 :                 state.dataGenerator->FuelSupply(this->FuelSupNum).TfuelIntoCompress =
    1759            0 :                     state.dataLoopNodes->Node(state.dataGenerator->FuelSupply(this->FuelSupNum).NodeNum).Temp;
    1760              : 
    1761         6705 :             } else if (state.dataGenerator->FuelSupply(this->FuelSupNum).FuelTempMode == DataGenerators::FuelTemperatureMode::FuelInTempSchedule) {
    1762              : 
    1763         6705 :                 state.dataGenerator->FuelSupply(this->FuelSupNum).TfuelIntoCompress =
    1764         6705 :                     state.dataGenerator->FuelSupply(this->FuelSupNum).sched->getCurrentVal();
    1765              :             }
    1766              : 
    1767              :             //  evaluate  heat capacity at average temperature using shomate
    1768              :             Real64 Cp; // temp Heat Capacity, used in thermochemistry units of (J/mol K)
    1769         6705 :             Real64 Tavg = (state.dataGenerator->FuelSupply(this->FuelSupNum).TfuelIntoCompress +
    1770         6705 :                            state.dataGenerator->FuelSupply(this->FuelSupNum).TfuelIntoFCPM) /
    1771         6705 :                           2.0;
    1772         6705 :             this->FigureFuelHeatCap(state, Tavg, Cp); // Cp in (J/mol K)
    1773              : 
    1774              :             // calculate a Temp of fuel out of compressor and into power module
    1775              : 
    1776         6705 :             if (this->FCPM.NdotFuel <= 0.0) { // just pass through, domain probably collapsed in modeling
    1777            0 :                 state.dataGenerator->FuelSupply(this->FuelSupNum).TfuelIntoFCPM = state.dataGenerator->FuelSupply(this->FuelSupNum).TfuelIntoCompress;
    1778              :             } else {
    1779         6705 :                 if (state.dataGenerator->FuelSupply(this->FuelSupNum).NumConstituents == 0) {
    1780            0 :                     state.dataGenerator->FuelSupply(this->FuelSupNum).TfuelIntoFCPM =
    1781            0 :                         state.dataGenerator->FuelSupply(this->FuelSupNum).TfuelIntoCompress;
    1782              :                 } else {
    1783         6705 :                     state.dataGenerator->FuelSupply(this->FuelSupNum).TfuelIntoFCPM =
    1784         6705 :                         ((1.0 - state.dataGenerator->FuelSupply(this->FuelSupNum).CompPowerLossFactor) *
    1785         6705 :                          state.dataGenerator->FuelSupply(this->FuelSupNum).PfuelCompEl / (this->FCPM.NdotFuel * Cp * 1000.0)) +
    1786         6705 :                         state.dataGenerator->FuelSupply(this->FuelSupNum).TfuelIntoCompress; // 1000 Cp units mol-> kmol
    1787              :                 }
    1788              :             }
    1789              :             // calc skin losses from fuel compressor
    1790         6705 :             state.dataGenerator->FuelSupply(this->FuelSupNum).QskinLoss =
    1791         6705 :                 state.dataGenerator->FuelSupply(this->FuelSupNum).CompPowerLossFactor * state.dataGenerator->FuelSupply(this->FuelSupNum).PfuelCompEl;
    1792              : 
    1793         6705 :             if (state.dataGenerator->FuelSupply(this->FuelSupNum).QskinLoss < 0.0) {
    1794            0 :                 ShowWarningError(state,
    1795            0 :                                  format("problem in FuelSupply.QskinLoss {:.3R}", state.dataGenerator->FuelSupply(this->FuelSupNum).QskinLoss));
    1796            0 :                 state.dataGenerator->FuelSupply(this->FuelSupNum).QskinLoss = 0.0;
    1797              :             }
    1798              : 
    1799              :             // calculate total fuel enthalpy coming into power module
    1800              : 
    1801              :             // (Hmolfuel in KJ/mol)
    1802              :             Real64 Hmolfuel; // temp enthalpy of fuel mixture in KJ/mol
    1803         6705 :             this->FigureFuelEnthalpy(state, state.dataGenerator->FuelSupply(this->FuelSupNum).TfuelIntoFCPM, Hmolfuel);
    1804              : 
    1805              :             // units, NdotFuel in kmol/sec. Hmolfule in KJ/mol ,
    1806              :             //        factor of 1000's to get to J/s or watts
    1807         6705 :             this->FCPM.TotFuelInEnthalpy = Hmolfuel * 1000.0 * this->FCPM.NdotFuel * 1000.0;
    1808              : 
    1809              :             // Calculation Step 6, water compressor calculations
    1810              : 
    1811              :             // calculate water consumption
    1812              : 
    1813         6705 :             this->FCPM.NdotLiqwater = this->WaterSup.WaterSupRateCurve->value(state, this->FCPM.NdotFuel);
    1814              : 
    1815              :             // set inlet temp.  (could move to init)
    1816              : 
    1817         6705 :             switch (this->WaterSup.waterTempMode) {
    1818            0 :             case DataGenerators::WaterTempMode::Mains: {
    1819            0 :                 this->WaterSup.TwaterIntoCompress = state.dataEnvrn->WaterMainsTemp;
    1820            0 :             } break;
    1821            0 :             case DataGenerators::WaterTempMode::AirNode:
    1822              :             case DataGenerators::WaterTempMode::WaterNode: {
    1823            0 :                 this->WaterSup.TwaterIntoCompress = state.dataLoopNodes->Node(this->WaterSup.NodeNum).Temp;
    1824            0 :             } break;
    1825         6705 :             case DataGenerators::WaterTempMode::Schedule: {
    1826         6705 :                 this->WaterSup.TwaterIntoCompress = this->WaterSup.sched->getCurrentVal();
    1827         6705 :             } break;
    1828            0 :             default:
    1829            0 :                 break;
    1830              :             }
    1831              : 
    1832         6705 :             this->WaterSup.PwaterCompEl = this->WaterSup.PmpPowerCurve->value(state, this->FCPM.NdotLiqwater);
    1833              : 
    1834              :             // 75.325  J/mol K Water at 0.1 MPa and 298 K, reference NIST WEBBOOK
    1835              :             Real64 CpWater; // heat capacity of water in molar units
    1836         6705 :             FigureLiquidWaterHeatCap(this->WaterSup.TwaterIntoCompress, CpWater);
    1837              : 
    1838         6705 :             if (this->FCPM.NdotLiqwater <= 0.0) { // just pass through, domain probably collapsed in modeling
    1839         6705 :                 this->WaterSup.TwaterIntoFCPM = this->WaterSup.TwaterIntoCompress;
    1840              :             } else {
    1841              : 
    1842            0 :                 this->WaterSup.TwaterIntoFCPM =
    1843            0 :                     ((1 - this->WaterSup.PmpPowerLossFactor) * this->WaterSup.PwaterCompEl / (this->FCPM.NdotLiqwater * CpWater * 1000.0)) +
    1844            0 :                     this->WaterSup.TwaterIntoCompress;
    1845              :             }
    1846              : 
    1847         6705 :             this->WaterSup.QskinLoss = this->WaterSup.PmpPowerLossFactor * this->WaterSup.PwaterCompEl;
    1848              : 
    1849         6705 :             if (this->WaterSup.QskinLoss < 0.0) {
    1850            0 :                 this->WaterSup.QskinLoss = 0.0;
    1851              :             }
    1852              : 
    1853              :             Real64 HLiqWater;                                                    // temp enthalpy of liquid water in KJ/mol   No Formation
    1854         6705 :             FigureLiquidWaterEnthalpy(this->WaterSup.TwaterIntoFCPM, HLiqWater); // HLiqWater in KJ/mol
    1855              : 
    1856         6705 :             this->FCPM.WaterInEnthalpy = this->FCPM.NdotLiqwater * HLiqWater * 1000.0 * 1000.0;
    1857              : 
    1858              :             // Calculation Step 7, Air compressor
    1859              : 
    1860         6705 :             this->AirSup.TairIntoBlower = state.dataLoopNodes->Node(this->AirSup.SupNodeNum).Temp;
    1861              : 
    1862         6705 :             this->AirSup.PairCompEl = this->AirSup.BlowerPowerCurve->value(state, this->FCPM.NdotAir);
    1863              : 
    1864         6705 :             Tavg = (this->AirSup.TairIntoBlower + this->AirSup.TairIntoFCPM) / 2.0;
    1865              : 
    1866         6705 :             this->FigureAirHeatCap(state, Tavg, Cp); // Cp in (J/mol K)
    1867              : 
    1868              :             // if PEMFC with stack cooler, then calculate stack cooler impacts
    1869         6705 :             if (this->StackCooler.StackCoolerPresent) {
    1870              : 
    1871            0 :                 this->StackCooler.qs_cool =
    1872            0 :                     (this->StackCooler.r0 + this->StackCooler.r1 * (this->StackCooler.TstackActual - this->StackCooler.TstackNom)) *
    1873            0 :                     (1 + this->StackCooler.r2 * Pel + this->StackCooler.r3 * Pel * Pel) * Pel;
    1874              : 
    1875            0 :                 this->FCPM.QdotStackCool = this->StackCooler.qs_cool;
    1876              :             }
    1877              : 
    1878              :             // Figure heat recovery from Electrical Storage, power conditioning, and auxiliary burner
    1879              : 
    1880         6705 :             switch (this->AirSup.IntakeRecoveryMode) {
    1881            0 :             case DataGenerators::RecoverMode::RecoverBurnInvertBatt: {
    1882            0 :                 this->AirSup.QintakeRecovery = this->AuxilHeat.QairIntake + this->ElecStorage.QairIntake + this->Inverter.QairIntake;
    1883            0 :             } break;
    1884            0 :             case DataGenerators::RecoverMode::RecoverAuxiliaryBurner: {
    1885            0 :                 this->AirSup.QintakeRecovery = this->AuxilHeat.QairIntake;
    1886            0 :             } break;
    1887            0 :             case DataGenerators::RecoverMode::RecoverInverterBatt: {
    1888            0 :                 this->AirSup.QintakeRecovery = this->ElecStorage.QairIntake + this->Inverter.QairIntake;
    1889            0 :             } break;
    1890            0 :             case DataGenerators::RecoverMode::RecoverInverter: {
    1891            0 :                 this->AirSup.QintakeRecovery = this->Inverter.QairIntake;
    1892            0 :             } break;
    1893            0 :             case DataGenerators::RecoverMode::RecoverBattery: {
    1894            0 :                 this->AirSup.QintakeRecovery = this->ElecStorage.QairIntake;
    1895            0 :             } break;
    1896         6705 :             case DataGenerators::RecoverMode::NoRecoveryOnAirIntake: {
    1897         6705 :                 this->AirSup.QintakeRecovery = 0.0;
    1898         6705 :             } break;
    1899            0 :             default:
    1900            0 :                 break;
    1901              :             }
    1902              : 
    1903         6705 :             if (this->FCPM.NdotAir <= 0.0) { // just pass through, domain probably collapsed in modeling
    1904            0 :                 this->AirSup.TairIntoFCPM = this->AirSup.TairIntoBlower;
    1905              : 
    1906              :             } else {
    1907         6705 :                 this->AirSup.TairIntoFCPM = (((1 - this->AirSup.BlowerHeatLossFactor) * this->AirSup.PairCompEl + this->AirSup.QintakeRecovery) /
    1908         6705 :                                              (this->FCPM.NdotAir * Cp * 1000.0)) +
    1909         6705 :                                             this->AirSup.TairIntoBlower; // 1000 Cp units mol-> kmol
    1910              :             }
    1911              : 
    1912         6705 :             this->AirSup.QskinLoss = this->AirSup.BlowerHeatLossFactor * this->AirSup.PairCompEl;
    1913              : 
    1914         6705 :             if (this->AirSup.QskinLoss < 0.0) {
    1915            0 :                 ShowWarningError(state, format("problem in AirSup.QskinLoss {:.3R}", this->AirSup.QskinLoss));
    1916            0 :                 this->AirSup.QskinLoss = 0.0;
    1917              :             }
    1918              : 
    1919              :             Real64 Hmolair;                                                     // temp enthalpy of air mixture in KJ/mol
    1920         6705 :             this->FigureAirEnthalpy(state, this->AirSup.TairIntoFCPM, Hmolair); // (Hmolair in KJ/mol)
    1921              : 
    1922              :             // units, NdotAir in kmol/sec.; Hmolfuel in KJ/mol ,
    1923              :             //        factor of 1000's to get to J/s or watts
    1924         6705 :             this->FCPM.TotAirInEnthalpy = Hmolair * 1000.0 * this->FCPM.NdotAir * 1000.0;
    1925              : 
    1926              :             // calculation Step 8, Figure Product Gases
    1927              : 
    1928              :             // figure stoic N dot for air
    1929         6705 :             Real64 NdotO2 = state.dataGenerator->FuelSupply(this->FuelSupNum).StoicOxygenRate * this->FCPM.NdotFuel;
    1930              : 
    1931              :             // Air in excess of match for fuel
    1932         6705 :             Real64 NdotStoicAir = NdotO2 / this->AirSup.O2fraction;
    1933              : 
    1934              :             // figure excess air rate
    1935              : 
    1936              :             // Air in excess of match for fuel
    1937         6705 :             Real64 NdotExcessAir = this->FCPM.NdotAir - NdotStoicAir;
    1938              : 
    1939         6705 :             if (NdotExcessAir < 0) { // can't meet stoichiometric fuel reaction
    1940              : 
    1941            0 :                 ShowWarningError(state, "Air flow rate into fuel cell is too low for stoichiometric fuel reaction");
    1942            0 :                 ShowContinueError(state, format("Increase air flow in GENERATOR:FC:AIR SUPPLY object:{}", this->AirSup.Name));
    1943              :             }
    1944              : 
    1945              :             // figure CO2 and Water rate from products (coefs setup during one-time processing in gas phase library )
    1946              : 
    1947              :             // CO2 from reaction
    1948         6705 :             Real64 NdotCO2ProdGas = this->FCPM.NdotFuel * state.dataGenerator->FuelSupply(this->FuelSupNum).CO2ProductGasCoef;
    1949              : 
    1950              :             // Water from reaction
    1951         6705 :             Real64 NdotH2OProdGas = this->FCPM.NdotFuel * state.dataGenerator->FuelSupply(this->FuelSupNum).H2OProductGasCoef;
    1952              : 
    1953              :             //  set product gas constituent fractions  (assume five usual components)
    1954         6705 :             Real64 NdotCO2 = 0.0; // temp CO2 molar rate coef product gas stream
    1955         6705 :             Real64 NdotN2 = 0.0;  // temp Nitrogen rate coef product gas stream
    1956         6705 :             Real64 Ndot02 = 0.0;  // temp Oxygen rate coef product gas stream
    1957         6705 :             Real64 NdotH2O = 0.0; // temp Water rate coef product gas stream
    1958         6705 :             Real64 NdotAr = 0.0;  // temp Argon rate coef product gas stream
    1959              : 
    1960              :             // Product gas constituents are fixed (not a user defined thing)
    1961              : 
    1962        40230 :             for (int thisGas = 1; thisGas <= this->AirSup.NumConstituents; ++thisGas) {
    1963              : 
    1964        33525 :                 switch (this->AirSup.GasLibID(thisGas)) {
    1965         6705 :                 case GasID::CarbonDioxide: {
    1966              :                     // all the CO2 coming in plus the new CO2 from reactions
    1967         6705 :                     NdotCO2 = NdotCO2ProdGas + this->AirSup.ConstitMolalFract(thisGas) * this->FCPM.NdotAir;
    1968         6705 :                 } break;
    1969         6705 :                 case GasID::Nitrogen: {
    1970              :                     // all the nitrogen coming in
    1971         6705 :                     NdotN2 = this->FCPM.NdotAir * this->AirSup.ConstitMolalFract(thisGas);
    1972         6705 :                 } break;
    1973         6705 :                 case GasID::Oxygen: {
    1974              :                     // all the oxygen in the excess air stream
    1975         6705 :                     Ndot02 = NdotExcessAir * this->AirSup.ConstitMolalFract(thisGas);
    1976         6705 :                 } break;
    1977         6705 :                 case GasID::Water: {
    1978              :                     // all the H2O coming in plus the new H2O from reactions and the H2O from water used in reforming
    1979         6705 :                     NdotH2O = NdotH2OProdGas + this->AirSup.ConstitMolalFract(thisGas) * this->FCPM.NdotAir;
    1980              : 
    1981         6705 :                 } break;
    1982         6705 :                 case GasID::Argon: {
    1983              :                     // all the argon coming in.
    1984         6705 :                     NdotAr = this->FCPM.NdotAir * this->AirSup.ConstitMolalFract(thisGas);
    1985              : 
    1986         6705 :                 } break;
    1987            0 :                 default:
    1988            0 :                     break;
    1989              :                 }
    1990              :             }
    1991              : 
    1992         6705 :             this->FCPM.NdotProdGas = NdotCO2 + NdotN2 + Ndot02 + NdotH2O + NdotAr;
    1993              : 
    1994              :             // now that we have the total, figure molar fractions
    1995              : 
    1996         6705 :             this->FCPM.ConstitMolalFract(1) = NdotCO2 / this->FCPM.NdotProdGas;
    1997              : 
    1998              :             // all the nitrogen coming in
    1999         6705 :             this->FCPM.ConstitMolalFract(2) = NdotN2 / this->FCPM.NdotProdGas;
    2000              : 
    2001              :             // all the oxygen in the excess air stream
    2002         6705 :             this->FCPM.ConstitMolalFract(3) = Ndot02 / this->FCPM.NdotProdGas;
    2003              : 
    2004              :             // all the H2O coming in plus the new H2O from reactions and the H2O from water used in reforming
    2005         6705 :             this->FCPM.ConstitMolalFract(4) = NdotH2O / this->FCPM.NdotProdGas;
    2006              : 
    2007              :             // all the argon coming in.
    2008         6705 :             this->FCPM.ConstitMolalFract(5) = NdotAr / this->FCPM.NdotProdGas;
    2009              : 
    2010              :             // HmolProdGases KJ/mol)
    2011              :             Real64 HmolProdGases; // enthalpy of product gas mixture in KJ/mol
    2012         6705 :             this->FigureProductGasesEnthalpy(state, this->FCPM.TprodGasLeavingFCPM, HmolProdGases);
    2013              : 
    2014              :             // units, NdotProdGas in kmol/sec.; HmolProdGases in KJ/mol ,
    2015              :             //        factor of 1000's to get to J/s or watts
    2016         6705 :             this->FCPM.TotProdGasEnthalpy = HmolProdGases * 1000.0 * this->FCPM.NdotProdGas * 1000.0;
    2017              : 
    2018              :             // calculation Step 9, Figure Skin losses
    2019              : 
    2020         6705 :             if (this->FCPM.SkinLossMode == DataGenerators::SkinLoss::ConstantRate) {
    2021              :                 // do nothing just use QdotSkin
    2022              : 
    2023            0 :             } else if (this->FCPM.SkinLossMode == DataGenerators::SkinLoss::UADT) {
    2024              : 
    2025              :                 // get zone air temp
    2026            0 :                 if (this->FCPM.ZoneID > 0) {
    2027            0 :                     this->FCPM.QdotSkin = this->FCPM.UAskin * (this->FCPM.TprodGasLeavingFCPM -
    2028            0 :                                                                state.dataZoneTempPredictorCorrector->zoneHeatBalance(this->FCPM.ZoneID).ZT);
    2029              :                 }
    2030              : 
    2031            0 :             } else if (this->FCPM.SkinLossMode == DataGenerators::SkinLoss::QuadraticFuelNdot) {
    2032              : 
    2033            0 :                 this->FCPM.QdotSkin = this->FCPM.SkinLossCurve->value(state, this->FCPM.NdotFuel);
    2034              :             }
    2035              : 
    2036              :             // calculation Step 10, AC FCPM power ancillaries
    2037              : 
    2038         6705 :             this->FCPM.PelancillariesAC = this->FCPM.ANC0 + this->FCPM.ANC1 * this->FCPM.NdotFuel;
    2039              : 
    2040              :             // calculation Step 11, Dilution air
    2041         6705 :             this->FigureAirEnthalpy(state, this->AirSup.TairIntoBlower, Hmolair); // (Hmolair in KJ/mol)
    2042              : 
    2043              :             // units, NdotDilutionAir in kmol/sec.; Hmolair in KJ/mol ,
    2044              :             //        factor of 1000's to get to J/s or watts
    2045         6705 :             this->FCPM.DilutionAirInEnthalpy = Hmolair * 1000.0 * this->FCPM.NdotDilutionAir * 1000.0;
    2046         6705 :             this->FCPM.DilutionAirOutEnthalpy = this->FCPM.DilutionAirInEnthalpy + this->FCPM.StackHeatLossToDilution;
    2047              : 
    2048              :             // calculation Step 12, Calculate Reforming water out enthalpy
    2049              :             Real64 HGasWater; // temp enthalpy of gaseous water in KJ/mol  No Formation
    2050         6705 :             FigureGaseousWaterEnthalpy(this->FCPM.TprodGasLeavingFCPM, HGasWater);
    2051              : 
    2052         6705 :             this->FCPM.WaterOutEnthalpy = HGasWater * 1000.0 * this->FCPM.NdotLiqwater * 1000.0;
    2053              : 
    2054              :             // calculation Step 13, Calculate Heat balance
    2055              :             //    move all terms in Equation 7 to RHS and calculate imbalance
    2056              : 
    2057         6705 :             Real64 MagofImbalance = -this->FCPM.TotFuelInEnthalpy - this->FCPM.TotAirInEnthalpy - this->FCPM.WaterInEnthalpy -
    2058        13410 :                                     this->FCPM.DilutionAirInEnthalpy -
    2059         6705 :                                     this->FCPM.NdotFuel * state.dataGenerator->FuelSupply(this->FuelSupNum).LHV * 1000000.0 -
    2060         6705 :                                     this->FCPM.PelancillariesAC + this->FCPM.Pel + this->FCPM.TotProdGasEnthalpy + this->FCPM.WaterOutEnthalpy +
    2061         6705 :                                     this->FCPM.QdotStackCool + this->FCPM.QdotSkin + this->FCPM.DilutionAirOutEnthalpy;
    2062              : 
    2063              :             // Now find a new total prod Gas Enthalpy that would result in an energy balance
    2064              :             // TODO check signs...
    2065         6705 :             Real64 tmpTotProdGasEnthalpy = this->FCPM.TotProdGasEnthalpy - MagofImbalance;
    2066              : 
    2067              :             // solve for a new TprodGasLeavingFCPM using regula falsi method
    2068              : 
    2069         6705 :             Real64 Acc = 0.01; // guessing need to refine
    2070         6705 :             int MaxIter = 150; // guessing need to refine
    2071         6705 :             SolverFlag = 0;    // init
    2072         6705 :             Real64 tmpTprodGas = this->FCPM.TprodGasLeavingFCPM;
    2073        60345 :             auto f = [&state, this, tmpTotProdGasEnthalpy](Real64 const TprodGas) {
    2074              :                 Real64 thisHmolalProdGases;
    2075        60345 :                 this->FigureProductGasesEnthalpy(state, TprodGas, thisHmolalProdGases);
    2076        60345 :                 return (thisHmolalProdGases * this->FCPM.NdotProdGas * 1000000.0) - tmpTotProdGasEnthalpy;
    2077         6705 :             };
    2078         6705 :             General::SolveRoot(state, Acc, MaxIter, SolverFlag, tmpTprodGas, f, DataGenerators::MinProductGasTemp, DataGenerators::MaxProductGasTemp);
    2079              : 
    2080         6705 :             if (SolverFlag == -2) {
    2081            0 :                 ++this->SolverErr_Type2_Iter;
    2082            0 :                 if (this->SolverErr_Type2_Iter == 1) {
    2083            0 :                     ShowWarningError(state, "CalcFuelCellGeneratorModel: Root Solver problem, flag = -2, check signs, all positive");
    2084            0 :                     ShowRecurringWarningErrorAtEnd(state,
    2085              :                                                    "CalcFuelCellGeneratorModel: Root Solver problem, flag = -2, check signs, all positive",
    2086            0 :                                                    this->SolverErr_Type2_IterIndex);
    2087              :                 } else {
    2088            0 :                     ShowRecurringWarningErrorAtEnd(state,
    2089              :                                                    "CalcFuelCellGeneratorModel: Root Solver problem, flag = -2, check signs, all positive",
    2090            0 :                                                    this->SolverErr_Type2_IterIndex);
    2091              :                 }
    2092              :             }
    2093         6705 :             if (SolverFlag == -1) {
    2094            0 :                 ++this->SolverErr_Type1_Iter;
    2095            0 :                 if (this->SolverErr_Type1_Iter == 1) {
    2096            0 :                     ShowWarningError(state,
    2097              :                                      "CalcFuelCellGeneratorModel: Root Solver problem, flag = -1, check accuracy and iterations, did not converge");
    2098            0 :                     ShowRecurringWarningErrorAtEnd(
    2099              :                         state,
    2100              :                         "CalcFuelCellGeneratorModel: Root Solver problem, flag = -1, check accuracy and iterations, did not converge",
    2101            0 :                         this->SolverErr_Type1_IterIndex);
    2102              :                 } else {
    2103            0 :                     ShowRecurringWarningErrorAtEnd(
    2104              :                         state,
    2105              :                         "CalcFuelCellGeneratorModel: Root Solver problem, flag = -1, check accuracy and iterations, did not converge",
    2106            0 :                         this->SolverErr_Type1_IterIndex);
    2107              :                 }
    2108              :             }
    2109         6705 :             if (SolverFlag > 0) {
    2110         6705 :                 this->FCPM.TprodGasLeavingFCPM = tmpTprodGas;
    2111              :                 //  write(*,*) 'Number of Root Solver iterations: ', solverFlag
    2112              :             }
    2113              : 
    2114              :             // Control Step 3 determine interaction with electrical storage
    2115              :             // How much power is really going into inverter?
    2116         6705 :             Real64 PintoInverter = Pel + Pstorage; // Back out so we can reapply
    2117              :             bool ConstrainedStorage;
    2118         6705 :             this->ManageElectStorInteractions(state, Pdemand, PpcuLosses, ConstrainedStorage, Pstorage, PgridExtra);
    2119         6705 :             PintoInverter = Pel - Pstorage;
    2120              :             // refine power conditioning losses with more current power production
    2121              : 
    2122         6705 :             if (this->Inverter.EffMode == DataGenerators::InverterEfficiencyMode::Constant) {
    2123         6705 :                 PpcuLosses = (1.0 - this->Inverter.ConstEff) * PintoInverter;
    2124            0 :             } else if (this->Inverter.EffMode == DataGenerators::InverterEfficiencyMode::Quadratic) {
    2125            0 :                 PpcuLosses = (1.0 - this->Inverter.EffQuadraticCurve->value(state, PintoInverter)) * PintoInverter;
    2126              :             }
    2127              : 
    2128         6705 :             PoutofInverter = PintoInverter - PpcuLosses;
    2129              : 
    2130        13410 :             this->ACPowerGen = PoutofInverter - this->FCPM.PelancillariesAC - this->AirSup.PairCompEl -
    2131         6705 :                                state.dataGenerator->FuelSupply(this->FuelSupNum).PfuelCompEl - this->WaterSup.PwaterCompEl;
    2132         6705 :             this->Inverter.PCUlosses = PpcuLosses;
    2133              :             // model assumes air intake is drawn over power conditioner to recovery heat
    2134         6705 :             this->Inverter.QairIntake = this->Inverter.PCUlosses;
    2135              : 
    2136         6705 :             this->CalcFuelCellAuxHeater();
    2137              : 
    2138         6705 :             this->CalcFuelCellGenHeatRecovery(state);
    2139              :             // calculation Step 11, If imbalance below threshold, then exit out of do loop.
    2140              : 
    2141         6705 :             if ((std::abs(MagofImbalance) < std::abs(DataGenerators::ImBalanceTol * this->FCPM.Pel)) && (iter > 2)) {
    2142         2235 :                 break;
    2143              :             }
    2144              : 
    2145              :         } // sequential substitution loop
    2146              : 
    2147         2235 :         this->FCPM.SeqSubstitIter = iter;
    2148         2235 :         this->FCPM.RegulaFalsiIter = SolverFlag;
    2149              :     }
    2150              : 
    2151         6705 :     void FCDataStruct::ManageElectStorInteractions(EnergyPlusData &state,
    2152              :                                                    Real64 const Pdemand,
    2153              :                                                    [[maybe_unused]] Real64 const PpcuLosses,
    2154              :                                                    bool &Constrained,
    2155              :                                                    Real64 &Pstorage,
    2156              :                                                    Real64 &PgridOverage // electricity that can't be stored and needs to go out
    2157              :     )
    2158              :     {
    2159              : 
    2160              :         // SUBROUTINE INFORMATION:
    2161              :         //       AUTHOR         B. Griffith
    2162              :         //       DATE WRITTEN   Aug 2005
    2163              : 
    2164              :         // PURPOSE OF THIS SUBROUTINE:
    2165              :         // manage controls and calculations related to electrical storage in FuelCell model
    2166              : 
    2167         6705 :         Real64 tmpPdraw = 0.0;
    2168         6705 :         Real64 tmpPcharge = 0.0;
    2169         6705 :         bool drawing = false;  // true if drawing power
    2170         6705 :         bool charging = false; // true if charging
    2171         6705 :         Constrained = false;
    2172              : 
    2173              :         // step 1 figure out what is desired of electrical storage system
    2174              : 
    2175         6705 :         if (this->FCPM.Pel < (Pdemand)) {
    2176              :             // draw from storage
    2177           63 :             tmpPdraw = (Pdemand) - this->FCPM.Pel;
    2178           63 :             drawing = true;
    2179              :         }
    2180              : 
    2181         6705 :         if (this->FCPM.Pel > (Pdemand)) {
    2182              :             // add to storage
    2183            0 :             tmpPcharge = this->FCPM.Pel - (Pdemand);
    2184            0 :             charging = true;
    2185              :         }
    2186              : 
    2187              :         //  step 2, figure out what is possible for electrical storage draws/charges
    2188              : 
    2189         6705 :         if (charging) {
    2190              : 
    2191            0 :             if (this->ElecStorage.StorageModelMode == DataGenerators::ElectricalStorage::SimpleEffConstraints) {
    2192              : 
    2193            0 :                 if (this->ElecStorage.LastTimeStepStateOfCharge >= this->ElecStorage.NominalEnergyCapacity) {
    2194              :                     // storage full!  no more allowed!
    2195            0 :                     PgridOverage = tmpPcharge;
    2196            0 :                     tmpPcharge = 0.0;
    2197            0 :                     Constrained = true;
    2198              :                 }
    2199            0 :                 if (tmpPcharge > this->ElecStorage.MaxPowerStore) {
    2200            0 :                     PgridOverage = tmpPcharge - this->ElecStorage.MaxPowerStore;
    2201            0 :                     tmpPcharge = this->ElecStorage.MaxPowerStore;
    2202            0 :                     Constrained = true;
    2203              :                 }
    2204              : 
    2205              :                 // now add energy to storage from charging
    2206            0 :                 if ((this->ElecStorage.LastTimeStepStateOfCharge +
    2207            0 :                      tmpPcharge * state.dataHVACGlobal->TimeStepSysSec * this->ElecStorage.EnergeticEfficCharge) <
    2208            0 :                     this->ElecStorage.NominalEnergyCapacity) {
    2209              : 
    2210            0 :                     this->ElecStorage.ThisTimeStepStateOfCharge =
    2211            0 :                         this->ElecStorage.LastTimeStepStateOfCharge +
    2212            0 :                         tmpPcharge * state.dataHVACGlobal->TimeStepSysSec * this->ElecStorage.EnergeticEfficCharge;
    2213              :                 } else { // would over charge this time step
    2214              : 
    2215            0 :                     tmpPcharge = (this->ElecStorage.NominalEnergyCapacity - this->ElecStorage.LastTimeStepStateOfCharge) /
    2216            0 :                                  (state.dataHVACGlobal->TimeStepSysSec * this->ElecStorage.EnergeticEfficCharge);
    2217            0 :                     Constrained = true;
    2218            0 :                     this->ElecStorage.ThisTimeStepStateOfCharge =
    2219            0 :                         this->ElecStorage.LastTimeStepStateOfCharge +
    2220            0 :                         tmpPcharge * state.dataHVACGlobal->TimeStepSysSec * this->ElecStorage.EnergeticEfficCharge;
    2221              :                 }
    2222              : 
    2223              :                 // losses go into QairIntake
    2224            0 :                 this->ElecStorage.QairIntake = tmpPcharge * (1.0 - this->ElecStorage.EnergeticEfficCharge);
    2225              : 
    2226            0 :             } else if (this->ElecStorage.StorageModelMode == DataGenerators::ElectricalStorage::LeadAcidBatterManwellMcGowan) {
    2227            0 :                 ShowWarningError(state, "ManageElectStorInteractions: Not yet implemented: Lead Acid Battery By Manwell and McGowan 1993 ");
    2228              : 
    2229            0 :             } else if (this->ElecStorage.StorageModelMode == DataGenerators::ElectricalStorage::LeadAcidBatterySaupe) {
    2230            0 :                 ShowWarningError(state, "ManageElectStorInteractions: Not yet implemented: Lead Acid Battery By Saupe 1993 ");
    2231              : 
    2232              :             } else {
    2233              : 
    2234              :                 // should not come here
    2235              :             }
    2236              : 
    2237            0 :             Pstorage = tmpPcharge;
    2238              : 
    2239              :         } // charging
    2240              : 
    2241         6705 :         if (drawing) {
    2242           63 :             if (this->ElecStorage.StorageModelMode == DataGenerators::ElectricalStorage::SimpleEffConstraints) {
    2243              : 
    2244           63 :                 if (this->ElecStorage.LastTimeStepStateOfCharge <= 0.0) {
    2245              :                     // storage empty  no more allowed!
    2246           63 :                     tmpPdraw = 0.0;
    2247           63 :                     Constrained = true;
    2248           63 :                     drawing = false;
    2249              :                 }
    2250           63 :                 if (tmpPdraw > this->ElecStorage.MaxPowerDraw) {
    2251            0 :                     tmpPdraw = this->ElecStorage.MaxPowerDraw;
    2252            0 :                     Constrained = true;
    2253              :                 }
    2254              : 
    2255              :                 // now take energy from storage by drawing  (amplified by energetic effic)
    2256          126 :                 if ((this->ElecStorage.LastTimeStepStateOfCharge -
    2257           63 :                      tmpPdraw * state.dataHVACGlobal->TimeStepSysSec / this->ElecStorage.EnergeticEfficDischarge) > 0.0) {
    2258              : 
    2259            0 :                     this->ElecStorage.ThisTimeStepStateOfCharge =
    2260            0 :                         this->ElecStorage.LastTimeStepStateOfCharge -
    2261            0 :                         tmpPdraw * state.dataHVACGlobal->TimeStepSysSec / this->ElecStorage.EnergeticEfficDischarge;
    2262              :                 } else { // would over drain storage this timestep so reduce tmpPdraw
    2263          126 :                     tmpPdraw = this->ElecStorage.LastTimeStepStateOfCharge * this->ElecStorage.EnergeticEfficDischarge /
    2264           63 :                                (state.dataHVACGlobal->TimeStepSysSec);
    2265           63 :                     this->ElecStorage.ThisTimeStepStateOfCharge =
    2266          126 :                         this->ElecStorage.LastTimeStepStateOfCharge -
    2267           63 :                         tmpPdraw * state.dataHVACGlobal->TimeStepSysSec / this->ElecStorage.EnergeticEfficDischarge;
    2268              : 
    2269           63 :                     Constrained = true;
    2270              :                 }
    2271              :                 // losses go into QairIntake
    2272           63 :                 this->ElecStorage.QairIntake = tmpPdraw * (1.0 / this->ElecStorage.EnergeticEfficDischarge - 1.0);
    2273            0 :             } else if (this->ElecStorage.StorageModelMode == DataGenerators::ElectricalStorage::LeadAcidBatterManwellMcGowan) {
    2274            0 :                 ShowWarningError(state, "ManageElectStorInteractions: Not yet implemented: Lead Acid Battery By Manwell and McGowan 1993 ");
    2275              : 
    2276            0 :             } else if (this->ElecStorage.StorageModelMode == DataGenerators::ElectricalStorage::LeadAcidBatterySaupe) {
    2277            0 :                 ShowWarningError(state, "ManageElectStorInteractions: Not yet implemented: Lead Acid Battery By Saupe 1993 ");
    2278              : 
    2279              :             } else {
    2280              : 
    2281              :                 // should not come here
    2282              :             }
    2283              : 
    2284           63 :             Pstorage = -tmpPdraw;
    2285              : 
    2286              :         } // drawing
    2287              : 
    2288         6705 :         if ((!charging) && (!drawing)) {
    2289              : 
    2290         6705 :             this->ElecStorage.ThisTimeStepStateOfCharge = this->ElecStorage.LastTimeStepStateOfCharge;
    2291         6705 :             this->ElecStorage.PelNeedFromStorage = 0.0;
    2292         6705 :             this->ElecStorage.PelFromStorage = 0.0;
    2293         6705 :             this->ElecStorage.QairIntake = 0.0;
    2294              :         }
    2295              : 
    2296         6705 :         if (Pstorage >= 0.0) {
    2297              : 
    2298         6705 :             this->ElecStorage.PelIntoStorage = Pstorage;
    2299         6705 :             this->ElecStorage.PelFromStorage = 0.0;
    2300              :         }
    2301         6705 :         if (Pstorage < 0.0) {
    2302              : 
    2303            0 :             this->ElecStorage.PelIntoStorage = 0.0;
    2304            0 :             this->ElecStorage.PelFromStorage = -Pstorage;
    2305              :         }
    2306         6705 :     }
    2307              : 
    2308         6705 :     void FCDataStruct::FigureAirHeatCap(EnergyPlusData &state, Real64 const FluidTemp, Real64 &Cp)
    2309              :     {
    2310              : 
    2311              :         // SUBROUTINE INFORMATION:
    2312              :         //       AUTHOR         B Griffith
    2313              :         //       DATE WRITTEN   August 2005
    2314              : 
    2315              :         // PURPOSE OF THIS SUBROUTINE:
    2316              :         // calculate Cp from Shomate equations for fuel
    2317              : 
    2318              :         // METHODOLOGY EMPLOYED:
    2319              :         // sum by weighting molar fractions of all Air constituents.
    2320              :         // assumes mixture is sum of parts.
    2321              : 
    2322              :         // REFERENCES:
    2323              :         // NIST Webbook on gas phase thermochemistry
    2324              : 
    2325              :         Real64 A;  // shomate coeff
    2326              :         Real64 B;  // shomate coeff
    2327              :         Real64 C;  // shomate coeff
    2328              :         Real64 D;  // shomate coeff
    2329              :         Real64 E;  // shomate coeff
    2330              :         Real64 A1; // NASA poly coeff
    2331              :         Real64 A2; // NASA poly coeff
    2332              :         Real64 A3; // NASA poly coeff
    2333              :         Real64 A4; // NASA poly coeff
    2334              :         Real64 A5; // NASA poly coeff
    2335              : 
    2336              :         // loop through fuel constituents and sum up Cp
    2337              : 
    2338              :         // two different thermodynamic curve fits might be used
    2339              : 
    2340         6705 :         Real64 tempCp = 0.0;
    2341              : 
    2342         6705 :         Real64 const Tkel = (FluidTemp + Constant::Kelvin);          // temp for NASA eq. in Kelvin
    2343         6705 :         Real64 const Tsho = (FluidTemp + Constant::Kelvin) / 1000.0; // temp for Shomate eq  in (Kelvin/1000)
    2344              : 
    2345         6705 :         Real64 const pow_2_Tsho(pow_2(Tsho));
    2346         6705 :         Real64 const pow_3_Tsho(pow_3(Tsho));
    2347         6705 :         Real64 const pow_2_Tkel(pow_2(Tkel));
    2348         6705 :         Real64 const pow_3_Tkel(pow_3(Tkel));
    2349         6705 :         Real64 const pow_4_Tkel(pow_4(Tkel));
    2350              : 
    2351        40230 :         for (int thisConstit = 1; thisConstit <= this->AirSup.NumConstituents; ++thisConstit) {
    2352        33525 :             int gasID = static_cast<int>(this->AirSup.GasLibID(thisConstit));
    2353        33525 :             if (gasID > 0) {
    2354        33525 :                 if (state.dataGenerator->GasPhaseThermoChemistryData(gasID).ThermoMode == DataGenerators::ThermodynamicMode::NISTShomate) {
    2355              : 
    2356        33525 :                     A = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateA;
    2357        33525 :                     B = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateB;
    2358        33525 :                     C = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateC;
    2359        33525 :                     D = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateD;
    2360        33525 :                     E = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateE;
    2361              : 
    2362        33525 :                     tempCp += ((A + B * Tsho + C * pow_2_Tsho + D * pow_3_Tsho + E / pow_2_Tsho) * this->AirSup.ConstitMolalFract(thisConstit));
    2363              :                 }
    2364              : 
    2365        33525 :                 if (state.dataGenerator->GasPhaseThermoChemistryData(gasID).ThermoMode == DataGenerators::ThermodynamicMode::NASAPolynomial) {
    2366              : 
    2367            0 :                     A1 = state.dataGenerator->GasPhaseThermoChemistryData(gasID).NASA_A1;
    2368            0 :                     A2 = state.dataGenerator->GasPhaseThermoChemistryData(gasID).NASA_A2;
    2369            0 :                     A3 = state.dataGenerator->GasPhaseThermoChemistryData(gasID).NASA_A3;
    2370            0 :                     A4 = state.dataGenerator->GasPhaseThermoChemistryData(gasID).NASA_A4;
    2371            0 :                     A5 = state.dataGenerator->GasPhaseThermoChemistryData(gasID).NASA_A5;
    2372              : 
    2373            0 :                     tempCp += (A1 + A2 * Tkel + A3 * pow_2_Tkel + A4 * pow_3_Tkel + A5 * pow_4_Tkel) * DataGenerators::RinKJperMolpK *
    2374            0 :                               this->AirSup.ConstitMolalFract(thisConstit);
    2375              :                 }
    2376              :             }
    2377              :         }
    2378              : 
    2379         6705 :         Cp = tempCp;
    2380         6705 :     }
    2381              : 
    2382        13410 :     void FCDataStruct::FigureAirEnthalpy(EnergyPlusData &state, Real64 const FluidTemp, Real64 &Hair)
    2383              :     {
    2384              : 
    2385              :         // SUBROUTINE INFORMATION:
    2386              :         //       AUTHOR         B Griffith
    2387              :         //       DATE WRITTEN   August 2005
    2388              : 
    2389              :         // PURPOSE OF THIS SUBROUTINE:
    2390              :         // calculate Enthalpy from Shomate equations for fuel
    2391              : 
    2392              :         // METHODOLOGY EMPLOYED:
    2393              :         // sum by weighting molar fractions of all fuel constituents.
    2394              :         // assumes mixture is sum of parts.
    2395              : 
    2396              :         // REFERENCES:
    2397              :         // NIST Webbook on gas phase thermochemistry
    2398              : 
    2399              :         Real64 A;  // shomate coeff
    2400              :         Real64 B;  // shomate coeff
    2401              :         Real64 C;  // shomate coeff
    2402              :         Real64 D;  // shomate coeff
    2403              :         Real64 E;  // shomate coeff
    2404              :         Real64 F;  // shomate coeff
    2405              :         Real64 H;  // shomate coeff
    2406              :         Real64 A1; // NASA poly coeff
    2407              :         Real64 A2; // NASA poly coeff
    2408              :         Real64 A3; // NASA poly coeff
    2409              :         Real64 A4; // NASA poly coeff
    2410              :         Real64 A5; // NASA poly coeff
    2411              :         Real64 A6; // NASA poly coeff
    2412              : 
    2413        13410 :         Real64 const Tsho = (FluidTemp + Constant::Kelvin) / 1000.0; // temp for Shomate eq  in (Kelvin/1000)
    2414        13410 :         Real64 const Tkel = (FluidTemp + Constant::Kelvin);          // temp for NASA eq. in Kelvin
    2415              : 
    2416              :         // loop through fuel constituents and sum up Cp
    2417              : 
    2418        13410 :         Real64 tempHair = 0.0;
    2419              : 
    2420        13410 :         Real64 const pow_2_Tsho(pow_2(Tsho));
    2421        13410 :         Real64 const pow_3_Tsho(pow_3(Tsho));
    2422        13410 :         Real64 const pow_4_Tsho(pow_4(Tsho));
    2423        13410 :         Real64 const pow_2_Tkel(pow_2(Tkel));
    2424        13410 :         Real64 const pow_3_Tkel(pow_3(Tkel));
    2425        13410 :         Real64 const pow_4_Tkel(pow_4(Tkel));
    2426              : 
    2427        80460 :         for (int thisConstit = 1; thisConstit <= this->AirSup.NumConstituents; ++thisConstit) {
    2428        67050 :             int gasID = static_cast<int>(this->AirSup.GasLibID(thisConstit));
    2429        67050 :             if (gasID > 0) {
    2430        67050 :                 if (state.dataGenerator->GasPhaseThermoChemistryData(gasID).ThermoMode == DataGenerators::ThermodynamicMode::NISTShomate) {
    2431              : 
    2432        67050 :                     A = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateA;
    2433        67050 :                     B = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateB;
    2434        67050 :                     C = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateC;
    2435        67050 :                     D = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateD;
    2436        67050 :                     E = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateE;
    2437        67050 :                     F = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateF;
    2438        67050 :                     H = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateH;
    2439              : 
    2440        67050 :                     Real64 HairI = (A * Tsho + B * pow_2_Tsho / 2.0 + C * pow_3_Tsho / 3.0 + D * pow_4_Tsho / 4.0 - E / Tsho + F - H);
    2441              : 
    2442        67050 :                     tempHair += HairI * this->AirSup.ConstitMolalFract(thisConstit);
    2443              :                 }
    2444        67050 :                 if (state.dataGenerator->GasPhaseThermoChemistryData(gasID).ThermoMode == DataGenerators::ThermodynamicMode::NASAPolynomial) {
    2445            0 :                     A1 = state.dataGenerator->GasPhaseThermoChemistryData(gasID).NASA_A1;
    2446            0 :                     A2 = state.dataGenerator->GasPhaseThermoChemistryData(gasID).NASA_A2;
    2447            0 :                     A3 = state.dataGenerator->GasPhaseThermoChemistryData(gasID).NASA_A3;
    2448            0 :                     A4 = state.dataGenerator->GasPhaseThermoChemistryData(gasID).NASA_A4;
    2449            0 :                     A5 = state.dataGenerator->GasPhaseThermoChemistryData(gasID).NASA_A5;
    2450            0 :                     A6 = state.dataGenerator->GasPhaseThermoChemistryData(gasID).NASA_A6;
    2451              : 
    2452            0 :                     tempHair += (((A1 + A2 * Tkel / 2.0 + A3 * pow_2_Tkel / 3.0 + A4 * pow_3_Tkel / 4.0 + A5 * pow_4_Tkel / 5.0 + A6 / Tkel) *
    2453            0 :                                   DataGenerators::RinKJperMolpK * Tkel) -
    2454            0 :                                  state.dataGenerator->GasPhaseThermoChemistryData(gasID).StdRefMolarEnthOfForm) *
    2455            0 :                                 this->AirSup.ConstitMolalFract(thisConstit);
    2456              :                 }
    2457              :             }
    2458              :         }
    2459              : 
    2460        13410 :         Hair = tempHair;
    2461        13410 :     }
    2462              : 
    2463         6705 :     void FCDataStruct::FigureFuelHeatCap(EnergyPlusData &state, Real64 const FluidTemp, Real64 &Cp) const
    2464              :     {
    2465              : 
    2466              :         // SUBROUTINE INFORMATION:
    2467              :         //       AUTHOR         B Griffith
    2468              :         //       DATE WRITTEN   August 2005
    2469              : 
    2470              :         // PURPOSE OF THIS SUBROUTINE:
    2471              :         // calculate Cp from Shomate equations for fuel
    2472              : 
    2473              :         // METHODOLOGY EMPLOYED:
    2474              :         // sum by weighting molar fractions of all fuel constituents.
    2475              :         // assumes mixture is sum of parts.
    2476              : 
    2477              :         // REFERENCES:
    2478              :         // NIST Webbook on gas phase thermochemistry
    2479              : 
    2480              :         Real64 A;  // shomate coeff
    2481              :         Real64 B;  // shomate coeff
    2482              :         Real64 C;  // shomate coeff
    2483              :         Real64 D;  // shomate coeff
    2484              :         Real64 E;  // shomate coeff
    2485              :         Real64 A1; // NASA poly coeff
    2486              :         Real64 A2; // NASA poly coeff
    2487              :         Real64 A3; // NASA poly coeff
    2488              :         Real64 A4; // NASA poly coeff
    2489              :         Real64 A5; // NASA poly coeff
    2490              : 
    2491         6705 :         Real64 const Tsho = (FluidTemp + Constant::Kelvin) / 1000.0; // temp for Shomate eq  in (Kelvin/1000)
    2492         6705 :         Real64 const Tkel = (FluidTemp + Constant::Kelvin);          // temp for NASA eq. in Kelvin
    2493              : 
    2494              :         // loop through fuel constituents and sum up Cp
    2495              : 
    2496         6705 :         Real64 tempCp = 0.0;
    2497              : 
    2498         6705 :         Real64 const pow_2_Tsho(pow_2(Tsho));
    2499         6705 :         Real64 const pow_3_Tsho(pow_3(Tsho));
    2500         6705 :         Real64 const pow_2_Tkel(pow_2(Tkel));
    2501         6705 :         Real64 const pow_3_Tkel(pow_3(Tkel));
    2502         6705 :         Real64 const pow_4_Tkel(pow_4(Tkel));
    2503              : 
    2504        60345 :         for (int thisConstit = 1; thisConstit <= state.dataGenerator->FuelSupply(this->FuelSupNum).NumConstituents; ++thisConstit) {
    2505        53640 :             int gasID = state.dataGenerator->FuelSupply(this->FuelSupNum).GasLibID(thisConstit);
    2506        53640 :             if (gasID > 0) {
    2507        53640 :                 if (state.dataGenerator->GasPhaseThermoChemistryData(gasID).ThermoMode == DataGenerators::ThermodynamicMode::NISTShomate) {
    2508              : 
    2509        53640 :                     A = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateA;
    2510        53640 :                     B = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateB;
    2511        53640 :                     C = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateC;
    2512        53640 :                     D = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateD;
    2513        53640 :                     E = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateE;
    2514              : 
    2515       107280 :                     tempCp += ((A + B * Tsho + C * pow_2_Tsho + D * pow_3_Tsho + E / pow_2_Tsho) *
    2516        53640 :                                state.dataGenerator->FuelSupply(this->FuelSupNum).ConstitMolalFract(thisConstit));
    2517              :                 }
    2518              : 
    2519        53640 :                 if (state.dataGenerator->GasPhaseThermoChemistryData(gasID).ThermoMode == DataGenerators::ThermodynamicMode::NASAPolynomial) {
    2520            0 :                     A1 = state.dataGenerator->GasPhaseThermoChemistryData(gasID).NASA_A1;
    2521            0 :                     A2 = state.dataGenerator->GasPhaseThermoChemistryData(gasID).NASA_A2;
    2522            0 :                     A3 = state.dataGenerator->GasPhaseThermoChemistryData(gasID).NASA_A3;
    2523            0 :                     A4 = state.dataGenerator->GasPhaseThermoChemistryData(gasID).NASA_A4;
    2524            0 :                     A5 = state.dataGenerator->GasPhaseThermoChemistryData(gasID).NASA_A5;
    2525              : 
    2526            0 :                     tempCp += (A1 + A2 * Tkel + A3 * pow_2_Tkel + A4 * pow_3_Tkel + A5 * pow_4_Tkel) * DataGenerators::RinKJperMolpK *
    2527            0 :                               state.dataGenerator->FuelSupply(this->FuelSupNum).ConstitMolalFract(thisConstit);
    2528              :                 }
    2529              :             }
    2530              :         }
    2531              : 
    2532         6705 :         Cp = tempCp;
    2533         6705 :     }
    2534              : 
    2535         6705 :     void FCDataStruct::FigureFuelEnthalpy(EnergyPlusData &state, Real64 const FluidTemp, Real64 &Hfuel) const
    2536              :     {
    2537              : 
    2538              :         // SUBROUTINE INFORMATION:
    2539              :         //       AUTHOR         B Griffith
    2540              :         //       DATE WRITTEN   August 2005
    2541              : 
    2542              :         // PURPOSE OF THIS SUBROUTINE:
    2543              :         // calculate Enthalpy from Shomate equations for fuel
    2544              : 
    2545              :         // METHODOLOGY EMPLOYED:
    2546              :         // sum by weighting molar fractions of all fuel constituents.
    2547              :         // assumes mixture is sum of parts.
    2548              : 
    2549              :         // REFERENCES:
    2550              :         // NIST Webbook on gas phase thermochemistry
    2551              : 
    2552              :         Real64 A;  // shomate coeff
    2553              :         Real64 B;  // shomate coeff
    2554              :         Real64 C;  // shomate coeff
    2555              :         Real64 D;  // shomate coeff
    2556              :         Real64 E;  // shomate coeff
    2557              :         Real64 F;  // shomate coeff
    2558              :         Real64 H;  // shomate coeff
    2559              :         Real64 A1; // NASA poly coeff
    2560              :         Real64 A2; // NASA poly coeff
    2561              :         Real64 A3; // NASA poly coeff
    2562              :         Real64 A4; // NASA poly coeff
    2563              :         Real64 A5; // NASA poly coeff
    2564              :         Real64 A6; // NASA poly coeff
    2565              : 
    2566         6705 :         Real64 const Tsho = (FluidTemp + Constant::Kelvin) / 1000.0; // temp for Shomate eq  in (Kelvin/1000)
    2567         6705 :         Real64 const Tkel = (FluidTemp + Constant::Kelvin);          // temp for NASA eq. in Kelvin
    2568              : 
    2569              :         // loop through fuel constituents and sum up Cp
    2570              : 
    2571         6705 :         Real64 tempHfuel = 0.0;
    2572              : 
    2573         6705 :         Real64 const pow_2_Tsho(pow_2(Tsho));
    2574         6705 :         Real64 const pow_3_Tsho(pow_3(Tsho));
    2575         6705 :         Real64 const pow_4_Tsho(pow_4(Tsho));
    2576         6705 :         Real64 const pow_2_Tkel(pow_2(Tkel));
    2577         6705 :         Real64 const pow_3_Tkel(pow_3(Tkel));
    2578         6705 :         Real64 const pow_4_Tkel(pow_4(Tkel));
    2579              : 
    2580        60345 :         for (int thisConstit = 1; thisConstit <= state.dataGenerator->FuelSupply(this->FuelSupNum).NumConstituents; ++thisConstit) {
    2581        53640 :             int gasID = state.dataGenerator->FuelSupply(this->FuelSupNum).GasLibID(thisConstit);
    2582        53640 :             if (gasID > 0) {
    2583        53640 :                 if (state.dataGenerator->GasPhaseThermoChemistryData(gasID).ThermoMode == DataGenerators::ThermodynamicMode::NISTShomate) {
    2584        53640 :                     A = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateA;
    2585        53640 :                     B = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateB;
    2586        53640 :                     C = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateC;
    2587        53640 :                     D = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateD;
    2588        53640 :                     E = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateE;
    2589        53640 :                     F = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateF;
    2590        53640 :                     H = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateH;
    2591              : 
    2592        53640 :                     Real64 HfuelI = (A * Tsho + B * pow_2_Tsho / 2.0 + C * pow_3_Tsho / 3.0 + D * pow_4_Tsho / 4.0 - E / Tsho + F - H);
    2593              : 
    2594        53640 :                     tempHfuel += HfuelI * state.dataGenerator->FuelSupply(this->FuelSupNum).ConstitMolalFract(thisConstit);
    2595              :                 }
    2596        53640 :                 if (state.dataGenerator->GasPhaseThermoChemistryData(gasID).ThermoMode == DataGenerators::ThermodynamicMode::NASAPolynomial) {
    2597              : 
    2598            0 :                     A1 = state.dataGenerator->GasPhaseThermoChemistryData(gasID).NASA_A1;
    2599            0 :                     A2 = state.dataGenerator->GasPhaseThermoChemistryData(gasID).NASA_A2;
    2600            0 :                     A3 = state.dataGenerator->GasPhaseThermoChemistryData(gasID).NASA_A3;
    2601            0 :                     A4 = state.dataGenerator->GasPhaseThermoChemistryData(gasID).NASA_A4;
    2602            0 :                     A5 = state.dataGenerator->GasPhaseThermoChemistryData(gasID).NASA_A5;
    2603            0 :                     A6 = state.dataGenerator->GasPhaseThermoChemistryData(gasID).NASA_A6;
    2604              : 
    2605            0 :                     tempHfuel += (((A1 + A2 * Tkel / 2.0 + A3 * pow_2_Tkel / 3.0 + A4 * pow_3_Tkel / 4.0 + A5 * pow_4_Tkel / 5.0 + A6 / Tkel) *
    2606            0 :                                    DataGenerators::RinKJperMolpK * Tkel) -
    2607            0 :                                   state.dataGenerator->GasPhaseThermoChemistryData(gasID).StdRefMolarEnthOfForm) *
    2608            0 :                                  state.dataGenerator->FuelSupply(this->FuelSupNum).ConstitMolalFract(thisConstit);
    2609              :                 }
    2610              :             }
    2611              :         }
    2612              : 
    2613         6705 :         Hfuel = tempHfuel;
    2614         6705 :     }
    2615              : 
    2616        67050 :     void FCDataStruct::FigureProductGasesEnthalpy(EnergyPlusData &state, Real64 const FluidTemp, Real64 &HProdGases)
    2617              :     {
    2618              : 
    2619              :         // SUBROUTINE INFORMATION:
    2620              :         //       AUTHOR         B Griffith
    2621              :         //       DATE WRITTEN   August 2005
    2622              : 
    2623              :         // PURPOSE OF THIS SUBROUTINE:
    2624              :         // calculate Enthalpy from Shomate equations for gases
    2625              : 
    2626              :         // METHODOLOGY EMPLOYED:
    2627              :         // sum by weighting molar fractions of all product gas constituents.
    2628              :         // assumes mixture is sum of parts.
    2629              : 
    2630              :         // REFERENCES:
    2631              :         // NIST Webbook on gas phase thermochemistry
    2632              : 
    2633              :         Real64 A;  // shomate coeff
    2634              :         Real64 B;  // shomate coeff
    2635              :         Real64 C;  // shomate coeff
    2636              :         Real64 D;  // shomate coeff
    2637              :         Real64 E;  // shomate coeff
    2638              :         Real64 F;  // shomate coeff
    2639              :         Real64 H;  // shomate coeff
    2640              :         Real64 A1; // NASA poly coeff
    2641              :         Real64 A2; // NASA poly coeff
    2642              :         Real64 A3; // NASA poly coeff
    2643              :         Real64 A4; // NASA poly coeff
    2644              :         Real64 A5; // NASA poly coeff
    2645              :         Real64 A6; // NASA poly coeff
    2646              : 
    2647        67050 :         Real64 const Tsho = (FluidTemp + Constant::Kelvin) / 1000.0; // temp for Shomate eq  in (Kelvin/1000)
    2648        67050 :         Real64 const Tkel = (FluidTemp + Constant::Kelvin);          // temp for NASA eq. in Kelvin
    2649              : 
    2650              :         // loop through fuel constituents and sum up Cp
    2651              : 
    2652        67050 :         Real64 tempHprodGases = 0.0;
    2653              : 
    2654        67050 :         Real64 const pow_2_Tsho(pow_2(Tsho));
    2655        67050 :         Real64 const pow_3_Tsho(pow_3(Tsho));
    2656        67050 :         Real64 const pow_4_Tsho(pow_4(Tsho));
    2657        67050 :         Real64 const pow_2_Tkel(pow_2(Tkel));
    2658        67050 :         Real64 const pow_3_Tkel(pow_3(Tkel));
    2659        67050 :         Real64 const pow_4_Tkel(pow_4(Tkel));
    2660              : 
    2661       402300 :         for (int thisConstit = 1; thisConstit <= 5; ++thisConstit) {
    2662       335250 :             int gasID = static_cast<int>(this->FCPM.GasLibID(thisConstit));
    2663       335250 :             if (gasID > 0) {
    2664       335250 :                 if (state.dataGenerator->GasPhaseThermoChemistryData(gasID).ThermoMode == DataGenerators::ThermodynamicMode::NISTShomate) {
    2665       335250 :                     A = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateA;
    2666       335250 :                     B = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateB;
    2667       335250 :                     C = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateC;
    2668       335250 :                     D = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateD;
    2669       335250 :                     E = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateE;
    2670       335250 :                     F = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateF;
    2671       335250 :                     H = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateH;
    2672              : 
    2673       670500 :                     tempHprodGases += ((A * Tsho + B * pow_2_Tsho / 2.0 + C * pow_3_Tsho / 3.0 + D * pow_4_Tsho / 4.0 - E / Tsho + F - H) *
    2674       335250 :                                        this->FCPM.ConstitMolalFract(thisConstit));
    2675              :                 }
    2676       335250 :                 if (state.dataGenerator->GasPhaseThermoChemistryData(gasID).ThermoMode == DataGenerators::ThermodynamicMode::NASAPolynomial) {
    2677            0 :                     A1 = state.dataGenerator->GasPhaseThermoChemistryData(gasID).NASA_A1;
    2678            0 :                     A2 = state.dataGenerator->GasPhaseThermoChemistryData(gasID).NASA_A2;
    2679            0 :                     A3 = state.dataGenerator->GasPhaseThermoChemistryData(gasID).NASA_A3;
    2680            0 :                     A4 = state.dataGenerator->GasPhaseThermoChemistryData(gasID).NASA_A4;
    2681            0 :                     A5 = state.dataGenerator->GasPhaseThermoChemistryData(gasID).NASA_A5;
    2682            0 :                     A6 = state.dataGenerator->GasPhaseThermoChemistryData(gasID).NASA_A6;
    2683              : 
    2684            0 :                     tempHprodGases += (((A1 + A2 * Tkel / 2.0 + A3 * pow_2_Tkel / 3.0 + A4 * pow_3_Tkel / 4.0 + A5 * pow_4_Tkel / 5.0 + A6 / Tkel) *
    2685            0 :                                         DataGenerators::RinKJperMolpK * Tkel) -
    2686            0 :                                        state.dataGenerator->GasPhaseThermoChemistryData(gasID).StdRefMolarEnthOfForm) *
    2687            0 :                                       this->FCPM.ConstitMolalFract(thisConstit);
    2688              :                 }
    2689              :             } // gasid > 0
    2690              :         }
    2691              : 
    2692        67050 :         HProdGases = tempHprodGases;
    2693        67050 :     }
    2694              : 
    2695         6684 :     void FCDataStruct::FigureAuxilHeatGasHeatCap(EnergyPlusData &state, Real64 const FluidTemp, Real64 &Cp)
    2696              :     {
    2697              : 
    2698              :         // SUBROUTINE INFORMATION:
    2699              :         //       AUTHOR         Brent Griffith
    2700              :         //       DATE WRITTEN   Aug. 2005
    2701              : 
    2702              :         Real64 tempCp;
    2703              :         Real64 A;  // shomate coeff
    2704              :         Real64 B;  // shomate coeff
    2705              :         Real64 C;  // shomate coeff
    2706              :         Real64 D;  // shomate coeff
    2707              :         Real64 E;  // shomate coeff
    2708              :         Real64 A1; // NASA poly coeff
    2709              :         Real64 A2; // NASA poly coeff
    2710              :         Real64 A3; // NASA poly coeff
    2711              :         Real64 A4; // NASA poly coeff
    2712              :         Real64 A5; // NASA poly coeff
    2713              : 
    2714         6684 :         Real64 const Tsho = (FluidTemp + Constant::Kelvin) / 1000.0; // temp for Shomate eq  in (Kelvin/1000)
    2715         6684 :         Real64 const Tkel = (FluidTemp + Constant::Kelvin);          // temp for NASA eq. in Kelvin
    2716              : 
    2717              :         // loop through fuel constituents and sum up Cp
    2718              : 
    2719         6684 :         tempCp = 0.0;
    2720              : 
    2721         6684 :         Real64 const pow_2_Tsho(pow_2(Tsho));
    2722         6684 :         Real64 const pow_3_Tsho(pow_3(Tsho));
    2723         6684 :         Real64 const pow_2_Tkel(pow_2(Tkel));
    2724         6684 :         Real64 const pow_3_Tkel(pow_3(Tkel));
    2725         6684 :         Real64 const pow_4_Tkel(pow_4(Tkel));
    2726              : 
    2727       100260 :         for (int thisConstit = 1; thisConstit <= isize(this->AuxilHeat.GasLibID); ++thisConstit) {
    2728        93576 :             int gasID = static_cast<int>(this->AuxilHeat.GasLibID(thisConstit));
    2729        93576 :             if (gasID > 0) {
    2730        33420 :                 if (state.dataGenerator->GasPhaseThermoChemistryData(gasID).ThermoMode == DataGenerators::ThermodynamicMode::NISTShomate) {
    2731              : 
    2732        33420 :                     A = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateA;
    2733        33420 :                     B = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateB;
    2734        33420 :                     C = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateC;
    2735        33420 :                     D = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateD;
    2736        33420 :                     E = state.dataGenerator->GasPhaseThermoChemistryData(gasID).ShomateE;
    2737              : 
    2738        33420 :                     tempCp += ((A + B * Tsho + C * pow_2_Tsho + D * pow_3_Tsho + E / pow_2_Tsho) * this->AuxilHeat.ConstitMolalFract(thisConstit));
    2739              :                 }
    2740              : 
    2741        33420 :                 if (state.dataGenerator->GasPhaseThermoChemistryData(gasID).ThermoMode == DataGenerators::ThermodynamicMode::NASAPolynomial) {
    2742            0 :                     A1 = state.dataGenerator->GasPhaseThermoChemistryData(gasID).NASA_A1;
    2743            0 :                     A2 = state.dataGenerator->GasPhaseThermoChemistryData(gasID).NASA_A2;
    2744            0 :                     A3 = state.dataGenerator->GasPhaseThermoChemistryData(gasID).NASA_A3;
    2745            0 :                     A4 = state.dataGenerator->GasPhaseThermoChemistryData(gasID).NASA_A4;
    2746            0 :                     A5 = state.dataGenerator->GasPhaseThermoChemistryData(gasID).NASA_A5;
    2747              : 
    2748            0 :                     tempCp += (A1 + A2 * Tkel + A3 * pow_2_Tkel + A4 * pow_3_Tkel + A5 * pow_4_Tkel) * DataGenerators::RinKJperMolpK *
    2749            0 :                               this->AuxilHeat.ConstitMolalFract(thisConstit);
    2750              :                 }
    2751              :             }
    2752              :         }
    2753              : 
    2754         6684 :         Cp = tempCp;
    2755         6684 :     }
    2756              : 
    2757         6705 :     void FCDataStruct::FigureGaseousWaterEnthalpy(Real64 const FluidTemp, // degree C
    2758              :                                                   Real64 &HGasWater       // kJ/mol
    2759              :     )
    2760              :     {
    2761              : 
    2762              :         // SUBROUTINE INFORMATION:
    2763              :         //       AUTHOR         B Griffith
    2764              :         //       DATE WRITTEN   December 2005
    2765              : 
    2766              :         // PURPOSE OF THIS SUBROUTINE:
    2767              :         // calculate Enthalpy from Shomate equations for gaseous water
    2768              :         // No enthalpy of formation in this one.
    2769              : 
    2770              :         // REFERENCES:
    2771              :         // NIST Webbook on gas phase thermochemistry
    2772              : 
    2773         6705 :         Real64 constexpr A = 29.0373;                                // shomate coeff
    2774         6705 :         Real64 constexpr B = 10.2573;                                // shomate coeff
    2775         6705 :         Real64 constexpr C = 2.81048;                                // shomate coeff
    2776         6705 :         Real64 constexpr D = -0.95914;                               // shomate coeff
    2777         6705 :         Real64 constexpr E = 0.11725;                                // shomate coeff
    2778         6705 :         Real64 constexpr F = -250.569;                               // shomate coeff
    2779         6705 :         Real64 const Tsho = (FluidTemp + Constant::Kelvin) / 1000.0; // temp for Shomate eq  in (Kelvin/1000)
    2780              : 
    2781         6705 :         HGasWater = A * Tsho + B * pow_2(Tsho) / 2.0 + C * pow_3(Tsho) / 3.0 + D * pow_4(Tsho) / 4.0 - E / Tsho + F; //- H
    2782         6705 :     }
    2783              : 
    2784         6705 :     void FCDataStruct::FigureLiquidWaterEnthalpy(Real64 const FluidTemp, // degree C
    2785              :                                                  Real64 &HLiqWater       // kJ/mol
    2786              :     )
    2787              :     {
    2788              : 
    2789              :         // SUBROUTINE INFORMATION:
    2790              :         //       AUTHOR         B Griffith
    2791              :         //       DATE WRITTEN   December 2005
    2792              : 
    2793              :         // PURPOSE OF THIS SUBROUTINE:
    2794              :         // calculate Enthalpy from Shomate equations for liquid water
    2795              :         // No enthalpy of formation in this one
    2796              : 
    2797              :         // REFERENCES:
    2798              :         // NIST Webbook on gas phase thermochemistry
    2799              : 
    2800         6705 :         Real64 constexpr A = -203.606;  // shomate coeff
    2801         6705 :         Real64 constexpr B = 1523.29;   // shomate coeff
    2802         6705 :         Real64 constexpr C = -3196.413; // shomate coeff
    2803         6705 :         Real64 constexpr D = 2474.455;  // shomate coeff
    2804         6705 :         Real64 constexpr E = 3.85533;   // shomate coeff
    2805         6705 :         Real64 constexpr F = -256.5478; // shomate coeff
    2806              : 
    2807         6705 :         Real64 const Tsho = (FluidTemp + Constant::Kelvin) / 1000.0; // temp for Shomate eq  in (Kelvin/1000)
    2808              : 
    2809         6705 :         HLiqWater = A * Tsho + B * pow_2(Tsho) / 2.0 + C * pow_3(Tsho) / 3.0 + D * pow_4(Tsho) / 4.0 - E / Tsho + F; //- H
    2810         6705 :     }
    2811              : 
    2812        13389 :     void FCDataStruct::FigureLiquidWaterHeatCap(Real64 const FluidTemp, // degree C
    2813              :                                                 Real64 &Cp              // (J/mol*K)
    2814              :     )
    2815              :     {
    2816              : 
    2817              :         // SUBROUTINE INFORMATION:
    2818              :         //       AUTHOR         Brent Griffith
    2819              :         //       DATE WRITTEN   December 2005
    2820              : 
    2821              :         // PURPOSE OF THIS SUBROUTINE:
    2822              :         // calculate shomate eq. for pure liquid water
    2823              : 
    2824        13389 :         Real64 constexpr A = -203.606;  // shomate coeff
    2825        13389 :         Real64 constexpr B = 1523.29;   // shomate coeff
    2826        13389 :         Real64 constexpr C = -3196.413; // shomate coeff
    2827        13389 :         Real64 constexpr D = 2474.455;  // shomate coeff
    2828        13389 :         Real64 constexpr E = 3.85533;   // shomate coeff
    2829        13389 :         Real64 const Tsho = (FluidTemp + Constant::Kelvin) / 1000.0;
    2830              : 
    2831        13389 :         Cp = A + B * Tsho + C * pow_2(Tsho) + D * pow_3(Tsho) + E / pow_2(Tsho);
    2832        13389 :     }
    2833              : 
    2834         6705 :     void FCDataStruct::FigureACAncillaries(EnergyPlusData &state, Real64 &PacAncill)
    2835              :     {
    2836              : 
    2837              :         // SUBROUTINE INFORMATION:
    2838              :         //       AUTHOR         B Griffith
    2839              :         //       DATE WRITTEN   March 2006
    2840              : 
    2841              :         // PURPOSE OF THIS SUBROUTINE:
    2842              :         // Calculate the AC ancillaries to determine Pel
    2843              : 
    2844              :         //  Using lagged values inside a sequential substitution loop
    2845         6705 :         PacAncill = 0.0;
    2846              :         // sect. 5.9
    2847         6705 :         this->FCPM.PelancillariesAC = this->FCPM.ANC0 + this->FCPM.ANC1 * this->FCPM.NdotFuel;
    2848              : 
    2849              :         // sect 6.0
    2850         6705 :         this->AirSup.PairCompEl = this->AirSup.BlowerPowerCurve->value(state, this->FCPM.NdotAir);
    2851              :         // sect 7.0
    2852         6705 :         state.dataGenerator->FuelSupply(this->FuelSupNum).PfuelCompEl =
    2853         6705 :             Curve::CurveValue(state, state.dataGenerator->FuelSupply(this->FuelSupNum).CompPowerCurveID, this->FCPM.NdotFuel);
    2854              : 
    2855              :         // sect. 8.0
    2856         6705 :         this->WaterSup.PwaterCompEl = this->WaterSup.PmpPowerCurve->value(state, this->FCPM.NdotLiqwater);
    2857              : 
    2858         6705 :         PacAncill = this->FCPM.PelancillariesAC + this->AirSup.PairCompEl + state.dataGenerator->FuelSupply(this->FuelSupNum).PfuelCompEl +
    2859         6705 :                     this->WaterSup.PwaterCompEl;
    2860         6705 :     }
    2861              : 
    2862         6705 :     void FCDataStruct::FigurePowerConditioningLosses(EnergyPlusData &state, Real64 const Pdemand, Real64 &PpcuLosses) const
    2863              :     {
    2864              : 
    2865              :         // SUBROUTINE INFORMATION:
    2866              :         //       AUTHOR         B Griffith
    2867              :         //       DATE WRITTEN   Aug 2005
    2868              : 
    2869              :         // PURPOSE OF THIS SUBROUTINE:
    2870              :         // Calculate inverter losses
    2871              : 
    2872         6705 :         if (this->Inverter.EffMode == DataGenerators::InverterEfficiencyMode::Constant) {
    2873         6705 :             PpcuLosses = Pdemand * (1 - this->Inverter.ConstEff) / this->Inverter.ConstEff;
    2874              : 
    2875            0 :         } else if (this->Inverter.EffMode == DataGenerators::InverterEfficiencyMode::Quadratic) {
    2876              : 
    2877              :             // first use Pdemand instead of Pel to get initial estimate
    2878              :             Real64 lastPpcuLosses =
    2879            0 :                 Pdemand * (1.0 - this->Inverter.EffQuadraticCurve->value(state, Pdemand)) / this->Inverter.EffQuadraticCurve->value(state, Pdemand);
    2880              : 
    2881            0 :             for (int iter = 1; iter <= 20; ++iter) { // seems like need to iterate (??) Need to investigate number and convergence success here
    2882              : 
    2883            0 :                 Real64 Pel = Pdemand + lastPpcuLosses;
    2884              : 
    2885            0 :                 lastPpcuLosses = (1.0 - this->Inverter.EffQuadraticCurve->value(state, Pel)) * Pel;
    2886              :             }
    2887              : 
    2888            0 :             PpcuLosses = lastPpcuLosses;
    2889              :         }
    2890         6705 :     }
    2891              : 
    2892         6705 :     void FCDataStruct::FigureTransientConstraints(EnergyPlusData &state,
    2893              :                                                   Real64 &Pel,       // DC power control setting for power module
    2894              :                                                   bool &Constrained, // true if transient constraints kick in
    2895              :                                                   Real64 &PelDiff    // if constrained then this is the difference, positive
    2896              :     )
    2897              :     {
    2898              : 
    2899              :         // SUBROUTINE INFORMATION:
    2900              :         //       AUTHOR         Brent Griffith
    2901              :         //       DATE WRITTEN   Aug 2005
    2902              : 
    2903         6705 :         Real64 PelInput = Pel; // hold initial value of input var
    2904              : 
    2905         6705 :         Real64 CurrentFractionalDay = double(state.dataGlobal->DayOfSim) +
    2906         6705 :                                       (int(state.dataGlobal->CurrentTime) + (state.dataHVACGlobal->SysTimeElapsed +
    2907         6705 :                                                                              (state.dataGlobal->CurrentTime - int(state.dataGlobal->CurrentTime)))) /
    2908         6705 :                                           Constant::rHoursInDay;
    2909              : 
    2910              :         // Check if in start up and if it still should be
    2911         6705 :         if (this->FCPM.DuringStartUp) {
    2912              : 
    2913              :             // calculate time for end of start up period
    2914            0 :             Real64 EndingFractionalDay = this->FCPM.FractionalDayofLastStartUp + this->FCPM.StartUpTime / Constant::rHoursInDay;
    2915              : 
    2916            0 :             if (CurrentFractionalDay > EndingFractionalDay) {
    2917              :                 // start up period is now over
    2918            0 :                 this->FCPM.DuringStartUp = false;
    2919              :             }
    2920              :         }
    2921              : 
    2922              :         // Check if in shut down up and if it still should be
    2923         6705 :         if (this->FCPM.DuringShutDown) {
    2924              : 
    2925              :             // calculate time for end of shut down period
    2926            0 :             Real64 EndingFractionalDay = this->FCPM.FractionalDayofLastShutDown + this->FCPM.ShutDownTime / Constant::rHoursInDay;
    2927              : 
    2928            0 :             if (CurrentFractionalDay > EndingFractionalDay) {
    2929              :                 // start up period is now over
    2930            0 :                 this->FCPM.DuringShutDown = false;
    2931              :             }
    2932              :         }
    2933              :         // compare
    2934              : 
    2935         6705 :         if (!(this->FCPM.DuringShutDown) && !(this->FCPM.DuringStartUp)) {
    2936              :             // unit is neither starting or stopping and the only constraints would come from transient limits
    2937         6705 :             if (Pel > this->FCPM.PelLastTimeStep) { // powering up
    2938              :                 // working variable for max allowed by transient constraint
    2939           90 :                 Real64 MaxPel = this->FCPM.PelLastTimeStep + this->FCPM.UpTranLimit * state.dataHVACGlobal->TimeStepSysSec;
    2940           90 :                 if (MaxPel < Pel) {
    2941           39 :                     Pel = MaxPel;
    2942           39 :                     Constrained = true;
    2943              :                 } else {
    2944           51 :                     Constrained = false;
    2945              :                 }
    2946         6615 :             } else if (Pel < this->FCPM.PelLastTimeStep) { // powering down
    2947              :                                                            // working variable for min allowed by transient constraint
    2948            0 :                 Real64 MinPel = this->FCPM.PelLastTimeStep - this->FCPM.DownTranLimit * state.dataHVACGlobal->TimeStepSysSec;
    2949            0 :                 if (Pel < MinPel) {
    2950            0 :                     Pel = MinPel;
    2951            0 :                     Constrained = true;
    2952              :                 } else {
    2953            0 :                     Constrained = false;
    2954              :                 }
    2955              :             } else { // the same
    2956              :                 // do nothing
    2957         6615 :                 Constrained = false;
    2958              :             }
    2959              : 
    2960              :         } // not in start up or shut down
    2961              : 
    2962         6705 :         if (this->FCPM.DuringStartUp) {
    2963              :             // constant during start up modeling artifact
    2964            0 :             Pel = this->FCPM.StartUpElectProd / this->FCPM.StartUpTime;
    2965            0 :             Constrained = true;
    2966              :         }
    2967              : 
    2968         6705 :         if (this->FCPM.DuringShutDown) {
    2969              : 
    2970            0 :             Pel = 0.0; // assumes no power generated during shut down
    2971            0 :             Constrained = true;
    2972              :         }
    2973              : 
    2974         6705 :         PelDiff = 0.0;
    2975         6705 :         if (Constrained) {
    2976           39 :             PelDiff = PelInput - Pel;
    2977              :         }
    2978         6705 :     }
    2979              : 
    2980         6705 :     void FCDataStruct::CalcFuelCellAuxHeater() // Generator number
    2981              :     {
    2982              : 
    2983              :         // not yet implemented, just pass product gases thru nul domain
    2984              : 
    2985         6705 :         this->AuxilHeat.TauxMix = this->FCPM.TprodGasLeavingFCPM;
    2986         6705 :         this->AuxilHeat.NdotAuxMix = this->FCPM.NdotProdGas;
    2987         6705 :         this->AuxilHeat.ConstitMolalFract = this->FCPM.ConstitMolalFract;
    2988         6705 :         this->AuxilHeat.GasLibID = this->FCPM.GasLibID;
    2989         6705 :     }
    2990              : 
    2991         6705 :     void FCDataStruct::CalcFuelCellGenHeatRecovery(EnergyPlusData &state) // Generator number
    2992              :     {
    2993              :         // SUBROUTINE INFORMATION:
    2994              :         //       AUTHOR:          Brent Griffith
    2995              :         //       DATE WRITTEN:    Aug. 2005
    2996              : 
    2997              :         // PURPOSE OF THIS SUBROUTINE:
    2998              :         // To perform heat recovery calculations and node updates
    2999              : 
    3000              :         // METHODOLOGY EMPLOYED:
    3001              :         // model exhaust gas to water heat exchanger
    3002              : 
    3003              :         // REFERENCES: Annex 42 model documentation
    3004              : 
    3005              :         static constexpr std::string_view RoutineName("CalcFuelCellGenHeatRecovery");
    3006              : 
    3007         6705 :         switch (this->ExhaustHX.HXmodelMode) {
    3008            0 :         case DataGenerators::ExhaustGasHX::FixedEffectiveness: { // Method 1
    3009              : 
    3010            0 :             Real64 eHX = this->ExhaustHX.HXEffect;
    3011              : 
    3012            0 :             Real64 MWwater = state.dataGenerator->GasPhaseThermoChemistryData(4).MolecularWeight;
    3013            0 :             Real64 NdotWater = this->ExhaustHX.WaterMassFlowRate / MWwater;
    3014            0 :             Real64 TwaterIn = this->ExhaustHX.WaterInletTemp;
    3015              : 
    3016              :             Real64 CpWaterMol;
    3017            0 :             FigureLiquidWaterHeatCap(TwaterIn, CpWaterMol);
    3018              : 
    3019            0 :             Real64 NdotGas = this->AuxilHeat.NdotAuxMix;
    3020            0 :             Real64 TprodGasIn = this->AuxilHeat.TauxMix;
    3021              :             Real64 CpProdGasMol;
    3022            0 :             this->FigureAuxilHeatGasHeatCap(state, TprodGasIn, CpProdGasMol); // Cp in (J/mol*K)
    3023              :             // factor of 1000.0 for kmol -> mol
    3024            0 :             Real64 NdotCp = min(NdotGas * CpProdGasMol * 1000.0, NdotWater * CpWaterMol * 1000.0);
    3025              : 
    3026            0 :             this->ExhaustHX.qHX = eHX * NdotCp * (TprodGasIn - TwaterIn);
    3027              : 
    3028            0 :             this->ExhaustHX.THXexh = TprodGasIn - this->ExhaustHX.qHX / (NdotGas * CpProdGasMol * 1000.0);
    3029              : 
    3030            0 :             Real64 Cp = state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).glycol->getSpecificHeat(state, TwaterIn, RoutineName);
    3031              : 
    3032            0 :             if (this->ExhaustHX.WaterMassFlowRate * Cp <= 0.0) {
    3033            0 :                 this->ExhaustHX.WaterOutletTemp = TwaterIn;
    3034              :             } else {
    3035            0 :                 this->ExhaustHX.WaterOutletTemp = TwaterIn + this->ExhaustHX.qHX / (this->ExhaustHX.WaterMassFlowRate * Cp);
    3036              :             }
    3037              : 
    3038            0 :         } break;
    3039            0 :         case DataGenerators::ExhaustGasHX::LMTDempiricalUAeff: { // method 2
    3040            0 :             Real64 MWwater = state.dataGenerator->GasPhaseThermoChemistryData(4).MolecularWeight;
    3041            0 :             Real64 NdotWater = this->ExhaustHX.WaterMassFlowRate / MWwater;
    3042            0 :             Real64 NdotGas = this->AuxilHeat.NdotAuxMix;
    3043              : 
    3044            0 :             Real64 UAeff = this->ExhaustHX.hxs0 + this->ExhaustHX.hxs1 * NdotWater + this->ExhaustHX.hxs2 * pow_2(NdotWater) +
    3045            0 :                            this->ExhaustHX.hxs3 * NdotGas + this->ExhaustHX.hxs4 * pow_2(NdotGas);
    3046              : 
    3047            0 :             Real64 TauxMix = this->AuxilHeat.TauxMix;
    3048            0 :             Real64 TwaterIn = this->ExhaustHX.WaterInletTemp;
    3049              :             Real64 CpWaterMol;
    3050            0 :             FigureLiquidWaterHeatCap(TwaterIn, CpWaterMol);
    3051              :             // factor of 1000.0 for kmol -> mol
    3052            0 :             Real64 NdotCpWater = NdotWater * CpWaterMol * 1000.0;
    3053              :             Real64 CpProdGasMol;
    3054            0 :             this->FigureAuxilHeatGasHeatCap(state, TauxMix, CpProdGasMol); // Cp in (J/mol*K)
    3055            0 :             Real64 NdotCpAuxMix = NdotGas * CpProdGasMol * 1000.0;
    3056              : 
    3057            0 :             if ((NdotCpWater != 0.0) && (NdotCpAuxMix != 0.0)) { // trap divide by zero
    3058              :                 // now evaluate Eq. 44
    3059            0 :                 this->ExhaustHX.THXexh =
    3060            0 :                     ((1.0 - NdotCpAuxMix / NdotCpWater) / (std::exp(UAeff * (1.0 / NdotCpAuxMix - 1.0 / NdotCpWater)) - NdotCpAuxMix / NdotCpWater)) *
    3061            0 :                         TauxMix +
    3062            0 :                     (std::expm1(UAeff * (1.0 / NdotCpAuxMix - 1.0 / NdotCpWater)) /
    3063            0 :                      (std::exp(UAeff * (1.0 / NdotCpAuxMix - 1.0 / NdotCpWater)) - NdotCpAuxMix / NdotCpWater)) *
    3064              :                         TwaterIn;
    3065              : 
    3066            0 :                 this->ExhaustHX.WaterOutletTemp = TwaterIn + (NdotCpAuxMix / NdotCpWater) * (TauxMix - this->ExhaustHX.THXexh); // Eq. 42
    3067              : 
    3068              :             } else {
    3069            0 :                 this->ExhaustHX.THXexh = TauxMix;
    3070            0 :                 this->ExhaustHX.WaterOutletTemp = TwaterIn;
    3071              :             }
    3072              :             // ENDIF
    3073              : 
    3074            0 :             if ((this->ExhaustHX.THXexh - TwaterIn) != 0.0) { // trap divide by zero
    3075            0 :                 this->ExhaustHX.qHX = UAeff * ((TauxMix - this->ExhaustHX.WaterOutletTemp) - (this->ExhaustHX.THXexh - TwaterIn)) /
    3076            0 :                                       std::log((TauxMix - this->ExhaustHX.WaterOutletTemp) / (this->ExhaustHX.THXexh - TwaterIn));
    3077              :             } else {
    3078            0 :                 this->ExhaustHX.qHX = 0.0;
    3079              :             }
    3080              : 
    3081            0 :         } break;
    3082            0 :         case DataGenerators::ExhaustGasHX::LMTDfundementalUAeff: { // method 3
    3083            0 :             Real64 NdotGas = this->AuxilHeat.NdotAuxMix;
    3084            0 :             Real64 MWwater = state.dataGenerator->GasPhaseThermoChemistryData(4).MolecularWeight;
    3085            0 :             Real64 NdotWater = this->ExhaustHX.WaterMassFlowRate / MWwater;
    3086              : 
    3087            0 :             Real64 hgas = this->ExhaustHX.h0gas * std::pow(NdotGas / this->ExhaustHX.NdotGasRef, this->ExhaustHX.nCoeff);         // Eq. 48
    3088            0 :             Real64 hwater = this->ExhaustHX.h0Water * std::pow(NdotWater / this->ExhaustHX.NdotWaterRef, this->ExhaustHX.mCoeff); // Eq. 48
    3089              : 
    3090              :             // now equation 47
    3091            0 :             Real64 UAeff = 1.0 / (1.0 / (hgas * this->ExhaustHX.AreaGas) + 1.0 / (hwater * this->ExhaustHX.AreaWater) + this->ExhaustHX.Fadjust);
    3092              : 
    3093            0 :             Real64 TauxMix = this->AuxilHeat.TauxMix;
    3094            0 :             Real64 TwaterIn = this->ExhaustHX.WaterInletTemp;
    3095              :             Real64 CpWaterMol;
    3096            0 :             FigureLiquidWaterHeatCap(TwaterIn, CpWaterMol);
    3097            0 :             Real64 NdotCpWater = NdotWater * CpWaterMol * 1000.0;
    3098              :             Real64 CpProdGasMol;
    3099            0 :             this->FigureAuxilHeatGasHeatCap(state, TauxMix, CpProdGasMol); // Cp in (J/mol*K)
    3100            0 :             Real64 NdotCpAuxMix = NdotGas * CpProdGasMol * 1000.0;
    3101              : 
    3102            0 :             if ((NdotCpWater != 0.0) && (NdotCpAuxMix != 0.0)) { // trap divide by zero
    3103              :                 // now evaluate Eq. 44
    3104            0 :                 this->ExhaustHX.THXexh =
    3105            0 :                     ((1.0 - NdotCpAuxMix / NdotCpWater) / (std::exp(UAeff * (1.0 / NdotCpAuxMix - 1.0 / NdotCpWater)) - NdotCpAuxMix / NdotCpWater)) *
    3106            0 :                         TauxMix +
    3107            0 :                     (std::expm1(UAeff * (1.0 / NdotCpAuxMix - 1.0 / NdotCpWater)) /
    3108            0 :                      (std::exp(UAeff * (1.0 / NdotCpAuxMix - 1.0 / NdotCpWater)) - NdotCpAuxMix / NdotCpWater)) *
    3109              :                         TwaterIn;
    3110              : 
    3111            0 :                 this->ExhaustHX.WaterOutletTemp = TwaterIn + (NdotCpAuxMix / NdotCpWater) * (TauxMix - this->ExhaustHX.THXexh); // Eq. 42
    3112              : 
    3113              :             } else {
    3114            0 :                 this->ExhaustHX.THXexh = TauxMix;
    3115            0 :                 this->ExhaustHX.WaterOutletTemp = TwaterIn;
    3116              :             }
    3117              : 
    3118            0 :             if ((this->ExhaustHX.THXexh - TwaterIn) != 0.0) { // trap divide by zero
    3119            0 :                 this->ExhaustHX.qHX = UAeff * ((TauxMix - this->ExhaustHX.WaterOutletTemp) - (this->ExhaustHX.THXexh - TwaterIn)) /
    3120            0 :                                       std::log((TauxMix - this->ExhaustHX.WaterOutletTemp) / (this->ExhaustHX.THXexh - TwaterIn));
    3121              :             } else {
    3122            0 :                 this->ExhaustHX.qHX = 0.0;
    3123              :             }
    3124              : 
    3125            0 :         } break;
    3126         6705 :         case DataGenerators::ExhaustGasHX::Condensing: { // method 4
    3127         6705 :             if (this->ExhaustHX.WaterMassFlowRate != 0.0) {
    3128              : 
    3129         6684 :                 Real64 MWwater = state.dataGenerator->GasPhaseThermoChemistryData(4).MolecularWeight;
    3130         6684 :                 Real64 NdotWater = this->ExhaustHX.WaterMassFlowRate / MWwater;
    3131         6684 :                 Real64 NdotGas = this->AuxilHeat.NdotAuxMix;
    3132              : 
    3133         6684 :                 Real64 UAeff = this->ExhaustHX.hxs0 + this->ExhaustHX.hxs1 * NdotWater + this->ExhaustHX.hxs2 * pow_2(NdotWater) +
    3134         6684 :                                this->ExhaustHX.hxs3 * NdotGas + this->ExhaustHX.hxs4 * pow_2(NdotGas);
    3135              : 
    3136         6684 :                 Real64 TauxMix = this->AuxilHeat.TauxMix;
    3137         6684 :                 Real64 TwaterIn = this->ExhaustHX.WaterInletTemp;
    3138              :                 Real64 CpWaterMol;
    3139         6684 :                 FigureLiquidWaterHeatCap(TwaterIn, CpWaterMol);
    3140         6684 :                 Real64 NdotCpWater = NdotWater * CpWaterMol * 1000.0;
    3141              :                 Real64 CpProdGasMol;
    3142         6684 :                 this->FigureAuxilHeatGasHeatCap(state, TauxMix, CpProdGasMol); // Cp in (J/mol*K)
    3143         6684 :                 Real64 NdotCpAuxMix = NdotGas * CpProdGasMol * 1000.0;
    3144              : 
    3145              :                 // find water fraction in incoming gas stream
    3146       100260 :                 for (int i = 1; i <= isize(this->AuxilHeat.GasLibID); ++i) {
    3147        93576 :                     if (this->AuxilHeat.GasLibID(i) == GasID::Water) this->ExhaustHX.WaterVaporFractExh = this->AuxilHeat.ConstitMolalFract(i);
    3148              :                 }
    3149         6684 :                 Real64 NdotWaterVapor = this->ExhaustHX.WaterVaporFractExh * NdotGas;
    3150              : 
    3151         6684 :                 Real64 TcondThresh = this->ExhaustHX.CondensationThresholdTemp;
    3152         6684 :                 Real64 hxl1 = this->ExhaustHX.l1Coeff;
    3153         6684 :                 Real64 hxl2 = this->ExhaustHX.l2Coeff;
    3154              : 
    3155         6684 :                 this->ExhaustHX.CondensateRate =
    3156         6684 :                     (TcondThresh - TwaterIn) * (hxl1 * (NdotWaterVapor / NdotGas) + hxl2 * pow_2(NdotWaterVapor / NdotGas));
    3157              : 
    3158         6684 :                 if (this->ExhaustHX.CondensateRate < 0.0) this->ExhaustHX.CondensateRate = 0.0;
    3159              : 
    3160         6684 :                 Real64 hfpwater = 4.4004e+07; // molal heat of vaporization of water J/kmol)
    3161              : 
    3162         6684 :                 if ((NdotCpWater != 0.0) && (NdotCpAuxMix != 0.0)) { // trap divide by zero
    3163              : 
    3164              :                     // now evaluate Eq. 44
    3165         6684 :                     this->ExhaustHX.THXexh = ((1.0 - NdotCpAuxMix / NdotCpWater) /
    3166         6684 :                                               (std::exp(UAeff * (1.0 / NdotCpAuxMix - 1.0 / NdotCpWater)) - NdotCpAuxMix / NdotCpWater)) *
    3167         6684 :                                                  TauxMix +
    3168         6684 :                                              (std::expm1(UAeff * (1.0 / NdotCpAuxMix - 1.0 / NdotCpWater)) /
    3169         6684 :                                               (std::exp(UAeff * (1.0 / NdotCpAuxMix - 1.0 / NdotCpWater)) - NdotCpAuxMix / NdotCpWater)) *
    3170              :                                                  TwaterIn;
    3171              : 
    3172         6684 :                     this->ExhaustHX.WaterOutletTemp = TwaterIn + (NdotCpAuxMix / NdotCpWater) * (TauxMix - this->ExhaustHX.THXexh) +
    3173         6684 :                                                       (this->ExhaustHX.CondensateRate * hfpwater) / NdotCpWater;
    3174              : 
    3175         6684 :                     if (this->ExhaustHX.CondensateRate > 0) { // Eq. 44 is not correct. use its result as first guess for revised way...
    3176              :                         // iterative solution because in condensing case THXexh is function of qSens and qLatent
    3177            0 :                         for (int loop = 1; loop <= 5; ++loop) {
    3178              : 
    3179              :                             Real64 qSens;
    3180              :                             Real64 qLatent;
    3181              : 
    3182            0 :                             if ((this->ExhaustHX.THXexh - TwaterIn) != 0.0 &&
    3183            0 :                                 ((TauxMix - this->ExhaustHX.WaterOutletTemp) / (this->ExhaustHX.THXexh - TwaterIn) >
    3184              :                                  0.0001)) { // trap divide by zero and negative log
    3185            0 :                                 qSens = UAeff * ((TauxMix - this->ExhaustHX.WaterOutletTemp) - (this->ExhaustHX.THXexh - TwaterIn)) /
    3186            0 :                                         std::log((TauxMix - this->ExhaustHX.WaterOutletTemp) / (this->ExhaustHX.THXexh - TwaterIn));
    3187              :                             } else {
    3188            0 :                                 qSens = 0.0;
    3189              :                             }
    3190            0 :                             qLatent = this->ExhaustHX.CondensateRate * hfpwater;
    3191            0 :                             if (qSens > 0) {
    3192            0 :                                 this->ExhaustHX.THXexh =
    3193            0 :                                     TauxMix * ((1.0 - NdotCpAuxMix / NdotCpWater) / ((std::exp(UAeff * (1.0 / NdotCpAuxMix - 1.0 / NdotCpWater)) /
    3194            0 :                                                                                       (std::exp((UAeff * qLatent) / (NdotCpWater * qSens)))) -
    3195            0 :                                                                                      NdotCpAuxMix / NdotCpWater)) +
    3196            0 :                                     TwaterIn * ((std::exp(UAeff * (1.0 / NdotCpAuxMix - 1.0 / NdotCpWater)) /
    3197            0 :                                                      (std::exp((UAeff * qLatent) / (NdotCpWater * qSens))) -
    3198            0 :                                                  1.0) /
    3199            0 :                                                 (std::exp(UAeff * (1.0 / NdotCpAuxMix - 1.0 / NdotCpWater)) /
    3200            0 :                                                      (std::exp((UAeff * qLatent) / (NdotCpWater * qSens))) -
    3201            0 :                                                  NdotCpAuxMix / NdotCpWater)) -
    3202            0 :                                     ((qLatent / NdotCpWater) / (std::exp(UAeff * (1.0 / NdotCpAuxMix - 1.0 / NdotCpWater)) /
    3203            0 :                                                                     (std::exp((UAeff * qLatent) / (NdotCpWater * qSens))) -
    3204            0 :                                                                 NdotCpAuxMix / NdotCpWater));
    3205              :                             } else {
    3206            0 :                                 this->ExhaustHX.THXexh = TauxMix;
    3207              :                             }
    3208              : 
    3209            0 :                             this->ExhaustHX.WaterOutletTemp = TwaterIn + (NdotCpAuxMix / NdotCpWater) * (TauxMix - this->ExhaustHX.THXexh) +
    3210            0 :                                                               (this->ExhaustHX.CondensateRate * hfpwater) / NdotCpWater;
    3211              :                         }
    3212              :                     }
    3213              : 
    3214         6684 :                 } else {
    3215            0 :                     this->ExhaustHX.THXexh = TauxMix;
    3216            0 :                     this->ExhaustHX.WaterOutletTemp = TwaterIn;
    3217              :                 }
    3218              : 
    3219         6684 :                 if ((this->ExhaustHX.THXexh - TwaterIn) != 0.0 && ((TauxMix - this->ExhaustHX.WaterOutletTemp) / (this->ExhaustHX.THXexh - TwaterIn) >
    3220              :                                                                    0.0001)) { // trap divide by zero and negative log
    3221              : 
    3222         6684 :                     this->ExhaustHX.qHX = UAeff * ((TauxMix - this->ExhaustHX.WaterOutletTemp) - (this->ExhaustHX.THXexh - TwaterIn)) /
    3223         6684 :                                               std::log((TauxMix - this->ExhaustHX.WaterOutletTemp) / (this->ExhaustHX.THXexh - TwaterIn)) +
    3224         6684 :                                           this->ExhaustHX.CondensateRate * hfpwater;
    3225              :                 } else {
    3226            0 :                     this->ExhaustHX.qHX = 0.0;
    3227              :                 }
    3228              :             } else { // no cooling water flow, model will blow up.
    3229           21 :                 this->ExhaustHX.qHX = 0.0;
    3230           21 :                 this->ExhaustHX.THXexh = this->AuxilHeat.TauxMix;
    3231           21 :                 this->ExhaustHX.WaterOutletTemp = this->ExhaustHX.WaterInletTemp;
    3232           21 :                 this->ExhaustHX.CondensateRate = 0.0;
    3233           21 :                 this->ExhaustHX.WaterVaporFractExh = -9999.0; // not defined
    3234              :             }
    3235         6705 :         } break;
    3236            0 :         default: {
    3237            0 :             assert(false); // Variables not set are used below
    3238              :         } break;
    3239              :         }
    3240              : 
    3241              :         // update results in data structure.
    3242         6705 :         this->ExhaustHX.WaterOutletEnthalpy = state.dataLoopNodes->Node(this->ExhaustHX.WaterInNode).Enthalpy + this->ExhaustHX.qHX;
    3243         6705 :     }
    3244              : 
    3245            5 :     void FCDataStruct::getDesignCapacities([[maybe_unused]] EnergyPlusData &state,
    3246              :                                            [[maybe_unused]] const PlantLocation &calledFromLocation,
    3247              :                                            Real64 &MaxLoad,
    3248              :                                            Real64 &MinLoad,
    3249              :                                            Real64 &OptLoad)
    3250              :     {
    3251            5 :         MaxLoad = 0.0;
    3252            5 :         MinLoad = 0.0;
    3253            5 :         OptLoad = 0.0;
    3254            5 :     }
    3255              : 
    3256         5966 :     void FCDataStruct::simulate(EnergyPlusData &state,
    3257              :                                 [[maybe_unused]] const PlantLocation &calledFromLocation,
    3258              :                                 bool FirstHVACIteration,
    3259              :                                 [[maybe_unused]] Real64 &CurLoad,
    3260              :                                 [[maybe_unused]] bool RunFlag)
    3261              :     {
    3262         5966 :         if (this->Type == DataPlant::PlantEquipmentType::Generator_FCStackCooler) {
    3263            0 :             PlantUtilities::UpdateComponentHeatRecoverySide(state,
    3264              :                                                             this->CWPlantLoc.loopNum,
    3265              :                                                             this->CWPlantLoc.loopSideNum,
    3266              :                                                             DataPlant::PlantEquipmentType::Generator_FCStackCooler,
    3267              :                                                             this->StackCooler.WaterInNode,
    3268              :                                                             this->StackCooler.WaterOutNode,
    3269              :                                                             this->Report.qHX,
    3270              :                                                             this->Report.HeatRecInletTemp,
    3271              :                                                             this->Report.HeatRecOutletTemp,
    3272              :                                                             this->Report.HeatRecMdot,
    3273              :                                                             FirstHVACIteration);
    3274         5966 :         } else if (this->Type == DataPlant::PlantEquipmentType::Generator_FCExhaust) {
    3275         5966 :             PlantUtilities::UpdateComponentHeatRecoverySide(state,
    3276              :                                                             this->CWPlantLoc.loopNum,
    3277              :                                                             this->CWPlantLoc.loopSideNum,
    3278              :                                                             DataPlant::PlantEquipmentType::Generator_FCExhaust,
    3279              :                                                             this->ExhaustHX.WaterInNode,
    3280              :                                                             this->ExhaustHX.WaterOutNode,
    3281              :                                                             this->ExhaustHX.qHX,
    3282              :                                                             this->ExhaustHX.WaterInletTemp,
    3283              :                                                             this->ExhaustHX.WaterOutletTemp,
    3284              :                                                             this->ExhaustHX.WaterMassFlowRate,
    3285              :                                                             FirstHVACIteration);
    3286              :         }
    3287         5966 :     }
    3288              : 
    3289         2235 :     void FCDataStruct::initialize(EnergyPlusData &state) // index to specific fuel cell generator
    3290              :     {
    3291              : 
    3292              :         // SUBROUTINE INFORMATION:
    3293              :         //       AUTHOR         Brent Griffith
    3294              :         //       DATE WRITTEN   Aug 2005
    3295              :         //       RE-ENGINEERED  B. Griffith Sept 2010, plant upgrades
    3296              : 
    3297              :         // PURPOSE OF THIS SUBROUTINE:
    3298              :         // This subroutine is for initializations of the FuelCell generators.
    3299              : 
    3300              :         // METHODOLOGY EMPLOYED:
    3301              :         // Uses the status flags to trigger initializations.
    3302              : 
    3303              :         static constexpr std::string_view RoutineName("InitFuelCellGenerators");
    3304              : 
    3305              :         // Do the Begin Environment initializations
    3306         2235 :         if (state.dataGlobal->BeginEnvrnFlag && this->MyEnvrnFlag_Init && !this->MyPlantScanFlag_Init) {
    3307              : 
    3308            2 :             state.dataGenerator->FuelSupply(this->FuelSupNum).PfuelCompEl = 0.0;
    3309            2 :             state.dataGenerator->FuelSupply(this->FuelSupNum).TfuelIntoFCPM = 0.0;
    3310            2 :             state.dataGenerator->FuelSupply(this->FuelSupNum).TfuelIntoCompress = 0.0;
    3311            2 :             state.dataGenerator->FuelSupply(this->FuelSupNum).QskinLoss = 0.0;
    3312              : 
    3313            2 :             this->AirSup.TairIntoFCPM = 0.0;
    3314            2 :             this->AirSup.PairCompEl = 0.0;
    3315            2 :             this->AirSup.TairIntoBlower = 0.0;
    3316            2 :             this->AirSup.QskinLoss = 0.0;
    3317            2 :             this->AirSup.QintakeRecovery = 0.0;
    3318            2 :             this->FCPM.NumCycles = this->FCPM.NumCyclesAtStart;
    3319            2 :             this->FCPM.Pel = 0.0;
    3320            2 :             this->FCPM.PelLastTimeStep = 0.0;
    3321            2 :             this->FCPM.Eel = 0.0;
    3322            2 :             this->FCPM.PelancillariesAC = 0.0;
    3323            2 :             this->FCPM.NdotFuel = 0.0;
    3324            2 :             this->FCPM.TotFuelInEnthalpy = 0.0;
    3325            2 :             this->FCPM.NdotProdGas = 0.0;
    3326            2 :             this->FCPM.TprodGasLeavingFCPM = 0.0;
    3327            2 :             this->FCPM.TotProdGasEnthalpy = 0.0;
    3328            2 :             this->FCPM.NdotAir = 0.0;
    3329            2 :             this->FCPM.TotAirInEnthalpy = 0.0;
    3330            2 :             this->FCPM.NdotLiqwater = 0.0;
    3331            2 :             this->FCPM.TwaterInlet = 0.0;
    3332            2 :             this->FCPM.WaterInEnthalpy = 0.0;
    3333            2 :             this->FCPM.TprodGasLeavingFCPM = 200.0;
    3334            2 :             this->FCPM.FractionalDayofLastStartUp = 0.0;
    3335            2 :             this->FCPM.FractionalDayofLastShutDown = 0.0;
    3336            2 :             this->FCPM.HasBeenOn = true;
    3337            2 :             this->FCPM.DuringShutDown = false;
    3338            2 :             this->FCPM.DuringStartUp = false;
    3339            2 :             this->WaterSup.TwaterIntoCompress = 0.0;
    3340            2 :             this->WaterSup.TwaterIntoFCPM = 0.0;
    3341            2 :             this->WaterSup.PwaterCompEl = 0.0;
    3342            2 :             this->WaterSup.QskinLoss = 0.0;
    3343            2 :             this->AuxilHeat.TauxMix = 0.0;
    3344            2 :             this->AuxilHeat.NdotAuxMix = 0.0;
    3345            2 :             this->AuxilHeat.QskinLoss = 0.0;
    3346            2 :             this->AuxilHeat.QairIntake = 0.0;
    3347            2 :             this->ExhaustHX.NdotHXleaving = 0.0;
    3348            2 :             this->ExhaustHX.WaterOutletTemp = 0.0;
    3349            2 :             this->ExhaustHX.WaterOutletEnthalpy = 0.0;
    3350            2 :             this->ElecStorage.LastTimeStepStateOfCharge = this->ElecStorage.StartingEnergyStored;
    3351            2 :             this->ElecStorage.ThisTimeStepStateOfCharge = this->ElecStorage.StartingEnergyStored;
    3352            2 :             this->ElecStorage.PelNeedFromStorage = 0.0;
    3353            2 :             this->ElecStorage.IdesiredDischargeCurrent = 0.0;
    3354            2 :             this->ElecStorage.PelFromStorage = 0.0;
    3355            2 :             this->ElecStorage.IfromStorage = 0.0;
    3356            2 :             this->ElecStorage.PelIntoStorage = 0.0;
    3357            2 :             this->ElecStorage.QairIntake = 0.0;
    3358              : 
    3359            2 :             this->Inverter.PCUlosses = 0.0;
    3360            2 :             this->Inverter.QairIntake = 0.0;
    3361              : 
    3362            2 :             Real64 rho = state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).glycol->getDensity(state, DataGenerators::InitHRTemp, RoutineName);
    3363              : 
    3364            2 :             this->ExhaustHX.WaterMassFlowRateDesign = this->ExhaustHX.WaterVolumeFlowMax * rho;
    3365            2 :             this->ExhaustHX.WaterMassFlowRate = this->ExhaustHX.WaterMassFlowRateDesign;
    3366            2 :             state.dataLoopNodes->Node(this->ExhaustHX.WaterInNode).Temp = DataGenerators::InitHRTemp;
    3367            2 :             state.dataLoopNodes->Node(this->ExhaustHX.WaterOutNode).Temp = DataGenerators::InitHRTemp;
    3368              : 
    3369            2 :             PlantUtilities::InitComponentNodes(
    3370              :                 state, 0.0, this->ExhaustHX.WaterMassFlowRateDesign, this->ExhaustHX.WaterInNode, this->ExhaustHX.WaterOutNode);
    3371              : 
    3372            2 :             this->MyEnvrnFlag_Init = false;
    3373            2 :             this->MyWarmupFlag_Init = true;
    3374              :         } // end environmental inits
    3375              : 
    3376         2235 :         if (!state.dataGlobal->BeginEnvrnFlag) {
    3377         2229 :             this->MyEnvrnFlag_Init = true;
    3378              :         }
    3379              : 
    3380         2235 :         if (this->MyWarmupFlag_Init && (!state.dataGlobal->WarmupFlag)) {
    3381              :             // need to reset initial state of charge at beginning of environment but after warm up is complete
    3382            1 :             this->ElecStorage.LastTimeStepStateOfCharge = this->ElecStorage.StartingEnergyStored;
    3383            1 :             this->ElecStorage.ThisTimeStepStateOfCharge = this->ElecStorage.StartingEnergyStored;
    3384            1 :             this->MyWarmupFlag_Init = false;
    3385              :         }
    3386              : 
    3387              :         // using and elapsed time method rather than FirstHVACIteration here
    3388              :         Real64 timeElapsed =
    3389         2235 :             state.dataGlobal->HourOfDay + state.dataGlobal->TimeStep * state.dataGlobal->TimeStepZone + state.dataHVACGlobal->SysTimeElapsed;
    3390         2235 :         if (this->TimeElapsed != timeElapsed) {
    3391              : 
    3392          725 :             this->ElecStorage.LastTimeStepStateOfCharge = this->ElecStorage.ThisTimeStepStateOfCharge;
    3393          725 :             this->FCPM.PelLastTimeStep = this->FCPM.Pel;
    3394              : 
    3395              :             // initialize flow rate in water loop, this is "requesting" flow
    3396          725 :             Real64 mdot = this->ExhaustHX.WaterMassFlowRateDesign;
    3397              : 
    3398          725 :             PlantUtilities::SetComponentFlowRate(state, mdot, this->ExhaustHX.WaterInNode, this->ExhaustHX.WaterOutNode, this->CWPlantLoc);
    3399              : 
    3400          725 :             this->ExhaustHX.WaterMassFlowRate = mdot;
    3401          725 :             this->ExhaustHX.WaterInletTemp = state.dataLoopNodes->Node(this->ExhaustHX.WaterInNode).Temp;
    3402          725 :             this->TimeElapsed = timeElapsed;
    3403              :         } else {
    3404              : 
    3405         1510 :             PlantUtilities::SetComponentFlowRate(
    3406         1510 :                 state, this->ExhaustHX.WaterMassFlowRate, this->ExhaustHX.WaterInNode, this->ExhaustHX.WaterOutNode, this->CWPlantLoc);
    3407              : 
    3408         1510 :             this->ExhaustHX.WaterInletTemp = state.dataLoopNodes->Node(this->ExhaustHX.WaterInNode).Temp;
    3409              :         }
    3410         2235 :     }
    3411              : 
    3412       249958 :     void FigureFuelCellZoneGains(EnergyPlusData &state)
    3413              :     {
    3414              : 
    3415              :         // SUBROUTINE INFORMATION:
    3416              :         //       AUTHOR         B. Griffith
    3417              :         //       DATE WRITTEN   Aug 2005
    3418              :         //       MODIFIED       BG March 2007
    3419              : 
    3420              :         // PURPOSE OF THIS SUBROUTINE:
    3421              :         // Couple equipment skin losses to the Zone Heat Balance
    3422              :         // calculate skin losses from different subsystems and set the value
    3423              : 
    3424              :         // METHODOLOGY EMPLOYED:
    3425              :         // This routine adds up the various skin losses and then
    3426              :         //  sets the values in the ZoneIntGain structure
    3427              : 
    3428       249958 :         if (state.dataFuelCellElectGen->NumFuelCellGenerators == 0) return;
    3429              : 
    3430          674 :         if (state.dataGlobal->BeginEnvrnFlag && state.dataFuelCellElectGen->MyEnvrnFlag) {
    3431            2 :             for (auto &e : state.dataGenerator->FuelSupply)
    3432            1 :                 e.QskinLoss = 0.0;
    3433            1 :             state.dataFuelCellElectGen->MyEnvrnFlag = false;
    3434            2 :             for (int i = state.dataFuelCellElectGen->FuelCell.l(), e = state.dataFuelCellElectGen->FuelCell.u(); i <= e; ++i) {
    3435            1 :                 auto &cell(state.dataFuelCellElectGen->FuelCell(i));
    3436            1 :                 cell.FCPM.HasBeenOn = false;
    3437            1 :                 cell.AirSup.PairCompEl = 0.0;
    3438            1 :                 cell.QconvZone = 0.0;
    3439            1 :                 cell.QradZone = 0.0;
    3440            1 :                 cell.AirSup.QskinLoss = 0.0;
    3441            1 :                 cell.WaterSup.QskinLoss = 0.0;
    3442            1 :                 cell.AuxilHeat.QskinLoss = 0.0;
    3443            1 :                 if (cell.FCPM.SkinLossMode != DataGenerators::SkinLoss::ConstantRate) {
    3444              :                     // If Constant Skin Loss Rate, then do not zero out
    3445            0 :                     cell.FCPM.QdotSkin = 0.0;
    3446              :                 }
    3447            1 :                 cell.Report.SkinLossConvect = 0.0;
    3448            1 :                 cell.Report.SkinLossRadiat = 0.0;
    3449            1 :                 cell.AuxilHeat.QairIntake = 0.0;
    3450            1 :                 cell.ElecStorage.QairIntake = 0.0;
    3451            1 :                 cell.Inverter.QairIntake = 0.0;
    3452              :             }
    3453              :         }
    3454              : 
    3455          674 :         if (!state.dataGlobal->BeginEnvrnFlag) state.dataFuelCellElectGen->MyEnvrnFlag = true;
    3456              : 
    3457              :         // this routine needs to do something for zone gains during sizing
    3458              : 
    3459              :         // first collect skin losses from different subsystems
    3460         1348 :         for (int FCnum = 1; FCnum <= state.dataFuelCellElectGen->NumFuelCellGenerators; ++FCnum) {
    3461          674 :             auto &thisFC = state.dataFuelCellElectGen->FuelCell(FCnum);
    3462          674 :             Real64 TotalZoneHeatGain = thisFC.AirSup.QskinLoss + state.dataGenerator->FuelSupply(thisFC.FuelSupNum).QskinLoss +
    3463          674 :                                        thisFC.WaterSup.QskinLoss + thisFC.AuxilHeat.QskinLoss +
    3464          674 :                                        thisFC.FCPM.QdotSkin; // intake Blower losses to zone | fuel compressor losses to
    3465              :                                                              // zone | water pump losses to zone | auxil burner losses to
    3466              :                                                              // zone | power module (stack and reformer) losses to zone
    3467              : 
    3468              :             // now account for other subsystems that may or may not have air intake recovery
    3469          674 :             switch (thisFC.AirSup.IntakeRecoveryMode) {
    3470          674 :             case DataGenerators::RecoverMode::NoRecoveryOnAirIntake: { // then the heat has to go into zone
    3471          674 :                 TotalZoneHeatGain += thisFC.AuxilHeat.QairIntake + thisFC.ElecStorage.QairIntake + thisFC.Inverter.QairIntake;
    3472          674 :             } break;
    3473            0 :             case DataGenerators::RecoverMode::RecoverAuxiliaryBurner: {
    3474            0 :                 TotalZoneHeatGain += thisFC.ElecStorage.QairIntake + thisFC.Inverter.QairIntake;
    3475            0 :             } break;
    3476            0 :             case DataGenerators::RecoverMode::RecoverInverterBatt: {
    3477            0 :                 TotalZoneHeatGain += thisFC.AuxilHeat.QairIntake;
    3478            0 :             } break;
    3479            0 :             case DataGenerators::RecoverMode::RecoverInverter: {
    3480            0 :                 TotalZoneHeatGain += thisFC.AuxilHeat.QairIntake + thisFC.ElecStorage.QairIntake;
    3481            0 :             } break;
    3482            0 :             case DataGenerators::RecoverMode::RecoverBattery: {
    3483            0 :                 TotalZoneHeatGain += thisFC.AuxilHeat.QairIntake + thisFC.Inverter.QairIntake;
    3484            0 :             } break;
    3485            0 :             case DataGenerators::RecoverMode::RecoverBurnInvertBatt: {
    3486              :                 // do nothing
    3487            0 :             } break;
    3488            0 :             default:
    3489            0 :                 break;
    3490              :             }
    3491              : 
    3492          674 :             thisFC.QconvZone = TotalZoneHeatGain * (1 - thisFC.FCPM.RadiativeFract);
    3493          674 :             thisFC.Report.SkinLossConvect = thisFC.QconvZone;
    3494          674 :             thisFC.QradZone = TotalZoneHeatGain * thisFC.FCPM.RadiativeFract;
    3495          674 :             thisFC.Report.SkinLossRadiat = thisFC.QradZone;
    3496              : 
    3497              :         } // over number of Fuel cells
    3498              :     }
    3499              : 
    3500         2235 :     void FCDataStruct::CalcUpdateHeatRecovery(EnergyPlusData &state, [[maybe_unused]] bool const FirstHVACIteration) const
    3501              :     {
    3502              : 
    3503              :         // SUBROUTINE INFORMATION:
    3504              :         //       AUTHOR         B Griffith
    3505              :         //       DATE WRITTEN   March 2008
    3506              : 
    3507              :         // PURPOSE OF THIS SUBROUTINE:
    3508              :         // update plant loop interactions, do any calcs needed
    3509              : 
    3510              :         // now update water outlet node Changing to Kg/s!
    3511         2235 :         PlantUtilities::SafeCopyPlantNode(state, this->ExhaustHX.WaterInNode, this->ExhaustHX.WaterOutNode);
    3512              : 
    3513         2235 :         state.dataLoopNodes->Node(this->ExhaustHX.WaterOutNode).Temp = this->ExhaustHX.WaterOutletTemp;
    3514         2235 :         state.dataLoopNodes->Node(this->ExhaustHX.WaterOutNode).Enthalpy = this->ExhaustHX.WaterOutletEnthalpy;
    3515         2235 :     }
    3516              : 
    3517         2235 :     void FCDataStruct::UpdateFuelCellGeneratorRecords(EnergyPlusData &state)
    3518              :     {
    3519              : 
    3520         2235 :         this->Report.ACPowerGen = this->ACPowerGen;                                         // electrical power produced [W]
    3521         2235 :         this->Report.ACEnergyGen = this->ACPowerGen * state.dataHVACGlobal->TimeStepSysSec; // energy produced (J)
    3522         2235 :         this->Report.QdotExhaust = 0.0;                                                     // reporting: exhaust gas heat recovered (W)
    3523         2235 :         this->Report.TotalHeatEnergyRec = 0.0;                                              // reporting: total heat recovered (J)
    3524         2235 :         this->Report.ExhaustEnergyRec = 0.0;                                                // reporting: exhaust gas heat recovered (J)
    3525              : 
    3526         2235 :         this->Report.HeatRecInletTemp = 0.0;  // reporting: Heat Recovery Loop Inlet Temperature (C)
    3527         2235 :         this->Report.HeatRecOutletTemp = 0.0; // reporting: Heat Recovery Loop Outlet Temperature (C)
    3528         2235 :         this->Report.HeatRecMdot = 0.0;       // reporting: Heat Recovery Loop Mass flow rate (kg/s)
    3529              : 
    3530         2235 :         this->Report.ElectEfficiency = 0.0;
    3531         2235 :         this->Report.ThermalEfficiency = 0.0;
    3532         2235 :         this->Report.OverallEfficiency = 0.0;
    3533         2235 :         this->Report.ExergyEfficiency = 0.0;
    3534              : 
    3535         2235 :         this->Report.TairInlet = this->AirSup.TairIntoBlower;                                       // State point 1
    3536         2235 :         this->Report.TairIntoFCPM = this->AirSup.TairIntoFCPM;                                      // State point 4
    3537         2235 :         this->Report.NdotAir = this->FCPM.NdotAir;                                                  // air flow in kmol/sec
    3538         2235 :         this->Report.TotAirInEnthalpy = this->FCPM.TotAirInEnthalpy;                                // State point 4
    3539         2235 :         this->Report.BlowerPower = this->AirSup.PairCompEl;                                         // electrical power used by air supply blower
    3540         2235 :         this->Report.BlowerEnergy = this->AirSup.PairCompEl * state.dataHVACGlobal->TimeStepSysSec; // electrical energy
    3541         2235 :         this->Report.BlowerSkinLoss = this->AirSup.QskinLoss;                                       // heat rate of losses by blower
    3542              : 
    3543         2235 :         this->Report.TfuelInlet = state.dataGenerator->FuelSupply(this->FuelSupNum).TfuelIntoCompress; // State point 2
    3544         2235 :         this->Report.TfuelIntoFCPM = state.dataGenerator->FuelSupply(this->FuelSupNum).TfuelIntoFCPM;  // TEmperature state point 5 [C]
    3545         2235 :         this->Report.NdotFuel = this->FCPM.NdotFuel;                                                   // fuel flow in kmol/sec
    3546         2235 :         this->Report.TotFuelInEnthalpy = this->FCPM.TotFuelInEnthalpy;                                 // enthalpy at state point 5 [W]
    3547         2235 :         this->Report.FuelCompressPower = state.dataGenerator->FuelSupply(this->FuelSupNum).PfuelCompEl;
    3548              :         // electrical power used by fuel supply compressor [W]
    3549         2235 :         this->Report.FuelCompressEnergy =
    3550         2235 :             state.dataGenerator->FuelSupply(this->FuelSupNum).PfuelCompEl * state.dataHVACGlobal->TimeStepSys * Constant::rSecsInHour; // elect energy
    3551         2235 :         this->Report.FuelCompressSkinLoss = state.dataGenerator->FuelSupply(this->FuelSupNum).QskinLoss;
    3552              :         // heat rate of losses.by fuel supply compressor [W]
    3553         2235 :         this->Report.FuelEnergyLHV = this->FCPM.NdotFuel * state.dataGenerator->FuelSupply(this->FuelSupNum).LHV * 1000000.0 *
    3554         2235 :                                      state.dataHVACGlobal->TimeStepSysSec; // reporting: Fuel Energy used (J)
    3555         2235 :         this->Report.FuelEnergyUseRateLHV =
    3556         2235 :             this->FCPM.NdotFuel * state.dataGenerator->FuelSupply(this->FuelSupNum).LHV * 1000000.0; // reporting: Fuel Energy used (W)
    3557         2235 :         this->Report.FuelEnergyHHV = this->FCPM.NdotFuel * state.dataGenerator->FuelSupply(this->FuelSupNum).HHV *
    3558         2235 :                                      state.dataGenerator->FuelSupply(this->FuelSupNum).KmolPerSecToKgPerSec * state.dataHVACGlobal->TimeStepSys *
    3559              :                                      Constant::rSecsInHour;
    3560              : 
    3561         2235 :         this->Report.FuelEnergyUseRateHHV = this->FCPM.NdotFuel * state.dataGenerator->FuelSupply(this->FuelSupNum).HHV *
    3562         2235 :                                             state.dataGenerator->FuelSupply(this->FuelSupNum).KmolPerSecToKgPerSec;
    3563              : 
    3564         2235 :         this->Report.FuelRateMdot = 0.0; // (Kg/s)
    3565              : 
    3566         2235 :         this->Report.TwaterInlet = this->WaterSup.TwaterIntoCompress;
    3567         2235 :         this->Report.TwaterIntoFCPM = this->WaterSup.TwaterIntoFCPM;
    3568         2235 :         this->Report.NdotWater = this->FCPM.NdotLiqwater; // water flow in kmol/sec (reformer water)
    3569         2235 :         this->Report.WaterPumpPower = this->WaterSup.PwaterCompEl;
    3570         2235 :         this->Report.WaterPumpEnergy = this->WaterSup.PwaterCompEl * state.dataHVACGlobal->TimeStepSysSec; // electrical energy
    3571         2235 :         this->Report.WaterIntoFCPMEnthalpy = this->FCPM.WaterInEnthalpy;
    3572              : 
    3573         2235 :         this->Report.TprodGas = this->FCPM.TprodGasLeavingFCPM;     // temperature at State point 7
    3574         2235 :         this->Report.EnthalProdGas = this->FCPM.TotProdGasEnthalpy; // enthalpy at State point 7
    3575         2235 :         this->Report.NdotProdGas = this->FCPM.NdotProdGas;          // flow rate at point 7 [kmol/sec]
    3576         2235 :         this->Report.NdotProdAr = this->FCPM.ConstitMolalFract(5) * this->FCPM.NdotProdGas;
    3577         2235 :         this->Report.NdotProdCO2 = this->FCPM.ConstitMolalFract(1) * this->FCPM.NdotProdGas;
    3578         2235 :         this->Report.NdotProdH2O = this->FCPM.ConstitMolalFract(4) * this->FCPM.NdotProdGas;
    3579         2235 :         this->Report.NdotProdN2 = this->FCPM.ConstitMolalFract(2) * this->FCPM.NdotProdGas;
    3580         2235 :         this->Report.NdotProdO2 = this->FCPM.ConstitMolalFract(3) * this->FCPM.NdotProdGas;
    3581              : 
    3582         2235 :         this->Report.qHX = this->ExhaustHX.qHX;
    3583         2235 :         this->Report.HXenergy = this->ExhaustHX.qHX * state.dataHVACGlobal->TimeStepSysSec;
    3584         2235 :         this->Report.THXexh = this->ExhaustHX.THXexh;
    3585         2235 :         this->Report.WaterVaporFractExh = this->ExhaustHX.WaterVaporFractExh;
    3586         2235 :         this->Report.CondensateRate = this->ExhaustHX.CondensateRate;
    3587              : 
    3588         2235 :         this->Report.SeqSubstIterations = this->FCPM.SeqSubstitIter;     // number of iterations in FuelCell loop
    3589         2235 :         this->Report.RegulaFalsiIterations = this->FCPM.RegulaFalsiIter; // number of iterations in Tproduct gas solving
    3590         2235 :         this->Report.NumCycles = this->FCPM.NumCycles;                   // number of start-stop cycles
    3591         2235 :         this->Report.FCPMSkinLoss = this->FCPM.QdotSkin;                 // Skin loss of power module
    3592              : 
    3593         2235 :         this->Report.ACancillariesPower = this->FCPM.PelancillariesAC;
    3594         2235 :         this->Report.ACancillariesEnergy = this->FCPM.PelancillariesAC * state.dataHVACGlobal->TimeStepSysSec;
    3595              : 
    3596         2235 :         this->Report.PCUlosses = this->Inverter.PCUlosses; // inverter losses
    3597         2235 :         this->Report.DCPowerGen = this->FCPM.Pel;          // DC power out of FCPM.
    3598         2235 :         this->Report.DCPowerEff = this->FCPM.Eel;          // FCPM efficiency Eel.
    3599         2235 :         this->Report.ElectEnergyinStorage = this->ElecStorage.ThisTimeStepStateOfCharge;
    3600         2235 :         this->Report.StoredPower = this->ElecStorage.PelIntoStorage;
    3601         2235 :         this->Report.StoredEnergy = this->ElecStorage.PelIntoStorage * state.dataHVACGlobal->TimeStepSysSec;
    3602         2235 :         this->Report.DrawnPower = this->ElecStorage.PelFromStorage;
    3603         2235 :         this->Report.DrawnEnergy = this->ElecStorage.PelFromStorage * state.dataHVACGlobal->TimeStepSysSec;
    3604              : 
    3605         2235 :         this->Report.SkinLossPower = this->QconvZone + this->QradZone;
    3606         2235 :         this->Report.SkinLossEnergy = (this->QconvZone + this->QradZone) * state.dataHVACGlobal->TimeStepSysSec;
    3607         2235 :         this->Report.SkinLossConvect = this->QconvZone;
    3608         2235 :         this->Report.SkinLossRadiat = this->QradZone;
    3609         2235 :     }
    3610            1 :     void FCDataStruct::oneTimeInit_new(EnergyPlusData &state)
    3611              :     {
    3612              : 
    3613            1 :         if (this->MyPlantScanFlag_Init && allocated(state.dataPlnt->PlantLoop)) {
    3614            1 :             bool errFlag = false;
    3615              : 
    3616            2 :             PlantUtilities::ScanPlantLoopsForObject(
    3617            1 :                 state, this->NameExhaustHX, DataPlant::PlantEquipmentType::Generator_FCExhaust, this->CWPlantLoc, errFlag, _, _, _, _, _);
    3618              : 
    3619              :             // if there is a stack cooler option it might be connected to plant as well
    3620              : 
    3621            1 :             if (errFlag) {
    3622            0 :                 ShowFatalError(state, "InitFuelCellGenerators: Program terminated due to previous condition(s).");
    3623              :             }
    3624            1 :             this->MyPlantScanFlag_Init = false;
    3625              :         }
    3626            1 :     }
    3627              : 
    3628            0 :     void FCDataStruct::oneTimeInit([[maybe_unused]] EnergyPlusData &state)
    3629              :     {
    3630            0 :     }
    3631              : 
    3632              : } // namespace FuelCellElectricGenerator
    3633              : 
    3634              : } // namespace EnergyPlus
        

Generated by: LCOV version 2.0-1