LCOV - code coverage report
Current view: top level - EnergyPlus - BoilerSteam.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 46.9 % 435 204
Test Date: 2025-05-22 16:09:37 Functions: 78.6 % 14 11

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

Generated by: LCOV version 2.0-1