LCOV - code coverage report
Current view: top level - EnergyPlus - BoilerSteam.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 310 447 69.4 %
Date: 2024-08-23 23:50:59 Functions: 14 14 100.0 %

          Line data    Source code
       1             : // EnergyPlus, Copyright (c) 1996-2024, The Board of Trustees of the University of Illinois,
       2             : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3             : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4             : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5             : // contributors. All rights reserved.
       6             : //
       7             : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8             : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9             : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10             : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11             : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12             : //
      13             : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14             : // provided that the following conditions are met:
      15             : //
      16             : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17             : //     conditions and the following disclaimer.
      18             : //
      19             : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20             : //     conditions and the following disclaimer in the documentation and/or other materials
      21             : //     provided with the distribution.
      22             : //
      23             : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24             : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25             : //     used to endorse or promote products derived from this software without specific prior
      26             : //     written permission.
      27             : //
      28             : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29             : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30             : //     reference solely to the software portion of its product, Licensee must refer to the
      31             : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32             : //     obtained under this License and may not use a different name for the software. Except as
      33             : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34             : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35             : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36             : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37             : //
      38             : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39             : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40             : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41             : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42             : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43             : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44             : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45             : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46             : // POSSIBILITY OF SUCH DAMAGE.
      47             : 
      48             : // C++ Headers
      49             : #include <cmath>
      50             : 
      51             : // ObjexxFCL Headers
      52             : #include <ObjexxFCL/Array.functions.hh>
      53             : #include <ObjexxFCL/Fmath.hh>
      54             : 
      55             : // EnergyPlus Headers
      56             : #include <EnergyPlus/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             :     const char *fluidNameSteam = "STEAM";
      91             : 
      92           8 :     BoilerSpecs *BoilerSpecs::factory(EnergyPlusData &state, std::string const &objectName)
      93             :     {
      94             :         // Process the input data for boilers if it hasn't been done already
      95           8 :         if (state.dataBoilerSteam->getSteamBoilerInput) {
      96           8 :             GetBoilerInput(state);
      97           8 :             state.dataBoilerSteam->getSteamBoilerInput = false;
      98             :         }
      99             : 
     100             :         // Now look for this particular pipe in the list
     101           8 :         auto myBoiler = std::find_if(state.dataBoilerSteam->Boiler.begin(),
     102           8 :                                      state.dataBoilerSteam->Boiler.end(),
     103           8 :                                      [&objectName](const BoilerSpecs &boiler) { return boiler.Name == objectName; });
     104           8 :         if (myBoiler != state.dataBoilerSteam->Boiler.end()) return myBoiler;
     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      109628 :     void BoilerSpecs::simulate(
     113             :         EnergyPlusData &state, [[maybe_unused]] const PlantLocation &calledFromLocation, bool FirstHVACIteration, Real64 &CurLoad, bool RunFlag)
     114             :     {
     115      109628 :         this->initialize(state);
     116      109628 :         auto &sim_component(DataPlant::CompData::getPlantComponent(state, this->plantLoc));
     117      109628 :         this->calculate(state, CurLoad, RunFlag, sim_component.FlowCtrl);
     118      109628 :         this->update(state, CurLoad, RunFlag, FirstHVACIteration);
     119      109628 :     }
     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             : 
     152             :         // LOCAL VARIABLES
     153             :         int BoilerNum;       // boiler identifier
     154             :         int NumAlphas;       // Number of elements in the alpha array
     155             :         int NumNums;         // Number of elements in the numeric array
     156             :         int IOStat;          // IO Status when calling get input subroutine
     157             :         int SteamFluidIndex; // Fluid Index for Steam
     158           8 :         bool ErrorsFound(false);
     159             : 
     160           8 :         SteamFluidIndex = 0;
     161           8 :         state.dataIPShortCut->cCurrentModuleObject = "Boiler:Steam";
     162           8 :         int numBoilers = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, state.dataIPShortCut->cCurrentModuleObject);
     163             : 
     164           8 :         if (numBoilers <= 0) {
     165           0 :             ShowSevereError(state, format("No {} equipment specified in input file", state.dataIPShortCut->cCurrentModuleObject));
     166           0 :             ErrorsFound = true;
     167             :         }
     168             : 
     169             :         // See if load distribution manager has already gotten the input
     170           8 :         if (allocated(state.dataBoilerSteam->Boiler)) return;
     171             : 
     172             :         // Boiler will have fuel input to it , that is it !
     173           8 :         state.dataBoilerSteam->Boiler.allocate(numBoilers);
     174             : 
     175             :         // LOAD ARRAYS WITH CURVE FIT Boiler DATA
     176          16 :         for (BoilerNum = 1; BoilerNum <= numBoilers; ++BoilerNum) {
     177          24 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     178           8 :                                                                      state.dataIPShortCut->cCurrentModuleObject,
     179             :                                                                      BoilerNum,
     180           8 :                                                                      state.dataIPShortCut->cAlphaArgs,
     181             :                                                                      NumAlphas,
     182           8 :                                                                      state.dataIPShortCut->rNumericArgs,
     183             :                                                                      NumNums,
     184             :                                                                      IOStat,
     185             :                                                                      _,
     186             :                                                                      _,
     187           8 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
     188           8 :                                                                      state.dataIPShortCut->cNumericFieldNames);
     189             :             // ErrorsFound will be set to True if problem was found, left untouched otherwise
     190           8 :             GlobalNames::VerifyUniqueBoilerName(state,
     191           8 :                                                 state.dataIPShortCut->cCurrentModuleObject,
     192           8 :                                                 state.dataIPShortCut->cAlphaArgs(1),
     193             :                                                 ErrorsFound,
     194          16 :                                                 state.dataIPShortCut->cCurrentModuleObject + " Name");
     195           8 :             auto &thisBoiler = state.dataBoilerSteam->Boiler(BoilerNum);
     196           8 :             thisBoiler.Name = state.dataIPShortCut->cAlphaArgs(1);
     197             : 
     198             :             // Validate fuel type input
     199           8 :             thisBoiler.FuelType = static_cast<Constant::eFuel>(getEnumValue(Constant::eFuelNamesUC, state.dataIPShortCut->cAlphaArgs(2)));
     200             : 
     201             :             // INPUTS from the IDF file
     202           8 :             thisBoiler.BoilerMaxOperPress = state.dataIPShortCut->rNumericArgs(1);
     203           8 :             if (thisBoiler.BoilerMaxOperPress < 1e5) {
     204           0 :                 ShowWarningMessage(state, format("{}=\"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     205           0 :                 ShowContinueError(state, "Field: Maximum Operation Pressure units are Pa. Verify units.");
     206             :             }
     207           8 :             thisBoiler.NomEffic = state.dataIPShortCut->rNumericArgs(2);
     208           8 :             thisBoiler.TempUpLimitBoilerOut = state.dataIPShortCut->rNumericArgs(3);
     209           8 :             thisBoiler.NomCap = state.dataIPShortCut->rNumericArgs(4);
     210           8 :             if (thisBoiler.NomCap == DataSizing::AutoSize) {
     211           8 :                 thisBoiler.NomCapWasAutoSized = true;
     212             :             }
     213           8 :             thisBoiler.MinPartLoadRat = state.dataIPShortCut->rNumericArgs(5);
     214           8 :             thisBoiler.MaxPartLoadRat = state.dataIPShortCut->rNumericArgs(6);
     215           8 :             thisBoiler.OptPartLoadRat = state.dataIPShortCut->rNumericArgs(7);
     216           8 :             thisBoiler.FullLoadCoef[0] = state.dataIPShortCut->rNumericArgs(8);
     217           8 :             thisBoiler.FullLoadCoef[1] = state.dataIPShortCut->rNumericArgs(9);
     218           8 :             thisBoiler.FullLoadCoef[2] = state.dataIPShortCut->rNumericArgs(10);
     219           8 :             thisBoiler.SizFac = state.dataIPShortCut->rNumericArgs(11);
     220           8 :             if (thisBoiler.SizFac <= 0.0) thisBoiler.SizFac = 1.0;
     221             : 
     222           8 :             if ((state.dataIPShortCut->rNumericArgs(8) + state.dataIPShortCut->rNumericArgs(9) + state.dataIPShortCut->rNumericArgs(10)) == 0.0) {
     223           0 :                 ShowSevereError(state,
     224           0 :                                 format("{}{}=\"{}\",", RoutineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     225           0 :                 ShowContinueError(state, " Sum of fuel use curve coefficients = 0.0");
     226           0 :                 ErrorsFound = true;
     227             :             }
     228             : 
     229           8 :             if (state.dataIPShortCut->rNumericArgs(5) < 0.0) {
     230           0 :                 ShowSevereError(state,
     231           0 :                                 format("{}{}=\"{}\",", RoutineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     232           0 :                 ShowContinueError(state,
     233           0 :                                   format("Invalid {}={:.3R}", state.dataIPShortCut->cNumericFieldNames(5), state.dataIPShortCut->rNumericArgs(5)));
     234           0 :                 ErrorsFound = true;
     235             :             }
     236             : 
     237           8 :             if (state.dataIPShortCut->rNumericArgs(3) == 0.0) {
     238           0 :                 ShowSevereError(state,
     239           0 :                                 format("{}{}=\"{}\",", RoutineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     240           0 :                 ShowContinueError(state,
     241           0 :                                   format("Invalid {}={:.3R}", state.dataIPShortCut->cNumericFieldNames(3), state.dataIPShortCut->rNumericArgs(3)));
     242           0 :                 ErrorsFound = true;
     243             :             }
     244           8 :             thisBoiler.BoilerInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
     245           8 :                                                                                 state.dataIPShortCut->cAlphaArgs(3),
     246             :                                                                                 ErrorsFound,
     247             :                                                                                 DataLoopNode::ConnectionObjectType::BoilerSteam,
     248           8 :                                                                                 state.dataIPShortCut->cAlphaArgs(1),
     249             :                                                                                 DataLoopNode::NodeFluidType::Steam,
     250             :                                                                                 DataLoopNode::ConnectionType::Inlet,
     251             :                                                                                 NodeInputManager::CompFluidStream::Primary,
     252             :                                                                                 DataLoopNode::ObjectIsNotParent);
     253           8 :             thisBoiler.BoilerOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
     254           8 :                                                                                  state.dataIPShortCut->cAlphaArgs(4),
     255             :                                                                                  ErrorsFound,
     256             :                                                                                  DataLoopNode::ConnectionObjectType::BoilerSteam,
     257           8 :                                                                                  state.dataIPShortCut->cAlphaArgs(1),
     258             :                                                                                  DataLoopNode::NodeFluidType::Steam,
     259             :                                                                                  DataLoopNode::ConnectionType::Outlet,
     260             :                                                                                  NodeInputManager::CompFluidStream::Primary,
     261             :                                                                                  DataLoopNode::ObjectIsNotParent);
     262          16 :             BranchNodeConnections::TestCompSet(state,
     263           8 :                                                state.dataIPShortCut->cCurrentModuleObject,
     264           8 :                                                state.dataIPShortCut->cAlphaArgs(1),
     265           8 :                                                state.dataIPShortCut->cAlphaArgs(3),
     266           8 :                                                state.dataIPShortCut->cAlphaArgs(4),
     267             :                                                "Hot Steam Nodes");
     268             : 
     269           8 :             if (SteamFluidIndex == 0 && BoilerNum == 1) {
     270           8 :                 SteamFluidIndex = FluidProperties::GetRefrigNum(state, fluidNameSteam); // Steam is a refrigerant?
     271           8 :                 if (SteamFluidIndex == 0) {
     272           0 :                     ShowSevereError(
     273           0 :                         state, format("{}{}=\"{}\",", RoutineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     274           0 :                     ShowContinueError(state, "Steam Properties not found; Steam Fluid Properties must be included in the input file.");
     275           0 :                     ErrorsFound = true;
     276             :                 }
     277             :             }
     278             : 
     279           8 :             thisBoiler.FluidIndex = SteamFluidIndex;
     280             : 
     281           8 :             if (NumAlphas > 4) {
     282           0 :                 thisBoiler.EndUseSubcategory = state.dataIPShortCut->cAlphaArgs(5);
     283             :             } else {
     284           8 :                 thisBoiler.EndUseSubcategory = "General";
     285             :             }
     286             :         }
     287             : 
     288           8 :         if (ErrorsFound) {
     289           0 :             ShowFatalError(state, format("{}Errors found in processing {} input.", RoutineName, state.dataIPShortCut->cCurrentModuleObject));
     290             :         }
     291             :     }
     292             : 
     293           8 :     void BoilerSpecs::oneTimeInit(EnergyPlusData &state)
     294             :     {
     295           8 :         bool errFlag = false;
     296          16 :         PlantUtilities::ScanPlantLoopsForObject(
     297           8 :             state, this->Name, DataPlant::PlantEquipmentType::Boiler_Steam, this->plantLoc, errFlag, _, _, _, _, _);
     298           8 :         if (errFlag) {
     299           0 :             ShowFatalError(state, "InitBoiler: Program terminated due to previous condition(s).");
     300             :         }
     301           8 :     }
     302             : 
     303          47 :     void BoilerSpecs::initEachEnvironment(EnergyPlusData &state)
     304             :     {
     305             :         static constexpr std::string_view RoutineName("BoilerSpecs::initEachEnvironment");
     306             : 
     307          47 :         int BoilerInletNode = this->BoilerInletNodeNum;
     308             : 
     309             :         Real64 EnthSteamOutDry =
     310          47 :             FluidProperties::GetSatEnthalpyRefrig(state, fluidNameSteam, this->TempUpLimitBoilerOut, 1.0, this->FluidIndex, RoutineName);
     311             :         Real64 EnthSteamOutWet =
     312          47 :             FluidProperties::GetSatEnthalpyRefrig(state, fluidNameSteam, this->TempUpLimitBoilerOut, 0.0, this->FluidIndex, RoutineName);
     313          47 :         Real64 LatentEnthSteam = EnthSteamOutDry - EnthSteamOutWet;
     314             : 
     315             :         Real64 CpWater =
     316          47 :             FluidProperties::GetSatSpecificHeatRefrig(state, fluidNameSteam, this->TempUpLimitBoilerOut, 0.0, this->FluidIndex, RoutineName);
     317             : 
     318          47 :         this->DesMassFlowRate =
     319          47 :             this->NomCap / (LatentEnthSteam + CpWater * (this->TempUpLimitBoilerOut - state.dataLoopNodes->Node(BoilerInletNode).Temp));
     320             : 
     321          47 :         PlantUtilities::InitComponentNodes(state, 0.0, this->DesMassFlowRate, this->BoilerInletNodeNum, this->BoilerOutletNodeNum);
     322             : 
     323          47 :         this->BoilerPressCheck = 0.0;
     324          47 :         this->FuelUsed = 0.0;
     325          47 :         this->BoilerLoad = 0.0;
     326          47 :         this->BoilerEff = 0.0;
     327          47 :         this->BoilerOutletTemp = 0.0;
     328             : 
     329          50 :         if ((state.dataLoopNodes->Node(this->BoilerOutletNodeNum).TempSetPoint == DataLoopNode::SensedNodeFlagValue) &&
     330           3 :             (state.dataLoopNodes->Node(this->BoilerOutletNodeNum).TempSetPointLo == DataLoopNode::SensedNodeFlagValue)) {
     331           3 :             if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
     332           3 :                 if (!this->MissingSetPointErrDone) {
     333           1 :                     ShowWarningError(state, format("Missing temperature setpoint for Boiler:Steam = {}", this->Name));
     334           1 :                     ShowContinueError(state, " A temperature setpoint is needed at the outlet node of the boiler, use a SetpointManager");
     335           1 :                     ShowContinueError(state, " The overall loop setpoint will be assumed for this boiler. The simulation continues ...");
     336           1 :                     this->MissingSetPointErrDone = true;
     337             :                 }
     338             :             } else {
     339             :                 // need call to EMS to check node
     340           0 :                 bool FatalError = false; // but not really fatal yet, but should be.
     341           0 :                 EMSManager::CheckIfNodeSetPointManagedByEMS(state, this->BoilerOutletNodeNum, HVAC::CtrlVarType::Temp, FatalError);
     342           0 :                 state.dataLoopNodes->NodeSetpointCheck(this->BoilerOutletNodeNum).needsSetpointChecking = false;
     343           0 :                 if (FatalError) {
     344           0 :                     if (!this->MissingSetPointErrDone) {
     345           0 :                         ShowWarningError(state, format("Missing temperature setpoint for LeavingSetpointModulated mode Boiler named {}", this->Name));
     346           0 :                         ShowContinueError(state, " A temperature setpoint is needed at the outlet node of the boiler.");
     347           0 :                         ShowContinueError(state, " Use a Setpoint Manager to establish a setpoint at the boiler outlet node ");
     348           0 :                         ShowContinueError(state, " or use an EMS actuator to establish a setpoint at the boiler outlet node.");
     349           0 :                         ShowContinueError(state, " The overall loop setpoint will be assumed for this boiler. The simulation continues...");
     350           0 :                         this->MissingSetPointErrDone = true;
     351             :                     }
     352             :                 }
     353             :             }
     354           3 :             this->UseLoopSetPoint = true; // this is for backward compatibility and could be removed
     355             :         }
     356          47 :     }
     357             : 
     358      109668 :     void BoilerSpecs::initialize(EnergyPlusData &state) // number of the current electric chiller being simulated
     359             :     {
     360             :         // SUBROUTINE INFORMATION:
     361             :         //       AUTHOR         Rahul Chillar
     362             :         //       DATE WRITTEN   Dec 2004
     363             :         //       RE-ENGINEERED  D. Shirey, rework for plant upgrade
     364             : 
     365             :         // PURPOSE OF THIS SUBROUTINE:
     366             :         // This subroutine is for initializations of the Boiler components
     367             : 
     368             :         // METHODOLOGY EMPLOYED:
     369             :         // Uses the status flags to trigger initializations.
     370             : 
     371             :         // Init more variables
     372      109668 :         if (this->myFlag) {
     373           8 :             this->setupOutputVars(state);
     374           8 :             this->oneTimeInit(state);
     375           8 :             this->myFlag = false;
     376             :         }
     377             : 
     378      109668 :         if (state.dataGlobal->BeginEnvrnFlag && this->myEnvrnFlag && (state.dataPlnt->PlantFirstSizesOkayToFinalize)) {
     379          47 :             this->initEachEnvironment(state);
     380          47 :             this->myEnvrnFlag = false;
     381             :         }
     382      109668 :         if (!state.dataGlobal->BeginEnvrnFlag) {
     383      108708 :             this->myEnvrnFlag = true;
     384             :         }
     385             : 
     386      109668 :         if (this->UseLoopSetPoint) {
     387             :             //  At some point, need to circle back and get from plant data structure instead of node
     388             :             // fix for clumsy old input that worked because loop setpoint was spread.
     389             :             //  could be removed with transition, testing , model change, period of being obsolete.
     390        5366 :             int BoilerOutletNode = this->BoilerOutletNodeNum;
     391        5366 :             switch (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopDemandCalcScheme) {
     392             : 
     393        5366 :             case DataPlant::LoopDemandCalcScheme::SingleSetPoint:
     394        5366 :                 state.dataLoopNodes->Node(BoilerOutletNode).TempSetPoint =
     395        5366 :                     state.dataLoopNodes->Node(state.dataPlnt->PlantLoop(this->plantLoc.loopNum).TempSetPointNodeNum).TempSetPoint;
     396        5366 :                 break;
     397           0 :             case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand:
     398           0 :                 state.dataLoopNodes->Node(BoilerOutletNode).TempSetPointLo =
     399           0 :                     state.dataLoopNodes->Node(state.dataPlnt->PlantLoop(this->plantLoc.loopNum).TempSetPointNodeNum).TempSetPointLo;
     400           0 :                 break;
     401           0 :             default:
     402           0 :                 break;
     403             :             }
     404             :         }
     405      109668 :     }
     406             : 
     407           8 :     void BoilerSpecs::setupOutputVars(EnergyPlusData &state)
     408             :     {
     409           8 :         std::string_view sFuelType = Constant::eFuelNames[static_cast<int>(this->FuelType)];
     410          16 :         SetupOutputVariable(state,
     411             :                             "Boiler Heating Rate",
     412             :                             Constant::Units::W,
     413           8 :                             this->BoilerLoad,
     414             :                             OutputProcessor::TimeStepType::System,
     415             :                             OutputProcessor::StoreType::Average,
     416           8 :                             this->Name);
     417             : 
     418          16 :         SetupOutputVariable(state,
     419             :                             "Boiler Heating Energy",
     420             :                             Constant::Units::J,
     421           8 :                             this->BoilerEnergy,
     422             :                             OutputProcessor::TimeStepType::System,
     423             :                             OutputProcessor::StoreType::Sum,
     424           8 :                             this->Name,
     425             :                             Constant::eResource::EnergyTransfer,
     426             :                             OutputProcessor::Group::Plant,
     427             :                             OutputProcessor::EndUseCat::Boilers);
     428          24 :         SetupOutputVariable(state,
     429          16 :                             format("Boiler {} Rate", sFuelType),
     430             :                             Constant::Units::W,
     431           8 :                             this->FuelUsed,
     432             :                             OutputProcessor::TimeStepType::System,
     433             :                             OutputProcessor::StoreType::Average,
     434           8 :                             this->Name);
     435          24 :         SetupOutputVariable(state,
     436          16 :                             format("Boiler {} Energy", sFuelType),
     437             :                             Constant::Units::J,
     438           8 :                             this->FuelConsumed,
     439             :                             OutputProcessor::TimeStepType::System,
     440             :                             OutputProcessor::StoreType::Sum,
     441           8 :                             this->Name,
     442           8 :                             Constant::eFuel2eResource[(int)this->FuelType],
     443             :                             OutputProcessor::Group::Plant,
     444             :                             OutputProcessor::EndUseCat::Heating,
     445             :                             this->EndUseSubcategory);
     446          16 :         SetupOutputVariable(state,
     447             :                             "Boiler Steam Efficiency",
     448             :                             Constant::Units::None,
     449           8 :                             this->BoilerEff,
     450             :                             OutputProcessor::TimeStepType::System,
     451             :                             OutputProcessor::StoreType::Average,
     452           8 :                             this->Name);
     453          16 :         SetupOutputVariable(state,
     454             :                             "Boiler Steam Inlet Temperature",
     455             :                             Constant::Units::C,
     456           8 :                             this->BoilerInletTemp,
     457             :                             OutputProcessor::TimeStepType::System,
     458             :                             OutputProcessor::StoreType::Average,
     459           8 :                             this->Name);
     460          16 :         SetupOutputVariable(state,
     461             :                             "Boiler Steam Outlet Temperature",
     462             :                             Constant::Units::C,
     463           8 :                             this->BoilerOutletTemp,
     464             :                             OutputProcessor::TimeStepType::System,
     465             :                             OutputProcessor::StoreType::Average,
     466           8 :                             this->Name);
     467          16 :         SetupOutputVariable(state,
     468             :                             "Boiler Steam Mass Flow Rate",
     469             :                             Constant::Units::kg_s,
     470           8 :                             this->BoilerMassFlowRate,
     471             :                             OutputProcessor::TimeStepType::System,
     472             :                             OutputProcessor::StoreType::Average,
     473           8 :                             this->Name);
     474           8 :     }
     475             : 
     476          40 :     void BoilerSpecs::autosize(EnergyPlusData &state)
     477             :     {
     478             : 
     479             :         // SUBROUTINE INFORMATION:
     480             :         //       AUTHOR         Rahul Chillar
     481             :         //       DATE WRITTEN   Dec 2004
     482             :         //       MODIFIED       November 2013 Daeho Kang, add component sizing table entries
     483             : 
     484             :         // PURPOSE OF THIS SUBROUTINE:
     485             :         // This subroutine is for sizing Boiler Components for which capacities and flow rates
     486             :         // have not been specified in the input.
     487             : 
     488             :         // METHODOLOGY EMPLOYED:
     489             :         // Obtains Steam flow rate from the plant sizing array. Calculates nominal capacity from
     490             :         // the hot water flow rate and the hot water loop design delta T.
     491             : 
     492             :         // SUBROUTINE PARAMETER DEFINITIONS:
     493             :         static constexpr std::string_view RoutineName("SizeBoiler");
     494             : 
     495             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     496          40 :         bool ErrorsFound(false); // If errors detected in input
     497          40 :         Real64 tmpNomCap = this->NomCap;
     498          40 :         int PltSizNum = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).PlantSizNum;
     499             : 
     500          40 :         if (PltSizNum > 0) {
     501          40 :             if (state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
     502          32 :                 Real64 SizingTemp = this->TempUpLimitBoilerOut;
     503          32 :                 Real64 SteamDensity = FluidProperties::GetSatDensityRefrig(state, fluidNameSteam, SizingTemp, 1.0, this->FluidIndex, RoutineName);
     504          32 :                 Real64 EnthSteamOutDry = FluidProperties::GetSatEnthalpyRefrig(state, fluidNameSteam, SizingTemp, 1.0, this->FluidIndex, RoutineName);
     505          32 :                 Real64 EnthSteamOutWet = FluidProperties::GetSatEnthalpyRefrig(state, fluidNameSteam, SizingTemp, 0.0, this->FluidIndex, RoutineName);
     506          32 :                 Real64 LatentEnthSteam = EnthSteamOutDry - EnthSteamOutWet;
     507          32 :                 Real64 CpWater = FluidProperties::GetSatSpecificHeatRefrig(state, fluidNameSteam, SizingTemp, 0.0, this->FluidIndex, RoutineName);
     508          32 :                 tmpNomCap = (CpWater * SteamDensity * this->SizFac * state.dataSize->PlantSizData(PltSizNum).DeltaT *
     509          32 :                                  state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate +
     510          32 :                              state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate * SteamDensity * LatentEnthSteam);
     511             :             } else {
     512           8 :                 if (this->NomCapWasAutoSized) tmpNomCap = 0.0;
     513             :             }
     514          40 :             if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
     515           8 :                 if (this->NomCapWasAutoSized) {
     516           8 :                     this->NomCap = tmpNomCap;
     517           8 :                     if (state.dataPlnt->PlantFinalSizesOkayToReport) {
     518           8 :                         BaseSizer::reportSizerOutput(state, "Boiler:Steam", this->Name, "Design Size Nominal Capacity [W]", tmpNomCap);
     519             : 
     520             :                         // Std 229 Boilers new report table
     521           8 :                         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchBoilerType, this->Name, "Boiler:Steam");
     522           8 :                         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchBoilerRefCap, this->Name, this->NomCap);
     523           8 :                         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchBoilerRefEff, this->Name, this->NomEffic);
     524           8 :                         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchBoilerRatedCap, this->Name, this->NomCap);
     525           8 :                         OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchBoilerRatedEff, this->Name, this->NomEffic);
     526          16 :                         OutputReportPredefined::PreDefTableEntry(state,
     527           8 :                                                                  state.dataOutRptPredefined->pdchBoilerPlantloopName,
     528             :                                                                  this->Name,
     529          16 :                                                                  this->plantLoc.loopNum > 0 ? state.dataPlnt->PlantLoop(this->plantLoc.loopNum).Name
     530             :                                                                                             : "N/A");
     531          16 :                         OutputReportPredefined::PreDefTableEntry(state,
     532           8 :                                                                  state.dataOutRptPredefined->pdchBoilerPlantloopBranchName,
     533             :                                                                  this->Name,
     534          16 :                                                                  this->plantLoc.loopNum > 0 ? state.dataPlnt->PlantLoop(this->plantLoc.loopNum)
     535           8 :                                                                                                   .LoopSide(this->plantLoc.loopSideNum)
     536           8 :                                                                                                   .Branch(this->plantLoc.branchNum)
     537           8 :                                                                                                   .Name
     538             :                                                                                             : "N/A");
     539          16 :                         OutputReportPredefined::PreDefTableEntry(
     540           8 :                             state, state.dataOutRptPredefined->pdchBoilerMinPLR, this->Name, this->MinPartLoadRat);
     541          16 :                         OutputReportPredefined::PreDefTableEntry(state,
     542           8 :                                                                  state.dataOutRptPredefined->pdchBoilerFuelType,
     543             :                                                                  this->Name,
     544           8 :                                                                  Constant::eFuelNames[static_cast<int>(this->FuelType)]);
     545          16 :                         OutputReportPredefined::PreDefTableEntry(
     546           8 :                             state, state.dataOutRptPredefined->pdchBoilerParaElecLoad, this->Name, "Not Applicable");
     547             :                     }
     548           8 :                     if (state.dataPlnt->PlantFirstSizesOkayToReport) {
     549           0 :                         BaseSizer::reportSizerOutput(state, "Boiler:Steam", this->Name, "Initial Design Size Nominal Capacity [W]", tmpNomCap);
     550             :                     }
     551             :                 } else { // Hard-sized with sizing data
     552           0 :                     if (this->NomCap > 0.0 && tmpNomCap > 0.0) {
     553           0 :                         Real64 NomCapUser = this->NomCap;
     554           0 :                         if (state.dataPlnt->PlantFinalSizesOkayToReport) {
     555           0 :                             BaseSizer::reportSizerOutput(state,
     556             :                                                          "Boiler:Steam",
     557             :                                                          this->Name,
     558             :                                                          "Design Size Nominal Capacity [W]",
     559             :                                                          tmpNomCap,
     560             :                                                          "User-Specified Nominal Capacity [W]",
     561             :                                                          NomCapUser);
     562             : 
     563             :                             // Std 229 Boilers new report table
     564           0 :                             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchBoilerType, this->Name, "Boiler:Steam");
     565           0 :                             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchBoilerRefCap, this->Name, this->NomCap);
     566           0 :                             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchBoilerRefEff, this->Name, this->NomEffic);
     567           0 :                             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchBoilerRatedCap, this->Name, this->NomCap);
     568           0 :                             OutputReportPredefined::PreDefTableEntry(
     569           0 :                                 state, state.dataOutRptPredefined->pdchBoilerRatedEff, this->Name, this->NomEffic);
     570           0 :                             OutputReportPredefined::PreDefTableEntry(
     571             :                                 state,
     572           0 :                                 state.dataOutRptPredefined->pdchBoilerPlantloopName,
     573             :                                 this->Name,
     574           0 :                                 this->plantLoc.loopNum > 0 ? state.dataPlnt->PlantLoop(this->plantLoc.loopNum).Name : "N/A");
     575           0 :                             OutputReportPredefined::PreDefTableEntry(state,
     576           0 :                                                                      state.dataOutRptPredefined->pdchBoilerPlantloopBranchName,
     577             :                                                                      this->Name,
     578           0 :                                                                      this->plantLoc.loopNum > 0 ? state.dataPlnt->PlantLoop(this->plantLoc.loopNum)
     579           0 :                                                                                                       .LoopSide(this->plantLoc.loopSideNum)
     580           0 :                                                                                                       .Branch(this->plantLoc.branchNum)
     581           0 :                                                                                                       .Name
     582             :                                                                                                 : "N/A");
     583           0 :                             OutputReportPredefined::PreDefTableEntry(
     584           0 :                                 state, state.dataOutRptPredefined->pdchBoilerMinPLR, this->Name, this->MinPartLoadRat);
     585           0 :                             OutputReportPredefined::PreDefTableEntry(state,
     586           0 :                                                                      state.dataOutRptPredefined->pdchBoilerFuelType,
     587             :                                                                      this->Name,
     588           0 :                                                                      Constant::eFuelNames[static_cast<int>(this->FuelType)]);
     589           0 :                             OutputReportPredefined::PreDefTableEntry(
     590           0 :                                 state, state.dataOutRptPredefined->pdchBoilerParaElecLoad, this->Name, "Not Applicable");
     591             : 
     592           0 :                             if (state.dataGlobal->DisplayExtraWarnings) {
     593           0 :                                 if ((std::abs(tmpNomCap - NomCapUser) / NomCapUser) > state.dataSize->AutoVsHardSizingThreshold) {
     594           0 :                                     ShowMessage(state, format("SizePump: Potential issue with equipment sizing for {}", this->Name));
     595           0 :                                     ShowContinueError(state, format("User-Specified Nominal Capacity of {:.2R} [W]", NomCapUser));
     596           0 :                                     ShowContinueError(state, format("differs from Design Size Nominal Capacity of {:.2R} [W]", tmpNomCap));
     597           0 :                                     ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
     598           0 :                                     ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
     599             :                                 }
     600             :                             }
     601             :                         }
     602             :                     }
     603             :                 }
     604             :             }
     605             :         } else {
     606           0 :             if (this->NomCapWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
     607           0 :                 ShowSevereError(state, "Autosizing of Boiler nominal capacity requires a loop Sizing:Plant object");
     608           0 :                 ShowContinueError(state, format("Occurs in Boiler:Steam object={}", this->Name));
     609           0 :                 ErrorsFound = true;
     610             :             }
     611           0 :             if (!this->NomCapWasAutoSized && this->NomCap > 0.0 && state.dataPlnt->PlantFinalSizesOkayToReport) {
     612           0 :                 BaseSizer::reportSizerOutput(state, "Boiler:Steam", this->Name, "User-Specified Nominal Capacity [W]", this->NomCap);
     613             :             }
     614             :         }
     615             : 
     616          40 :         if (state.dataPlnt->PlantFinalSizesOkayToReport) {
     617             :             // create predefined report
     618           8 :             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchMechType, this->Name, "Boiler:Steam");
     619           8 :             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchMechNomEff, this->Name, this->NomEffic);
     620           8 :             OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchMechNomCap, this->Name, this->NomCap);
     621             :         }
     622             : 
     623          40 :         if (ErrorsFound) {
     624           0 :             ShowFatalError(state, "Preceding sizing errors cause program termination");
     625             :         }
     626          40 :     }
     627             : 
     628      109628 :     void BoilerSpecs::calculate(EnergyPlusData &state,
     629             :                                 Real64 &MyLoad,                                         // W - hot water demand to be met by boiler
     630             :                                 bool const RunFlag,                                     // TRUE if boiler operating
     631             :                                 DataBranchAirLoopPlant::ControlType const EquipFlowCtrl // Flow control mode for the equipment
     632             :     )
     633             :     {
     634             :         // SUBROUTINE INFORMATION:
     635             :         //       AUTHOR         Rahul Chillar
     636             :         //       DATE WRITTEN   Dec 2004
     637             : 
     638             :         // PURPOSE OF THIS SUBROUTINE:
     639             :         // This subroutine calculates the boiler fuel consumption and the associated
     640             :         // hot water demand met by the boiler
     641             : 
     642             :         // METHODOLOGY EMPLOYED:
     643             :         // The model is based on a single combustion efficiency (=1 for electric)
     644             :         // and a second order polynomial fit of performance data to obtain part
     645             :         // load performance
     646             : 
     647             :         // SUBROUTINE PARAMETER DEFINITIONS:
     648             :         static constexpr std::string_view RoutineName("CalcBoilerModel");
     649             : 
     650             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     651      109628 :         Real64 BoilerDeltaTemp(0.0); // C - boiler inlet to outlet temperature difference
     652             :         Real64 CpWater;              // Heat capacity of condensed steam
     653             : 
     654             :         // Loading the variables derived type in to local variables
     655      109628 :         this->BoilerLoad = 0.0;
     656      109628 :         this->BoilerMassFlowRate = 0.0;
     657             : 
     658      109628 :         switch (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopDemandCalcScheme) {
     659      109628 :         case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
     660      109628 :             this->BoilerOutletTemp = state.dataLoopNodes->Node(this->BoilerOutletNodeNum).TempSetPoint;
     661      109628 :         } break;
     662           0 :         case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
     663           0 :             this->BoilerOutletTemp = state.dataLoopNodes->Node(this->BoilerOutletNodeNum).TempSetPointLo;
     664           0 :         } break;
     665           0 :         default:
     666           0 :             break;
     667             :         }
     668             :         // If the specified load is 0.0 or the boiler should not run then we leave this subroutine.Before leaving
     669             :         // if the component control is SERIESACTIVE we set the component flow to inlet flow so that flow resolver
     670             :         // will not shut down the branch
     671      109628 :         if (MyLoad <= 0.0 || !RunFlag) {
     672       76472 :             if (EquipFlowCtrl == DataBranchAirLoopPlant::ControlType::SeriesActive)
     673           0 :                 this->BoilerMassFlowRate = state.dataLoopNodes->Node(this->BoilerInletNodeNum).MassFlowRate;
     674       76472 :             return;
     675             :         }
     676             : 
     677             :         // Set the current load equal to the boiler load
     678       33156 :         this->BoilerLoad = MyLoad;
     679             : 
     680       33156 :         this->BoilerPressCheck = FluidProperties::GetSatPressureRefrig(state, fluidNameSteam, this->BoilerOutletTemp, this->FluidIndex, RoutineName);
     681             : 
     682       33156 :         if ((this->BoilerPressCheck) > this->BoilerMaxOperPress) {
     683           0 :             if (this->PressErrIndex == 0) {
     684           0 :                 ShowSevereError(state, format("Boiler:Steam=\"{}\", Saturation Pressure is greater than Maximum Operating Pressure,", this->Name));
     685           0 :                 ShowContinueError(state, "Lower Input Temperature");
     686           0 :                 ShowContinueError(state, format("Steam temperature=[{:.2R}] C", this->BoilerOutletTemp));
     687           0 :                 ShowContinueError(state, format("Refrigerant Saturation Pressure =[{:.0R}] Pa", this->BoilerPressCheck));
     688             :             }
     689           0 :             ShowRecurringSevereErrorAtEnd(state,
     690           0 :                                           "Boiler:Steam=\"" + this->Name +
     691             :                                               "\", Saturation Pressure is greater than Maximum Operating Pressure..continues",
     692           0 :                                           this->PressErrIndex,
     693           0 :                                           this->BoilerPressCheck,
     694           0 :                                           this->BoilerPressCheck,
     695             :                                           _,
     696             :                                           "[Pa]",
     697             :                                           "[Pa]");
     698             :         }
     699             : 
     700       33156 :         CpWater = FluidProperties::GetSatSpecificHeatRefrig(
     701       33156 :             state, fluidNameSteam, state.dataLoopNodes->Node(this->BoilerInletNodeNum).Temp, 0.0, this->FluidIndex, RoutineName);
     702             : 
     703       33156 :         if (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopSide(this->plantLoc.loopSideNum).FlowLock ==
     704             :             DataPlant::FlowLock::Unlocked) { // TODO: Components shouldn't check FlowLock
     705             :             // Calculate the flow for the boiler
     706             : 
     707       16578 :             switch (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopDemandCalcScheme) {
     708       16578 :             case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
     709       16578 :                 BoilerDeltaTemp =
     710       16578 :                     state.dataLoopNodes->Node(this->BoilerOutletNodeNum).TempSetPoint - state.dataLoopNodes->Node(this->BoilerInletNodeNum).Temp;
     711       16578 :             } break;
     712           0 :             default: { // DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand
     713           0 :                 BoilerDeltaTemp =
     714           0 :                     state.dataLoopNodes->Node(this->BoilerOutletNodeNum).TempSetPointLo - state.dataLoopNodes->Node(this->BoilerInletNodeNum).Temp;
     715           0 :             } break;
     716             :             }
     717       16578 :             this->BoilerOutletTemp = BoilerDeltaTemp + state.dataLoopNodes->Node(this->BoilerInletNodeNum).Temp;
     718             : 
     719             :             Real64 const EnthSteamOutDry =
     720       16578 :                 FluidProperties::GetSatEnthalpyRefrig(state, fluidNameSteam, this->BoilerOutletTemp, 1.0, this->FluidIndex, RoutineName);
     721             :             Real64 const EnthSteamOutWet =
     722       16578 :                 FluidProperties::GetSatEnthalpyRefrig(state, fluidNameSteam, this->BoilerOutletTemp, 0.0, this->FluidIndex, RoutineName);
     723       16578 :             Real64 const LatentEnthSteam = EnthSteamOutDry - EnthSteamOutWet;
     724       16578 :             this->BoilerMassFlowRate = this->BoilerLoad / (LatentEnthSteam + (CpWater * BoilerDeltaTemp));
     725             : 
     726       16578 :             PlantUtilities::SetComponentFlowRate(
     727       16578 :                 state, this->BoilerMassFlowRate, this->BoilerInletNodeNum, this->BoilerOutletNodeNum, this->plantLoc);
     728             : 
     729             :         } else { // If FlowLock is True
     730             :             // Set the boiler flow rate from inlet node and then check performance
     731       16578 :             this->BoilerMassFlowRate = state.dataLoopNodes->Node(this->BoilerInletNodeNum).MassFlowRate;
     732             :             // Assume that it can meet the setpoint
     733       16578 :             switch (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopDemandCalcScheme) {
     734       16578 :             case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
     735       16578 :                 BoilerDeltaTemp =
     736       16578 :                     state.dataLoopNodes->Node(this->BoilerOutletNodeNum).TempSetPoint - state.dataLoopNodes->Node(this->BoilerInletNodeNum).Temp;
     737       16578 :             } break;
     738           0 :             case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
     739           0 :                 BoilerDeltaTemp =
     740           0 :                     state.dataLoopNodes->Node(this->BoilerOutletNodeNum).TempSetPointLo - state.dataLoopNodes->Node(this->BoilerInletNodeNum).Temp;
     741           0 :             } break;
     742           0 :             default:
     743           0 :                 break;
     744             :             }
     745             :             // If boiler outlet temp is already greater than setpoint than it does not need to operate this iteration
     746       16578 :             if (BoilerDeltaTemp < 0.0) {
     747           2 :                 switch (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopDemandCalcScheme) {
     748           2 :                 case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
     749           2 :                     this->BoilerOutletTemp = state.dataLoopNodes->Node(this->BoilerOutletNodeNum).TempSetPoint;
     750           2 :                 } 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             :                 Real64 const EnthSteamOutDry =
     758           2 :                     FluidProperties::GetSatEnthalpyRefrig(state, fluidNameSteam, this->BoilerOutletTemp, 1.0, this->FluidIndex, RoutineName);
     759             :                 Real64 const EnthSteamOutWet =
     760           2 :                     FluidProperties::GetSatEnthalpyRefrig(state, fluidNameSteam, this->BoilerOutletTemp, 0.0, this->FluidIndex, RoutineName);
     761           2 :                 Real64 const LatentEnthSteam = EnthSteamOutDry - EnthSteamOutWet;
     762           2 :                 this->BoilerLoad = (this->BoilerMassFlowRate * LatentEnthSteam);
     763             : 
     764             :             } else {
     765       16576 :                 switch (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopDemandCalcScheme) {
     766       16576 :                 case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
     767       16576 :                     this->BoilerOutletTemp = state.dataLoopNodes->Node(this->BoilerOutletNodeNum).TempSetPoint;
     768       16576 :                 } break;
     769           0 :                 case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
     770           0 :                     this->BoilerOutletTemp = state.dataLoopNodes->Node(this->BoilerOutletNodeNum).TempSetPointLo;
     771           0 :                 } break;
     772           0 :                 default:
     773           0 :                     break;
     774             :                 }
     775             : 
     776             :                 Real64 const EnthSteamOutDry =
     777       16576 :                     FluidProperties::GetSatEnthalpyRefrig(state, fluidNameSteam, this->BoilerOutletTemp, 1.0, this->FluidIndex, RoutineName);
     778             :                 Real64 const EnthSteamOutWet =
     779       16576 :                     FluidProperties::GetSatEnthalpyRefrig(state, fluidNameSteam, this->BoilerOutletTemp, 0.0, this->FluidIndex, RoutineName);
     780       16576 :                 Real64 const LatentEnthSteam = EnthSteamOutDry - EnthSteamOutWet;
     781       16576 :                 this->BoilerLoad =
     782       16576 :                     std::abs(this->BoilerMassFlowRate * LatentEnthSteam) + std::abs(this->BoilerMassFlowRate * CpWater * BoilerDeltaTemp);
     783             :             }
     784             : 
     785             :             // If load exceeds the distributed load set to the distributed load
     786       16578 :             if (this->BoilerLoad > MyLoad) {
     787           2 :                 this->BoilerLoad = MyLoad;
     788             : 
     789             :                 // Reset later , here just for calculating latent heat
     790           2 :                 switch (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopDemandCalcScheme) {
     791           2 :                 case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
     792           2 :                     this->BoilerOutletTemp = state.dataLoopNodes->Node(this->BoilerOutletNodeNum).TempSetPoint;
     793           2 :                 } break;
     794           0 :                 case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
     795           0 :                     this->BoilerOutletTemp = state.dataLoopNodes->Node(this->BoilerOutletNodeNum).TempSetPointLo;
     796           0 :                 } break;
     797           0 :                 default:
     798           0 :                     break;
     799             :                 }
     800             : 
     801             :                 Real64 const EnthSteamOutDry =
     802           2 :                     FluidProperties::GetSatEnthalpyRefrig(state, fluidNameSteam, this->BoilerOutletTemp, 1.0, this->FluidIndex, RoutineName);
     803             :                 Real64 const EnthSteamOutWet =
     804           2 :                     FluidProperties::GetSatEnthalpyRefrig(state, fluidNameSteam, this->BoilerOutletTemp, 0.0, this->FluidIndex, RoutineName);
     805           2 :                 Real64 const LatentEnthSteam = EnthSteamOutDry - EnthSteamOutWet;
     806           2 :                 BoilerDeltaTemp = this->BoilerOutletTemp - state.dataLoopNodes->Node(this->BoilerInletNodeNum).Temp;
     807           2 :                 this->BoilerMassFlowRate = this->BoilerLoad / (LatentEnthSteam + CpWater * BoilerDeltaTemp);
     808             : 
     809           2 :                 PlantUtilities::SetComponentFlowRate(
     810           2 :                     state, this->BoilerMassFlowRate, this->BoilerInletNodeNum, this->BoilerOutletNodeNum, this->plantLoc);
     811             :             }
     812             : 
     813             :             // Checks Boiler Load on the basis of the machine limits.
     814       16578 :             if (this->BoilerLoad > this->NomCap) {
     815           0 :                 if (this->BoilerMassFlowRate > DataBranchAirLoopPlant::MassFlowTolerance) {
     816           0 :                     this->BoilerLoad = this->NomCap;
     817             : 
     818             :                     Real64 const EnthSteamOutDry =
     819           0 :                         FluidProperties::GetSatEnthalpyRefrig(state, fluidNameSteam, this->BoilerOutletTemp, 1.0, this->FluidIndex, RoutineName);
     820             :                     Real64 const EnthSteamOutWet =
     821           0 :                         FluidProperties::GetSatEnthalpyRefrig(state, fluidNameSteam, this->BoilerOutletTemp, 0.0, this->FluidIndex, RoutineName);
     822           0 :                     Real64 const LatentEnthSteam = EnthSteamOutDry - EnthSteamOutWet;
     823           0 :                     BoilerDeltaTemp = this->BoilerOutletTemp - state.dataLoopNodes->Node(this->BoilerInletNodeNum).Temp;
     824           0 :                     this->BoilerMassFlowRate = this->BoilerLoad / (LatentEnthSteam + CpWater * BoilerDeltaTemp);
     825             : 
     826           0 :                     PlantUtilities::SetComponentFlowRate(
     827           0 :                         state, this->BoilerMassFlowRate, this->BoilerInletNodeNum, this->BoilerOutletNodeNum, this->plantLoc);
     828             :                 } else {
     829           0 :                     this->BoilerLoad = 0.0;
     830           0 :                     this->BoilerOutletTemp = state.dataLoopNodes->Node(this->BoilerInletNodeNum).Temp;
     831             :                 }
     832             :             }
     833             : 
     834             :         } // End of the FlowLock If block
     835             : 
     836             :         // Limit BoilerOutletTemp.  If > max temp, trip boiler.
     837       33156 :         if (this->BoilerOutletTemp > this->TempUpLimitBoilerOut) {
     838           0 :             this->BoilerLoad = 0.0;
     839           0 :             this->BoilerOutletTemp = state.dataLoopNodes->Node(this->BoilerInletNodeNum).Temp;
     840             :             //  Does BoilerMassFlowRate need to be set????
     841             :         }
     842             : 
     843       33156 :         Real64 OperPLR = this->BoilerLoad / this->NomCap;
     844       33156 :         OperPLR = min(OperPLR, this->MaxPartLoadRat);
     845       33156 :         OperPLR = max(OperPLR, this->MinPartLoadRat);
     846       33156 :         Real64 TheorFuelUse = this->BoilerLoad / this->NomEffic;
     847             : 
     848             :         // Calculate fuel used
     849       33156 :         this->FuelUsed = TheorFuelUse / (this->FullLoadCoef[0] + this->FullLoadCoef[1] * OperPLR + this->FullLoadCoef[2] * pow_2(OperPLR));
     850             :         // Calculate boiler efficiency
     851       33156 :         this->BoilerEff = this->BoilerLoad / this->FuelUsed;
     852             :     }
     853             : 
     854             :     // Beginning of Record Keeping subroutines for the BOILER:SIMPLE Module
     855             : 
     856      109628 :     void BoilerSpecs::update(EnergyPlusData &state,
     857             :                              Real64 const MyLoad,                           // boiler operating load
     858             :                              bool const RunFlag,                            // boiler on when TRUE
     859             :                              [[maybe_unused]] bool const FirstHVACIteration // TRUE if First iteration of simulation
     860             :     )
     861             :     {
     862             :         // SUBROUTINE INFORMATION:
     863             :         //       AUTHOR         Rahul Chillar
     864             :         //       DATE WRITTEN   Dec 2004
     865             : 
     866             :         // PURPOSE OF THIS SUBROUTINE:
     867             :         // Boiler simulation reporting
     868             : 
     869      109628 :         Real64 ReportingConstant = state.dataHVACGlobal->TimeStepSysSec;
     870      109628 :         int BoilerInletNode = this->BoilerInletNodeNum;
     871      109628 :         int BoilerOutletNode = this->BoilerOutletNodeNum;
     872             : 
     873      109628 :         if (MyLoad <= 0.0 || !RunFlag) {
     874             :             // set node temperatures
     875       76472 :             PlantUtilities::SafeCopyPlantNode(state, BoilerInletNode, BoilerOutletNode);
     876       76472 :             state.dataLoopNodes->Node(BoilerOutletNode).Temp = state.dataLoopNodes->Node(BoilerInletNode).Temp;
     877       76472 :             this->BoilerOutletTemp = state.dataLoopNodes->Node(BoilerInletNode).Temp;
     878       76472 :             this->BoilerLoad = 0.0;
     879       76472 :             this->FuelUsed = 0.0;
     880       76472 :             this->BoilerEff = 0.0;
     881       76472 :             state.dataLoopNodes->Node(BoilerInletNode).Press = this->BoilerPressCheck;
     882       76472 :             state.dataLoopNodes->Node(BoilerOutletNode).Press = state.dataLoopNodes->Node(BoilerInletNode).Press;
     883       76472 :             state.dataLoopNodes->Node(BoilerInletNode).Quality = 0.0;
     884       76472 :             state.dataLoopNodes->Node(BoilerOutletNode).Quality = state.dataLoopNodes->Node(BoilerInletNode).Quality;
     885             : 
     886             :         } else {
     887             :             // set node temperatures
     888       33156 :             PlantUtilities::SafeCopyPlantNode(state, BoilerInletNode, BoilerOutletNode);
     889       33156 :             state.dataLoopNodes->Node(BoilerOutletNode).Temp = this->BoilerOutletTemp;
     890       33156 :             state.dataLoopNodes->Node(BoilerInletNode).Press = this->BoilerPressCheck; //???
     891       33156 :             state.dataLoopNodes->Node(BoilerOutletNode).Press = state.dataLoopNodes->Node(BoilerInletNode).Press;
     892       33156 :             state.dataLoopNodes->Node(BoilerOutletNode).Quality = 1.0; // Model assumes saturated steam exiting the boiler
     893             :         }
     894             : 
     895      109628 :         this->BoilerInletTemp = state.dataLoopNodes->Node(BoilerInletNode).Temp;
     896      109628 :         this->BoilerMassFlowRate = state.dataLoopNodes->Node(BoilerOutletNode).MassFlowRate;
     897      109628 :         this->BoilerEnergy = this->BoilerLoad * ReportingConstant;
     898      109628 :         this->FuelConsumed = this->FuelUsed * ReportingConstant;
     899      109628 :     }
     900             : 
     901             : } // namespace BoilerSteam
     902             : 
     903             : } // namespace EnergyPlus

Generated by: LCOV version 1.14