LCOV - code coverage report
Current view: top level - EnergyPlus - OutsideEnergySources.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 241 281 85.8 %
Date: 2024-08-23 23:50:59 Functions: 9 10 90.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             : #include <iostream>
      51             : #include <string>
      52             : 
      53             : // ObjexxFCL Headers
      54             : #include <ObjexxFCL/Array.functions.hh>
      55             : #include <ObjexxFCL/Fmath.hh>
      56             : 
      57             : // EnergyPlus Headers
      58             : #include <EnergyPlus/Autosizing/Base.hh>
      59             : #include <EnergyPlus/BranchNodeConnections.hh>
      60             : #include <EnergyPlus/Data/EnergyPlusData.hh>
      61             : #include <EnergyPlus/DataEnvironment.hh>
      62             : #include <EnergyPlus/DataHVACGlobals.hh>
      63             : #include <EnergyPlus/DataIPShortCuts.hh>
      64             : #include <EnergyPlus/DataLoopNode.hh>
      65             : #include <EnergyPlus/DataSizing.hh>
      66             : #include <EnergyPlus/FluidProperties.hh>
      67             : #include <EnergyPlus/General.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/OutsideEnergySources.hh>
      73             : #include <EnergyPlus/Plant/DataPlant.hh>
      74             : #include <EnergyPlus/PlantUtilities.hh>
      75             : #include <EnergyPlus/ScheduleManager.hh>
      76             : #include <EnergyPlus/UtilityRoutines.hh>
      77             : 
      78             : namespace EnergyPlus::OutsideEnergySources {
      79             : 
      80             : // MODULE INFORMATION:
      81             : //       AUTHOR         Dan Fisher
      82             : //       DATE WRITTEN   Unknown
      83             : //       MODIFIED       na
      84             : //       RE-ENGINEERED  Brent Griffith, Sept 2010, revised plant interactions.
      85             : 
      86             : // PURPOSE OF THIS MODULE:
      87             : // Module containing the routines dealing with the OutsideEnergySources
      88             : 
      89         278 : PlantComponent *OutsideEnergySourceSpecs::factory(EnergyPlusData &state, DataPlant::PlantEquipmentType objectType, std::string_view objectName)
      90             : {
      91             :     // Process the input data for outside energy sources if it hasn't been done already
      92         278 :     if (state.dataOutsideEnergySrcs->SimOutsideEnergyGetInputFlag) {
      93         159 :         GetOutsideEnergySourcesInput(state);
      94         159 :         state.dataOutsideEnergySrcs->SimOutsideEnergyGetInputFlag = false;
      95             :     }
      96             :     // Now look for this particular pipe in the list
      97         397 :     for (auto &source : state.dataOutsideEnergySrcs->EnergySource) {
      98         397 :         if (source.EnergyType == objectType && source.Name == objectName) {
      99         278 :             return &source;
     100             :         }
     101             :     }
     102             :     // If we didn't find it, fatal
     103             :     ShowFatalError(state, format("OutsideEnergySourceSpecsFactory: Error getting inputs for source named: {}", objectName)); // LCOV_EXCL_LINE
     104             :     // Shut up the compiler
     105             :     return nullptr; // LCOV_EXCL_LINE
     106             : }
     107             : 
     108     7036517 : void OutsideEnergySourceSpecs::simulate(EnergyPlusData &state,
     109             :                                         [[maybe_unused]] const PlantLocation &calledFromLocation,
     110             :                                         [[maybe_unused]] bool FirstHVACIteration,
     111             :                                         Real64 &CurLoad,
     112             :                                         bool RunFlag)
     113             : {
     114     7036517 :     this->initialize(state, CurLoad);
     115     7036517 :     this->calculate(state, RunFlag, CurLoad);
     116     7036517 : }
     117             : 
     118        1392 : void OutsideEnergySourceSpecs::onInitLoopEquip(EnergyPlusData &state, const PlantLocation &)
     119             : {
     120        1392 :     this->initialize(state, 0.0);
     121        1392 :     this->size(state);
     122        1392 : }
     123             : 
     124        1392 : void OutsideEnergySourceSpecs::getDesignCapacities([[maybe_unused]] EnergyPlusData &state,
     125             :                                                    [[maybe_unused]] const PlantLocation &calledFromLocation,
     126             :                                                    Real64 &MaxLoad,
     127             :                                                    Real64 &MinLoad,
     128             :                                                    Real64 &OptLoad)
     129             : {
     130        1392 :     MinLoad = 0.0;
     131        1392 :     MaxLoad = this->NomCap;
     132        1392 :     OptLoad = this->NomCap;
     133        1392 : }
     134             : 
     135         159 : void GetOutsideEnergySourcesInput(EnergyPlusData &state)
     136             : {
     137             :     // SUBROUTINE INFORMATION:
     138             :     //       AUTHOR         Dan Fisher
     139             :     //       DATE WRITTEN   April 1998
     140             :     //       MODIFIED       May 2010; Edwin Lee; Linda Lawrie (consolidation)
     141             :     //                      June 2022, Dareum Nam, Add DistrictHeatingSteam
     142             :     //       RE-ENGINEERED  na
     143             : 
     144             :     // PURPOSE OF THIS SUBROUTINE:
     145             :     // This routine obtains the input data puts it into the
     146             :     // component arrays. Data items in the component arrays
     147             :     // are initialized. Output variables are set up.
     148             : 
     149             :     // GET NUMBER OF ALL EQUIPMENT TYPES
     150         159 :     int const NumDistrictUnitsHeatWater = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "DistrictHeating:Water");
     151         159 :     int const NumDistrictUnitsCool = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "DistrictCooling");
     152         159 :     int const NumDistrictUnitsHeatSteam = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "DistrictHeating:Steam");
     153         159 :     state.dataOutsideEnergySrcs->NumDistrictUnits = NumDistrictUnitsHeatWater + NumDistrictUnitsCool + NumDistrictUnitsHeatSteam;
     154             : 
     155         159 :     if (allocated(state.dataOutsideEnergySrcs->EnergySource)) return;
     156             : 
     157         159 :     state.dataOutsideEnergySrcs->EnergySource.allocate(state.dataOutsideEnergySrcs->NumDistrictUnits);
     158         159 :     state.dataOutsideEnergySrcs->EnergySourceUniqueNames.reserve(static_cast<unsigned>(state.dataOutsideEnergySrcs->NumDistrictUnits));
     159             : 
     160         159 :     bool ErrorsFound(false); // If errors detected in input
     161         159 :     int heatWaterIndex = 0;
     162         159 :     int coolIndex = 0;
     163         159 :     int heatSteamIndex = 0;
     164             : 
     165         437 :     for (int EnergySourceNum = 1; EnergySourceNum <= state.dataOutsideEnergySrcs->NumDistrictUnits; ++EnergySourceNum) {
     166             : 
     167         278 :         std::string nodeNames;
     168             :         DataPlant::PlantEquipmentType EnergyType;
     169             :         DataLoopNode::ConnectionObjectType objType;
     170             :         int thisIndex;
     171         278 :         if (EnergySourceNum <= NumDistrictUnitsHeatWater) {
     172         144 :             state.dataIPShortCut->cCurrentModuleObject = "DistrictHeating:Water";
     173         144 :             objType = DataLoopNode::ConnectionObjectType::DistrictHeatingWater;
     174         144 :             nodeNames = "Hot Water Nodes";
     175         144 :             EnergyType = DataPlant::PlantEquipmentType::PurchHotWater;
     176         144 :             heatWaterIndex++;
     177         144 :             thisIndex = heatWaterIndex;
     178         134 :         } else if (EnergySourceNum > NumDistrictUnitsHeatWater && EnergySourceNum <= NumDistrictUnitsHeatWater + NumDistrictUnitsCool) {
     179         133 :             state.dataIPShortCut->cCurrentModuleObject = "DistrictCooling";
     180         133 :             objType = DataLoopNode::ConnectionObjectType::DistrictCooling;
     181         133 :             nodeNames = "Chilled Water Nodes";
     182         133 :             EnergyType = DataPlant::PlantEquipmentType::PurchChilledWater;
     183         133 :             coolIndex++;
     184         133 :             thisIndex = coolIndex;
     185             :         } else { // EnergySourceNum > NumDistrictUnitsHeatWater + NumDistrictUnitsCool
     186           1 :             state.dataIPShortCut->cCurrentModuleObject = "DistrictHeating:Steam";
     187           1 :             objType = DataLoopNode::ConnectionObjectType::DistrictHeatingSteam;
     188           1 :             nodeNames = "Steam Nodes";
     189           1 :             EnergyType = DataPlant::PlantEquipmentType::PurchSteam;
     190           1 :             heatSteamIndex++;
     191           1 :             thisIndex = heatSteamIndex;
     192             :         }
     193             : 
     194         278 :         int NumAlphas = 0, NumNums = 0, IOStat = 0;
     195         834 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     196         278 :                                                                  state.dataIPShortCut->cCurrentModuleObject,
     197             :                                                                  thisIndex,
     198         278 :                                                                  state.dataIPShortCut->cAlphaArgs,
     199             :                                                                  NumAlphas,
     200         278 :                                                                  state.dataIPShortCut->rNumericArgs,
     201             :                                                                  NumNums,
     202             :                                                                  IOStat,
     203             :                                                                  _,
     204         278 :                                                                  state.dataIPShortCut->lAlphaFieldBlanks,
     205         278 :                                                                  state.dataIPShortCut->cAlphaFieldNames);
     206             : 
     207         278 :         if (EnergySourceNum > 1) {
     208         119 :             GlobalNames::VerifyUniqueInterObjectName(state,
     209         119 :                                                      state.dataOutsideEnergySrcs->EnergySourceUniqueNames,
     210         119 :                                                      state.dataIPShortCut->cAlphaArgs(1),
     211         119 :                                                      state.dataIPShortCut->cCurrentModuleObject,
     212         119 :                                                      state.dataIPShortCut->cAlphaFieldNames(1),
     213             :                                                      ErrorsFound);
     214             :         }
     215         278 :         state.dataOutsideEnergySrcs->EnergySource(EnergySourceNum).Name = state.dataIPShortCut->cAlphaArgs(1);
     216         278 :         if (EnergySourceNum <= NumDistrictUnitsHeatWater + NumDistrictUnitsCool) {
     217         277 :             state.dataOutsideEnergySrcs->EnergySource(EnergySourceNum).InletNodeNum =
     218         554 :                 NodeInputManager::GetOnlySingleNode(state,
     219         277 :                                                     state.dataIPShortCut->cAlphaArgs(2),
     220             :                                                     ErrorsFound,
     221             :                                                     objType,
     222         277 :                                                     state.dataIPShortCut->cAlphaArgs(1),
     223             :                                                     DataLoopNode::NodeFluidType::Water,
     224             :                                                     DataLoopNode::ConnectionType::Inlet,
     225             :                                                     NodeInputManager::CompFluidStream::Primary,
     226             :                                                     DataLoopNode::ObjectIsNotParent);
     227         277 :             state.dataOutsideEnergySrcs->EnergySource(EnergySourceNum).OutletNodeNum =
     228         831 :                 NodeInputManager::GetOnlySingleNode(state,
     229         277 :                                                     state.dataIPShortCut->cAlphaArgs(3),
     230             :                                                     ErrorsFound,
     231             :                                                     objType,
     232         277 :                                                     state.dataIPShortCut->cAlphaArgs(1),
     233             :                                                     DataLoopNode::NodeFluidType::Water,
     234             :                                                     DataLoopNode::ConnectionType::Outlet,
     235             :                                                     NodeInputManager::CompFluidStream::Primary,
     236             :                                                     DataLoopNode::ObjectIsNotParent);
     237             :         } else {
     238           1 :             state.dataOutsideEnergySrcs->EnergySource(EnergySourceNum).InletNodeNum =
     239           2 :                 NodeInputManager::GetOnlySingleNode(state,
     240           1 :                                                     state.dataIPShortCut->cAlphaArgs(2),
     241             :                                                     ErrorsFound,
     242             :                                                     objType,
     243           1 :                                                     state.dataIPShortCut->cAlphaArgs(1),
     244             :                                                     DataLoopNode::NodeFluidType::Steam,
     245             :                                                     DataLoopNode::ConnectionType::Inlet,
     246             :                                                     NodeInputManager::CompFluidStream::Primary,
     247             :                                                     DataLoopNode::ObjectIsNotParent);
     248           1 :             state.dataOutsideEnergySrcs->EnergySource(EnergySourceNum).OutletNodeNum =
     249           3 :                 NodeInputManager::GetOnlySingleNode(state,
     250           1 :                                                     state.dataIPShortCut->cAlphaArgs(3),
     251             :                                                     ErrorsFound,
     252             :                                                     objType,
     253           1 :                                                     state.dataIPShortCut->cAlphaArgs(1),
     254             :                                                     DataLoopNode::NodeFluidType::Steam,
     255             :                                                     DataLoopNode::ConnectionType::Outlet,
     256             :                                                     NodeInputManager::CompFluidStream::Primary,
     257             :                                                     DataLoopNode::ObjectIsNotParent);
     258             :         }
     259         278 :         BranchNodeConnections::TestCompSet(state,
     260         278 :                                            state.dataIPShortCut->cCurrentModuleObject,
     261         278 :                                            state.dataIPShortCut->cAlphaArgs(1),
     262         278 :                                            state.dataIPShortCut->cAlphaArgs(2),
     263         278 :                                            state.dataIPShortCut->cAlphaArgs(3),
     264             :                                            nodeNames);
     265         278 :         state.dataOutsideEnergySrcs->EnergySource(EnergySourceNum).NomCap = state.dataIPShortCut->rNumericArgs(1);
     266         278 :         if (state.dataOutsideEnergySrcs->EnergySource(EnergySourceNum).NomCap == DataSizing::AutoSize) {
     267           8 :             state.dataOutsideEnergySrcs->EnergySource(EnergySourceNum).NomCapWasAutoSized = true;
     268             :         }
     269         278 :         state.dataOutsideEnergySrcs->EnergySource(EnergySourceNum).EnergyTransfer = 0.0;
     270         278 :         state.dataOutsideEnergySrcs->EnergySource(EnergySourceNum).EnergyRate = 0.0;
     271         278 :         state.dataOutsideEnergySrcs->EnergySource(EnergySourceNum).EnergyType = EnergyType;
     272         278 :         if (!state.dataIPShortCut->lAlphaFieldBlanks(4)) {
     273           0 :             state.dataOutsideEnergySrcs->EnergySource(EnergySourceNum).CapFractionSchedNum =
     274           0 :                 ScheduleManager::GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(4));
     275           0 :             if (state.dataOutsideEnergySrcs->EnergySource(EnergySourceNum).CapFractionSchedNum == 0) {
     276           0 :                 ShowSevereError(state,
     277           0 :                                 format("{}=\"{}\", is not valid",
     278           0 :                                        state.dataIPShortCut->cCurrentModuleObject,
     279           0 :                                        state.dataOutsideEnergySrcs->EnergySource(EnergySourceNum).Name));
     280           0 :                 ShowContinueError(state,
     281           0 :                                   format("{}=\"{}\" was not found.", state.dataIPShortCut->cAlphaFieldNames(4), state.dataIPShortCut->cAlphaArgs(4)));
     282           0 :                 ErrorsFound = true;
     283             :             }
     284           0 :             if (!ScheduleManager::CheckScheduleValueMinMax(
     285           0 :                     state, state.dataOutsideEnergySrcs->EnergySource(EnergySourceNum).CapFractionSchedNum, true, 0.0)) {
     286           0 :                 ShowWarningError(state,
     287           0 :                                  format("{}=\"{}\", is not valid",
     288           0 :                                         state.dataIPShortCut->cCurrentModuleObject,
     289           0 :                                         state.dataOutsideEnergySrcs->EnergySource(EnergySourceNum).Name));
     290           0 :                 ShowContinueError(state,
     291           0 :                                   format("{}=\"{}\" should not have negative values.",
     292           0 :                                          state.dataIPShortCut->cAlphaFieldNames(4),
     293           0 :                                          state.dataIPShortCut->cAlphaArgs(4)));
     294           0 :                 ShowContinueError(state, "Negative values will be treated as zero, and the simulation continues.");
     295             :             }
     296             :         } else {
     297         278 :             state.dataOutsideEnergySrcs->EnergySource(EnergySourceNum).CapFractionSchedNum = ScheduleManager::ScheduleAlwaysOn;
     298             :         }
     299         278 :     }
     300             : 
     301         159 :     if (ErrorsFound) {
     302           0 :         ShowFatalError(
     303             :             state,
     304           0 :             format("Errors found in processing input for {}, Preceding condition caused termination.", state.dataIPShortCut->cCurrentModuleObject));
     305             :     }
     306             : }
     307             : 
     308     7037909 : void OutsideEnergySourceSpecs::initialize(EnergyPlusData &state, Real64 MyLoad)
     309             : {
     310             : 
     311             :     // SUBROUTINE INFORMATION:
     312             :     //       AUTHOR:          Dan Fisher
     313             :     //       DATE WRITTEN:    October 1998
     314             :     //       MODIFIED       May 2010; Edwin Lee; Linda Lawrie (consolidation)
     315             :     //       RE-ENGINEERED  Sept 2010, Brent Griffith, plant rewrite
     316             : 
     317             :     // PURPOSE OF THIS SUBROUTINE:
     318             :     // This subroutine does one-time inits and sets the operating mass flow rate of this machine
     319             : 
     320             :     // METHODOLOGY EMPLOYED:
     321             :     // One time inits include validating source type (should happen in getinput?) and locating this
     322             :     //  component on the PlantLoop topology.
     323             :     // The mass flow rate is determined based on component load, and making use of
     324             :     //  the SetComponentFlowRate routine.
     325             :     // The mass flow rate could be an inter-connected-loop side trigger. This is not really the type of
     326             :     //  interconnect that that routine was written for, but it is the clearest example of using it.
     327             : 
     328     7037909 :     auto &loop = state.dataPlnt->PlantLoop(this->plantLoc.loopNum);
     329             : 
     330             :     // begin environment inits
     331     7037909 :     if (state.dataGlobal->BeginEnvrnFlag && this->BeginEnvrnInitFlag) {
     332             :         // component model has not design flow rates, using data for overall plant loop
     333        1619 :         PlantUtilities::InitComponentNodes(state, loop.MinMassFlowRate, loop.MaxMassFlowRate, this->InletNodeNum, this->OutletNodeNum);
     334        1619 :         this->BeginEnvrnInitFlag = false;
     335             :     }
     336     7037909 :     if (!state.dataGlobal->BeginEnvrnFlag) this->BeginEnvrnInitFlag = true;
     337             : 
     338     7037909 :     Real64 TempPlantMassFlow(0.0);
     339     7037909 :     if (std::abs(MyLoad) > 0.0) {
     340     1692056 :         TempPlantMassFlow = loop.MaxMassFlowRate;
     341             :     }
     342             : 
     343             :     // get actual mass flow to use, hold in MassFlowRate variable
     344     7037909 :     PlantUtilities::SetComponentFlowRate(state, TempPlantMassFlow, this->InletNodeNum, this->OutletNodeNum, this->plantLoc);
     345             : 
     346     7037909 :     this->InletTemp = state.dataLoopNodes->Node(this->InletNodeNum).Temp;
     347     7037909 :     this->MassFlowRate = TempPlantMassFlow;
     348     7037909 : }
     349             : 
     350        1392 : void OutsideEnergySourceSpecs::size(EnergyPlusData &state)
     351             : {
     352             :     // SUBROUTINE INFORMATION:
     353             :     //       AUTHOR         Daeho Kang
     354             :     //       DATE WRITTEN   April 2014
     355             :     //       MODIFIED       June 2021, Dareum Nam, Add DistrictHeatingSteam
     356             :     //       RE-ENGINEERED  na
     357             : 
     358             :     // PURPOSE OF THIS SUBROUTINE:
     359             :     //  This subroutine is for sizing capacities of district cooling and heating objects.
     360             : 
     361             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     362        1392 :     bool ErrorsFound(false); // If errors detected in input
     363             : 
     364             :     // Type name string variable to collapse the sizing for cooling and heating into one block
     365        1392 :     std::string_view typeName = DataPlant::PlantEquipTypeNames[static_cast<int>(this->EnergyType)];
     366             : 
     367        1392 :     auto &loop = state.dataPlnt->PlantLoop(this->plantLoc.loopNum);
     368        1392 :     int const PltSizNum = loop.PlantSizNum;
     369        1392 :     if (PltSizNum > 0) {
     370             :         Real64 NomCapDes;
     371         427 :         if (this->EnergyType == DataPlant::PlantEquipmentType::PurchChilledWater ||
     372         242 :             this->EnergyType == DataPlant::PlantEquipmentType::PurchHotWater) {
     373             :             Real64 const rho =
     374         422 :                 FluidProperties::GetDensityGlycol(state, loop.FluidName, Constant::InitConvTemp, loop.FluidIndex, format("Size {}", typeName));
     375             :             Real64 const Cp =
     376         422 :                 FluidProperties::GetSpecificHeatGlycol(state, loop.FluidName, Constant::InitConvTemp, loop.FluidIndex, format("Size {}", typeName));
     377         422 :             NomCapDes = Cp * rho * state.dataSize->PlantSizData(PltSizNum).DeltaT * state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate;
     378         422 :         } else { // this->EnergyType == DataPlant::TypeOf_PurchSteam
     379          10 :             Real64 const tempSteam = FluidProperties::GetSatTemperatureRefrig(
     380          15 :                 state, loop.FluidName, state.dataEnvrn->StdBaroPress, loop.FluidIndex, format("Size {}", typeName));
     381             :             Real64 const rhoSteam =
     382           5 :                 FluidProperties::GetSatDensityRefrig(state, loop.FluidName, tempSteam, 1.0, loop.FluidIndex, format("Size {}", typeName));
     383             :             Real64 const EnthSteamDry =
     384           5 :                 FluidProperties::GetSatEnthalpyRefrig(state, loop.FluidName, tempSteam, 1.0, loop.FluidIndex, format("Size {}", typeName));
     385             :             Real64 const EnthSteamWet =
     386           5 :                 FluidProperties::GetSatEnthalpyRefrig(state, loop.FluidName, tempSteam, 0.0, loop.FluidIndex, format("Size {}", typeName));
     387           5 :             Real64 const LatentHeatSteam = EnthSteamDry - EnthSteamWet;
     388           5 :             NomCapDes = rhoSteam * state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate * LatentHeatSteam;
     389             :         }
     390         427 :         if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
     391          87 :             if (this->NomCapWasAutoSized) {
     392          10 :                 this->NomCap = NomCapDes;
     393          10 :                 if (state.dataPlnt->PlantFinalSizesOkayToReport) {
     394           8 :                     BaseSizer::reportSizerOutput(state, typeName, this->Name, "Design Size Nominal Capacity [W]", NomCapDes);
     395             :                 }
     396          10 :                 if (state.dataPlnt->PlantFirstSizesOkayToReport) {
     397           1 :                     BaseSizer::reportSizerOutput(state, typeName, this->Name, "Initial Design Size Nominal Capacity [W]", NomCapDes);
     398             :                 }
     399             :             } else { // Hard-size with sizing data
     400          77 :                 if (this->NomCap > 0.0 && NomCapDes > 0.0) {
     401          75 :                     Real64 const NomCapUser = this->NomCap;
     402          75 :                     if (state.dataPlnt->PlantFinalSizesOkayToReport) {
     403          75 :                         BaseSizer::reportSizerOutput(state,
     404             :                                                      typeName,
     405             :                                                      this->Name,
     406             :                                                      "Design Size Nominal Capacity [W]",
     407             :                                                      NomCapDes,
     408             :                                                      "User-Specified Nominal Capacity [W]",
     409             :                                                      NomCapUser);
     410          75 :                         if (state.dataGlobal->DisplayExtraWarnings) {
     411           5 :                             if ((std::abs(NomCapDes - NomCapUser) / NomCapUser) > state.dataSize->AutoVsHardSizingThreshold) {
     412           1 :                                 ShowMessage(state, format("Size {}: Potential issue with equipment sizing for {}", typeName, this->Name));
     413           1 :                                 ShowContinueError(state, format("User-Specified Nominal Capacity of {:.2R} [W]", NomCapUser));
     414           1 :                                 ShowContinueError(state, format("differs from Design Size Nominal Capacity of {:.2R} [W]", NomCapDes));
     415           1 :                                 ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
     416           1 :                                 ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
     417             :                             }
     418             :                         }
     419             :                     }
     420             :                 }
     421             :             }
     422             :         }
     423             :     } else {
     424         965 :         if (this->NomCapWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
     425           0 :             ShowSevereError(state, format("Autosizing of {} nominal capacity requires a loop Sizing:Plant object", typeName));
     426           0 :             ShowContinueError(state, format("Occurs in {} object={}", typeName, this->Name));
     427           0 :             ErrorsFound = true;
     428             :         }
     429         965 :         if (!this->NomCapWasAutoSized && this->NomCap > 0.0 && state.dataPlnt->PlantFinalSizesOkayToReport) {
     430         193 :             BaseSizer::reportSizerOutput(state, typeName, this->Name, "User-Specified Nominal Capacity [W]", this->NomCap);
     431             :         }
     432             :     }
     433        1392 :     if (ErrorsFound) {
     434           0 :         ShowFatalError(state, "Preceding sizing errors cause program termination");
     435             :     }
     436        1392 : }
     437             : 
     438     7036517 : void OutsideEnergySourceSpecs::calculate(EnergyPlusData &state, bool runFlag, Real64 MyLoad)
     439             : {
     440             :     // SUBROUTINE INFORMATION:
     441             :     //       AUTHOR         Dan Fisher
     442             :     //       DATE WRITTEN   July 1998
     443             :     //       MODIFIED       May 2010; Edwin Lee; Linda Lawrie (consolidation)
     444             :     //                      June 2021, Dareum Nam, Add DistrictHeatingSteam
     445             :     //       RE-ENGINEERED  Sept 2010, Brent Griffith, plant rewrite
     446             : 
     447             :     // SUBROUTINE PARAMETER DEFINITIONS:
     448             :     static constexpr std::string_view RoutineName("SimDistrictEnergy");
     449             : 
     450     7036517 :     auto &loop = state.dataPlnt->PlantLoop(this->plantLoc.loopNum);
     451             : 
     452             :     // set inlet and outlet nodes
     453     7036517 :     int const LoopNum = this->plantLoc.loopNum;
     454     7036517 :     Real64 const LoopMinTemp = state.dataPlnt->PlantLoop(LoopNum).MinTemp;
     455     7036517 :     Real64 const LoopMaxTemp = state.dataPlnt->PlantLoop(LoopNum).MaxTemp;
     456     7036517 :     Real64 const LoopMinMdot = state.dataPlnt->PlantLoop(LoopNum).MinMassFlowRate;
     457     7036517 :     Real64 const LoopMaxMdot = state.dataPlnt->PlantLoop(LoopNum).MaxMassFlowRate;
     458             : 
     459             :     //  apply power limit from input
     460     7036517 :     Real64 CapFraction = ScheduleManager::GetCurrentScheduleValue(state, this->CapFractionSchedNum);
     461     7036517 :     CapFraction = max(0.0, CapFraction); // ensure non negative
     462     7036517 :     Real64 const CurrentCap = this->NomCap * CapFraction;
     463     7036517 :     if (std::abs(MyLoad) > CurrentCap) {
     464          40 :         MyLoad = sign(CurrentCap, MyLoad);
     465             :     }
     466             : 
     467     7036517 :     if (this->EnergyType == DataPlant::PlantEquipmentType::PurchChilledWater) {
     468     3260166 :         if (MyLoad > 0.0) MyLoad = 0.0;
     469     3776351 :     } else if (this->EnergyType == DataPlant::PlantEquipmentType::PurchHotWater || this->EnergyType == DataPlant::PlantEquipmentType::PurchSteam) {
     470     3776351 :         if (MyLoad < 0.0) MyLoad = 0.0;
     471             :     }
     472             : 
     473             :     // determine outlet temp based on inlet temp, cp, and MyLoad
     474     7036517 :     if ((this->MassFlowRate > 0.0) && runFlag) {
     475     1691706 :         if (this->EnergyType == DataPlant::PlantEquipmentType::PurchChilledWater ||
     476     1375112 :             this->EnergyType == DataPlant::PlantEquipmentType::PurchHotWater) {
     477     1686242 :             Real64 const Cp = FluidProperties::GetSpecificHeatGlycol(
     478     1686242 :                 state, state.dataPlnt->PlantLoop(LoopNum).FluidName, this->InletTemp, state.dataPlnt->PlantLoop(LoopNum).FluidIndex, RoutineName);
     479     1686242 :             this->OutletTemp = (MyLoad + this->MassFlowRate * Cp * this->InletTemp) / (this->MassFlowRate * Cp);
     480             :             // apply loop limits on temperature result to keep in check
     481     1686242 :             if (this->OutletTemp < LoopMinTemp) {
     482           0 :                 this->OutletTemp = max(this->OutletTemp, LoopMinTemp);
     483           0 :                 MyLoad = this->MassFlowRate * Cp * (this->OutletTemp - this->InletTemp);
     484             :             }
     485     1686242 :             if (this->OutletTemp > LoopMaxTemp) {
     486           0 :                 this->OutletTemp = min(this->OutletTemp, LoopMaxTemp);
     487           0 :                 MyLoad = this->MassFlowRate * Cp * (this->OutletTemp - this->InletTemp);
     488             :             }
     489     1691706 :         } else if (this->EnergyType == DataPlant::PlantEquipmentType::PurchSteam) { // determine mass flow rate based on inlet temp, saturate temp at
     490             :                                                                                     // atmospheric pressure, Cp of inlet condensate, and MyLoad
     491             :             Real64 SatTempAtmPress =
     492        5464 :                 FluidProperties::GetSatTemperatureRefrig(state, loop.FluidName, DataEnvironment::StdPressureSeaLevel, loop.FluidIndex, RoutineName);
     493        5464 :             Real64 CpCondensate = FluidProperties::GetSpecificHeatGlycol(state, loop.FluidName, this->InletTemp, loop.FluidIndex, RoutineName);
     494        5464 :             Real64 deltaTsensible = SatTempAtmPress - this->InletTemp;
     495        5464 :             Real64 EnthSteamInDry = FluidProperties::GetSatEnthalpyRefrig(state, loop.FluidName, this->InletTemp, 1.0, loop.FluidIndex, RoutineName);
     496        5464 :             Real64 EnthSteamOutWet = FluidProperties::GetSatEnthalpyRefrig(state, loop.FluidName, this->InletTemp, 0.0, loop.FluidIndex, RoutineName);
     497        5464 :             Real64 LatentHeatSteam = EnthSteamInDry - EnthSteamOutWet;
     498        5464 :             this->MassFlowRate = MyLoad / (LatentHeatSteam + (CpCondensate * deltaTsensible));
     499        5464 :             PlantUtilities::SetComponentFlowRate(state, this->MassFlowRate, this->InletNodeNum, this->OutletNodeNum, this->plantLoc);
     500             :             // Like the assumption in Boiler:Steam, assume that it can meet the steam loop setpoint
     501        5464 :             this->OutletTemp = state.dataLoopNodes->Node(loop.TempSetPointNodeNum).TempSetPoint;
     502        5464 :             this->OutletSteamQuality = 0.0;
     503             :             // apply loop limits on mass flow rate result to keep in check
     504        5464 :             if (this->MassFlowRate < LoopMinMdot) {
     505           0 :                 this->MassFlowRate = max(this->MassFlowRate, LoopMinMdot);
     506           0 :                 PlantUtilities::SetComponentFlowRate(state, this->MassFlowRate, this->InletNodeNum, this->OutletNodeNum, this->plantLoc);
     507           0 :                 MyLoad = this->MassFlowRate * LatentHeatSteam;
     508             :             }
     509        5464 :             if (this->MassFlowRate > LoopMaxMdot) {
     510           0 :                 this->MassFlowRate = min(this->MassFlowRate, LoopMaxMdot);
     511           0 :                 PlantUtilities::SetComponentFlowRate(state, this->MassFlowRate, this->InletNodeNum, this->OutletNodeNum, this->plantLoc);
     512           0 :                 MyLoad = this->MassFlowRate * LatentHeatSteam;
     513             :             }
     514             :             // Like the assumption in Boiler:Steam, assume that saturated steam is leaving the district heating steam plant
     515        5464 :             state.dataLoopNodes->Node(this->OutletNodeNum).Quality = 1.0;
     516             :         }
     517     1691706 :     } else {
     518     5344811 :         this->OutletTemp = this->InletTemp;
     519     5344811 :         MyLoad = 0.0;
     520             :     }
     521     7036517 :     int const OutletNode = this->OutletNodeNum;
     522     7036517 :     state.dataLoopNodes->Node(OutletNode).Temp = this->OutletTemp;
     523     7036517 :     this->EnergyRate = std::abs(MyLoad);
     524     7036517 :     this->EnergyTransfer = this->EnergyRate * state.dataHVACGlobal->TimeStepSysSec;
     525     7036517 : }
     526             : 
     527         278 : void OutsideEnergySourceSpecs::oneTimeInit_new(EnergyPlusData &state)
     528             : {
     529             :     // Locate the unit on the plant loops for later usage
     530         278 :     bool errFlag = false;
     531         278 :     PlantUtilities::ScanPlantLoopsForObject(state, this->Name, this->EnergyType, this->plantLoc, errFlag, _, _, _, _, _);
     532         278 :     if (errFlag) {
     533           0 :         ShowFatalError(state, "InitSimVars: Program terminated due to previous condition(s).");
     534             :     }
     535             : 
     536         278 :     auto &loop = state.dataPlnt->PlantLoop(this->plantLoc.loopNum);
     537             :     // set limits on outlet node temps to plant loop limits
     538         278 :     DataPlant::CompData::getPlantComponent(state, this->plantLoc).MinOutletTemp = loop.MinTemp;
     539         278 :     DataPlant::CompData::getPlantComponent(state, this->plantLoc).MaxOutletTemp = loop.MaxTemp;
     540             :     // Register design flow rate for inlet node (helps to autosize comp setpoint op scheme flows
     541         278 :     PlantUtilities::RegisterPlantCompDesignFlow(state, this->InletNodeNum, loop.MaxVolFlowRate);
     542             : 
     543         278 :     std::string reportVarPrefix = "District Heating Water ";
     544         278 :     OutputProcessor::EndUseCat heatingOrCooling = OutputProcessor::EndUseCat::Heating;
     545         278 :     Constant::eResource meterTypeKey = Constant::eResource::DistrictHeatingWater;
     546             : 
     547         278 :     if (this->EnergyType == DataPlant::PlantEquipmentType::PurchChilledWater) {
     548         133 :         reportVarPrefix = "District Cooling Water ";
     549         133 :         heatingOrCooling = OutputProcessor::EndUseCat::Cooling;
     550         133 :         meterTypeKey = Constant::eResource::DistrictCooling;
     551         145 :     } else if (this->EnergyType == DataPlant::PlantEquipmentType::PurchSteam) {
     552           1 :         reportVarPrefix = "District Heating Steam ";
     553           1 :         heatingOrCooling = OutputProcessor::EndUseCat::Heating;
     554           1 :         meterTypeKey = Constant::eResource::DistrictHeatingSteam;
     555             :     }
     556         834 :     SetupOutputVariable(state,
     557         556 :                         format("{}Energy", reportVarPrefix),
     558             :                         Constant::Units::J,
     559         278 :                         this->EnergyTransfer,
     560             :                         OutputProcessor::TimeStepType::System,
     561             :                         OutputProcessor::StoreType::Sum,
     562         278 :                         this->Name,
     563             :                         meterTypeKey,
     564             :                         OutputProcessor::Group::Plant,
     565             :                         heatingOrCooling);
     566         834 :     SetupOutputVariable(state,
     567         556 :                         format("{}Rate", reportVarPrefix),
     568             :                         Constant::Units::W,
     569         278 :                         this->EnergyRate,
     570             :                         OutputProcessor::TimeStepType::System,
     571             :                         OutputProcessor::StoreType::Average,
     572         278 :                         this->Name);
     573         834 :     SetupOutputVariable(state,
     574         556 :                         format("{}Inlet Temperature", reportVarPrefix),
     575             :                         Constant::Units::C,
     576         278 :                         this->InletTemp,
     577             :                         OutputProcessor::TimeStepType::System,
     578             :                         OutputProcessor::StoreType::Average,
     579         278 :                         this->Name);
     580         834 :     SetupOutputVariable(state,
     581         556 :                         format("{}Outlet Temperature", reportVarPrefix),
     582             :                         Constant::Units::C,
     583         278 :                         this->OutletTemp,
     584             :                         OutputProcessor::TimeStepType::System,
     585             :                         OutputProcessor::StoreType::Average,
     586         278 :                         this->Name);
     587         834 :     SetupOutputVariable(state,
     588         556 :                         format("{}Mass Flow Rate", reportVarPrefix),
     589             :                         Constant::Units::kg_s,
     590         278 :                         this->MassFlowRate,
     591             :                         OutputProcessor::TimeStepType::System,
     592             :                         OutputProcessor::StoreType::Average,
     593         278 :                         this->Name);
     594         278 : }
     595             : 
     596           0 : void OutsideEnergySourceSpecs::oneTimeInit([[maybe_unused]] EnergyPlusData &state)
     597             : {
     598           0 : }
     599             : 
     600             : } // namespace EnergyPlus::OutsideEnergySources

Generated by: LCOV version 1.14