LCOV - code coverage report
Current view: top level - EnergyPlus - MicroturbineElectricGenerator.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 538 1034 52.0 %
Date: 2024-08-24 18:31:18 Functions: 9 9 100.0 %

          Line data    Source code
       1             : // EnergyPlus, Copyright (c) 1996-2024, The Board of Trustees of the University of Illinois,
       2             : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3             : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4             : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5             : // contributors. All rights reserved.
       6             : //
       7             : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8             : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9             : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10             : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11             : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12             : //
      13             : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14             : // provided that the following conditions are met:
      15             : //
      16             : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17             : //     conditions and the following disclaimer.
      18             : //
      19             : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20             : //     conditions and the following disclaimer in the documentation and/or other materials
      21             : //     provided with the distribution.
      22             : //
      23             : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24             : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25             : //     used to endorse or promote products derived from this software without specific prior
      26             : //     written permission.
      27             : //
      28             : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29             : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30             : //     reference solely to the software portion of its product, Licensee must refer to the
      31             : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32             : //     obtained under this License and may not use a different name for the software. Except as
      33             : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34             : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35             : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36             : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37             : //
      38             : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39             : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40             : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41             : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42             : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43             : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44             : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45             : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46             : // POSSIBILITY OF SUCH DAMAGE.
      47             : 
      48             : // C++ Headers
      49             : #include <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 Modifer 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           4 :             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) return;
    1132             : 
    1133             :     // Do the Begin Environment initializations
    1134       19272 :     if (state.dataGlobal->BeginEnvrnFlag && this->MyEnvrnFlag) {
    1135             :         // set the node max and min mass flow rates
    1136          16 :         PlantUtilities::InitComponentNodes(state, 0.0, this->HeatRecMaxMassFlowRate, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum);
    1137             : 
    1138          16 :         state.dataLoopNodes->Node(this->HeatRecInletNodeNum).Temp = 20.0; // Set the node temperature, assuming freeze control
    1139          16 :         state.dataLoopNodes->Node(this->HeatRecOutletNodeNum).Temp = 20.0;
    1140             : 
    1141          16 :         this->MyEnvrnFlag = false;
    1142             :     } // end environmental inits
    1143             : 
    1144       19272 :     if (!state.dataGlobal->BeginEnvrnFlag) {
    1145       18992 :         this->MyEnvrnFlag = true;
    1146             :     }
    1147             : 
    1148             :     // set/request flow rates
    1149       19272 :     if (FirstHVACIteration) {
    1150             : 
    1151             :         Real64 DesiredMassFlowRate;
    1152       12414 :         if (!RunFlag) {
    1153       10310 :             DesiredMassFlowRate = 0.0;
    1154             : 
    1155        2104 :         } else if (RunFlag && this->InternalFlowControl) {
    1156             :             // assume dispatch power in MyLoad is what gets produced (future, reset during calc routine and iterate)
    1157           0 :             if (this->HeatRecFlowFTempPowCurveNum != 0) {
    1158           0 :                 DesiredMassFlowRate =
    1159           0 :                     this->DesignHeatRecMassFlowRate *
    1160           0 :                     Curve::CurveValue(state, this->HeatRecFlowFTempPowCurveNum, state.dataLoopNodes->Node(this->HeatRecInletNodeNum).Temp, MyLoad);
    1161             :             } else {
    1162           0 :                 DesiredMassFlowRate = this->DesignHeatRecMassFlowRate; // Assume modifier = 1 if curve not specified
    1163             :             }
    1164             : 
    1165           0 :             DesiredMassFlowRate = max(DataPrecisionGlobals::constant_zero, DesiredMassFlowRate); // protect from neg. curve result
    1166             : 
    1167        2104 :         } else if (RunFlag && (!this->InternalFlowControl)) {
    1168        2104 :             DesiredMassFlowRate = this->DesignHeatRecMassFlowRate;
    1169             :         }
    1170             : 
    1171       12414 :         PlantUtilities::SetComponentFlowRate(state, DesiredMassFlowRate, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum, this->HRPlantLoc);
    1172             :     } else { // not FirstHVACIteration
    1173        6858 :         if (!RunFlag) {
    1174        5594 :             state.dataLoopNodes->Node(this->HeatRecInletNodeNum).MassFlowRate =
    1175        5594 :                 min(DataPrecisionGlobals::constant_zero, state.dataLoopNodes->Node(this->HeatRecInletNodeNum).MassFlowRateMaxAvail);
    1176        5594 :             state.dataLoopNodes->Node(this->HeatRecInletNodeNum).MassFlowRate =
    1177        5594 :                 max(DataPrecisionGlobals::constant_zero, state.dataLoopNodes->Node(this->HeatRecInletNodeNum).MassFlowRateMinAvail);
    1178             : 
    1179        1264 :         } else if (RunFlag && this->InternalFlowControl) {
    1180             :             // assume dispatch power in MyLoad is what gets produced (future, reset during calc routine and iterate)
    1181           0 :             if (this->HeatRecFlowFTempPowCurveNum != 0) {
    1182             :                 Real64 DesiredMassFlowRate =
    1183           0 :                     this->DesignHeatRecMassFlowRate *
    1184           0 :                     Curve::CurveValue(state, this->HeatRecFlowFTempPowCurveNum, state.dataLoopNodes->Node(this->HeatRecInletNodeNum).Temp, MyLoad);
    1185           0 :                 PlantUtilities::SetComponentFlowRate(
    1186           0 :                     state, DesiredMassFlowRate, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum, this->HRPlantLoc);
    1187             :             } else {
    1188           0 :                 PlantUtilities::SetComponentFlowRate(
    1189           0 :                     state, this->HeatRecMdot, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum, this->HRPlantLoc);
    1190             :             }
    1191        1264 :         } else if (RunFlag && (!this->InternalFlowControl)) {
    1192        1264 :             PlantUtilities::SetComponentFlowRate(state, this->HeatRecMdot, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum, this->HRPlantLoc);
    1193             :         }
    1194             :     }
    1195             : }
    1196             : 
    1197       51343 : void MTGeneratorSpecs::CalcMTGeneratorModel(EnergyPlusData &state,
    1198             :                                             bool const RunFlag,  // TRUE when generator is being asked to operate
    1199             :                                             Real64 const MyLoad) // Generator demand (W)
    1200             : {
    1201             :     // SUBROUTINE INFORMATION:
    1202             :     //       AUTHOR         R. Raustad/D. Shirey
    1203             :     //       DATE WRITTEN   Mar 2008
    1204             :     //       MODIFIED       na
    1205             :     //       RE-ENGINEERED  na
    1206             : 
    1207             :     // PURPOSE OF THIS SUBROUTINE:
    1208             :     //  Simulate a combustion generator.
    1209             : 
    1210             :     // METHODOLOGY EMPLOYED:
    1211             :     //  Curve fits of performance data.
    1212             : 
    1213       51343 :     Real64 constexpr KJtoJ(1000.0);          // Convert kilojoules to joules
    1214       51343 :     int constexpr MaxAncPowerIter(50);       // Maximum number of iteration (subroutine ancillary power iteration loop)
    1215       51343 :     Real64 constexpr AncPowerDiffToler(5.0); // Tolerance for Ancillary Power Difference (W)
    1216       51343 :     Real64 constexpr RelaxFactor(0.7);       // Relaxation factor for iteration loop
    1217             :     static constexpr std::string_view RoutineName("CalcMTGeneratorModel");
    1218             : 
    1219             :     //   Load local variables from data structure (for code readability)
    1220             :     // Min allowed operating fraction at full load
    1221       51343 :     Real64 minPartLoadRat = this->MinPartLoadRat;
    1222             : 
    1223             :     // Max allowed operating fraction at full load
    1224       51343 :     Real64 maxPartLoadRat = this->MaxPartLoadRat;
    1225             : 
    1226             :     // Generator reference capacity (W)
    1227       51343 :     Real64 ReferencePowerOutput = this->RefElecPowerOutput;
    1228             : 
    1229             :     // Reference electrical efficiency
    1230       51343 :     Real64 RefElecEfficiency = this->RefElecEfficiencyLHV;
    1231             : 
    1232             :     //   Initialize variables
    1233       51343 :     this->ElecPowerGenerated = 0.0;
    1234       51343 :     this->HeatRecInletTemp = 0.0;
    1235       51343 :     this->HeatRecOutletTemp = 0.0;
    1236       51343 :     this->HeatRecMdot = 0.0;
    1237       51343 :     this->QHeatRecovered = 0.0;
    1238       51343 :     this->ExhaustEnergyRec = 0.0;
    1239       51343 :     this->FuelEnergyUseRateHHV = 0.0;
    1240       51343 :     this->FuelMdot = 0.0;
    1241       51343 :     this->AncillaryPowerRate = 0.0;
    1242       51343 :     this->StandbyPowerRate = 0.0;
    1243       51343 :     this->FuelEnergyUseRateLHV = 0.0;
    1244       51343 :     this->ExhaustAirMassFlowRate = 0.0;
    1245       51343 :     this->ExhaustAirTemperature = 0.0;
    1246       51343 :     this->ExhaustAirHumRat = 0.0;
    1247             : 
    1248             :     Real64 HeatRecInTemp; // Heat recovery fluid inlet temperature (C)
    1249             :     Real64 heatRecMdot;   // Heat recovery fluid mass flow rate (kg/s)
    1250             :     Real64 HeatRecCp;     // Specific heat of the heat recovery fluid (J/kg-K)
    1251             : 
    1252       51343 :     if (this->HeatRecActive) {
    1253       19272 :         HeatRecInTemp = state.dataLoopNodes->Node(this->HeatRecInletNodeNum).Temp;
    1254       19272 :         HeatRecCp = FluidProperties::GetSpecificHeatGlycol(state,
    1255       19272 :                                                            state.dataPlnt->PlantLoop(this->HRPlantLoc.loopNum).FluidName,
    1256             :                                                            HeatRecInTemp,
    1257       19272 :                                                            state.dataPlnt->PlantLoop(this->HRPlantLoc.loopNum).FluidIndex,
    1258             :                                                            RoutineName);
    1259       19272 :         heatRecMdot = state.dataLoopNodes->Node(this->HeatRecInletNodeNum).MassFlowRate;
    1260             :     } else {
    1261       32071 :         HeatRecInTemp = 0.0;
    1262       32071 :         HeatRecCp = 0.0;
    1263       32071 :         heatRecMdot = 0.0;
    1264             :     }
    1265             : 
    1266             :     Real64 CombustionAirInletTemp;  // Combustion air inlet temperature (C)
    1267             :     Real64 CombustionAirInletPress; // Barometric pressure of combustion inlet air (Pa)
    1268             :     Real64 CombustionAirInletW;     // Combustion air inlet humidity ratio (kg/kg)
    1269             : 
    1270             :     //   Set combustion inlet air temperature, humidity ratio and pressure local variables
    1271       51343 :     if (this->CombustionAirInletNodeNum == 0) { // no inlet air node specified, so use weather file values
    1272       24208 :         CombustionAirInletTemp = state.dataEnvrn->OutDryBulbTemp;
    1273       24208 :         CombustionAirInletW = state.dataEnvrn->OutHumRat;
    1274       24208 :         CombustionAirInletPress = state.dataEnvrn->OutBaroPress;
    1275             :     } else { // use inlet node information
    1276       27135 :         CombustionAirInletTemp = state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).Temp;
    1277       27135 :         CombustionAirInletW = state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).HumRat;
    1278       27135 :         CombustionAirInletPress = state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).Press;
    1279       27135 :         if (state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).Height > 0.0) {
    1280             :         }
    1281             :         //     Initialize combustion outlet air conditions to inlet air conditions (all node properties)
    1282       27135 :         if (this->ExhAirCalcsActive) {
    1283       27135 :             state.dataLoopNodes->Node(this->CombustionAirOutletNodeNum) = state.dataLoopNodes->Node(this->CombustionAirInletNodeNum);
    1284             :         }
    1285             :     }
    1286             : 
    1287             :     //   If no loop demand or generator OFF, set some variables and then return
    1288             :     //    IF (.NOT. RunFlag .OR. MyLoad .LE. 0.0d0) THEN
    1289       51343 :     if (MyLoad <= 0.0) {
    1290       32878 :         this->HeatRecInletTemp = HeatRecInTemp;
    1291       32878 :         this->HeatRecOutletTemp = HeatRecInTemp;
    1292       32878 :         if (RunFlag) {
    1293           0 :             this->StandbyPowerRate = this->StandbyPower;
    1294             :         }
    1295       32878 :         this->ExhaustAirTemperature = CombustionAirInletTemp;
    1296       32878 :         this->ExhaustAirHumRat = CombustionAirInletW;
    1297       32878 :         return;
    1298             :     }
    1299             : 
    1300             :     //   Calculate power modifier curve value (function of inlet air temperature and elevation)
    1301             :     // Power ratio as a function of inlet air temperature and elevation
    1302       18465 :     Real64 PowerFTempElev = Curve::CurveValue(state, this->ElecPowFTempElevCurveNum, CombustionAirInletTemp, state.dataEnvrn->Elevation);
    1303             : 
    1304             :     //   Warn user if power modifier curve output is less than 0
    1305       18465 :     if (PowerFTempElev < 0.0) {
    1306           0 :         if (this->PowerFTempElevErrorIndex == 0) {
    1307             :             //        MTGenerator(GeneratorNum)%PowerFTempElevErrorCount = MTGenerator(GeneratorNum)%PowerFTempElevErrorCount + 1
    1308           0 :             ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
    1309           0 :             ShowContinueError(state,
    1310           0 :                               format("... Electrical Power Modifier curve (function of temperature and elevation) output is less than zero ({:.4T}).",
    1311             :                                      PowerFTempElev));
    1312           0 :             ShowContinueError(state, format("... Value occurs using a combustion inlet air temperature of {:.2T} C.", CombustionAirInletTemp));
    1313           0 :             ShowContinueError(state, format("... and an elevation of {:.2T} m.", state.dataEnvrn->Elevation));
    1314           0 :             ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
    1315             :         }
    1316           0 :         ShowRecurringWarningErrorAtEnd(state,
    1317           0 :                                        "GENERATOR:MICROTURBINE \"" + this->Name +
    1318             :                                            "\": Electrical Power Modifier curve is less than zero warning continues...",
    1319           0 :                                        this->PowerFTempElevErrorIndex,
    1320             :                                        PowerFTempElev,
    1321             :                                        PowerFTempElev);
    1322           0 :         PowerFTempElev = 0.0;
    1323             :     }
    1324             : 
    1325             :     //   Calculate available full-load power output. cannot exceed maximum full-load power output.
    1326             :     // Generator full-load power output at actual inlet conditions and elevation (W)
    1327       18465 :     Real64 FullLoadPowerOutput = min((ReferencePowerOutput * PowerFTempElev), this->MaxElecPowerOutput);
    1328             :     //   Also can't be below the minimum full-load power output.
    1329       18465 :     FullLoadPowerOutput = max(FullLoadPowerOutput, this->MinElecPowerOutput);
    1330             : 
    1331             :     // Ancillary power used by pump (if not specified in manufacturers data)
    1332       18465 :     Real64 ancillaryPowerRate = this->AncillaryPower;
    1333             : 
    1334             :     // Difference between ancillary power rate and ancillary power rate last (last iteration)
    1335       18465 :     Real64 AncillaryPowerRateDiff = AncPowerDiffToler + 1.0; // Initialize to force through DO WHILE Loop at least once
    1336             : 
    1337       18465 :     Real64 PLR(0.0);                    // Generator operating part load ratio
    1338       18465 :     Real64 elecPowerGenerated(0.0);     // Generator electric power output (W)
    1339       18465 :     Real64 FuelUseEnergyRateLHV(0.0);   // Rate of fuel energy required to run microturbine, LHV basis (W)
    1340       18465 :     Real64 fuelHigherHeatingValue(0.0); // Higher heating value (LLV) of fuel kJ/kg)
    1341       18465 :     Real64 fuelLowerHeatingValue(0.0);  // Lower heating value (LLV) of fuel kJ/kg)
    1342       18465 :     Real64 AnciPowerFMdotFuel(0.0);     // Ancillary power as a function of fuel flow curve output
    1343       18465 :     int AncPowerCalcIterIndex = 0;      // Index for subroutine iteration loop if Ancillary Power (function of fuel flow) is used
    1344             : 
    1345       36930 :     while (AncillaryPowerRateDiff > AncPowerDiffToler && AncPowerCalcIterIndex <= MaxAncPowerIter) {
    1346             : 
    1347       18465 :         ++AncPowerCalcIterIndex; // Increment iteration loop counter
    1348             : 
    1349             :         //     Calculate operating power output (gross)
    1350       18465 :         elecPowerGenerated = min(max(0.0, MyLoad + ancillaryPowerRate), FullLoadPowerOutput);
    1351             : 
    1352             :         //     Calculate PLR, but must be between the minPLR and maxPLR
    1353       18465 :         if (FullLoadPowerOutput > 0.0) {
    1354       18465 :             PLR = min(elecPowerGenerated / FullLoadPowerOutput, maxPartLoadRat);
    1355       18465 :             PLR = max(PLR, minPartLoadRat);
    1356             :         } else {
    1357           0 :             PLR = 0.0;
    1358             :         }
    1359             : 
    1360             :         //     Recalculate elecPowerGenerated based on "final" PLR
    1361       18465 :         elecPowerGenerated = FullLoadPowerOutput * PLR;
    1362             : 
    1363             :         //     Calculate electrical efficiency modifier curve output (function of temp)
    1364             :         // Electrical efficiency as a function of temperature curve output
    1365       18465 :         Real64 ElecEfficiencyFTemp = Curve::CurveValue(state, this->ElecEffFTempCurveNum, CombustionAirInletTemp);
    1366             : 
    1367             :         //     Warn user if efficiency modifier curve output is less than 0
    1368       18465 :         if (ElecEfficiencyFTemp < 0.0) {
    1369           0 :             if (this->EffFTempErrorIndex == 0) {
    1370             :                 //          MTGenerator(GeneratorNum)%EffFTempErrorCount = MTGenerator(GeneratorNum)%EffFTempErrorCount + 1
    1371           0 :                 ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
    1372           0 :                 ShowContinueError(
    1373             :                     state,
    1374           0 :                     format("... Electrical Efficiency Modifier (function of temperature) output is less than zero ({:.4T}).", ElecEfficiencyFTemp));
    1375           0 :                 ShowContinueError(state, format("... Value occurs using a combustion inlet air temperature of {:.2T} C.", CombustionAirInletTemp));
    1376           0 :                 ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
    1377             :             }
    1378           0 :             ShowRecurringWarningErrorAtEnd(
    1379             :                 state,
    1380           0 :                 "GENERATOR:MICROTURBINE \"" + this->Name +
    1381             :                     "\": Electrical Efficiency Modifier (function of temperature) output is less than zero warning continues...",
    1382           0 :                 this->EffFTempErrorIndex,
    1383             :                 ElecEfficiencyFTemp,
    1384             :                 ElecEfficiencyFTemp);
    1385           0 :             ElecEfficiencyFTemp = 0.0;
    1386             :         }
    1387             : 
    1388             :         //     Calculate efficiency modifier curve output (function of PLR)
    1389             :         // Electrical efficiency as a function of PLR curve output
    1390       18465 :         Real64 ElecEfficiencyFPLR = Curve::CurveValue(state, this->ElecEffFPLRCurveNum, PLR);
    1391             : 
    1392             :         //     Warn user if efficiency modifier curve output is less than 0
    1393       18465 :         if (ElecEfficiencyFPLR < 0.0) {
    1394           0 :             if (this->EffFPLRErrorIndex == 0) {
    1395           0 :                 ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
    1396           0 :                 ShowContinueError(state,
    1397           0 :                                   format("... Electrical Efficiency Modifier (function of part-load ratio) output is less than zero ({:.4T}).",
    1398             :                                          ElecEfficiencyFPLR));
    1399           0 :                 ShowContinueError(state, format("... Value occurs using a part-load ratio of {:.3T}.", PLR));
    1400           0 :                 ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
    1401             :             }
    1402           0 :             ShowRecurringWarningErrorAtEnd(
    1403             :                 state,
    1404           0 :                 "GENERATOR:MICROTURBINE \"" + this->Name +
    1405             :                     "\": Electrical Efficiency Modifier (function of part-load ratio) output is less than zero warning continues...",
    1406           0 :                 this->EffFPLRErrorIndex,
    1407             :                 ElecEfficiencyFPLR,
    1408             :                 ElecEfficiencyFPLR);
    1409           0 :             ElecEfficiencyFPLR = 0.0;
    1410             :         }
    1411             : 
    1412             :         //     Calculate operating electrical efficiency
    1413             :         // Actual operating efficiency
    1414       18465 :         Real64 OperatingElecEfficiency = RefElecEfficiency * ElecEfficiencyFTemp * ElecEfficiencyFPLR;
    1415             : 
    1416             :         //     Calculate fuel use (W = J/s), LHV basis
    1417       18465 :         if (OperatingElecEfficiency > 0.0) {
    1418       18465 :             FuelUseEnergyRateLHV = elecPowerGenerated / OperatingElecEfficiency;
    1419             :         } else {
    1420           0 :             FuelUseEnergyRateLHV = 0.0; // If fuel use rate is zero, then
    1421           0 :             elecPowerGenerated = 0.0;   //  electric power generated must be zero.
    1422             :         }
    1423             : 
    1424             :         //     Set fuel heating values
    1425       18465 :         fuelHigherHeatingValue = this->FuelHigherHeatingValue;
    1426       18465 :         fuelLowerHeatingValue = this->FuelLowerHeatingValue;
    1427             : 
    1428             :         //     Calculate fuel mass flow rate
    1429       18465 :         this->FuelMdot = FuelUseEnergyRateLHV / (fuelLowerHeatingValue * KJtoJ);
    1430             : 
    1431             :         //     Calculate ancillary power requirement
    1432       18465 :         if (this->AncillaryPowerFuelCurveNum > 0) {
    1433           0 :             AnciPowerFMdotFuel = Curve::CurveValue(state, this->AncillaryPowerFuelCurveNum, this->FuelMdot);
    1434             :             //       Warn user if ancillary power modifier curve output is less than 0
    1435           0 :             if (AnciPowerFMdotFuel < 0.0) {
    1436           0 :                 if (this->AnciPowerFMdotFuelErrorIndex == 0) {
    1437           0 :                     ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
    1438           0 :                     ShowContinueError(
    1439             :                         state,
    1440           0 :                         format("... Ancillary Power Modifier (function of fuel input) output is less than zero ({:.4T}).", AnciPowerFMdotFuel));
    1441           0 :                     ShowContinueError(state, format("... Value occurs using a fuel input mass flow rate of {:.4T} kg/s.", this->FuelMdot));
    1442           0 :                     ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
    1443             :                 }
    1444           0 :                 ShowRecurringWarningErrorAtEnd(
    1445             :                     state,
    1446           0 :                     "GENERATOR:MICROTURBINE \"" + this->Name +
    1447             :                         "\": Ancillary Power Modifier (function of fuel input) output is less than zero warning continues...",
    1448           0 :                     this->AnciPowerFMdotFuelErrorIndex,
    1449             :                     AnciPowerFMdotFuel,
    1450             :                     AnciPowerFMdotFuel);
    1451           0 :                 AnciPowerFMdotFuel = 0.0;
    1452             :             }
    1453             :         } else {
    1454       18465 :             AnciPowerFMdotFuel = 1.0;
    1455             :         }
    1456             : 
    1457             :         // Ancillary power used by pump from last iteration (iteration loop within this subroutine)
    1458       18465 :         Real64 AncillaryPowerRateLast = ancillaryPowerRate;
    1459             : 
    1460       18465 :         if (this->AncillaryPowerFuelCurveNum > 0) {
    1461           0 :             ancillaryPowerRate = RelaxFactor * this->AncillaryPower * AnciPowerFMdotFuel - (1.0 - RelaxFactor) * AncillaryPowerRateLast;
    1462             :         }
    1463             : 
    1464       18465 :         AncillaryPowerRateDiff = std::abs(ancillaryPowerRate - AncillaryPowerRateLast);
    1465             :     }
    1466             : 
    1467       18465 :     if (AncPowerCalcIterIndex > MaxAncPowerIter) {
    1468             : 
    1469           0 :         if (this->AnciPowerIterErrorIndex == 0) {
    1470           0 :             ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
    1471           0 :             ShowContinueError(state, "... Iteration loop for electric power generation is not converging within tolerance.");
    1472           0 :             ShowContinueError(state, "... Check the Ancillary Power Modifier Curve (function of fuel input).");
    1473           0 :             ShowContinueError(state, format("... Ancillary Power = {:.1T} W.", ancillaryPowerRate));
    1474           0 :             ShowContinueError(state, format("... Fuel input rate = {:.4T} kg/s.", AnciPowerFMdotFuel));
    1475           0 :             ShowContinueErrorTimeStamp(state, "... Simulation will continue.");
    1476             :         }
    1477           0 :         ShowRecurringWarningErrorAtEnd(state,
    1478           0 :                                        "GENERATOR:MICROTURBINE \"" + this->Name +
    1479             :                                            "\": Iteration loop for electric power generation is not converging within tolerance continues...",
    1480           0 :                                        this->AnciPowerIterErrorIndex);
    1481             :     }
    1482             : 
    1483             :     //   Calculate electrical power generated
    1484       18465 :     this->ElecPowerGenerated = elecPowerGenerated - ancillaryPowerRate;
    1485             : 
    1486             :     //   Report fuel energy use rate on HHV basis, which is the unit of measure when the fuel is sold
    1487       18465 :     this->FuelEnergyUseRateHHV = this->FuelMdot * fuelHigherHeatingValue * KJtoJ;
    1488       18465 :     this->AncillaryPowerRate = ancillaryPowerRate;     // Move to data structure for later reporting
    1489       18465 :     this->FuelEnergyUseRateLHV = FuelUseEnergyRateLHV; // Move to data structure for reporting calculations
    1490             : 
    1491             :     //   When generator operates, standby losses are 0
    1492       18465 :     this->StandbyPowerRate = 0.0;
    1493             : 
    1494       18465 :     Real64 QHeatRecToWater = 0.0; // Recovered waste heat to water (W)
    1495             : 
    1496             :     //   Calculate heat recovery if active
    1497       18465 :     if (this->HeatRecActive) {
    1498             : 
    1499             :         // Thermal efficiency as a function of air temperature and elevation
    1500             :         Real64 ThermalEffFTempElev;
    1501        3368 :         if (this->ThermEffFTempElevCurveNum > 0) {
    1502        3368 :             ThermalEffFTempElev = Curve::CurveValue(state, this->ThermEffFTempElevCurveNum, CombustionAirInletTemp, state.dataEnvrn->Elevation);
    1503             :             //       Warn user if power modifier curve output is less than 0
    1504        3368 :             if (ThermalEffFTempElev < 0.0) {
    1505           0 :                 if (this->ThermEffFTempElevErrorIndex == 0) {
    1506           0 :                     ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
    1507           0 :                     ShowContinueError(
    1508             :                         state,
    1509           0 :                         format("... Electrical Power Modifier curve (function of temperature and elevation) output is less than zero ({:.4T}).",
    1510             :                                PowerFTempElev));
    1511           0 :                     ShowContinueError(state,
    1512           0 :                                       format("... Value occurs using a combustion inlet air temperature of {:.2T} C.", CombustionAirInletTemp));
    1513           0 :                     ShowContinueError(state, format("... and an elevation of {:.2T} m.", state.dataEnvrn->Elevation));
    1514           0 :                     ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
    1515             :                 }
    1516           0 :                 ShowRecurringWarningErrorAtEnd(state,
    1517           0 :                                                "GENERATOR:MICROTURBINE \"" + this->Name +
    1518             :                                                    "\": Electrical Power Modifier curve is less than zero warning continues...",
    1519           0 :                                                this->ThermEffFTempElevErrorIndex,
    1520             :                                                ThermalEffFTempElev,
    1521             :                                                ThermalEffFTempElev);
    1522           0 :                 ThermalEffFTempElev = 0.0;
    1523             :             }
    1524             :         } else {
    1525           0 :             ThermalEffFTempElev = 1.0; // If no curve provided, assume multiplier factor = 1.0
    1526             :         }
    1527             : 
    1528        3368 :         QHeatRecToWater = FuelUseEnergyRateLHV * this->RefThermalEffLHV * ThermalEffFTempElev;
    1529             :         Real64 HeatRecRateFPLR; // Heat recovery rate as a function of PLR curve output
    1530             : 
    1531             :         //     Calculate heat recovery rate modifier curve output (function of PLR)
    1532        3368 :         if (this->HeatRecRateFPLRCurveNum > 0) {
    1533        3368 :             HeatRecRateFPLR = Curve::CurveValue(state, this->HeatRecRateFPLRCurveNum, PLR);
    1534             :             //       Warn user if heat recovery modifier curve output is less than 0
    1535        3368 :             if (HeatRecRateFPLR < 0.0) {
    1536           0 :                 if (this->HeatRecRateFPLRErrorIndex == 0) {
    1537           0 :                     ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
    1538           0 :                     ShowContinueError(
    1539             :                         state,
    1540           0 :                         format("... Heat Recovery Rate Modifier (function of part-load ratio) output is less than zero ({:.4T}).", HeatRecRateFPLR));
    1541           0 :                     ShowContinueError(state, format("... Value occurs using a part-load ratio of {:.3T}.", PLR));
    1542           0 :                     ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
    1543             :                 }
    1544           0 :                 ShowRecurringWarningErrorAtEnd(
    1545             :                     state,
    1546           0 :                     "GENERATOR:MICROTURBINE \"" + this->Name +
    1547             :                         "\": Heat Recovery Rate Modifier (function of part-load ratio) output is less than zero warning continues...",
    1548           0 :                     this->HeatRecRateFPLRErrorIndex,
    1549             :                     HeatRecRateFPLR,
    1550             :                     HeatRecRateFPLR);
    1551           0 :                 HeatRecRateFPLR = 0.0;
    1552             :             }
    1553             :         } else {
    1554           0 :             HeatRecRateFPLR = 1.0; // If no curve provided, assume multiplier factor = 1.0
    1555             :         }
    1556             : 
    1557             :         Real64 HeatRecRateFTemp; // Heat recovery rate as a function of inlet water temp curve output
    1558             : 
    1559             :         //     Calculate heat recovery rate modifier curve output (function of inlet water temp)
    1560        3368 :         if (this->HeatRecRateFTempCurveNum > 0) {
    1561        3368 :             HeatRecRateFTemp = Curve::CurveValue(state, this->HeatRecRateFTempCurveNum, HeatRecInTemp);
    1562        3368 :             if (HeatRecRateFTemp < 0.0) {
    1563           0 :                 if (this->HeatRecRateFTempErrorIndex == 0) {
    1564           0 :                     ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
    1565           0 :                     ShowContinueError(state,
    1566           0 :                                       format("... Heat Recovery Rate Modifier (function of inlet water temp) output is less than zero ({:.4T}).",
    1567             :                                              HeatRecRateFTemp));
    1568           0 :                     ShowContinueError(state, format("... Value occurs using an inlet water temperature temperature of {:.2T} C.", HeatRecInTemp));
    1569           0 :                     ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
    1570             :                 }
    1571           0 :                 ShowRecurringWarningErrorAtEnd(
    1572             :                     state,
    1573           0 :                     "GENERATOR:MICROTURBINE \"" + this->Name +
    1574             :                         "\": Heat Recovery Rate Modifier (function of inlet water temp) output is less than zero warning continues...",
    1575           0 :                     this->HeatRecRateFTempErrorIndex,
    1576             :                     HeatRecRateFTemp,
    1577             :                     HeatRecRateFTemp);
    1578           0 :                 HeatRecRateFTemp = 0.0;
    1579             :             }
    1580             :         } else {
    1581           0 :             HeatRecRateFTemp = 1.0; // If no curve provided, assume multiplier factor = 1.0
    1582             :         }
    1583             : 
    1584             :         Real64 HeatRecRateFFlow; // Heat recovery rate as a function of water flow rate curve output
    1585             : 
    1586             :         //     Calculate heat recovery rate modifier curve output (function of water [volumetric] flow rate)
    1587        3368 :         if (this->HeatRecRateFWaterFlowCurveNum > 0) {
    1588        3368 :             Real64 rho = FluidProperties::GetDensityGlycol(state,
    1589        3368 :                                                            state.dataPlnt->PlantLoop(this->HRPlantLoc.loopNum).FluidName,
    1590             :                                                            HeatRecInTemp,
    1591        3368 :                                                            state.dataPlnt->PlantLoop(this->HRPlantLoc.loopNum).FluidIndex,
    1592             :                                                            RoutineName);
    1593             : 
    1594             :             // Heat recovery fluid flow rate (m3/s)
    1595        3368 :             Real64 HeatRecVolFlowRate = heatRecMdot / rho;
    1596        3368 :             HeatRecRateFFlow = Curve::CurveValue(state, this->HeatRecRateFWaterFlowCurveNum, HeatRecVolFlowRate);
    1597        3368 :             if (HeatRecRateFFlow < 0.0) {
    1598           0 :                 if (this->HeatRecRateFFlowErrorIndex == 0) {
    1599           0 :                     ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
    1600           0 :                     ShowContinueError(
    1601             :                         state,
    1602           0 :                         format("... Heat Recovery Rate Modifier (function of water flow rate) output is less than zero ({:.4T}).", HeatRecRateFFlow));
    1603           0 :                     ShowContinueError(state, format("... Value occurs using a water flow rate of {:.4T} m3/s.", HeatRecVolFlowRate));
    1604           0 :                     ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
    1605             :                 }
    1606           0 :                 ShowRecurringWarningErrorAtEnd(
    1607             :                     state,
    1608           0 :                     "GENERATOR:MICROTURBINE \"" + this->Name +
    1609             :                         "\": Heat Recovery Rate Modifier (function of water flow rate) output is less than zero warning continues...",
    1610           0 :                     this->HeatRecRateFFlowErrorIndex,
    1611             :                     HeatRecRateFFlow,
    1612             :                     HeatRecRateFFlow);
    1613           0 :                 HeatRecRateFFlow = 0.0;
    1614             :             }
    1615             :         } else {
    1616           0 :             HeatRecRateFFlow = 1.0; // If no curve provided, assume multiplier factor = 1.0
    1617             :         }
    1618             : 
    1619        3368 :         QHeatRecToWater *= HeatRecRateFPLR * HeatRecRateFTemp * HeatRecRateFFlow;
    1620             : 
    1621             :         Real64 HeatRecOutTemp; // Heat recovery fluid outlet temperature (C)
    1622             : 
    1623             :         //     Check for divide by zero
    1624        3368 :         if ((heatRecMdot > 0.0) && (HeatRecCp > 0.0)) {
    1625        3368 :             HeatRecOutTemp = HeatRecInTemp + QHeatRecToWater / (heatRecMdot * HeatRecCp);
    1626             :         } else {
    1627           0 :             heatRecMdot = 0.0;
    1628           0 :             HeatRecOutTemp = HeatRecInTemp;
    1629           0 :             QHeatRecToWater = 0.0;
    1630             :         }
    1631             : 
    1632             :         //     Now verify the maximum heat recovery temperature was not exceeded
    1633        3368 :         if (HeatRecOutTemp > this->HeatRecMaxWaterTemp) {
    1634             : 
    1635        1659 :             Real64 MinHeatRecMdot = 0.0; // Heat recovery flow rate if minimal heat recovery is accomplished (kg/s)
    1636             : 
    1637        1659 :             if (this->HeatRecMaxWaterTemp != HeatRecInTemp) {
    1638        1659 :                 MinHeatRecMdot = QHeatRecToWater / (HeatRecCp * (this->HeatRecMaxWaterTemp - HeatRecInTemp));
    1639        1659 :                 if (MinHeatRecMdot < 0.0) MinHeatRecMdot = 0.0;
    1640             :             }
    1641             : 
    1642             :             //       Recalculate outlet water temperature with minimum flow rate (will normally match the max water outlet temp,
    1643             :             //       unless the inlet water temp is greater than the max outlet temp)
    1644             :             Real64 HRecRatio; // When maximum temperature is reached the amount of recovered heat has to be reduced
    1645             : 
    1646        1659 :             if ((MinHeatRecMdot > 0.0) && (HeatRecCp > 0.0)) {
    1647        1651 :                 HeatRecOutTemp = QHeatRecToWater / (MinHeatRecMdot * HeatRecCp) + HeatRecInTemp;
    1648        1651 :                 HRecRatio = heatRecMdot / MinHeatRecMdot;
    1649             :             } else {
    1650           8 :                 HeatRecOutTemp = HeatRecInTemp;
    1651           8 :                 HRecRatio = 0.0;
    1652             :             }
    1653        1659 :             QHeatRecToWater *= HRecRatio; // Scale heat recovery rate using HRecRatio. Don't adjust flow rate.
    1654             :         }
    1655             : 
    1656             :         //     Check water mass flow rate against minimum
    1657        3368 :         if (this->HeatRecMinMassFlowRate > heatRecMdot && heatRecMdot > 0.0) {
    1658           0 :             if (this->HRMinFlowErrorIndex == 0) {
    1659           0 :                 ShowWarningError(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
    1660           0 :                 ShowContinueError(state,
    1661           0 :                                   format("...Heat reclaim water flow rate is below the generators minimum mass flow rate of ({:.4T}).",
    1662           0 :                                          this->HeatRecMinMassFlowRate));
    1663           0 :                 ShowContinueError(state, format("...Heat reclaim water mass flow rate = {:.4T}.", heatRecMdot));
    1664           0 :                 ShowContinueErrorTimeStamp(state, "...Check inputs for heat recovery water flow rate.");
    1665             :             }
    1666           0 :             ShowRecurringWarningErrorAtEnd(
    1667             :                 state,
    1668           0 :                 "GENERATOR:MICROTURBINE \"" + this->Name +
    1669             :                     "\": Heat recovery water flow rate is below the generators minimum mass flow rate warning continues...",
    1670           0 :                 this->HRMinFlowErrorIndex,
    1671             :                 heatRecMdot,
    1672             :                 heatRecMdot);
    1673             :         }
    1674             : 
    1675             :         //     Check water mass flow rate against maximum
    1676        3368 :         if (heatRecMdot > this->HeatRecMaxMassFlowRate && heatRecMdot > 0.0) {
    1677           0 :             if (this->HRMaxFlowErrorIndex == 0) {
    1678           0 :                 ShowWarningError(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
    1679           0 :                 ShowContinueError(state,
    1680           0 :                                   format("...Heat reclaim water flow rate is above the generators maximum mass flow rate of ({:.4T}).",
    1681           0 :                                          this->HeatRecMaxMassFlowRate));
    1682           0 :                 ShowContinueError(state, format("...Heat reclaim water mass flow rate = {:.4T}.", heatRecMdot));
    1683           0 :                 ShowContinueErrorTimeStamp(state, "...Check inputs for heat recovery water flow rate.");
    1684             :             }
    1685           0 :             ShowRecurringWarningErrorAtEnd(
    1686             :                 state,
    1687           0 :                 "GENERATOR:MICROTURBINE \"" + this->Name +
    1688             :                     "\": Heat recovery water flow rate is above the generators maximum mass flow rate warning continues...",
    1689           0 :                 this->HRMaxFlowErrorIndex,
    1690             :                 heatRecMdot,
    1691             :                 heatRecMdot);
    1692             :         }
    1693             : 
    1694             :         //     Set report variables
    1695        3368 :         this->HeatRecInletTemp = HeatRecInTemp;
    1696        3368 :         this->HeatRecOutletTemp = HeatRecOutTemp;
    1697        3368 :         this->HeatRecMdot = heatRecMdot;
    1698        3368 :         this->QHeatRecovered = QHeatRecToWater;
    1699             : 
    1700             :     } // End of  IF (MTGenerator(GeneratorNum)%HeatRecActive) THEN
    1701             : 
    1702             :     //   Calculate combustion air outlet conditions if exhaust air calculations are active
    1703       18465 :     if (this->ExhAirCalcsActive) {
    1704             : 
    1705             :         Real64 ExhFlowFTemp; // Exhaust air flow rate as a function of temperature curve output
    1706             : 
    1707        8666 :         if (this->ExhFlowFTempCurveNum != 0) { // Exhaust Flow Rate versus Inlet Air Temp
    1708        8666 :             ExhFlowFTemp = Curve::CurveValue(state, this->ExhFlowFTempCurveNum, CombustionAirInletTemp);
    1709             :             //       Warn user if exhaust modifier curve output is less than or equal to 0
    1710        8666 :             if (ExhFlowFTemp <= 0.0) {
    1711           0 :                 if (this->ExhFlowFTempErrorIndex == 0) {
    1712           0 :                     ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
    1713           0 :                     ShowContinueError(
    1714             :                         state,
    1715           0 :                         format("...Exhaust Air Flow Rate Modifier (function of temperature) output is less than or equal to zero ({:.4T}).",
    1716             :                                ExhFlowFTemp));
    1717           0 :                     ShowContinueError(state, format("...Value occurs using a combustion inlet air temperature of {:.2T}.", CombustionAirInletTemp));
    1718           0 :                     ShowContinueErrorTimeStamp(state, "...Resetting curve output to zero and continuing simulation.");
    1719             :                 }
    1720           0 :                 ShowRecurringWarningErrorAtEnd(
    1721             :                     state,
    1722           0 :                     "GENERATOR:MICROTURBINE \"" + this->Name +
    1723             :                         "\": Exhaust Air Flow Rate Modifier (function of temperature) output is less than or equal to zero warning continues...",
    1724           0 :                     this->ExhFlowFTempErrorIndex,
    1725             :                     ExhFlowFTemp,
    1726             :                     ExhFlowFTemp);
    1727           0 :                 ExhFlowFTemp = 0.0;
    1728             :             }
    1729             :         } else {
    1730           0 :             ExhFlowFTemp = 1.0; // No curve input means modifier = 1.0 always
    1731             :         }
    1732             : 
    1733             :         Real64 ExhFlowFPLR; // Exhaust air flow rate as a function of part-load ratio curve output
    1734             : 
    1735        8666 :         if (this->ExhFlowFPLRCurveNum != 0) { // Exhaust Flow Rate versus Part-Load Ratio
    1736        8666 :             ExhFlowFPLR = Curve::CurveValue(state, this->ExhFlowFPLRCurveNum, PLR);
    1737             :             //       Warn user if exhaust modifier curve output is less than or equal to 0
    1738        8666 :             if (ExhFlowFPLR <= 0.0) {
    1739           0 :                 if (this->ExhFlowFPLRErrorIndex == 0) {
    1740           0 :                     ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
    1741           0 :                     ShowContinueError(
    1742             :                         state,
    1743           0 :                         format("...Exhaust Air Flow Rate Modifier (function of part-load ratio) output is less than or equal to zero ({:.4T}).",
    1744             :                                ExhFlowFPLR));
    1745           0 :                     ShowContinueError(state, format("...Value occurs using a part-load ratio of {:.2T}.", PLR));
    1746           0 :                     ShowContinueErrorTimeStamp(state, "...Resetting curve output to zero and continuing simulation.");
    1747             :                 }
    1748           0 :                 ShowRecurringWarningErrorAtEnd(state,
    1749           0 :                                                "GENERATOR:MICROTURBINE \"" + this->Name +
    1750             :                                                    "\": Exhaust Air Flow Rate Modifier (function of part-load ratio) output is less than or "
    1751             :                                                    "equal to zero warning continues...",
    1752           0 :                                                this->ExhFlowFPLRErrorIndex,
    1753             :                                                ExhFlowFPLR,
    1754             :                                                ExhFlowFPLR);
    1755           0 :                 ExhFlowFPLR = 0.0;
    1756             :             }
    1757             :         } else {
    1758           0 :             ExhFlowFPLR = 1.0; // No curve input means modifier = 1.0 always
    1759             :         }
    1760             : 
    1761             :         //     Calculate exhaust air mass flow, accounting for temperature and PLR modifier factors
    1762             :         // Actual exhaust air mass flow rate (accounting for temp and PLR modifier curves)
    1763        8666 :         Real64 ExhAirMassFlowRate = this->RefExhaustAirMassFlowRate * ExhFlowFTemp * ExhFlowFPLR;
    1764             :         //     Adjust for difference in air density at reference conditions versus actual inlet air conditions
    1765             : 
    1766             :         // Density of air at actual combustion inlet air conditions (kg/m3)
    1767        8666 :         Real64 AirDensity = Psychrometrics::PsyRhoAirFnPbTdbW(state, CombustionAirInletPress, CombustionAirInletTemp, CombustionAirInletW);
    1768        8666 :         if (this->RefCombustAirInletDensity >= 0.0) {
    1769        8666 :             ExhAirMassFlowRate = max(0.0, ExhAirMassFlowRate * AirDensity / this->RefCombustAirInletDensity);
    1770             :         } else {
    1771           0 :             ExhAirMassFlowRate = 0.0;
    1772             :         }
    1773        8666 :         this->ExhaustAirMassFlowRate = ExhAirMassFlowRate;
    1774             : 
    1775             :         Real64 ExhAirTempFTemp; // Exhaust air temperature as a function of inlet air temp curve output
    1776             : 
    1777        8666 :         if (this->ExhAirTempFTempCurveNum != 0) { // Exhaust Air Temp versus Inlet Air Temp
    1778        8666 :             ExhAirTempFTemp = Curve::CurveValue(state, this->ExhAirTempFTempCurveNum, CombustionAirInletTemp);
    1779             :             //       Warn user if exhaust modifier curve output is less than or equal to 0
    1780        8666 :             if (ExhAirTempFTemp <= 0.0) {
    1781           0 :                 if (this->ExhTempFTempErrorIndex == 0) {
    1782           0 :                     ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
    1783           0 :                     ShowContinueError(
    1784             :                         state,
    1785           0 :                         format("...Exhaust Air Temperature Modifier (function of temperature) output is less than or equal to zero ({:.4T}).",
    1786             :                                ExhAirTempFTemp));
    1787           0 :                     ShowContinueError(state, format("...Value occurs using a combustion inlet air temperature of {:.2T}.", CombustionAirInletTemp));
    1788           0 :                     ShowContinueErrorTimeStamp(state, "...Resetting curve output to zero and continuing simulation.");
    1789             :                 }
    1790           0 :                 ShowRecurringWarningErrorAtEnd(state,
    1791           0 :                                                "GENERATOR:MICROTURBINE \"" + this->Name +
    1792             :                                                    "\": Exhaust Air Temperature Modifier (function of temperature) output is less than or equal "
    1793             :                                                    "to zero warning continues...",
    1794           0 :                                                this->ExhTempFTempErrorIndex,
    1795             :                                                ExhAirTempFTemp,
    1796             :                                                ExhAirTempFTemp);
    1797           0 :                 ExhAirTempFTemp = 0.0;
    1798             :             }
    1799             :         } else {
    1800           0 :             ExhAirTempFTemp = 1.0; // No curve input means modifier = 1.0 always
    1801             :         }
    1802             : 
    1803             :         Real64 ExhAirTempFPLR; // Exhaust air temperature as a function of part-load ratio curve output
    1804             : 
    1805        8666 :         if (this->ExhAirTempFPLRCurveNum != 0) { // Exhaust Air Temp versus Part-Load Ratio
    1806        8666 :             ExhAirTempFPLR = Curve::CurveValue(state, this->ExhAirTempFPLRCurveNum, PLR);
    1807             :             //       Warn user if exhaust modifier curve output is less than or equal to 0
    1808        8666 :             if (ExhAirTempFPLR <= 0.0) {
    1809           0 :                 if (this->ExhTempFPLRErrorIndex == 0) {
    1810           0 :                     ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
    1811           0 :                     ShowContinueError(
    1812             :                         state,
    1813           0 :                         format("...Exhaust Air Temperature Modifier (function of part-load ratio) output is less than or equal to zero ({:.4T}).",
    1814             :                                ExhAirTempFPLR));
    1815           0 :                     ShowContinueError(state, format("...Value occurs using a part-load ratio of {:.2T}.", PLR));
    1816           0 :                     ShowContinueErrorTimeStamp(state, "...Resetting curve output to zero and continuing simulation.");
    1817             :                 }
    1818           0 :                 ShowRecurringWarningErrorAtEnd(state,
    1819           0 :                                                "GENERATOR:MICROTURBINE \"" + this->Name +
    1820             :                                                    "\": Exhaust Air Temperature Modifier (function of part-load ratio) output is less than or "
    1821             :                                                    "equal to zero warning continues...",
    1822           0 :                                                this->ExhTempFPLRErrorIndex,
    1823             :                                                ExhAirTempFPLR,
    1824             :                                                ExhAirTempFPLR);
    1825           0 :                 ExhAirTempFPLR = 0.0;
    1826             :             }
    1827             :         } else {
    1828           0 :             ExhAirTempFPLR = 1.0; // No curve input means modifier = 1.0 always
    1829             :         }
    1830             : 
    1831        8666 :         if (ExhAirMassFlowRate <= 0.0) {
    1832           0 :             this->ExhaustAirTemperature = CombustionAirInletTemp;
    1833           0 :             this->ExhaustAirHumRat = CombustionAirInletW;
    1834             :         } else {
    1835             :             //       Calculate exhaust air temperature, accounting for inlet air temperature and PLR modifier factors
    1836             :             // Actual exhaust air temperature (accounting for temp and PLR modifier curves)
    1837        8666 :             Real64 ExhaustAirTemp = this->NomExhAirOutletTemp * ExhAirTempFTemp * ExhAirTempFPLR;
    1838        8666 :             this->ExhaustAirTemperature = ExhaustAirTemp;
    1839             :             //       Adjust exhaust air temperature if heat recovery to water is being done
    1840        8666 :             if (QHeatRecToWater > 0.0) {
    1841        3360 :                 Real64 CpAir = Psychrometrics::PsyCpAirFnW(CombustionAirInletW);
    1842        3360 :                 if (CpAir > 0.0) {
    1843        3360 :                     this->ExhaustAirTemperature = ExhaustAirTemp - QHeatRecToWater / (CpAir * ExhAirMassFlowRate);
    1844             :                 }
    1845             :             }
    1846             :             //       Calculate exhaust air humidity ratio
    1847             : 
    1848             :             // Heat of vaporization of water (J/kg)
    1849        8666 :             Real64 H2OHtOfVap = Psychrometrics::PsyHfgAirFnWTdb(1.0, 16.0); // W not used, passing 1.0 as dummy.
    1850             :             // Assume fuel is at 16C (ASHRAE HOF)
    1851        8666 :             if (H2OHtOfVap > 0.0) {
    1852        8666 :                 this->ExhaustAirHumRat = CombustionAirInletW + this->FuelMdot *
    1853        8666 :                                                                    ((fuelHigherHeatingValue - fuelLowerHeatingValue) * KJtoJ / H2OHtOfVap) /
    1854             :                                                                    ExhAirMassFlowRate;
    1855             :             } else {
    1856           0 :                 this->ExhaustAirHumRat = CombustionAirInletW;
    1857             :             }
    1858             :         }
    1859             : 
    1860        8666 :         if (this->ExhaustAirTemperature < CombustionAirInletTemp) {
    1861           0 :             if (this->ExhTempLTInletTempIndex == 0) {
    1862           0 :                 ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
    1863           0 :                 ShowContinueError(state,
    1864             :                                   "...The model has calculated the exhaust air temperature to be less than the combustion air inlet temperature.");
    1865           0 :                 ShowContinueError(state, format("...Value of exhaust air temperature   ={:.4T} C.", this->ExhaustAirTemperature));
    1866           0 :                 ShowContinueError(state, format("...Value of combustion air inlet temp ={:.4T} C.", CombustionAirInletTemp));
    1867           0 :                 ShowContinueErrorTimeStamp(state, "... Simulation will continue.");
    1868             :             }
    1869           0 :             ShowRecurringWarningErrorAtEnd(state,
    1870           0 :                                            "GENERATOR:MICROTURBINE \"" + this->Name +
    1871             :                                                "\": Exhaust air temperature less than combustion air inlet temperature warning continues...",
    1872           0 :                                            this->ExhTempLTInletTempIndex,
    1873           0 :                                            this->ExhaustAirTemperature,
    1874           0 :                                            this->ExhaustAirTemperature);
    1875             :         }
    1876             : 
    1877        8666 :         if (this->ExhaustAirHumRat < CombustionAirInletW) {
    1878           0 :             if (this->ExhHRLTInletHRIndex == 0) {
    1879           0 :                 ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
    1880           0 :                 ShowContinueError(
    1881             :                     state, "...The model has calculated the exhaust air humidity ratio to be less than the combustion air inlet humidity ratio.");
    1882           0 :                 ShowContinueError(state, format("...Value of exhaust air humidity ratio          ={:.6T} kgWater/kgDryAir.", this->ExhaustAirHumRat));
    1883           0 :                 ShowContinueError(state, format("...Value of combustion air inlet humidity ratio ={:.6T} kgWater/kgDryAir.", CombustionAirInletW));
    1884           0 :                 ShowContinueErrorTimeStamp(state, "... Simulation will continue.");
    1885             :             }
    1886           0 :             ShowRecurringWarningErrorAtEnd(state,
    1887           0 :                                            "GENERATOR:MICROTURBINE \"" + this->Name +
    1888             :                                                "\": Exhaust air humidity ratio less than combustion air inlet humidity ratio warning continues...",
    1889           0 :                                            this->ExhHRLTInletHRIndex,
    1890           0 :                                            this->ExhaustAirHumRat,
    1891           0 :                                            this->ExhaustAirHumRat);
    1892             :         }
    1893             :     }
    1894             : }
    1895             : 
    1896       51343 : void MTGeneratorSpecs::UpdateMTGeneratorRecords(EnergyPlusData &state)
    1897             : {
    1898             :     // SUBROUTINE INFORMATION:
    1899             :     //       AUTHOR         R. Raustad/D. Shirey
    1900             :     //       DATE WRITTEN   Mar 2008
    1901             :     //       MODIFIED       na
    1902             :     //       RE-ENGINEERED  na
    1903             : 
    1904             :     // PURPOSE OF THIS SUBROUTINE:
    1905             :     //  Reporting and updating nodes if necessary.
    1906             : 
    1907       51343 :     if (this->HeatRecActive) {
    1908       19272 :         state.dataLoopNodes->Node(this->HeatRecOutletNodeNum).Temp = this->HeatRecOutletTemp;
    1909             :     }
    1910             : 
    1911       51343 :     if (this->ExhAirCalcsActive) {
    1912       27135 :         state.dataLoopNodes->Node(this->CombustionAirOutletNodeNum).MassFlowRate = this->ExhaustAirMassFlowRate;
    1913       27135 :         state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).MassFlowRate = this->ExhaustAirMassFlowRate;
    1914             : 
    1915       27135 :         state.dataLoopNodes->Node(this->CombustionAirOutletNodeNum).Temp = this->ExhaustAirTemperature;
    1916       27135 :         state.dataLoopNodes->Node(this->CombustionAirOutletNodeNum).HumRat = this->ExhaustAirHumRat;
    1917       27135 :         state.dataLoopNodes->Node(this->CombustionAirOutletNodeNum).MassFlowRateMaxAvail =
    1918       27135 :             state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).MassFlowRateMaxAvail;
    1919       27135 :         state.dataLoopNodes->Node(this->CombustionAirOutletNodeNum).MassFlowRateMinAvail =
    1920       27135 :             state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).MassFlowRateMinAvail;
    1921             :     }
    1922             : 
    1923       51343 :     this->EnergyGen = this->ElecPowerGenerated * state.dataHVACGlobal->TimeStepSysSec;
    1924       51343 :     this->ExhaustEnergyRec = this->QHeatRecovered * state.dataHVACGlobal->TimeStepSysSec;
    1925       51343 :     this->FuelEnergyHHV = this->FuelEnergyUseRateHHV * state.dataHVACGlobal->TimeStepSysSec;
    1926       51343 :     if (this->FuelEnergyUseRateLHV > 0.0) {
    1927       18465 :         this->ElectricEfficiencyLHV = this->ElecPowerGenerated / this->FuelEnergyUseRateLHV;
    1928       18465 :         this->ThermalEfficiencyLHV = this->QHeatRecovered / this->FuelEnergyUseRateLHV;
    1929             :     } else {
    1930       32878 :         this->ElectricEfficiencyLHV = 0.0;
    1931       32878 :         this->ThermalEfficiencyLHV = 0.0;
    1932             :     }
    1933       51343 :     this->AncillaryEnergy = this->AncillaryPowerRate * state.dataHVACGlobal->TimeStepSysSec;
    1934       51343 :     this->StandbyEnergy = this->StandbyPowerRate * state.dataHVACGlobal->TimeStepSysSec;
    1935       51343 : }
    1936       51343 : void MTGeneratorSpecs::oneTimeInit(EnergyPlusData &state)
    1937             : {
    1938             : 
    1939       51343 :     std::string const RoutineName("InitMTGenerators");
    1940             :     bool errFlag;
    1941             : 
    1942       51343 :     if (this->myFlag) {
    1943           6 :         this->setupOutputVars(state);
    1944           6 :         this->myFlag = false;
    1945             :     }
    1946             : 
    1947       51343 :     if (this->MyPlantScanFlag && allocated(state.dataPlnt->PlantLoop) && this->HeatRecActive) {
    1948           2 :         errFlag = false;
    1949           4 :         PlantUtilities::ScanPlantLoopsForObject(
    1950           2 :             state, this->Name, DataPlant::PlantEquipmentType::Generator_MicroTurbine, this->HRPlantLoc, errFlag, _, _, _, _, _);
    1951           2 :         if (errFlag) {
    1952           0 :             ShowFatalError(state, "InitMTGenerators: Program terminated due to previous condition(s).");
    1953             :         }
    1954             : 
    1955           2 :         this->MyPlantScanFlag = false;
    1956             :     }
    1957             : 
    1958       51343 :     if (this->MySizeAndNodeInitFlag && (!this->MyPlantScanFlag) && this->HeatRecActive) {
    1959             : 
    1960             :         // size mass flow rate
    1961           4 :         Real64 rho = FluidProperties::GetDensityGlycol(state,
    1962           2 :                                                        state.dataPlnt->PlantLoop(this->HRPlantLoc.loopNum).FluidName,
    1963             :                                                        Constant::InitConvTemp,
    1964           2 :                                                        state.dataPlnt->PlantLoop(this->HRPlantLoc.loopNum).FluidIndex,
    1965             :                                                        RoutineName);
    1966             : 
    1967           2 :         this->DesignHeatRecMassFlowRate = rho * this->RefHeatRecVolFlowRate;
    1968           2 :         this->HeatRecMaxMassFlowRate = rho * this->HeatRecMaxVolFlowRate;
    1969             : 
    1970           2 :         PlantUtilities::InitComponentNodes(state, 0.0, this->HeatRecMaxMassFlowRate, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum);
    1971             : 
    1972           2 :         this->MySizeAndNodeInitFlag = false;
    1973             :     }
    1974       51343 : }
    1975             : 
    1976             : } // namespace EnergyPlus::MicroturbineElectricGenerator

Generated by: LCOV version 1.14