LCOV - code coverage report
Current view: top level - EnergyPlus - FuelCellElectricGenerator.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 1276 1779 71.7 %
Date: 2024-08-24 18:31:18 Functions: 30 31 96.8 %

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

Generated by: LCOV version 1.14