LCOV - code coverage report
Current view: top level - EnergyPlus - MicroCHPElectricGenerator.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 504 676 74.6 %
Date: 2023-01-17 19:17:23 Functions: 17 17 100.0 %

          Line data    Source code
       1             : // EnergyPlus, Copyright (c) 1996-2023, The Board of Trustees of the University of Illinois,
       2             : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3             : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4             : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5             : // contributors. All rights reserved.
       6             : //
       7             : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8             : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9             : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10             : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11             : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12             : //
      13             : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14             : // provided that the following conditions are met:
      15             : //
      16             : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17             : //     conditions and the following disclaimer.
      18             : //
      19             : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20             : //     conditions and the following disclaimer in the documentation and/or other materials
      21             : //     provided with the distribution.
      22             : //
      23             : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24             : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25             : //     used to endorse or promote products derived from this software without specific prior
      26             : //     written permission.
      27             : //
      28             : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29             : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30             : //     reference solely to the software portion of its product, Licensee must refer to the
      31             : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32             : //     obtained under this License and may not use a different name for the software. Except as
      33             : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34             : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35             : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36             : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37             : //
      38             : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39             : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40             : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41             : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42             : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43             : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44             : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45             : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46             : // POSSIBILITY OF SUCH DAMAGE.
      47             : 
      48             : // C++ Headers
      49             : #include <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       16024 : PlantComponent *MicroCHPDataStruct::factory(EnergyPlusData &state, std::string const &objectName)
     106             : {
     107             :     // Process the input data
     108       16024 :     if (state.dataCHPElectGen->getMicroCHPInputFlag) {
     109           2 :         GetMicroCHPGeneratorInput(state);
     110           2 :         state.dataCHPElectGen->getMicroCHPInputFlag = false;
     111             :     }
     112             : 
     113             :     // Now look for this object
     114       16024 :     for (auto &thisMCHP : state.dataCHPElectGen->MicroCHP) {
     115       16024 :         if (thisMCHP.Name == objectName) {
     116       16024 :             return &thisMCHP;
     117             :         }
     118             :     }
     119             :     // If we didn't find it, fatal
     120             :     ShowFatalError(state, "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           4 :     Array1D_string AlphArray(25);  // character string data
     142           4 :     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           2 :         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, "No " + state.dataIPShortCut->cCurrentModuleObject + " equipment specified in input file");
     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          10 :             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           4 :             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 (UtilityRoutines::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 ((!(UtilityRoutines::SameString(AlphArray(4), "InternalControl"))) && (!(UtilityRoutines::SameString(AlphArray(4), "PlantControl")))) {
     193           0 :                 ShowSevereError(state, "Invalid, " + state.dataIPShortCut->cAlphaFieldNames(4) + " = " + AlphArray(4));
     194           0 :                 ShowContinueError(state, "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, "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, "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 (UtilityRoutines::SameString(AlphArray(7), "TimeDelay")) {
     229           2 :                 state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).WarmUpByTimeDelay = true;
     230           2 :                 state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).WarmUpByEngineTemp = false;
     231             :             }
     232           6 :             if ((!(UtilityRoutines::SameString(AlphArray(7), "NominalEngineTemperature"))) &&
     233           4 :                 (!(UtilityRoutines::SameString(AlphArray(7), "TimeDelay")))) {
     234           0 :                 ShowSevereError(state, "Invalid, " + state.dataIPShortCut->cAlphaFieldNames(7) + " = " + AlphArray(7));
     235           0 :                 ShowContinueError(state, "Entered in " + state.dataIPShortCut->cCurrentModuleObject + '=' + AlphArray(1));
     236           0 :                 ErrorsFound = true;
     237             :             }
     238           2 :             state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).kf = NumArray(13);          // N13 Warmup Fuel Flow Rate Coefficient k_f
     239           2 :             state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).TnomEngOp = NumArray(14);   // N14 Nominal Engine Operating Temperature [C]
     240           2 :             state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).kp = NumArray(15);          // N15 Warmup Power Coefficient k_p
     241           2 :             state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).Rfuelwarmup = NumArray(16); // N16 Warm Up Fuel Flow Rate Limit Ratio
     242           2 :             state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).WarmUpDelay = NumArray(17); // N17 Warm Up Delay Time
     243             : 
     244           2 :             state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).PcoolDown = NumArray(18); // N18 Cool Down Power
     245             : 
     246           2 :             state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).CoolDownDelay = NumArray(19); // N19 Cool Down Delay Time in seconds
     247             : 
     248           2 :             if (UtilityRoutines::SameString(AlphArray(8), "MandatoryCoolDown")) {
     249           1 :                 state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).MandatoryFullCoolDown = true;
     250           1 :                 state.dataCHPElectGen->MicroCHPParamInput(CHPParamNum).WarmRestartOkay = false;
     251             :             }
     252           5 :             if ((!(UtilityRoutines::SameString(AlphArray(8), "MandatoryCoolDown"))) &&
     253           3 :                 (!(UtilityRoutines::SameString(AlphArray(8), "OptionalCoolDown")))) {
     254           0 :                 ShowSevereError(state, "Invalid, " + state.dataIPShortCut->cAlphaFieldNames(8) + " = " + AlphArray(8));
     255           0 :                 ShowContinueError(state, "Entered in " + state.dataIPShortCut->cCurrentModuleObject + '=' + AlphArray(1));
     256           0 :                 ErrorsFound = true;
     257             :             }
     258             :         }
     259             : 
     260           2 :         state.dataIPShortCut->cCurrentModuleObject = "Generator:MicroCHP";
     261           2 :         state.dataCHPElectGen->NumMicroCHPs =
     262           2 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, state.dataIPShortCut->cCurrentModuleObject);
     263             : 
     264           2 :         if (state.dataCHPElectGen->NumMicroCHPs <= 0) {
     265             :             // shouldn't ever come here?
     266           0 :             ShowSevereError(state, "No " + state.dataIPShortCut->cCurrentModuleObject + " equipment specified in input file");
     267           0 :             ErrorsFound = true;
     268             :         }
     269             : 
     270           2 :         if (!(allocated(state.dataCHPElectGen->MicroCHP))) {
     271           2 :             state.dataCHPElectGen->MicroCHP.allocate(state.dataCHPElectGen->NumMicroCHPs); // inits handeled in derived type definitions
     272             :         }
     273             : 
     274             :         // load in Micro CHPs
     275           4 :         for (int GeneratorNum = 1; GeneratorNum <= state.dataCHPElectGen->NumMicroCHPs; ++GeneratorNum) {
     276          10 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     277           2 :                                                                      state.dataIPShortCut->cCurrentModuleObject,
     278             :                                                                      GeneratorNum,
     279             :                                                                      AlphArray,
     280             :                                                                      NumAlphas,
     281             :                                                                      NumArray,
     282             :                                                                      NumNums,
     283             :                                                                      IOStat,
     284             :                                                                      _,
     285           2 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
     286           2 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
     287           2 :                                                                      state.dataIPShortCut->cNumericFieldNames);
     288           2 :             UtilityRoutines::IsNameEmpty(state, AlphArray(1), state.dataIPShortCut->cCurrentModuleObject, ErrorsFound);
     289             : 
     290             :             // GENERATOR:MICRO CHP,
     291           2 :             state.dataCHPElectGen->MicroCHP(GeneratorNum).DynamicsControlID = GeneratorNum;
     292           2 :             state.dataCHPElectGen->MicroCHP(GeneratorNum).Name = AlphArray(1);         //  A1 Generator name
     293           2 :             state.dataCHPElectGen->MicroCHP(GeneratorNum).ParamObjName = AlphArray(2); //  A2 Micro CHP Parameter Object Name
     294             :             // find input structure
     295           2 :             int thisParamID = UtilityRoutines::FindItemInList(AlphArray(2), state.dataCHPElectGen->MicroCHPParamInput);
     296           2 :             if (thisParamID != 0) {
     297           4 :                 state.dataCHPElectGen->MicroCHP(GeneratorNum).A42Model =
     298           4 :                     state.dataCHPElectGen->MicroCHPParamInput(thisParamID); // entire structure of input data assigned here!
     299             :             } else {
     300           0 :                 ShowSevereError(state, "Invalid, " + state.dataIPShortCut->cAlphaFieldNames(2) + " = " + AlphArray(2));
     301           0 :                 ShowContinueError(state, "Entered in " + state.dataIPShortCut->cCurrentModuleObject + '=' + AlphArray(1));
     302           0 :                 ErrorsFound = true;
     303             :             }
     304             : 
     305           2 :             if (!state.dataIPShortCut->lAlphaFieldBlanks(3)) {
     306           2 :                 state.dataCHPElectGen->MicroCHP(GeneratorNum).ZoneName = AlphArray(3); //  A3 Zone Name
     307           2 :                 state.dataCHPElectGen->MicroCHP(GeneratorNum).ZoneID =
     308           2 :                     UtilityRoutines::FindItemInList(state.dataCHPElectGen->MicroCHP(GeneratorNum).ZoneName, state.dataHeatBal->Zone);
     309           2 :                 if (state.dataCHPElectGen->MicroCHP(GeneratorNum).ZoneID == 0) {
     310           0 :                     ShowSevereError(state, "Invalid, " + state.dataIPShortCut->cAlphaFieldNames(3) + " = " + AlphArray(3));
     311           0 :                     ShowContinueError(state, "Entered in " + state.dataIPShortCut->cCurrentModuleObject + '=' + AlphArray(1));
     312           0 :                     ErrorsFound = true;
     313             :                 }
     314             :             } else {
     315           0 :                 state.dataCHPElectGen->MicroCHP(GeneratorNum).ZoneID = 0;
     316             :             }
     317           2 :             state.dataCHPElectGen->MicroCHP(GeneratorNum).PlantInletNodeName = AlphArray(4);  //  A4 Cooling Water Inlet Node Name
     318           2 :             state.dataCHPElectGen->MicroCHP(GeneratorNum).PlantOutletNodeName = AlphArray(5); //  A5 Cooling Water Outlet Node Name
     319             :             // find node ids for water path
     320           2 :             state.dataCHPElectGen->MicroCHP(GeneratorNum).PlantInletNodeID =
     321           4 :                 NodeInputManager::GetOnlySingleNode(state,
     322           2 :                                                     AlphArray(4),
     323             :                                                     ErrorsFound,
     324             :                                                     DataLoopNode::ConnectionObjectType::GeneratorMicroCHP,
     325           2 :                                                     AlphArray(1),
     326             :                                                     DataLoopNode::NodeFluidType::Water,
     327             :                                                     DataLoopNode::ConnectionType::Inlet,
     328             :                                                     NodeInputManager::CompFluidStream::Primary,
     329           2 :                                                     DataLoopNode::ObjectIsNotParent);
     330           2 :             state.dataCHPElectGen->MicroCHP(GeneratorNum).PlantOutletNodeID =
     331           4 :                 NodeInputManager::GetOnlySingleNode(state,
     332           2 :                                                     AlphArray(5),
     333             :                                                     ErrorsFound,
     334             :                                                     DataLoopNode::ConnectionObjectType::GeneratorMicroCHP,
     335           2 :                                                     AlphArray(1),
     336             :                                                     DataLoopNode::NodeFluidType::Water,
     337             :                                                     DataLoopNode::ConnectionType::Outlet,
     338             :                                                     NodeInputManager::CompFluidStream::Primary,
     339           2 :                                                     DataLoopNode::ObjectIsNotParent);
     340           6 :             BranchNodeConnections::TestCompSet(
     341           4 :                 state, state.dataIPShortCut->cCurrentModuleObject, AlphArray(1), AlphArray(4), AlphArray(5), "Heat Recovery Nodes");
     342             : 
     343           2 :             state.dataCHPElectGen->MicroCHP(GeneratorNum).AirInletNodeName = AlphArray(6); //  A6 Air Inlet Node Name
     344             :             // check the node connections
     345           2 :             state.dataCHPElectGen->MicroCHP(GeneratorNum).AirInletNodeID =
     346           4 :                 NodeInputManager::GetOnlySingleNode(state,
     347           2 :                                                     AlphArray(6),
     348             :                                                     ErrorsFound,
     349             :                                                     DataLoopNode::ConnectionObjectType::GeneratorMicroCHP,
     350           2 :                                                     AlphArray(1),
     351             :                                                     DataLoopNode::NodeFluidType::Air,
     352             :                                                     DataLoopNode::ConnectionType::Inlet,
     353             :                                                     NodeInputManager::CompFluidStream::Secondary,
     354           2 :                                                     DataLoopNode::ObjectIsNotParent);
     355             : 
     356           2 :             state.dataCHPElectGen->MicroCHP(GeneratorNum).AirOutletNodeName = AlphArray(7); //  A7 Air Outlet Node Name
     357           2 :             state.dataCHPElectGen->MicroCHP(GeneratorNum).AirOutletNodeID =
     358           4 :                 NodeInputManager::GetOnlySingleNode(state,
     359           2 :                                                     AlphArray(7),
     360             :                                                     ErrorsFound,
     361             :                                                     DataLoopNode::ConnectionObjectType::GeneratorMicroCHP,
     362           2 :                                                     AlphArray(1),
     363             :                                                     DataLoopNode::NodeFluidType::Air,
     364             :                                                     DataLoopNode::ConnectionType::Outlet,
     365             :                                                     NodeInputManager::CompFluidStream::Secondary,
     366           2 :                                                     DataLoopNode::ObjectIsNotParent);
     367             : 
     368           2 :             state.dataCHPElectGen->MicroCHP(GeneratorNum).FuelSupplyID =
     369           2 :                 UtilityRoutines::FindItemInList(AlphArray(8), state.dataGenerator->FuelSupply); // Fuel Supply ID
     370           2 :             if (state.dataCHPElectGen->MicroCHP(GeneratorNum).FuelSupplyID == 0) {
     371           0 :                 ShowSevereError(state, "Invalid, " + state.dataIPShortCut->cAlphaFieldNames(8) + " = " + AlphArray(8));
     372           0 :                 ShowContinueError(state, "Entered in " + state.dataIPShortCut->cCurrentModuleObject + '=' + AlphArray(1));
     373           0 :                 ErrorsFound = true;
     374             :             }
     375             : 
     376           2 :             if (state.dataIPShortCut->lAlphaFieldBlanks(9)) {
     377           0 :                 state.dataCHPElectGen->MicroCHP(GeneratorNum).AvailabilitySchedID = DataGlobalConstants::ScheduleAlwaysOn;
     378             :             } else {
     379           2 :                 state.dataCHPElectGen->MicroCHP(GeneratorNum).AvailabilitySchedID = ScheduleManager::GetScheduleIndex(state, AlphArray(9));
     380           2 :                 if (state.dataCHPElectGen->MicroCHP(GeneratorNum).AvailabilitySchedID == 0) {
     381           0 :                     ShowSevereError(state, "Invalid, " + state.dataIPShortCut->cAlphaFieldNames(9) + " = " + AlphArray(9));
     382           0 :                     ShowContinueError(state, "Entered in " + state.dataIPShortCut->cCurrentModuleObject + '=' + AlphArray(1));
     383           0 :                     ErrorsFound = true;
     384             :                 }
     385             :             }
     386           2 :             state.dataCHPElectGen->MicroCHP(GeneratorNum).A42Model.TengLast = 20.0;      // inits
     387           2 :             state.dataCHPElectGen->MicroCHP(GeneratorNum).A42Model.TempCWOutLast = 20.0; // inits
     388             :         }
     389             : 
     390           2 :         if (ErrorsFound) {
     391           0 :             ShowFatalError(state, "Errors found in processing input for " + state.dataIPShortCut->cCurrentModuleObject);
     392             :         }
     393             : 
     394             :         // setup report variables
     395           2 :         for (int GeneratorNum = 1; GeneratorNum <= state.dataCHPElectGen->NumMicroCHPs; ++GeneratorNum) {
     396             :         }
     397             : 
     398           2 :         state.dataCHPElectGen->MyOneTimeFlag = false;
     399             :     }
     400           2 : }
     401             : 
     402           2 : void MicroCHPDataStruct::setupOutputVars(EnergyPlusData &state)
     403             : {
     404           4 :     SetupOutputVariable(state,
     405             :                         "Generator Off Mode Time",
     406             :                         OutputProcessor::Unit::s,
     407             :                         this->A42Model.OffModeTime,
     408             :                         OutputProcessor::SOVTimeStepType::System,
     409             :                         OutputProcessor::SOVStoreType::Summed,
     410           2 :                         this->Name);
     411             : 
     412           4 :     SetupOutputVariable(state,
     413             :                         "Generator Standby Mode Time",
     414             :                         OutputProcessor::Unit::s,
     415             :                         this->A42Model.StandyByModeTime,
     416             :                         OutputProcessor::SOVTimeStepType::System,
     417             :                         OutputProcessor::SOVStoreType::Summed,
     418           2 :                         this->Name);
     419             : 
     420           4 :     SetupOutputVariable(state,
     421             :                         "Generator Warm Up Mode Time",
     422             :                         OutputProcessor::Unit::s,
     423             :                         this->A42Model.WarmUpModeTime,
     424             :                         OutputProcessor::SOVTimeStepType::System,
     425             :                         OutputProcessor::SOVStoreType::Summed,
     426           2 :                         this->Name);
     427             : 
     428           4 :     SetupOutputVariable(state,
     429             :                         "Generator Normal Operating Mode Time",
     430             :                         OutputProcessor::Unit::s,
     431             :                         this->A42Model.NormalModeTime,
     432             :                         OutputProcessor::SOVTimeStepType::System,
     433             :                         OutputProcessor::SOVStoreType::Summed,
     434           2 :                         this->Name);
     435             : 
     436           4 :     SetupOutputVariable(state,
     437             :                         "Generator Cool Down Mode Time",
     438             :                         OutputProcessor::Unit::s,
     439             :                         this->A42Model.CoolDownModeTime,
     440             :                         OutputProcessor::SOVTimeStepType::System,
     441             :                         OutputProcessor::SOVStoreType::Summed,
     442           2 :                         this->Name);
     443             : 
     444           4 :     SetupOutputVariable(state,
     445             :                         "Generator Produced AC Electricity Rate",
     446             :                         OutputProcessor::Unit::W,
     447             :                         this->A42Model.ACPowerGen,
     448             :                         OutputProcessor::SOVTimeStepType::System,
     449             :                         OutputProcessor::SOVStoreType::Average,
     450           2 :                         this->Name);
     451             : 
     452           4 :     SetupOutputVariable(state,
     453             :                         "Generator Produced AC Electricity Energy",
     454             :                         OutputProcessor::Unit::J,
     455             :                         this->A42Model.ACEnergyGen,
     456             :                         OutputProcessor::SOVTimeStepType::System,
     457             :                         OutputProcessor::SOVStoreType::Summed,
     458             :                         this->Name,
     459             :                         _,
     460             :                         "ElectricityProduced",
     461             :                         "COGENERATION",
     462             :                         _,
     463           2 :                         "Plant");
     464             : 
     465           4 :     SetupOutputVariable(state,
     466             :                         "Generator Produced Thermal Rate",
     467             :                         OutputProcessor::Unit::W,
     468             :                         this->A42Model.QdotHR,
     469             :                         OutputProcessor::SOVTimeStepType::System,
     470             :                         OutputProcessor::SOVStoreType::Average,
     471           2 :                         this->Name);
     472             : 
     473           4 :     SetupOutputVariable(state,
     474             :                         "Generator Produced Thermal Energy",
     475             :                         OutputProcessor::Unit::J,
     476             :                         this->A42Model.TotalHeatEnergyRec,
     477             :                         OutputProcessor::SOVTimeStepType::System,
     478             :                         OutputProcessor::SOVStoreType::Summed,
     479             :                         this->Name,
     480             :                         _,
     481             :                         "ENERGYTRANSFER",
     482             :                         "COGENERATION",
     483             :                         _,
     484           2 :                         "Plant");
     485             : 
     486           4 :     SetupOutputVariable(state,
     487             :                         "Generator Electric Efficiency",
     488             :                         OutputProcessor::Unit::None,
     489             :                         this->A42Model.ElecEff,
     490             :                         OutputProcessor::SOVTimeStepType::System,
     491             :                         OutputProcessor::SOVStoreType::Average,
     492           2 :                         this->Name);
     493             : 
     494           4 :     SetupOutputVariable(state,
     495             :                         "Generator Thermal Efficiency",
     496             :                         OutputProcessor::Unit::None,
     497             :                         this->A42Model.ThermEff,
     498             :                         OutputProcessor::SOVTimeStepType::System,
     499             :                         OutputProcessor::SOVStoreType::Average,
     500           2 :                         this->Name);
     501             : 
     502           4 :     SetupOutputVariable(state,
     503             :                         "Generator Gross Input Heat Rate",
     504             :                         OutputProcessor::Unit::W,
     505             :                         this->A42Model.Qgross,
     506             :                         OutputProcessor::SOVTimeStepType::System,
     507             :                         OutputProcessor::SOVStoreType::Average,
     508           2 :                         this->Name);
     509             : 
     510           4 :     SetupOutputVariable(state,
     511             :                         "Generator Steady State Engine Heat Generation Rate",
     512             :                         OutputProcessor::Unit::W,
     513             :                         this->A42Model.Qgenss,
     514             :                         OutputProcessor::SOVTimeStepType::System,
     515             :                         OutputProcessor::SOVStoreType::Average,
     516           2 :                         this->Name);
     517             : 
     518           4 :     SetupOutputVariable(state,
     519             :                         "Generator Engine Heat Exchange Rate",
     520             :                         OutputProcessor::Unit::W,
     521             :                         this->A42Model.QdotHX,
     522             :                         OutputProcessor::SOVTimeStepType::System,
     523             :                         OutputProcessor::SOVStoreType::Average,
     524           2 :                         this->Name);
     525             : 
     526           4 :     SetupOutputVariable(state,
     527             :                         "Generator Air Mass Flow Rate",
     528             :                         OutputProcessor::Unit::kg_s,
     529             :                         this->A42Model.MdotAir,
     530             :                         OutputProcessor::SOVTimeStepType::System,
     531             :                         OutputProcessor::SOVStoreType::Average,
     532           2 :                         this->Name);
     533             : 
     534           4 :     SetupOutputVariable(state,
     535             :                         "Generator Fuel Molar Flow Rate",
     536             :                         OutputProcessor::Unit::kmol_s,
     537             :                         this->A42Model.NdotFuel,
     538             :                         OutputProcessor::SOVTimeStepType::System,
     539             :                         OutputProcessor::SOVStoreType::Average,
     540           2 :                         this->Name);
     541             : 
     542           4 :     SetupOutputVariable(state,
     543             :                         "Generator Fuel Mass Flow Rate",
     544             :                         OutputProcessor::Unit::kg_s,
     545             :                         this->A42Model.MdotFuel,
     546             :                         OutputProcessor::SOVTimeStepType::System,
     547             :                         OutputProcessor::SOVStoreType::Average,
     548           2 :                         this->Name);
     549             : 
     550           4 :     SetupOutputVariable(state,
     551             :                         "Generator Engine Temperature",
     552             :                         OutputProcessor::Unit::C,
     553             :                         this->A42Model.Teng,
     554             :                         OutputProcessor::SOVTimeStepType::System,
     555             :                         OutputProcessor::SOVStoreType::Average,
     556           2 :                         this->Name);
     557             : 
     558           4 :     SetupOutputVariable(state,
     559             :                         "Generator Coolant Inlet Temperature",
     560             :                         OutputProcessor::Unit::C,
     561             :                         this->A42Model.HeatRecInletTemp,
     562             :                         OutputProcessor::SOVTimeStepType::System,
     563             :                         OutputProcessor::SOVStoreType::Average,
     564           2 :                         this->Name);
     565             : 
     566           4 :     SetupOutputVariable(state,
     567             :                         "Generator Coolant Outlet Temperature",
     568             :                         OutputProcessor::Unit::C,
     569             :                         this->A42Model.HeatRecOutletTemp,
     570             :                         OutputProcessor::SOVTimeStepType::System,
     571             :                         OutputProcessor::SOVStoreType::Average,
     572           2 :                         this->Name);
     573             : 
     574             :     // this next one needs to be reconciled with non-gas fuel constituents.
     575             :     //   need custom resourceTypeKey or something for user defined fuel compositions.
     576           4 :     SetupOutputVariable(state,
     577             :                         "Generator Fuel HHV Basis Energy",
     578             :                         OutputProcessor::Unit::J,
     579             :                         this->A42Model.FuelEnergyHHV,
     580             :                         OutputProcessor::SOVTimeStepType::System,
     581             :                         OutputProcessor::SOVStoreType::Summed,
     582             :                         this->Name,
     583             :                         _,
     584             :                         "NaturalGas",
     585             :                         "COGENERATION",
     586             :                         _,
     587           2 :                         "Plant");
     588             : 
     589           4 :     SetupOutputVariable(state,
     590             :                         "Generator Fuel HHV Basis Rate",
     591             :                         OutputProcessor::Unit::W,
     592             :                         this->A42Model.FuelEnergyUseRateHHV,
     593             :                         OutputProcessor::SOVTimeStepType::System,
     594             :                         OutputProcessor::SOVStoreType::Average,
     595           2 :                         this->Name);
     596             : 
     597           4 :     SetupOutputVariable(state,
     598             :                         "Generator Fuel LHV Basis Energy",
     599             :                         OutputProcessor::Unit::J,
     600             :                         this->A42Model.FuelEnergyLHV,
     601             :                         OutputProcessor::SOVTimeStepType::System,
     602             :                         OutputProcessor::SOVStoreType::Summed,
     603           2 :                         this->Name);
     604             : 
     605           4 :     SetupOutputVariable(state,
     606             :                         "Generator Fuel LHV Basis Rate",
     607             :                         OutputProcessor::Unit::W,
     608             :                         this->A42Model.FuelEnergyUseRateLHV,
     609             :                         OutputProcessor::SOVTimeStepType::System,
     610             :                         OutputProcessor::SOVStoreType::Average,
     611           2 :                         this->Name);
     612             : 
     613           4 :     SetupOutputVariable(state,
     614             :                         "Generator Fuel Compressor Electricity Rate",
     615             :                         OutputProcessor::Unit::W,
     616             :                         this->A42Model.FuelCompressPower,
     617             :                         OutputProcessor::SOVTimeStepType::System,
     618             :                         OutputProcessor::SOVStoreType::Average,
     619           2 :                         this->Name);
     620             : 
     621           4 :     SetupOutputVariable(state,
     622             :                         "Generator Fuel Compressor Electricity Energy",
     623             :                         OutputProcessor::Unit::J,
     624             :                         this->A42Model.FuelCompressEnergy,
     625             :                         OutputProcessor::SOVTimeStepType::System,
     626             :                         OutputProcessor::SOVStoreType::Summed,
     627           2 :                         this->Name);
     628             : 
     629           4 :     SetupOutputVariable(state,
     630             :                         "Generator Fuel Compressor Skin Heat Loss Rate",
     631             :                         OutputProcessor::Unit::W,
     632             :                         this->A42Model.FuelCompressSkinLoss,
     633             :                         OutputProcessor::SOVTimeStepType::System,
     634             :                         OutputProcessor::SOVStoreType::Average,
     635           2 :                         this->Name);
     636             : 
     637           4 :     SetupOutputVariable(state,
     638             :                         "Generator Zone Sensible Heat Transfer Rate",
     639             :                         OutputProcessor::Unit::W,
     640             :                         this->A42Model.SkinLossPower,
     641             :                         OutputProcessor::SOVTimeStepType::System,
     642             :                         OutputProcessor::SOVStoreType::Average,
     643           2 :                         this->Name);
     644             : 
     645           4 :     SetupOutputVariable(state,
     646             :                         "Generator Zone Sensible Heat Transfer Energy",
     647             :                         OutputProcessor::Unit::J,
     648             :                         this->A42Model.SkinLossEnergy,
     649             :                         OutputProcessor::SOVTimeStepType::System,
     650             :                         OutputProcessor::SOVStoreType::Summed,
     651           2 :                         this->Name);
     652             : 
     653           4 :     SetupOutputVariable(state,
     654             :                         "Generator Zone Convection Heat Transfer Rate",
     655             :                         OutputProcessor::Unit::W,
     656             :                         this->A42Model.SkinLossConvect,
     657             :                         OutputProcessor::SOVTimeStepType::System,
     658             :                         OutputProcessor::SOVStoreType::Average,
     659           2 :                         this->Name);
     660             : 
     661           4 :     SetupOutputVariable(state,
     662             :                         "Generator Zone Radiation Heat Transfer Rate",
     663             :                         OutputProcessor::Unit::W,
     664             :                         this->A42Model.SkinLossRadiat,
     665             :                         OutputProcessor::SOVTimeStepType::System,
     666             :                         OutputProcessor::SOVStoreType::Average,
     667           2 :                         this->Name);
     668             : 
     669           2 :     if (this->ZoneID > 0) {
     670           2 :         SetupZoneInternalGain(state,
     671             :                               this->ZoneID,
     672             :                               this->Name,
     673             :                               DataHeatBalance::IntGainType::GeneratorMicroCHP,
     674             :                               &this->A42Model.SkinLossConvect,
     675             :                               nullptr,
     676             :                               &this->A42Model.SkinLossRadiat);
     677             :     }
     678           2 : }
     679             : 
     680       80743 : void MicroCHPDataStruct::simulate(EnergyPlusData &state,
     681             :                                   [[maybe_unused]] const EnergyPlus::PlantLocation &calledFromLocation,
     682             :                                   bool FirstHVACIteration,
     683             :                                   [[maybe_unused]] Real64 &CurLoad,
     684             :                                   [[maybe_unused]] bool RunFlag)
     685             : {
     686             :     // empty function to emulate current behavior as of conversion to using the PlantComponent calling structure.
     687             :     // calls from the plant side only update the nodes.
     688             :     // calls from the ElectricPowerServiceManger call the init, calc, and update worker functions
     689             : 
     690       80743 :     PlantUtilities::UpdateComponentHeatRecoverySide(state,
     691             :                                                     this->CWPlantLoc.loopNum,
     692             :                                                     this->CWPlantLoc.loopSideNum,
     693             :                                                     DataPlant::PlantEquipmentType::Generator_MicroCHP,
     694             :                                                     this->PlantInletNodeID,
     695             :                                                     this->PlantOutletNodeID,
     696             :                                                     this->A42Model.QdotHR,
     697             :                                                     this->A42Model.HeatRecInletTemp,
     698             :                                                     this->A42Model.HeatRecOutletTemp,
     699             :                                                     this->PlantMassFlowRate,
     700             :                                                     FirstHVACIteration);
     701       80743 : }
     702             : 
     703          10 : void MicroCHPDataStruct::onInitLoopEquip(EnergyPlusData &state, const EnergyPlus::PlantLocation &)
     704             : {
     705             :     static constexpr std::string_view RoutineName("MicroCHPDataStruct::onInitLoopEquip");
     706             : 
     707          30 :     Real64 rho = FluidProperties::GetDensityGlycol(state,
     708          10 :                                                    state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).FluidName,
     709          10 :                                                    state.dataLoopNodes->Node(this->PlantInletNodeID).Temp,
     710          10 :                                                    state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).FluidIndex,
     711          10 :                                                    RoutineName);
     712          10 :     if (this->A42Model.InternalFlowControl) { // got a curve
     713           5 :         this->PlantMassFlowRateMax =
     714          15 :             2.0 * Curve::CurveValue(
     715           5 :                       state, this->A42Model.WaterFlowCurveID, this->A42Model.MaxElecPower, state.dataLoopNodes->Node(this->PlantInletNodeID).Temp);
     716           5 :     } else if (this->CWPlantLoc.loopSideNum == DataPlant::LoopSideLocation::Supply) {
     717           5 :         if (state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).MaxMassFlowRate > 0.0) {
     718           4 :             this->PlantMassFlowRateMax = state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).MaxMassFlowRate;
     719           1 :         } else if (state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).PlantSizNum > 0) {
     720           0 :             this->PlantMassFlowRateMax = state.dataSize->PlantSizData(this->CWPlantLoc.loopNum).DesVolFlowRate * rho;
     721             :         } else {
     722           1 :             this->PlantMassFlowRateMax = 2.0;
     723             :         }
     724             : 
     725           0 :     } else if (this->CWPlantLoc.loopSideNum == DataPlant::LoopSideLocation::Demand) {
     726           0 :         this->PlantMassFlowRateMax = 2.0; // would like to use plant loop max but not ready yet
     727             :     }
     728             : 
     729          10 :     PlantUtilities::RegisterPlantCompDesignFlow(state, this->PlantInletNodeID, this->PlantMassFlowRateMax / rho);
     730             : 
     731          20 :     this->A42Model.ElecEff = Curve::CurveValue(state,
     732             :                                                this->A42Model.ElecEffCurveID,
     733             :                                                this->A42Model.MaxElecPower,
     734             :                                                this->PlantMassFlowRateMax,
     735          10 :                                                state.dataLoopNodes->Node(this->PlantInletNodeID).Temp);
     736             : 
     737          20 :     this->A42Model.ThermEff = Curve::CurveValue(state,
     738             :                                                 this->A42Model.ThermalEffCurveID,
     739             :                                                 this->A42Model.MaxElecPower,
     740             :                                                 this->PlantMassFlowRateMax,
     741          10 :                                                 state.dataLoopNodes->Node(this->PlantInletNodeID).Temp);
     742             : 
     743          10 :     GeneratorDynamicsManager::SetupGeneratorControlStateManager(state, this->DynamicsControlID);
     744          10 : }
     745             : 
     746       16022 : void MicroCHPDataStruct::InitMicroCHPNoNormalizeGenerators(EnergyPlusData &state)
     747             : {
     748             :     // SUBROUTINE INFORMATION:
     749             :     //       AUTHOR         BGriffith
     750             :     //       DATE WRITTEN   March 2007
     751             :     //       MODIFIED       na
     752             :     //       RE-ENGINEERED  na
     753             : 
     754       16022 :     this->oneTimeInit(state);
     755             : 
     756       16022 :     if (!state.dataGlobal->SysSizingCalc && this->MySizeFlag && !this->MyPlantScanFlag && (state.dataPlnt->PlantFirstSizesOkayToFinalize)) {
     757           2 :         this->MySizeFlag = false;
     758             :     }
     759             : 
     760       16022 :     if (this->MySizeFlag) return;
     761             : 
     762       13932 :     int DynaCntrlNum = this->DynamicsControlID;
     763             : 
     764       13932 :     if (state.dataGlobal->BeginEnvrnFlag && this->MyEnvrnFlag) {
     765             :         // reset to starting condition for different environment runperiods, design days
     766         162 :         this->A42Model.TengLast = 20.0;
     767         162 :         this->A42Model.TempCWOutLast = 20.0;
     768         162 :         this->A42Model.TimeElapsed = 0.0;
     769         162 :         this->A42Model.OpMode = DataGenerators::OperatingMode::Invalid;
     770         162 :         this->A42Model.OffModeTime = 0.0;
     771         162 :         this->A42Model.StandyByModeTime = 0.0;
     772         162 :         this->A42Model.WarmUpModeTime = 0.0;
     773         162 :         this->A42Model.NormalModeTime = 0.0;
     774         162 :         this->A42Model.CoolDownModeTime = 0.0;
     775         162 :         this->A42Model.Pnet = 0.0;
     776         162 :         this->A42Model.ElecEff = 0.0;
     777         162 :         this->A42Model.Qgross = 0.0;
     778         162 :         this->A42Model.ThermEff = 0.0;
     779         162 :         this->A42Model.Qgenss = 0.0;
     780         162 :         this->A42Model.NdotFuel = 0.0;
     781         162 :         this->A42Model.MdotFuel = 0.0;
     782         162 :         this->A42Model.Teng = 20.0;
     783         162 :         this->A42Model.TcwIn = 20.0;
     784         162 :         this->A42Model.TcwOut = 20.0;
     785         162 :         this->A42Model.MdotAir = 0.0;
     786         162 :         this->A42Model.QdotSkin = 0.0;
     787         162 :         this->A42Model.QdotConvZone = 0.0;
     788         162 :         this->A42Model.QdotRadZone = 0.0;
     789         162 :         state.dataGenerator->GeneratorDynamics(DynaCntrlNum).LastOpMode = DataGenerators::OperatingMode::Off;
     790         162 :         state.dataGenerator->GeneratorDynamics(DynaCntrlNum).CurrentOpMode = DataGenerators::OperatingMode::Off;
     791         162 :         state.dataGenerator->GeneratorDynamics(DynaCntrlNum).FractionalDayofLastShutDown = 0.0;
     792         162 :         state.dataGenerator->GeneratorDynamics(DynaCntrlNum).FractionalDayofLastStartUp = 0.0;
     793         162 :         state.dataGenerator->GeneratorDynamics(DynaCntrlNum).HasBeenOn = false;
     794         162 :         state.dataGenerator->GeneratorDynamics(DynaCntrlNum).DuringStartUp = false;
     795         162 :         state.dataGenerator->GeneratorDynamics(DynaCntrlNum).DuringShutDown = false;
     796         162 :         state.dataGenerator->GeneratorDynamics(DynaCntrlNum).FuelMdotLastTimestep = 0.0;
     797         162 :         state.dataGenerator->GeneratorDynamics(DynaCntrlNum).PelLastTimeStep = 0.0;
     798         162 :         state.dataGenerator->GeneratorDynamics(DynaCntrlNum).NumCycles = 0;
     799             : 
     800         162 :         state.dataGenerator->FuelSupply(this->FuelSupplyID).QskinLoss = 0.0;
     801             : 
     802         162 :         PlantUtilities::InitComponentNodes(state, 0.0, this->PlantMassFlowRateMax, this->PlantInletNodeID, this->PlantOutletNodeID);
     803             :     }
     804             : 
     805       13932 :     if (!state.dataGlobal->BeginEnvrnFlag) {
     806       13770 :         this->MyEnvrnFlag = true;
     807             :     }
     808             : 
     809             :     Real64 TimeElapsed =
     810       13932 :         state.dataGlobal->HourOfDay + state.dataGlobal->TimeStep * state.dataGlobal->TimeStepZone + state.dataHVACGlobal->SysTimeElapsed;
     811       13932 :     if (this->A42Model.TimeElapsed != TimeElapsed) {
     812             :         // The simulation has advanced to the next system timestep.  Save conditions from the end of the previous system
     813             :         // timestep for use as the initial conditions of each iteration that does not advance the system timestep.
     814        4648 :         this->A42Model.TengLast = this->A42Model.Teng;
     815        4648 :         this->A42Model.TempCWOutLast = this->A42Model.TcwOut;
     816        4648 :         this->A42Model.TimeElapsed = TimeElapsed;
     817        4648 :         state.dataGenerator->GeneratorDynamics(DynaCntrlNum).LastOpMode = state.dataGenerator->GeneratorDynamics(DynaCntrlNum).CurrentOpMode;
     818        4648 :         state.dataGenerator->GeneratorDynamics(DynaCntrlNum).FuelMdotLastTimestep = this->A42Model.MdotFuel;
     819        4648 :         state.dataGenerator->GeneratorDynamics(DynaCntrlNum).PelLastTimeStep = this->A42Model.Pnet;
     820             :     }
     821             : 
     822       13932 :     if (!this->A42Model.InternalFlowControl) {
     823             : 
     824        6134 :         Real64 mdot = this->PlantMassFlowRateMax;
     825        6134 :         PlantUtilities::SetComponentFlowRate(state, mdot, this->PlantInletNodeID, this->PlantOutletNodeID, this->CWPlantLoc);
     826        6134 :         this->PlantMassFlowRate = mdot;
     827             :     }
     828             : }
     829             : 
     830       13932 : void MicroCHPDataStruct::CalcMicroCHPNoNormalizeGeneratorModel(EnergyPlusData &state,
     831             :                                                                bool const RunFlagElectCenter, // TRUE when Generator operating
     832             :                                                                bool const RunFlagPlant,
     833             :                                                                Real64 const MyElectricLoad, // Generator demand
     834             :                                                                Real64 const MyThermalLoad,
     835             :                                                                bool const FirstHVACIteration)
     836             : {
     837             : 
     838             :     // SUBROUTINE INFORMATION:
     839             :     //       AUTHOR        B Griffith
     840             :     //       DATE WRITTEN   July 2006
     841             :     //       MODIFIED       na
     842             :     //       RE-ENGINEERED  na
     843             : 
     844             :     // PURPOSE OF THIS SUBROUTINE:
     845             :     // Main calculation subroutine for the IEA Annex 42 model
     846             : 
     847             :     // METHODOLOGY EMPLOYED:
     848             :     // curve fit, dynamic control limits,
     849             : 
     850             :     // REFERENCES:
     851             :     // IEA Annex 42 FC-COGEN-SIM "A Generic Model Specification for Combustion-based Residential CHP Devices"
     852             :     // Alex Ferguson, Nick Kelly, Version 3, June 26, 2006
     853             : 
     854             :     static constexpr std::string_view RoutineName("CalcMicroCHPNoNormalizeGeneratorModel");
     855             : 
     856       13932 :     DataGenerators::OperatingMode CurrentOpMode = DataGenerators::OperatingMode::Invalid;
     857       13932 :     Real64 AllowedLoad = 0.0;
     858       13932 :     Real64 PLRforSubtimestepStartUp(1.0);
     859       13932 :     Real64 PLRforSubtimestepShutDown(0.0);
     860       13932 :     bool RunFlag(false);
     861             : 
     862       13932 :     GeneratorDynamicsManager::ManageGeneratorControlState(state,
     863             :                                                           GeneratorType::MicroCHP,
     864             :                                                           this->Name,
     865             :                                                           this->DynamicsControlID,
     866             :                                                           RunFlagElectCenter,
     867             :                                                           RunFlagPlant,
     868             :                                                           MyElectricLoad,
     869             :                                                           MyThermalLoad,
     870             :                                                           AllowedLoad,
     871             :                                                           CurrentOpMode,
     872             :                                                           PLRforSubtimestepStartUp,
     873             :                                                           PLRforSubtimestepShutDown,
     874             :                                                           FirstHVACIteration);
     875             : 
     876       13932 :     if (RunFlagElectCenter || RunFlagPlant) RunFlag = true;
     877             : 
     878       13932 :     Real64 Teng = this->A42Model.Teng;
     879       13932 :     Real64 TcwOut = this->A42Model.TcwOut;
     880             : 
     881             :     Real64 thisAmbientTemp;
     882       13932 :     if (this->ZoneID > 0) {
     883       13932 :         thisAmbientTemp = state.dataZoneTempPredictorCorrector->zoneHeatBalance(this->ZoneID).MAT;
     884             :     } else { // outdoor location, no zone
     885           0 :         thisAmbientTemp = state.dataEnvrn->OutDryBulbTemp;
     886             :     }
     887             : 
     888       13932 :     Real64 Pnetss = 0.0;
     889       13932 :     Real64 Pstandby = 0.0; // power draw during standby, positive here means negative production
     890       13932 :     Real64 Pcooler = 0.0;  // power draw during cool down, positive here means negative production
     891       13932 :     Real64 NdotFuel = 0.0;
     892       13932 :     Real64 ElecEff = 0.0;
     893       13932 :     Real64 MdotAir = 0.0;
     894       13932 :     Real64 Qgenss = 0.0;
     895       13932 :     Real64 MdotCW = 0.0;
     896       13932 :     Real64 TcwIn = 0.0;
     897       13932 :     Real64 MdotFuel = 0.0;
     898       13932 :     Real64 Qgross = 0.0;
     899       13932 :     Real64 ThermEff = 0.0;
     900             : 
     901       13932 :     switch (CurrentOpMode) {
     902        5630 :     case DataGenerators::OperatingMode::Off: { // same as standby in model spec but no Pnet standby electicity losses.
     903             : 
     904        5630 :         Qgenss = 0.0;
     905        5630 :         MdotCW = state.dataLoopNodes->Node(this->PlantInletNodeID).MassFlowRate; // kg/s
     906        5630 :         TcwIn = state.dataLoopNodes->Node(this->PlantInletNodeID).Temp;          // C
     907        5630 :         Pnetss = 0.0;
     908        5630 :         Pstandby = 0.0;
     909        5630 :         Pcooler = this->A42Model.PcoolDown * PLRforSubtimestepShutDown;
     910        5630 :         ElecEff = 0.0;
     911        5630 :         ThermEff = 0.0;
     912        5630 :         Qgross = 0.0;
     913        5630 :         NdotFuel = 0.0;
     914        5630 :         MdotFuel = 0.0;
     915        5630 :         MdotAir = 0.0;
     916             : 
     917        5630 :         MdotCW = 0.0;
     918        5630 :         PlantUtilities::SetComponentFlowRate(state, MdotCW, this->PlantInletNodeID, this->PlantOutletNodeID, this->CWPlantLoc);
     919        5630 :         this->PlantMassFlowRate = MdotCW;
     920        5630 :     } break;
     921        3967 :     case DataGenerators::OperatingMode::Standby: {
     922        3967 :         Qgenss = 0.0;
     923        3967 :         MdotCW = state.dataLoopNodes->Node(this->PlantInletNodeID).MassFlowRate; // kg/s
     924        3967 :         TcwIn = state.dataLoopNodes->Node(this->PlantInletNodeID).Temp;          // C
     925        3967 :         Pnetss = 0.0;
     926        3967 :         Pstandby = this->A42Model.Pstandby * (1.0 - PLRforSubtimestepShutDown);
     927        3967 :         Pcooler = this->A42Model.PcoolDown * PLRforSubtimestepShutDown;
     928        3967 :         ElecEff = 0.0;
     929        3967 :         ThermEff = 0.0;
     930        3967 :         Qgross = 0.0;
     931        3967 :         NdotFuel = 0.0;
     932        3967 :         MdotFuel = 0.0;
     933        3967 :         MdotAir = 0.0;
     934             : 
     935        3967 :         MdotCW = 0.0;
     936        3967 :         PlantUtilities::SetComponentFlowRate(state, MdotCW, this->PlantInletNodeID, this->PlantOutletNodeID, this->CWPlantLoc);
     937        3967 :         this->PlantMassFlowRate = MdotCW;
     938        3967 :     } break;
     939           0 :     case DataGenerators::OperatingMode::WarmUp: {
     940           0 :         if (this->A42Model.WarmUpByTimeDelay) {
     941             :             // Internal combustion engine.  This is just like normal  operation but no net power yet.
     942           0 :             Pnetss = MyElectricLoad; // W
     943           0 :             Pstandby = 0.0;
     944           0 :             Pcooler = this->A42Model.PcoolDown * PLRforSubtimestepShutDown;
     945           0 :             TcwIn = state.dataLoopNodes->Node(this->PlantInletNodeID).Temp;          // C
     946           0 :             MdotCW = state.dataLoopNodes->Node(this->PlantInletNodeID).MassFlowRate; // kg/s
     947           0 :             if (this->A42Model.InternalFlowControl) {
     948           0 :                 MdotCW = GeneratorDynamicsManager::FuncDetermineCWMdotForInternalFlowControl(state, this->DynamicsControlID, Pnetss, TcwIn);
     949             :             }
     950           0 :             ElecEff = Curve::CurveValue(state, this->A42Model.ElecEffCurveID, Pnetss, MdotCW, TcwIn);
     951           0 :             ElecEff = max(0.0, ElecEff); // protect against bad curve result
     952             : 
     953           0 :             if (ElecEff > 0.0) {           // trap divide by bad thing
     954           0 :                 Qgross = Pnetss / ElecEff; // W
     955             :             } else {
     956           0 :                 Qgross = 0.0;
     957             :             }
     958           0 :             ThermEff = Curve::CurveValue(state, this->A42Model.ThermalEffCurveID, Pnetss, MdotCW, TcwIn);
     959           0 :             ThermEff = max(0.0, ThermEff); // protect against bad curve result
     960             : 
     961           0 :             Qgenss = ThermEff * Qgross; // W
     962             : 
     963           0 :             MdotFuel = Qgross / (state.dataGenerator->FuelSupply(this->FuelSupplyID).LHV * 1000.0 * 1000.0) *
     964           0 :                        state.dataGenerator->FuelSupply(this->FuelSupplyID).KmolPerSecToKgPerSec;
     965             :             //  kMol/s = (J/s) /(KJ/mol * 1000 J/KJ * 1000 mol/kmol)
     966             : 
     967           0 :             bool ConstrainedIncreasingNdot(false);
     968           0 :             bool ConstrainedDecreasingNdot(false);
     969           0 :             Real64 MdotFuelAllowed = 0.0;
     970             : 
     971           0 :             GeneratorDynamicsManager::ManageGeneratorFuelFlow(state,
     972             :                                                               GeneratorType::MicroCHP,
     973             :                                                               this->Name,
     974             :                                                               this->DynamicsControlID,
     975             :                                                               RunFlag,
     976             :                                                               MdotFuel,
     977             :                                                               MdotFuelAllowed,
     978             :                                                               ConstrainedIncreasingNdot,
     979             :                                                               ConstrainedDecreasingNdot);
     980             : 
     981           0 :             if (ConstrainedIncreasingNdot || ConstrainedDecreasingNdot) { // recalculate Pnetss with new NdotFuel with iteration
     982           0 :                 MdotFuel = MdotFuelAllowed;
     983           0 :                 NdotFuel = MdotFuel / state.dataGenerator->FuelSupply(this->FuelSupplyID).KmolPerSecToKgPerSec;
     984           0 :                 Qgross = NdotFuel * (state.dataGenerator->FuelSupply(this->FuelSupplyID).LHV * 1000.0 * 1000.0);
     985             : 
     986           0 :                 for (int i = 1; i <= 20; ++i) { // iterating here  could add use of seach method
     987           0 :                     Pnetss = Qgross * ElecEff;
     988           0 :                     if (this->A42Model.InternalFlowControl) {
     989           0 :                         MdotCW = GeneratorDynamicsManager::FuncDetermineCWMdotForInternalFlowControl(state, this->DynamicsControlID, Pnetss, TcwIn);
     990             :                     }
     991           0 :                     ElecEff = Curve::CurveValue(state, this->A42Model.ElecEffCurveID, Pnetss, MdotCW, TcwIn);
     992           0 :                     ElecEff = max(0.0, ElecEff); // protect against bad curve result
     993             :                 }
     994             : 
     995           0 :                 ThermEff = Curve::CurveValue(state, this->A42Model.ThermalEffCurveID, Pnetss, MdotCW, TcwIn);
     996           0 :                 ThermEff = max(0.0, ThermEff); // protect against bad curve result
     997           0 :                 Qgenss = ThermEff * Qgross;    // W
     998             :             }
     999           0 :             Pnetss = 0.0; // no actually power produced here.
    1000           0 :             NdotFuel = MdotFuel / state.dataGenerator->FuelSupply(this->FuelSupplyID).KmolPerSecToKgPerSec;
    1001           0 :             MdotAir = Curve::CurveValue(state, this->A42Model.AirFlowCurveID, MdotFuel);
    1002           0 :             MdotAir = max(0.0, MdotAir); // protect against bad curve result
    1003             : 
    1004           0 :         } else if (this->A42Model.WarmUpByEngineTemp) {
    1005             :             // Stirling engine mode warm up
    1006             :             //   find MdotFuelMax
    1007           0 :             Real64 Pmax = this->A42Model.MaxElecPower;
    1008           0 :             Pstandby = 0.0;
    1009           0 :             Pcooler = this->A42Model.PcoolDown * PLRforSubtimestepShutDown;          // could be here with part load in cool down
    1010           0 :             TcwIn = state.dataLoopNodes->Node(this->PlantInletNodeID).Temp;          // C
    1011           0 :             MdotCW = state.dataLoopNodes->Node(this->PlantInletNodeID).MassFlowRate; // kg/s
    1012           0 :             ElecEff = Curve::CurveValue(state, this->A42Model.ElecEffCurveID, Pmax, MdotCW, TcwIn);
    1013           0 :             ElecEff = max(0.0, ElecEff); // protect against bad curve result
    1014           0 :             if (ElecEff > 0.0) {         // trap divide by bad thing
    1015           0 :                 Qgross = Pmax / ElecEff; // W
    1016             :             } else {
    1017           0 :                 Qgross = 0.0;
    1018             :             }
    1019           0 :             NdotFuel = Qgross / (state.dataGenerator->FuelSupply(this->FuelSupplyID).LHV * 1000.0 * 1000.0);
    1020             :             //  kMol/s = (J/s) /(KJ/mol * 1000 J/KJ * 1000 mol/kmol)
    1021           0 :             Real64 MdotFuelMax = NdotFuel * state.dataGenerator->FuelSupply(this->FuelSupplyID).KmolPerSecToKgPerSec;
    1022             : 
    1023             :             Real64 MdotFuelWarmup;
    1024           0 :             if (Teng > thisAmbientTemp) {
    1025           0 :                 MdotFuelWarmup =
    1026           0 :                     MdotFuelMax + this->A42Model.kf * MdotFuelMax * ((this->A42Model.TnomEngOp - thisAmbientTemp) / (Teng - thisAmbientTemp));
    1027             :                 // check that numerical answer didn't blow up beyond limit, and reset if it did
    1028           0 :                 if (MdotFuelWarmup > this->A42Model.Rfuelwarmup * MdotFuelMax) {
    1029           0 :                     MdotFuelWarmup = this->A42Model.Rfuelwarmup * MdotFuelMax;
    1030             :                 }
    1031             :             } else { // equal would divide by zero
    1032           0 :                 MdotFuelWarmup = this->A42Model.Rfuelwarmup * MdotFuelMax;
    1033             :             }
    1034             : 
    1035           0 :             if (this->A42Model.TnomEngOp > thisAmbientTemp) {
    1036           0 :                 Pnetss = Pmax * this->A42Model.kp * ((Teng - thisAmbientTemp) / (this->A42Model.TnomEngOp - thisAmbientTemp));
    1037             :             } else { // equal would divide by zero
    1038           0 :                 Pnetss = Pmax;
    1039             :             }
    1040             : 
    1041           0 :             MdotFuel = MdotFuelWarmup;
    1042           0 :             NdotFuel = MdotFuel / state.dataGenerator->FuelSupply(this->FuelSupplyID).KmolPerSecToKgPerSec;
    1043           0 :             MdotAir = Curve::CurveValue(state, this->A42Model.AirFlowCurveID, MdotFuelWarmup);
    1044           0 :             MdotAir = max(0.0, MdotAir); // protect against bad curve result
    1045           0 :             Qgross = NdotFuel * (state.dataGenerator->FuelSupply(this->FuelSupplyID).LHV * 1000.0 * 1000.0);
    1046           0 :             ThermEff = Curve::CurveValue(state, this->A42Model.ThermalEffCurveID, Pmax, MdotCW, TcwIn);
    1047           0 :             Qgenss = ThermEff * Qgross; // W
    1048             :         }
    1049           0 :         NdotFuel = MdotFuel / state.dataGenerator->FuelSupply(this->FuelSupplyID).KmolPerSecToKgPerSec;
    1050           0 :     } break;
    1051        4335 :     case DataGenerators::OperatingMode::Normal: {
    1052        4335 :         if (PLRforSubtimestepStartUp < 1.0) {
    1053        1223 :             if (RunFlagElectCenter) Pnetss = MyElectricLoad; // W
    1054        1223 :             if (RunFlagPlant) Pnetss = AllowedLoad;
    1055             :         } else {
    1056        3112 :             Pnetss = AllowedLoad;
    1057             :         }
    1058        4335 :         Pstandby = 0.0;
    1059        4335 :         Pcooler = 0.0;
    1060        4335 :         TcwIn = state.dataLoopNodes->Node(this->PlantInletNodeID).Temp;          // C
    1061        4335 :         MdotCW = state.dataLoopNodes->Node(this->PlantInletNodeID).MassFlowRate; // kg/s
    1062        4335 :         if (this->A42Model.InternalFlowControl) {
    1063        3831 :             MdotCW = GeneratorDynamicsManager::FuncDetermineCWMdotForInternalFlowControl(state, this->DynamicsControlID, Pnetss, TcwIn);
    1064             :         }
    1065             : 
    1066        4335 :         ElecEff = Curve::CurveValue(state, this->A42Model.ElecEffCurveID, Pnetss, MdotCW, TcwIn);
    1067        4335 :         ElecEff = max(0.0, ElecEff); // protect against bad curve result
    1068             : 
    1069        4335 :         if (ElecEff > 0.0) {           // trap divide by bad thing
    1070        4335 :             Qgross = Pnetss / ElecEff; // W
    1071             :         } else {
    1072           0 :             Qgross = 0.0;
    1073             :         }
    1074             : 
    1075        4335 :         ThermEff = Curve::CurveValue(state, this->A42Model.ThermalEffCurveID, Pnetss, MdotCW, TcwIn);
    1076        4335 :         ThermEff = max(0.0, ThermEff); // protect against bad curve result
    1077        4335 :         Qgenss = ThermEff * Qgross;    // W
    1078        8670 :         MdotFuel = Qgross / (state.dataGenerator->FuelSupply(this->FuelSupplyID).LHV * 1000.0 * 1000.0) *
    1079        4335 :                    state.dataGenerator->FuelSupply(this->FuelSupplyID).KmolPerSecToKgPerSec;
    1080             :         //  kMol/s = (J/s) /(KJ/mol * 1000 J/KJ * 1000 mol/kmol)
    1081             : 
    1082        4335 :         bool ConstrainedIncreasingNdot(false);
    1083        4335 :         bool ConstrainedDecreasingNdot(false);
    1084        4335 :         Real64 MdotFuelAllowed = 0.0;
    1085             : 
    1086        4335 :         GeneratorDynamicsManager::ManageGeneratorFuelFlow(state,
    1087             :                                                           GeneratorType::MicroCHP,
    1088             :                                                           this->Name,
    1089             :                                                           this->DynamicsControlID,
    1090             :                                                           RunFlag,
    1091             :                                                           MdotFuel,
    1092             :                                                           MdotFuelAllowed,
    1093             :                                                           ConstrainedIncreasingNdot,
    1094             :                                                           ConstrainedDecreasingNdot);
    1095             : 
    1096        4335 :         if (ConstrainedIncreasingNdot || ConstrainedDecreasingNdot) { // recalculate Pnetss with new NdotFuel with iteration
    1097           0 :             MdotFuel = MdotFuelAllowed;
    1098           0 :             NdotFuel = MdotFuel / state.dataGenerator->FuelSupply(this->FuelSupplyID).KmolPerSecToKgPerSec;
    1099           0 :             Qgross = NdotFuel * (state.dataGenerator->FuelSupply(this->FuelSupplyID).LHV * 1000.0 * 1000.0);
    1100             : 
    1101           0 :             for (int i = 1; i <= 20; ++i) { // iterating here,  could add use of seach method error signal
    1102           0 :                 Pnetss = Qgross * ElecEff;
    1103           0 :                 if (this->A42Model.InternalFlowControl) {
    1104           0 :                     MdotCW = GeneratorDynamicsManager::FuncDetermineCWMdotForInternalFlowControl(state, this->DynamicsControlID, Pnetss, TcwIn);
    1105             :                 }
    1106           0 :                 ElecEff = Curve::CurveValue(state, this->A42Model.ElecEffCurveID, Pnetss, MdotCW, TcwIn);
    1107           0 :                 ElecEff = max(0.0, ElecEff); // protect against bad curve result
    1108             :             }
    1109             : 
    1110           0 :             ThermEff = Curve::CurveValue(state, this->A42Model.ThermalEffCurveID, Pnetss, MdotCW, TcwIn);
    1111           0 :             ThermEff = max(0.0, ThermEff); // protect against bad curve result
    1112           0 :             Qgenss = ThermEff * Qgross;    // W
    1113             :         }
    1114             : 
    1115        4335 :         NdotFuel = MdotFuel / state.dataGenerator->FuelSupply(this->FuelSupplyID).KmolPerSecToKgPerSec;
    1116        4335 :         MdotAir = Curve::CurveValue(state, this->A42Model.AirFlowCurveID, MdotFuel);
    1117        4335 :         MdotAir = max(0.0, MdotAir); // protect against bad curve result
    1118        4335 :         if (PLRforSubtimestepStartUp < 1.0) {
    1119        1223 :             Pnetss = AllowedLoad;
    1120        4335 :         }
    1121        4335 :     } break;
    1122           0 :     case DataGenerators::OperatingMode::CoolDown: {
    1123           0 :         Pnetss = 0.0;
    1124           0 :         Pstandby = 0.0;
    1125           0 :         Pcooler = this->A42Model.PcoolDown;
    1126           0 :         TcwIn = state.dataLoopNodes->Node(this->PlantInletNodeID).Temp;          // C
    1127           0 :         MdotCW = state.dataLoopNodes->Node(this->PlantInletNodeID).MassFlowRate; // kg/s
    1128           0 :         if (this->A42Model.InternalFlowControl) {
    1129           0 :             MdotCW = GeneratorDynamicsManager::FuncDetermineCWMdotForInternalFlowControl(state, this->DynamicsControlID, Pnetss, TcwIn);
    1130             :         }
    1131           0 :         NdotFuel = 0.0;
    1132           0 :         MdotFuel = 0.0;
    1133           0 :         MdotAir = 0.0;
    1134           0 :         ElecEff = 0.0;
    1135           0 :         ThermEff = 0.0;
    1136           0 :         Qgross = 0.0;
    1137           0 :         Qgenss = 0.0;
    1138           0 :     } break;
    1139           0 :     default:
    1140           0 :         break;
    1141             :     }
    1142             : 
    1143       69660 :     for (int i = 1; i <= 20; ++i) { // sequential search with exit criteria
    1144             :         // calculate new value for engine temperature
    1145             :         // for Stirling in warmup, need to include dependency of Qgness on Teng
    1146       69660 :         if ((this->A42Model.WarmUpByEngineTemp) && (CurrentOpMode == DataGenerators::OperatingMode::WarmUp)) {
    1147             : 
    1148           0 :             Real64 Pmax = this->A42Model.MaxElecPower;
    1149           0 :             TcwIn = state.dataLoopNodes->Node(this->PlantInletNodeID).Temp;          // C
    1150           0 :             MdotCW = state.dataLoopNodes->Node(this->PlantInletNodeID).MassFlowRate; // kg/s
    1151           0 :             ElecEff = Curve::CurveValue(state, this->A42Model.ElecEffCurveID, Pmax, MdotCW, TcwIn);
    1152           0 :             ElecEff = max(0.0, ElecEff); // protect against bad curve result
    1153           0 :             if (ElecEff > 0.0) {         // trap divide by bad thing
    1154           0 :                 Qgross = Pmax / ElecEff; // W
    1155             :             } else {
    1156           0 :                 Qgross = 0.0;
    1157             :             }
    1158           0 :             NdotFuel = Qgross / (state.dataGenerator->FuelSupply(this->FuelSupplyID).LHV * 1000.0 * 1000.0);
    1159             :             //  kMol/s = (J/s) /(KJ/mol * 1000 J/KJ * 1000 mol/kmol)
    1160           0 :             Real64 MdotFuelMax = NdotFuel * state.dataGenerator->FuelSupply(this->FuelSupplyID).KmolPerSecToKgPerSec;
    1161             : 
    1162             :             Real64 MdotFuelWarmup;
    1163           0 :             if (Teng > thisAmbientTemp) {
    1164           0 :                 MdotFuelWarmup =
    1165           0 :                     MdotFuelMax + this->A42Model.kf * MdotFuelMax * ((this->A42Model.TnomEngOp - thisAmbientTemp) / (Teng - thisAmbientTemp));
    1166             : 
    1167             :                 // check that numerical answer didn't blow up beyond limit, and reset if it did
    1168           0 :                 if (MdotFuelWarmup > this->A42Model.Rfuelwarmup * MdotFuelMax) {
    1169           0 :                     MdotFuelWarmup = this->A42Model.Rfuelwarmup * MdotFuelMax;
    1170             :                 }
    1171           0 :                 if (this->A42Model.TnomEngOp > thisAmbientTemp) {
    1172           0 :                     Pnetss = Pmax * this->A42Model.kp * ((Teng - thisAmbientTemp) / (this->A42Model.TnomEngOp - thisAmbientTemp));
    1173             :                 } else { // equal would divide by zero
    1174           0 :                     Pnetss = Pmax;
    1175             :                 }
    1176             :             } else { // equal would divide by zero
    1177           0 :                 MdotFuelWarmup = this->A42Model.Rfuelwarmup * MdotFuelMax;
    1178             :             }
    1179           0 :             MdotFuel = MdotFuelWarmup;
    1180           0 :             NdotFuel = MdotFuel / state.dataGenerator->FuelSupply(this->FuelSupplyID).KmolPerSecToKgPerSec;
    1181           0 :             MdotAir = Curve::CurveValue(state, this->A42Model.AirFlowCurveID, MdotFuelWarmup);
    1182           0 :             MdotAir = max(0.0, MdotAir); // protect against bad curve result
    1183           0 :             Qgross = NdotFuel * (state.dataGenerator->FuelSupply(this->FuelSupplyID).LHV * 1000.0 * 1000.0);
    1184           0 :             ThermEff = Curve::CurveValue(state, this->A42Model.ThermalEffCurveID, Pmax, MdotCW, TcwIn);
    1185           0 :             ThermEff = max(0.0, ThermEff); // protect against bad curve result
    1186           0 :             Qgenss = ThermEff * Qgross;    // W
    1187             :         }
    1188             : 
    1189       69660 :         Real64 dt = state.dataHVACGlobal->TimeStepSys * DataGlobalConstants::SecInHour;
    1190             : 
    1191       69660 :         Teng = FuncDetermineEngineTemp(
    1192             :             TcwOut, this->A42Model.MCeng, this->A42Model.UAhx, this->A42Model.UAskin, thisAmbientTemp, Qgenss, this->A42Model.TengLast, dt);
    1193             : 
    1194      139320 :         Real64 Cp = FluidProperties::GetSpecificHeatGlycol(state,
    1195       69660 :                                                            state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).FluidName,
    1196             :                                                            TcwIn,
    1197       69660 :                                                            state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).FluidIndex,
    1198       69660 :                                                            RoutineName);
    1199             : 
    1200       69660 :         TcwOut =
    1201       69660 :             FuncDetermineCoolantWaterExitTemp(TcwIn, this->A42Model.MCcw, this->A42Model.UAhx, MdotCW * Cp, Teng, this->A42Model.TempCWOutLast, dt);
    1202             : 
    1203             :         // form balance and exit once met.
    1204       69660 :         bool EnergyBalOK = CheckMicroCHPThermalBalance(this->A42Model.MaxElecPower,
    1205             :                                                        TcwIn,
    1206             :                                                        TcwOut,
    1207             :                                                        Teng,
    1208             :                                                        thisAmbientTemp,
    1209             :                                                        this->A42Model.UAhx,
    1210             :                                                        this->A42Model.UAskin,
    1211             :                                                        Qgenss,
    1212             :                                                        this->A42Model.MCeng,
    1213             :                                                        this->A42Model.MCcw,
    1214       69660 :                                                        MdotCW * Cp);
    1215             : 
    1216       69660 :         if (EnergyBalOK && (i > 4)) break;
    1217             :     }
    1218             : 
    1219       13932 :     this->PlantMassFlowRate = MdotCW;
    1220       13932 :     this->A42Model.Pnet = Pnetss - Pcooler - Pstandby;
    1221       13932 :     this->A42Model.ElecEff = ElecEff;
    1222       13932 :     this->A42Model.Qgross = Qgross;
    1223       13932 :     this->A42Model.ThermEff = ThermEff;
    1224       13932 :     this->A42Model.Qgenss = Qgenss;
    1225       13932 :     this->A42Model.NdotFuel = NdotFuel;
    1226       13932 :     this->A42Model.MdotFuel = MdotFuel;
    1227       13932 :     this->A42Model.Teng = Teng;
    1228       13932 :     this->A42Model.TcwOut = TcwOut;
    1229       13932 :     this->A42Model.TcwIn = TcwIn;
    1230       13932 :     this->A42Model.MdotAir = MdotAir;
    1231       13932 :     this->A42Model.QdotSkin = this->A42Model.UAskin * (Teng - thisAmbientTemp);
    1232             : 
    1233       13932 :     this->A42Model.OpMode = CurrentOpMode;
    1234       13932 : }
    1235             : 
    1236       69660 : Real64 FuncDetermineEngineTemp(Real64 const TcwOut,   // hot water leaving temp
    1237             :                                Real64 const MCeng,    // Fictitious mass and heat capacity of engine
    1238             :                                Real64 const UAHX,     // Heat exchanger UA
    1239             :                                Real64 const UAskin,   // Skin losses UA
    1240             :                                Real64 const Troom,    // surrounding zone temperature C
    1241             :                                Real64 const Qgenss,   // steady state generator heat generation
    1242             :                                Real64 const TengLast, // engine temp at previous time step
    1243             :                                Real64 const time      // elapsed time since previous evaluation
    1244             : )
    1245             : {
    1246             : 
    1247             :     // FUNCTION INFORMATION:
    1248             :     //       AUTHOR         B. Griffith
    1249             :     //       DATE WRITTEN   Feb. 2007
    1250             :     //       MODIFIED       na
    1251             :     //       RE-ENGINEERED  na
    1252             : 
    1253             :     // PURPOSE OF THIS FUNCTION:
    1254             :     // Calculate engine temperaure,
    1255             : 
    1256             :     // METHODOLOGY EMPLOYED:
    1257             :     // model is dynamic in that previous condition affects current timestep
    1258             :     //  solve ode for engine temp using analytical solution
    1259             : 
    1260       69660 :     Real64 a = ((UAHX * TcwOut / MCeng) + (UAskin * Troom / MCeng) + (Qgenss / MCeng));
    1261       69660 :     Real64 b = ((-1.0 * UAHX / MCeng) + (-1.0 * UAskin / MCeng));
    1262             : 
    1263       69660 :     return (TengLast + a / b) * std::exp(b * time) - a / b;
    1264             : }
    1265             : 
    1266       69660 : Real64 FuncDetermineCoolantWaterExitTemp(Real64 const TcwIn,      // hot water inlet temp
    1267             :                                          Real64 const MCcw,       // Fictitious mass and heat capacity of coolant hx
    1268             :                                          Real64 const UAHX,       // Heat exchanger UA
    1269             :                                          Real64 const MdotCpcw,   // mass flow and specific heat of coolant water
    1270             :                                          Real64 const Teng,       // engine mass temperature C
    1271             :                                          Real64 const TcwoutLast, // coolant water leaving temp at previous time step
    1272             :                                          Real64 const time        // elapsed time since previous evaluation
    1273             : )
    1274             : {
    1275             : 
    1276             :     // FUNCTION INFORMATION:
    1277             :     //       AUTHOR         B. Griffith
    1278             :     //       DATE WRITTEN   Feb. 2007
    1279             :     //       MODIFIED       na
    1280             :     //       RE-ENGINEERED  na
    1281             : 
    1282             :     // PURPOSE OF THIS FUNCTION:
    1283             :     // Calculate coolan water leaving temperaure,
    1284             : 
    1285             :     // METHODOLOGY EMPLOYED:
    1286             :     // model is dynamic in that previous condition affects current timestep
    1287             :     //  solve ode for coolant water outlet temp using analytical solution
    1288             : 
    1289       69660 :     Real64 a = (MdotCpcw * TcwIn / MCcw) + (UAHX * Teng / MCcw);
    1290       69660 :     Real64 b = ((-1.0 * MdotCpcw / MCcw) + (-1.0 * UAHX / MCcw));
    1291             : 
    1292       69660 :     if (b * time < (-1.0 * DataGlobalConstants::MaxEXPArg)) {
    1293       19170 :         return -a / b;
    1294             :     } else {
    1295       50490 :         return (TcwoutLast + a / b) * std::exp(b * time) - a / b;
    1296             :     }
    1297             : }
    1298             : 
    1299       69660 : bool CheckMicroCHPThermalBalance(Real64 const NomHeatGen, // nominal heat generation rate for scaling
    1300             :                                  Real64 const TcwIn,      // hot water inlet temp
    1301             :                                  Real64 const TcwOut,     // hot water leaving temp
    1302             :                                  Real64 const Teng,       // engine mass temperature C
    1303             :                                  Real64 const Troom,      // surrounding zone temperature C
    1304             :                                  Real64 const UAHX,       // Heat exchanger UA
    1305             :                                  Real64 const UAskin,     // Skin losses UA
    1306             :                                  Real64 const Qgenss,     // steady state generator heat generation
    1307             :                                  Real64 const MCeng,      // Fictitious mass and heat capacity of engine
    1308             :                                  Real64 const MCcw,       // Fictitious mass and heat capacity of coolant hx
    1309             :                                  Real64 const MdotCpcw    // mass flow and specific heat of coolant water
    1310             : )
    1311             : {
    1312             : 
    1313             :     // FUNCTION INFORMATION:
    1314             :     //       AUTHOR         B. Griffith
    1315             :     //       DATE WRITTEN   Feb. 2007
    1316             :     //       MODIFIED       na
    1317             :     //       RE-ENGINEERED  na
    1318             : 
    1319             :     // PURPOSE OF THIS FUNCTION:
    1320             :     // Check for energy balance to test if can exit iteration loop
    1321             : 
    1322             :     // METHODOLOGY EMPLOYED:
    1323             :     // put all terms of dynamic energy balances on RHS and compute magnitude of imbalance
    1324             :     //  compare imbalance to scalable thresholds and make a boolean conclusion.
    1325             : 
    1326             :     // first compute derivatives using a + bT
    1327             :     // derivative of engine temp wrt time
    1328       69660 :     Real64 a = ((UAHX * TcwOut / MCeng) + (UAskin * Troom / MCeng) + (Qgenss / MCeng));
    1329       69660 :     Real64 b = ((-1.0 * UAHX / MCeng) + (-1.0 * UAskin / MCeng));
    1330       69660 :     Real64 DTengDTime = a + b * Teng;
    1331             : 
    1332             :     // derivative of coolant exit temp wrt time
    1333       69660 :     Real64 c = (MdotCpcw * TcwIn / MCcw) + (UAHX * Teng / MCcw);
    1334       69660 :     Real64 d = ((-1.0 * MdotCpcw / MCcw) + (-1.0 * UAHX / MCcw));
    1335       69660 :     Real64 DCoolOutTDtime = c + d * TcwOut;
    1336             : 
    1337             :     // energy imbalance for engine control volume
    1338       69660 :     Real64 magImbalEng = UAHX * (TcwOut - Teng) + UAskin * (Troom - Teng) + Qgenss - MCeng * DTengDTime;
    1339             : 
    1340             :     // energy imbalance for coolant control volume
    1341       69660 :     Real64 magImbalCooling = MdotCpcw * (TcwIn - TcwOut) + UAHX * (Teng - TcwOut) - MCcw * DCoolOutTDtime;
    1342             : 
    1343             :     // criteria for when to call energy balance okay
    1344       69660 :     Real64 threshold = NomHeatGen / 10000000.0;
    1345             : 
    1346       69660 :     return (threshold > magImbalEng) && (threshold > magImbalCooling);
    1347             : }
    1348             : 
    1349     2568509 : void FigureMicroCHPZoneGains(EnergyPlusData &state)
    1350             : {
    1351             : 
    1352             :     // SUBROUTINE INFORMATION:
    1353             :     //       AUTHOR         B. Griffith
    1354             :     //       DATE WRITTEN   July 2006
    1355             :     //       MODIFIED       na
    1356             :     //       RE-ENGINEERED  na
    1357             : 
    1358             :     // PURPOSE OF THIS SUBROUTINE:
    1359             :     // Couple equipment skin losses to the Zone Heat Balance
    1360             : 
    1361             :     // METHODOLOGY EMPLOYED:
    1362             :     // This routine adds up the various skin losses and then
    1363             :     //  sets the values in the ZoneIntGain structure
    1364             : 
    1365     2568509 :     if (state.dataCHPElectGen->NumMicroCHPs == 0) return;
    1366             : 
    1367        6502 :     if (state.dataGlobal->BeginEnvrnFlag && state.dataCHPElectGen->MyEnvrnFlag) {
    1368          32 :         for (auto &e : state.dataGenerator->FuelSupply)
    1369          20 :             e.QskinLoss = 0.0;
    1370          24 :         for (auto &e : state.dataCHPElectGen->MicroCHP) {
    1371          12 :             e.A42Model.QdotSkin = 0.0;
    1372          12 :             e.A42Model.SkinLossConvect = 0.0;
    1373          12 :             e.A42Model.SkinLossRadiat = 0.0;
    1374             :         }
    1375          12 :         state.dataCHPElectGen->MyEnvrnFlag = false;
    1376             :     }
    1377             : 
    1378        6502 :     if (!state.dataGlobal->BeginEnvrnFlag) state.dataCHPElectGen->MyEnvrnFlag = true;
    1379             : 
    1380       13004 :     for (int CHPnum = 1; CHPnum <= state.dataCHPElectGen->NumMicroCHPs; ++CHPnum) {
    1381        6502 :         Real64 TotalZoneHeatGain = state.dataGenerator->FuelSupply(state.dataCHPElectGen->MicroCHP(CHPnum).FuelSupplyID).QskinLoss +
    1382        6502 :                                    state.dataCHPElectGen->MicroCHP(CHPnum).A42Model.QdotSkin;
    1383             : 
    1384        6502 :         state.dataCHPElectGen->MicroCHP(CHPnum).A42Model.QdotConvZone =
    1385        6502 :             TotalZoneHeatGain * (1 - state.dataCHPElectGen->MicroCHP(CHPnum).A42Model.RadiativeFraction);
    1386        6502 :         state.dataCHPElectGen->MicroCHP(CHPnum).A42Model.SkinLossConvect = state.dataCHPElectGen->MicroCHP(CHPnum).A42Model.QdotConvZone;
    1387        6502 :         state.dataCHPElectGen->MicroCHP(CHPnum).A42Model.QdotRadZone =
    1388        6502 :             TotalZoneHeatGain * state.dataCHPElectGen->MicroCHP(CHPnum).A42Model.RadiativeFraction;
    1389        6502 :         state.dataCHPElectGen->MicroCHP(CHPnum).A42Model.SkinLossRadiat = state.dataCHPElectGen->MicroCHP(CHPnum).A42Model.QdotRadZone;
    1390             :     }
    1391             : }
    1392             : 
    1393       13932 : void MicroCHPDataStruct::CalcUpdateHeatRecovery(EnergyPlusData &state) const
    1394             : {
    1395             : 
    1396             :     // SUBROUTINE INFORMATION:
    1397             :     //       AUTHOR         B Griffith
    1398             :     //       DATE WRITTEN   Aug 2006
    1399             :     //       MODIFIED       na
    1400             :     //       RE-ENGINEERED  na
    1401             : 
    1402             :     // PURPOSE OF THIS SUBROUTINE:
    1403             :     // update plant loop interactions, do any calcs needed
    1404             : 
    1405             :     static constexpr std::string_view RoutineName("CalcUpdateHeatRecovery");
    1406             : 
    1407       13932 :     PlantUtilities::SafeCopyPlantNode(state, this->PlantInletNodeID, this->PlantOutletNodeID);
    1408             : 
    1409       13932 :     state.dataLoopNodes->Node(this->PlantOutletNodeID).Temp = this->A42Model.TcwOut;
    1410             : 
    1411       27864 :     Real64 Cp = FluidProperties::GetSpecificHeatGlycol(state,
    1412       13932 :                                                        state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).FluidName,
    1413       13932 :                                                        this->A42Model.TcwIn,
    1414       13932 :                                                        state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).FluidIndex,
    1415       13932 :                                                        RoutineName);
    1416             : 
    1417       13932 :     state.dataLoopNodes->Node(this->PlantOutletNodeID).Enthalpy = this->A42Model.TcwOut * Cp;
    1418       13932 : }
    1419             : 
    1420          10 : void MicroCHPDataStruct::getDesignCapacities(
    1421             :     [[maybe_unused]] EnergyPlusData &state, const EnergyPlus::PlantLocation &, Real64 &MaxLoad, Real64 &MinLoad, Real64 &OptLoad)
    1422             : {
    1423          10 :     MaxLoad = state.dataGenerator->GeneratorDynamics(this->DynamicsControlID).QdotHXMax;
    1424          10 :     MinLoad = state.dataGenerator->GeneratorDynamics(this->DynamicsControlID).QdotHXMin;
    1425          10 :     OptLoad = state.dataGenerator->GeneratorDynamics(this->DynamicsControlID).QdotHXOpt;
    1426          10 : }
    1427             : 
    1428       13932 : void MicroCHPDataStruct::UpdateMicroCHPGeneratorRecords(EnergyPlusData &state) // Generator number
    1429             : {
    1430             : 
    1431             :     // SUBROUTINE INFORMATION:
    1432             :     //       AUTHOR         B. Griffith
    1433             :     //       DATE WRITTEN   July 2006
    1434             :     //       MODIFIED       na
    1435             :     //       RE-ENGINEERED  na
    1436             : 
    1437             :     // PURPOSE OF THIS SUBROUTINE:
    1438             :     // update variables in structures linked to output reports
    1439             : 
    1440             :     static constexpr std::string_view RoutineName("UpdateMicroCHPGeneratorRecords");
    1441             : 
    1442       13932 :     this->A42Model.ACPowerGen = this->A42Model.Pnet; // electrical power produced [W]
    1443       13932 :     this->A42Model.ACEnergyGen = this->A42Model.Pnet * state.dataHVACGlobal->TimeStepSys * DataGlobalConstants::SecInHour; // energy produced (J)
    1444       13932 :     this->A42Model.QdotHX = this->A42Model.UAhx * (this->A42Model.Teng - this->A42Model.TcwOut);                           //  heat recovered rate (W)
    1445             : 
    1446       27864 :     Real64 Cp = FluidProperties::GetSpecificHeatGlycol(state,
    1447       13932 :                                                        state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).FluidName,
    1448             :                                                        this->A42Model.TcwIn,
    1449       13932 :                                                        state.dataPlnt->PlantLoop(this->CWPlantLoc.loopNum).FluidIndex,
    1450       13932 :                                                        RoutineName);
    1451             : 
    1452       13932 :     this->A42Model.QdotHR = this->PlantMassFlowRate * Cp * (this->A42Model.TcwOut - this->A42Model.TcwIn);
    1453       13932 :     this->A42Model.TotalHeatEnergyRec =
    1454       13932 :         this->A42Model.QdotHR * state.dataHVACGlobal->TimeStepSys * DataGlobalConstants::SecInHour; // heat recovered energy (J)
    1455             : 
    1456       13932 :     this->A42Model.HeatRecInletTemp = this->A42Model.TcwIn;   // Heat Recovery Loop Inlet Temperature (C)
    1457       13932 :     this->A42Model.HeatRecOutletTemp = this->A42Model.TcwOut; // Heat Recovery Loop Outlet Temperature (C)
    1458             : 
    1459       13932 :     this->A42Model.FuelCompressPower = state.dataGenerator->FuelSupply(this->FuelSupplyID).PfuelCompEl;
    1460             :     // electrical power used by fuel supply compressor [W]
    1461       13932 :     this->A42Model.FuelCompressEnergy = state.dataGenerator->FuelSupply(this->FuelSupplyID).PfuelCompEl * state.dataHVACGlobal->TimeStepSys *
    1462             :                                         DataGlobalConstants::SecInHour; // elect energy
    1463       13932 :     this->A42Model.FuelCompressSkinLoss = state.dataGenerator->FuelSupply(this->FuelSupplyID).QskinLoss;
    1464             :     // heat rate of losses.by fuel supply compressor [W]
    1465       41796 :     this->A42Model.FuelEnergyHHV = this->A42Model.NdotFuel * state.dataGenerator->FuelSupply(this->FuelSupplyID).HHV *
    1466       27864 :                                    state.dataGenerator->FuelSupply(this->FuelSupplyID).KmolPerSecToKgPerSec * state.dataHVACGlobal->TimeStepSys *
    1467             :                                    DataGlobalConstants::SecInHour;
    1468             :     // reporting: Fuel Energy used (W)
    1469       27864 :     this->A42Model.FuelEnergyUseRateHHV = this->A42Model.NdotFuel * state.dataGenerator->FuelSupply(this->FuelSupplyID).HHV *
    1470       13932 :                                           state.dataGenerator->FuelSupply(this->FuelSupplyID).KmolPerSecToKgPerSec;
    1471             :     // reporting: Fuel Energy used (J)
    1472       41796 :     this->A42Model.FuelEnergyLHV = this->A42Model.NdotFuel * state.dataGenerator->FuelSupply(this->FuelSupplyID).LHV * 1000000.0 *
    1473       27864 :                                    state.dataHVACGlobal->TimeStepSys * DataGlobalConstants::SecInHour;
    1474             :     // reporting: Fuel Energy used (W)
    1475       13932 :     this->A42Model.FuelEnergyUseRateLHV = this->A42Model.NdotFuel * state.dataGenerator->FuelSupply(this->FuelSupplyID).LHV * 1000000.0;
    1476             : 
    1477       13932 :     this->A42Model.SkinLossPower = this->A42Model.QdotConvZone + this->A42Model.QdotRadZone;
    1478       13932 :     this->A42Model.SkinLossEnergy =
    1479       13932 :         (this->A42Model.QdotConvZone + this->A42Model.QdotRadZone) * state.dataHVACGlobal->TimeStepSys * DataGlobalConstants::SecInHour;
    1480       13932 :     this->A42Model.SkinLossConvect = this->A42Model.QdotConvZone;
    1481       13932 :     this->A42Model.SkinLossRadiat = this->A42Model.QdotRadZone;
    1482             : 
    1483             :     // update node data for air inlet (and outlet)
    1484       13932 :     if (this->AirInletNodeID > 0) {
    1485       13932 :         state.dataLoopNodes->Node(this->AirInletNodeID).MassFlowRate = this->A42Model.MdotAir;
    1486             :     }
    1487       13932 :     if (this->AirOutletNodeID > 0) {
    1488           0 :         state.dataLoopNodes->Node(this->AirOutletNodeID).MassFlowRate = this->A42Model.MdotAir;
    1489           0 :         state.dataLoopNodes->Node(this->AirOutletNodeID).Temp = this->A42Model.Teng;
    1490             :     }
    1491       13932 : }
    1492       16022 : void MicroCHPDataStruct::oneTimeInit(EnergyPlusData &state)
    1493             : {
    1494             : 
    1495             :     bool errFlag;
    1496             : 
    1497       16022 :     if (this->myFlag) {
    1498           2 :         this->setupOutputVars(state);
    1499           2 :         this->myFlag = false;
    1500             :     }
    1501             : 
    1502       16022 :     if (this->MyPlantScanFlag) {
    1503           2 :         if (allocated(state.dataPlnt->PlantLoop)) {
    1504           2 :             errFlag = false;
    1505           2 :             PlantUtilities::ScanPlantLoopsForObject(
    1506             :                 state, this->Name, DataPlant::PlantEquipmentType::Generator_MicroCHP, this->CWPlantLoc, errFlag, _, _, _, _, _);
    1507             : 
    1508           2 :             if (errFlag) {
    1509           0 :                 ShowFatalError(state, "InitMicroCHPNoNormalizeGenerators: Program terminated for previous conditions.");
    1510             :             }
    1511             : 
    1512           2 :             if (!this->A42Model.InternalFlowControl) {
    1513             :                 // IF this is on the supply side and not internal flow control then reset flow priority to lower
    1514           1 :                 if (this->CWPlantLoc.loopSideNum == DataPlant::LoopSideLocation::Supply) {
    1515           1 :                     DataPlant::CompData::getPlantComponent(state, this->CWPlantLoc).FlowPriority = DataPlant::LoopFlowStatus::TakesWhatGets;
    1516             :                 }
    1517             :             }
    1518             : 
    1519           2 :             this->MyPlantScanFlag = false;
    1520             :         }
    1521             :     }
    1522       16022 : }
    1523        2313 : } // namespace EnergyPlus::MicroCHPElectricGenerator

Generated by: LCOV version 1.13