LCOV - code coverage report
Current view: top level - EnergyPlus - MicroturbineElectricGenerator.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 51.8 % 1030 534
Test Date: 2025-06-02 07:23:51 Functions: 100.0 % 9 9

            Line data    Source code
       1              : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
       2              : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3              : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4              : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5              : // contributors. All rights reserved.
       6              : //
       7              : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8              : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9              : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10              : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11              : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12              : //
      13              : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14              : // provided that the following conditions are met:
      15              : //
      16              : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17              : //     conditions and the following disclaimer.
      18              : //
      19              : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20              : //     conditions and the following disclaimer in the documentation and/or other materials
      21              : //     provided with the distribution.
      22              : //
      23              : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24              : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25              : //     used to endorse or promote products derived from this software without specific prior
      26              : //     written permission.
      27              : //
      28              : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29              : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30              : //     reference solely to the software portion of its product, Licensee must refer to the
      31              : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32              : //     obtained under this License and may not use a different name for the software. Except as
      33              : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34              : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35              : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36              : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37              : //
      38              : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39              : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40              : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41              : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42              : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43              : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44              : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45              : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46              : // POSSIBILITY OF SUCH DAMAGE.
      47              : 
      48              : // C++ Headers
      49              : #include <cmath>
      50              : 
      51              : // ObjexxFCL Headers
      52              : #include <ObjexxFCL/Array.functions.hh>
      53              : #include <ObjexxFCL/Fmath.hh>
      54              : 
      55              : // EnergyPlus Headers
      56              : #include <EnergyPlus/BranchNodeConnections.hh>
      57              : #include <EnergyPlus/CurveManager.hh>
      58              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      59              : #include <EnergyPlus/DataEnvironment.hh>
      60              : #include <EnergyPlus/DataGlobalConstants.hh>
      61              : #include <EnergyPlus/DataHVACGlobals.hh>
      62              : #include <EnergyPlus/DataIPShortCuts.hh>
      63              : #include <EnergyPlus/DataLoopNode.hh>
      64              : #include <EnergyPlus/DataPrecisionGlobals.hh>
      65              : #include <EnergyPlus/FluidProperties.hh>
      66              : #include <EnergyPlus/General.hh>
      67              : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      68              : #include <EnergyPlus/MicroturbineElectricGenerator.hh>
      69              : #include <EnergyPlus/NodeInputManager.hh>
      70              : #include <EnergyPlus/OutAirNodeManager.hh>
      71              : #include <EnergyPlus/OutputProcessor.hh>
      72              : #include <EnergyPlus/Plant/DataPlant.hh>
      73              : #include <EnergyPlus/PlantUtilities.hh>
      74              : #include <EnergyPlus/Psychrometrics.hh>
      75              : #include <EnergyPlus/UtilityRoutines.hh>
      76              : 
      77              : namespace EnergyPlus::MicroturbineElectricGenerator {
      78              : 
      79              : // MODULE INFORMATION:
      80              : //       AUTHOR         R. Raustad/D. Shirey
      81              : //       DATE WRITTEN   Mar 2008
      82              : //       MODIFIED       na
      83              : //       RE-ENGINEERED  na
      84              : 
      85              : // PURPOSE OF THIS MODULE:
      86              : //  This module simulates the performance of microturbine electric
      87              : //  generators.
      88              : 
      89              : // METHODOLOGY EMPLOYED:
      90              : //  Once the electric power manager determines that the MT Generator
      91              : //  is available, it calls SimMTGenerator which in turn calls the
      92              : //  appropriate microturbine generator model.
      93              : //  MT Generator models are based on polynomial curve fits of generator
      94              : //  performance data.
      95              : 
      96        51346 : PlantComponent *MTGeneratorSpecs::factory(EnergyPlusData &state, std::string const &objectName)
      97              : {
      98              :     // Process the input data for generator if it hasn't been done already
      99        51346 :     if (state.dataMircoturbElectGen->GetMTInput) {
     100            6 :         GetMTGeneratorInput(state);
     101            6 :         state.dataMircoturbElectGen->GetMTInput = false;
     102              :     }
     103              : 
     104              :     // Now look for this particular gen in the list
     105        51346 :     for (auto &thisMTG : state.dataMircoturbElectGen->MTGenerator) {
     106        51346 :         if (thisMTG.Name == objectName) {
     107        51346 :             return &thisMTG;
     108              :         }
     109       102692 :     }
     110              :     // If we didn't find it, fatal
     111            0 :     ShowFatalError(
     112              :         state, format("LocalMicroTurbineGeneratorFactory: Error getting inputs for microturbine generator named: {}", objectName)); // LCOV_EXCL_LINE
     113              :     // Shut up the compiler
     114              :     return nullptr; // LCOV_EXCL_LINE
     115              : }
     116              : 
     117            6 : void GetMTGeneratorInput(EnergyPlusData &state)
     118              : {
     119              :     // SUBROUTINE INFORMATION:
     120              :     //       AUTHOR         R. Raustad/D. Shirey
     121              :     //       DATE WRITTEN   Mar 2008
     122              :     //       MODIFIED       na
     123              :     //       RE-ENGINEERED  na
     124              : 
     125              :     // PURPOSE OF THIS SUBROUTINE:
     126              :     //  This routine gets the input information for the Microturbine (MT) Generator model.
     127              : 
     128            6 :     bool ErrorsFound(false);
     129              : 
     130            6 :     state.dataIPShortCut->cCurrentModuleObject = "Generator:MicroTurbine";
     131           12 :     state.dataMircoturbElectGen->NumMTGenerators =
     132            6 :         state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, state.dataIPShortCut->cCurrentModuleObject);
     133              : 
     134            6 :     if (state.dataMircoturbElectGen->NumMTGenerators <= 0) {
     135            0 :         ShowSevereError(state, format("No {} equipment specified in input file", state.dataIPShortCut->cCurrentModuleObject));
     136            0 :         ErrorsFound = true;
     137              :     }
     138              : 
     139              :     // ALLOCATE ARRAYS
     140            6 :     state.dataMircoturbElectGen->MTGenerator.allocate(state.dataMircoturbElectGen->NumMTGenerators);
     141              : 
     142              :     // LOAD ARRAYS WITH MICROTURBINE GENERATOR DATA
     143           12 :     for (int GeneratorNum = 1; GeneratorNum <= state.dataMircoturbElectGen->NumMTGenerators; ++GeneratorNum) {
     144              :         int NumAlphas;
     145              :         int NumNums;
     146              :         int IOStat;
     147            6 :         Array1D<Real64> NumArray(19);
     148            6 :         Array1D_string AlphArray(20);
     149           18 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     150            6 :                                                                  state.dataIPShortCut->cCurrentModuleObject,
     151              :                                                                  GeneratorNum,
     152              :                                                                  AlphArray,
     153              :                                                                  NumAlphas,
     154              :                                                                  NumArray,
     155              :                                                                  NumNums,
     156              :                                                                  IOStat,
     157            6 :                                                                  state.dataIPShortCut->lNumericFieldBlanks,
     158            6 :                                                                  state.dataIPShortCut->lAlphaFieldBlanks,
     159            6 :                                                                  state.dataIPShortCut->cAlphaFieldNames,
     160            6 :                                                                  state.dataIPShortCut->cNumericFieldNames);
     161            6 :         Util::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), state.dataIPShortCut->cCurrentModuleObject, ErrorsFound);
     162            6 :         state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name = AlphArray(1);
     163              : 
     164            6 :         state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecPowerOutput = NumArray(1);
     165            6 :         if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecPowerOutput <= 0.0) {
     166            0 :             ShowSevereError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(1), NumArray(1)));
     167            0 :             ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
     168            0 :             ShowContinueError(state, format("{} must be greater than 0.", state.dataIPShortCut->cNumericFieldNames(1)));
     169            0 :             ErrorsFound = true;
     170              :         }
     171              : 
     172            6 :         state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MinElecPowerOutput = NumArray(2);
     173            6 :         state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MaxElecPowerOutput = NumArray(3);
     174              : 
     175            6 :         if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MinElecPowerOutput < 0.0) {
     176            0 :             ShowSevereError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(2), NumArray(2)));
     177            0 :             ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
     178            0 :             ShowContinueError(state, format("{} must be greater than 0.", state.dataIPShortCut->cNumericFieldNames(2)));
     179            0 :             ErrorsFound = true;
     180              :         }
     181              : 
     182            6 :         if (state.dataIPShortCut->lNumericFieldBlanks(3)) {
     183            0 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MaxElecPowerOutput =
     184            0 :                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecPowerOutput;
     185              :         } else {
     186            6 :             if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MaxElecPowerOutput <= 0.0) {
     187            0 :                 ShowSevereError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(3), NumArray(3)));
     188            0 :                 ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
     189            0 :                 ShowContinueError(state, format("{} must be greater than 0.", state.dataIPShortCut->cNumericFieldNames(3)));
     190            0 :                 ErrorsFound = true;
     191              :             }
     192              :         }
     193              : 
     194            6 :         if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MinElecPowerOutput >=
     195            6 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MaxElecPowerOutput) {
     196            0 :             ShowSevereError(
     197            0 :                 state, format("{}= {}", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
     198            0 :             ShowContinueError(state,
     199            0 :                               format("{} [{:.2R}] > {} [{:.2R}]",
     200            0 :                                      state.dataIPShortCut->cNumericFieldNames(2),
     201              :                                      NumArray(2),
     202            0 :                                      state.dataIPShortCut->cNumericFieldNames(3),
     203              :                                      NumArray(3)));
     204            0 :             ShowContinueError(state, "Minimum Full Load Electrical Power Output must be less than or equal");
     205            0 :             ShowContinueError(state, "to Maximum Full Load Electrical Power Output.");
     206            0 :             ErrorsFound = true;
     207              :         }
     208              : 
     209            6 :         if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecPowerOutput >
     210           12 :                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MaxElecPowerOutput ||
     211            6 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecPowerOutput <
     212            6 :                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MinElecPowerOutput) {
     213            0 :             ShowSevereError(
     214            0 :                 state, format("{}= {}", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
     215            0 :             ShowContinueError(state,
     216            0 :                               format("{} must be >= {}", state.dataIPShortCut->cNumericFieldNames(1), state.dataIPShortCut->cNumericFieldNames(2)));
     217            0 :             ShowContinueError(state,
     218            0 :                               format("{} must be <= {}", state.dataIPShortCut->cNumericFieldNames(1), state.dataIPShortCut->cNumericFieldNames(3)));
     219            0 :             ShowContinueError(state, format("{} = {:.2R}", state.dataIPShortCut->cNumericFieldNames(1), NumArray(1)));
     220            0 :             ShowContinueError(state, format("{} = {:.2R}", state.dataIPShortCut->cNumericFieldNames(2), NumArray(2)));
     221            0 :             ShowContinueError(state, format("{} = {:.2R}", state.dataIPShortCut->cNumericFieldNames(3), NumArray(3)));
     222            0 :             ErrorsFound = true;
     223              :         }
     224              : 
     225            6 :         state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecEfficiencyLHV = NumArray(4);
     226              : 
     227            6 :         if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecEfficiencyLHV <= 0.0) {
     228            0 :             ShowSevereError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(4), NumArray(4)));
     229            0 :             ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
     230            0 :             ShowContinueError(state, format("{} must be greater than 0.", state.dataIPShortCut->cNumericFieldNames(4)));
     231            0 :             ErrorsFound = true;
     232              :         }
     233              : 
     234            6 :         state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletTemp = NumArray(5);
     235            6 :         state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletHumRat = NumArray(6);
     236            6 :         state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElevation = NumArray(7);
     237              : 
     238            6 :         if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletHumRat <= 0.0) {
     239            0 :             ShowSevereError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(6), NumArray(6)));
     240            0 :             ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
     241            0 :             ShowContinueError(state, format("{} must be greater than 0.", state.dataIPShortCut->cNumericFieldNames(6)));
     242            0 :             ErrorsFound = true;
     243              :         } else {
     244              :             // Reference barometric pressure, adjusted for reference elevation (Pa)
     245              :             Real64 RefBaroPressure =
     246            6 :                 101325.0 * std::pow(1.0 - 2.25577e-05 * state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElevation, 5.2559);
     247            6 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletDensity =
     248           18 :                 Psychrometrics::PsyRhoAirFnPbTdbW(state,
     249              :                                                   RefBaroPressure,
     250            6 :                                                   state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletTemp,
     251            6 :                                                   state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletHumRat);
     252              :         }
     253              : 
     254            6 :         state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ElecPowFTempElevCurveNum =
     255            6 :             Curve::GetCurveIndex(state, AlphArray(2)); // Convert curve name to number
     256            6 :         if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ElecPowFTempElevCurveNum == 0) {
     257            0 :             ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(2), AlphArray(2)));
     258            0 :             ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
     259            0 :             ErrorsFound = true;
     260              :         } else {
     261              :             // Verify curve object, only legal type is BiQuadratic
     262              : 
     263            6 :             if (!ErrorsFound) {
     264              :                 // Check electrical power output at reference combustion inlet temp and elevation
     265              :                 // Output of Electrical Power Output Modifier Curve (function of temp and elev)
     266           24 :                 Real64 ElectOutFTempElevOutput = Curve::CurveValue(state,
     267            6 :                                                                    state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ElecPowFTempElevCurveNum,
     268            6 :                                                                    state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletTemp,
     269            6 :                                                                    state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElevation);
     270            6 :                 if (std::abs(ElectOutFTempElevOutput - 1.0) > 0.1) {
     271            0 :                     ShowWarningError(
     272              :                         state,
     273            0 :                         format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
     274            0 :                     ShowContinueError(state, format("{} = {}", state.dataIPShortCut->cAlphaFieldNames(2), AlphArray(2)));
     275            0 :                     ShowContinueError(state, "... Curve output at reference conditions should equal 1 (+-10%).");
     276            0 :                     ShowContinueError(state,
     277            0 :                                       format("...Reference combustion air inlet temperature = {:.4T} C",
     278            0 :                                              state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletTemp));
     279            0 :                     ShowContinueError(state,
     280            0 :                                       format("...Reference elevation                        = {:.4T} m",
     281            0 :                                              state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElevation));
     282            0 :                     ShowContinueError(state, format("...Curve output                               = {:.4T}", ElectOutFTempElevOutput));
     283              :                 }
     284              :             }
     285              :         }
     286              : 
     287            6 :         state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ElecEffFTempCurveNum =
     288            6 :             Curve::GetCurveIndex(state, AlphArray(3)); // Convert curve name to number
     289            6 :         if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ElecEffFTempCurveNum == 0) {
     290            0 :             ShowSevereError(
     291            0 :                 state, format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
     292            0 :             ShowContinueError(state, format("{} not found = {}", state.dataIPShortCut->cAlphaFieldNames(3), AlphArray(3)));
     293            0 :             ErrorsFound = true;
     294              :         } else {
     295              :             // Verify curve object, only legal types are Quadratic and Cubic
     296              : 
     297            6 :             if (!ErrorsFound) {
     298              :                 // Check electrical efficiency at reference combustion inlet temp
     299              :                 // Output of Electrical Efficiency Modifier Curve (function of temp)
     300           18 :                 Real64 ElecEfficFTempOutput = Curve::CurveValue(state,
     301            6 :                                                                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ElecEffFTempCurveNum,
     302            6 :                                                                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletTemp);
     303            6 :                 if (std::abs(ElecEfficFTempOutput - 1.0) > 0.1) {
     304            0 :                     ShowWarningError(
     305              :                         state,
     306            0 :                         format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
     307            0 :                     ShowContinueError(state, format("{} = {}", state.dataIPShortCut->cAlphaFieldNames(3), AlphArray(3)));
     308            0 :                     ShowContinueError(state, "... Curve output at reference condition should equal 1 (+-10%).");
     309            0 :                     ShowContinueError(state,
     310            0 :                                       format("... Reference combustion air inlet temperature = {:.4T} C",
     311            0 :                                              state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletTemp));
     312            0 :                     ShowContinueError(state, format("... Curve output                               = {:.4T}", ElecEfficFTempOutput));
     313              :                 }
     314              :             }
     315              :         }
     316              : 
     317            6 :         state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ElecEffFPLRCurveNum =
     318            6 :             Curve::GetCurveIndex(state, AlphArray(4)); // Convert curve name to number
     319            6 :         if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ElecEffFPLRCurveNum == 0) {
     320            0 :             ShowSevereError(
     321            0 :                 state, format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
     322            0 :             ShowContinueError(state, format("{} not found = {}", state.dataIPShortCut->cAlphaFieldNames(4), AlphArray(4)));
     323            0 :             ErrorsFound = true;
     324              :         } else {
     325              :             // Verify curve object, only legal types are Quadratic and Cubic
     326              : 
     327            6 :             if (!ErrorsFound) {
     328              :                 // Check electrical efficiency at PLR = 1
     329              :                 // Output of Electrical Efficiency Modifier Curve (function of PLR)
     330              :                 Real64 ElecEfficFPLROutput =
     331            6 :                     Curve::CurveValue(state, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ElecEffFPLRCurveNum, 1.0);
     332            6 :                 if (std::abs(ElecEfficFPLROutput - 1.0) > 0.1) {
     333            0 :                     ShowWarningError(
     334              :                         state,
     335            0 :                         format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
     336            0 :                     ShowContinueError(state, format("{} = {}", state.dataIPShortCut->cAlphaFieldNames(4), AlphArray(4)));
     337            0 :                     ShowContinueError(state, "... Curve output at a part-load ratio of 1 should equal 1 (+-10%).");
     338            0 :                     ShowContinueError(state, format("... Curve output = {:.4T}", ElecEfficFPLROutput));
     339              :                 }
     340              : 
     341            6 :                 Real64 Var1Min(0.0);
     342            6 :                 Real64 Var1Max(0.0);
     343            6 :                 Curve::GetCurveMinMaxValues(state, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ElecEffFPLRCurveNum, Var1Min, Var1Max);
     344            6 :                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MinPartLoadRat = Var1Min;
     345            6 :                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MaxPartLoadRat = Var1Max;
     346              :             }
     347              :         }
     348              : 
     349              :         // Validate fuel type input
     350            6 :         state.dataMircoturbElectGen->MTGenerator(GeneratorNum).FuelType =
     351            6 :             static_cast<Constant::eFuel>(getEnumValue(Constant::eFuelNamesUC, AlphArray(5)));
     352            6 :         if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).FuelType == Constant::eFuel::Invalid) {
     353            0 :             ShowSevereError(
     354            0 :                 state, format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
     355            0 :             ShowContinueError(state, format("Invalid {}  = {}", state.dataIPShortCut->cAlphaFieldNames(5), AlphArray(5)));
     356            0 :             ErrorsFound = true;
     357              :         }
     358              : 
     359            6 :         state.dataMircoturbElectGen->MTGenerator(GeneratorNum).FuelHigherHeatingValue = NumArray(8);
     360            6 :         state.dataMircoturbElectGen->MTGenerator(GeneratorNum).FuelLowerHeatingValue = NumArray(9);
     361              : 
     362            6 :         if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).FuelLowerHeatingValue <= 0.0) {
     363            0 :             ShowSevereError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(9), NumArray(9)));
     364            0 :             ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
     365            0 :             ShowContinueError(state, format("{} must be greater than 0.", state.dataIPShortCut->cNumericFieldNames(9)));
     366            0 :             ErrorsFound = true;
     367              :         }
     368              : 
     369            6 :         if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).FuelHigherHeatingValue <= 0.0) {
     370            0 :             ShowSevereError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(8), NumArray(8)));
     371            0 :             ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
     372            0 :             ShowContinueError(state, format("{} must be greater than 0.", state.dataIPShortCut->cNumericFieldNames(8)));
     373            0 :             ErrorsFound = true;
     374              :         }
     375              : 
     376            6 :         if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).FuelLowerHeatingValue >
     377            6 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).FuelHigherHeatingValue) {
     378            0 :             ShowSevereError(
     379            0 :                 state, format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
     380            0 :             ShowContinueError(
     381              :                 state,
     382            0 :                 format("{} must be greater than the {}", state.dataIPShortCut->cNumericFieldNames(8), state.dataIPShortCut->cNumericFieldNames(9)));
     383            0 :             ShowContinueError(state, format("{}={:.2R}", state.dataIPShortCut->cNumericFieldNames(8), NumArray(8)));
     384            0 :             ShowContinueError(state, format("{}={:.2R}", state.dataIPShortCut->cNumericFieldNames(9), NumArray(9)));
     385            0 :             ErrorsFound = true;
     386              :         }
     387              : 
     388            6 :         state.dataMircoturbElectGen->MTGenerator(GeneratorNum).StandbyPower = NumArray(10);
     389            6 :         if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).StandbyPower < 0.0) {
     390            0 :             ShowWarningError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(10), NumArray(10)));
     391            0 :             ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
     392            0 :             ShowContinueError(state, format("{} must be greater than 0.", state.dataIPShortCut->cNumericFieldNames(10)));
     393            0 :             ShowContinueError(state, "Resetting to 0 and the simulation continues.");
     394            0 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).StandbyPower = 0.0;
     395              :         }
     396              : 
     397            6 :         state.dataMircoturbElectGen->MTGenerator(GeneratorNum).AncillaryPower = NumArray(11);
     398            6 :         if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).AncillaryPower < 0.0) {
     399            0 :             ShowWarningError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(11), NumArray(11)));
     400            0 :             ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
     401            0 :             ShowContinueError(state, format("{} must be greater than 0.", state.dataIPShortCut->cNumericFieldNames(11)));
     402            0 :             ShowContinueError(state, "Resetting to 0 and the simulation continues.");
     403            0 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).AncillaryPower = 0.0;
     404              :         }
     405              : 
     406            6 :         state.dataMircoturbElectGen->MTGenerator(GeneratorNum).AncillaryPowerFuelCurveNum =
     407            6 :             Curve::GetCurveIndex(state, AlphArray(6)); // Convert curve name to number
     408              :         //   If blank, then the calc routine assumes modifier curve value = 1 for entire simulation
     409            6 :         if (!state.dataIPShortCut->lAlphaFieldBlanks(6) && state.dataMircoturbElectGen->MTGenerator(GeneratorNum).AncillaryPowerFuelCurveNum == 0) {
     410            0 :             ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(6), AlphArray(6)));
     411            0 :             ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
     412            0 :             ErrorsFound = true;
     413            6 :         } else if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).AncillaryPowerFuelCurveNum > 0) {
     414              :             // Verify curve object, only legal type is Quadratic
     415              : 
     416            0 :             if (!ErrorsFound) {
     417              :                 // Fuel mass flow rate at reference conditions (kg/s)
     418            0 :                 Real64 RefFuelUseMdot = (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecPowerOutput /
     419            0 :                                          state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecEfficiencyLHV) /
     420            0 :                                         (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).FuelLowerHeatingValue * 1000.0);
     421              :                 // Output of Ancillary Power Modifier Curve (function of temps and fuel flow)
     422              :                 Real64 AncillaryPowerOutput =
     423            0 :                     Curve::CurveValue(state, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).AncillaryPowerFuelCurveNum, RefFuelUseMdot);
     424            0 :                 if (std::abs(AncillaryPowerOutput - 1.0) > 0.1) {
     425            0 :                     ShowWarningError(
     426              :                         state,
     427            0 :                         format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
     428            0 :                     ShowContinueError(state, format("{} = {}", state.dataIPShortCut->cAlphaFieldNames(6), AlphArray(6)));
     429            0 :                     ShowContinueError(state, "... Curve output at reference conditions should equal 1 (+-10%).");
     430            0 :                     ShowContinueError(state,
     431            0 :                                       format("... Reference Electrical Power Output           = {:.2T} W",
     432            0 :                                              state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecPowerOutput));
     433            0 :                     ShowContinueError(state,
     434            0 :                                       format("... Reference Electrical Efficiency (LHV basis) = {:.4T}",
     435            0 :                                              state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecEfficiencyLHV));
     436            0 :                     ShowContinueError(state,
     437            0 :                                       format("... Fuel Lower Heating Value                    = {:.2T} kJ/kg",
     438            0 :                                              state.dataMircoturbElectGen->MTGenerator(GeneratorNum).FuelLowerHeatingValue));
     439            0 :                     ShowContinueError(state, format("... Calculated fuel flow                        = {:.4T} kg/s", RefFuelUseMdot));
     440            0 :                     ShowContinueError(state, format("... Curve output                                = {:.4T}", AncillaryPowerOutput));
     441              :                 }
     442              :             }
     443              :         }
     444              : 
     445            6 :         if (!state.dataIPShortCut->lAlphaFieldBlanks(7)) {
     446            2 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecInletNodeNum =
     447            6 :                 NodeInputManager::GetOnlySingleNode(state,
     448            2 :                                                     AlphArray(7),
     449              :                                                     ErrorsFound,
     450              :                                                     DataLoopNode::ConnectionObjectType::GeneratorMicroTurbine,
     451            2 :                                                     state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name,
     452              :                                                     DataLoopNode::NodeFluidType::Water,
     453              :                                                     DataLoopNode::ConnectionType::Inlet,
     454              :                                                     NodeInputManager::CompFluidStream::Primary,
     455              :                                                     DataLoopNode::ObjectIsNotParent);
     456              :         }
     457              : 
     458            6 :         if (!state.dataIPShortCut->lAlphaFieldBlanks(8)) {
     459            2 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecOutletNodeNum =
     460            6 :                 NodeInputManager::GetOnlySingleNode(state,
     461            2 :                                                     AlphArray(8),
     462              :                                                     ErrorsFound,
     463              :                                                     DataLoopNode::ConnectionObjectType::GeneratorMicroTurbine,
     464            2 :                                                     state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name,
     465              :                                                     DataLoopNode::NodeFluidType::Water,
     466              :                                                     DataLoopNode::ConnectionType::Outlet,
     467              :                                                     NodeInputManager::CompFluidStream::Primary,
     468              :                                                     DataLoopNode::ObjectIsNotParent);
     469              :         }
     470              : 
     471            8 :         if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecInletNodeNum > 0 &&
     472            2 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecOutletNodeNum > 0) {
     473            6 :             BranchNodeConnections::TestCompSet(state,
     474            2 :                                                state.dataIPShortCut->cCurrentModuleObject,
     475            2 :                                                state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name,
     476            2 :                                                AlphArray(7),
     477            2 :                                                AlphArray(8),
     478              :                                                "Heat Recovery Nodes");
     479              :         }
     480              : 
     481            6 :         if ((state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecOutletNodeNum > 0 &&
     482           12 :              state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecInletNodeNum == 0) ||
     483            6 :             (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecOutletNodeNum == 0 &&
     484            4 :              state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecInletNodeNum > 0)) {
     485            0 :             ShowSevereError(
     486            0 :                 state, format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
     487            0 :             ShowContinueError(state, "... If one Heat Recovery Water Node Name is specified, then both the Inlet and Outlet Heat Recovery");
     488            0 :             ShowContinueError(state, "... Water Node Names must be specified. Only one water node is being specified for this generator.");
     489            0 :             ErrorsFound = true;
     490              :         }
     491              : 
     492              :         //   Heat recovery to water input fields only valid if water nodes are defined
     493            8 :         if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecInletNodeNum != 0 &&
     494            2 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecOutletNodeNum != 0) {
     495              : 
     496            2 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecActive = true;
     497              : 
     498            2 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefThermalEffLHV = NumArray(12);
     499            2 :             if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefThermalEffLHV < 0.0) {
     500            0 :                 ShowWarningError(
     501              :                     state,
     502            0 :                     format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
     503            0 :                 ShowContinueError(state, format("{} must be >= 0.", state.dataIPShortCut->cNumericFieldNames(12)));
     504            0 :                 ShowContinueError(state, "Resetting to 0 and the simulation continues.");
     505            0 :                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefThermalEffLHV = 0.0;
     506              :             }
     507              : 
     508              :             // Next store thermal power output ranges using nominal thermal to electrical efficiency ratio and electrical power data
     509            2 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefThermalPowerOutput =
     510            2 :                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecPowerOutput *
     511            2 :                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefThermalEffLHV /
     512            2 :                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecEfficiencyLHV;
     513            2 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MinThermalPowerOutput =
     514            2 :                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MinElecPowerOutput *
     515            2 :                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefThermalEffLHV /
     516            2 :                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecEfficiencyLHV;
     517            2 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MaxThermalPowerOutput =
     518            2 :                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MaxElecPowerOutput *
     519            2 :                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefThermalEffLHV /
     520            2 :                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecEfficiencyLHV;
     521              : 
     522            2 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefInletWaterTemp = NumArray(13);
     523              : 
     524            2 :             if (Util::SameString(AlphArray(9), "InternalControl")) {
     525            0 :                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).InternalFlowControl =
     526              :                     true; //  A9, \field Heat Recovery Water Flow Operating Mode
     527            0 :                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).PlantFlowControl = false;
     528              :             }
     529            2 :             if ((!(Util::SameString(AlphArray(9), "InternalControl"))) && (!(Util::SameString(AlphArray(9), "PlantControl")))) {
     530            0 :                 ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(9), AlphArray(9)));
     531            0 :                 ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
     532            0 :                 ShowContinueError(state, "Operating Mode must be INTERNAL CONTROL or PLANT CONTROL.");
     533            0 :                 ErrorsFound = true;
     534              :             }
     535              : 
     536            2 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefHeatRecVolFlowRate = NumArray(14);
     537              : 
     538            2 :             if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefHeatRecVolFlowRate <= 0.0) {
     539            0 :                 ShowSevereError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(14), NumArray(14)));
     540            0 :                 ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
     541            0 :                 ShowContinueError(state, format("{} must be greater than 0.", state.dataIPShortCut->cNumericFieldNames(14)));
     542            0 :                 ErrorsFound = true;
     543              :             }
     544              : 
     545            2 :             if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).InternalFlowControl) { // Get Heat Recovery Water Flow Rate Modifier Curve
     546              : 
     547            0 :                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecFlowFTempPowCurveNum = Curve::GetCurveIndex(state, AlphArray(10));
     548            0 :                 if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecFlowFTempPowCurveNum != 0) {
     549              :                     // Verify curve object, only legal type is BiQuadratic
     550              :                 }
     551              : 
     552              :             } // End of IF (MTGenerator(GeneratorNum)%InternalFlowControl) THEN
     553              : 
     554            2 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ThermEffFTempElevCurveNum =
     555            2 :                 Curve::GetCurveIndex(state, AlphArray(11)); // convert curve name to number
     556            2 :             if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ThermEffFTempElevCurveNum != 0) {
     557              :                 // Verify curve object, only legal types are BiQuadratic and BiCubic
     558              : 
     559            2 :                 if (!ErrorsFound) {
     560              :                     // Output of Thermal Efficiency Modifier Curve (function of temp and elevation)
     561              :                     Real64 ThermalEffTempElevOutput =
     562            8 :                         Curve::CurveValue(state,
     563            2 :                                           state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ThermEffFTempElevCurveNum,
     564            2 :                                           state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletTemp,
     565            2 :                                           state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElevation);
     566              : 
     567            2 :                     if (std::abs(ThermalEffTempElevOutput - 1.0) > 0.1) {
     568            0 :                         ShowWarningError(state,
     569            0 :                                          format("{} \"{}\"",
     570            0 :                                                 state.dataIPShortCut->cCurrentModuleObject,
     571            0 :                                                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
     572            0 :                         ShowContinueError(state, format("{} = {}", state.dataIPShortCut->cAlphaFieldNames(11), AlphArray(11)));
     573            0 :                         ShowContinueError(state, "... Curve output at reference conditions should equal 1 (+-10%).");
     574            0 :                         ShowContinueError(state,
     575            0 :                                           format("... Reference combustion air inlet temperature      = {:.4T} C",
     576            0 :                                                  state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletTemp));
     577            0 :                         ShowContinueError(state,
     578            0 :                                           format("... Reference elevation                             = {:.4T} m",
     579            0 :                                                  state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElevation));
     580              :                     }
     581              :                 }
     582              :             }
     583              : 
     584            2 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecRateFPLRCurveNum =
     585            2 :                 Curve::GetCurveIndex(state, AlphArray(12)); // convert curve name to number
     586            2 :             if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecRateFPLRCurveNum != 0) {
     587              :                 // Verify curve object, only legal types are Quadratic or Cubic
     588              : 
     589            2 :                 if (!ErrorsFound) {
     590              :                     // Output of Heat Recovery Rate Modifier Curve (function of PLR)
     591              :                     Real64 HeatRecRateFPLROutput =
     592            2 :                         Curve::CurveValue(state, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecRateFPLRCurveNum, 1.0);
     593              : 
     594            2 :                     if (std::abs(HeatRecRateFPLROutput - 1.0) > 0.1) {
     595            0 :                         ShowWarningError(state,
     596            0 :                                          format("{} \"{}\"",
     597            0 :                                                 state.dataIPShortCut->cCurrentModuleObject,
     598            0 :                                                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
     599            0 :                         ShowContinueError(state, format("{} = {}", state.dataIPShortCut->cAlphaFieldNames(12), AlphArray(12)));
     600            0 :                         ShowContinueError(state, "... Curve output at a part-load ratio of 1 should equal 1 (+-10%).");
     601            0 :                         ShowContinueError(state, format("... Curve output = {:.4T}", HeatRecRateFPLROutput));
     602              :                     }
     603              :                 }
     604              :             }
     605              : 
     606            2 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecRateFTempCurveNum =
     607            2 :                 Curve::GetCurveIndex(state, AlphArray(13)); // convert curve name to number
     608            2 :             if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecRateFTempCurveNum != 0) {
     609              :                 // Verify curve object, only legal type is Quadratic
     610              : 
     611            2 :                 if (!ErrorsFound) {
     612              :                     // Output of Heat Recovery Rate Modifier Curve (function of inlet water temp)
     613            6 :                     Real64 HeatRecRateFTempOutput = Curve::CurveValue(state,
     614            2 :                                                                       state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecRateFTempCurveNum,
     615            2 :                                                                       state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefInletWaterTemp);
     616              : 
     617            2 :                     if (std::abs(HeatRecRateFTempOutput - 1.0) > 0.1) {
     618            0 :                         ShowWarningError(state,
     619            0 :                                          format("{} \"{}\"",
     620            0 :                                                 state.dataIPShortCut->cCurrentModuleObject,
     621            0 :                                                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
     622            0 :                         ShowContinueError(state, format("{} = {}", state.dataIPShortCut->cAlphaFieldNames(13), AlphArray(13)));
     623            0 :                         ShowContinueError(state, "... Curve output at reference condition should equal 1 (+-10%).");
     624            0 :                         ShowContinueError(state,
     625            0 :                                           format("... Reference inlet water temperature temperature      = {:.4T} C",
     626            0 :                                                  state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefInletWaterTemp));
     627            0 :                         ShowContinueError(state, format("... Curve output = {:.4T}", HeatRecRateFTempOutput));
     628              :                     }
     629              :                 }
     630              :             }
     631              : 
     632            2 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecRateFWaterFlowCurveNum = Curve::GetCurveIndex(state, AlphArray(14));
     633            2 :             if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecRateFWaterFlowCurveNum != 0) {
     634              :                 // Verify curve object, only legal type is Quadratic
     635              : 
     636            2 :                 if (!ErrorsFound) {
     637              :                     // Output of Heat Recovery Rate Modifier Curve (function of water flow rate)
     638              :                     Real64 HeatRecRateFFlowOutput =
     639            6 :                         Curve::CurveValue(state,
     640            2 :                                           state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecRateFWaterFlowCurveNum,
     641            2 :                                           state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefHeatRecVolFlowRate);
     642              : 
     643            2 :                     if (std::abs(HeatRecRateFFlowOutput - 1.0) > 0.1) {
     644            0 :                         ShowWarningError(state,
     645            0 :                                          format("{} \"{}\"",
     646            0 :                                                 state.dataIPShortCut->cCurrentModuleObject,
     647            0 :                                                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
     648            0 :                         ShowContinueError(state, format("{} = {}", state.dataIPShortCut->cAlphaFieldNames(14), AlphArray(14)));
     649            0 :                         ShowContinueError(state, "... Curve output at reference condition should equal 1 (+-10%).");
     650            0 :                         ShowContinueError(state,
     651            0 :                                           format("... Reference Heat Recovery Water Flow Rate      = {:.4T} m3/s",
     652            0 :                                                  state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefHeatRecVolFlowRate));
     653            0 :                         ShowContinueError(state, format("... Curve output = {:.4T}", HeatRecRateFFlowOutput));
     654              :                     }
     655              :                 }
     656              :             }
     657              : 
     658            2 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMinVolFlowRate = NumArray(15);
     659            2 :             if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMinVolFlowRate < 0.0) {
     660            0 :                 ShowWarningError(
     661              :                     state,
     662            0 :                     format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
     663            0 :                 ShowContinueError(state, format("{} must be >= 0.", state.dataIPShortCut->cNumericFieldNames(15)));
     664            0 :                 ShowContinueError(state, "Resetting to 0 and the simulation continues.");
     665            0 :                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMinVolFlowRate = 0.0;
     666              :             }
     667              : 
     668            2 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMaxVolFlowRate = NumArray(16);
     669            2 :             if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMaxVolFlowRate < 0.0) {
     670            0 :                 ShowWarningError(
     671              :                     state,
     672            0 :                     format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
     673            0 :                 ShowContinueError(state, format("{} must be >= 0.", state.dataIPShortCut->cNumericFieldNames(16)));
     674            0 :                 ShowContinueError(state, "Resetting to 0 and the simulation continues.");
     675            0 :                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMaxVolFlowRate = 0.0;
     676              :             }
     677              : 
     678            2 :             if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMaxVolFlowRate <
     679            2 :                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMinVolFlowRate) {
     680            0 :                 ShowWarningError(
     681              :                     state,
     682            0 :                     format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
     683            0 :                 ShowContinueError(
     684            0 :                     state, format("{} must be >= {}", state.dataIPShortCut->cNumericFieldNames(16), state.dataIPShortCut->cNumericFieldNames(15)));
     685            0 :                 ShowContinueError(state,
     686            0 :                                   format("Resetting {} = {} and the simulation continues.",
     687            0 :                                          state.dataIPShortCut->cNumericFieldNames(16),
     688            0 :                                          state.dataIPShortCut->cNumericFieldNames(15)));
     689            0 :                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMaxVolFlowRate =
     690            0 :                     state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMinVolFlowRate;
     691              :             }
     692              : 
     693              :             //     Check if reference heat recovery water flow rate is below the minimum flow rate
     694            2 :             if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefHeatRecVolFlowRate <
     695            2 :                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMinVolFlowRate) {
     696            0 :                 ShowWarningError(
     697              :                     state,
     698            0 :                     format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
     699            0 :                 ShowContinueError(
     700            0 :                     state, format("{} must be >= {}", state.dataIPShortCut->cNumericFieldNames(14), state.dataIPShortCut->cNumericFieldNames(15)));
     701            0 :                 ShowContinueError(state,
     702            0 :                                   format("Resetting {} = {} and the simulation continues.",
     703            0 :                                          state.dataIPShortCut->cNumericFieldNames(14),
     704            0 :                                          state.dataIPShortCut->cNumericFieldNames(15)));
     705            0 :                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefHeatRecVolFlowRate =
     706            0 :                     state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMinVolFlowRate;
     707              :             }
     708              : 
     709              :             //     Check if reference heat recovery water flow rate is above the maximum flow rate
     710            2 :             if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefHeatRecVolFlowRate >
     711            2 :                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMaxVolFlowRate) {
     712            0 :                 ShowWarningError(
     713              :                     state,
     714            0 :                     format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
     715            0 :                 ShowContinueError(
     716            0 :                     state, format("{} must be <= {}", state.dataIPShortCut->cNumericFieldNames(14), state.dataIPShortCut->cNumericFieldNames(16)));
     717            0 :                 ShowContinueError(state,
     718            0 :                                   format("Resetting {} = {} and the simulation continues.",
     719            0 :                                          state.dataIPShortCut->cNumericFieldNames(14),
     720            0 :                                          state.dataIPShortCut->cNumericFieldNames(16)));
     721            0 :                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefHeatRecVolFlowRate =
     722            0 :                     state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMaxVolFlowRate;
     723              :             }
     724              : 
     725            4 :             PlantUtilities::RegisterPlantCompDesignFlow(state,
     726            2 :                                                         state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecInletNodeNum,
     727            2 :                                                         state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMaxVolFlowRate);
     728              : 
     729            2 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMaxWaterTemp = NumArray(17);
     730              : 
     731              :         } // End of 'IF (MTGenerator(GeneratorNum)%HeatRecInletNodeNum .NE. 0 .AND. &
     732              :         //             MTGenerator(GeneratorNum)%HeatRecOutletNodeNum .NE. 0) THEN'
     733              : 
     734            6 :         if (!state.dataIPShortCut->lAlphaFieldBlanks(15)) {
     735            3 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).CombustionAirInletNodeNum =
     736            9 :                 NodeInputManager::GetOnlySingleNode(state,
     737            3 :                                                     AlphArray(15),
     738              :                                                     ErrorsFound,
     739              :                                                     DataLoopNode::ConnectionObjectType::GeneratorMicroTurbine,
     740            3 :                                                     AlphArray(1),
     741              :                                                     DataLoopNode::NodeFluidType::Air,
     742              :                                                     DataLoopNode::ConnectionType::Inlet,
     743              :                                                     NodeInputManager::CompFluidStream::Secondary,
     744              :                                                     DataLoopNode::ObjectIsNotParent);
     745              :         }
     746              : 
     747              :         //    Combustion air inlet node must be an outside air node
     748            9 :         if (!state.dataIPShortCut->lAlphaFieldBlanks(15) &&
     749            3 :             !OutAirNodeManager::CheckOutAirNodeNumber(state, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).CombustionAirInletNodeNum)) {
     750            0 :             ShowSevereError(
     751            0 :                 state, format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
     752            0 :             ShowContinueError(state, format("{} is not a valid Outdoor Air Node = {}", state.dataIPShortCut->cAlphaFieldNames(15), AlphArray(15)));
     753            0 :             ShowContinueError(state, "it does not appear in an OutdoorAir:NodeList or as an OutdoorAir:Node.");
     754            0 :             ErrorsFound = true;
     755              :         }
     756              : 
     757            6 :         if (!state.dataIPShortCut->lAlphaFieldBlanks(16)) {
     758            3 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).CombustionAirOutletNodeNum =
     759            9 :                 NodeInputManager::GetOnlySingleNode(state,
     760            3 :                                                     AlphArray(16),
     761              :                                                     ErrorsFound,
     762              :                                                     DataLoopNode::ConnectionObjectType::GeneratorMicroTurbine,
     763            3 :                                                     AlphArray(1),
     764              :                                                     DataLoopNode::NodeFluidType::Air,
     765              :                                                     DataLoopNode::ConnectionType::Outlet,
     766              :                                                     NodeInputManager::CompFluidStream::Secondary,
     767              :                                                     DataLoopNode::ObjectIsNotParent);
     768              :         }
     769              : 
     770            9 :         if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).CombustionAirOutletNodeNum > 0 &&
     771            3 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).CombustionAirInletNodeNum == 0) {
     772            0 :             ShowSevereError(
     773            0 :                 state, format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
     774            0 :             ShowContinueError(state,
     775            0 :                               format("A {} must be specified when a {} is specified.",
     776            0 :                                      state.dataIPShortCut->cAlphaFieldNames(15),
     777            0 :                                      state.dataIPShortCut->cAlphaFieldNames(16)));
     778            0 :             ErrorsFound = true;
     779              :         }
     780              : 
     781              :         //   Get other exhaust air inputs only if combustion air inlet and outlet nodes are valid
     782            9 :         if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).CombustionAirOutletNodeNum > 0 &&
     783            3 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).CombustionAirInletNodeNum > 0) {
     784              : 
     785            3 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhAirCalcsActive = true;
     786            3 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefExhaustAirMassFlowRate = NumArray(18);
     787            3 :             if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefExhaustAirMassFlowRate <= 0.0 &&
     788            0 :                 !state.dataIPShortCut->lNumericFieldBlanks(18)) {
     789            0 :                 ShowSevereError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(18), NumArray(18)));
     790            0 :                 ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
     791            0 :                 ShowContinueError(state, format("{} must be greater than 0.", state.dataIPShortCut->cNumericFieldNames(18)));
     792            0 :                 ErrorsFound = true;
     793              :             }
     794              : 
     795            3 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhFlowFTempCurveNum = Curve::GetCurveIndex(state, AlphArray(17));
     796            3 :             if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhFlowFTempCurveNum != 0) {
     797              :                 // Verify curve object, only legal types are Quadratic and Cubic
     798              : 
     799            3 :                 if (!ErrorsFound) {
     800              :                     // Output of Exhaust Air Flow Modifier Curve (function of inlet air temp)
     801            9 :                     Real64 ExhFlowFTempOutput = Curve::CurveValue(state,
     802            3 :                                                                   state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhFlowFTempCurveNum,
     803            3 :                                                                   state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletTemp);
     804              : 
     805            3 :                     if (std::abs(ExhFlowFTempOutput - 1.0) > 0.1) {
     806            0 :                         ShowWarningError(state,
     807            0 :                                          format("{} \"{}\"",
     808            0 :                                                 state.dataIPShortCut->cCurrentModuleObject,
     809            0 :                                                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
     810            0 :                         ShowContinueError(state, format("{} = {}", state.dataIPShortCut->cAlphaFieldNames(17), AlphArray(17)));
     811            0 :                         ShowContinueError(state, "... Curve output at reference condition should equal 1 (+-10%).");
     812            0 :                         ShowContinueError(state,
     813            0 :                                           format("... Reference combustion air inlet temperature      = {:.4T} C",
     814            0 :                                                  state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletTemp));
     815            0 :                         ShowContinueError(state, format("... Curve output = {:.4T}", ExhFlowFTempOutput));
     816              :                     }
     817              :                 }
     818              :             }
     819              : 
     820            3 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhFlowFPLRCurveNum =
     821            3 :                 Curve::GetCurveIndex(state, AlphArray(18)); // convert curve name to number
     822            3 :             if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhFlowFPLRCurveNum != 0) {
     823              :                 // Verify curve object, legal types are Quadratic or Cubic
     824              : 
     825            3 :                 if (!ErrorsFound) {
     826              :                     // Output of Exhaust Air Flow Modifier Curve (function of PLR)
     827              :                     Real64 ExhFlowFPLROutput =
     828            3 :                         Curve::CurveValue(state, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhFlowFPLRCurveNum, 1.0);
     829              : 
     830            3 :                     if (std::abs(ExhFlowFPLROutput - 1.0) > 0.1) {
     831            0 :                         ShowWarningError(state,
     832            0 :                                          format("{} \"{}\"",
     833            0 :                                                 state.dataIPShortCut->cCurrentModuleObject,
     834            0 :                                                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
     835            0 :                         ShowContinueError(state, format("{} = {}", state.dataIPShortCut->cAlphaFieldNames(18), AlphArray(18)));
     836            0 :                         ShowContinueError(state, "... Curve output at a part-load ratio of 1 should equal 1 (+-10%).");
     837            0 :                         ShowContinueError(state, format("... Curve output = {:.4T}", ExhFlowFPLROutput));
     838              :                     }
     839              :                 }
     840              :             }
     841              : 
     842            3 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).NomExhAirOutletTemp = NumArray(19);
     843              : 
     844            3 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhAirTempFTempCurveNum = Curve::GetCurveIndex(state, AlphArray(19));
     845            3 :             if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhAirTempFTempCurveNum != 0) {
     846              :                 // Verify curve object, only legal types are Quadratic and Cubic
     847              : 
     848            3 :                 if (!ErrorsFound) {
     849              :                     // Output of Exhaust Air Temperature Modifier Curve (function of inlet air temp)
     850            9 :                     Real64 ExhAirTempFTempOutput = Curve::CurveValue(state,
     851            3 :                                                                      state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhAirTempFTempCurveNum,
     852            3 :                                                                      state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletTemp);
     853              : 
     854            3 :                     if (std::abs(ExhAirTempFTempOutput - 1.0) > 0.1) {
     855            0 :                         ShowWarningError(state,
     856            0 :                                          format("{} \"{}\"",
     857            0 :                                                 state.dataIPShortCut->cCurrentModuleObject,
     858            0 :                                                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
     859            0 :                         ShowContinueError(state, format("{} = {}", state.dataIPShortCut->cAlphaFieldNames(19), AlphArray(19)));
     860            0 :                         ShowContinueError(state, "... Curve output at reference condition should equal 1 (+-10%).");
     861            0 :                         ShowContinueError(state,
     862            0 :                                           format("... Reference combustion air inlet temperature      = {:.4T} C",
     863            0 :                                                  state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletTemp));
     864            0 :                         ShowContinueError(state, format("... Curve output = {:.4T}", ExhAirTempFTempOutput));
     865              :                     }
     866              :                 }
     867              :             }
     868              : 
     869            3 :             state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhAirTempFPLRCurveNum =
     870            3 :                 Curve::GetCurveIndex(state, AlphArray(20)); // convert curve name to number
     871            3 :             if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhAirTempFPLRCurveNum != 0) {
     872              :                 // Verify curve object, legal types are Quadratic or Cubic
     873              : 
     874            3 :                 if (!ErrorsFound) {
     875              :                     // Output of Exhaust Air Temperature Modifier Curve (function of PLR)
     876              :                     Real64 ExhOutAirTempFPLROutput =
     877            3 :                         Curve::CurveValue(state, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhAirTempFPLRCurveNum, 1.0);
     878              : 
     879            3 :                     if (std::abs(ExhOutAirTempFPLROutput - 1.0) > 0.1) {
     880            0 :                         ShowWarningError(state,
     881            0 :                                          format("{} \"{}\"",
     882            0 :                                                 state.dataIPShortCut->cCurrentModuleObject,
     883            0 :                                                 state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
     884            0 :                         ShowContinueError(state, format("{} = {}", state.dataIPShortCut->cAlphaFieldNames(20), AlphArray(20)));
     885            0 :                         ShowContinueError(state, "... Curve output at a part-load ratio of 1 should equal 1 (+-10%).");
     886            0 :                         ShowContinueError(state, format("... Curve output = {:.4T}", ExhOutAirTempFPLROutput));
     887              :                     }
     888              :                 }
     889              :             }
     890              : 
     891              :         } // End of '    IF (MTGenerator(GeneratorNum)%CombustionAirOutletNodeNum .GT. 0 .AND. &
     892              :           //                 MTGenerator(GeneratorNum)%CombustionAirInletNodeNum .GT. 0) THEN
     893            6 :     }
     894              : 
     895            6 :     if (ErrorsFound) {
     896            0 :         ShowFatalError(state, format("Errors found in processing input for {}", state.dataIPShortCut->cCurrentModuleObject));
     897              :     }
     898            6 : }
     899              : 
     900            6 : void MTGeneratorSpecs::setupOutputVars(EnergyPlusData &state)
     901              : {
     902            6 :     std::string_view const sFuelType = Constant::eFuelNames[static_cast<int>(this->FuelType)];
     903           12 :     SetupOutputVariable(state,
     904              :                         "Generator Produced AC Electricity Rate",
     905              :                         Constant::Units::W,
     906            6 :                         this->ElecPowerGenerated,
     907              :                         OutputProcessor::TimeStepType::System,
     908              :                         OutputProcessor::StoreType::Average,
     909            6 :                         this->Name);
     910              : 
     911           12 :     SetupOutputVariable(state,
     912              :                         "Generator Produced AC Electricity Energy",
     913              :                         Constant::Units::J,
     914            6 :                         this->EnergyGen,
     915              :                         OutputProcessor::TimeStepType::System,
     916              :                         OutputProcessor::StoreType::Sum,
     917            6 :                         this->Name,
     918              :                         Constant::eResource::ElectricityProduced,
     919              :                         OutputProcessor::Group::Plant,
     920              :                         OutputProcessor::EndUseCat::Cogeneration);
     921              : 
     922           12 :     SetupOutputVariable(state,
     923              :                         "Generator LHV Basis Electric Efficiency",
     924              :                         Constant::Units::None,
     925            6 :                         this->ElectricEfficiencyLHV,
     926              :                         OutputProcessor::TimeStepType::System,
     927              :                         OutputProcessor::StoreType::Average,
     928            6 :                         this->Name);
     929              : 
     930              :     //    Fuel specific report variables
     931           18 :     SetupOutputVariable(state,
     932           12 :                         format("Generator {} HHV Basis Rate", sFuelType),
     933              :                         Constant::Units::W,
     934            6 :                         this->FuelEnergyUseRateHHV,
     935              :                         OutputProcessor::TimeStepType::System,
     936              :                         OutputProcessor::StoreType::Average,
     937            6 :                         this->Name);
     938              : 
     939           18 :     SetupOutputVariable(state,
     940           12 :                         format("Generator {} HHV Basis Energy", sFuelType),
     941              :                         Constant::Units::J,
     942            6 :                         this->FuelEnergyHHV,
     943              :                         OutputProcessor::TimeStepType::System,
     944              :                         OutputProcessor::StoreType::Sum,
     945            6 :                         this->Name,
     946            6 :                         Constant::eFuel2eResource[(int)this->FuelType],
     947              :                         OutputProcessor::Group::Plant,
     948              :                         OutputProcessor::EndUseCat::Cogeneration);
     949              : 
     950           18 :     SetupOutputVariable(state,
     951           12 :                         format("Generator {} Mass Flow Rate", sFuelType),
     952              :                         Constant::Units::kg_s,
     953            6 :                         this->FuelMdot,
     954              :                         OutputProcessor::TimeStepType::System,
     955              :                         OutputProcessor::StoreType::Average,
     956            6 :                         this->Name);
     957              : 
     958              :     //    general fuel use report (to match other generators)
     959           12 :     SetupOutputVariable(state,
     960              :                         "Generator Fuel HHV Basis Rate",
     961              :                         Constant::Units::W,
     962            6 :                         this->FuelEnergyUseRateHHV,
     963              :                         OutputProcessor::TimeStepType::System,
     964              :                         OutputProcessor::StoreType::Average,
     965            6 :                         this->Name);
     966              : 
     967           12 :     SetupOutputVariable(state,
     968              :                         "Generator Fuel HHV Basis Energy",
     969              :                         Constant::Units::J,
     970            6 :                         this->FuelEnergyHHV,
     971              :                         OutputProcessor::TimeStepType::System,
     972              :                         OutputProcessor::StoreType::Sum,
     973            6 :                         this->Name);
     974              : 
     975              :     //    Heat recovery (to water) report variables
     976            6 :     if (this->HeatRecActive) {
     977              : 
     978            4 :         SetupOutputVariable(state,
     979              :                             "Generator Produced Thermal Rate",
     980              :                             Constant::Units::W,
     981            2 :                             this->QHeatRecovered,
     982              :                             OutputProcessor::TimeStepType::System,
     983              :                             OutputProcessor::StoreType::Average,
     984            2 :                             this->Name);
     985              : 
     986            4 :         SetupOutputVariable(state,
     987              :                             "Generator Produced Thermal Energy",
     988              :                             Constant::Units::J,
     989            2 :                             this->ExhaustEnergyRec,
     990              :                             OutputProcessor::TimeStepType::System,
     991              :                             OutputProcessor::StoreType::Sum,
     992            2 :                             this->Name,
     993              :                             Constant::eResource::EnergyTransfer,
     994              :                             OutputProcessor::Group::Plant,
     995              :                             OutputProcessor::EndUseCat::HeatRecovery);
     996              : 
     997            4 :         SetupOutputVariable(state,
     998              :                             "Generator Thermal Efficiency LHV Basis",
     999              :                             Constant::Units::None,
    1000            2 :                             this->ThermalEfficiencyLHV,
    1001              :                             OutputProcessor::TimeStepType::System,
    1002              :                             OutputProcessor::StoreType::Average,
    1003            2 :                             this->Name);
    1004              : 
    1005            4 :         SetupOutputVariable(state,
    1006              :                             "Generator Heat Recovery Inlet Temperature",
    1007              :                             Constant::Units::C,
    1008            2 :                             this->HeatRecInletTemp,
    1009              :                             OutputProcessor::TimeStepType::System,
    1010              :                             OutputProcessor::StoreType::Average,
    1011            2 :                             this->Name);
    1012              : 
    1013            4 :         SetupOutputVariable(state,
    1014              :                             "Generator Heat Recovery Outlet Temperature",
    1015              :                             Constant::Units::C,
    1016            2 :                             this->HeatRecOutletTemp,
    1017              :                             OutputProcessor::TimeStepType::System,
    1018              :                             OutputProcessor::StoreType::Average,
    1019            2 :                             this->Name);
    1020              : 
    1021            4 :         SetupOutputVariable(state,
    1022              :                             "Generator Heat Recovery Water Mass Flow Rate",
    1023              :                             Constant::Units::kg_s,
    1024            2 :                             this->HeatRecMdot,
    1025              :                             OutputProcessor::TimeStepType::System,
    1026              :                             OutputProcessor::StoreType::Average,
    1027            2 :                             this->Name);
    1028              :     }
    1029              : 
    1030            6 :     if (this->StandbyPower > 0.0) { // Report Standby Power if entered by user
    1031           10 :         SetupOutputVariable(state,
    1032              :                             "Generator Standby Electricity Rate",
    1033              :                             Constant::Units::W,
    1034            5 :                             this->StandbyPowerRate,
    1035              :                             OutputProcessor::TimeStepType::System,
    1036              :                             OutputProcessor::StoreType::Average,
    1037            5 :                             this->Name);
    1038              : 
    1039           10 :         SetupOutputVariable(state,
    1040              :                             "Generator Standby Electricity Energy",
    1041              :                             Constant::Units::J,
    1042            5 :                             this->StandbyEnergy,
    1043              :                             OutputProcessor::TimeStepType::System,
    1044              :                             OutputProcessor::StoreType::Sum,
    1045            5 :                             this->Name,
    1046              :                             Constant::eResource::Electricity,
    1047              :                             OutputProcessor::Group::Plant,
    1048              :                             OutputProcessor::EndUseCat::Cogeneration);
    1049              :     }
    1050              : 
    1051            6 :     if (this->AncillaryPower > 0.0) { // Report Ancillary Power if entered by user
    1052           10 :         SetupOutputVariable(state,
    1053              :                             "Generator Ancillary Electricity Rate",
    1054              :                             Constant::Units::W,
    1055            5 :                             this->AncillaryPowerRate,
    1056              :                             OutputProcessor::TimeStepType::System,
    1057              :                             OutputProcessor::StoreType::Average,
    1058            5 :                             this->Name);
    1059              : 
    1060           10 :         SetupOutputVariable(state,
    1061              :                             "Generator Ancillary Electricity Energy",
    1062              :                             Constant::Units::J,
    1063            5 :                             this->AncillaryEnergy,
    1064              :                             OutputProcessor::TimeStepType::System,
    1065              :                             OutputProcessor::StoreType::Sum,
    1066            5 :                             this->Name);
    1067              :     }
    1068              : 
    1069              :     //   Report combustion air outlet conditions if exhaust air calculations are active
    1070            6 :     if (this->ExhAirCalcsActive) {
    1071            6 :         SetupOutputVariable(state,
    1072              :                             "Generator Exhaust Air Mass Flow Rate",
    1073              :                             Constant::Units::kg_s,
    1074            3 :                             this->ExhaustAirMassFlowRate,
    1075              :                             OutputProcessor::TimeStepType::System,
    1076              :                             OutputProcessor::StoreType::Average,
    1077            3 :                             this->Name);
    1078              : 
    1079            6 :         SetupOutputVariable(state,
    1080              :                             "Generator Exhaust Air Temperature",
    1081              :                             Constant::Units::C,
    1082            3 :                             this->ExhaustAirTemperature,
    1083              :                             OutputProcessor::TimeStepType::System,
    1084              :                             OutputProcessor::StoreType::Average,
    1085            3 :                             this->Name);
    1086              :     }
    1087            6 : }
    1088              : 
    1089        84490 : void MTGeneratorSpecs::simulate([[maybe_unused]] EnergyPlusData &state,
    1090              :                                 [[maybe_unused]] const PlantLocation &calledFromLocation,
    1091              :                                 [[maybe_unused]] bool FirstHVACIteration,
    1092              :                                 [[maybe_unused]] Real64 &CurLoad,
    1093              :                                 [[maybe_unused]] bool RunFlag)
    1094              : {
    1095              :     // empty function to emulate current behavior as of conversion to using the PlantComponent calling structure.
    1096              :     // calls from the plant side... do nothing.
    1097              :     // calls from the ElectricPowerServiceManger call the init, calc, and update worker functions
    1098        84490 : }
    1099              : 
    1100           10 : void MTGeneratorSpecs::getDesignCapacities([[maybe_unused]] EnergyPlusData &state,
    1101              :                                            [[maybe_unused]] const PlantLocation &calledFromLocation,
    1102              :                                            Real64 &MaxLoad,
    1103              :                                            Real64 &MinLoad,
    1104              :                                            Real64 &OptLoad)
    1105              : {
    1106           10 :     MaxLoad = 0.0;
    1107           10 :     MinLoad = 0.0;
    1108           10 :     OptLoad = 0.0;
    1109           10 : }
    1110              : 
    1111        51343 : void MTGeneratorSpecs::InitMTGenerators(EnergyPlusData &state,
    1112              :                                         bool const RunFlag,
    1113              :                                         Real64 const MyLoad, // electrical load in W
    1114              :                                         bool const FirstHVACIteration)
    1115              : {
    1116              : 
    1117              :     // SUBROUTINE INFORMATION:
    1118              :     //       AUTHOR         R. Raustad/D. Shirey
    1119              :     //       DATE WRITTEN   Mar 2008
    1120              :     //       MODIFIED       na
    1121              :     //       RE-ENGINEERED  B. Griffith, Sept 2010, plant upgrades, general fluid props
    1122              : 
    1123              :     // PURPOSE OF THIS SUBROUTINE:
    1124              :     //  This subroutine is for initializations of the CT generators.
    1125              : 
    1126              :     // METHODOLOGY EMPLOYED:
    1127              :     //  Uses the status flags to trigger initializations.
    1128              : 
    1129        51343 :     this->oneTimeInit(state); // end one time inits
    1130              : 
    1131        51343 :     if (!this->HeatRecActive) {
    1132        32071 :         return;
    1133              :     }
    1134              : 
    1135              :     // Do the Begin Environment initializations
    1136        19272 :     if (state.dataGlobal->BeginEnvrnFlag && this->MyEnvrnFlag) {
    1137              :         // set the node max and min mass flow rates
    1138           16 :         PlantUtilities::InitComponentNodes(state, 0.0, this->HeatRecMaxMassFlowRate, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum);
    1139              : 
    1140           16 :         state.dataLoopNodes->Node(this->HeatRecInletNodeNum).Temp = 20.0; // Set the node temperature, assuming freeze control
    1141           16 :         state.dataLoopNodes->Node(this->HeatRecOutletNodeNum).Temp = 20.0;
    1142              : 
    1143           16 :         this->MyEnvrnFlag = false;
    1144              :     } // end environmental inits
    1145              : 
    1146        19272 :     if (!state.dataGlobal->BeginEnvrnFlag) {
    1147        18992 :         this->MyEnvrnFlag = true;
    1148              :     }
    1149              : 
    1150              :     // set/request flow rates
    1151        19272 :     if (FirstHVACIteration) {
    1152              : 
    1153              :         Real64 DesiredMassFlowRate;
    1154        12414 :         if (!RunFlag) {
    1155        10310 :             DesiredMassFlowRate = 0.0;
    1156              : 
    1157         2104 :         } else if (RunFlag && this->InternalFlowControl) {
    1158              :             // assume dispatch power in MyLoad is what gets produced (future, reset during calc routine and iterate)
    1159            0 :             if (this->HeatRecFlowFTempPowCurveNum != 0) {
    1160            0 :                 DesiredMassFlowRate =
    1161            0 :                     this->DesignHeatRecMassFlowRate *
    1162            0 :                     Curve::CurveValue(state, this->HeatRecFlowFTempPowCurveNum, state.dataLoopNodes->Node(this->HeatRecInletNodeNum).Temp, MyLoad);
    1163              :             } else {
    1164            0 :                 DesiredMassFlowRate = this->DesignHeatRecMassFlowRate; // Assume modifier = 1 if curve not specified
    1165              :             }
    1166              : 
    1167            0 :             DesiredMassFlowRate = max(DataPrecisionGlobals::constant_zero, DesiredMassFlowRate); // protect from neg. curve result
    1168              : 
    1169         2104 :         } else if (RunFlag && (!this->InternalFlowControl)) {
    1170         2104 :             DesiredMassFlowRate = this->DesignHeatRecMassFlowRate;
    1171              :         }
    1172              : 
    1173        12414 :         PlantUtilities::SetComponentFlowRate(state, DesiredMassFlowRate, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum, this->HRPlantLoc);
    1174              :     } else { // not FirstHVACIteration
    1175         6858 :         if (!RunFlag) {
    1176         5594 :             state.dataLoopNodes->Node(this->HeatRecInletNodeNum).MassFlowRate =
    1177         5594 :                 min(DataPrecisionGlobals::constant_zero, state.dataLoopNodes->Node(this->HeatRecInletNodeNum).MassFlowRateMaxAvail);
    1178         5594 :             state.dataLoopNodes->Node(this->HeatRecInletNodeNum).MassFlowRate =
    1179         5594 :                 max(DataPrecisionGlobals::constant_zero, state.dataLoopNodes->Node(this->HeatRecInletNodeNum).MassFlowRateMinAvail);
    1180              : 
    1181         1264 :         } else if (RunFlag && this->InternalFlowControl) {
    1182              :             // assume dispatch power in MyLoad is what gets produced (future, reset during calc routine and iterate)
    1183            0 :             if (this->HeatRecFlowFTempPowCurveNum != 0) {
    1184              :                 Real64 DesiredMassFlowRate =
    1185            0 :                     this->DesignHeatRecMassFlowRate *
    1186            0 :                     Curve::CurveValue(state, this->HeatRecFlowFTempPowCurveNum, state.dataLoopNodes->Node(this->HeatRecInletNodeNum).Temp, MyLoad);
    1187            0 :                 PlantUtilities::SetComponentFlowRate(
    1188            0 :                     state, DesiredMassFlowRate, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum, this->HRPlantLoc);
    1189              :             } else {
    1190            0 :                 PlantUtilities::SetComponentFlowRate(
    1191            0 :                     state, this->HeatRecMdot, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum, this->HRPlantLoc);
    1192              :             }
    1193         1264 :         } else if (RunFlag && (!this->InternalFlowControl)) {
    1194         1264 :             PlantUtilities::SetComponentFlowRate(state, this->HeatRecMdot, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum, this->HRPlantLoc);
    1195              :         }
    1196              :     }
    1197              : }
    1198              : 
    1199        51343 : void MTGeneratorSpecs::CalcMTGeneratorModel(EnergyPlusData &state,
    1200              :                                             bool const RunFlag,  // TRUE when generator is being asked to operate
    1201              :                                             Real64 const MyLoad) // Generator demand (W)
    1202              : {
    1203              :     // SUBROUTINE INFORMATION:
    1204              :     //       AUTHOR         R. Raustad/D. Shirey
    1205              :     //       DATE WRITTEN   Mar 2008
    1206              :     //       MODIFIED       na
    1207              :     //       RE-ENGINEERED  na
    1208              : 
    1209              :     // PURPOSE OF THIS SUBROUTINE:
    1210              :     //  Simulate a combustion generator.
    1211              : 
    1212              :     // METHODOLOGY EMPLOYED:
    1213              :     //  Curve fits of performance data.
    1214              : 
    1215        51343 :     Real64 constexpr KJtoJ(1000.0);          // Convert kilojoules to joules
    1216        51343 :     int constexpr MaxAncPowerIter(50);       // Maximum number of iteration (subroutine ancillary power iteration loop)
    1217        51343 :     Real64 constexpr AncPowerDiffToler(5.0); // Tolerance for Ancillary Power Difference (W)
    1218        51343 :     Real64 constexpr RelaxFactor(0.7);       // Relaxation factor for iteration loop
    1219              :     static constexpr std::string_view RoutineName("CalcMTGeneratorModel");
    1220              : 
    1221              :     //   Load local variables from data structure (for code readability)
    1222              :     // Min allowed operating fraction at full load
    1223        51343 :     Real64 minPartLoadRat = this->MinPartLoadRat;
    1224              : 
    1225              :     // Max allowed operating fraction at full load
    1226        51343 :     Real64 maxPartLoadRat = this->MaxPartLoadRat;
    1227              : 
    1228              :     // Generator reference capacity (W)
    1229        51343 :     Real64 ReferencePowerOutput = this->RefElecPowerOutput;
    1230              : 
    1231              :     // Reference electrical efficiency
    1232        51343 :     Real64 RefElecEfficiency = this->RefElecEfficiencyLHV;
    1233              : 
    1234              :     //   Initialize variables
    1235        51343 :     this->ElecPowerGenerated = 0.0;
    1236        51343 :     this->HeatRecInletTemp = 0.0;
    1237        51343 :     this->HeatRecOutletTemp = 0.0;
    1238        51343 :     this->HeatRecMdot = 0.0;
    1239        51343 :     this->QHeatRecovered = 0.0;
    1240        51343 :     this->ExhaustEnergyRec = 0.0;
    1241        51343 :     this->FuelEnergyUseRateHHV = 0.0;
    1242        51343 :     this->FuelMdot = 0.0;
    1243        51343 :     this->AncillaryPowerRate = 0.0;
    1244        51343 :     this->StandbyPowerRate = 0.0;
    1245        51343 :     this->FuelEnergyUseRateLHV = 0.0;
    1246        51343 :     this->ExhaustAirMassFlowRate = 0.0;
    1247        51343 :     this->ExhaustAirTemperature = 0.0;
    1248        51343 :     this->ExhaustAirHumRat = 0.0;
    1249              : 
    1250              :     Real64 HeatRecInTemp; // Heat recovery fluid inlet temperature (C)
    1251              :     Real64 heatRecMdot;   // Heat recovery fluid mass flow rate (kg/s)
    1252              :     Real64 HeatRecCp;     // Specific heat of the heat recovery fluid (J/kg-K)
    1253              : 
    1254        51343 :     if (this->HeatRecActive) {
    1255        19272 :         HeatRecInTemp = state.dataLoopNodes->Node(this->HeatRecInletNodeNum).Temp;
    1256        19272 :         HeatRecCp = state.dataPlnt->PlantLoop(this->HRPlantLoc.loopNum).glycol->getSpecificHeat(state, HeatRecInTemp, RoutineName);
    1257        19272 :         heatRecMdot = state.dataLoopNodes->Node(this->HeatRecInletNodeNum).MassFlowRate;
    1258              :     } else {
    1259        32071 :         HeatRecInTemp = 0.0;
    1260        32071 :         HeatRecCp = 0.0;
    1261        32071 :         heatRecMdot = 0.0;
    1262              :     }
    1263              : 
    1264              :     Real64 CombustionAirInletTemp;  // Combustion air inlet temperature (C)
    1265              :     Real64 CombustionAirInletPress; // Barometric pressure of combustion inlet air (Pa)
    1266              :     Real64 CombustionAirInletW;     // Combustion air inlet humidity ratio (kg/kg)
    1267              : 
    1268              :     //   Set combustion inlet air temperature, humidity ratio and pressure local variables
    1269        51343 :     if (this->CombustionAirInletNodeNum == 0) { // no inlet air node specified, so use weather file values
    1270        24208 :         CombustionAirInletTemp = state.dataEnvrn->OutDryBulbTemp;
    1271        24208 :         CombustionAirInletW = state.dataEnvrn->OutHumRat;
    1272        24208 :         CombustionAirInletPress = state.dataEnvrn->OutBaroPress;
    1273              :     } else { // use inlet node information
    1274        27135 :         CombustionAirInletTemp = state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).Temp;
    1275        27135 :         CombustionAirInletW = state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).HumRat;
    1276        27135 :         CombustionAirInletPress = state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).Press;
    1277        27135 :         if (state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).Height > 0.0) {
    1278              :         }
    1279              :         //     Initialize combustion outlet air conditions to inlet air conditions (all node properties)
    1280        27135 :         if (this->ExhAirCalcsActive) {
    1281        27135 :             state.dataLoopNodes->Node(this->CombustionAirOutletNodeNum) = state.dataLoopNodes->Node(this->CombustionAirInletNodeNum);
    1282              :         }
    1283              :     }
    1284              : 
    1285              :     //   If no loop demand or generator OFF, set some variables and then return
    1286              :     //    IF (.NOT. RunFlag .OR. MyLoad .LE. 0.0d0) THEN
    1287        51343 :     if (MyLoad <= 0.0) {
    1288        32878 :         this->HeatRecInletTemp = HeatRecInTemp;
    1289        32878 :         this->HeatRecOutletTemp = HeatRecInTemp;
    1290        32878 :         if (RunFlag) {
    1291            0 :             this->StandbyPowerRate = this->StandbyPower;
    1292              :         }
    1293        32878 :         this->ExhaustAirTemperature = CombustionAirInletTemp;
    1294        32878 :         this->ExhaustAirHumRat = CombustionAirInletW;
    1295        32878 :         return;
    1296              :     }
    1297              : 
    1298              :     //   Calculate power modifier curve value (function of inlet air temperature and elevation)
    1299              :     // Power ratio as a function of inlet air temperature and elevation
    1300        18465 :     Real64 PowerFTempElev = Curve::CurveValue(state, this->ElecPowFTempElevCurveNum, CombustionAirInletTemp, state.dataEnvrn->Elevation);
    1301              : 
    1302              :     //   Warn user if power modifier curve output is less than 0
    1303        18465 :     if (PowerFTempElev < 0.0) {
    1304            0 :         if (this->PowerFTempElevErrorIndex == 0) {
    1305              :             //        MTGenerator(GeneratorNum)%PowerFTempElevErrorCount = MTGenerator(GeneratorNum)%PowerFTempElevErrorCount + 1
    1306            0 :             ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
    1307            0 :             ShowContinueError(state,
    1308            0 :                               format("... Electrical Power Modifier curve (function of temperature and elevation) output is less than zero ({:.4T}).",
    1309              :                                      PowerFTempElev));
    1310            0 :             ShowContinueError(state, format("... Value occurs using a combustion inlet air temperature of {:.2T} C.", CombustionAirInletTemp));
    1311            0 :             ShowContinueError(state, format("... and an elevation of {:.2T} m.", state.dataEnvrn->Elevation));
    1312            0 :             ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
    1313              :         }
    1314            0 :         ShowRecurringWarningErrorAtEnd(state,
    1315            0 :                                        "GENERATOR:MICROTURBINE \"" + this->Name +
    1316              :                                            "\": Electrical Power Modifier curve is less than zero warning continues...",
    1317            0 :                                        this->PowerFTempElevErrorIndex,
    1318              :                                        PowerFTempElev,
    1319              :                                        PowerFTempElev);
    1320            0 :         PowerFTempElev = 0.0;
    1321              :     }
    1322              : 
    1323              :     //   Calculate available full-load power output. cannot exceed maximum full-load power output.
    1324              :     // Generator full-load power output at actual inlet conditions and elevation (W)
    1325        18465 :     Real64 FullLoadPowerOutput = min((ReferencePowerOutput * PowerFTempElev), this->MaxElecPowerOutput);
    1326              :     //   Also can't be below the minimum full-load power output.
    1327        18465 :     FullLoadPowerOutput = max(FullLoadPowerOutput, this->MinElecPowerOutput);
    1328              : 
    1329              :     // Ancillary power used by pump (if not specified in manufacturers data)
    1330        18465 :     Real64 ancillaryPowerRate = this->AncillaryPower;
    1331              : 
    1332              :     // Difference between ancillary power rate and ancillary power rate last (last iteration)
    1333        18465 :     Real64 AncillaryPowerRateDiff = AncPowerDiffToler + 1.0; // Initialize to force through DO WHILE Loop at least once
    1334              : 
    1335        18465 :     Real64 PLR(0.0);                    // Generator operating part load ratio
    1336        18465 :     Real64 elecPowerGenerated(0.0);     // Generator electric power output (W)
    1337        18465 :     Real64 FuelUseEnergyRateLHV(0.0);   // Rate of fuel energy required to run microturbine, LHV basis (W)
    1338        18465 :     Real64 fuelHigherHeatingValue(0.0); // Higher heating value (LLV) of fuel kJ/kg)
    1339        18465 :     Real64 fuelLowerHeatingValue(0.0);  // Lower heating value (LLV) of fuel kJ/kg)
    1340        18465 :     Real64 AnciPowerFMdotFuel(0.0);     // Ancillary power as a function of fuel flow curve output
    1341        18465 :     int AncPowerCalcIterIndex = 0;      // Index for subroutine iteration loop if Ancillary Power (function of fuel flow) is used
    1342              : 
    1343        36930 :     while (AncillaryPowerRateDiff > AncPowerDiffToler && AncPowerCalcIterIndex <= MaxAncPowerIter) {
    1344              : 
    1345        18465 :         ++AncPowerCalcIterIndex; // Increment iteration loop counter
    1346              : 
    1347              :         //     Calculate operating power output (gross)
    1348        18465 :         elecPowerGenerated = min(max(0.0, MyLoad + ancillaryPowerRate), FullLoadPowerOutput);
    1349              : 
    1350              :         //     Calculate PLR, but must be between the minPLR and maxPLR
    1351        18465 :         if (FullLoadPowerOutput > 0.0) {
    1352        18465 :             PLR = min(elecPowerGenerated / FullLoadPowerOutput, maxPartLoadRat);
    1353        18465 :             PLR = max(PLR, minPartLoadRat);
    1354              :         } else {
    1355            0 :             PLR = 0.0;
    1356              :         }
    1357              : 
    1358              :         //     Recalculate elecPowerGenerated based on "final" PLR
    1359        18465 :         elecPowerGenerated = FullLoadPowerOutput * PLR;
    1360              : 
    1361              :         //     Calculate electrical efficiency modifier curve output (function of temp)
    1362              :         // Electrical efficiency as a function of temperature curve output
    1363        18465 :         Real64 ElecEfficiencyFTemp = Curve::CurveValue(state, this->ElecEffFTempCurveNum, CombustionAirInletTemp);
    1364              : 
    1365              :         //     Warn user if efficiency modifier curve output is less than 0
    1366        18465 :         if (ElecEfficiencyFTemp < 0.0) {
    1367            0 :             if (this->EffFTempErrorIndex == 0) {
    1368              :                 //          MTGenerator(GeneratorNum)%EffFTempErrorCount = MTGenerator(GeneratorNum)%EffFTempErrorCount + 1
    1369            0 :                 ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
    1370            0 :                 ShowContinueError(
    1371              :                     state,
    1372            0 :                     format("... Electrical Efficiency Modifier (function of temperature) output is less than zero ({:.4T}).", ElecEfficiencyFTemp));
    1373            0 :                 ShowContinueError(state, format("... Value occurs using a combustion inlet air temperature of {:.2T} C.", CombustionAirInletTemp));
    1374            0 :                 ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
    1375              :             }
    1376            0 :             ShowRecurringWarningErrorAtEnd(
    1377              :                 state,
    1378            0 :                 "GENERATOR:MICROTURBINE \"" + this->Name +
    1379              :                     "\": Electrical Efficiency Modifier (function of temperature) output is less than zero warning continues...",
    1380            0 :                 this->EffFTempErrorIndex,
    1381              :                 ElecEfficiencyFTemp,
    1382              :                 ElecEfficiencyFTemp);
    1383            0 :             ElecEfficiencyFTemp = 0.0;
    1384              :         }
    1385              : 
    1386              :         //     Calculate efficiency modifier curve output (function of PLR)
    1387              :         // Electrical efficiency as a function of PLR curve output
    1388        18465 :         Real64 ElecEfficiencyFPLR = Curve::CurveValue(state, this->ElecEffFPLRCurveNum, PLR);
    1389              : 
    1390              :         //     Warn user if efficiency modifier curve output is less than 0
    1391        18465 :         if (ElecEfficiencyFPLR < 0.0) {
    1392            0 :             if (this->EffFPLRErrorIndex == 0) {
    1393            0 :                 ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
    1394            0 :                 ShowContinueError(state,
    1395            0 :                                   format("... Electrical Efficiency Modifier (function of part-load ratio) output is less than zero ({:.4T}).",
    1396              :                                          ElecEfficiencyFPLR));
    1397            0 :                 ShowContinueError(state, format("... Value occurs using a part-load ratio of {:.3T}.", PLR));
    1398            0 :                 ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
    1399              :             }
    1400            0 :             ShowRecurringWarningErrorAtEnd(
    1401              :                 state,
    1402            0 :                 "GENERATOR:MICROTURBINE \"" + this->Name +
    1403              :                     "\": Electrical Efficiency Modifier (function of part-load ratio) output is less than zero warning continues...",
    1404            0 :                 this->EffFPLRErrorIndex,
    1405              :                 ElecEfficiencyFPLR,
    1406              :                 ElecEfficiencyFPLR);
    1407            0 :             ElecEfficiencyFPLR = 0.0;
    1408              :         }
    1409              : 
    1410              :         //     Calculate operating electrical efficiency
    1411              :         // Actual operating efficiency
    1412        18465 :         Real64 OperatingElecEfficiency = RefElecEfficiency * ElecEfficiencyFTemp * ElecEfficiencyFPLR;
    1413              : 
    1414              :         //     Calculate fuel use (W = J/s), LHV basis
    1415        18465 :         if (OperatingElecEfficiency > 0.0) {
    1416        18465 :             FuelUseEnergyRateLHV = elecPowerGenerated / OperatingElecEfficiency;
    1417              :         } else {
    1418            0 :             FuelUseEnergyRateLHV = 0.0; // If fuel use rate is zero, then
    1419            0 :             elecPowerGenerated = 0.0;   //  electric power generated must be zero.
    1420              :         }
    1421              : 
    1422              :         //     Set fuel heating values
    1423        18465 :         fuelHigherHeatingValue = this->FuelHigherHeatingValue;
    1424        18465 :         fuelLowerHeatingValue = this->FuelLowerHeatingValue;
    1425              : 
    1426              :         //     Calculate fuel mass flow rate
    1427        18465 :         this->FuelMdot = FuelUseEnergyRateLHV / (fuelLowerHeatingValue * KJtoJ);
    1428              : 
    1429              :         //     Calculate ancillary power requirement
    1430        18465 :         if (this->AncillaryPowerFuelCurveNum > 0) {
    1431            0 :             AnciPowerFMdotFuel = Curve::CurveValue(state, this->AncillaryPowerFuelCurveNum, this->FuelMdot);
    1432              :             //       Warn user if ancillary power modifier curve output is less than 0
    1433            0 :             if (AnciPowerFMdotFuel < 0.0) {
    1434            0 :                 if (this->AnciPowerFMdotFuelErrorIndex == 0) {
    1435            0 :                     ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
    1436            0 :                     ShowContinueError(
    1437              :                         state,
    1438            0 :                         format("... Ancillary Power Modifier (function of fuel input) output is less than zero ({:.4T}).", AnciPowerFMdotFuel));
    1439            0 :                     ShowContinueError(state, format("... Value occurs using a fuel input mass flow rate of {:.4T} kg/s.", this->FuelMdot));
    1440            0 :                     ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
    1441              :                 }
    1442            0 :                 ShowRecurringWarningErrorAtEnd(
    1443              :                     state,
    1444            0 :                     "GENERATOR:MICROTURBINE \"" + this->Name +
    1445              :                         "\": Ancillary Power Modifier (function of fuel input) output is less than zero warning continues...",
    1446            0 :                     this->AnciPowerFMdotFuelErrorIndex,
    1447              :                     AnciPowerFMdotFuel,
    1448              :                     AnciPowerFMdotFuel);
    1449            0 :                 AnciPowerFMdotFuel = 0.0;
    1450              :             }
    1451              :         } else {
    1452        18465 :             AnciPowerFMdotFuel = 1.0;
    1453              :         }
    1454              : 
    1455              :         // Ancillary power used by pump from last iteration (iteration loop within this subroutine)
    1456        18465 :         Real64 AncillaryPowerRateLast = ancillaryPowerRate;
    1457              : 
    1458        18465 :         if (this->AncillaryPowerFuelCurveNum > 0) {
    1459            0 :             ancillaryPowerRate = RelaxFactor * this->AncillaryPower * AnciPowerFMdotFuel - (1.0 - RelaxFactor) * AncillaryPowerRateLast;
    1460              :         }
    1461              : 
    1462        18465 :         AncillaryPowerRateDiff = std::abs(ancillaryPowerRate - AncillaryPowerRateLast);
    1463              :     }
    1464              : 
    1465        18465 :     if (AncPowerCalcIterIndex > MaxAncPowerIter) {
    1466              : 
    1467            0 :         if (this->AnciPowerIterErrorIndex == 0) {
    1468            0 :             ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
    1469            0 :             ShowContinueError(state, "... Iteration loop for electric power generation is not converging within tolerance.");
    1470            0 :             ShowContinueError(state, "... Check the Ancillary Power Modifier Curve (function of fuel input).");
    1471            0 :             ShowContinueError(state, format("... Ancillary Power = {:.1T} W.", ancillaryPowerRate));
    1472            0 :             ShowContinueError(state, format("... Fuel input rate = {:.4T} kg/s.", AnciPowerFMdotFuel));
    1473            0 :             ShowContinueErrorTimeStamp(state, "... Simulation will continue.");
    1474              :         }
    1475            0 :         ShowRecurringWarningErrorAtEnd(state,
    1476            0 :                                        "GENERATOR:MICROTURBINE \"" + this->Name +
    1477              :                                            "\": Iteration loop for electric power generation is not converging within tolerance continues...",
    1478            0 :                                        this->AnciPowerIterErrorIndex);
    1479              :     }
    1480              : 
    1481              :     //   Calculate electrical power generated
    1482        18465 :     this->ElecPowerGenerated = elecPowerGenerated - ancillaryPowerRate;
    1483              : 
    1484              :     //   Report fuel energy use rate on HHV basis, which is the unit of measure when the fuel is sold
    1485        18465 :     this->FuelEnergyUseRateHHV = this->FuelMdot * fuelHigherHeatingValue * KJtoJ;
    1486        18465 :     this->AncillaryPowerRate = ancillaryPowerRate;     // Move to data structure for later reporting
    1487        18465 :     this->FuelEnergyUseRateLHV = FuelUseEnergyRateLHV; // Move to data structure for reporting calculations
    1488              : 
    1489              :     //   When generator operates, standby losses are 0
    1490        18465 :     this->StandbyPowerRate = 0.0;
    1491              : 
    1492        18465 :     Real64 QHeatRecToWater = 0.0; // Recovered waste heat to water (W)
    1493              : 
    1494              :     //   Calculate heat recovery if active
    1495        18465 :     if (this->HeatRecActive) {
    1496              : 
    1497              :         // Thermal efficiency as a function of air temperature and elevation
    1498              :         Real64 ThermalEffFTempElev;
    1499         3368 :         if (this->ThermEffFTempElevCurveNum > 0) {
    1500         3368 :             ThermalEffFTempElev = Curve::CurveValue(state, this->ThermEffFTempElevCurveNum, CombustionAirInletTemp, state.dataEnvrn->Elevation);
    1501              :             //       Warn user if power modifier curve output is less than 0
    1502         3368 :             if (ThermalEffFTempElev < 0.0) {
    1503            0 :                 if (this->ThermEffFTempElevErrorIndex == 0) {
    1504            0 :                     ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
    1505            0 :                     ShowContinueError(
    1506              :                         state,
    1507            0 :                         format("... Electrical Power Modifier curve (function of temperature and elevation) output is less than zero ({:.4T}).",
    1508              :                                PowerFTempElev));
    1509            0 :                     ShowContinueError(state,
    1510            0 :                                       format("... Value occurs using a combustion inlet air temperature of {:.2T} C.", CombustionAirInletTemp));
    1511            0 :                     ShowContinueError(state, format("... and an elevation of {:.2T} m.", state.dataEnvrn->Elevation));
    1512            0 :                     ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
    1513              :                 }
    1514            0 :                 ShowRecurringWarningErrorAtEnd(state,
    1515            0 :                                                "GENERATOR:MICROTURBINE \"" + this->Name +
    1516              :                                                    "\": Electrical Power Modifier curve is less than zero warning continues...",
    1517            0 :                                                this->ThermEffFTempElevErrorIndex,
    1518              :                                                ThermalEffFTempElev,
    1519              :                                                ThermalEffFTempElev);
    1520            0 :                 ThermalEffFTempElev = 0.0;
    1521              :             }
    1522              :         } else {
    1523            0 :             ThermalEffFTempElev = 1.0; // If no curve provided, assume multiplier factor = 1.0
    1524              :         }
    1525              : 
    1526         3368 :         QHeatRecToWater = FuelUseEnergyRateLHV * this->RefThermalEffLHV * ThermalEffFTempElev;
    1527              :         Real64 HeatRecRateFPLR; // Heat recovery rate as a function of PLR curve output
    1528              : 
    1529              :         //     Calculate heat recovery rate modifier curve output (function of PLR)
    1530         3368 :         if (this->HeatRecRateFPLRCurveNum > 0) {
    1531         3368 :             HeatRecRateFPLR = Curve::CurveValue(state, this->HeatRecRateFPLRCurveNum, PLR);
    1532              :             //       Warn user if heat recovery modifier curve output is less than 0
    1533         3368 :             if (HeatRecRateFPLR < 0.0) {
    1534            0 :                 if (this->HeatRecRateFPLRErrorIndex == 0) {
    1535            0 :                     ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
    1536            0 :                     ShowContinueError(
    1537              :                         state,
    1538            0 :                         format("... Heat Recovery Rate Modifier (function of part-load ratio) output is less than zero ({:.4T}).", HeatRecRateFPLR));
    1539            0 :                     ShowContinueError(state, format("... Value occurs using a part-load ratio of {:.3T}.", PLR));
    1540            0 :                     ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
    1541              :                 }
    1542            0 :                 ShowRecurringWarningErrorAtEnd(
    1543              :                     state,
    1544            0 :                     "GENERATOR:MICROTURBINE \"" + this->Name +
    1545              :                         "\": Heat Recovery Rate Modifier (function of part-load ratio) output is less than zero warning continues...",
    1546            0 :                     this->HeatRecRateFPLRErrorIndex,
    1547              :                     HeatRecRateFPLR,
    1548              :                     HeatRecRateFPLR);
    1549            0 :                 HeatRecRateFPLR = 0.0;
    1550              :             }
    1551              :         } else {
    1552            0 :             HeatRecRateFPLR = 1.0; // If no curve provided, assume multiplier factor = 1.0
    1553              :         }
    1554              : 
    1555              :         Real64 HeatRecRateFTemp; // Heat recovery rate as a function of inlet water temp curve output
    1556              : 
    1557              :         //     Calculate heat recovery rate modifier curve output (function of inlet water temp)
    1558         3368 :         if (this->HeatRecRateFTempCurveNum > 0) {
    1559         3368 :             HeatRecRateFTemp = Curve::CurveValue(state, this->HeatRecRateFTempCurveNum, HeatRecInTemp);
    1560         3368 :             if (HeatRecRateFTemp < 0.0) {
    1561            0 :                 if (this->HeatRecRateFTempErrorIndex == 0) {
    1562            0 :                     ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
    1563            0 :                     ShowContinueError(state,
    1564            0 :                                       format("... Heat Recovery Rate Modifier (function of inlet water temp) output is less than zero ({:.4T}).",
    1565              :                                              HeatRecRateFTemp));
    1566            0 :                     ShowContinueError(state, format("... Value occurs using an inlet water temperature temperature of {:.2T} C.", HeatRecInTemp));
    1567            0 :                     ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
    1568              :                 }
    1569            0 :                 ShowRecurringWarningErrorAtEnd(
    1570              :                     state,
    1571            0 :                     "GENERATOR:MICROTURBINE \"" + this->Name +
    1572              :                         "\": Heat Recovery Rate Modifier (function of inlet water temp) output is less than zero warning continues...",
    1573            0 :                     this->HeatRecRateFTempErrorIndex,
    1574              :                     HeatRecRateFTemp,
    1575              :                     HeatRecRateFTemp);
    1576            0 :                 HeatRecRateFTemp = 0.0;
    1577              :             }
    1578              :         } else {
    1579            0 :             HeatRecRateFTemp = 1.0; // If no curve provided, assume multiplier factor = 1.0
    1580              :         }
    1581              : 
    1582              :         Real64 HeatRecRateFFlow; // Heat recovery rate as a function of water flow rate curve output
    1583              : 
    1584              :         //     Calculate heat recovery rate modifier curve output (function of water [volumetric] flow rate)
    1585         3368 :         if (this->HeatRecRateFWaterFlowCurveNum > 0) {
    1586         3368 :             Real64 rho = state.dataPlnt->PlantLoop(this->HRPlantLoc.loopNum).glycol->getDensity(state, HeatRecInTemp, RoutineName);
    1587              : 
    1588              :             // Heat recovery fluid flow rate (m3/s)
    1589         3368 :             Real64 HeatRecVolFlowRate = heatRecMdot / rho;
    1590         3368 :             HeatRecRateFFlow = Curve::CurveValue(state, this->HeatRecRateFWaterFlowCurveNum, HeatRecVolFlowRate);
    1591         3368 :             if (HeatRecRateFFlow < 0.0) {
    1592            0 :                 if (this->HeatRecRateFFlowErrorIndex == 0) {
    1593            0 :                     ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
    1594            0 :                     ShowContinueError(
    1595              :                         state,
    1596            0 :                         format("... Heat Recovery Rate Modifier (function of water flow rate) output is less than zero ({:.4T}).", HeatRecRateFFlow));
    1597            0 :                     ShowContinueError(state, format("... Value occurs using a water flow rate of {:.4T} m3/s.", HeatRecVolFlowRate));
    1598            0 :                     ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
    1599              :                 }
    1600            0 :                 ShowRecurringWarningErrorAtEnd(
    1601              :                     state,
    1602            0 :                     "GENERATOR:MICROTURBINE \"" + this->Name +
    1603              :                         "\": Heat Recovery Rate Modifier (function of water flow rate) output is less than zero warning continues...",
    1604            0 :                     this->HeatRecRateFFlowErrorIndex,
    1605              :                     HeatRecRateFFlow,
    1606              :                     HeatRecRateFFlow);
    1607            0 :                 HeatRecRateFFlow = 0.0;
    1608              :             }
    1609              :         } else {
    1610            0 :             HeatRecRateFFlow = 1.0; // If no curve provided, assume multiplier factor = 1.0
    1611              :         }
    1612              : 
    1613         3368 :         QHeatRecToWater *= HeatRecRateFPLR * HeatRecRateFTemp * HeatRecRateFFlow;
    1614              : 
    1615              :         Real64 HeatRecOutTemp; // Heat recovery fluid outlet temperature (C)
    1616              : 
    1617              :         //     Check for divide by zero
    1618         3368 :         if ((heatRecMdot > 0.0) && (HeatRecCp > 0.0)) {
    1619         3368 :             HeatRecOutTemp = HeatRecInTemp + QHeatRecToWater / (heatRecMdot * HeatRecCp);
    1620              :         } else {
    1621            0 :             heatRecMdot = 0.0;
    1622            0 :             HeatRecOutTemp = HeatRecInTemp;
    1623            0 :             QHeatRecToWater = 0.0;
    1624              :         }
    1625              : 
    1626              :         //     Now verify the maximum heat recovery temperature was not exceeded
    1627         3368 :         if (HeatRecOutTemp > this->HeatRecMaxWaterTemp) {
    1628              : 
    1629         1659 :             Real64 MinHeatRecMdot = 0.0; // Heat recovery flow rate if minimal heat recovery is accomplished (kg/s)
    1630              : 
    1631         1659 :             if (this->HeatRecMaxWaterTemp != HeatRecInTemp) {
    1632         1659 :                 MinHeatRecMdot = QHeatRecToWater / (HeatRecCp * (this->HeatRecMaxWaterTemp - HeatRecInTemp));
    1633         1659 :                 if (MinHeatRecMdot < 0.0) {
    1634            8 :                     MinHeatRecMdot = 0.0;
    1635              :                 }
    1636              :             }
    1637              : 
    1638              :             //       Recalculate outlet water temperature with minimum flow rate (will normally match the max water outlet temp,
    1639              :             //       unless the inlet water temp is greater than the max outlet temp)
    1640              :             Real64 HRecRatio; // When maximum temperature is reached the amount of recovered heat has to be reduced
    1641              : 
    1642         1659 :             if ((MinHeatRecMdot > 0.0) && (HeatRecCp > 0.0)) {
    1643         1651 :                 HeatRecOutTemp = QHeatRecToWater / (MinHeatRecMdot * HeatRecCp) + HeatRecInTemp;
    1644         1651 :                 HRecRatio = heatRecMdot / MinHeatRecMdot;
    1645              :             } else {
    1646            8 :                 HeatRecOutTemp = HeatRecInTemp;
    1647            8 :                 HRecRatio = 0.0;
    1648              :             }
    1649         1659 :             QHeatRecToWater *= HRecRatio; // Scale heat recovery rate using HRecRatio. Don't adjust flow rate.
    1650              :         }
    1651              : 
    1652              :         //     Check water mass flow rate against minimum
    1653         3368 :         if (this->HeatRecMinMassFlowRate > heatRecMdot && heatRecMdot > 0.0) {
    1654            0 :             if (this->HRMinFlowErrorIndex == 0) {
    1655            0 :                 ShowWarningError(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
    1656            0 :                 ShowContinueError(state,
    1657            0 :                                   format("...Heat reclaim water flow rate is below the generators minimum mass flow rate of ({:.4T}).",
    1658            0 :                                          this->HeatRecMinMassFlowRate));
    1659            0 :                 ShowContinueError(state, format("...Heat reclaim water mass flow rate = {:.4T}.", heatRecMdot));
    1660            0 :                 ShowContinueErrorTimeStamp(state, "...Check inputs for heat recovery water flow rate.");
    1661              :             }
    1662            0 :             ShowRecurringWarningErrorAtEnd(
    1663              :                 state,
    1664            0 :                 "GENERATOR:MICROTURBINE \"" + this->Name +
    1665              :                     "\": Heat recovery water flow rate is below the generators minimum mass flow rate warning continues...",
    1666            0 :                 this->HRMinFlowErrorIndex,
    1667              :                 heatRecMdot,
    1668              :                 heatRecMdot);
    1669              :         }
    1670              : 
    1671              :         //     Check water mass flow rate against maximum
    1672         3368 :         if (heatRecMdot > this->HeatRecMaxMassFlowRate && heatRecMdot > 0.0) {
    1673            0 :             if (this->HRMaxFlowErrorIndex == 0) {
    1674            0 :                 ShowWarningError(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
    1675            0 :                 ShowContinueError(state,
    1676            0 :                                   format("...Heat reclaim water flow rate is above the generators maximum mass flow rate of ({:.4T}).",
    1677            0 :                                          this->HeatRecMaxMassFlowRate));
    1678            0 :                 ShowContinueError(state, format("...Heat reclaim water mass flow rate = {:.4T}.", heatRecMdot));
    1679            0 :                 ShowContinueErrorTimeStamp(state, "...Check inputs for heat recovery water flow rate.");
    1680              :             }
    1681            0 :             ShowRecurringWarningErrorAtEnd(
    1682              :                 state,
    1683            0 :                 "GENERATOR:MICROTURBINE \"" + this->Name +
    1684              :                     "\": Heat recovery water flow rate is above the generators maximum mass flow rate warning continues...",
    1685            0 :                 this->HRMaxFlowErrorIndex,
    1686              :                 heatRecMdot,
    1687              :                 heatRecMdot);
    1688              :         }
    1689              : 
    1690              :         //     Set report variables
    1691         3368 :         this->HeatRecInletTemp = HeatRecInTemp;
    1692         3368 :         this->HeatRecOutletTemp = HeatRecOutTemp;
    1693         3368 :         this->HeatRecMdot = heatRecMdot;
    1694         3368 :         this->QHeatRecovered = QHeatRecToWater;
    1695              : 
    1696              :     } // End of  IF (MTGenerator(GeneratorNum)%HeatRecActive) THEN
    1697              : 
    1698              :     //   Calculate combustion air outlet conditions if exhaust air calculations are active
    1699        18465 :     if (this->ExhAirCalcsActive) {
    1700              : 
    1701              :         Real64 ExhFlowFTemp; // Exhaust air flow rate as a function of temperature curve output
    1702              : 
    1703         8666 :         if (this->ExhFlowFTempCurveNum != 0) { // Exhaust Flow Rate versus Inlet Air Temp
    1704         8666 :             ExhFlowFTemp = Curve::CurveValue(state, this->ExhFlowFTempCurveNum, CombustionAirInletTemp);
    1705              :             //       Warn user if exhaust modifier curve output is less than or equal to 0
    1706         8666 :             if (ExhFlowFTemp <= 0.0) {
    1707            0 :                 if (this->ExhFlowFTempErrorIndex == 0) {
    1708            0 :                     ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
    1709            0 :                     ShowContinueError(
    1710              :                         state,
    1711            0 :                         format("...Exhaust Air Flow Rate Modifier (function of temperature) output is less than or equal to zero ({:.4T}).",
    1712              :                                ExhFlowFTemp));
    1713            0 :                     ShowContinueError(state, format("...Value occurs using a combustion inlet air temperature of {:.2T}.", CombustionAirInletTemp));
    1714            0 :                     ShowContinueErrorTimeStamp(state, "...Resetting curve output to zero and continuing simulation.");
    1715              :                 }
    1716            0 :                 ShowRecurringWarningErrorAtEnd(
    1717              :                     state,
    1718            0 :                     "GENERATOR:MICROTURBINE \"" + this->Name +
    1719              :                         "\": Exhaust Air Flow Rate Modifier (function of temperature) output is less than or equal to zero warning continues...",
    1720            0 :                     this->ExhFlowFTempErrorIndex,
    1721              :                     ExhFlowFTemp,
    1722              :                     ExhFlowFTemp);
    1723            0 :                 ExhFlowFTemp = 0.0;
    1724              :             }
    1725              :         } else {
    1726            0 :             ExhFlowFTemp = 1.0; // No curve input means modifier = 1.0 always
    1727              :         }
    1728              : 
    1729              :         Real64 ExhFlowFPLR; // Exhaust air flow rate as a function of part-load ratio curve output
    1730              : 
    1731         8666 :         if (this->ExhFlowFPLRCurveNum != 0) { // Exhaust Flow Rate versus Part-Load Ratio
    1732         8666 :             ExhFlowFPLR = Curve::CurveValue(state, this->ExhFlowFPLRCurveNum, PLR);
    1733              :             //       Warn user if exhaust modifier curve output is less than or equal to 0
    1734         8666 :             if (ExhFlowFPLR <= 0.0) {
    1735            0 :                 if (this->ExhFlowFPLRErrorIndex == 0) {
    1736            0 :                     ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
    1737            0 :                     ShowContinueError(
    1738              :                         state,
    1739            0 :                         format("...Exhaust Air Flow Rate Modifier (function of part-load ratio) output is less than or equal to zero ({:.4T}).",
    1740              :                                ExhFlowFPLR));
    1741            0 :                     ShowContinueError(state, format("...Value occurs using a part-load ratio of {:.2T}.", PLR));
    1742            0 :                     ShowContinueErrorTimeStamp(state, "...Resetting curve output to zero and continuing simulation.");
    1743              :                 }
    1744            0 :                 ShowRecurringWarningErrorAtEnd(state,
    1745            0 :                                                "GENERATOR:MICROTURBINE \"" + this->Name +
    1746              :                                                    "\": Exhaust Air Flow Rate Modifier (function of part-load ratio) output is less than or "
    1747              :                                                    "equal to zero warning continues...",
    1748            0 :                                                this->ExhFlowFPLRErrorIndex,
    1749              :                                                ExhFlowFPLR,
    1750              :                                                ExhFlowFPLR);
    1751            0 :                 ExhFlowFPLR = 0.0;
    1752              :             }
    1753              :         } else {
    1754            0 :             ExhFlowFPLR = 1.0; // No curve input means modifier = 1.0 always
    1755              :         }
    1756              : 
    1757              :         //     Calculate exhaust air mass flow, accounting for temperature and PLR modifier factors
    1758              :         // Actual exhaust air mass flow rate (accounting for temp and PLR modifier curves)
    1759         8666 :         Real64 ExhAirMassFlowRate = this->RefExhaustAirMassFlowRate * ExhFlowFTemp * ExhFlowFPLR;
    1760              :         //     Adjust for difference in air density at reference conditions versus actual inlet air conditions
    1761              : 
    1762              :         // Density of air at actual combustion inlet air conditions (kg/m3)
    1763         8666 :         Real64 AirDensity = Psychrometrics::PsyRhoAirFnPbTdbW(state, CombustionAirInletPress, CombustionAirInletTemp, CombustionAirInletW);
    1764         8666 :         if (this->RefCombustAirInletDensity >= 0.0) {
    1765         8666 :             ExhAirMassFlowRate = max(0.0, ExhAirMassFlowRate * AirDensity / this->RefCombustAirInletDensity);
    1766              :         } else {
    1767            0 :             ExhAirMassFlowRate = 0.0;
    1768              :         }
    1769         8666 :         this->ExhaustAirMassFlowRate = ExhAirMassFlowRate;
    1770              : 
    1771              :         Real64 ExhAirTempFTemp; // Exhaust air temperature as a function of inlet air temp curve output
    1772              : 
    1773         8666 :         if (this->ExhAirTempFTempCurveNum != 0) { // Exhaust Air Temp versus Inlet Air Temp
    1774         8666 :             ExhAirTempFTemp = Curve::CurveValue(state, this->ExhAirTempFTempCurveNum, CombustionAirInletTemp);
    1775              :             //       Warn user if exhaust modifier curve output is less than or equal to 0
    1776         8666 :             if (ExhAirTempFTemp <= 0.0) {
    1777            0 :                 if (this->ExhTempFTempErrorIndex == 0) {
    1778            0 :                     ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
    1779            0 :                     ShowContinueError(
    1780              :                         state,
    1781            0 :                         format("...Exhaust Air Temperature Modifier (function of temperature) output is less than or equal to zero ({:.4T}).",
    1782              :                                ExhAirTempFTemp));
    1783            0 :                     ShowContinueError(state, format("...Value occurs using a combustion inlet air temperature of {:.2T}.", CombustionAirInletTemp));
    1784            0 :                     ShowContinueErrorTimeStamp(state, "...Resetting curve output to zero and continuing simulation.");
    1785              :                 }
    1786            0 :                 ShowRecurringWarningErrorAtEnd(state,
    1787            0 :                                                "GENERATOR:MICROTURBINE \"" + this->Name +
    1788              :                                                    "\": Exhaust Air Temperature Modifier (function of temperature) output is less than or equal "
    1789              :                                                    "to zero warning continues...",
    1790            0 :                                                this->ExhTempFTempErrorIndex,
    1791              :                                                ExhAirTempFTemp,
    1792              :                                                ExhAirTempFTemp);
    1793            0 :                 ExhAirTempFTemp = 0.0;
    1794              :             }
    1795              :         } else {
    1796            0 :             ExhAirTempFTemp = 1.0; // No curve input means modifier = 1.0 always
    1797              :         }
    1798              : 
    1799              :         Real64 ExhAirTempFPLR; // Exhaust air temperature as a function of part-load ratio curve output
    1800              : 
    1801         8666 :         if (this->ExhAirTempFPLRCurveNum != 0) { // Exhaust Air Temp versus Part-Load Ratio
    1802         8666 :             ExhAirTempFPLR = Curve::CurveValue(state, this->ExhAirTempFPLRCurveNum, PLR);
    1803              :             //       Warn user if exhaust modifier curve output is less than or equal to 0
    1804         8666 :             if (ExhAirTempFPLR <= 0.0) {
    1805            0 :                 if (this->ExhTempFPLRErrorIndex == 0) {
    1806            0 :                     ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
    1807            0 :                     ShowContinueError(
    1808              :                         state,
    1809            0 :                         format("...Exhaust Air Temperature Modifier (function of part-load ratio) output is less than or equal to zero ({:.4T}).",
    1810              :                                ExhAirTempFPLR));
    1811            0 :                     ShowContinueError(state, format("...Value occurs using a part-load ratio of {:.2T}.", PLR));
    1812            0 :                     ShowContinueErrorTimeStamp(state, "...Resetting curve output to zero and continuing simulation.");
    1813              :                 }
    1814            0 :                 ShowRecurringWarningErrorAtEnd(state,
    1815            0 :                                                "GENERATOR:MICROTURBINE \"" + this->Name +
    1816              :                                                    "\": Exhaust Air Temperature Modifier (function of part-load ratio) output is less than or "
    1817              :                                                    "equal to zero warning continues...",
    1818            0 :                                                this->ExhTempFPLRErrorIndex,
    1819              :                                                ExhAirTempFPLR,
    1820              :                                                ExhAirTempFPLR);
    1821            0 :                 ExhAirTempFPLR = 0.0;
    1822              :             }
    1823              :         } else {
    1824            0 :             ExhAirTempFPLR = 1.0; // No curve input means modifier = 1.0 always
    1825              :         }
    1826              : 
    1827         8666 :         if (ExhAirMassFlowRate <= 0.0) {
    1828            0 :             this->ExhaustAirTemperature = CombustionAirInletTemp;
    1829            0 :             this->ExhaustAirHumRat = CombustionAirInletW;
    1830              :         } else {
    1831              :             //       Calculate exhaust air temperature, accounting for inlet air temperature and PLR modifier factors
    1832              :             // Actual exhaust air temperature (accounting for temp and PLR modifier curves)
    1833         8666 :             Real64 ExhaustAirTemp = this->NomExhAirOutletTemp * ExhAirTempFTemp * ExhAirTempFPLR;
    1834         8666 :             this->ExhaustAirTemperature = ExhaustAirTemp;
    1835              :             //       Adjust exhaust air temperature if heat recovery to water is being done
    1836         8666 :             if (QHeatRecToWater > 0.0) {
    1837         3360 :                 Real64 CpAir = Psychrometrics::PsyCpAirFnW(CombustionAirInletW);
    1838         3360 :                 if (CpAir > 0.0) {
    1839         3360 :                     this->ExhaustAirTemperature = ExhaustAirTemp - QHeatRecToWater / (CpAir * ExhAirMassFlowRate);
    1840              :                 }
    1841              :             }
    1842              :             //       Calculate exhaust air humidity ratio
    1843              : 
    1844              :             // Heat of vaporization of water (J/kg)
    1845         8666 :             Real64 H2OHtOfVap = Psychrometrics::PsyHfgAirFnWTdb(1.0, 16.0); // W not used, passing 1.0 as dummy.
    1846              :             // Assume fuel is at 16C (ASHRAE HOF)
    1847         8666 :             if (H2OHtOfVap > 0.0) {
    1848         8666 :                 this->ExhaustAirHumRat = CombustionAirInletW + this->FuelMdot *
    1849         8666 :                                                                    ((fuelHigherHeatingValue - fuelLowerHeatingValue) * KJtoJ / H2OHtOfVap) /
    1850              :                                                                    ExhAirMassFlowRate;
    1851              :             } else {
    1852            0 :                 this->ExhaustAirHumRat = CombustionAirInletW;
    1853              :             }
    1854              :         }
    1855              : 
    1856         8666 :         if (this->ExhaustAirTemperature < CombustionAirInletTemp) {
    1857            0 :             if (this->ExhTempLTInletTempIndex == 0) {
    1858            0 :                 ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
    1859            0 :                 ShowContinueError(state,
    1860              :                                   "...The model has calculated the exhaust air temperature to be less than the combustion air inlet temperature.");
    1861            0 :                 ShowContinueError(state, format("...Value of exhaust air temperature   ={:.4T} C.", this->ExhaustAirTemperature));
    1862            0 :                 ShowContinueError(state, format("...Value of combustion air inlet temp ={:.4T} C.", CombustionAirInletTemp));
    1863            0 :                 ShowContinueErrorTimeStamp(state, "... Simulation will continue.");
    1864              :             }
    1865            0 :             ShowRecurringWarningErrorAtEnd(state,
    1866            0 :                                            "GENERATOR:MICROTURBINE \"" + this->Name +
    1867              :                                                "\": Exhaust air temperature less than combustion air inlet temperature warning continues...",
    1868            0 :                                            this->ExhTempLTInletTempIndex,
    1869            0 :                                            this->ExhaustAirTemperature,
    1870            0 :                                            this->ExhaustAirTemperature);
    1871              :         }
    1872              : 
    1873         8666 :         if (this->ExhaustAirHumRat < CombustionAirInletW) {
    1874            0 :             if (this->ExhHRLTInletHRIndex == 0) {
    1875            0 :                 ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
    1876            0 :                 ShowContinueError(
    1877              :                     state, "...The model has calculated the exhaust air humidity ratio to be less than the combustion air inlet humidity ratio.");
    1878            0 :                 ShowContinueError(state, format("...Value of exhaust air humidity ratio          ={:.6T} kgWater/kgDryAir.", this->ExhaustAirHumRat));
    1879            0 :                 ShowContinueError(state, format("...Value of combustion air inlet humidity ratio ={:.6T} kgWater/kgDryAir.", CombustionAirInletW));
    1880            0 :                 ShowContinueErrorTimeStamp(state, "... Simulation will continue.");
    1881              :             }
    1882            0 :             ShowRecurringWarningErrorAtEnd(state,
    1883            0 :                                            "GENERATOR:MICROTURBINE \"" + this->Name +
    1884              :                                                "\": Exhaust air humidity ratio less than combustion air inlet humidity ratio warning continues...",
    1885            0 :                                            this->ExhHRLTInletHRIndex,
    1886            0 :                                            this->ExhaustAirHumRat,
    1887            0 :                                            this->ExhaustAirHumRat);
    1888              :         }
    1889              :     }
    1890              : }
    1891              : 
    1892        51343 : void MTGeneratorSpecs::UpdateMTGeneratorRecords(EnergyPlusData &state)
    1893              : {
    1894              :     // SUBROUTINE INFORMATION:
    1895              :     //       AUTHOR         R. Raustad/D. Shirey
    1896              :     //       DATE WRITTEN   Mar 2008
    1897              :     //       MODIFIED       na
    1898              :     //       RE-ENGINEERED  na
    1899              : 
    1900              :     // PURPOSE OF THIS SUBROUTINE:
    1901              :     //  Reporting and updating nodes if necessary.
    1902              : 
    1903        51343 :     if (this->HeatRecActive) {
    1904        19272 :         state.dataLoopNodes->Node(this->HeatRecOutletNodeNum).Temp = this->HeatRecOutletTemp;
    1905              :     }
    1906              : 
    1907        51343 :     if (this->ExhAirCalcsActive) {
    1908        27135 :         state.dataLoopNodes->Node(this->CombustionAirOutletNodeNum).MassFlowRate = this->ExhaustAirMassFlowRate;
    1909        27135 :         state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).MassFlowRate = this->ExhaustAirMassFlowRate;
    1910              : 
    1911        27135 :         state.dataLoopNodes->Node(this->CombustionAirOutletNodeNum).Temp = this->ExhaustAirTemperature;
    1912        27135 :         state.dataLoopNodes->Node(this->CombustionAirOutletNodeNum).HumRat = this->ExhaustAirHumRat;
    1913        27135 :         state.dataLoopNodes->Node(this->CombustionAirOutletNodeNum).MassFlowRateMaxAvail =
    1914        27135 :             state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).MassFlowRateMaxAvail;
    1915        27135 :         state.dataLoopNodes->Node(this->CombustionAirOutletNodeNum).MassFlowRateMinAvail =
    1916        27135 :             state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).MassFlowRateMinAvail;
    1917              :     }
    1918              : 
    1919        51343 :     this->EnergyGen = this->ElecPowerGenerated * state.dataHVACGlobal->TimeStepSysSec;
    1920        51343 :     this->ExhaustEnergyRec = this->QHeatRecovered * state.dataHVACGlobal->TimeStepSysSec;
    1921        51343 :     this->FuelEnergyHHV = this->FuelEnergyUseRateHHV * state.dataHVACGlobal->TimeStepSysSec;
    1922        51343 :     if (this->FuelEnergyUseRateLHV > 0.0) {
    1923        18465 :         this->ElectricEfficiencyLHV = this->ElecPowerGenerated / this->FuelEnergyUseRateLHV;
    1924        18465 :         this->ThermalEfficiencyLHV = this->QHeatRecovered / this->FuelEnergyUseRateLHV;
    1925              :     } else {
    1926        32878 :         this->ElectricEfficiencyLHV = 0.0;
    1927        32878 :         this->ThermalEfficiencyLHV = 0.0;
    1928              :     }
    1929        51343 :     this->AncillaryEnergy = this->AncillaryPowerRate * state.dataHVACGlobal->TimeStepSysSec;
    1930        51343 :     this->StandbyEnergy = this->StandbyPowerRate * state.dataHVACGlobal->TimeStepSysSec;
    1931        51343 : }
    1932        51343 : void MTGeneratorSpecs::oneTimeInit(EnergyPlusData &state)
    1933              : {
    1934              : 
    1935        51343 :     std::string const RoutineName("InitMTGenerators");
    1936              :     bool errFlag;
    1937              : 
    1938        51343 :     if (this->myFlag) {
    1939            6 :         this->setupOutputVars(state);
    1940            6 :         this->myFlag = false;
    1941              :     }
    1942              : 
    1943        51343 :     if (this->MyPlantScanFlag && allocated(state.dataPlnt->PlantLoop) && this->HeatRecActive) {
    1944            2 :         errFlag = false;
    1945            4 :         PlantUtilities::ScanPlantLoopsForObject(
    1946            2 :             state, this->Name, DataPlant::PlantEquipmentType::Generator_MicroTurbine, this->HRPlantLoc, errFlag, _, _, _, _, _);
    1947            2 :         if (errFlag) {
    1948            0 :             ShowFatalError(state, "InitMTGenerators: Program terminated due to previous condition(s).");
    1949              :         }
    1950              : 
    1951            2 :         this->MyPlantScanFlag = false;
    1952              :     }
    1953              : 
    1954        51343 :     if (this->MySizeAndNodeInitFlag && (!this->MyPlantScanFlag) && this->HeatRecActive) {
    1955              : 
    1956              :         // size mass flow rate
    1957            2 :         Real64 rho = state.dataPlnt->PlantLoop(this->HRPlantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
    1958              : 
    1959            2 :         this->DesignHeatRecMassFlowRate = rho * this->RefHeatRecVolFlowRate;
    1960            2 :         this->HeatRecMaxMassFlowRate = rho * this->HeatRecMaxVolFlowRate;
    1961              : 
    1962            2 :         PlantUtilities::InitComponentNodes(state, 0.0, this->HeatRecMaxMassFlowRate, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum);
    1963              : 
    1964            2 :         this->MySizeAndNodeInitFlag = false;
    1965              :     }
    1966        51343 : }
    1967              : 
    1968              : } // namespace EnergyPlus::MicroturbineElectricGenerator
        

Generated by: LCOV version 2.0-1