LCOV - code coverage report
Current view: top level - EnergyPlus - GeneratorDynamicsManager.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 169 355 47.6 %
Date: 2024-08-24 18:31:18 Functions: 4 4 100.0 %

          Line data    Source code
       1             : // EnergyPlus, Copyright (c) 1996-2024, The Board of Trustees of the University of Illinois,
       2             : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3             : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4             : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5             : // contributors. All rights reserved.
       6             : //
       7             : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8             : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9             : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10             : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11             : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12             : //
      13             : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14             : // provided that the following conditions are met:
      15             : //
      16             : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17             : //     conditions and the following disclaimer.
      18             : //
      19             : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20             : //     conditions and the following disclaimer in the documentation and/or other materials
      21             : //     provided with the distribution.
      22             : //
      23             : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24             : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25             : //     used to endorse or promote products derived from this software without specific prior
      26             : //     written permission.
      27             : //
      28             : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29             : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30             : //     reference solely to the software portion of its product, Licensee must refer to the
      31             : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32             : //     obtained under this License and may not use a different name for the software. Except as
      33             : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34             : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35             : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36             : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37             : //
      38             : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39             : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40             : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41             : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42             : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43             : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44             : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45             : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46             : // POSSIBILITY OF SUCH DAMAGE.
      47             : 
      48             : // C++ Headers
      49             : #include <cmath>
      50             : 
      51             : // ObjexxFCL Headers
      52             : #include <ObjexxFCL/Array.functions.hh>
      53             : #include <ObjexxFCL/Fmath.hh>
      54             : 
      55             : // EnergyPlus Headers
      56             : #include <EnergyPlus/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          10 :     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          10 :         int const NumGensWDynamics = state.dataCHPElectGen->NumMicroCHPs; // TODO  + NumFuelCellCGenerators
     105             : 
     106          10 :         if (!allocated(state.dataGenerator->GeneratorDynamics)) {
     107           2 :             state.dataGenerator->GeneratorDynamics.allocate(NumGensWDynamics);
     108             :         }
     109             : 
     110             :         // first populate with Micro CHP data
     111          10 :         auto &thisGen = state.dataGenerator->GeneratorDynamics(GenNum);
     112          10 :         auto &thisMicroCHP = state.dataCHPElectGen->MicroCHP(GenNum);
     113          10 :         thisGen.Name = thisMicroCHP.Name;
     114          10 :         thisGen.PelMin = thisMicroCHP.A42Model.MinElecPower;
     115          10 :         thisGen.PelMax = thisMicroCHP.A42Model.MaxElecPower;
     116          10 :         thisGen.UpTranLimit = thisMicroCHP.A42Model.DeltaPelMax;
     117          10 :         thisGen.DownTranLimit = thisMicroCHP.A42Model.DeltaPelMax;
     118          10 :         thisGen.UpTranLimitFuel = thisMicroCHP.A42Model.DeltaFuelMdotMax;
     119          10 :         thisGen.DownTranLimitFuel = thisMicroCHP.A42Model.DeltaFuelMdotMax;
     120          10 :         thisGen.WarmUpByTimeDelay = thisMicroCHP.A42Model.WarmUpByTimeDelay;
     121          10 :         thisGen.WarmUpByEngineTemp = thisMicroCHP.A42Model.WarmUpByEngineTemp;
     122          10 :         thisGen.MandatoryFullCoolDown = thisMicroCHP.A42Model.MandatoryFullCoolDown;
     123          10 :         thisGen.WarmRestartOkay = thisMicroCHP.A42Model.WarmRestartOkay;
     124          10 :         thisGen.WarmUpDelay = thisMicroCHP.A42Model.WarmUpDelay;
     125          10 :         thisGen.CoolDownDelay = thisMicroCHP.A42Model.CoolDownDelay / Constant::SecInHour; // seconds to hours
     126          10 :         thisGen.PcoolDown = thisMicroCHP.A42Model.PcoolDown;
     127          10 :         thisGen.Pstandby = thisMicroCHP.A42Model.Pstandby;
     128          10 :         thisGen.MCeng = thisMicroCHP.A42Model.MCeng;
     129          10 :         thisGen.MCcw = thisMicroCHP.A42Model.MCcw;
     130          10 :         thisGen.kf = thisMicroCHP.A42Model.kf;
     131          10 :         thisGen.TnomEngOp = thisMicroCHP.A42Model.TnomEngOp;
     132          10 :         thisGen.kp = thisMicroCHP.A42Model.kp;
     133          10 :         thisGen.AvailabilitySchedID = thisMicroCHP.AvailabilitySchedID;
     134          10 :         thisGen.StartUpTimeDelay = thisMicroCHP.A42Model.WarmUpDelay / Constant::SecInHour; // seconds to hours
     135             : 
     136          10 :         thisGen.ElectEffNom = thisMicroCHP.A42Model.ElecEff;
     137          10 :         thisGen.ThermEffNom = thisMicroCHP.A42Model.ThermEff;
     138          10 :         thisGen.QdotHXMax = thisMicroCHP.A42Model.ThermEff * thisMicroCHP.A42Model.MaxElecPower / thisMicroCHP.A42Model.ElecEff;
     139          10 :         thisGen.QdotHXMin = thisMicroCHP.A42Model.ThermEff * thisMicroCHP.A42Model.MinElecPower / thisMicroCHP.A42Model.ElecEff;
     140          10 :         thisGen.QdotHXOpt = thisGen.QdotHXMax;
     141          10 :         thisMicroCHP.DynamicsControlID = GenNum;
     142          10 :     }
     143             : 
     144       15328 :     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 occuring 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       15328 :         Real64 const SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
     208       15328 :         Real64 const TimeStepSys = state.dataHVACGlobal->TimeStepSys;
     209       15328 :         Real64 const TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
     210             : 
     211             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     212             :         bool RunFlag; // true if generator supposed to run
     213       15328 :         DataGenerators::OperatingMode newOpMode(DataGenerators::OperatingMode::Invalid);
     214             : 
     215             :         // inits
     216       15328 :         PLRforSubtimestepStartUp = 1.0;
     217       15328 :         PLRforSubtimestepShutDown = 0.0;
     218       15328 :         bool PLRStartUp = false; // true if subtimestep issue involving startup
     219       15328 :         bool PLRShutDown = false;
     220       15328 :         state.dataGenerator->InternalFlowControl = false;
     221             : 
     222             :         // get index for this generator in dynamics control structure
     223       15328 :         int DynaCntrlNum = state.dataCHPElectGen->MicroCHP(GeneratorNum).DynamicsControlID;
     224             :         // OutletCWnode = MicroCHPElectricGenerator::MicroCHP(GeneratorNum)%PlantOutletNodeID
     225       15328 :         state.dataGenerator->InletCWnode = state.dataCHPElectGen->MicroCHP(GeneratorNum).PlantInletNodeID;
     226       15328 :         state.dataGenerator->TcwIn = state.dataLoopNodes->Node(state.dataCHPElectGen->MicroCHP(GeneratorNum).PlantInletNodeID).Temp;
     227       15328 :         if (state.dataCHPElectGen->MicroCHP(GeneratorNum).A42Model.InternalFlowControl) {
     228        9194 :             state.dataGenerator->InternalFlowControl = true;
     229             :         }
     230       15328 :         state.dataGenerator->LimitMinMdotcw = state.dataCHPElectGen->MicroCHP(GeneratorNum).A42Model.MinWaterMdot;
     231             : 
     232       15328 :         auto &thisGen = state.dataGenerator->GeneratorDynamics(DynaCntrlNum);
     233       15328 :         Real64 PelInput = ElecLoadRequest; // holds initial value of IN var
     234       15328 :         Real64 ElectLoadForThermalRequest = 0.0;
     235       15328 :         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       15328 :         if ((RunFlagElectCenter) || (RunFlagPlant)) {
     242        5144 :             RunFlag = true;
     243             :         } else {
     244       10184 :             RunFlag = false;
     245             :         }
     246             : 
     247             :         // check availability schedule
     248       15328 :         Real64 SchedVal = ScheduleManager::GetCurrentScheduleValue(state, thisGen.AvailabilitySchedID);
     249       15328 :         Real64 Pel = PelInput;
     250             : 
     251             :         // get data to check if sufficient flow available from Plant
     252       15328 :         if (state.dataGenerator->InternalFlowControl && (SchedVal > 0.0)) {
     253        9194 :             state.dataGenerator->TrialMdotcw = FuncDetermineCWMdotForInternalFlowControl(state, GeneratorNum, Pel, state.dataGenerator->TcwIn);
     254             :         } else {
     255        6134 :             state.dataGenerator->TrialMdotcw = state.dataLoopNodes->Node(state.dataGenerator->InletCWnode).MassFlowRate;
     256             :         }
     257             : 
     258             :         // determine current operating mode.
     259       15328 :         switch (thisGen.LastOpMode) {
     260       10546 :         case DataGenerators::OperatingMode::Off:
     261             :         case DataGenerators::OperatingMode::Standby: {
     262             :             // possible future states {Off, Standby, WarmUp,Normal }
     263       10546 :             if (SchedVal == 0.0) {
     264        5588 :                 newOpMode = DataGenerators::OperatingMode::Off;
     265             : 
     266        4958 :             } else if (((SchedVal != 0.0) && (!RunFlag)) || (state.dataGenerator->TrialMdotcw < state.dataGenerator->LimitMinMdotcw)) {
     267        3420 :                 newOpMode = DataGenerators::OperatingMode::Standby;
     268        1538 :             } else if ((SchedVal != 0.0) && (RunFlag)) {
     269             : 
     270        1538 :                 if (thisGen.WarmUpByTimeDelay) {
     271             : 
     272        1538 :                     if (thisGen.StartUpTimeDelay == 0.0) {
     273          42 :                         newOpMode = DataGenerators::OperatingMode::Normal;
     274             : 
     275             :                         // is startUp time delay longer than timestep?
     276        1496 :                     } 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::HoursInDay;
     284             : 
     285             :                     } else { // warm up period is less than a single system time step
     286        1496 :                         newOpMode = DataGenerators::OperatingMode::Normal;
     287        1496 :                         PLRStartUp = true;
     288        1496 :                         PLRforSubtimestepStartUp = (TimeStepSys - thisGen.StartUpTimeDelay) / TimeStepSys;
     289             :                     }
     290             :                 }
     291        1538 :                 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       10546 :         } 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::HoursInDay;
     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::HoursInDay;
     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::HoursInDay;
     360           0 :                     Real64 EndingFractionalDay = thisGen.FractionalDayofLastStartUp + thisGen.StartUpTimeDelay / Constant::HoursInDay;
     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::HoursInDay);
     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        4782 :         case DataGenerators::OperatingMode::Normal: {
     395             :             // possible Future states {CoolDown, standby, off}
     396        4782 :             if (((SchedVal == 0.0) || (!RunFlag)) || (state.dataGenerator->TrialMdotcw < state.dataGenerator->LimitMinMdotcw)) {
     397             :                 // is cool down time delay longer than timestep?
     398        1176 :                 if (thisGen.CoolDownDelay == 0.0) {
     399          42 :                     if (SchedVal != 0.0) {
     400           0 :                         newOpMode = DataGenerators::OperatingMode::Standby;
     401             :                     } else {
     402          42 :                         newOpMode = DataGenerators::OperatingMode::Off;
     403             :                     }
     404        1134 :                 } 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::HoursInDay;
     411             :                 } else { // cool down period is less than a single system time step
     412        1134 :                     if (SchedVal != 0.0) {
     413        1134 :                         newOpMode = DataGenerators::OperatingMode::Standby;
     414             :                     } else {
     415           0 :                         newOpMode = DataGenerators::OperatingMode::Off;
     416             :                     }
     417        1134 :                     PLRShutDown = true;
     418        1134 :                     PLRforSubtimestepShutDown = (thisGen.CoolDownDelay) / TimeStepSys;
     419             : 
     420             :                     // also, generator just shut down so record shut down time
     421        1134 :                     thisGen.FractionalDayofLastShutDown = double(state.dataGlobal->DayOfSim) +
     422        1134 :                                                           (int(state.dataGlobal->CurrentTime) +
     423        1134 :                                                            (SysTimeElapsed + (state.dataGlobal->CurrentTime - int(state.dataGlobal->CurrentTime)))) /
     424             :                                                               Constant::HoursInDay;
     425             :                 }
     426             :             } else {
     427             : 
     428        3606 :                 newOpMode = DataGenerators::OperatingMode::Normal;
     429             :             }
     430        4782 :         } 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::HoursInDay;
     442           0 :                     Real64 EndingFractionalDay =
     443           0 :                         thisGen.FractionalDayofLastShutDown + thisGen.CoolDownDelay / Constant::HoursInDay - (TimeStepSys / Constant::HoursInDay);
     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::HoursInDay);
     449           0 :                         PLRforSubtimestepShutDown = (EndingFractionalDay - LastSystemTimeStepFractionalDay) * Constant::HoursInDay / 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::HoursInDay;
     464           0 :                     Real64 EndingFractionalDay =
     465           0 :                         thisGen.FractionalDayofLastShutDown + thisGen.CoolDownDelay / Constant::HoursInDay - (TimeStepSys / Constant::HoursInDay);
     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::HoursInDay);
     471           0 :                         PLRforSubtimestepShutDown = (EndingFractionalDay - LastSystemTimeStepFractionalDay) * Constant::HoursInDay / 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::HoursInDay;
     489           0 :                         Real64 EndingFractionalDay =
     490           0 :                             thisGen.FractionalDayofLastShutDown + thisGen.CoolDownDelay / Constant::HoursInDay - (TimeStepSys / Constant::HoursInDay);
     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::HoursInDay);
     499           0 :                             PLRforSubtimestepShutDown = (EndingFractionalDay - LastSystemTimeStepFractionalDay) * Constant::HoursInDay / 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::HoursInDay;
     523             :                                 }
     524             :                             }
     525             :                         }
     526             :                     } else {
     527             : 
     528           0 :                         newOpMode = DataGenerators::OperatingMode::Standby;
     529             :                     }
     530             :                 } else { // not mandetory cool donw
     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::HoursInDay;
     541           0 :                             Real64 EndingFractionalDay = thisGen.FractionalDayofLastShutDown + thisGen.CoolDownDelay / Constant::HoursInDay;
     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::HoursInDay);
     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::HoursInDay;
     559             :                             }
     560             :                         }
     561             :                     }
     562             :                 }
     563             :             }
     564           0 :         } break;
     565           0 :         default:
     566           0 :             break;
     567             :         } // previous case
     568             : 
     569       15328 :         if (PLRforSubtimestepStartUp < 0.0) PLRforSubtimestepStartUp = 0.0;
     570       15328 :         if (PLRforSubtimestepStartUp > 1.0) PLRforSubtimestepStartUp = 1.0;
     571             : 
     572       15328 :         if (PLRforSubtimestepShutDown < 0.0) PLRforSubtimestepShutDown = 0.0;
     573       15328 :         if (PLRforSubtimestepShutDown > 1.0) PLRforSubtimestepShutDown = 1.0;
     574             : 
     575       15328 :         if (newOpMode == DataGenerators::OperatingMode::WarmUp) {
     576           0 :             Pel = PelInput * PLRforSubtimestepStartUp;
     577             :         }
     578             : 
     579       15328 :         if (newOpMode == DataGenerators::OperatingMode::Normal) {
     580             :             // correct if switched to normal at sub timestep
     581        5144 :             Pel *= PLRforSubtimestepStartUp;
     582             :             // unit may have constraints from transient limits or operating ranges.
     583        5144 :             if (Pel > thisGen.PelLastTimeStep) { // powering up
     584        3028 :                 Real64 MaxPel = thisGen.PelLastTimeStep + thisGen.UpTranLimit * TimeStepSysSec;
     585        3028 :                 if (MaxPel < Pel) {
     586           0 :                     Pel = MaxPel;
     587             :                 }
     588        2116 :             } else if (Pel < thisGen.PelLastTimeStep) { // powering down
     589         609 :                 Real64 MinPel = thisGen.PelLastTimeStep - thisGen.DownTranLimit * TimeStepSysSec;
     590         609 :                 if (Pel < MinPel) {
     591           0 :                     Pel = MinPel;
     592             :                 }
     593             :             }
     594             :         }
     595             : 
     596       15328 :         if (newOpMode == DataGenerators::OperatingMode::CoolDown) {
     597           0 :             Pel = 0.0; // assumes no power generated during shut down
     598             :         }
     599             : 
     600       15328 :         if (newOpMode == DataGenerators::OperatingMode::Off) {
     601        5630 :             Pel = 0.0; // assumes no power generated during OFF mode
     602             :         }
     603             : 
     604       15328 :         if (newOpMode == DataGenerators::OperatingMode::Standby) {
     605        4554 :             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       15328 :         if (Pel < thisGen.PelMin) {
     611           0 :             Pel = thisGen.PelMin;
     612             :         }
     613       15328 :         if (Pel > thisGen.PelMax) {
     614           0 :             Pel = thisGen.PelMax;
     615             :         }
     616             : 
     617       15328 :         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       15328 :         thisMicroCHP.A42Model.OffModeTime = 0.0;
     621       15328 :         thisMicroCHP.A42Model.StandyByModeTime = 0.0;
     622       15328 :         thisMicroCHP.A42Model.WarmUpModeTime = 0.0;
     623       15328 :         thisMicroCHP.A42Model.NormalModeTime = 0.0;
     624       15328 :         thisMicroCHP.A42Model.CoolDownModeTime = 0.0;
     625       15328 :         switch (newOpMode) {
     626        5630 :         case DataGenerators::OperatingMode::Off: {
     627        5630 :             if (PLRforSubtimestepShutDown == 0.0) {
     628        5630 :                 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        5630 :         } break;
     636        4554 :         case DataGenerators::OperatingMode::Standby: {
     637        4554 :             if (PLRforSubtimestepShutDown == 0.0) {
     638        3420 :                 thisMicroCHP.A42Model.StandyByModeTime = TimeStepSysSec;
     639        1134 :             } else if ((PLRforSubtimestepShutDown > 0.0) && (PLRforSubtimestepShutDown < 1.0)) {
     640        1134 :                 thisMicroCHP.A42Model.CoolDownModeTime = TimeStepSysSec * (PLRforSubtimestepShutDown);
     641        1134 :                 thisMicroCHP.A42Model.StandyByModeTime = TimeStepSysSec * (1.0 - PLRforSubtimestepShutDown);
     642             :             } else {
     643           0 :                 thisMicroCHP.A42Model.StandyByModeTime = TimeStepSysSec;
     644             :             }
     645        4554 :         } 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        5144 :         case DataGenerators::OperatingMode::Normal: {
     657        5144 :             if (PLRforSubtimestepStartUp == 0.0) {
     658           0 :                 thisMicroCHP.A42Model.WarmUpModeTime = TimeStepSysSec;
     659             : 
     660        5144 :             } else if ((PLRforSubtimestepStartUp > 0.0) && (PLRforSubtimestepStartUp < 1.0)) {
     661        1496 :                 thisMicroCHP.A42Model.WarmUpModeTime = TimeStepSysSec * (1.0 - PLRforSubtimestepStartUp);
     662        1496 :                 thisMicroCHP.A42Model.NormalModeTime = TimeStepSysSec * (PLRforSubtimestepStartUp);
     663             :             } else {
     664        3648 :                 if (PLRforSubtimestepShutDown == 0.0) {
     665        3648 :                     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        5144 :         } 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       15328 :         ElecLoadProvided = Pel;
     682             : 
     683       15328 :         thisGen.CurrentOpMode = newOpMode;
     684       15328 :         OperatingMode = newOpMode;
     685       15328 :     }
     686             : 
     687        5144 :     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        5144 :         Real64 const TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
     705             : 
     706        5144 :         ConstrainedIncreasingMdot = false;
     707        5144 :         ConstrainedDecreasingMdot = false;
     708        5144 :         Real64 MdotFuel = FuelFlowRequest;
     709             : 
     710             :         // get index from GeneratorNum
     711        5144 :         int DynaCntrlNum = state.dataCHPElectGen->MicroCHP(GeneratorNum).DynamicsControlID;
     712        5144 :         auto const &thisGen = state.dataGenerator->GeneratorDynamics(DynaCntrlNum);
     713             : 
     714        5144 :         if (FuelFlowRequest > thisGen.FuelMdotLastTimestep) { // fuel flow is up
     715        1736 :             Real64 MaxMdot = thisGen.FuelMdotLastTimestep + thisGen.UpTranLimitFuel * TimeStepSysSec;
     716        1736 :             if (MaxMdot < FuelFlowRequest) {
     717           0 :                 MdotFuel = MaxMdot;
     718           0 :                 ConstrainedIncreasingMdot = true;
     719             :             }
     720             : 
     721        3408 :         } else if (FuelFlowRequest < thisGen.FuelMdotLastTimestep) { // fuel flow is down
     722         613 :             Real64 MinMdot = thisGen.FuelMdotLastTimestep - thisGen.DownTranLimitFuel * TimeStepSysSec;
     723         613 :             if (FuelFlowRequest < MinMdot) {
     724           0 :                 MdotFuel = MinMdot;
     725           0 :                 ConstrainedDecreasingMdot = true;
     726             :             }
     727             :         } else {
     728             :             // do nothing
     729             :         }
     730             : 
     731        5144 :         FuelFlowProvided = MdotFuel;
     732        5144 :     }
     733             : 
     734       13834 :     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 contraints imposed by plant according to flow lock, first HVAC iteration etc.
     751             : 
     752             :         // Return value
     753             :         Real64 FuncDetermineCWMdotForInternalFlowControl;
     754       13834 :         auto const &thisMicroCHP = state.dataCHPElectGen->MicroCHP(GeneratorNum);
     755       13834 :         int const InletNode = thisMicroCHP.PlantInletNodeID;
     756       13834 :         int const OutletNode = thisMicroCHP.PlantOutletNodeID;
     757             : 
     758             :         // first evaluate curve
     759       13834 :         Real64 MdotCW = Curve::CurveValue(state, thisMicroCHP.A42Model.WaterFlowCurveID, Pnetss, TcwIn);
     760             : 
     761             :         // now apply constraints
     762       13834 :         MdotCW = max(0.0, MdotCW);
     763             : 
     764             :         // make sure plant can provide, utility call may change flow
     765       13834 :         if (thisMicroCHP.CWPlantLoc.loopNum > 0) { // protect early calls
     766       13834 :             PlantUtilities::SetComponentFlowRate(state, MdotCW, InletNode, OutletNode, thisMicroCHP.CWPlantLoc);
     767             :         }
     768             : 
     769       13834 :         FuncDetermineCWMdotForInternalFlowControl = MdotCW;
     770       13834 :         return FuncDetermineCWMdotForInternalFlowControl;
     771             :     }
     772             : 
     773             : } // namespace GeneratorDynamicsManager
     774             : 
     775             : } // namespace EnergyPlus

Generated by: LCOV version 1.14