LCOV - code coverage report
Current view: top level - EnergyPlus - GeneratorDynamicsManager.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 9.9 % 355 35
Test Date: 2025-05-22 16:09:37 Functions: 25.0 % 4 1

            Line data    Source code
       1              : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
       2              : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3              : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4              : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5              : // contributors. All rights reserved.
       6              : //
       7              : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8              : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9              : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10              : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11              : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12              : //
      13              : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14              : // provided that the following conditions are met:
      15              : //
      16              : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17              : //     conditions and the following disclaimer.
      18              : //
      19              : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20              : //     conditions and the following disclaimer in the documentation and/or other materials
      21              : //     provided with the distribution.
      22              : //
      23              : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24              : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25              : //     used to endorse or promote products derived from this software without specific prior
      26              : //     written permission.
      27              : //
      28              : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29              : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30              : //     reference solely to the software portion of its product, Licensee must refer to the
      31              : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32              : //     obtained under this License and may not use a different name for the software. Except as
      33              : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34              : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35              : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36              : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37              : //
      38              : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39              : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40              : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41              : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42              : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43              : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44              : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45              : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46              : // POSSIBILITY OF SUCH DAMAGE.
      47              : 
      48              : // C++ Headers
      49              : #include <cmath>
      50              : 
      51              : // ObjexxFCL Headers
      52              : #include <ObjexxFCL/Array.functions.hh>
      53              : #include <ObjexxFCL/Fmath.hh>
      54              : 
      55              : // EnergyPlus Headers
      56              : #include <EnergyPlus/CurveManager.hh>
      57              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      58              : #include <EnergyPlus/DataGenerators.hh>
      59              : #include <EnergyPlus/DataGlobalConstants.hh>
      60              : #include <EnergyPlus/DataHVACGlobals.hh>
      61              : #include <EnergyPlus/DataLoopNode.hh>
      62              : #include <EnergyPlus/GeneratorDynamicsManager.hh>
      63              : #include <EnergyPlus/MicroCHPElectricGenerator.hh>
      64              : #include <EnergyPlus/PlantUtilities.hh>
      65              : #include <EnergyPlus/ScheduleManager.hh>
      66              : 
      67              : namespace EnergyPlus {
      68              : 
      69              : namespace GeneratorDynamicsManager {
      70              : 
      71              :     //_______________________________________________
      72              :     // Utility modules used by other generators.
      73              :     //
      74              :     // GeneratorDynamicsManager
      75              :     //   reused among some generators to on/off state, transient limits, control implications etc.
      76              : 
      77              :     // Module containing the routines dealing with the management of dynamic constraints on Generator response
      78              : 
      79              :     // MODULE INFORMATION:
      80              :     //       AUTHOR        B. Griffith
      81              :     //       DATE WRITTEN   July 2006
      82              : 
      83              :     // PURPOSE OF THIS MODULE:
      84              :     // collect routines for managing generator states
      85              :     // reused by different generator models
      86              :     //  determine response that generator is capable of providing
      87              :     //  given load request data
      88              :     //   models requiring calculations across timesteps
      89              : 
      90            2 :     void SetupGeneratorControlStateManager(EnergyPlusData &state, int const GenNum) // index of generator to setup
      91              :     {
      92              :         // SUBROUTINE INFORMATION:
      93              :         //       AUTHOR         B. Griffith
      94              :         //       DATE WRITTEN   July 2006
      95              : 
      96              :         // PURPOSE OF THIS SUBROUTINE:
      97              :         // sets up data structures
      98              : 
      99              :         // METHODOLOGY EMPLOYED:
     100              :         // like a get input routine but feeds from
     101              :         //  parent objects, could have its own input object someday
     102              : 
     103              :         // get the number of generators that might use this module
     104            2 :         int const NumGensWDynamics = state.dataCHPElectGen->NumMicroCHPs; // TODO  + NumFuelCellCGenerators
     105              : 
     106            2 :         if (!allocated(state.dataGenerator->GeneratorDynamics)) {
     107            1 :             state.dataGenerator->GeneratorDynamics.allocate(NumGensWDynamics);
     108              :         }
     109              : 
     110              :         // first populate with Micro CHP data
     111            2 :         auto &thisGen = state.dataGenerator->GeneratorDynamics(GenNum);
     112            2 :         auto &thisMicroCHP = state.dataCHPElectGen->MicroCHP(GenNum);
     113            2 :         thisGen.Name = thisMicroCHP.Name;
     114            2 :         thisGen.PelMin = thisMicroCHP.A42Model.MinElecPower;
     115            2 :         thisGen.PelMax = thisMicroCHP.A42Model.MaxElecPower;
     116            2 :         thisGen.UpTranLimit = thisMicroCHP.A42Model.DeltaPelMax;
     117            2 :         thisGen.DownTranLimit = thisMicroCHP.A42Model.DeltaPelMax;
     118            2 :         thisGen.UpTranLimitFuel = thisMicroCHP.A42Model.DeltaFuelMdotMax;
     119            2 :         thisGen.DownTranLimitFuel = thisMicroCHP.A42Model.DeltaFuelMdotMax;
     120            2 :         thisGen.WarmUpByTimeDelay = thisMicroCHP.A42Model.WarmUpByTimeDelay;
     121            2 :         thisGen.WarmUpByEngineTemp = thisMicroCHP.A42Model.WarmUpByEngineTemp;
     122            2 :         thisGen.MandatoryFullCoolDown = thisMicroCHP.A42Model.MandatoryFullCoolDown;
     123            2 :         thisGen.WarmRestartOkay = thisMicroCHP.A42Model.WarmRestartOkay;
     124            2 :         thisGen.WarmUpDelay = thisMicroCHP.A42Model.WarmUpDelay;
     125            2 :         thisGen.CoolDownDelay = thisMicroCHP.A42Model.CoolDownDelay / Constant::rSecsInHour; // seconds to hours
     126            2 :         thisGen.PcoolDown = thisMicroCHP.A42Model.PcoolDown;
     127            2 :         thisGen.Pstandby = thisMicroCHP.A42Model.Pstandby;
     128            2 :         thisGen.MCeng = thisMicroCHP.A42Model.MCeng;
     129            2 :         thisGen.MCcw = thisMicroCHP.A42Model.MCcw;
     130            2 :         thisGen.kf = thisMicroCHP.A42Model.kf;
     131            2 :         thisGen.TnomEngOp = thisMicroCHP.A42Model.TnomEngOp;
     132            2 :         thisGen.kp = thisMicroCHP.A42Model.kp;
     133            2 :         thisGen.availSched = thisMicroCHP.availSched;
     134            2 :         thisGen.StartUpTimeDelay = thisMicroCHP.A42Model.WarmUpDelay / Constant::rSecsInHour; // seconds to hours
     135              : 
     136            2 :         thisGen.ElectEffNom = thisMicroCHP.A42Model.ElecEff;
     137            2 :         thisGen.ThermEffNom = thisMicroCHP.A42Model.ThermEff;
     138            2 :         thisGen.QdotHXMax = thisMicroCHP.A42Model.ThermEff * thisMicroCHP.A42Model.MaxElecPower / thisMicroCHP.A42Model.ElecEff;
     139            2 :         thisGen.QdotHXMin = thisMicroCHP.A42Model.ThermEff * thisMicroCHP.A42Model.MinElecPower / thisMicroCHP.A42Model.ElecEff;
     140            2 :         thisGen.QdotHXOpt = thisGen.QdotHXMax;
     141            2 :         thisMicroCHP.DynamicsControlID = GenNum;
     142            2 :     }
     143              : 
     144            0 :     void ManageGeneratorControlState(EnergyPlusData &state,
     145              :                                      int const GeneratorNum,                       // Generator number
     146              :                                      bool const RunFlagElectCenter,                // TRUE when Generator operating per electric load center request
     147              :                                      bool const RunFlagPlant,                      // TRUE when generator operating per Plant request (always false)
     148              :                                      Real64 const ElecLoadRequest,                 // Generator Electrical power demand
     149              :                                      Real64 const ThermalLoadRequest,              // cogenerator Thermal power demand
     150              :                                      Real64 &ElecLoadProvided,                     // power allowed
     151              :                                      DataGenerators::OperatingMode &OperatingMode, // operating mode
     152              :                                      Real64 &PLRforSubtimestepStartUp,             // part load ratio for switch to normal from start up
     153              :                                      Real64 &PLRforSubtimestepShutDown             // part load ratio for switch from cool down to other
     154              :     )
     155              :     {
     156              : 
     157              :         // SUBROUTINE INFORMATION:
     158              :         //       AUTHOR         B Griffith
     159              :         //       DATE WRITTEN   February-March 2007  (replaced July 2006 attempt)
     160              :         //       MODIFIED       Dec 2009, check and constrain with flow available from plant
     161              : 
     162              :         // PURPOSE OF THIS SUBROUTINE:
     163              :         // provide a service to other generators to make decisions, mostly temporal, or cross-timestep issues
     164              :         //  used to model internal controlling issues within an individual generator model
     165              :         //  This subroutine determines the current operating mode and returns the allowed power and
     166              :         // and part load ratio for certain sub-time step switching e.g. in and out of normal mode or cool down mode
     167              : 
     168              :         // METHODOLOGY EMPLOYED:
     169              :         // model controls-related issues, rules based algorithm
     170              :         // Control decision results include:
     171              :         //     -- electrical load allowed/resulting/provided
     172              :         //     -- new operating mode
     173              :         //     -- part load this timestep for shift to normal mode occurring midway in timestep
     174              :         //     -- part load this timestep for shift out of cool down mode
     175              : 
     176              :         // Input data used to make control decisions include:
     177              :         //     -- Electrical load request
     178              :         //     -- Thermal Load request
     179              :         //     -- RunFlagElectricCenter
     180              :         //     -- RunFlagPlant
     181              :         //     -- previous timestep operating mode
     182              :         //     -- previous timestep Power generated
     183              :         //     -- availability schedule (off if not available)
     184              :         //     -- Generator control parameter constants including
     185              :         //           ** Start Up Time Delay  (in hours)
     186              :         //           ** Cool-down time delay (in hours)
     187              :         //     -- Expected Plant flow rate
     188              :         //     -- minimum cooling water flow rate
     189              : 
     190              :         // Algorithm summary
     191              :         //   1.  examine calling run flags and refine electric load request to account for
     192              :         //       thermal load requests (not yet ready for prime time)
     193              :         //   2.  Determine states of various control inputs that change during simulation
     194              :         //   3.  enter case statement based on previous operating mode.
     195              :         //       --  decide on current operating mode
     196              :         //       --  calculate part loads
     197              : 
     198              :         //   4.  based on current operating mode determine allowed/provided electrical load
     199              :         //        a. set allowed elec load by mode
     200              :         //        b. set allowed elec load by constraints on rate of change
     201              :         //        c. set allowed elec load by min and max
     202              : 
     203              :         //   5.  Calculated part load ratios for special cases.
     204              :         // REFERENCES:
     205              :         // controls specifications in Annex 42 model specs.
     206              :         // Using/Aliasing
     207            0 :         Real64 const SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
     208            0 :         Real64 const TimeStepSys = state.dataHVACGlobal->TimeStepSys;
     209            0 :         Real64 const TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
     210              : 
     211              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     212              :         bool RunFlag; // true if generator supposed to run
     213            0 :         DataGenerators::OperatingMode newOpMode(DataGenerators::OperatingMode::Invalid);
     214              : 
     215              :         // inits
     216            0 :         PLRforSubtimestepStartUp = 1.0;
     217            0 :         PLRforSubtimestepShutDown = 0.0;
     218            0 :         bool PLRStartUp = false; // true if subtimestep issue involving startup
     219            0 :         bool PLRShutDown = false;
     220            0 :         state.dataGenerator->InternalFlowControl = false;
     221              : 
     222              :         // get index for this generator in dynamics control structure
     223            0 :         int DynaCntrlNum = state.dataCHPElectGen->MicroCHP(GeneratorNum).DynamicsControlID;
     224              :         // OutletCWnode = MicroCHPElectricGenerator::MicroCHP(GeneratorNum)%PlantOutletNodeID
     225            0 :         state.dataGenerator->InletCWnode = state.dataCHPElectGen->MicroCHP(GeneratorNum).PlantInletNodeID;
     226            0 :         state.dataGenerator->TcwIn = state.dataLoopNodes->Node(state.dataCHPElectGen->MicroCHP(GeneratorNum).PlantInletNodeID).Temp;
     227            0 :         if (state.dataCHPElectGen->MicroCHP(GeneratorNum).A42Model.InternalFlowControl) {
     228            0 :             state.dataGenerator->InternalFlowControl = true;
     229              :         }
     230            0 :         state.dataGenerator->LimitMinMdotcw = state.dataCHPElectGen->MicroCHP(GeneratorNum).A42Model.MinWaterMdot;
     231              : 
     232            0 :         auto &thisGen = state.dataGenerator->GeneratorDynamics(DynaCntrlNum);
     233            0 :         Real64 PelInput = ElecLoadRequest; // holds initial value of IN var
     234            0 :         Real64 ElectLoadForThermalRequest = 0.0;
     235            0 :         if ((ThermalLoadRequest > 0.0) && RunFlagPlant) { // deal with possible thermal load following
     236              :             // Modify electric load request based on thermal load following signal using nominal efficiencies
     237            0 :             ElectLoadForThermalRequest = thisGen.ThermEffNom * ThermalLoadRequest / thisGen.ElectEffNom;
     238            0 :             PelInput = max(PelInput, ElectLoadForThermalRequest);
     239              :         }
     240              : 
     241            0 :         if ((RunFlagElectCenter) || (RunFlagPlant)) {
     242            0 :             RunFlag = true;
     243              :         } else {
     244            0 :             RunFlag = false;
     245              :         }
     246              : 
     247              :         // check availability schedule
     248            0 :         Real64 SchedVal = thisGen.availSched->getCurrentVal();
     249            0 :         Real64 Pel = PelInput;
     250              : 
     251              :         // get data to check if sufficient flow available from Plant
     252            0 :         if (state.dataGenerator->InternalFlowControl && (SchedVal > 0.0)) {
     253            0 :             state.dataGenerator->TrialMdotcw = FuncDetermineCWMdotForInternalFlowControl(state, GeneratorNum, Pel, state.dataGenerator->TcwIn);
     254              :         } else {
     255            0 :             state.dataGenerator->TrialMdotcw = state.dataLoopNodes->Node(state.dataGenerator->InletCWnode).MassFlowRate;
     256              :         }
     257              : 
     258              :         // determine current operating mode.
     259            0 :         switch (thisGen.LastOpMode) {
     260            0 :         case DataGenerators::OperatingMode::Off:
     261              :         case DataGenerators::OperatingMode::Standby: {
     262              :             // possible future states {Off, Standby, WarmUp,Normal }
     263            0 :             if (SchedVal == 0.0) {
     264            0 :                 newOpMode = DataGenerators::OperatingMode::Off;
     265              : 
     266            0 :             } else if (((SchedVal != 0.0) && (!RunFlag)) || (state.dataGenerator->TrialMdotcw < state.dataGenerator->LimitMinMdotcw)) {
     267            0 :                 newOpMode = DataGenerators::OperatingMode::Standby;
     268            0 :             } else if ((SchedVal != 0.0) && (RunFlag)) {
     269              : 
     270            0 :                 if (thisGen.WarmUpByTimeDelay) {
     271              : 
     272            0 :                     if (thisGen.StartUpTimeDelay == 0.0) {
     273            0 :                         newOpMode = DataGenerators::OperatingMode::Normal;
     274              : 
     275              :                         // is startUp time delay longer than timestep?
     276            0 :                     } else if (thisGen.StartUpTimeDelay >= TimeStepSys) {
     277            0 :                         newOpMode = DataGenerators::OperatingMode::WarmUp;
     278              :                         // generator just started so set start time
     279            0 :                         thisGen.FractionalDayofLastStartUp =
     280            0 :                             double(state.dataGlobal->DayOfSim) +
     281            0 :                             (int(state.dataGlobal->CurrentTime) +
     282            0 :                              (SysTimeElapsed + (state.dataGlobal->CurrentTime - int(state.dataGlobal->CurrentTime) - TimeStepSys))) /
     283              :                                 Constant::rHoursInDay;
     284              : 
     285              :                     } else { // warm up period is less than a single system time step
     286            0 :                         newOpMode = DataGenerators::OperatingMode::Normal;
     287            0 :                         PLRStartUp = true;
     288            0 :                         PLRforSubtimestepStartUp = (TimeStepSys - thisGen.StartUpTimeDelay) / TimeStepSys;
     289              :                     }
     290              :                 }
     291            0 :                 if (thisGen.WarmUpByEngineTemp) {
     292            0 :                     if (state.dataCHPElectGen->MicroCHP(GeneratorNum).A42Model.Teng >= thisGen.TnomEngOp) {
     293            0 :                         auto const &thisMicroCHP = state.dataCHPElectGen->MicroCHP(GeneratorNum);
     294            0 :                         newOpMode = DataGenerators::OperatingMode::Normal;
     295              :                         // assume linear interpolation for PLR
     296            0 :                         PLRStartUp = true;
     297            0 :                         if ((thisMicroCHP.A42Model.Teng - thisMicroCHP.A42Model.TengLast) > 0.0) {
     298              :                             // protect divide by zero or neg
     299            0 :                             PLRforSubtimestepStartUp =
     300            0 :                                 (thisMicroCHP.A42Model.Teng - thisGen.TnomEngOp) / (thisMicroCHP.A42Model.Teng - thisMicroCHP.A42Model.TengLast);
     301              :                         } else {
     302            0 :                             PLRforSubtimestepStartUp = 1.0;
     303              :                         }
     304              :                     } else {
     305            0 :                         newOpMode = DataGenerators::OperatingMode::WarmUp;
     306              :                     }
     307              :                 }
     308              :             }
     309              : 
     310            0 :         } break;
     311            0 :         case DataGenerators::OperatingMode::WarmUp: {
     312              :             // possible Future states {OFF, WarmUp, Normal, CoolDown }
     313              :             // check availability manager
     314            0 :             if (SchedVal == 0.0) {
     315              :                 // to off unless cool down time period is needed
     316            0 :                 if (thisGen.CoolDownDelay == 0.0) {
     317            0 :                     newOpMode = DataGenerators::OperatingMode::Off;
     318              :                 } else {
     319            0 :                     if (thisGen.CoolDownDelay > TimeStepSys) {
     320            0 :                         newOpMode = DataGenerators::OperatingMode::CoolDown;
     321              :                         // need to reset time of last shut down here
     322            0 :                         thisGen.FractionalDayofLastShutDown =
     323            0 :                             double(state.dataGlobal->DayOfSim) +
     324            0 :                             (int(state.dataGlobal->CurrentTime) +
     325            0 :                              (SysTimeElapsed + (state.dataGlobal->CurrentTime - int(state.dataGlobal->CurrentTime)))) /
     326              :                                 Constant::rHoursInDay;
     327              :                     } else {
     328            0 :                         newOpMode = DataGenerators::OperatingMode::Off;
     329              :                     }
     330              :                 }
     331            0 :             } else if (((SchedVal != 0.0) && (!RunFlag)) || (state.dataGenerator->TrialMdotcw < state.dataGenerator->LimitMinMdotcw)) {
     332              :                 // to standby unless cool down time period is needed
     333            0 :                 if (thisGen.CoolDownDelay == 0.0) {
     334            0 :                     newOpMode = DataGenerators::OperatingMode::Standby;
     335              :                 } else {
     336            0 :                     if (thisGen.CoolDownDelay > TimeStepSys) {
     337            0 :                         newOpMode = DataGenerators::OperatingMode::CoolDown;
     338              :                         // need to reset time of last shut down here
     339            0 :                         thisGen.FractionalDayofLastShutDown =
     340            0 :                             double(state.dataGlobal->DayOfSim) +
     341            0 :                             (int(state.dataGlobal->CurrentTime) +
     342            0 :                              (SysTimeElapsed + (state.dataGlobal->CurrentTime - int(state.dataGlobal->CurrentTime)))) /
     343              :                                 Constant::rHoursInDay;
     344              : 
     345              :                     } else {
     346            0 :                         newOpMode = DataGenerators::OperatingMode::Standby;
     347              :                         // assuming no PLR situation unless engine made to normal operation.
     348              :                     }
     349              :                 }
     350            0 :             } else if ((SchedVal != 0.0) && (RunFlag)) {
     351              :                 // either warm up or normal
     352              :                 // check if warm up completed, depends on type of warm up control time delay or reach nominal temperature
     353            0 :                 if (thisGen.WarmUpByTimeDelay) {
     354              :                     // compare current time to when warm up is over
     355              :                     // calculate time for end of warmup period
     356            0 :                     Real64 CurrentFractionalDay = double(state.dataGlobal->DayOfSim) +
     357            0 :                                                   (int(state.dataGlobal->CurrentTime) +
     358            0 :                                                    (SysTimeElapsed + (state.dataGlobal->CurrentTime - int(state.dataGlobal->CurrentTime)))) /
     359            0 :                                                       Constant::rHoursInDay;
     360            0 :                     Real64 EndingFractionalDay = thisGen.FractionalDayofLastStartUp + thisGen.StartUpTimeDelay / Constant::rHoursInDay;
     361            0 :                     if ((std::abs(CurrentFractionalDay - EndingFractionalDay) < 0.000001) || (CurrentFractionalDay > EndingFractionalDay)) {
     362            0 :                         newOpMode = DataGenerators::OperatingMode::Normal;
     363            0 :                         PLRStartUp = true;
     364            0 :                         Real64 LastSystemTimeStepFractionalDay = CurrentFractionalDay - (TimeStepSys / Constant::rHoursInDay);
     365            0 :                         PLRforSubtimestepStartUp =
     366            0 :                             ((CurrentFractionalDay - EndingFractionalDay) / (CurrentFractionalDay - LastSystemTimeStepFractionalDay));
     367              :                     } else {
     368            0 :                         newOpMode = DataGenerators::OperatingMode::WarmUp;
     369              :                     }
     370              : 
     371            0 :                 } else if (thisGen.WarmUpByEngineTemp) {
     372              :                     // only change to normal if this is result from completed timestep, not just an interation
     373            0 :                     if (state.dataCHPElectGen->MicroCHP(GeneratorNum).A42Model.TengLast >= thisGen.TnomEngOp) {
     374            0 :                         auto const &thisMicroCHP = state.dataCHPElectGen->MicroCHP(GeneratorNum);
     375            0 :                         newOpMode = DataGenerators::OperatingMode::Normal;
     376              :                         // assume linear interpolation for PLR
     377            0 :                         PLRStartUp = true;
     378            0 :                         if ((thisMicroCHP.A42Model.Teng - thisMicroCHP.A42Model.TengLast) > 0.0) {
     379              :                             // protect divide by zero or neg
     380            0 :                             PLRforSubtimestepStartUp =
     381            0 :                                 (thisMicroCHP.A42Model.Teng - thisGen.TnomEngOp) / (thisMicroCHP.A42Model.Teng - thisMicroCHP.A42Model.TengLast);
     382              :                         } else {
     383            0 :                             PLRforSubtimestepStartUp = 1.0;
     384              :                         }
     385              :                     } else {
     386            0 :                         newOpMode = DataGenerators::OperatingMode::WarmUp;
     387              :                     }
     388              :                 } else {
     389              :                     // shouldn't come here
     390              :                     // Write(*,*) 'problem with warm up type of control logical flags'
     391              :                 }
     392              :             }
     393            0 :         } break;
     394            0 :         case DataGenerators::OperatingMode::Normal: {
     395              :             // possible Future states {CoolDown, standby, off}
     396            0 :             if (((SchedVal == 0.0) || (!RunFlag)) || (state.dataGenerator->TrialMdotcw < state.dataGenerator->LimitMinMdotcw)) {
     397              :                 // is cool down time delay longer than timestep?
     398            0 :                 if (thisGen.CoolDownDelay == 0.0) {
     399            0 :                     if (SchedVal != 0.0) {
     400            0 :                         newOpMode = DataGenerators::OperatingMode::Standby;
     401              :                     } else {
     402            0 :                         newOpMode = DataGenerators::OperatingMode::Off;
     403              :                     }
     404            0 :                 } else if (thisGen.CoolDownDelay >= TimeStepSys) {
     405            0 :                     newOpMode = DataGenerators::OperatingMode::CoolDown;
     406              :                     // also, generator just shut down so record shut down time
     407            0 :                     thisGen.FractionalDayofLastShutDown = double(state.dataGlobal->DayOfSim) +
     408            0 :                                                           (int(state.dataGlobal->CurrentTime) +
     409            0 :                                                            (SysTimeElapsed + (state.dataGlobal->CurrentTime - int(state.dataGlobal->CurrentTime)))) /
     410              :                                                               Constant::rHoursInDay;
     411              :                 } else { // cool down period is less than a single system time step
     412            0 :                     if (SchedVal != 0.0) {
     413            0 :                         newOpMode = DataGenerators::OperatingMode::Standby;
     414              :                     } else {
     415            0 :                         newOpMode = DataGenerators::OperatingMode::Off;
     416              :                     }
     417            0 :                     PLRShutDown = true;
     418            0 :                     PLRforSubtimestepShutDown = (thisGen.CoolDownDelay) / TimeStepSys;
     419              : 
     420              :                     // also, generator just shut down so record shut down time
     421            0 :                     thisGen.FractionalDayofLastShutDown = double(state.dataGlobal->DayOfSim) +
     422            0 :                                                           (int(state.dataGlobal->CurrentTime) +
     423            0 :                                                            (SysTimeElapsed + (state.dataGlobal->CurrentTime - int(state.dataGlobal->CurrentTime)))) /
     424              :                                                               Constant::rHoursInDay;
     425              :                 }
     426              :             } else {
     427              : 
     428            0 :                 newOpMode = DataGenerators::OperatingMode::Normal;
     429              :             }
     430            0 :         } break;
     431            0 :         case DataGenerators::OperatingMode::CoolDown: {
     432              :             // possible Future States {Standby, OFF, WarmUp, Normal}
     433              : 
     434            0 :             if (SchedVal == 0.0) { // no longer available.
     435              :                 // probably goes to off but could be stuck in cool down for awhile
     436            0 :                 if (thisGen.CoolDownDelay > 0.0) {
     437              :                     // calculate time for end of cool down period
     438            0 :                     Real64 CurrentFractionalDay = double(state.dataGlobal->DayOfSim) +
     439            0 :                                                   (int(state.dataGlobal->CurrentTime) +
     440            0 :                                                    (SysTimeElapsed + (state.dataGlobal->CurrentTime - int(state.dataGlobal->CurrentTime)))) /
     441            0 :                                                       Constant::rHoursInDay;
     442            0 :                     Real64 EndingFractionalDay =
     443            0 :                         thisGen.FractionalDayofLastShutDown + thisGen.CoolDownDelay / Constant::rHoursInDay - (TimeStepSys / Constant::rHoursInDay);
     444            0 :                     if ((std::abs(CurrentFractionalDay - EndingFractionalDay) < 0.000001) ||
     445              :                         (CurrentFractionalDay > EndingFractionalDay)) { // CurrentFractionalDay == EndingFractionalDay
     446            0 :                         newOpMode = DataGenerators::OperatingMode::Off;
     447            0 :                         PLRShutDown = true;
     448            0 :                         Real64 LastSystemTimeStepFractionalDay = CurrentFractionalDay - (TimeStepSys / Constant::rHoursInDay);
     449            0 :                         PLRforSubtimestepShutDown = (EndingFractionalDay - LastSystemTimeStepFractionalDay) * Constant::rHoursInDay / TimeStepSys;
     450              :                     } else { // CurrentFractionalDay > EndingFractionalDay
     451            0 :                         newOpMode = DataGenerators::OperatingMode::CoolDown;
     452              :                     }
     453              :                 } else {
     454            0 :                     newOpMode = DataGenerators::OperatingMode::Off;
     455              :                 }
     456            0 :             } else if (((SchedVal != 0.0) && (!RunFlag)) || (state.dataGenerator->TrialMdotcw < state.dataGenerator->LimitMinMdotcw)) {
     457              :                 // probably goes to standby but could be stuck in cool down for awhile
     458            0 :                 if (thisGen.CoolDownDelay > 0.0) {
     459              :                     // calculate time for end of cool down period
     460            0 :                     Real64 CurrentFractionalDay = double(state.dataGlobal->DayOfSim) +
     461            0 :                                                   (int(state.dataGlobal->CurrentTime) +
     462            0 :                                                    (SysTimeElapsed + (state.dataGlobal->CurrentTime - int(state.dataGlobal->CurrentTime)))) /
     463            0 :                                                       Constant::rHoursInDay;
     464            0 :                     Real64 EndingFractionalDay =
     465            0 :                         thisGen.FractionalDayofLastShutDown + thisGen.CoolDownDelay / Constant::rHoursInDay - (TimeStepSys / Constant::rHoursInDay);
     466            0 :                     if ((std::abs(CurrentFractionalDay - EndingFractionalDay) < 0.000001) ||
     467              :                         (CurrentFractionalDay > EndingFractionalDay)) { // CurrentFractionalDay == EndingFractionalDay
     468            0 :                         newOpMode = DataGenerators::OperatingMode::Standby;
     469            0 :                         PLRShutDown = true;
     470            0 :                         Real64 LastSystemTimeStepFractionalDay = CurrentFractionalDay - (TimeStepSys / Constant::rHoursInDay);
     471            0 :                         PLRforSubtimestepShutDown = (EndingFractionalDay - LastSystemTimeStepFractionalDay) * Constant::rHoursInDay / TimeStepSys;
     472              :                     } else { // CurrentFractionalDay < EndingFractionalDay
     473            0 :                         newOpMode = DataGenerators::OperatingMode::CoolDown;
     474              :                     }
     475              :                 } else {
     476            0 :                     newOpMode = DataGenerators::OperatingMode::Standby;
     477              :                 }
     478            0 :             } else if ((SchedVal != 0.0) && (RunFlag)) {
     479              :                 // was in cool down mode but is now being asked to restart
     480              :                 // probably goes to warm up but could be stuck in cool down or jump to normal
     481            0 :                 if (thisGen.MandatoryFullCoolDown) {
     482              :                     // is cool down done or not?
     483            0 :                     if (thisGen.CoolDownDelay > 0.0) {
     484              :                         // calculate time for end of cool down period
     485            0 :                         Real64 CurrentFractionalDay = double(state.dataGlobal->DayOfSim) +
     486            0 :                                                       (int(state.dataGlobal->CurrentTime) +
     487            0 :                                                        (SysTimeElapsed + (state.dataGlobal->CurrentTime - int(state.dataGlobal->CurrentTime)))) /
     488            0 :                                                           Constant::rHoursInDay;
     489            0 :                         Real64 EndingFractionalDay = thisGen.FractionalDayofLastShutDown + thisGen.CoolDownDelay / Constant::rHoursInDay -
     490            0 :                                                      (TimeStepSys / Constant::rHoursInDay);
     491            0 :                         if ((std::abs(CurrentFractionalDay - EndingFractionalDay) < 0.000001) ||
     492              :                             (CurrentFractionalDay < EndingFractionalDay)) { // CurrentFractionalDay == EndingFractionalDay
     493              : 
     494            0 :                             newOpMode = DataGenerators::OperatingMode::CoolDown;
     495              :                         } else { // CurrentFractionalDay > EndingFractionalDay
     496              :                             // could go to warm up or normal now
     497            0 :                             PLRShutDown = true;
     498            0 :                             Real64 LastSystemTimeStepFractionalDay = CurrentFractionalDay - (TimeStepSys / Constant::rHoursInDay);
     499            0 :                             PLRforSubtimestepShutDown = (EndingFractionalDay - LastSystemTimeStepFractionalDay) * Constant::rHoursInDay / TimeStepSys;
     500            0 :                             if (thisGen.StartUpTimeDelay == 0.0) {
     501            0 :                                 newOpMode = DataGenerators::OperatingMode::Normal;
     502              :                                 // possible PLR on start up.
     503            0 :                                 PLRStartUp = true;
     504            0 :                                 PLRforSubtimestepStartUp =
     505            0 :                                     ((CurrentFractionalDay - EndingFractionalDay) / (CurrentFractionalDay - LastSystemTimeStepFractionalDay));
     506              : 
     507            0 :                             } else if (thisGen.StartUpTimeDelay > 0.0) {
     508              :                                 // is remaining time enough?
     509            0 :                                 if ((CurrentFractionalDay - EndingFractionalDay) > thisGen.StartUpTimeDelay) {
     510            0 :                                     newOpMode = DataGenerators::OperatingMode::Normal;
     511              :                                     // possible PLR on start up.
     512            0 :                                     PLRStartUp = true;
     513            0 :                                     PLRforSubtimestepStartUp =
     514            0 :                                         ((CurrentFractionalDay - EndingFractionalDay) / (CurrentFractionalDay - LastSystemTimeStepFractionalDay));
     515              :                                 } else {
     516            0 :                                     newOpMode = DataGenerators::OperatingMode::WarmUp;
     517              :                                     // generator just started so set start time
     518            0 :                                     thisGen.FractionalDayofLastStartUp =
     519            0 :                                         double(state.dataGlobal->DayOfSim) +
     520            0 :                                         (int(state.dataGlobal->CurrentTime) +
     521            0 :                                          (SysTimeElapsed + (state.dataGlobal->CurrentTime - int(state.dataGlobal->CurrentTime) - TimeStepSys))) /
     522              :                                             Constant::rHoursInDay;
     523              :                                 }
     524              :                             }
     525              :                         }
     526              :                     } else {
     527              : 
     528            0 :                         newOpMode = DataGenerators::OperatingMode::Standby;
     529              :                     }
     530              :                 } else { // not mandatory cool down
     531              :                     // likely to go into warm up but if no warm up then back to normal
     532            0 :                     if (thisGen.WarmUpByTimeDelay) {
     533            0 :                         if (thisGen.StartUpTimeDelay == 0.0) {
     534            0 :                             newOpMode = DataGenerators::OperatingMode::Normal;
     535              : 
     536            0 :                         } else if (thisGen.StartUpTimeDelay > 0.0) {
     537            0 :                             Real64 CurrentFractionalDay = double(state.dataGlobal->DayOfSim) +
     538            0 :                                                           (int(state.dataGlobal->CurrentTime) +
     539            0 :                                                            (SysTimeElapsed + (state.dataGlobal->CurrentTime - int(state.dataGlobal->CurrentTime)))) /
     540            0 :                                                               Constant::rHoursInDay;
     541            0 :                             Real64 EndingFractionalDay = thisGen.FractionalDayofLastShutDown + thisGen.CoolDownDelay / Constant::rHoursInDay;
     542            0 :                             if ((std::abs(CurrentFractionalDay - EndingFractionalDay) < 0.000001) ||
     543              :                                 (CurrentFractionalDay > EndingFractionalDay)) { // CurrentFractionalDay == EndingFractionalDay
     544            0 :                                 newOpMode = DataGenerators::OperatingMode::Normal;
     545              :                                 // possible PLR on start up.
     546            0 :                                 PLRStartUp = true;
     547            0 :                                 Real64 LastSystemTimeStepFractionalDay = CurrentFractionalDay - (TimeStepSys / Constant::rHoursInDay);
     548            0 :                                 PLRforSubtimestepStartUp =
     549            0 :                                     ((CurrentFractionalDay - EndingFractionalDay) / (CurrentFractionalDay - LastSystemTimeStepFractionalDay));
     550              :                             } else {
     551            0 :                                 newOpMode = DataGenerators::OperatingMode::WarmUp;
     552              :                                 // set start up time
     553              :                                 // generator just started so set start time
     554            0 :                                 thisGen.FractionalDayofLastStartUp =
     555            0 :                                     double(state.dataGlobal->DayOfSim) +
     556            0 :                                     (int(state.dataGlobal->CurrentTime) +
     557            0 :                                      (SysTimeElapsed + (state.dataGlobal->CurrentTime - int(state.dataGlobal->CurrentTime) - TimeStepSys))) /
     558              :                                         Constant::rHoursInDay;
     559              :                             }
     560              :                         }
     561              :                     }
     562              :                 }
     563              :             }
     564            0 :         } break;
     565            0 :         default:
     566            0 :             break;
     567              :         } // previous case
     568              : 
     569            0 :         if (PLRforSubtimestepStartUp < 0.0) PLRforSubtimestepStartUp = 0.0;
     570            0 :         if (PLRforSubtimestepStartUp > 1.0) PLRforSubtimestepStartUp = 1.0;
     571              : 
     572            0 :         if (PLRforSubtimestepShutDown < 0.0) PLRforSubtimestepShutDown = 0.0;
     573            0 :         if (PLRforSubtimestepShutDown > 1.0) PLRforSubtimestepShutDown = 1.0;
     574              : 
     575            0 :         if (newOpMode == DataGenerators::OperatingMode::WarmUp) {
     576            0 :             Pel = PelInput * PLRforSubtimestepStartUp;
     577              :         }
     578              : 
     579            0 :         if (newOpMode == DataGenerators::OperatingMode::Normal) {
     580              :             // correct if switched to normal at sub timestep
     581            0 :             Pel *= PLRforSubtimestepStartUp;
     582              :             // unit may have constraints from transient limits or operating ranges.
     583            0 :             if (Pel > thisGen.PelLastTimeStep) { // powering up
     584            0 :                 Real64 MaxPel = thisGen.PelLastTimeStep + thisGen.UpTranLimit * TimeStepSysSec;
     585            0 :                 if (MaxPel < Pel) {
     586            0 :                     Pel = MaxPel;
     587              :                 }
     588            0 :             } else if (Pel < thisGen.PelLastTimeStep) { // powering down
     589            0 :                 Real64 MinPel = thisGen.PelLastTimeStep - thisGen.DownTranLimit * TimeStepSysSec;
     590            0 :                 if (Pel < MinPel) {
     591            0 :                     Pel = MinPel;
     592              :                 }
     593              :             }
     594              :         }
     595              : 
     596            0 :         if (newOpMode == DataGenerators::OperatingMode::CoolDown) {
     597            0 :             Pel = 0.0; // assumes no power generated during shut down
     598              :         }
     599              : 
     600            0 :         if (newOpMode == DataGenerators::OperatingMode::Off) {
     601            0 :             Pel = 0.0; // assumes no power generated during OFF mode
     602              :         }
     603              : 
     604            0 :         if (newOpMode == DataGenerators::OperatingMode::Standby) {
     605            0 :             Pel = 0.0; // assumes no power generated during standby mode
     606              :         }
     607              : 
     608              :         // Control step 3: adjust for max and min limits on Pel
     609              : 
     610            0 :         if (Pel < thisGen.PelMin) {
     611            0 :             Pel = thisGen.PelMin;
     612              :         }
     613            0 :         if (Pel > thisGen.PelMax) {
     614            0 :             Pel = thisGen.PelMax;
     615              :         }
     616              : 
     617            0 :         auto &thisMicroCHP = state.dataCHPElectGen->MicroCHP(GeneratorNum);
     618              :         // now do record keeping for amount of time spent in various operating modes
     619              :         // first clear out values
     620            0 :         thisMicroCHP.A42Model.OffModeTime = 0.0;
     621            0 :         thisMicroCHP.A42Model.StandyByModeTime = 0.0;
     622            0 :         thisMicroCHP.A42Model.WarmUpModeTime = 0.0;
     623            0 :         thisMicroCHP.A42Model.NormalModeTime = 0.0;
     624            0 :         thisMicroCHP.A42Model.CoolDownModeTime = 0.0;
     625            0 :         switch (newOpMode) {
     626            0 :         case DataGenerators::OperatingMode::Off: {
     627            0 :             if (PLRforSubtimestepShutDown == 0.0) {
     628            0 :                 thisMicroCHP.A42Model.OffModeTime = TimeStepSysSec;
     629            0 :             } else if ((PLRforSubtimestepShutDown > 0.0) && (PLRforSubtimestepShutDown < 1.0)) {
     630            0 :                 thisMicroCHP.A42Model.CoolDownModeTime = TimeStepSysSec * (PLRforSubtimestepShutDown);
     631            0 :                 thisMicroCHP.A42Model.OffModeTime = TimeStepSysSec * (1.0 - PLRforSubtimestepShutDown);
     632              :             } else {
     633            0 :                 thisMicroCHP.A42Model.OffModeTime = TimeStepSysSec;
     634              :             }
     635            0 :         } break;
     636            0 :         case DataGenerators::OperatingMode::Standby: {
     637            0 :             if (PLRforSubtimestepShutDown == 0.0) {
     638            0 :                 thisMicroCHP.A42Model.StandyByModeTime = TimeStepSysSec;
     639            0 :             } else if ((PLRforSubtimestepShutDown > 0.0) && (PLRforSubtimestepShutDown < 1.0)) {
     640            0 :                 thisMicroCHP.A42Model.CoolDownModeTime = TimeStepSysSec * (PLRforSubtimestepShutDown);
     641            0 :                 thisMicroCHP.A42Model.StandyByModeTime = TimeStepSysSec * (1.0 - PLRforSubtimestepShutDown);
     642              :             } else {
     643            0 :                 thisMicroCHP.A42Model.StandyByModeTime = TimeStepSysSec;
     644              :             }
     645            0 :         } break;
     646            0 :         case DataGenerators::OperatingMode::WarmUp: {
     647            0 :             if (PLRforSubtimestepShutDown == 0.0) {
     648            0 :                 thisMicroCHP.A42Model.WarmUpModeTime = TimeStepSysSec;
     649            0 :             } else if ((PLRforSubtimestepShutDown > 0.0) && (PLRforSubtimestepShutDown < 1.0)) {
     650            0 :                 thisMicroCHP.A42Model.CoolDownModeTime = TimeStepSysSec * (PLRforSubtimestepShutDown);
     651            0 :                 thisMicroCHP.A42Model.WarmUpModeTime = TimeStepSysSec * (1.0 - PLRforSubtimestepShutDown);
     652              :             } else {
     653            0 :                 thisMicroCHP.A42Model.WarmUpModeTime = TimeStepSysSec;
     654              :             }
     655            0 :         } break;
     656            0 :         case DataGenerators::OperatingMode::Normal: {
     657            0 :             if (PLRforSubtimestepStartUp == 0.0) {
     658            0 :                 thisMicroCHP.A42Model.WarmUpModeTime = TimeStepSysSec;
     659              : 
     660            0 :             } else if ((PLRforSubtimestepStartUp > 0.0) && (PLRforSubtimestepStartUp < 1.0)) {
     661            0 :                 thisMicroCHP.A42Model.WarmUpModeTime = TimeStepSysSec * (1.0 - PLRforSubtimestepStartUp);
     662            0 :                 thisMicroCHP.A42Model.NormalModeTime = TimeStepSysSec * (PLRforSubtimestepStartUp);
     663              :             } else {
     664            0 :                 if (PLRforSubtimestepShutDown == 0.0) {
     665            0 :                     thisMicroCHP.A42Model.NormalModeTime = TimeStepSysSec;
     666            0 :                 } else if ((PLRforSubtimestepShutDown > 0.0) && (PLRforSubtimestepShutDown < 1.0)) {
     667            0 :                     thisMicroCHP.A42Model.CoolDownModeTime = TimeStepSysSec * (PLRforSubtimestepShutDown);
     668            0 :                     thisMicroCHP.A42Model.NormalModeTime = TimeStepSysSec * (1.0 - PLRforSubtimestepShutDown);
     669              :                 } else {
     670            0 :                     thisMicroCHP.A42Model.NormalModeTime = TimeStepSysSec;
     671              :                 }
     672              :             }
     673            0 :         } break;
     674            0 :         case DataGenerators::OperatingMode::CoolDown: {
     675            0 :             thisMicroCHP.A42Model.CoolDownModeTime = TimeStepSysSec;
     676            0 :         } break;
     677            0 :         default:
     678            0 :             break;
     679              :         }
     680              : 
     681            0 :         ElecLoadProvided = Pel;
     682              : 
     683            0 :         thisGen.CurrentOpMode = newOpMode;
     684            0 :         OperatingMode = newOpMode;
     685            0 :     }
     686              : 
     687            0 :     void ManageGeneratorFuelFlow(EnergyPlusData &state,
     688              :                                  int const GeneratorNum,          // Generator number
     689              :                                  Real64 const FuelFlowRequest,    // Generator demand mdot kg/ s
     690              :                                  Real64 &FuelFlowProvided,        // allowed after constraints kg/s
     691              :                                  bool &ConstrainedIncreasingMdot, // true if request was altered because of fuel rate of change up
     692              :                                  bool &ConstrainedDecreasingMdot  // true if request was altered because of fuel rate of change down
     693              :     )
     694              :     {
     695              : 
     696              :         // SUBROUTINE INFORMATION:
     697              :         //       AUTHOR         B. Griffith
     698              :         //       DATE WRITTEN   July 2006
     699              : 
     700              :         // PURPOSE OF THIS SUBROUTINE:
     701              :         // check if change in fuel flow rate is okay
     702              : 
     703              :         // Using/Aliasing
     704            0 :         Real64 const TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
     705              : 
     706            0 :         ConstrainedIncreasingMdot = false;
     707            0 :         ConstrainedDecreasingMdot = false;
     708            0 :         Real64 MdotFuel = FuelFlowRequest;
     709              : 
     710              :         // get index from GeneratorNum
     711            0 :         int DynaCntrlNum = state.dataCHPElectGen->MicroCHP(GeneratorNum).DynamicsControlID;
     712            0 :         auto const &thisGen = state.dataGenerator->GeneratorDynamics(DynaCntrlNum);
     713              : 
     714            0 :         if (FuelFlowRequest > thisGen.FuelMdotLastTimestep) { // fuel flow is up
     715            0 :             Real64 MaxMdot = thisGen.FuelMdotLastTimestep + thisGen.UpTranLimitFuel * TimeStepSysSec;
     716            0 :             if (MaxMdot < FuelFlowRequest) {
     717            0 :                 MdotFuel = MaxMdot;
     718            0 :                 ConstrainedIncreasingMdot = true;
     719              :             }
     720              : 
     721            0 :         } else if (FuelFlowRequest < thisGen.FuelMdotLastTimestep) { // fuel flow is down
     722            0 :             Real64 MinMdot = thisGen.FuelMdotLastTimestep - thisGen.DownTranLimitFuel * TimeStepSysSec;
     723            0 :             if (FuelFlowRequest < MinMdot) {
     724            0 :                 MdotFuel = MinMdot;
     725            0 :                 ConstrainedDecreasingMdot = true;
     726              :             }
     727              :         } else {
     728              :             // do nothing
     729              :         }
     730              : 
     731            0 :         FuelFlowProvided = MdotFuel;
     732            0 :     }
     733              : 
     734            0 :     Real64 FuncDetermineCWMdotForInternalFlowControl(EnergyPlusData &state,
     735              :                                                      int const GeneratorNum, // ID of generator
     736              :                                                      Real64 const Pnetss,    // power net steady state
     737              :                                                      Real64 const TcwIn      // temperature of cooling water at inlet
     738              :     )
     739              :     {
     740              : 
     741              :         // FUNCTION INFORMATION:
     742              :         //       AUTHOR         B. Griffith
     743              :         //       DATE WRITTEN   Dec 2009
     744              :         //       RE-ENGINEERED  B. Griffith, Sept 2010, plant upgrade
     745              : 
     746              :         // PURPOSE OF THIS FUNCTION:
     747              :         // common place to figure flow rates with internal flow control
     748              : 
     749              :         // METHODOLOGY EMPLOYED:
     750              :         // apply constraints imposed by plant according to flow lock, first HVAC iteration etc.
     751              : 
     752              :         // Return value
     753              :         Real64 FuncDetermineCWMdotForInternalFlowControl;
     754            0 :         auto const &thisMicroCHP = state.dataCHPElectGen->MicroCHP(GeneratorNum);
     755            0 :         int const InletNode = thisMicroCHP.PlantInletNodeID;
     756            0 :         int const OutletNode = thisMicroCHP.PlantOutletNodeID;
     757              : 
     758              :         // first evaluate curve
     759            0 :         Real64 MdotCW = thisMicroCHP.A42Model.WaterFlowCurve->value(state, Pnetss, TcwIn);
     760              : 
     761              :         // now apply constraints
     762            0 :         MdotCW = max(0.0, MdotCW);
     763              : 
     764              :         // make sure plant can provide, utility call may change flow
     765            0 :         if (thisMicroCHP.CWPlantLoc.loopNum > 0) { // protect early calls
     766            0 :             PlantUtilities::SetComponentFlowRate(state, MdotCW, InletNode, OutletNode, thisMicroCHP.CWPlantLoc);
     767              :         }
     768              : 
     769            0 :         FuncDetermineCWMdotForInternalFlowControl = MdotCW;
     770            0 :         return FuncDetermineCWMdotForInternalFlowControl;
     771              :     }
     772              : 
     773              : } // namespace GeneratorDynamicsManager
     774              : 
     775              : } // namespace EnergyPlus
        

Generated by: LCOV version 2.0-1