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

Generated by: LCOV version 2.0-1