LCOV - code coverage report
Current view: top level - EnergyPlus - FuelCellElectricGenerator.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 1235 1739 71.0 %
Date: 2023-01-17 19:17:23 Functions: 31 32 96.9 %

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

Generated by: LCOV version 1.13