LCOV - code coverage report
Current view: top level - EnergyPlus - BoilerSteam.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 69.5 % 439 305
Test Date: 2025-06-02 07:23:51 Functions: 100.0 % 14 14

            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/Autosizing/Base.hh>
      57              : #include <EnergyPlus/BoilerSteam.hh>
      58              : #include <EnergyPlus/BranchNodeConnections.hh>
      59              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      60              : #include <EnergyPlus/DataBranchAirLoopPlant.hh>
      61              : #include <EnergyPlus/DataGlobalConstants.hh>
      62              : #include <EnergyPlus/DataHVACGlobals.hh>
      63              : #include <EnergyPlus/DataIPShortCuts.hh>
      64              : #include <EnergyPlus/DataLoopNode.hh>
      65              : #include <EnergyPlus/DataSizing.hh>
      66              : #include <EnergyPlus/EMSManager.hh>
      67              : #include <EnergyPlus/FluidProperties.hh>
      68              : #include <EnergyPlus/GlobalNames.hh>
      69              : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      70              : #include <EnergyPlus/NodeInputManager.hh>
      71              : #include <EnergyPlus/OutputProcessor.hh>
      72              : #include <EnergyPlus/OutputReportPredefined.hh>
      73              : #include <EnergyPlus/Plant/DataPlant.hh>
      74              : #include <EnergyPlus/PlantUtilities.hh>
      75              : #include <EnergyPlus/UtilityRoutines.hh>
      76              : 
      77              : namespace EnergyPlus {
      78              : 
      79              : namespace BoilerSteam {
      80              : 
      81              :     // Module containing the routines dealing with the Boilers
      82              : 
      83              :     // MODULE INFORMATION:
      84              :     //    AUTHOR         Rahul Chillar
      85              :     //    DATE WRITTEN   Dec 2004
      86              : 
      87              :     // PURPOSE OF THIS MODULE:
      88              :     // Performs steam boiler simulation for plant simulation
      89              : 
      90            8 :     BoilerSpecs *BoilerSpecs::factory(EnergyPlusData &state, std::string const &objectName)
      91              :     {
      92              :         // Process the input data for boilers if it hasn't been done already
      93            8 :         if (state.dataBoilerSteam->getSteamBoilerInput) {
      94            8 :             GetBoilerInput(state);
      95            8 :             state.dataBoilerSteam->getSteamBoilerInput = false;
      96              :         }
      97              : 
      98              :         // Now look for this particular pipe in the list
      99            8 :         auto myBoiler = std::find_if(state.dataBoilerSteam->Boiler.begin(),
     100            8 :                                      state.dataBoilerSteam->Boiler.end(),
     101            8 :                                      [&objectName](const BoilerSpecs &boiler) { return boiler.Name == objectName; });
     102            8 :         if (myBoiler != state.dataBoilerSteam->Boiler.end()) {
     103            8 :             return myBoiler;
     104              :         }
     105              : 
     106              :         // If we didn't find it, fatal
     107              :         ShowFatalError(state, format("LocalBoilerSteamFactory: Error getting inputs for steam boiler named: {}", objectName)); // LCOV_EXCL_LINE
     108              :         // Shut up the compiler
     109              :         return nullptr; // LCOV_EXCL_LINE
     110              :     }
     111              : 
     112       107780 :     void BoilerSpecs::simulate(
     113              :         EnergyPlusData &state, [[maybe_unused]] const PlantLocation &calledFromLocation, bool FirstHVACIteration, Real64 &CurLoad, bool RunFlag)
     114              :     {
     115       107780 :         this->initialize(state);
     116       107780 :         auto &sim_component(DataPlant::CompData::getPlantComponent(state, this->plantLoc));
     117       107780 :         this->calculate(state, CurLoad, RunFlag, sim_component.FlowCtrl);
     118       107780 :         this->update(state, CurLoad, RunFlag, FirstHVACIteration);
     119       107780 :     }
     120              : 
     121              :     void
     122           40 :     BoilerSpecs::getDesignCapacities([[maybe_unused]] EnergyPlusData &state, const PlantLocation &, Real64 &MaxLoad, Real64 &MinLoad, Real64 &OptLoad)
     123              :     {
     124           40 :         MinLoad = this->NomCap * this->MinPartLoadRat;
     125           40 :         MaxLoad = this->NomCap * this->MaxPartLoadRat;
     126           40 :         OptLoad = this->NomCap * this->OptPartLoadRat;
     127           40 :     }
     128              : 
     129            8 :     void BoilerSpecs::getSizingFactor(Real64 &sizFac)
     130              :     {
     131            8 :         sizFac = this->SizFac;
     132            8 :     }
     133              : 
     134           40 :     void BoilerSpecs::onInitLoopEquip(EnergyPlusData &state, const PlantLocation &)
     135              :     {
     136           40 :         this->initialize(state);
     137           40 :         this->autosize(state);
     138           40 :     }
     139              : 
     140            8 :     void GetBoilerInput(EnergyPlusData &state)
     141              :     {
     142              :         // SUBROUTINE INFORMATION:
     143              :         //       AUTHOR         Rahul Chillar
     144              :         //       DATE WRITTEN   Dec 2004
     145              : 
     146              :         // PURPOSE OF THIS SUBROUTINE:
     147              :         // Get all boiler data from input file
     148              : 
     149              :         // Locals
     150              :         static constexpr std::string_view RoutineName("GetBoilerInput: ");
     151              :         static constexpr std::string_view routineName = "GetBoilerInput";
     152              : 
     153              :         // LOCAL VARIABLES
     154              :         int BoilerNum; // boiler identifier
     155              :         int NumAlphas; // Number of elements in the alpha array
     156              :         int NumNums;   // Number of elements in the numeric array
     157              :         int IOStat;    // IO Status when calling get input subroutine
     158            8 :         bool ErrorsFound(false);
     159              : 
     160            8 :         state.dataIPShortCut->cCurrentModuleObject = "Boiler:Steam";
     161            8 :         int numBoilers = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, state.dataIPShortCut->cCurrentModuleObject);
     162              : 
     163            8 :         if (numBoilers <= 0) {
     164            0 :             ShowSevereError(state, format("No {} equipment specified in input file", state.dataIPShortCut->cCurrentModuleObject));
     165            0 :             ErrorsFound = true;
     166              :         }
     167              : 
     168              :         // See if load distribution manager has already gotten the input
     169            8 :         if (allocated(state.dataBoilerSteam->Boiler)) {
     170            0 :             return;
     171              :         }
     172              : 
     173              :         // Boiler will have fuel input to it , that is it !
     174            8 :         state.dataBoilerSteam->Boiler.allocate(numBoilers);
     175              : 
     176              :         // LOAD ARRAYS WITH CURVE FIT Boiler DATA
     177           16 :         for (BoilerNum = 1; BoilerNum <= numBoilers; ++BoilerNum) {
     178           24 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     179            8 :                                                                      state.dataIPShortCut->cCurrentModuleObject,
     180              :                                                                      BoilerNum,
     181            8 :                                                                      state.dataIPShortCut->cAlphaArgs,
     182              :                                                                      NumAlphas,
     183            8 :                                                                      state.dataIPShortCut->rNumericArgs,
     184              :                                                                      NumNums,
     185              :                                                                      IOStat,
     186              :                                                                      _,
     187              :                                                                      _,
     188            8 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
     189            8 :                                                                      state.dataIPShortCut->cNumericFieldNames);
     190              : 
     191              :             // ErrorsFound will be set to True if problem was found, left untouched otherwise
     192            8 :             GlobalNames::VerifyUniqueBoilerName(state,
     193            8 :                                                 state.dataIPShortCut->cCurrentModuleObject,
     194            8 :                                                 state.dataIPShortCut->cAlphaArgs(1),
     195              :                                                 ErrorsFound,
     196           16 :                                                 state.dataIPShortCut->cCurrentModuleObject + " Name");
     197            8 :             auto &thisBoiler = state.dataBoilerSteam->Boiler(BoilerNum);
     198            8 :             thisBoiler.Name = state.dataIPShortCut->cAlphaArgs(1);
     199              : 
     200              :             // Validate fuel type input
     201            8 :             thisBoiler.FuelType = static_cast<Constant::eFuel>(getEnumValue(Constant::eFuelNamesUC, state.dataIPShortCut->cAlphaArgs(2)));
     202              : 
     203              :             // INPUTS from the IDF file
     204            8 :             thisBoiler.BoilerMaxOperPress = state.dataIPShortCut->rNumericArgs(1);
     205            8 :             if (thisBoiler.BoilerMaxOperPress < 1e5) {
     206            0 :                 ShowWarningMessage(state, format("{}=\"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     207            0 :                 ShowContinueError(state, "Field: Maximum Operation Pressure units are Pa. Verify units.");
     208              :             }
     209            8 :             thisBoiler.NomEffic = state.dataIPShortCut->rNumericArgs(2);
     210            8 :             thisBoiler.TempUpLimitBoilerOut = state.dataIPShortCut->rNumericArgs(3);
     211            8 :             thisBoiler.NomCap = state.dataIPShortCut->rNumericArgs(4);
     212            8 :             if (thisBoiler.NomCap == DataSizing::AutoSize) {
     213            8 :                 thisBoiler.NomCapWasAutoSized = true;
     214              :             }
     215            8 :             thisBoiler.MinPartLoadRat = state.dataIPShortCut->rNumericArgs(5);
     216            8 :             thisBoiler.MaxPartLoadRat = state.dataIPShortCut->rNumericArgs(6);
     217            8 :             thisBoiler.OptPartLoadRat = state.dataIPShortCut->rNumericArgs(7);
     218            8 :             thisBoiler.FullLoadCoef[0] = state.dataIPShortCut->rNumericArgs(8);
     219            8 :             thisBoiler.FullLoadCoef[1] = state.dataIPShortCut->rNumericArgs(9);
     220            8 :             thisBoiler.FullLoadCoef[2] = state.dataIPShortCut->rNumericArgs(10);
     221            8 :             thisBoiler.SizFac = state.dataIPShortCut->rNumericArgs(11);
     222            8 :             if (thisBoiler.SizFac <= 0.0) {
     223            0 :                 thisBoiler.SizFac = 1.0;
     224              :             }
     225              : 
     226            8 :             if ((state.dataIPShortCut->rNumericArgs(8) + state.dataIPShortCut->rNumericArgs(9) + state.dataIPShortCut->rNumericArgs(10)) == 0.0) {
     227            0 :                 ShowSevereError(state,
     228            0 :                                 format("{}{}=\"{}\",", RoutineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     229            0 :                 ShowContinueError(state, " Sum of fuel use curve coefficients = 0.0");
     230            0 :                 ErrorsFound = true;
     231              :             }
     232              : 
     233            8 :             if (state.dataIPShortCut->rNumericArgs(5) < 0.0) {
     234            0 :                 ShowSevereError(state,
     235            0 :                                 format("{}{}=\"{}\",", RoutineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     236            0 :                 ShowContinueError(state,
     237            0 :                                   format("Invalid {}={:.3R}", state.dataIPShortCut->cNumericFieldNames(5), state.dataIPShortCut->rNumericArgs(5)));
     238            0 :                 ErrorsFound = true;
     239              :             }
     240              : 
     241            8 :             if (state.dataIPShortCut->rNumericArgs(3) == 0.0) {
     242            0 :                 ShowSevereError(state,
     243            0 :                                 format("{}{}=\"{}\",", RoutineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     244            0 :                 ShowContinueError(state,
     245            0 :                                   format("Invalid {}={:.3R}", state.dataIPShortCut->cNumericFieldNames(3), state.dataIPShortCut->rNumericArgs(3)));
     246            0 :                 ErrorsFound = true;
     247              :             }
     248            8 :             thisBoiler.BoilerInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
     249            8 :                                                                                 state.dataIPShortCut->cAlphaArgs(3),
     250              :                                                                                 ErrorsFound,
     251              :                                                                                 DataLoopNode::ConnectionObjectType::BoilerSteam,
     252            8 :                                                                                 state.dataIPShortCut->cAlphaArgs(1),
     253              :                                                                                 DataLoopNode::NodeFluidType::Steam,
     254              :                                                                                 DataLoopNode::ConnectionType::Inlet,
     255              :                                                                                 NodeInputManager::CompFluidStream::Primary,
     256              :                                                                                 DataLoopNode::ObjectIsNotParent);
     257           16 :             thisBoiler.BoilerOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
     258            8 :                                                                                  state.dataIPShortCut->cAlphaArgs(4),
     259              :                                                                                  ErrorsFound,
     260              :                                                                                  DataLoopNode::ConnectionObjectType::BoilerSteam,
     261            8 :                                                                                  state.dataIPShortCut->cAlphaArgs(1),
     262              :                                                                                  DataLoopNode::NodeFluidType::Steam,
     263              :                                                                                  DataLoopNode::ConnectionType::Outlet,
     264              :                                                                                  NodeInputManager::CompFluidStream::Primary,
     265              :                                                                                  DataLoopNode::ObjectIsNotParent);
     266           16 :             BranchNodeConnections::TestCompSet(state,
     267            8 :                                                state.dataIPShortCut->cCurrentModuleObject,
     268            8 :                                                state.dataIPShortCut->cAlphaArgs(1),
     269            8 :                                                state.dataIPShortCut->cAlphaArgs(3),
     270            8 :                                                state.dataIPShortCut->cAlphaArgs(4),
     271              :                                                "Hot Steam Nodes");
     272              : 
     273            8 :             thisBoiler.fluid = Fluid::GetSteam(state);
     274            8 :             if (thisBoiler.fluid == nullptr && BoilerNum == 1) {
     275            0 :                 ShowSevereError(state, "Fluid Properties for STEAM not found.");
     276            0 :                 ErrorsFound = true;
     277              :             }
     278              : 
     279            8 :             if (NumAlphas > 4) {
     280            0 :                 thisBoiler.EndUseSubcategory = state.dataIPShortCut->cAlphaArgs(5);
     281              :             } else {
     282            8 :                 thisBoiler.EndUseSubcategory = "General";
     283              :             }
     284              :         }
     285              : 
     286            8 :         if (ErrorsFound) {
     287            0 :             ShowFatalError(state, format("{}Errors found in processing {} input.", RoutineName, state.dataIPShortCut->cCurrentModuleObject));
     288              :         }
     289              :     }
     290              : 
     291            8 :     void BoilerSpecs::oneTimeInit(EnergyPlusData &state)
     292              :     {
     293            8 :         bool errFlag = false;
     294           16 :         PlantUtilities::ScanPlantLoopsForObject(
     295            8 :             state, this->Name, DataPlant::PlantEquipmentType::Boiler_Steam, this->plantLoc, errFlag, _, _, _, _, _);
     296            8 :         if (errFlag) {
     297            0 :             ShowFatalError(state, "InitBoiler: Program terminated due to previous condition(s).");
     298              :         }
     299            8 :     }
     300              : 
     301           47 :     void BoilerSpecs::initEachEnvironment(EnergyPlusData &state)
     302              :     {
     303              :         static constexpr std::string_view RoutineName("BoilerSpecs::initEachEnvironment");
     304              : 
     305           47 :         int BoilerInletNode = this->BoilerInletNodeNum;
     306              : 
     307           47 :         Real64 EnthSteamOutDry = this->fluid->getSatEnthalpy(state, this->TempUpLimitBoilerOut, 1.0, RoutineName);
     308           47 :         Real64 EnthSteamOutWet = this->fluid->getSatEnthalpy(state, this->TempUpLimitBoilerOut, 0.0, RoutineName);
     309           47 :         Real64 LatentEnthSteam = EnthSteamOutDry - EnthSteamOutWet;
     310              : 
     311           47 :         Real64 CpWater = this->fluid->getSatSpecificHeat(state, this->TempUpLimitBoilerOut, 0.0, RoutineName);
     312              : 
     313           47 :         this->DesMassFlowRate =
     314           47 :             this->NomCap / (LatentEnthSteam + CpWater * (this->TempUpLimitBoilerOut - state.dataLoopNodes->Node(BoilerInletNode).Temp));
     315              : 
     316           47 :         PlantUtilities::InitComponentNodes(state, 0.0, this->DesMassFlowRate, this->BoilerInletNodeNum, this->BoilerOutletNodeNum);
     317              : 
     318           47 :         this->BoilerPressCheck = 0.0;
     319           47 :         this->FuelUsed = 0.0;
     320           47 :         this->BoilerLoad = 0.0;
     321           47 :         this->BoilerEff = 0.0;
     322           47 :         this->BoilerOutletTemp = 0.0;
     323              : 
     324           50 :         if ((state.dataLoopNodes->Node(this->BoilerOutletNodeNum).TempSetPoint == DataLoopNode::SensedNodeFlagValue) &&
     325            3 :             (state.dataLoopNodes->Node(this->BoilerOutletNodeNum).TempSetPointLo == DataLoopNode::SensedNodeFlagValue)) {
     326            3 :             if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
     327            3 :                 if (!this->MissingSetPointErrDone) {
     328            1 :                     ShowWarningError(state, format("Missing temperature setpoint for Boiler:Steam = {}", this->Name));
     329            2 :                     ShowContinueError(state, " A temperature setpoint is needed at the outlet node of the boiler, use a SetpointManager");
     330            2 :                     ShowContinueError(state, " The overall loop setpoint will be assumed for this boiler. The simulation continues ...");
     331            1 :                     this->MissingSetPointErrDone = true;
     332              :                 }
     333              :             } else {
     334              :                 // need call to EMS to check node
     335            0 :                 bool FatalError = false; // but not really fatal yet, but should be.
     336            0 :                 EMSManager::CheckIfNodeSetPointManagedByEMS(state, this->BoilerOutletNodeNum, HVAC::CtrlVarType::Temp, FatalError);
     337            0 :                 state.dataLoopNodes->NodeSetpointCheck(this->BoilerOutletNodeNum).needsSetpointChecking = false;
     338            0 :                 if (FatalError) {
     339            0 :                     if (!this->MissingSetPointErrDone) {
     340            0 :                         ShowWarningError(state, format("Missing temperature setpoint for LeavingSetpointModulated mode Boiler named {}", this->Name));
     341            0 :                         ShowContinueError(state, " A temperature setpoint is needed at the outlet node of the boiler.");
     342            0 :                         ShowContinueError(state, " Use a Setpoint Manager to establish a setpoint at the boiler outlet node ");
     343            0 :                         ShowContinueError(state, " or use an EMS actuator to establish a setpoint at the boiler outlet node.");
     344            0 :                         ShowContinueError(state, " The overall loop setpoint will be assumed for this boiler. The simulation continues...");
     345            0 :                         this->MissingSetPointErrDone = true;
     346              :                     }
     347              :                 }
     348              :             }
     349            3 :             this->UseLoopSetPoint = true; // this is for backward compatibility and could be removed
     350              :         }
     351           47 :     }
     352              : 
     353       107820 :     void BoilerSpecs::initialize(EnergyPlusData &state) // number of the current electric chiller being simulated
     354              :     {
     355              :         // SUBROUTINE INFORMATION:
     356              :         //       AUTHOR         Rahul Chillar
     357              :         //       DATE WRITTEN   Dec 2004
     358              :         //       RE-ENGINEERED  D. Shirey, rework for plant upgrade
     359              : 
     360              :         // PURPOSE OF THIS SUBROUTINE:
     361              :         // This subroutine is for initializations of the Boiler components
     362              : 
     363              :         // METHODOLOGY EMPLOYED:
     364              :         // Uses the status flags to trigger initializations.
     365              : 
     366              :         // Init more variables
     367       107820 :         if (this->myFlag) {
     368            8 :             this->setupOutputVars(state);
     369            8 :             this->oneTimeInit(state);
     370            8 :             this->myFlag = false;
     371              :         }
     372              : 
     373       107820 :         if (state.dataGlobal->BeginEnvrnFlag && this->myEnvrnFlag && (state.dataPlnt->PlantFirstSizesOkayToFinalize)) {
     374           47 :             this->initEachEnvironment(state);
     375           47 :             this->myEnvrnFlag = false;
     376              :         }
     377       107820 :         if (!state.dataGlobal->BeginEnvrnFlag) {
     378       106868 :             this->myEnvrnFlag = true;
     379              :         }
     380              : 
     381       107820 :         if (this->UseLoopSetPoint) {
     382              :             //  At some point, need to circle back and get from plant data structure instead of node
     383              :             // fix for clumsy old input that worked because loop setpoint was spread.
     384              :             //  could be removed with transition, testing , model change, period of being obsolete.
     385         5366 :             int BoilerOutletNode = this->BoilerOutletNodeNum;
     386         5366 :             switch (this->plantLoc.loop->LoopDemandCalcScheme) {
     387              : 
     388         5366 :             case DataPlant::LoopDemandCalcScheme::SingleSetPoint:
     389         5366 :                 state.dataLoopNodes->Node(BoilerOutletNode).TempSetPoint =
     390         5366 :                     state.dataLoopNodes->Node(this->plantLoc.loop->TempSetPointNodeNum).TempSetPoint;
     391         5366 :                 break;
     392            0 :             case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand:
     393            0 :                 state.dataLoopNodes->Node(BoilerOutletNode).TempSetPointLo =
     394            0 :                     state.dataLoopNodes->Node(this->plantLoc.loop->TempSetPointNodeNum).TempSetPointLo;
     395            0 :                 break;
     396            0 :             default:
     397            0 :                 break;
     398              :             }
     399              :         }
     400       107820 :     }
     401              : 
     402            8 :     void BoilerSpecs::setupOutputVars(EnergyPlusData &state)
     403              :     {
     404            8 :         std::string_view sFuelType = Constant::eFuelNames[static_cast<int>(this->FuelType)];
     405           16 :         SetupOutputVariable(state,
     406              :                             "Boiler Heating Rate",
     407              :                             Constant::Units::W,
     408            8 :                             this->BoilerLoad,
     409              :                             OutputProcessor::TimeStepType::System,
     410              :                             OutputProcessor::StoreType::Average,
     411            8 :                             this->Name);
     412              : 
     413           16 :         SetupOutputVariable(state,
     414              :                             "Boiler Heating Energy",
     415              :                             Constant::Units::J,
     416            8 :                             this->BoilerEnergy,
     417              :                             OutputProcessor::TimeStepType::System,
     418              :                             OutputProcessor::StoreType::Sum,
     419            8 :                             this->Name,
     420              :                             Constant::eResource::EnergyTransfer,
     421              :                             OutputProcessor::Group::Plant,
     422              :                             OutputProcessor::EndUseCat::Boilers);
     423           24 :         SetupOutputVariable(state,
     424           16 :                             format("Boiler {} Rate", sFuelType),
     425              :                             Constant::Units::W,
     426            8 :                             this->FuelUsed,
     427              :                             OutputProcessor::TimeStepType::System,
     428              :                             OutputProcessor::StoreType::Average,
     429            8 :                             this->Name);
     430           24 :         SetupOutputVariable(state,
     431           16 :                             format("Boiler {} Energy", sFuelType),
     432              :                             Constant::Units::J,
     433            8 :                             this->FuelConsumed,
     434              :                             OutputProcessor::TimeStepType::System,
     435              :                             OutputProcessor::StoreType::Sum,
     436            8 :                             this->Name,
     437            8 :                             Constant::eFuel2eResource[(int)this->FuelType],
     438              :                             OutputProcessor::Group::Plant,
     439              :                             OutputProcessor::EndUseCat::Heating,
     440              :                             this->EndUseSubcategory);
     441           16 :         SetupOutputVariable(state,
     442              :                             "Boiler Steam Efficiency",
     443              :                             Constant::Units::None,
     444            8 :                             this->BoilerEff,
     445              :                             OutputProcessor::TimeStepType::System,
     446              :                             OutputProcessor::StoreType::Average,
     447            8 :                             this->Name);
     448           16 :         SetupOutputVariable(state,
     449              :                             "Boiler Steam Inlet Temperature",
     450              :                             Constant::Units::C,
     451            8 :                             this->BoilerInletTemp,
     452              :                             OutputProcessor::TimeStepType::System,
     453              :                             OutputProcessor::StoreType::Average,
     454            8 :                             this->Name);
     455           16 :         SetupOutputVariable(state,
     456              :                             "Boiler Steam Outlet Temperature",
     457              :                             Constant::Units::C,
     458            8 :                             this->BoilerOutletTemp,
     459              :                             OutputProcessor::TimeStepType::System,
     460              :                             OutputProcessor::StoreType::Average,
     461            8 :                             this->Name);
     462           16 :         SetupOutputVariable(state,
     463              :                             "Boiler Steam Mass Flow Rate",
     464              :                             Constant::Units::kg_s,
     465            8 :                             this->BoilerMassFlowRate,
     466              :                             OutputProcessor::TimeStepType::System,
     467              :                             OutputProcessor::StoreType::Average,
     468            8 :                             this->Name);
     469            8 :     }
     470              : 
     471           40 :     void BoilerSpecs::autosize(EnergyPlusData &state)
     472              :     {
     473              : 
     474              :         // SUBROUTINE INFORMATION:
     475              :         //       AUTHOR         Rahul Chillar
     476              :         //       DATE WRITTEN   Dec 2004
     477              :         //       MODIFIED       November 2013 Daeho Kang, add component sizing table entries
     478              : 
     479              :         // PURPOSE OF THIS SUBROUTINE:
     480              :         // This subroutine is for sizing Boiler Components for which capacities and flow rates
     481              :         // have not been specified in the input.
     482              : 
     483              :         // METHODOLOGY EMPLOYED:
     484              :         // Obtains Steam flow rate from the plant sizing array. Calculates nominal capacity from
     485              :         // the hot water flow rate and the hot water loop design delta T.
     486              : 
     487              :         // SUBROUTINE PARAMETER DEFINITIONS:
     488              :         static constexpr std::string_view RoutineName("SizeBoiler");
     489              : 
     490              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     491           40 :         bool ErrorsFound(false); // If errors detected in input
     492           40 :         Real64 tmpNomCap = this->NomCap;
     493           40 :         int PltSizNum = this->plantLoc.loop->PlantSizNum;
     494              : 
     495           40 :         if (PltSizNum > 0) {
     496           40 :             if (state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
     497           32 :                 Real64 SizingTemp = this->TempUpLimitBoilerOut;
     498           32 :                 Real64 SteamDensity = this->fluid->getSatDensity(state, SizingTemp, 1.0, RoutineName);
     499           32 :                 Real64 EnthSteamOutDry = this->fluid->getSatEnthalpy(state, SizingTemp, 1.0, RoutineName);
     500           32 :                 Real64 EnthSteamOutWet = this->fluid->getSatEnthalpy(state, SizingTemp, 0.0, RoutineName);
     501           32 :                 Real64 LatentEnthSteam = EnthSteamOutDry - EnthSteamOutWet;
     502           32 :                 Real64 CpWater = this->fluid->getSatSpecificHeat(state, SizingTemp, 0.0, RoutineName);
     503           32 :                 tmpNomCap = (CpWater * SteamDensity * this->SizFac * state.dataSize->PlantSizData(PltSizNum).DeltaT *
     504           32 :                                  state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate +
     505           32 :                              state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate * SteamDensity * LatentEnthSteam);
     506              :             } else {
     507            8 :                 if (this->NomCapWasAutoSized) {
     508            8 :                     tmpNomCap = 0.0;
     509              :                 }
     510              :             }
     511           40 :             if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
     512            8 :                 if (this->NomCapWasAutoSized) {
     513            8 :                     this->NomCap = tmpNomCap;
     514            8 :                     if (state.dataPlnt->PlantFinalSizesOkayToReport) {
     515            8 :                         BaseSizer::reportSizerOutput(state, "Boiler:Steam", this->Name, "Design Size Nominal Capacity [W]", tmpNomCap);
     516              : 
     517              :                         // Std 229 Boilers new report table
     518            8 :                         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchBoilerType, this->Name, "Boiler:Steam");
     519            8 :                         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchBoilerRefCap, this->Name, this->NomCap);
     520            8 :                         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchBoilerRefEff, this->Name, this->NomEffic);
     521            8 :                         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchBoilerRatedCap, this->Name, this->NomCap);
     522            8 :                         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchBoilerRatedEff, this->Name, this->NomEffic);
     523           16 :                         OutputReportPredefined::PreDefTableEntry(state,
     524            8 :                                                                  state.dataOutRptPredefined->pdchBoilerPlantloopName,
     525              :                                                                  this->Name,
     526           16 :                                                                  (this->plantLoc.loop != nullptr) ? this->plantLoc.loop->Name : "N/A");
     527           16 :                         OutputReportPredefined::PreDefTableEntry(state,
     528            8 :                                                                  state.dataOutRptPredefined->pdchBoilerPlantloopBranchName,
     529              :                                                                  this->Name,
     530           16 :                                                                  (this->plantLoc.branch != nullptr) ? this->plantLoc.branch->Name : "N/A");
     531           16 :                         OutputReportPredefined::PreDefTableEntry(
     532            8 :                             state, state.dataOutRptPredefined->pdchBoilerMinPLR, this->Name, this->MinPartLoadRat);
     533           16 :                         OutputReportPredefined::PreDefTableEntry(state,
     534            8 :                                                                  state.dataOutRptPredefined->pdchBoilerFuelType,
     535              :                                                                  this->Name,
     536            8 :                                                                  Constant::eFuelNames[static_cast<int>(this->FuelType)]);
     537           16 :                         OutputReportPredefined::PreDefTableEntry(
     538            8 :                             state, state.dataOutRptPredefined->pdchBoilerParaElecLoad, this->Name, "Not Applicable");
     539              :                     }
     540            8 :                     if (state.dataPlnt->PlantFirstSizesOkayToReport) {
     541            0 :                         BaseSizer::reportSizerOutput(state, "Boiler:Steam", this->Name, "Initial Design Size Nominal Capacity [W]", tmpNomCap);
     542              :                     }
     543              :                 } else { // Hard-sized with sizing data
     544            0 :                     if (this->NomCap > 0.0 && tmpNomCap > 0.0) {
     545            0 :                         Real64 NomCapUser = this->NomCap;
     546            0 :                         if (state.dataPlnt->PlantFinalSizesOkayToReport) {
     547            0 :                             BaseSizer::reportSizerOutput(state,
     548              :                                                          "Boiler:Steam",
     549              :                                                          this->Name,
     550              :                                                          "Design Size Nominal Capacity [W]",
     551              :                                                          tmpNomCap,
     552              :                                                          "User-Specified Nominal Capacity [W]",
     553              :                                                          NomCapUser);
     554              : 
     555              :                             // Std 229 Boilers new report table
     556            0 :                             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchBoilerType, this->Name, "Boiler:Steam");
     557            0 :                             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchBoilerRefCap, this->Name, this->NomCap);
     558            0 :                             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchBoilerRefEff, this->Name, this->NomEffic);
     559            0 :                             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchBoilerRatedCap, this->Name, this->NomCap);
     560            0 :                             OutputReportPredefined::PreDefTableEntry(
     561            0 :                                 state, state.dataOutRptPredefined->pdchBoilerRatedEff, this->Name, this->NomEffic);
     562            0 :                             OutputReportPredefined::PreDefTableEntry(state,
     563            0 :                                                                      state.dataOutRptPredefined->pdchBoilerPlantloopName,
     564              :                                                                      this->Name,
     565            0 :                                                                      (this->plantLoc.loop != nullptr) ? this->plantLoc.loop->Name : "N/A");
     566            0 :                             OutputReportPredefined::PreDefTableEntry(state,
     567            0 :                                                                      state.dataOutRptPredefined->pdchBoilerPlantloopBranchName,
     568              :                                                                      this->Name,
     569            0 :                                                                      (this->plantLoc.branch != nullptr) ? this->plantLoc.branch->Name : "N/A");
     570            0 :                             OutputReportPredefined::PreDefTableEntry(
     571            0 :                                 state, state.dataOutRptPredefined->pdchBoilerMinPLR, this->Name, this->MinPartLoadRat);
     572            0 :                             OutputReportPredefined::PreDefTableEntry(state,
     573            0 :                                                                      state.dataOutRptPredefined->pdchBoilerFuelType,
     574              :                                                                      this->Name,
     575            0 :                                                                      Constant::eFuelNames[static_cast<int>(this->FuelType)]);
     576            0 :                             OutputReportPredefined::PreDefTableEntry(
     577            0 :                                 state, state.dataOutRptPredefined->pdchBoilerParaElecLoad, this->Name, "Not Applicable");
     578              : 
     579            0 :                             if (state.dataGlobal->DisplayExtraWarnings) {
     580            0 :                                 if ((std::abs(tmpNomCap - NomCapUser) / NomCapUser) > state.dataSize->AutoVsHardSizingThreshold) {
     581            0 :                                     ShowMessage(state, format("SizePump: Potential issue with equipment sizing for {}", this->Name));
     582            0 :                                     ShowContinueError(state, format("User-Specified Nominal Capacity of {:.2R} [W]", NomCapUser));
     583            0 :                                     ShowContinueError(state, format("differs from Design Size Nominal Capacity of {:.2R} [W]", tmpNomCap));
     584            0 :                                     ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
     585            0 :                                     ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
     586              :                                 }
     587              :                             }
     588              :                         }
     589              :                     }
     590              :                 }
     591              :             }
     592              :         } else {
     593            0 :             if (this->NomCapWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
     594            0 :                 ShowSevereError(state, "Autosizing of Boiler nominal capacity requires a loop Sizing:Plant object");
     595            0 :                 ShowContinueError(state, format("Occurs in Boiler:Steam object={}", this->Name));
     596            0 :                 ErrorsFound = true;
     597              :             }
     598            0 :             if (!this->NomCapWasAutoSized && this->NomCap > 0.0 && state.dataPlnt->PlantFinalSizesOkayToReport) {
     599            0 :                 BaseSizer::reportSizerOutput(state, "Boiler:Steam", this->Name, "User-Specified Nominal Capacity [W]", this->NomCap);
     600              :             }
     601              :         }
     602              : 
     603           40 :         if (state.dataPlnt->PlantFinalSizesOkayToReport) {
     604              :             // create predefined report
     605            8 :             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchMechType, this->Name, "Boiler:Steam");
     606            8 :             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchMechNomEff, this->Name, this->NomEffic);
     607            8 :             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchMechNomCap, this->Name, this->NomCap);
     608              :         }
     609              : 
     610           40 :         if (ErrorsFound) {
     611            0 :             ShowFatalError(state, "Preceding sizing errors cause program termination");
     612              :         }
     613           40 :     }
     614              : 
     615       107780 :     void BoilerSpecs::calculate(EnergyPlusData &state,
     616              :                                 Real64 &MyLoad,                                         // W - hot water demand to be met by boiler
     617              :                                 bool const RunFlag,                                     // TRUE if boiler operating
     618              :                                 DataBranchAirLoopPlant::ControlType const EquipFlowCtrl // Flow control mode for the equipment
     619              :     )
     620              :     {
     621              :         // SUBROUTINE INFORMATION:
     622              :         //       AUTHOR         Rahul Chillar
     623              :         //       DATE WRITTEN   Dec 2004
     624              : 
     625              :         // PURPOSE OF THIS SUBROUTINE:
     626              :         // This subroutine calculates the boiler fuel consumption and the associated
     627              :         // hot water demand met by the boiler
     628              : 
     629              :         // METHODOLOGY EMPLOYED:
     630              :         // The model is based on a single combustion efficiency (=1 for electric)
     631              :         // and a second order polynomial fit of performance data to obtain part
     632              :         // load performance
     633              : 
     634              :         // SUBROUTINE PARAMETER DEFINITIONS:
     635              :         static constexpr std::string_view RoutineName("CalcBoilerModel");
     636              : 
     637              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     638       107780 :         Real64 BoilerDeltaTemp(0.0); // C - boiler inlet to outlet temperature difference
     639              :         Real64 CpWater;              // Heat capacity of condensed steam
     640              : 
     641              :         // Loading the variables derived type in to local variables
     642       107780 :         this->BoilerLoad = 0.0;
     643       107780 :         this->BoilerMassFlowRate = 0.0;
     644              : 
     645       107780 :         switch (this->plantLoc.loop->LoopDemandCalcScheme) {
     646       107780 :         case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
     647       107780 :             this->BoilerOutletTemp = state.dataLoopNodes->Node(this->BoilerOutletNodeNum).TempSetPoint;
     648       107780 :         } break;
     649            0 :         case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
     650            0 :             this->BoilerOutletTemp = state.dataLoopNodes->Node(this->BoilerOutletNodeNum).TempSetPointLo;
     651            0 :         } break;
     652            0 :         default:
     653            0 :             break;
     654              :         }
     655              :         // If the specified load is 0.0 or the boiler should not run then we leave this subroutine.Before leaving
     656              :         // if the component control is SERIESACTIVE we set the component flow to inlet flow so that flow resolver
     657              :         // will not shut down the branch
     658       107780 :         if (MyLoad <= 0.0 || !RunFlag) {
     659        74576 :             if (EquipFlowCtrl == DataBranchAirLoopPlant::ControlType::SeriesActive) {
     660            0 :                 this->BoilerMassFlowRate = state.dataLoopNodes->Node(this->BoilerInletNodeNum).MassFlowRate;
     661              :             }
     662        74576 :             return;
     663              :         }
     664              : 
     665              :         // Set the current load equal to the boiler load
     666        33204 :         this->BoilerLoad = MyLoad;
     667              : 
     668        33204 :         this->BoilerPressCheck = this->fluid->getSatPressure(state, this->BoilerOutletTemp, RoutineName);
     669              : 
     670        33204 :         if ((this->BoilerPressCheck) > this->BoilerMaxOperPress) {
     671            0 :             if (this->PressErrIndex == 0) {
     672            0 :                 ShowSevereError(state, format("Boiler:Steam=\"{}\", Saturation Pressure is greater than Maximum Operating Pressure,", this->Name));
     673            0 :                 ShowContinueError(state, "Lower Input Temperature");
     674            0 :                 ShowContinueError(state, format("Steam temperature=[{:.2R}] C", this->BoilerOutletTemp));
     675            0 :                 ShowContinueError(state, format("Refrigerant Saturation Pressure =[{:.0R}] Pa", this->BoilerPressCheck));
     676              :             }
     677            0 :             ShowRecurringSevereErrorAtEnd(state,
     678            0 :                                           "Boiler:Steam=\"" + this->Name +
     679              :                                               "\", Saturation Pressure is greater than Maximum Operating Pressure..continues",
     680            0 :                                           this->PressErrIndex,
     681            0 :                                           this->BoilerPressCheck,
     682            0 :                                           this->BoilerPressCheck,
     683              :                                           _,
     684              :                                           "[Pa]",
     685              :                                           "[Pa]");
     686              :         }
     687              : 
     688        33204 :         CpWater = this->fluid->getSatSpecificHeat(state, state.dataLoopNodes->Node(this->BoilerInletNodeNum).Temp, 0.0, RoutineName);
     689              : 
     690        33204 :         if (this->plantLoc.side->FlowLock == DataPlant::FlowLock::Unlocked) { // TODO: Components shouldn't check FlowLock
     691              :             // Calculate the flow for the boiler
     692              : 
     693        16602 :             switch (this->plantLoc.loop->LoopDemandCalcScheme) {
     694        16602 :             case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
     695        16602 :                 BoilerDeltaTemp =
     696        16602 :                     state.dataLoopNodes->Node(this->BoilerOutletNodeNum).TempSetPoint - state.dataLoopNodes->Node(this->BoilerInletNodeNum).Temp;
     697        16602 :             } break;
     698            0 :             default: { // DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand
     699            0 :                 BoilerDeltaTemp =
     700            0 :                     state.dataLoopNodes->Node(this->BoilerOutletNodeNum).TempSetPointLo - state.dataLoopNodes->Node(this->BoilerInletNodeNum).Temp;
     701            0 :             } break;
     702              :             }
     703        16602 :             this->BoilerOutletTemp = BoilerDeltaTemp + state.dataLoopNodes->Node(this->BoilerInletNodeNum).Temp;
     704              : 
     705        16602 :             Real64 const EnthSteamOutDry = this->fluid->getSatEnthalpy(state, this->BoilerOutletTemp, 1.0, RoutineName);
     706        16602 :             Real64 const EnthSteamOutWet = this->fluid->getSatEnthalpy(state, this->BoilerOutletTemp, 0.0, RoutineName);
     707        16602 :             Real64 const LatentEnthSteam = EnthSteamOutDry - EnthSteamOutWet;
     708        16602 :             this->BoilerMassFlowRate = this->BoilerLoad / (LatentEnthSteam + (CpWater * BoilerDeltaTemp));
     709              : 
     710        16602 :             PlantUtilities::SetComponentFlowRate(
     711        16602 :                 state, this->BoilerMassFlowRate, this->BoilerInletNodeNum, this->BoilerOutletNodeNum, this->plantLoc);
     712              : 
     713              :         } else { // If FlowLock is True
     714              :             // Set the boiler flow rate from inlet node and then check performance
     715        16602 :             this->BoilerMassFlowRate = state.dataLoopNodes->Node(this->BoilerInletNodeNum).MassFlowRate;
     716              :             // Assume that it can meet the setpoint
     717        16602 :             switch (this->plantLoc.loop->LoopDemandCalcScheme) {
     718        16602 :             case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
     719        16602 :                 BoilerDeltaTemp =
     720        16602 :                     state.dataLoopNodes->Node(this->BoilerOutletNodeNum).TempSetPoint - state.dataLoopNodes->Node(this->BoilerInletNodeNum).Temp;
     721        16602 :             } break;
     722            0 :             case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
     723            0 :                 BoilerDeltaTemp =
     724            0 :                     state.dataLoopNodes->Node(this->BoilerOutletNodeNum).TempSetPointLo - state.dataLoopNodes->Node(this->BoilerInletNodeNum).Temp;
     725            0 :             } break;
     726            0 :             default:
     727            0 :                 break;
     728              :             }
     729              :             // If boiler outlet temp is already greater than setpoint than it does not need to operate this iteration
     730        16602 :             if (BoilerDeltaTemp < 0.0) {
     731            2 :                 switch (this->plantLoc.loop->LoopDemandCalcScheme) {
     732            2 :                 case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
     733            2 :                     this->BoilerOutletTemp = state.dataLoopNodes->Node(this->BoilerOutletNodeNum).TempSetPoint;
     734            2 :                 } break;
     735            0 :                 case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
     736            0 :                     this->BoilerOutletTemp = state.dataLoopNodes->Node(this->BoilerOutletNodeNum).TempSetPointLo;
     737            0 :                 } break;
     738            0 :                 default:
     739            0 :                     break;
     740              :                 }
     741            2 :                 Real64 const EnthSteamOutDry = this->fluid->getSatEnthalpy(state, this->BoilerOutletTemp, 1.0, RoutineName);
     742            2 :                 Real64 const EnthSteamOutWet = this->fluid->getSatEnthalpy(state, this->BoilerOutletTemp, 0.0, RoutineName);
     743            2 :                 Real64 const LatentEnthSteam = EnthSteamOutDry - EnthSteamOutWet;
     744            2 :                 this->BoilerLoad = (this->BoilerMassFlowRate * LatentEnthSteam);
     745              : 
     746              :             } else {
     747        16600 :                 switch (this->plantLoc.loop->LoopDemandCalcScheme) {
     748        16600 :                 case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
     749        16600 :                     this->BoilerOutletTemp = state.dataLoopNodes->Node(this->BoilerOutletNodeNum).TempSetPoint;
     750        16600 :                 } break;
     751            0 :                 case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
     752            0 :                     this->BoilerOutletTemp = state.dataLoopNodes->Node(this->BoilerOutletNodeNum).TempSetPointLo;
     753            0 :                 } break;
     754            0 :                 default:
     755            0 :                     break;
     756              :                 }
     757              : 
     758        16600 :                 Real64 const EnthSteamOutDry = this->fluid->getSatEnthalpy(state, this->BoilerOutletTemp, 1.0, RoutineName);
     759        16600 :                 Real64 const EnthSteamOutWet = this->fluid->getSatEnthalpy(state, this->BoilerOutletTemp, 0.0, RoutineName);
     760        16600 :                 Real64 const LatentEnthSteam = EnthSteamOutDry - EnthSteamOutWet;
     761        16600 :                 this->BoilerLoad =
     762        16600 :                     std::abs(this->BoilerMassFlowRate * LatentEnthSteam) + std::abs(this->BoilerMassFlowRate * CpWater * BoilerDeltaTemp);
     763              :             }
     764              : 
     765              :             // If load exceeds the distributed load set to the distributed load
     766        16602 :             if (this->BoilerLoad > MyLoad) {
     767            2 :                 this->BoilerLoad = MyLoad;
     768              : 
     769              :                 // Reset later , here just for calculating latent heat
     770            2 :                 switch (this->plantLoc.loop->LoopDemandCalcScheme) {
     771            2 :                 case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
     772            2 :                     this->BoilerOutletTemp = state.dataLoopNodes->Node(this->BoilerOutletNodeNum).TempSetPoint;
     773            2 :                 } break;
     774            0 :                 case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
     775            0 :                     this->BoilerOutletTemp = state.dataLoopNodes->Node(this->BoilerOutletNodeNum).TempSetPointLo;
     776            0 :                 } break;
     777            0 :                 default:
     778            0 :                     break;
     779              :                 }
     780              : 
     781            2 :                 Real64 const EnthSteamOutDry = this->fluid->getSatEnthalpy(state, this->BoilerOutletTemp, 1.0, RoutineName);
     782            2 :                 Real64 const EnthSteamOutWet = this->fluid->getSatEnthalpy(state, this->BoilerOutletTemp, 0.0, RoutineName);
     783            2 :                 Real64 const LatentEnthSteam = EnthSteamOutDry - EnthSteamOutWet;
     784            2 :                 BoilerDeltaTemp = this->BoilerOutletTemp - state.dataLoopNodes->Node(this->BoilerInletNodeNum).Temp;
     785            2 :                 this->BoilerMassFlowRate = this->BoilerLoad / (LatentEnthSteam + CpWater * BoilerDeltaTemp);
     786              : 
     787            2 :                 PlantUtilities::SetComponentFlowRate(
     788            2 :                     state, this->BoilerMassFlowRate, this->BoilerInletNodeNum, this->BoilerOutletNodeNum, this->plantLoc);
     789              :             }
     790              : 
     791              :             // Checks Boiler Load on the basis of the machine limits.
     792        16602 :             if (this->BoilerLoad > this->NomCap) {
     793            0 :                 if (this->BoilerMassFlowRate > DataBranchAirLoopPlant::MassFlowTolerance) {
     794            0 :                     this->BoilerLoad = this->NomCap;
     795              : 
     796            0 :                     Real64 const EnthSteamOutDry = this->fluid->getSatEnthalpy(state, this->BoilerOutletTemp, 1.0, RoutineName);
     797            0 :                     Real64 const EnthSteamOutWet = this->fluid->getSatEnthalpy(state, this->BoilerOutletTemp, 0.0, RoutineName);
     798            0 :                     Real64 const LatentEnthSteam = EnthSteamOutDry - EnthSteamOutWet;
     799            0 :                     BoilerDeltaTemp = this->BoilerOutletTemp - state.dataLoopNodes->Node(this->BoilerInletNodeNum).Temp;
     800            0 :                     this->BoilerMassFlowRate = this->BoilerLoad / (LatentEnthSteam + CpWater * BoilerDeltaTemp);
     801              : 
     802            0 :                     PlantUtilities::SetComponentFlowRate(
     803            0 :                         state, this->BoilerMassFlowRate, this->BoilerInletNodeNum, this->BoilerOutletNodeNum, this->plantLoc);
     804              :                 } else {
     805            0 :                     this->BoilerLoad = 0.0;
     806            0 :                     this->BoilerOutletTemp = state.dataLoopNodes->Node(this->BoilerInletNodeNum).Temp;
     807              :                 }
     808              :             }
     809              : 
     810              :         } // End of the FlowLock If block
     811              : 
     812              :         // Limit BoilerOutletTemp.  If > max temp, trip boiler.
     813        33204 :         if (this->BoilerOutletTemp > this->TempUpLimitBoilerOut) {
     814            0 :             this->BoilerLoad = 0.0;
     815            0 :             this->BoilerOutletTemp = state.dataLoopNodes->Node(this->BoilerInletNodeNum).Temp;
     816              :             //  Does BoilerMassFlowRate need to be set????
     817              :         }
     818              : 
     819        33204 :         Real64 OperPLR = this->BoilerLoad / this->NomCap;
     820        33204 :         OperPLR = min(OperPLR, this->MaxPartLoadRat);
     821        33204 :         OperPLR = max(OperPLR, this->MinPartLoadRat);
     822        33204 :         Real64 TheorFuelUse = this->BoilerLoad / this->NomEffic;
     823              : 
     824              :         // Calculate fuel used
     825        33204 :         this->FuelUsed = TheorFuelUse / (this->FullLoadCoef[0] + this->FullLoadCoef[1] * OperPLR + this->FullLoadCoef[2] * pow_2(OperPLR));
     826              :         // Calculate boiler efficiency
     827        33204 :         this->BoilerEff = this->BoilerLoad / this->FuelUsed;
     828              :     }
     829              : 
     830              :     // Beginning of Record Keeping subroutines for the BOILER:SIMPLE Module
     831              : 
     832       107780 :     void BoilerSpecs::update(EnergyPlusData &state,
     833              :                              Real64 const MyLoad,                           // boiler operating load
     834              :                              bool const RunFlag,                            // boiler on when TRUE
     835              :                              [[maybe_unused]] bool const FirstHVACIteration // TRUE if First iteration of simulation
     836              :     )
     837              :     {
     838              :         // SUBROUTINE INFORMATION:
     839              :         //       AUTHOR         Rahul Chillar
     840              :         //       DATE WRITTEN   Dec 2004
     841              : 
     842              :         // PURPOSE OF THIS SUBROUTINE:
     843              :         // Boiler simulation reporting
     844              : 
     845       107780 :         Real64 ReportingConstant = state.dataHVACGlobal->TimeStepSysSec;
     846       107780 :         int BoilerInletNode = this->BoilerInletNodeNum;
     847       107780 :         int BoilerOutletNode = this->BoilerOutletNodeNum;
     848              : 
     849       107780 :         if (MyLoad <= 0.0 || !RunFlag) {
     850              :             // set node temperatures
     851        74576 :             PlantUtilities::SafeCopyPlantNode(state, BoilerInletNode, BoilerOutletNode);
     852        74576 :             state.dataLoopNodes->Node(BoilerOutletNode).Temp = state.dataLoopNodes->Node(BoilerInletNode).Temp;
     853        74576 :             this->BoilerOutletTemp = state.dataLoopNodes->Node(BoilerInletNode).Temp;
     854        74576 :             this->BoilerLoad = 0.0;
     855        74576 :             this->FuelUsed = 0.0;
     856        74576 :             this->BoilerEff = 0.0;
     857        74576 :             state.dataLoopNodes->Node(BoilerInletNode).Press = this->BoilerPressCheck;
     858        74576 :             state.dataLoopNodes->Node(BoilerOutletNode).Press = state.dataLoopNodes->Node(BoilerInletNode).Press;
     859        74576 :             state.dataLoopNodes->Node(BoilerInletNode).Quality = 0.0;
     860        74576 :             state.dataLoopNodes->Node(BoilerOutletNode).Quality = state.dataLoopNodes->Node(BoilerInletNode).Quality;
     861              : 
     862              :         } else {
     863              :             // set node temperatures
     864        33204 :             PlantUtilities::SafeCopyPlantNode(state, BoilerInletNode, BoilerOutletNode);
     865        33204 :             state.dataLoopNodes->Node(BoilerOutletNode).Temp = this->BoilerOutletTemp;
     866        33204 :             state.dataLoopNodes->Node(BoilerInletNode).Press = this->BoilerPressCheck; //???
     867        33204 :             state.dataLoopNodes->Node(BoilerOutletNode).Press = state.dataLoopNodes->Node(BoilerInletNode).Press;
     868        33204 :             state.dataLoopNodes->Node(BoilerOutletNode).Quality = 1.0; // Model assumes saturated steam exiting the boiler
     869              :         }
     870              : 
     871       107780 :         this->BoilerInletTemp = state.dataLoopNodes->Node(BoilerInletNode).Temp;
     872       107780 :         this->BoilerMassFlowRate = state.dataLoopNodes->Node(BoilerOutletNode).MassFlowRate;
     873       107780 :         this->BoilerEnergy = this->BoilerLoad * ReportingConstant;
     874       107780 :         this->FuelConsumed = this->FuelUsed * ReportingConstant;
     875       107780 :     }
     876              : 
     877              : } // namespace BoilerSteam
     878              : 
     879              : } // namespace EnergyPlus
        

Generated by: LCOV version 2.0-1