LCOV - code coverage report
Current view: top level - EnergyPlus - MicroCHPElectricGenerator.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 524 696 75.3 %
Date: 2024-08-24 18:31:18 Functions: 15 15 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/DataGenerators.hh>
      61             : #include <EnergyPlus/DataGlobalConstants.hh>
      62             : #include <EnergyPlus/DataHVACGlobals.hh>
      63             : #include <EnergyPlus/DataHeatBalance.hh>
      64             : #include <EnergyPlus/DataIPShortCuts.hh>
      65             : #include <EnergyPlus/DataLoopNode.hh>
      66             : #include <EnergyPlus/DataSizing.hh>
      67             : #include <EnergyPlus/FluidProperties.hh>
      68             : #include <EnergyPlus/General.hh>
      69             : #include <EnergyPlus/GeneratorDynamicsManager.hh>
      70             : #include <EnergyPlus/GeneratorFuelSupply.hh>
      71             : #include <EnergyPlus/HeatBalanceInternalHeatGains.hh>
      72             : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      73             : #include <EnergyPlus/MicroCHPElectricGenerator.hh>
      74             : #include <EnergyPlus/NodeInputManager.hh>
      75             : #include <EnergyPlus/OutputProcessor.hh>
      76             : #include <EnergyPlus/Plant/DataPlant.hh>
      77             : #include <EnergyPlus/PlantUtilities.hh>
      78             : #include <EnergyPlus/ScheduleManager.hh>
      79             : #include <EnergyPlus/UtilityRoutines.hh>
      80             : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
      81             : 
      82             : namespace EnergyPlus::MicroCHPElectricGenerator {
      83             : 
      84             : // MODULE INFORMATION:
      85             : //       AUTHOR         Brent Griffith
      86             : //       DATE WRITTEN   June 2006
      87             : //       MODIFIED       na
      88             : //       RE-ENGINEERED  na
      89             : 
      90             : // PURPOSE OF THIS MODULE:
      91             : // This module simulates the operation of Internal Combustion and Stirling Engine
      92             : //  residential-scale generators for combined heat and power.
      93             : 
      94             : // METHODOLOGY EMPLOYED:
      95             : // Once the ElectricPowerManager determines that the Combustion Generator
      96             : // is available to meet an electric load demand, it calls SimCombustionGenerator
      97             : // which in turn calls the Combustion model.
      98             : // See DataFuelCells.cc for structures and variables
      99             : 
     100             : // REFERENCES:
     101             : // IEA/ECBCS Annex 42 model specification titled: " A Generic Model Specification for
     102             : // Combustion-based Residential CHP Devices"  Alex Ferguson, Nick Kelly, IEA Annex 42.
     103             : // Module developed from
     104             : 
     105       17417 : PlantComponent *MicroCHPDataStruct::factory(EnergyPlusData &state, std::string const &objectName)
     106             : {
     107             :     // Process the input data
     108       17417 :     if (state.dataCHPElectGen->getMicroCHPInputFlag) {
     109           2 :         GetMicroCHPGeneratorInput(state);
     110           2 :         state.dataCHPElectGen->getMicroCHPInputFlag = false;
     111             :     }
     112             : 
     113             :     // Now look for this object
     114       17417 :     for (auto &thisMCHP : state.dataCHPElectGen->MicroCHP) {
     115       17417 :         if (thisMCHP.Name == objectName) {
     116       17417 :             return &thisMCHP;
     117             :         }
     118       34834 :     }
     119             :     // If we didn't find it, fatal
     120             :     ShowFatalError(state, format("LocalMicroCHPGenFactory: Error getting inputs for micro-CHP gen named: {}", objectName)); // LCOV_EXCL_LINE
     121             :     // Shut up the compiler
     122             :     return nullptr; // LCOV_EXCL_LINE
     123             : }
     124             : 
     125           2 : void GetMicroCHPGeneratorInput(EnergyPlusData &state)
     126             : {
     127             :     // SUBROUTINE INFORMATION:
     128             :     //       AUTHOR:          Brent Griffith
     129             :     //       DATE WRITTEN:    July 2005
     130             : 
     131             :     // PURPOSE OF THIS SUBROUTINE:
     132             :     // This routine will get the input
     133             :     // required by the Micro CHP Generator models.
     134             : 
     135             :     // METHODOLOGY EMPLOYED:
     136             :     // EnergyPlus input processor
     137             : 
     138             :     int NumAlphas;                 // Number of elements in the alpha array
     139             :     int NumNums;                   // Number of elements in the numeric array
     140             :     int IOStat;                    // IO Status when calling get input subroutine
     141           2 :     Array1D_string AlphArray(25);  // character string data
     142           2 :     Array1D<Real64> NumArray(200); // numeric data TODO deal with allocatable for extensible
     143           2 :     bool ErrorsFound(false);       // error flag
     144             : 
     145           2 :     if (state.dataCHPElectGen->MyOneTimeFlag) {
     146             : 
     147             :         // call to Fuel supply module to set up data there.
     148           2 :         GeneratorFuelSupply::GetGeneratorFuelSupplyInput(state);
     149             : 
     150             :         // First get the Micro CHP Parameters so they can be nested in structure later
     151           2 :         state.dataIPShortCut->cCurrentModuleObject = "Generator:MicroCHP:NonNormalizedParameters";
     152           4 :         state.dataCHPElectGen->NumMicroCHPParams =
     153           2 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, state.dataIPShortCut->cCurrentModuleObject);
     154             : 
     155           2 :         if (state.dataCHPElectGen->NumMicroCHPParams <= 0) {
     156           0 :             ShowSevereError(state, format("No {} equipment specified in input file", state.dataIPShortCut->cCurrentModuleObject));
     157           0 :             ErrorsFound = true;
     158             :         }
     159             : 
     160           2 :         state.dataCHPElectGen->MicroCHPParamInput.allocate(state.dataCHPElectGen->NumMicroCHPParams);
     161             : 
     162           4 :         for (int CHPParamNum = 1; CHPParamNum <= state.dataCHPElectGen->NumMicroCHPParams; ++CHPParamNum) {
     163           6 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     164           2 :                                                                      state.dataIPShortCut->cCurrentModuleObject,
     165             :                                                                      CHPParamNum,
     166             :                                                                      AlphArray,
     167             :                                                                      NumAlphas,
     168             :                                                                      NumArray,
     169             :                                                                      NumNums,
     170             :                                                                      IOStat,
     171             :                                                                      _,
     172           2 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
     173           2 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
     174           2 :                                                                      state.dataIPShortCut->cNumericFieldNames);
     175             : 
     176           2 :             std::string ObjMSGName = state.dataIPShortCut->cCurrentModuleObject + " Named " + AlphArray(1);
     177             : 
     178           2 :             state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).Name = AlphArray(1);        // A1 name
     179           2 :             state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).MaxElecPower = NumArray(1); // N1 Maximum Electric Power [W]
     180           2 :             state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).MinElecPower = NumArray(2); // N2 Minimum Electric Power [W]
     181           2 :             state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).MinWaterMdot = NumArray(3); // N3 Minimum Cooling Water Flow Rate [kg/s]
     182           2 :             state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).MaxWaterTemp = NumArray(4); // N3 Maximum Cooling Water Inlet Temp [C]
     183           2 :             state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).ElecEffCurveID =
     184           2 :                 Curve::GetCurveCheck(state, AlphArray(2), ErrorsFound, ObjMSGName); // Electrical Eff. ID
     185           2 :             state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).ThermalEffCurveID =
     186           2 :                 Curve::GetCurveCheck(state, AlphArray(3), ErrorsFound, ObjMSGName); // Thermal Efficiency
     187             : 
     188           2 :             if (Util::SameString(AlphArray(4), "InternalControl")) {
     189           1 :                 state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).InternalFlowControl = true; //  A4, \field Cooling Water Flow Rate Mode
     190           1 :                 state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).PlantFlowControl = false;
     191             :             }
     192           2 :             if ((!(Util::SameString(AlphArray(4), "InternalControl"))) && (!(Util::SameString(AlphArray(4), "PlantControl")))) {
     193           0 :                 ShowSevereError(state, format("Invalid, {} = {}", state.dataIPShortCut->cAlphaFieldNames(4), AlphArray(4)));
     194           0 :                 ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
     195           0 :                 ErrorsFound = true;
     196             :             }
     197           2 :             if (state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).InternalFlowControl) { // get the curve
     198           1 :                 state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).WaterFlowCurveID =
     199           1 :                     Curve::GetCurveCheck(state, AlphArray(5), ErrorsFound, ObjMSGName);
     200             :                 //  Curve for Cooling Water Flow Rate
     201             :             }
     202           2 :             state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).AirFlowCurveID =
     203           2 :                 Curve::GetCurveCheck(state, AlphArray(6), ErrorsFound, ObjMSGName);
     204             :             //  Name of Curve for Air Flow Rate
     205           2 :             state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).DeltaPelMax =
     206           2 :                 NumArray(5); // N5 Maximum rate of change in net electrical power [W/s]
     207           2 :             state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).DeltaFuelMdotMax =
     208           2 :                 NumArray(6);                                                             // N6 Maximum Rate of change in fuel flow rate [kg/s2]
     209           2 :             state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).UAhx = NumArray(7);   // N7 Heat Exchanger UA_hx
     210           2 :             state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).UAskin = NumArray(8); // N8 Skin Loss UA_loss
     211           2 :             state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).RadiativeFraction = NumArray(9); // N9 radiative fraction for skin losses
     212           2 :             state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).MCeng = NumArray(10);            // N10 Aggregated Thermal Mass of Generator MC_eng
     213           2 :             if (state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).MCeng <= 0.0) {
     214           0 :                 ShowSevereError(state, format("Invalid, {} = {:.5R}", state.dataIPShortCut->cNumericFieldNames(10), NumArray(10)));
     215           0 :                 ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
     216           0 :                 ShowContinueError(state, "Thermal mass must be greater than zero");
     217           0 :                 ErrorsFound = true;
     218             :             }
     219           2 :             state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).MCcw = NumArray(11); // Aggregated Thermal Mass of Heat Recovery MC_cw
     220           2 :             if (state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).MCcw <= 0.0) {
     221           0 :                 ShowSevereError(state, format("Invalid, {} = {:.5R}", state.dataIPShortCut->cNumericFieldNames(11), NumArray(11)));
     222           0 :                 ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
     223           0 :                 ShowContinueError(state, "Thermal mass must be greater than zero");
     224           0 :                 ErrorsFound = true;
     225             :             }
     226           2 :             state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).Pstandby = NumArray(12); // N12 Standby Power [W]
     227             : 
     228           2 :             if (Util::SameString(AlphArray(7), "TimeDelay")) {
     229           2 :                 state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).WarmUpByTimeDelay = true;
     230           2 :                 state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).WarmUpByEngineTemp = false;
     231             :             }
     232           2 :             if ((!(Util::SameString(AlphArray(7), "NominalEngineTemperature"))) && (!(Util::SameString(AlphArray(7), "TimeDelay")))) {
     233           0 :                 ShowSevereError(state, format("Invalid, {} = {}", state.dataIPShortCut->cAlphaFieldNames(7), AlphArray(7)));
     234           0 :                 ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
     235           0 :                 ErrorsFound = true;
     236             :             }
     237           2 :             state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).kf = NumArray(13);          // N13 Warmup Fuel Flow Rate Coefficient k_f
     238           2 :             state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).TnomEngOp = NumArray(14);   // N14 Nominal Engine Operating Temperature [C]
     239           2 :             state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).kp = NumArray(15);          // N15 Warmup Power Coefficient k_p
     240           2 :             state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).Rfuelwarmup = NumArray(16); // N16 Warm Up Fuel Flow Rate Limit Ratio
     241           2 :             state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).WarmUpDelay = NumArray(17); // N17 Warm Up Delay Time
     242             : 
     243           2 :             state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).PcoolDown = NumArray(18); // N18 Cool Down Power
     244             : 
     245           2 :             state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).CoolDownDelay = NumArray(19); // N19 Cool Down Delay Time in seconds
     246             : 
     247           2 :             if (Util::SameString(AlphArray(8), "MandatoryCoolDown")) {
     248           1 :                 state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).MandatoryFullCoolDown = true;
     249           1 :                 state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).WarmRestartOkay = false;
     250             :             }
     251           2 :             if ((!(Util::SameString(AlphArray(8), "MandatoryCoolDown"))) && (!(Util::SameString(AlphArray(8), "OptionalCoolDown")))) {
     252           0 :                 ShowSevereError(state, format("Invalid, {} = {}", state.dataIPShortCut->cAlphaFieldNames(8), AlphArray(8)));
     253           0 :                 ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
     254           0 :                 ErrorsFound = true;
     255             :             }
     256           2 :         }
     257             : 
     258           2 :         state.dataIPShortCut->cCurrentModuleObject = "Generator:MicroCHP";
     259           4 :         state.dataCHPElectGen->NumMicroCHPs =
     260           2 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, state.dataIPShortCut->cCurrentModuleObject);
     261             : 
     262           2 :         if (state.dataCHPElectGen->NumMicroCHPs <= 0) {
     263             :             // shouldn't ever come here?
     264           0 :             ShowSevereError(state, format("No {} equipment specified in input file", state.dataIPShortCut->cCurrentModuleObject));
     265           0 :             ErrorsFound = true;
     266             :         }
     267             : 
     268           2 :         if (!(allocated(state.dataCHPElectGen->MicroCHP))) {
     269           2 :             state.dataCHPElectGen->MicroCHP.allocate(state.dataCHPElectGen->NumMicroCHPs); // inits handeled in derived type definitions
     270             :         }
     271             : 
     272             :         // load in Micro CHPs
     273           4 :         for (int GeneratorNum = 1; GeneratorNum <= state.dataCHPElectGen->NumMicroCHPs; ++GeneratorNum) {
     274           6 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     275           2 :                                                                      state.dataIPShortCut->cCurrentModuleObject,
     276             :                                                                      GeneratorNum,
     277             :                                                                      AlphArray,
     278             :                                                                      NumAlphas,
     279             :                                                                      NumArray,
     280             :                                                                      NumNums,
     281             :                                                                      IOStat,
     282             :                                                                      _,
     283           2 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
     284           2 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
     285           2 :                                                                      state.dataIPShortCut->cNumericFieldNames);
     286           2 :             Util::IsNameEmpty(state, AlphArray(1), state.dataIPShortCut->cCurrentModuleObject, ErrorsFound);
     287             : 
     288             :             // GENERATOR:MICRO CHP,
     289           2 :             state.dataCHPElectGen->MicroCHP(GeneratorNum).DynamicsControlID = GeneratorNum;
     290           2 :             state.dataCHPElectGen->MicroCHP(GeneratorNum).Name = AlphArray(1);         //  A1 Generator name
     291           2 :             state.dataCHPElectGen->MicroCHP(GeneratorNum).ParamObjName = AlphArray(2); //  A2 Micro CHP Parameter Object Name
     292             :             // find input structure
     293           2 :             int thisParamID = Util::FindItemInList(AlphArray(2), state.dataCHPElectGen->MicroCHPParamInput);
     294           2 :             if (thisParamID != 0) {
     295           2 :                 state.dataCHPElectGen->MicroCHP(GeneratorNum).A42Model =
     296           4 :                     state.dataCHPElectGen->MicroCHPParamInput(thisParamID); // entire structure of input data assigned here!
     297             :             } else {
     298           0 :                 ShowSevereError(state, format("Invalid, {} = {}", state.dataIPShortCut->cAlphaFieldNames(2), AlphArray(2)));
     299           0 :                 ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
     300           0 :                 ErrorsFound = true;
     301             :             }
     302             : 
     303           2 :             if (!state.dataIPShortCut->lAlphaFieldBlanks(3)) {
     304           2 :                 state.dataCHPElectGen->MicroCHP(GeneratorNum).ZoneName = AlphArray(3); //  A3 Zone Name
     305           2 :                 state.dataCHPElectGen->MicroCHP(GeneratorNum).ZoneID =
     306           2 :                     Util::FindItemInList(state.dataCHPElectGen->MicroCHP(GeneratorNum).ZoneName, state.dataHeatBal->Zone);
     307           2 :                 if (state.dataCHPElectGen->MicroCHP(GeneratorNum).ZoneID == 0) {
     308           0 :                     ShowSevereError(state, format("Invalid, {} = {}", state.dataIPShortCut->cAlphaFieldNames(3), AlphArray(3)));
     309           0 :                     ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
     310           0 :                     ErrorsFound = true;
     311             :                 }
     312             :             } else {
     313           0 :                 state.dataCHPElectGen->MicroCHP(GeneratorNum).ZoneID = 0;
     314             :             }
     315           2 :             state.dataCHPElectGen->MicroCHP(GeneratorNum).PlantInletNodeName = AlphArray(4);  //  A4 Cooling Water Inlet Node Name
     316           2 :             state.dataCHPElectGen->MicroCHP(GeneratorNum).PlantOutletNodeName = AlphArray(5); //  A5 Cooling Water Outlet Node Name
     317             :             // find node ids for water path
     318           2 :             state.dataCHPElectGen->MicroCHP(GeneratorNum).PlantInletNodeID =
     319           4 :                 NodeInputManager::GetOnlySingleNode(state,
     320           2 :                                                     AlphArray(4),
     321             :                                                     ErrorsFound,
     322             :                                                     DataLoopNode::ConnectionObjectType::GeneratorMicroCHP,
     323           2 :                                                     AlphArray(1),
     324             :                                                     DataLoopNode::NodeFluidType::Water,
     325             :                                                     DataLoopNode::ConnectionType::Inlet,
     326             :                                                     NodeInputManager::CompFluidStream::Primary,
     327             :                                                     DataLoopNode::ObjectIsNotParent);
     328           2 :             state.dataCHPElectGen->MicroCHP(GeneratorNum).PlantOutletNodeID =
     329           4 :                 NodeInputManager::GetOnlySingleNode(state,
     330           2 :                                                     AlphArray(5),
     331             :                                                     ErrorsFound,
     332             :                                                     DataLoopNode::ConnectionObjectType::GeneratorMicroCHP,
     333           2 :                                                     AlphArray(1),
     334             :                                                     DataLoopNode::NodeFluidType::Water,
     335             :                                                     DataLoopNode::ConnectionType::Outlet,
     336             :                                                     NodeInputManager::CompFluidStream::Primary,
     337             :                                                     DataLoopNode::ObjectIsNotParent);
     338           4 :             BranchNodeConnections::TestCompSet(
     339           2 :                 state, state.dataIPShortCut->cCurrentModuleObject, AlphArray(1), AlphArray(4), AlphArray(5), "Heat Recovery Nodes");
     340             : 
     341           2 :             state.dataCHPElectGen->MicroCHP(GeneratorNum).AirInletNodeName = AlphArray(6); //  A6 Air Inlet Node Name
     342             :             // check the node connections
     343           2 :             state.dataCHPElectGen->MicroCHP(GeneratorNum).AirInletNodeID =
     344           4 :                 NodeInputManager::GetOnlySingleNode(state,
     345           2 :                                                     AlphArray(6),
     346             :                                                     ErrorsFound,
     347             :                                                     DataLoopNode::ConnectionObjectType::GeneratorMicroCHP,
     348           2 :                                                     AlphArray(1),
     349             :                                                     DataLoopNode::NodeFluidType::Air,
     350             :                                                     DataLoopNode::ConnectionType::Inlet,
     351             :                                                     NodeInputManager::CompFluidStream::Secondary,
     352             :                                                     DataLoopNode::ObjectIsNotParent);
     353             : 
     354           2 :             state.dataCHPElectGen->MicroCHP(GeneratorNum).AirOutletNodeName = AlphArray(7); //  A7 Air Outlet Node Name
     355           2 :             state.dataCHPElectGen->MicroCHP(GeneratorNum).AirOutletNodeID =
     356           4 :                 NodeInputManager::GetOnlySingleNode(state,
     357           2 :                                                     AlphArray(7),
     358             :                                                     ErrorsFound,
     359             :                                                     DataLoopNode::ConnectionObjectType::GeneratorMicroCHP,
     360           2 :                                                     AlphArray(1),
     361             :                                                     DataLoopNode::NodeFluidType::Air,
     362             :                                                     DataLoopNode::ConnectionType::Outlet,
     363             :                                                     NodeInputManager::CompFluidStream::Secondary,
     364             :                                                     DataLoopNode::ObjectIsNotParent);
     365             : 
     366           2 :             state.dataCHPElectGen->MicroCHP(GeneratorNum).FuelSupplyID =
     367           2 :                 Util::FindItemInList(AlphArray(8), state.dataGenerator->FuelSupply); // Fuel Supply ID
     368           2 :             if (state.dataCHPElectGen->MicroCHP(GeneratorNum).FuelSupplyID == 0) {
     369           0 :                 ShowSevereError(state, format("Invalid, {} = {}", state.dataIPShortCut->cAlphaFieldNames(8), AlphArray(8)));
     370           0 :                 ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
     371           0 :                 ErrorsFound = true;
     372             :             }
     373             : 
     374           2 :             if (state.dataIPShortCut->lAlphaFieldBlanks(9)) {
     375           0 :                 state.dataCHPElectGen->MicroCHP(GeneratorNum).AvailabilitySchedID = ScheduleManager::ScheduleAlwaysOn;
     376             :             } else {
     377           2 :                 state.dataCHPElectGen->MicroCHP(GeneratorNum).AvailabilitySchedID = ScheduleManager::GetScheduleIndex(state, AlphArray(9));
     378           2 :                 if (state.dataCHPElectGen->MicroCHP(GeneratorNum).AvailabilitySchedID == 0) {
     379           0 :                     ShowSevereError(state, format("Invalid, {} = {}", state.dataIPShortCut->cAlphaFieldNames(9), AlphArray(9)));
     380           0 :                     ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
     381           0 :                     ErrorsFound = true;
     382             :                 }
     383             :             }
     384           2 :             state.dataCHPElectGen->MicroCHP(GeneratorNum).A42Model.TengLast = 20.0;      // inits
     385           2 :             state.dataCHPElectGen->MicroCHP(GeneratorNum).A42Model.TempCWOutLast = 20.0; // inits
     386             :         }
     387             : 
     388           2 :         if (ErrorsFound) {
     389           0 :             ShowFatalError(state, format("Errors found in processing input for {}", state.dataIPShortCut->cCurrentModuleObject));
     390             :         }
     391             : 
     392             :         // setup report variables
     393           4 :         for (int GeneratorNum = 1; GeneratorNum <= state.dataCHPElectGen->NumMicroCHPs; ++GeneratorNum) {
     394             :         }
     395             : 
     396           2 :         state.dataCHPElectGen->MyOneTimeFlag = false;
     397             :     }
     398           2 : }
     399             : 
     400           2 : void MicroCHPDataStruct::setupOutputVars(EnergyPlusData &state)
     401             : {
     402           4 :     SetupOutputVariable(state,
     403             :                         "Generator Off Mode Time",
     404             :                         Constant::Units::s,
     405           2 :                         this->A42Model.OffModeTime,
     406             :                         OutputProcessor::TimeStepType::System,
     407             :                         OutputProcessor::StoreType::Sum,
     408           2 :                         this->Name);
     409             : 
     410           4 :     SetupOutputVariable(state,
     411             :                         "Generator Standby Mode Time",
     412             :                         Constant::Units::s,
     413           2 :                         this->A42Model.StandyByModeTime,
     414             :                         OutputProcessor::TimeStepType::System,
     415             :                         OutputProcessor::StoreType::Sum,
     416           2 :                         this->Name);
     417             : 
     418           4 :     SetupOutputVariable(state,
     419             :                         "Generator Warm Up Mode Time",
     420             :                         Constant::Units::s,
     421           2 :                         this->A42Model.WarmUpModeTime,
     422             :                         OutputProcessor::TimeStepType::System,
     423             :                         OutputProcessor::StoreType::Sum,
     424           2 :                         this->Name);
     425             : 
     426           4 :     SetupOutputVariable(state,
     427             :                         "Generator Normal Operating Mode Time",
     428             :                         Constant::Units::s,
     429           2 :                         this->A42Model.NormalModeTime,
     430             :                         OutputProcessor::TimeStepType::System,
     431             :                         OutputProcessor::StoreType::Sum,
     432           2 :                         this->Name);
     433             : 
     434           4 :     SetupOutputVariable(state,
     435             :                         "Generator Cool Down Mode Time",
     436             :                         Constant::Units::s,
     437           2 :                         this->A42Model.CoolDownModeTime,
     438             :                         OutputProcessor::TimeStepType::System,
     439             :                         OutputProcessor::StoreType::Sum,
     440           2 :                         this->Name);
     441             : 
     442           4 :     SetupOutputVariable(state,
     443             :                         "Generator Produced AC Electricity Rate",
     444             :                         Constant::Units::W,
     445           2 :                         this->A42Model.ACPowerGen,
     446             :                         OutputProcessor::TimeStepType::System,
     447             :                         OutputProcessor::StoreType::Average,
     448           2 :                         this->Name);
     449             : 
     450           4 :     SetupOutputVariable(state,
     451             :                         "Generator Produced AC Electricity Energy",
     452             :                         Constant::Units::J,
     453           2 :                         this->A42Model.ACEnergyGen,
     454             :                         OutputProcessor::TimeStepType::System,
     455             :                         OutputProcessor::StoreType::Sum,
     456           2 :                         this->Name,
     457             :                         Constant::eResource::ElectricityProduced,
     458             :                         OutputProcessor::Group::Plant,
     459             :                         OutputProcessor::EndUseCat::Cogeneration);
     460             : 
     461           4 :     SetupOutputVariable(state,
     462             :                         "Generator Produced Thermal Rate",
     463             :                         Constant::Units::W,
     464           2 :                         this->A42Model.QdotHR,
     465             :                         OutputProcessor::TimeStepType::System,
     466             :                         OutputProcessor::StoreType::Average,
     467           2 :                         this->Name);
     468             : 
     469           4 :     SetupOutputVariable(state,
     470             :                         "Generator Produced Thermal Energy",
     471             :                         Constant::Units::J,
     472           2 :                         this->A42Model.TotalHeatEnergyRec,
     473             :                         OutputProcessor::TimeStepType::System,
     474             :                         OutputProcessor::StoreType::Sum,
     475           2 :                         this->Name,
     476             :                         Constant::eResource::EnergyTransfer,
     477             :                         OutputProcessor::Group::Plant,
     478             :                         OutputProcessor::EndUseCat::Cogeneration);
     479             : 
     480           4 :     SetupOutputVariable(state,
     481             :                         "Generator Electric Efficiency",
     482             :                         Constant::Units::None,
     483           2 :                         this->A42Model.ElecEff,
     484             :                         OutputProcessor::TimeStepType::System,
     485             :                         OutputProcessor::StoreType::Average,
     486           2 :                         this->Name);
     487             : 
     488           4 :     SetupOutputVariable(state,
     489             :                         "Generator Thermal Efficiency",
     490             :                         Constant::Units::None,
     491           2 :                         this->A42Model.ThermEff,
     492             :                         OutputProcessor::TimeStepType::System,
     493             :                         OutputProcessor::StoreType::Average,
     494           2 :                         this->Name);
     495             : 
     496           4 :     SetupOutputVariable(state,
     497             :                         "Generator Gross Input Heat Rate",
     498             :                         Constant::Units::W,
     499           2 :                         this->A42Model.Qgross,
     500             :                         OutputProcessor::TimeStepType::System,
     501             :                         OutputProcessor::StoreType::Average,
     502           2 :                         this->Name);
     503             : 
     504           4 :     SetupOutputVariable(state,
     505             :                         "Generator Steady State Engine Heat Generation Rate",
     506             :                         Constant::Units::W,
     507           2 :                         this->A42Model.Qgenss,
     508             :                         OutputProcessor::TimeStepType::System,
     509             :                         OutputProcessor::StoreType::Average,
     510           2 :                         this->Name);
     511             : 
     512           4 :     SetupOutputVariable(state,
     513             :                         "Generator Engine Heat Exchange Rate",
     514             :                         Constant::Units::W,
     515           2 :                         this->A42Model.QdotHX,
     516             :                         OutputProcessor::TimeStepType::System,
     517             :                         OutputProcessor::StoreType::Average,
     518           2 :                         this->Name);
     519             : 
     520           4 :     SetupOutputVariable(state,
     521             :                         "Generator Air Mass Flow Rate",
     522             :                         Constant::Units::kg_s,
     523           2 :                         this->A42Model.MdotAir,
     524             :                         OutputProcessor::TimeStepType::System,
     525             :                         OutputProcessor::StoreType::Average,
     526           2 :                         this->Name);
     527             : 
     528           4 :     SetupOutputVariable(state,
     529             :                         "Generator Fuel Molar Flow Rate",
     530             :                         Constant::Units::kmol_s,
     531           2 :                         this->A42Model.NdotFuel,
     532             :                         OutputProcessor::TimeStepType::System,
     533             :                         OutputProcessor::StoreType::Average,
     534           2 :                         this->Name);
     535             : 
     536           4 :     SetupOutputVariable(state,
     537             :                         "Generator Fuel Mass Flow Rate",
     538             :                         Constant::Units::kg_s,
     539           2 :                         this->A42Model.MdotFuel,
     540             :                         OutputProcessor::TimeStepType::System,
     541             :                         OutputProcessor::StoreType::Average,
     542           2 :                         this->Name);
     543             : 
     544           4 :     SetupOutputVariable(state,
     545             :                         "Generator Engine Temperature",
     546             :                         Constant::Units::C,
     547           2 :                         this->A42Model.Teng,
     548             :                         OutputProcessor::TimeStepType::System,
     549             :                         OutputProcessor::StoreType::Average,
     550           2 :                         this->Name);
     551             : 
     552           4 :     SetupOutputVariable(state,
     553             :                         "Generator Coolant Inlet Temperature",
     554             :                         Constant::Units::C,
     555           2 :                         this->A42Model.HeatRecInletTemp,
     556             :                         OutputProcessor::TimeStepType::System,
     557             :                         OutputProcessor::StoreType::Average,
     558           2 :                         this->Name);
     559             : 
     560           4 :     SetupOutputVariable(state,
     561             :                         "Generator Coolant Outlet Temperature",
     562             :                         Constant::Units::C,
     563           2 :                         this->A42Model.HeatRecOutletTemp,
     564             :                         OutputProcessor::TimeStepType::System,
     565             :                         OutputProcessor::StoreType::Average,
     566           2 :                         this->Name);
     567             : 
     568             :     // this next one needs to be reconciled with non-gas fuel constituents.
     569             :     //   need custom resourceTypeKey or something for user defined fuel compositions.
     570           4 :     SetupOutputVariable(state,
     571             :                         "Generator Fuel HHV Basis Energy",
     572             :                         Constant::Units::J,
     573           2 :                         this->A42Model.FuelEnergyHHV,
     574             :                         OutputProcessor::TimeStepType::System,
     575             :                         OutputProcessor::StoreType::Sum,
     576           2 :                         this->Name,
     577             :                         Constant::eResource::NaturalGas,
     578             :                         OutputProcessor::Group::Plant,
     579             :                         OutputProcessor::EndUseCat::Cogeneration);
     580             : 
     581           4 :     SetupOutputVariable(state,
     582             :                         "Generator Fuel HHV Basis Rate",
     583             :                         Constant::Units::W,
     584           2 :                         this->A42Model.FuelEnergyUseRateHHV,
     585             :                         OutputProcessor::TimeStepType::System,
     586             :                         OutputProcessor::StoreType::Average,
     587           2 :                         this->Name);
     588             : 
     589           4 :     SetupOutputVariable(state,
     590             :                         "Generator Fuel LHV Basis Energy",
     591             :                         Constant::Units::J,
     592           2 :                         this->A42Model.FuelEnergyLHV,
     593             :                         OutputProcessor::TimeStepType::System,
     594             :                         OutputProcessor::StoreType::Sum,
     595           2 :                         this->Name);
     596             : 
     597           4 :     SetupOutputVariable(state,
     598             :                         "Generator Fuel LHV Basis Rate",
     599             :                         Constant::Units::W,
     600           2 :                         this->A42Model.FuelEnergyUseRateLHV,
     601             :                         OutputProcessor::TimeStepType::System,
     602             :                         OutputProcessor::StoreType::Average,
     603           2 :                         this->Name);
     604             : 
     605           4 :     SetupOutputVariable(state,
     606             :                         "Generator Fuel Compressor Electricity Rate",
     607             :                         Constant::Units::W,
     608           2 :                         this->A42Model.FuelCompressPower,
     609             :                         OutputProcessor::TimeStepType::System,
     610             :                         OutputProcessor::StoreType::Average,
     611           2 :                         this->Name);
     612             : 
     613           4 :     SetupOutputVariable(state,
     614             :                         "Generator Fuel Compressor Electricity Energy",
     615             :                         Constant::Units::J,
     616           2 :                         this->A42Model.FuelCompressEnergy,
     617             :                         OutputProcessor::TimeStepType::System,
     618             :                         OutputProcessor::StoreType::Sum,
     619           2 :                         this->Name);
     620             : 
     621           4 :     SetupOutputVariable(state,
     622             :                         "Generator Fuel Compressor Skin Heat Loss Rate",
     623             :                         Constant::Units::W,
     624           2 :                         this->A42Model.FuelCompressSkinLoss,
     625             :                         OutputProcessor::TimeStepType::System,
     626             :                         OutputProcessor::StoreType::Average,
     627           2 :                         this->Name);
     628             : 
     629           4 :     SetupOutputVariable(state,
     630             :                         "Generator Zone Sensible Heat Transfer Rate",
     631             :                         Constant::Units::W,
     632           2 :                         this->A42Model.SkinLossPower,
     633             :                         OutputProcessor::TimeStepType::System,
     634             :                         OutputProcessor::StoreType::Average,
     635           2 :                         this->Name);
     636             : 
     637           4 :     SetupOutputVariable(state,
     638             :                         "Generator Zone Sensible Heat Transfer Energy",
     639             :                         Constant::Units::J,
     640           2 :                         this->A42Model.SkinLossEnergy,
     641             :                         OutputProcessor::TimeStepType::System,
     642             :                         OutputProcessor::StoreType::Sum,
     643           2 :                         this->Name);
     644             : 
     645           4 :     SetupOutputVariable(state,
     646             :                         "Generator Zone Convection Heat Transfer Rate",
     647             :                         Constant::Units::W,
     648           2 :                         this->A42Model.SkinLossConvect,
     649             :                         OutputProcessor::TimeStepType::System,
     650             :                         OutputProcessor::StoreType::Average,
     651           2 :                         this->Name);
     652             : 
     653           4 :     SetupOutputVariable(state,
     654             :                         "Generator Zone Radiation Heat Transfer Rate",
     655             :                         Constant::Units::W,
     656           2 :                         this->A42Model.SkinLossRadiat,
     657             :                         OutputProcessor::TimeStepType::System,
     658             :                         OutputProcessor::StoreType::Average,
     659           2 :                         this->Name);
     660             : 
     661           2 :     if (this->ZoneID > 0) {
     662           2 :         SetupZoneInternalGain(state,
     663             :                               this->ZoneID,
     664             :                               this->Name,
     665             :                               DataHeatBalance::IntGainType::GeneratorMicroCHP,
     666             :                               &this->A42Model.SkinLossConvect,
     667             :                               nullptr,
     668             :                               &this->A42Model.SkinLossRadiat);
     669             :     }
     670           2 : }
     671             : 
     672       85963 : void MicroCHPDataStruct::simulate(EnergyPlusData &state,
     673             :                                   [[maybe_unused]] const EnergyPlus::PlantLocation &calledFromLocation,
     674             :                                   bool FirstHVACIteration,
     675             :                                   [[maybe_unused]] Real64 &CurLoad,
     676             :                                   [[maybe_unused]] bool RunFlag)
     677             : {
     678             :     // empty function to emulate current behavior as of conversion to using the PlantComponent calling structure.
     679             :     // calls from the plant side only update the nodes.
     680             :     // calls from the ElectricPowerServiceManger call the init, calc, and update worker functions
     681             : 
     682       85963 :     PlantUtilities::UpdateComponentHeatRecoverySide(state,
     683             :                                                     this->CWPlantLoc.loopNum,
     684             :                                                     this->CWPlantLoc.loopSideNum,
     685             :                                                     DataPlant::PlantEquipmentType::Generator_MicroCHP,
     686             :                                                     this->PlantInletNodeID,
     687             :                                                     this->PlantOutletNodeID,
     688             :                                                     this->A42Model.QdotHR,
     689             :                                                     this->A42Model.HeatRecInletTemp,
     690             :                                                     this->A42Model.HeatRecOutletTemp,
     691             :                                                     this->PlantMassFlowRate,
     692             :                                                     FirstHVACIteration);
     693       85963 : }
     694             : 
     695          10 : void MicroCHPDataStruct::onInitLoopEquip(EnergyPlusData &state, const EnergyPlus::PlantLocation &)
     696             : {
     697             :     static constexpr std::string_view RoutineName("MicroCHPDataStruct::onInitLoopEquip");
     698             : 
     699          10 :     Real64 rho = FluidProperties::GetDensityGlycol(state,
     700          10 :                                                    state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).FluidName,
     701          10 :                                                    state.dataLoopNodes->Node(this->PlantInletNodeID).Temp,
     702          10 :                                                    state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).FluidIndex,
     703             :                                                    RoutineName);
     704          10 :     if (this->A42Model.InternalFlowControl) { // got a curve
     705           5 :         this->PlantMassFlowRateMax =
     706           5 :             2.0 * Curve::CurveValue(
     707           5 :                       state, this->A42Model.WaterFlowCurveID, this->A42Model.MaxElecPower, state.dataLoopNodes->Node(this->PlantInletNodeID).Temp);
     708           5 :     } else if (this->CWPlantLoc.loopSideNum == DataPlant::LoopSideLocation::Supply) {
     709           5 :         if (state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).MaxMassFlowRate > 0.0) {
     710           4 :             this->PlantMassFlowRateMax = state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).MaxMassFlowRate;
     711           1 :         } else if (state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).PlantSizNum > 0) {
     712           0 :             this->PlantMassFlowRateMax = state.dataSize->PlantSizData(this->CWPlantLoc.loopNum).DesVolFlowRate * rho;
     713             :         } else {
     714           1 :             this->PlantMassFlowRateMax = 2.0;
     715             :         }
     716             : 
     717           0 :     } else if (this->CWPlantLoc.loopSideNum == DataPlant::LoopSideLocation::Demand) {
     718           0 :         this->PlantMassFlowRateMax = 2.0; // would like to use plant loop max but not ready yet
     719             :     }
     720             : 
     721          10 :     PlantUtilities::RegisterPlantCompDesignFlow(state, this->PlantInletNodeID, this->PlantMassFlowRateMax / rho);
     722             : 
     723          20 :     this->A42Model.ElecEff = Curve::CurveValue(state,
     724             :                                                this->A42Model.ElecEffCurveID,
     725             :                                                this->A42Model.MaxElecPower,
     726             :                                                this->PlantMassFlowRateMax,
     727          10 :                                                state.dataLoopNodes->Node(this->PlantInletNodeID).Temp);
     728             : 
     729          20 :     this->A42Model.ThermEff = Curve::CurveValue(state,
     730             :                                                 this->A42Model.ThermalEffCurveID,
     731             :                                                 this->A42Model.MaxElecPower,
     732             :                                                 this->PlantMassFlowRateMax,
     733          10 :                                                 state.dataLoopNodes->Node(this->PlantInletNodeID).Temp);
     734             : 
     735          10 :     GeneratorDynamicsManager::SetupGeneratorControlStateManager(state, this->DynamicsControlID);
     736          10 : }
     737             : 
     738       17415 : void MicroCHPDataStruct::InitMicroCHPNoNormalizeGenerators(EnergyPlusData &state)
     739             : {
     740             :     // SUBROUTINE INFORMATION:
     741             :     //       AUTHOR         BGriffith
     742             :     //       DATE WRITTEN   March 2007
     743             :     //       MODIFIED       na
     744             :     //       RE-ENGINEERED  na
     745             : 
     746       17415 :     this->oneTimeInit(state);
     747             : 
     748       17415 :     if (!state.dataGlobal->SysSizingCalc && this->MySizeFlag && !this->MyPlantScanFlag && (state.dataPlnt->PlantFirstSizesOkayToFinalize)) {
     749           2 :         this->MySizeFlag = false;
     750             :     }
     751             : 
     752       17415 :     if (this->MySizeFlag) return;
     753             : 
     754       15328 :     int DynaCntrlNum = this->DynamicsControlID;
     755             : 
     756       15328 :     if (state.dataGlobal->BeginEnvrnFlag && this->MyEnvrnFlag) {
     757             :         // reset to starting condition for different environment runperiods, design days
     758         162 :         this->A42Model.TengLast = 20.0;
     759         162 :         this->A42Model.TempCWOutLast = 20.0;
     760         162 :         this->A42Model.TimeElapsed = 0.0;
     761         162 :         this->A42Model.OpMode = DataGenerators::OperatingMode::Invalid;
     762         162 :         this->A42Model.OffModeTime = 0.0;
     763         162 :         this->A42Model.StandyByModeTime = 0.0;
     764         162 :         this->A42Model.WarmUpModeTime = 0.0;
     765         162 :         this->A42Model.NormalModeTime = 0.0;
     766         162 :         this->A42Model.CoolDownModeTime = 0.0;
     767         162 :         this->A42Model.Pnet = 0.0;
     768         162 :         this->A42Model.ElecEff = 0.0;
     769         162 :         this->A42Model.Qgross = 0.0;
     770         162 :         this->A42Model.ThermEff = 0.0;
     771         162 :         this->A42Model.Qgenss = 0.0;
     772         162 :         this->A42Model.NdotFuel = 0.0;
     773         162 :         this->A42Model.MdotFuel = 0.0;
     774         162 :         this->A42Model.Teng = 20.0;
     775         162 :         this->A42Model.TcwIn = 20.0;
     776         162 :         this->A42Model.TcwOut = 20.0;
     777         162 :         this->A42Model.MdotAir = 0.0;
     778         162 :         this->A42Model.QdotSkin = 0.0;
     779         162 :         this->A42Model.QdotConvZone = 0.0;
     780         162 :         this->A42Model.QdotRadZone = 0.0;
     781         162 :         state.dataGenerator->GeneratorDynamics(DynaCntrlNum).LastOpMode = DataGenerators::OperatingMode::Off;
     782         162 :         state.dataGenerator->GeneratorDynamics(DynaCntrlNum).CurrentOpMode = DataGenerators::OperatingMode::Off;
     783         162 :         state.dataGenerator->GeneratorDynamics(DynaCntrlNum).FractionalDayofLastShutDown = 0.0;
     784         162 :         state.dataGenerator->GeneratorDynamics(DynaCntrlNum).FractionalDayofLastStartUp = 0.0;
     785         162 :         state.dataGenerator->GeneratorDynamics(DynaCntrlNum).HasBeenOn = false;
     786         162 :         state.dataGenerator->GeneratorDynamics(DynaCntrlNum).DuringStartUp = false;
     787         162 :         state.dataGenerator->GeneratorDynamics(DynaCntrlNum).DuringShutDown = false;
     788         162 :         state.dataGenerator->GeneratorDynamics(DynaCntrlNum).FuelMdotLastTimestep = 0.0;
     789         162 :         state.dataGenerator->GeneratorDynamics(DynaCntrlNum).PelLastTimeStep = 0.0;
     790         162 :         state.dataGenerator->GeneratorDynamics(DynaCntrlNum).NumCycles = 0;
     791             : 
     792         162 :         state.dataGenerator->FuelSupply(this->FuelSupplyID).QskinLoss = 0.0;
     793             : 
     794         162 :         PlantUtilities::InitComponentNodes(state, 0.0, this->PlantMassFlowRateMax, this->PlantInletNodeID, this->PlantOutletNodeID);
     795             :     }
     796             : 
     797       15328 :     if (!state.dataGlobal->BeginEnvrnFlag) {
     798       15166 :         this->MyEnvrnFlag = true;
     799             :     }
     800             : 
     801             :     Real64 TimeElapsed =
     802       15328 :         state.dataGlobal->HourOfDay + state.dataGlobal->TimeStep * state.dataGlobal->TimeStepZone + state.dataHVACGlobal->SysTimeElapsed;
     803       15328 :     if (this->A42Model.TimeElapsed != TimeElapsed) {
     804             :         // The simulation has advanced to the next system timestep.  Save conditions from the end of the previous system
     805             :         // timestep for use as the initial conditions of each iteration that does not advance the system timestep.
     806        5081 :         this->A42Model.TengLast = this->A42Model.Teng;
     807        5081 :         this->A42Model.TempCWOutLast = this->A42Model.TcwOut;
     808        5081 :         this->A42Model.TimeElapsed = TimeElapsed;
     809        5081 :         state.dataGenerator->GeneratorDynamics(DynaCntrlNum).LastOpMode = state.dataGenerator->GeneratorDynamics(DynaCntrlNum).CurrentOpMode;
     810        5081 :         state.dataGenerator->GeneratorDynamics(DynaCntrlNum).FuelMdotLastTimestep = this->A42Model.MdotFuel;
     811        5081 :         state.dataGenerator->GeneratorDynamics(DynaCntrlNum).PelLastTimeStep = this->A42Model.Pnet;
     812             :     }
     813             : 
     814       15328 :     if (!this->A42Model.InternalFlowControl) {
     815             : 
     816        6134 :         Real64 mdot = this->PlantMassFlowRateMax;
     817        6134 :         PlantUtilities::SetComponentFlowRate(state, mdot, this->PlantInletNodeID, this->PlantOutletNodeID, this->CWPlantLoc);
     818        6134 :         this->PlantMassFlowRate = mdot;
     819             :     }
     820             : }
     821             : 
     822       15328 : void MicroCHPDataStruct::CalcMicroCHPNoNormalizeGeneratorModel(EnergyPlusData &state,
     823             :                                                                bool const RunFlagElectCenter, // TRUE when Generator operating
     824             :                                                                bool const RunFlagPlant,
     825             :                                                                Real64 const MyElectricLoad, // Generator demand
     826             :                                                                Real64 const MyThermalLoad)
     827             : {
     828             : 
     829             :     // SUBROUTINE INFORMATION:
     830             :     //       AUTHOR        B Griffith
     831             :     //       DATE WRITTEN   July 2006
     832             :     //       MODIFIED       na
     833             :     //       RE-ENGINEERED  na
     834             : 
     835             :     // PURPOSE OF THIS SUBROUTINE:
     836             :     // Main calculation subroutine for the IEA Annex 42 model
     837             : 
     838             :     // METHODOLOGY EMPLOYED:
     839             :     // curve fit, dynamic control limits,
     840             : 
     841             :     // REFERENCES:
     842             :     // IEA Annex 42 FC-COGEN-SIM "A Generic Model Specification for Combustion-based Residential CHP Devices"
     843             :     // Alex Ferguson, Nick Kelly, Version 3, June 26, 2006
     844             : 
     845             :     static constexpr std::string_view RoutineName("CalcMicroCHPNoNormalizeGeneratorModel");
     846             : 
     847       15328 :     DataGenerators::OperatingMode CurrentOpMode = DataGenerators::OperatingMode::Invalid;
     848       15328 :     Real64 AllowedLoad = 0.0;
     849       15328 :     Real64 PLRforSubtimestepStartUp(1.0);
     850       15328 :     Real64 PLRforSubtimestepShutDown(0.0);
     851       15328 :     bool RunFlag(false);
     852             : 
     853       15328 :     GeneratorDynamicsManager::ManageGeneratorControlState(state,
     854             :                                                           this->DynamicsControlID,
     855             :                                                           RunFlagElectCenter,
     856             :                                                           RunFlagPlant,
     857             :                                                           MyElectricLoad,
     858             :                                                           MyThermalLoad,
     859             :                                                           AllowedLoad,
     860             :                                                           CurrentOpMode,
     861             :                                                           PLRforSubtimestepStartUp,
     862             :                                                           PLRforSubtimestepShutDown);
     863             : 
     864       15328 :     if (RunFlagElectCenter || RunFlagPlant) RunFlag = true;
     865             : 
     866       15328 :     Real64 Teng = this->A42Model.Teng;
     867       15328 :     Real64 TcwOut = this->A42Model.TcwOut;
     868             : 
     869             :     Real64 thisAmbientTemp;
     870       15328 :     if (this->ZoneID > 0) {
     871       15328 :         thisAmbientTemp = state.dataZoneTempPredictorCorrector->zoneHeatBalance(this->ZoneID).MAT;
     872             :     } else { // outdoor location, no zone
     873           0 :         thisAmbientTemp = state.dataEnvrn->OutDryBulbTemp;
     874             :     }
     875             : 
     876       15328 :     Real64 Pnetss = 0.0;
     877       15328 :     Real64 Pstandby = 0.0; // power draw during standby, positive here means negative production
     878       15328 :     Real64 Pcooler = 0.0;  // power draw during cool down, positive here means negative production
     879       15328 :     Real64 NdotFuel = 0.0;
     880       15328 :     Real64 ElecEff = 0.0;
     881       15328 :     Real64 MdotAir = 0.0;
     882       15328 :     Real64 Qgenss = 0.0;
     883       15328 :     Real64 MdotCW = 0.0;
     884       15328 :     Real64 TcwIn = 0.0;
     885       15328 :     Real64 MdotFuel = 0.0;
     886       15328 :     Real64 Qgross = 0.0;
     887       15328 :     Real64 ThermEff = 0.0;
     888             : 
     889       15328 :     switch (CurrentOpMode) {
     890        5630 :     case DataGenerators::OperatingMode::Off: { // same as standby in model spec but no Pnet standby electicity losses.
     891             : 
     892        5630 :         Qgenss = 0.0;
     893        5630 :         MdotCW = state.dataLoopNodes->Node(this->PlantInletNodeID).MassFlowRate; // kg/s
     894        5630 :         TcwIn = state.dataLoopNodes->Node(this->PlantInletNodeID).Temp;          // C
     895        5630 :         Pnetss = 0.0;
     896        5630 :         Pstandby = 0.0;
     897        5630 :         Pcooler = this->A42Model.PcoolDown * PLRforSubtimestepShutDown;
     898        5630 :         ElecEff = 0.0;
     899        5630 :         ThermEff = 0.0;
     900        5630 :         Qgross = 0.0;
     901        5630 :         NdotFuel = 0.0;
     902        5630 :         MdotFuel = 0.0;
     903        5630 :         MdotAir = 0.0;
     904             : 
     905        5630 :         MdotCW = 0.0;
     906        5630 :         PlantUtilities::SetComponentFlowRate(state, MdotCW, this->PlantInletNodeID, this->PlantOutletNodeID, this->CWPlantLoc);
     907        5630 :         this->PlantMassFlowRate = MdotCW;
     908        5630 :     } break;
     909        4554 :     case DataGenerators::OperatingMode::Standby: {
     910        4554 :         Qgenss = 0.0;
     911        4554 :         MdotCW = state.dataLoopNodes->Node(this->PlantInletNodeID).MassFlowRate; // kg/s
     912        4554 :         TcwIn = state.dataLoopNodes->Node(this->PlantInletNodeID).Temp;          // C
     913        4554 :         Pnetss = 0.0;
     914        4554 :         Pstandby = this->A42Model.Pstandby * (1.0 - PLRforSubtimestepShutDown);
     915        4554 :         Pcooler = this->A42Model.PcoolDown * PLRforSubtimestepShutDown;
     916        4554 :         ElecEff = 0.0;
     917        4554 :         ThermEff = 0.0;
     918        4554 :         Qgross = 0.0;
     919        4554 :         NdotFuel = 0.0;
     920        4554 :         MdotFuel = 0.0;
     921        4554 :         MdotAir = 0.0;
     922             : 
     923        4554 :         MdotCW = 0.0;
     924        4554 :         PlantUtilities::SetComponentFlowRate(state, MdotCW, this->PlantInletNodeID, this->PlantOutletNodeID, this->CWPlantLoc);
     925        4554 :         this->PlantMassFlowRate = MdotCW;
     926        4554 :     } break;
     927           0 :     case DataGenerators::OperatingMode::WarmUp: {
     928           0 :         if (this->A42Model.WarmUpByTimeDelay) {
     929             :             // Internal combustion engine.  This is just like normal  operation but no net power yet.
     930           0 :             Pnetss = MyElectricLoad; // W
     931           0 :             Pstandby = 0.0;
     932           0 :             Pcooler = this->A42Model.PcoolDown * PLRforSubtimestepShutDown;
     933           0 :             TcwIn = state.dataLoopNodes->Node(this->PlantInletNodeID).Temp;          // C
     934           0 :             MdotCW = state.dataLoopNodes->Node(this->PlantInletNodeID).MassFlowRate; // kg/s
     935           0 :             if (this->A42Model.InternalFlowControl) {
     936           0 :                 MdotCW = GeneratorDynamicsManager::FuncDetermineCWMdotForInternalFlowControl(state, this->DynamicsControlID, Pnetss, TcwIn);
     937             :             }
     938           0 :             ElecEff = Curve::CurveValue(state, this->A42Model.ElecEffCurveID, Pnetss, MdotCW, TcwIn);
     939           0 :             ElecEff = max(0.0, ElecEff); // protect against bad curve result
     940             : 
     941           0 :             if (ElecEff > 0.0) {           // trap divide by bad thing
     942           0 :                 Qgross = Pnetss / ElecEff; // W
     943             :             } else {
     944           0 :                 Qgross = 0.0;
     945             :             }
     946           0 :             ThermEff = Curve::CurveValue(state, this->A42Model.ThermalEffCurveID, Pnetss, MdotCW, TcwIn);
     947           0 :             ThermEff = max(0.0, ThermEff); // protect against bad curve result
     948             : 
     949           0 :             Qgenss = ThermEff * Qgross; // W
     950             : 
     951           0 :             MdotFuel = Qgross / (state.dataGenerator->FuelSupply(this->FuelSupplyID).LHV * 1000.0 * 1000.0) *
     952           0 :                        state.dataGenerator->FuelSupply(this->FuelSupplyID).KmolPerSecToKgPerSec;
     953             :             //  kMol/s = (J/s) /(KJ/mol * 1000 J/KJ * 1000 mol/kmol)
     954             : 
     955           0 :             bool ConstrainedIncreasingNdot(false);
     956           0 :             bool ConstrainedDecreasingNdot(false);
     957           0 :             Real64 MdotFuelAllowed = 0.0;
     958             : 
     959           0 :             GeneratorDynamicsManager::ManageGeneratorFuelFlow(
     960             :                 state, this->DynamicsControlID, MdotFuel, MdotFuelAllowed, ConstrainedIncreasingNdot, ConstrainedDecreasingNdot);
     961             : 
     962           0 :             if (ConstrainedIncreasingNdot || ConstrainedDecreasingNdot) { // recalculate Pnetss with new NdotFuel with iteration
     963           0 :                 MdotFuel = MdotFuelAllowed;
     964           0 :                 NdotFuel = MdotFuel / state.dataGenerator->FuelSupply(this->FuelSupplyID).KmolPerSecToKgPerSec;
     965           0 :                 Qgross = NdotFuel * (state.dataGenerator->FuelSupply(this->FuelSupplyID).LHV * 1000.0 * 1000.0);
     966             : 
     967           0 :                 for (int i = 1; i <= 20; ++i) { // iterating here  could add use of seach method
     968           0 :                     Pnetss = Qgross * ElecEff;
     969           0 :                     if (this->A42Model.InternalFlowControl) {
     970           0 :                         MdotCW = GeneratorDynamicsManager::FuncDetermineCWMdotForInternalFlowControl(state, this->DynamicsControlID, Pnetss, TcwIn);
     971             :                     }
     972           0 :                     ElecEff = Curve::CurveValue(state, this->A42Model.ElecEffCurveID, Pnetss, MdotCW, TcwIn);
     973           0 :                     ElecEff = max(0.0, ElecEff); // protect against bad curve result
     974             :                 }
     975             : 
     976           0 :                 ThermEff = Curve::CurveValue(state, this->A42Model.ThermalEffCurveID, Pnetss, MdotCW, TcwIn);
     977           0 :                 ThermEff = max(0.0, ThermEff); // protect against bad curve result
     978           0 :                 Qgenss = ThermEff * Qgross;    // W
     979             :             }
     980           0 :             Pnetss = 0.0; // no actually power produced here.
     981           0 :             NdotFuel = MdotFuel / state.dataGenerator->FuelSupply(this->FuelSupplyID).KmolPerSecToKgPerSec;
     982           0 :             MdotAir = Curve::CurveValue(state, this->A42Model.AirFlowCurveID, MdotFuel);
     983           0 :             MdotAir = max(0.0, MdotAir); // protect against bad curve result
     984             : 
     985           0 :         } else if (this->A42Model.WarmUpByEngineTemp) {
     986             :             // Stirling engine mode warm up
     987             :             //   find MdotFuelMax
     988           0 :             Real64 Pmax = this->A42Model.MaxElecPower;
     989           0 :             Pstandby = 0.0;
     990           0 :             Pcooler = this->A42Model.PcoolDown * PLRforSubtimestepShutDown;          // could be here with part load in cool down
     991           0 :             TcwIn = state.dataLoopNodes->Node(this->PlantInletNodeID).Temp;          // C
     992           0 :             MdotCW = state.dataLoopNodes->Node(this->PlantInletNodeID).MassFlowRate; // kg/s
     993           0 :             ElecEff = Curve::CurveValue(state, this->A42Model.ElecEffCurveID, Pmax, MdotCW, TcwIn);
     994           0 :             ElecEff = max(0.0, ElecEff); // protect against bad curve result
     995           0 :             if (ElecEff > 0.0) {         // trap divide by bad thing
     996           0 :                 Qgross = Pmax / ElecEff; // W
     997             :             } else {
     998           0 :                 Qgross = 0.0;
     999             :             }
    1000           0 :             NdotFuel = Qgross / (state.dataGenerator->FuelSupply(this->FuelSupplyID).LHV * 1000.0 * 1000.0);
    1001             :             //  kMol/s = (J/s) /(KJ/mol * 1000 J/KJ * 1000 mol/kmol)
    1002           0 :             Real64 MdotFuelMax = NdotFuel * state.dataGenerator->FuelSupply(this->FuelSupplyID).KmolPerSecToKgPerSec;
    1003             : 
    1004             :             Real64 MdotFuelWarmup;
    1005           0 :             if (Teng > thisAmbientTemp) {
    1006           0 :                 MdotFuelWarmup =
    1007           0 :                     MdotFuelMax + this->A42Model.kf * MdotFuelMax * ((this->A42Model.TnomEngOp - thisAmbientTemp) / (Teng - thisAmbientTemp));
    1008             :                 // check that numerical answer didn't blow up beyond limit, and reset if it did
    1009           0 :                 if (MdotFuelWarmup > this->A42Model.Rfuelwarmup * MdotFuelMax) {
    1010           0 :                     MdotFuelWarmup = this->A42Model.Rfuelwarmup * MdotFuelMax;
    1011             :                 }
    1012             :             } else { // equal would divide by zero
    1013           0 :                 MdotFuelWarmup = this->A42Model.Rfuelwarmup * MdotFuelMax;
    1014             :             }
    1015             : 
    1016           0 :             if (this->A42Model.TnomEngOp > thisAmbientTemp) {
    1017           0 :                 Pnetss = Pmax * this->A42Model.kp * ((Teng - thisAmbientTemp) / (this->A42Model.TnomEngOp - thisAmbientTemp));
    1018             :             } else { // equal would divide by zero
    1019           0 :                 Pnetss = Pmax;
    1020             :             }
    1021             : 
    1022           0 :             MdotFuel = MdotFuelWarmup;
    1023           0 :             NdotFuel = MdotFuel / state.dataGenerator->FuelSupply(this->FuelSupplyID).KmolPerSecToKgPerSec;
    1024           0 :             MdotAir = Curve::CurveValue(state, this->A42Model.AirFlowCurveID, MdotFuelWarmup);
    1025           0 :             MdotAir = max(0.0, MdotAir); // protect against bad curve result
    1026           0 :             Qgross = NdotFuel * (state.dataGenerator->FuelSupply(this->FuelSupplyID).LHV * 1000.0 * 1000.0);
    1027           0 :             ThermEff = Curve::CurveValue(state, this->A42Model.ThermalEffCurveID, Pmax, MdotCW, TcwIn);
    1028           0 :             Qgenss = ThermEff * Qgross; // W
    1029             :         }
    1030           0 :         NdotFuel = MdotFuel / state.dataGenerator->FuelSupply(this->FuelSupplyID).KmolPerSecToKgPerSec;
    1031           0 :     } break;
    1032        5144 :     case DataGenerators::OperatingMode::Normal: {
    1033        5144 :         if (PLRforSubtimestepStartUp < 1.0) {
    1034        1496 :             if (RunFlagElectCenter) Pnetss = MyElectricLoad; // W
    1035        1496 :             if (RunFlagPlant) Pnetss = AllowedLoad;
    1036             :         } else {
    1037        3648 :             Pnetss = AllowedLoad;
    1038             :         }
    1039        5144 :         Pstandby = 0.0;
    1040        5144 :         Pcooler = 0.0;
    1041        5144 :         TcwIn = state.dataLoopNodes->Node(this->PlantInletNodeID).Temp;          // C
    1042        5144 :         MdotCW = state.dataLoopNodes->Node(this->PlantInletNodeID).MassFlowRate; // kg/s
    1043        5144 :         if (this->A42Model.InternalFlowControl) {
    1044        4640 :             MdotCW = GeneratorDynamicsManager::FuncDetermineCWMdotForInternalFlowControl(state, this->DynamicsControlID, Pnetss, TcwIn);
    1045             :         }
    1046             : 
    1047        5144 :         ElecEff = Curve::CurveValue(state, this->A42Model.ElecEffCurveID, Pnetss, MdotCW, TcwIn);
    1048        5144 :         ElecEff = max(0.0, ElecEff); // protect against bad curve result
    1049             : 
    1050        5144 :         if (ElecEff > 0.0) {           // trap divide by bad thing
    1051        5144 :             Qgross = Pnetss / ElecEff; // W
    1052             :         } else {
    1053           0 :             Qgross = 0.0;
    1054             :         }
    1055             : 
    1056        5144 :         ThermEff = Curve::CurveValue(state, this->A42Model.ThermalEffCurveID, Pnetss, MdotCW, TcwIn);
    1057        5144 :         ThermEff = max(0.0, ThermEff); // protect against bad curve result
    1058        5144 :         Qgenss = ThermEff * Qgross;    // W
    1059        5144 :         MdotFuel = Qgross / (state.dataGenerator->FuelSupply(this->FuelSupplyID).LHV * 1000.0 * 1000.0) *
    1060        5144 :                    state.dataGenerator->FuelSupply(this->FuelSupplyID).KmolPerSecToKgPerSec;
    1061             :         //  kMol/s = (J/s) /(KJ/mol * 1000 J/KJ * 1000 mol/kmol)
    1062             : 
    1063        5144 :         bool ConstrainedIncreasingNdot(false);
    1064        5144 :         bool ConstrainedDecreasingNdot(false);
    1065        5144 :         Real64 MdotFuelAllowed = 0.0;
    1066             : 
    1067        5144 :         GeneratorDynamicsManager::ManageGeneratorFuelFlow(
    1068             :             state, this->DynamicsControlID, MdotFuel, MdotFuelAllowed, ConstrainedIncreasingNdot, ConstrainedDecreasingNdot);
    1069             : 
    1070        5144 :         if (ConstrainedIncreasingNdot || ConstrainedDecreasingNdot) { // recalculate Pnetss with new NdotFuel with iteration
    1071           0 :             MdotFuel = MdotFuelAllowed;
    1072           0 :             NdotFuel = MdotFuel / state.dataGenerator->FuelSupply(this->FuelSupplyID).KmolPerSecToKgPerSec;
    1073           0 :             Qgross = NdotFuel * (state.dataGenerator->FuelSupply(this->FuelSupplyID).LHV * 1000.0 * 1000.0);
    1074             : 
    1075           0 :             for (int i = 1; i <= 20; ++i) { // iterating here,  could add use of seach method error signal
    1076           0 :                 Pnetss = Qgross * ElecEff;
    1077           0 :                 if (this->A42Model.InternalFlowControl) {
    1078           0 :                     MdotCW = GeneratorDynamicsManager::FuncDetermineCWMdotForInternalFlowControl(state, this->DynamicsControlID, Pnetss, TcwIn);
    1079             :                 }
    1080           0 :                 ElecEff = Curve::CurveValue(state, this->A42Model.ElecEffCurveID, Pnetss, MdotCW, TcwIn);
    1081           0 :                 ElecEff = max(0.0, ElecEff); // protect against bad curve result
    1082             :             }
    1083             : 
    1084           0 :             ThermEff = Curve::CurveValue(state, this->A42Model.ThermalEffCurveID, Pnetss, MdotCW, TcwIn);
    1085           0 :             ThermEff = max(0.0, ThermEff); // protect against bad curve result
    1086           0 :             Qgenss = ThermEff * Qgross;    // W
    1087             :         }
    1088             : 
    1089        5144 :         NdotFuel = MdotFuel / state.dataGenerator->FuelSupply(this->FuelSupplyID).KmolPerSecToKgPerSec;
    1090        5144 :         MdotAir = Curve::CurveValue(state, this->A42Model.AirFlowCurveID, MdotFuel);
    1091        5144 :         MdotAir = max(0.0, MdotAir); // protect against bad curve result
    1092        5144 :         if (PLRforSubtimestepStartUp < 1.0) {
    1093        1496 :             Pnetss = AllowedLoad;
    1094             :         }
    1095        5144 :     } break;
    1096           0 :     case DataGenerators::OperatingMode::CoolDown: {
    1097           0 :         Pnetss = 0.0;
    1098           0 :         Pstandby = 0.0;
    1099           0 :         Pcooler = this->A42Model.PcoolDown;
    1100           0 :         TcwIn = state.dataLoopNodes->Node(this->PlantInletNodeID).Temp;          // C
    1101           0 :         MdotCW = state.dataLoopNodes->Node(this->PlantInletNodeID).MassFlowRate; // kg/s
    1102           0 :         if (this->A42Model.InternalFlowControl) {
    1103           0 :             MdotCW = GeneratorDynamicsManager::FuncDetermineCWMdotForInternalFlowControl(state, this->DynamicsControlID, Pnetss, TcwIn);
    1104             :         }
    1105           0 :         NdotFuel = 0.0;
    1106           0 :         MdotFuel = 0.0;
    1107           0 :         MdotAir = 0.0;
    1108           0 :         ElecEff = 0.0;
    1109           0 :         ThermEff = 0.0;
    1110           0 :         Qgross = 0.0;
    1111           0 :         Qgenss = 0.0;
    1112           0 :     } break;
    1113           0 :     default:
    1114           0 :         break;
    1115             :     }
    1116             : 
    1117       76640 :     for (int i = 1; i <= 20; ++i) { // sequential search with exit criteria
    1118             :         // calculate new value for engine temperature
    1119             :         // for Stirling in warmup, need to include dependency of Qgness on Teng
    1120       76640 :         if ((this->A42Model.WarmUpByEngineTemp) && (CurrentOpMode == DataGenerators::OperatingMode::WarmUp)) {
    1121             : 
    1122           0 :             Real64 Pmax = this->A42Model.MaxElecPower;
    1123           0 :             TcwIn = state.dataLoopNodes->Node(this->PlantInletNodeID).Temp;          // C
    1124           0 :             MdotCW = state.dataLoopNodes->Node(this->PlantInletNodeID).MassFlowRate; // kg/s
    1125           0 :             ElecEff = Curve::CurveValue(state, this->A42Model.ElecEffCurveID, Pmax, MdotCW, TcwIn);
    1126           0 :             ElecEff = max(0.0, ElecEff); // protect against bad curve result
    1127           0 :             if (ElecEff > 0.0) {         // trap divide by bad thing
    1128           0 :                 Qgross = Pmax / ElecEff; // W
    1129             :             } else {
    1130           0 :                 Qgross = 0.0;
    1131             :             }
    1132           0 :             NdotFuel = Qgross / (state.dataGenerator->FuelSupply(this->FuelSupplyID).LHV * 1000.0 * 1000.0);
    1133             :             //  kMol/s = (J/s) /(KJ/mol * 1000 J/KJ * 1000 mol/kmol)
    1134           0 :             Real64 MdotFuelMax = NdotFuel * state.dataGenerator->FuelSupply(this->FuelSupplyID).KmolPerSecToKgPerSec;
    1135             : 
    1136             :             Real64 MdotFuelWarmup;
    1137           0 :             if (Teng > thisAmbientTemp) {
    1138           0 :                 MdotFuelWarmup =
    1139           0 :                     MdotFuelMax + this->A42Model.kf * MdotFuelMax * ((this->A42Model.TnomEngOp - thisAmbientTemp) / (Teng - thisAmbientTemp));
    1140             : 
    1141             :                 // check that numerical answer didn't blow up beyond limit, and reset if it did
    1142           0 :                 if (MdotFuelWarmup > this->A42Model.Rfuelwarmup * MdotFuelMax) {
    1143           0 :                     MdotFuelWarmup = this->A42Model.Rfuelwarmup * MdotFuelMax;
    1144             :                 }
    1145           0 :                 if (this->A42Model.TnomEngOp > thisAmbientTemp) {
    1146           0 :                     Pnetss = Pmax * this->A42Model.kp * ((Teng - thisAmbientTemp) / (this->A42Model.TnomEngOp - thisAmbientTemp));
    1147             :                 } else { // equal would divide by zero
    1148           0 :                     Pnetss = Pmax;
    1149             :                 }
    1150             :             } else { // equal would divide by zero
    1151           0 :                 MdotFuelWarmup = this->A42Model.Rfuelwarmup * MdotFuelMax;
    1152             :             }
    1153           0 :             MdotFuel = MdotFuelWarmup;
    1154           0 :             NdotFuel = MdotFuel / state.dataGenerator->FuelSupply(this->FuelSupplyID).KmolPerSecToKgPerSec;
    1155           0 :             MdotAir = Curve::CurveValue(state, this->A42Model.AirFlowCurveID, MdotFuelWarmup);
    1156           0 :             MdotAir = max(0.0, MdotAir); // protect against bad curve result
    1157           0 :             Qgross = NdotFuel * (state.dataGenerator->FuelSupply(this->FuelSupplyID).LHV * 1000.0 * 1000.0);
    1158           0 :             ThermEff = Curve::CurveValue(state, this->A42Model.ThermalEffCurveID, Pmax, MdotCW, TcwIn);
    1159           0 :             ThermEff = max(0.0, ThermEff); // protect against bad curve result
    1160           0 :             Qgenss = ThermEff * Qgross;    // W
    1161             :         }
    1162             : 
    1163       76640 :         Real64 dt = state.dataHVACGlobal->TimeStepSysSec;
    1164             : 
    1165       76640 :         Teng = FuncDetermineEngineTemp(
    1166             :             TcwOut, this->A42Model.MCeng, this->A42Model.UAhx, this->A42Model.UAskin, thisAmbientTemp, Qgenss, this->A42Model.TengLast, dt);
    1167             : 
    1168       76640 :         Real64 Cp = FluidProperties::GetSpecificHeatGlycol(state,
    1169       76640 :                                                            state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).FluidName,
    1170             :                                                            TcwIn,
    1171       76640 :                                                            state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).FluidIndex,
    1172             :                                                            RoutineName);
    1173             : 
    1174             :         TcwOut =
    1175       76640 :             FuncDetermineCoolantWaterExitTemp(TcwIn, this->A42Model.MCcw, this->A42Model.UAhx, MdotCW * Cp, Teng, this->A42Model.TempCWOutLast, dt);
    1176             : 
    1177             :         // form balance and exit once met.
    1178       76640 :         bool EnergyBalOK = CheckMicroCHPThermalBalance(this->A42Model.MaxElecPower,
    1179             :                                                        TcwIn,
    1180             :                                                        TcwOut,
    1181             :                                                        Teng,
    1182             :                                                        thisAmbientTemp,
    1183             :                                                        this->A42Model.UAhx,
    1184             :                                                        this->A42Model.UAskin,
    1185             :                                                        Qgenss,
    1186             :                                                        this->A42Model.MCeng,
    1187             :                                                        this->A42Model.MCcw,
    1188             :                                                        MdotCW * Cp);
    1189             : 
    1190       76640 :         if (EnergyBalOK && (i > 4)) break;
    1191             :     }
    1192             : 
    1193       15328 :     this->PlantMassFlowRate = MdotCW;
    1194       15328 :     this->A42Model.Pnet = Pnetss - Pcooler - Pstandby;
    1195       15328 :     this->A42Model.ElecEff = ElecEff;
    1196       15328 :     this->A42Model.Qgross = Qgross;
    1197       15328 :     this->A42Model.ThermEff = ThermEff;
    1198       15328 :     this->A42Model.Qgenss = Qgenss;
    1199       15328 :     this->A42Model.NdotFuel = NdotFuel;
    1200       15328 :     this->A42Model.MdotFuel = MdotFuel;
    1201       15328 :     this->A42Model.Teng = Teng;
    1202       15328 :     this->A42Model.TcwOut = TcwOut;
    1203       15328 :     this->A42Model.TcwIn = TcwIn;
    1204       15328 :     this->A42Model.MdotAir = MdotAir;
    1205       15328 :     this->A42Model.QdotSkin = this->A42Model.UAskin * (Teng - thisAmbientTemp);
    1206             : 
    1207       15328 :     this->A42Model.OpMode = CurrentOpMode;
    1208       15328 : }
    1209             : 
    1210       76640 : Real64 FuncDetermineEngineTemp(Real64 const TcwOut,   // hot water leaving temp
    1211             :                                Real64 const MCeng,    // Fictitious mass and heat capacity of engine
    1212             :                                Real64 const UAHX,     // Heat exchanger UA
    1213             :                                Real64 const UAskin,   // Skin losses UA
    1214             :                                Real64 const Troom,    // surrounding zone temperature C
    1215             :                                Real64 const Qgenss,   // steady state generator heat generation
    1216             :                                Real64 const TengLast, // engine temp at previous time step
    1217             :                                Real64 const time      // elapsed time since previous evaluation
    1218             : )
    1219             : {
    1220             : 
    1221             :     // FUNCTION INFORMATION:
    1222             :     //       AUTHOR         B. Griffith
    1223             :     //       DATE WRITTEN   Feb. 2007
    1224             :     //       MODIFIED       na
    1225             :     //       RE-ENGINEERED  na
    1226             : 
    1227             :     // PURPOSE OF THIS FUNCTION:
    1228             :     // Calculate engine temperaure,
    1229             : 
    1230             :     // METHODOLOGY EMPLOYED:
    1231             :     // model is dynamic in that previous condition affects current timestep
    1232             :     //  solve ode for engine temp using analytical solution
    1233             : 
    1234       76640 :     Real64 a = ((UAHX * TcwOut / MCeng) + (UAskin * Troom / MCeng) + (Qgenss / MCeng));
    1235       76640 :     Real64 b = ((-1.0 * UAHX / MCeng) + (-1.0 * UAskin / MCeng));
    1236             : 
    1237       76640 :     return (TengLast + a / b) * std::exp(b * time) - a / b;
    1238             : }
    1239             : 
    1240       76640 : Real64 FuncDetermineCoolantWaterExitTemp(Real64 const TcwIn,      // hot water inlet temp
    1241             :                                          Real64 const MCcw,       // Fictitious mass and heat capacity of coolant hx
    1242             :                                          Real64 const UAHX,       // Heat exchanger UA
    1243             :                                          Real64 const MdotCpcw,   // mass flow and specific heat of coolant water
    1244             :                                          Real64 const Teng,       // engine mass temperature C
    1245             :                                          Real64 const TcwoutLast, // coolant water leaving temp at previous time step
    1246             :                                          Real64 const time        // elapsed time since previous evaluation
    1247             : )
    1248             : {
    1249             : 
    1250             :     // FUNCTION INFORMATION:
    1251             :     //       AUTHOR         B. Griffith
    1252             :     //       DATE WRITTEN   Feb. 2007
    1253             :     //       MODIFIED       na
    1254             :     //       RE-ENGINEERED  na
    1255             : 
    1256             :     // PURPOSE OF THIS FUNCTION:
    1257             :     // Calculate coolan water leaving temperaure,
    1258             : 
    1259             :     // METHODOLOGY EMPLOYED:
    1260             :     // model is dynamic in that previous condition affects current timestep
    1261             :     //  solve ode for coolant water outlet temp using analytical solution
    1262             : 
    1263       76640 :     Real64 a = (MdotCpcw * TcwIn / MCcw) + (UAHX * Teng / MCcw);
    1264       76640 :     Real64 b = ((-1.0 * MdotCpcw / MCcw) + (-1.0 * UAHX / MCcw));
    1265             : 
    1266       76640 :     if (b * time < (-1.0 * Constant::MaxEXPArg)) {
    1267       23220 :         return -a / b;
    1268             :     } else {
    1269       53420 :         return (TcwoutLast + a / b) * std::exp(b * time) - a / b;
    1270             :     }
    1271             : }
    1272             : 
    1273       76640 : bool CheckMicroCHPThermalBalance(Real64 const NomHeatGen, // nominal heat generation rate for scaling
    1274             :                                  Real64 const TcwIn,      // hot water inlet temp
    1275             :                                  Real64 const TcwOut,     // hot water leaving temp
    1276             :                                  Real64 const Teng,       // engine mass temperature C
    1277             :                                  Real64 const Troom,      // surrounding zone temperature C
    1278             :                                  Real64 const UAHX,       // Heat exchanger UA
    1279             :                                  Real64 const UAskin,     // Skin losses UA
    1280             :                                  Real64 const Qgenss,     // steady state generator heat generation
    1281             :                                  Real64 const MCeng,      // Fictitious mass and heat capacity of engine
    1282             :                                  Real64 const MCcw,       // Fictitious mass and heat capacity of coolant hx
    1283             :                                  Real64 const MdotCpcw    // mass flow and specific heat of coolant water
    1284             : )
    1285             : {
    1286             : 
    1287             :     // FUNCTION INFORMATION:
    1288             :     //       AUTHOR         B. Griffith
    1289             :     //       DATE WRITTEN   Feb. 2007
    1290             :     //       MODIFIED       na
    1291             :     //       RE-ENGINEERED  na
    1292             : 
    1293             :     // PURPOSE OF THIS FUNCTION:
    1294             :     // Check for energy balance to test if can exit iteration loop
    1295             : 
    1296             :     // METHODOLOGY EMPLOYED:
    1297             :     // put all terms of dynamic energy balances on RHS and compute magnitude of imbalance
    1298             :     //  compare imbalance to scalable thresholds and make a boolean conclusion.
    1299             : 
    1300             :     // first compute derivatives using a + bT
    1301             :     // derivative of engine temp wrt time
    1302       76640 :     Real64 a = ((UAHX * TcwOut / MCeng) + (UAskin * Troom / MCeng) + (Qgenss / MCeng));
    1303       76640 :     Real64 b = ((-1.0 * UAHX / MCeng) + (-1.0 * UAskin / MCeng));
    1304       76640 :     Real64 DTengDTime = a + b * Teng;
    1305             : 
    1306             :     // derivative of coolant exit temp wrt time
    1307       76640 :     Real64 c = (MdotCpcw * TcwIn / MCcw) + (UAHX * Teng / MCcw);
    1308       76640 :     Real64 d = ((-1.0 * MdotCpcw / MCcw) + (-1.0 * UAHX / MCcw));
    1309       76640 :     Real64 DCoolOutTDtime = c + d * TcwOut;
    1310             : 
    1311             :     // energy imbalance for engine control volume
    1312       76640 :     Real64 magImbalEng = UAHX * (TcwOut - Teng) + UAskin * (Troom - Teng) + Qgenss - MCeng * DTengDTime;
    1313             : 
    1314             :     // energy imbalance for coolant control volume
    1315       76640 :     Real64 magImbalCooling = MdotCpcw * (TcwIn - TcwOut) + UAHX * (Teng - TcwOut) - MCcw * DCoolOutTDtime;
    1316             : 
    1317             :     // criteria for when to call energy balance okay
    1318       76640 :     Real64 threshold = NomHeatGen / 10000000.0;
    1319             : 
    1320       76640 :     return (threshold > magImbalEng) && (threshold > magImbalCooling);
    1321             : }
    1322             : 
    1323     2804678 : void FigureMicroCHPZoneGains(EnergyPlusData &state)
    1324             : {
    1325             : 
    1326             :     // SUBROUTINE INFORMATION:
    1327             :     //       AUTHOR         B. Griffith
    1328             :     //       DATE WRITTEN   July 2006
    1329             :     //       MODIFIED       na
    1330             :     //       RE-ENGINEERED  na
    1331             : 
    1332             :     // PURPOSE OF THIS SUBROUTINE:
    1333             :     // Couple equipment skin losses to the Zone Heat Balance
    1334             : 
    1335             :     // METHODOLOGY EMPLOYED:
    1336             :     // This routine adds up the various skin losses and then
    1337             :     //  sets the values in the ZoneIntGain structure
    1338             : 
    1339     2804678 :     if (state.dataCHPElectGen->NumMicroCHPs == 0) return;
    1340             : 
    1341        6934 :     if (state.dataGlobal->BeginEnvrnFlag && state.dataCHPElectGen->MyEnvrnFlag) {
    1342          32 :         for (auto &e : state.dataGenerator->FuelSupply)
    1343          20 :             e.QskinLoss = 0.0;
    1344          24 :         for (auto &e : state.dataCHPElectGen->MicroCHP) {
    1345          12 :             e.A42Model.QdotSkin = 0.0;
    1346          12 :             e.A42Model.SkinLossConvect = 0.0;
    1347          12 :             e.A42Model.SkinLossRadiat = 0.0;
    1348          12 :         }
    1349          12 :         state.dataCHPElectGen->MyEnvrnFlag = false;
    1350             :     }
    1351             : 
    1352        6934 :     if (!state.dataGlobal->BeginEnvrnFlag) state.dataCHPElectGen->MyEnvrnFlag = true;
    1353             : 
    1354       13868 :     for (int CHPnum = 1; CHPnum <= state.dataCHPElectGen->NumMicroCHPs; ++CHPnum) {
    1355        6934 :         Real64 TotalZoneHeatGain = state.dataGenerator->FuelSupply(state.dataCHPElectGen->MicroCHP(CHPnum).FuelSupplyID).QskinLoss +
    1356        6934 :                                    state.dataCHPElectGen->MicroCHP(CHPnum).A42Model.QdotSkin;
    1357             : 
    1358        6934 :         state.dataCHPElectGen->MicroCHP(CHPnum).A42Model.QdotConvZone =
    1359        6934 :             TotalZoneHeatGain * (1 - state.dataCHPElectGen->MicroCHP(CHPnum).A42Model.RadiativeFraction);
    1360        6934 :         state.dataCHPElectGen->MicroCHP(CHPnum).A42Model.SkinLossConvect = state.dataCHPElectGen->MicroCHP(CHPnum).A42Model.QdotConvZone;
    1361        6934 :         state.dataCHPElectGen->MicroCHP(CHPnum).A42Model.QdotRadZone =
    1362        6934 :             TotalZoneHeatGain * state.dataCHPElectGen->MicroCHP(CHPnum).A42Model.RadiativeFraction;
    1363        6934 :         state.dataCHPElectGen->MicroCHP(CHPnum).A42Model.SkinLossRadiat = state.dataCHPElectGen->MicroCHP(CHPnum).A42Model.QdotRadZone;
    1364             :     }
    1365             : }
    1366             : 
    1367       15328 : void MicroCHPDataStruct::CalcUpdateHeatRecovery(EnergyPlusData &state) const
    1368             : {
    1369             : 
    1370             :     // SUBROUTINE INFORMATION:
    1371             :     //       AUTHOR         B Griffith
    1372             :     //       DATE WRITTEN   Aug 2006
    1373             :     //       MODIFIED       na
    1374             :     //       RE-ENGINEERED  na
    1375             : 
    1376             :     // PURPOSE OF THIS SUBROUTINE:
    1377             :     // update plant loop interactions, do any calcs needed
    1378             : 
    1379             :     static constexpr std::string_view RoutineName("CalcUpdateHeatRecovery");
    1380             : 
    1381       15328 :     PlantUtilities::SafeCopyPlantNode(state, this->PlantInletNodeID, this->PlantOutletNodeID);
    1382             : 
    1383       15328 :     state.dataLoopNodes->Node(this->PlantOutletNodeID).Temp = this->A42Model.TcwOut;
    1384             : 
    1385       15328 :     Real64 Cp = FluidProperties::GetSpecificHeatGlycol(state,
    1386       15328 :                                                        state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).FluidName,
    1387       15328 :                                                        this->A42Model.TcwIn,
    1388       15328 :                                                        state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).FluidIndex,
    1389             :                                                        RoutineName);
    1390             : 
    1391       15328 :     state.dataLoopNodes->Node(this->PlantOutletNodeID).Enthalpy = this->A42Model.TcwOut * Cp;
    1392       15328 : }
    1393             : 
    1394          10 : void MicroCHPDataStruct::getDesignCapacities(
    1395             :     [[maybe_unused]] EnergyPlusData &state, const EnergyPlus::PlantLocation &, Real64 &MaxLoad, Real64 &MinLoad, Real64 &OptLoad)
    1396             : {
    1397          10 :     MaxLoad = state.dataGenerator->GeneratorDynamics(this->DynamicsControlID).QdotHXMax;
    1398          10 :     MinLoad = state.dataGenerator->GeneratorDynamics(this->DynamicsControlID).QdotHXMin;
    1399          10 :     OptLoad = state.dataGenerator->GeneratorDynamics(this->DynamicsControlID).QdotHXOpt;
    1400          10 : }
    1401             : 
    1402       15328 : void MicroCHPDataStruct::UpdateMicroCHPGeneratorRecords(EnergyPlusData &state) // Generator number
    1403             : {
    1404             : 
    1405             :     // SUBROUTINE INFORMATION:
    1406             :     //       AUTHOR         B. Griffith
    1407             :     //       DATE WRITTEN   July 2006
    1408             :     //       MODIFIED       na
    1409             :     //       RE-ENGINEERED  na
    1410             : 
    1411             :     // PURPOSE OF THIS SUBROUTINE:
    1412             :     // update variables in structures linked to output reports
    1413             : 
    1414             :     static constexpr std::string_view RoutineName("UpdateMicroCHPGeneratorRecords");
    1415             : 
    1416       15328 :     this->A42Model.ACPowerGen = this->A42Model.Pnet;                                             // electrical power produced [W]
    1417       15328 :     this->A42Model.ACEnergyGen = this->A42Model.Pnet * state.dataHVACGlobal->TimeStepSysSec;     // energy produced (J)
    1418       15328 :     this->A42Model.QdotHX = this->A42Model.UAhx * (this->A42Model.Teng - this->A42Model.TcwOut); //  heat recovered rate (W)
    1419             : 
    1420       15328 :     Real64 Cp = FluidProperties::GetSpecificHeatGlycol(state,
    1421       15328 :                                                        state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).FluidName,
    1422             :                                                        this->A42Model.TcwIn,
    1423       15328 :                                                        state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).FluidIndex,
    1424             :                                                        RoutineName);
    1425             : 
    1426       15328 :     this->A42Model.QdotHR = this->PlantMassFlowRate * Cp * (this->A42Model.TcwOut - this->A42Model.TcwIn);
    1427       15328 :     this->A42Model.TotalHeatEnergyRec = this->A42Model.QdotHR * state.dataHVACGlobal->TimeStepSysSec; // heat recovered energy (J)
    1428             : 
    1429       15328 :     this->A42Model.HeatRecInletTemp = this->A42Model.TcwIn;   // Heat Recovery Loop Inlet Temperature (C)
    1430       15328 :     this->A42Model.HeatRecOutletTemp = this->A42Model.TcwOut; // Heat Recovery Loop Outlet Temperature (C)
    1431             : 
    1432       15328 :     this->A42Model.FuelCompressPower = state.dataGenerator->FuelSupply(this->FuelSupplyID).PfuelCompEl;
    1433             :     // electrical power used by fuel supply compressor [W]
    1434       15328 :     this->A42Model.FuelCompressEnergy =
    1435       15328 :         state.dataGenerator->FuelSupply(this->FuelSupplyID).PfuelCompEl * state.dataHVACGlobal->TimeStepSys * Constant::SecInHour; // elect energy
    1436       15328 :     this->A42Model.FuelCompressSkinLoss = state.dataGenerator->FuelSupply(this->FuelSupplyID).QskinLoss;
    1437             :     // heat rate of losses.by fuel supply compressor [W]
    1438       15328 :     this->A42Model.FuelEnergyHHV = this->A42Model.NdotFuel * state.dataGenerator->FuelSupply(this->FuelSupplyID).HHV *
    1439       15328 :                                    state.dataGenerator->FuelSupply(this->FuelSupplyID).KmolPerSecToKgPerSec * state.dataHVACGlobal->TimeStepSys *
    1440             :                                    Constant::SecInHour;
    1441             :     // reporting: Fuel Energy used (W)
    1442       15328 :     this->A42Model.FuelEnergyUseRateHHV = this->A42Model.NdotFuel * state.dataGenerator->FuelSupply(this->FuelSupplyID).HHV *
    1443       15328 :                                           state.dataGenerator->FuelSupply(this->FuelSupplyID).KmolPerSecToKgPerSec;
    1444             :     // reporting: Fuel Energy used (J)
    1445       15328 :     this->A42Model.FuelEnergyLHV =
    1446       15328 :         this->A42Model.NdotFuel * state.dataGenerator->FuelSupply(this->FuelSupplyID).LHV * 1000000.0 * state.dataHVACGlobal->TimeStepSysSec;
    1447             :     // reporting: Fuel Energy used (W)
    1448       15328 :     this->A42Model.FuelEnergyUseRateLHV = this->A42Model.NdotFuel * state.dataGenerator->FuelSupply(this->FuelSupplyID).LHV * 1000000.0;
    1449             : 
    1450       15328 :     this->A42Model.SkinLossPower = this->A42Model.QdotConvZone + this->A42Model.QdotRadZone;
    1451       15328 :     this->A42Model.SkinLossEnergy = (this->A42Model.QdotConvZone + this->A42Model.QdotRadZone) * state.dataHVACGlobal->TimeStepSysSec;
    1452       15328 :     this->A42Model.SkinLossConvect = this->A42Model.QdotConvZone;
    1453       15328 :     this->A42Model.SkinLossRadiat = this->A42Model.QdotRadZone;
    1454             : 
    1455             :     // update node data for air inlet (and outlet)
    1456       15328 :     if (this->AirInletNodeID > 0) {
    1457       15328 :         state.dataLoopNodes->Node(this->AirInletNodeID).MassFlowRate = this->A42Model.MdotAir;
    1458             :     }
    1459       15328 :     if (this->AirOutletNodeID > 0) {
    1460           0 :         state.dataLoopNodes->Node(this->AirOutletNodeID).MassFlowRate = this->A42Model.MdotAir;
    1461           0 :         state.dataLoopNodes->Node(this->AirOutletNodeID).Temp = this->A42Model.Teng;
    1462             :     }
    1463       15328 : }
    1464       17415 : void MicroCHPDataStruct::oneTimeInit(EnergyPlusData &state)
    1465             : {
    1466             : 
    1467             :     bool errFlag;
    1468             : 
    1469       17415 :     if (this->myFlag) {
    1470           2 :         this->setupOutputVars(state);
    1471           2 :         this->myFlag = false;
    1472             :     }
    1473             : 
    1474       17415 :     if (this->MyPlantScanFlag) {
    1475           2 :         if (allocated(state.dataPlnt->PlantLoop)) {
    1476           2 :             errFlag = false;
    1477           4 :             PlantUtilities::ScanPlantLoopsForObject(
    1478           2 :                 state, this->Name, DataPlant::PlantEquipmentType::Generator_MicroCHP, this->CWPlantLoc, errFlag, _, _, _, _, _);
    1479             : 
    1480           2 :             if (errFlag) {
    1481           0 :                 ShowFatalError(state, "InitMicroCHPNoNormalizeGenerators: Program terminated for previous conditions.");
    1482             :             }
    1483             : 
    1484           2 :             if (!this->A42Model.InternalFlowControl) {
    1485             :                 // IF this is on the supply side and not internal flow control then reset flow priority to lower
    1486           1 :                 if (this->CWPlantLoc.loopSideNum == DataPlant::LoopSideLocation::Supply) {
    1487           1 :                     DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).FlowPriority = DataPlant::LoopFlowStatus::TakesWhatGets;
    1488             :                 }
    1489             :             }
    1490             : 
    1491           2 :             this->MyPlantScanFlag = false;
    1492             :         }
    1493             :     }
    1494       17415 : }
    1495             : } // namespace EnergyPlus::MicroCHPElectricGenerator

Generated by: LCOV version 1.14