LCOV - code coverage report
Current view: top level - EnergyPlus - OutsideEnergySources.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 81.7 % 268 219
Test Date: 2025-05-22 16:09:37 Functions: 90.0 % 10 9

            Line data    Source code
       1              : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
       2              : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3              : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4              : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5              : // contributors. All rights reserved.
       6              : //
       7              : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8              : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9              : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10              : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11              : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12              : //
      13              : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14              : // provided that the following conditions are met:
      15              : //
      16              : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17              : //     conditions and the following disclaimer.
      18              : //
      19              : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20              : //     conditions and the following disclaimer in the documentation and/or other materials
      21              : //     provided with the distribution.
      22              : //
      23              : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24              : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25              : //     used to endorse or promote products derived from this software without specific prior
      26              : //     written permission.
      27              : //
      28              : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29              : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30              : //     reference solely to the software portion of its product, Licensee must refer to the
      31              : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32              : //     obtained under this License and may not use a different name for the software. Except as
      33              : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34              : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35              : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36              : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37              : //
      38              : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39              : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40              : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41              : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42              : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43              : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44              : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45              : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46              : // POSSIBILITY OF SUCH DAMAGE.
      47              : 
      48              : // C++ Headers
      49              : #include <cmath>
      50              : #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           25 : 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           25 :     if (state.dataOutsideEnergySrcs->SimOutsideEnergyGetInputFlag) {
      93           16 :         GetOutsideEnergySourcesInput(state);
      94           16 :         state.dataOutsideEnergySrcs->SimOutsideEnergyGetInputFlag = false;
      95              :     }
      96              :     // Now look for this particular pipe in the list
      97           34 :     for (auto &source : state.dataOutsideEnergySrcs->EnergySource) {
      98           34 :         if (source.EnergyType == objectType && source.Name == objectName) {
      99           25 :             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        85899 : void OutsideEnergySourceSpecs::simulate(EnergyPlusData &state,
     109              :                                         [[maybe_unused]] const PlantLocation &calledFromLocation,
     110              :                                         [[maybe_unused]] bool FirstHVACIteration,
     111              :                                         Real64 &CurLoad,
     112              :                                         bool RunFlag)
     113              : {
     114        85899 :     this->initialize(state, CurLoad);
     115        85899 :     this->calculate(state, RunFlag, CurLoad);
     116        85899 : }
     117              : 
     118           70 : void OutsideEnergySourceSpecs::onInitLoopEquip(EnergyPlusData &state, const PlantLocation &)
     119              : {
     120           70 :     this->initialize(state, 0.0);
     121           70 :     this->size(state);
     122           70 : }
     123              : 
     124           70 : void OutsideEnergySourceSpecs::getDesignCapacities([[maybe_unused]] EnergyPlusData &state,
     125              :                                                    [[maybe_unused]] const PlantLocation &calledFromLocation,
     126              :                                                    Real64 &MaxLoad,
     127              :                                                    Real64 &MinLoad,
     128              :                                                    Real64 &OptLoad)
     129              : {
     130           70 :     MinLoad = 0.0;
     131           70 :     MaxLoad = this->NomCap;
     132           70 :     OptLoad = this->NomCap;
     133           70 : }
     134              : 
     135           17 : 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              :     static constexpr std::string_view routineName = "GetOutsideEnergySourcesInput";
     150              : 
     151              :     // GET NUMBER OF ALL EQUIPMENT TYPES
     152           17 :     int const NumDistrictUnitsHeatWater = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "DistrictHeating:Water");
     153           17 :     int const NumDistrictUnitsCool = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "DistrictCooling");
     154           17 :     int const NumDistrictUnitsHeatSteam = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "DistrictHeating:Steam");
     155           17 :     state.dataOutsideEnergySrcs->NumDistrictUnits = NumDistrictUnitsHeatWater + NumDistrictUnitsCool + NumDistrictUnitsHeatSteam;
     156              : 
     157           17 :     if (allocated(state.dataOutsideEnergySrcs->EnergySource)) return;
     158              : 
     159           17 :     state.dataOutsideEnergySrcs->EnergySource.allocate(state.dataOutsideEnergySrcs->NumDistrictUnits);
     160           17 :     state.dataOutsideEnergySrcs->EnergySourceUniqueNames.reserve(static_cast<unsigned>(state.dataOutsideEnergySrcs->NumDistrictUnits));
     161              : 
     162           17 :     bool ErrorsFound(false); // If errors detected in input
     163           17 :     int heatWaterIndex = 0;
     164           17 :     int coolIndex = 0;
     165           17 :     int heatSteamIndex = 0;
     166              : 
     167           45 :     for (int EnergySourceNum = 1; EnergySourceNum <= state.dataOutsideEnergySrcs->NumDistrictUnits; ++EnergySourceNum) {
     168              : 
     169           28 :         std::string nodeNames;
     170              :         DataPlant::PlantEquipmentType EnergyType;
     171              :         DataLoopNode::ConnectionObjectType objType;
     172              :         int thisIndex;
     173           28 :         if (EnergySourceNum <= NumDistrictUnitsHeatWater) {
     174           17 :             state.dataIPShortCut->cCurrentModuleObject = "DistrictHeating:Water";
     175           17 :             objType = DataLoopNode::ConnectionObjectType::DistrictHeatingWater;
     176           17 :             nodeNames = "Hot Water Nodes";
     177           17 :             EnergyType = DataPlant::PlantEquipmentType::PurchHotWater;
     178           17 :             heatWaterIndex++;
     179           17 :             thisIndex = heatWaterIndex;
     180           11 :         } else if (EnergySourceNum <= NumDistrictUnitsHeatWater + NumDistrictUnitsCool) {
     181           10 :             state.dataIPShortCut->cCurrentModuleObject = "DistrictCooling";
     182           10 :             objType = DataLoopNode::ConnectionObjectType::DistrictCooling;
     183           10 :             nodeNames = "Chilled Water Nodes";
     184           10 :             EnergyType = DataPlant::PlantEquipmentType::PurchChilledWater;
     185           10 :             coolIndex++;
     186           10 :             thisIndex = coolIndex;
     187              :         } else { // EnergySourceNum > NumDistrictUnitsHeatWater + NumDistrictUnitsCool
     188            1 :             state.dataIPShortCut->cCurrentModuleObject = "DistrictHeating:Steam";
     189            1 :             objType = DataLoopNode::ConnectionObjectType::DistrictHeatingSteam;
     190            1 :             nodeNames = "Steam Nodes";
     191            1 :             EnergyType = DataPlant::PlantEquipmentType::PurchSteam;
     192            1 :             heatSteamIndex++;
     193            1 :             thisIndex = heatSteamIndex;
     194              :         }
     195              : 
     196           28 :         int NumAlphas = 0, NumNums = 0, IOStat = 0;
     197           84 :         state.dataInputProcessing->inputProcessor->getObjectItem(state,
     198           28 :                                                                  state.dataIPShortCut->cCurrentModuleObject,
     199              :                                                                  thisIndex,
     200           28 :                                                                  state.dataIPShortCut->cAlphaArgs,
     201              :                                                                  NumAlphas,
     202           28 :                                                                  state.dataIPShortCut->rNumericArgs,
     203              :                                                                  NumNums,
     204              :                                                                  IOStat,
     205              :                                                                  _,
     206           28 :                                                                  state.dataIPShortCut->lAlphaFieldBlanks,
     207           28 :                                                                  state.dataIPShortCut->cAlphaFieldNames);
     208              : 
     209           28 :         ErrorObjectHeader eoh{routineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
     210              : 
     211           28 :         if (EnergySourceNum > 1) {
     212           11 :             GlobalNames::VerifyUniqueInterObjectName(state,
     213           11 :                                                      state.dataOutsideEnergySrcs->EnergySourceUniqueNames,
     214           11 :                                                      state.dataIPShortCut->cAlphaArgs(1),
     215           11 :                                                      state.dataIPShortCut->cCurrentModuleObject,
     216           11 :                                                      state.dataIPShortCut->cAlphaFieldNames(1),
     217              :                                                      ErrorsFound);
     218              :         }
     219           28 :         state.dataOutsideEnergySrcs->EnergySource(EnergySourceNum).Name = state.dataIPShortCut->cAlphaArgs(1);
     220           28 :         if (EnergySourceNum <= NumDistrictUnitsHeatWater + NumDistrictUnitsCool) {
     221           27 :             state.dataOutsideEnergySrcs->EnergySource(EnergySourceNum).InletNodeNum =
     222           54 :                 NodeInputManager::GetOnlySingleNode(state,
     223           27 :                                                     state.dataIPShortCut->cAlphaArgs(2),
     224              :                                                     ErrorsFound,
     225              :                                                     objType,
     226           27 :                                                     state.dataIPShortCut->cAlphaArgs(1),
     227              :                                                     DataLoopNode::NodeFluidType::Water,
     228              :                                                     DataLoopNode::ConnectionType::Inlet,
     229              :                                                     NodeInputManager::CompFluidStream::Primary,
     230              :                                                     DataLoopNode::ObjectIsNotParent);
     231           27 :             state.dataOutsideEnergySrcs->EnergySource(EnergySourceNum).OutletNodeNum =
     232           81 :                 NodeInputManager::GetOnlySingleNode(state,
     233           27 :                                                     state.dataIPShortCut->cAlphaArgs(3),
     234              :                                                     ErrorsFound,
     235              :                                                     objType,
     236           27 :                                                     state.dataIPShortCut->cAlphaArgs(1),
     237              :                                                     DataLoopNode::NodeFluidType::Water,
     238              :                                                     DataLoopNode::ConnectionType::Outlet,
     239              :                                                     NodeInputManager::CompFluidStream::Primary,
     240              :                                                     DataLoopNode::ObjectIsNotParent);
     241              :         } else {
     242            1 :             state.dataOutsideEnergySrcs->EnergySource(EnergySourceNum).InletNodeNum =
     243            2 :                 NodeInputManager::GetOnlySingleNode(state,
     244            1 :                                                     state.dataIPShortCut->cAlphaArgs(2),
     245              :                                                     ErrorsFound,
     246              :                                                     objType,
     247            1 :                                                     state.dataIPShortCut->cAlphaArgs(1),
     248              :                                                     DataLoopNode::NodeFluidType::Steam,
     249              :                                                     DataLoopNode::ConnectionType::Inlet,
     250              :                                                     NodeInputManager::CompFluidStream::Primary,
     251              :                                                     DataLoopNode::ObjectIsNotParent);
     252            1 :             state.dataOutsideEnergySrcs->EnergySource(EnergySourceNum).OutletNodeNum =
     253            3 :                 NodeInputManager::GetOnlySingleNode(state,
     254            1 :                                                     state.dataIPShortCut->cAlphaArgs(3),
     255              :                                                     ErrorsFound,
     256              :                                                     objType,
     257            1 :                                                     state.dataIPShortCut->cAlphaArgs(1),
     258              :                                                     DataLoopNode::NodeFluidType::Steam,
     259              :                                                     DataLoopNode::ConnectionType::Outlet,
     260              :                                                     NodeInputManager::CompFluidStream::Primary,
     261              :                                                     DataLoopNode::ObjectIsNotParent);
     262              :         }
     263           28 :         BranchNodeConnections::TestCompSet(state,
     264           28 :                                            state.dataIPShortCut->cCurrentModuleObject,
     265           28 :                                            state.dataIPShortCut->cAlphaArgs(1),
     266           28 :                                            state.dataIPShortCut->cAlphaArgs(2),
     267           28 :                                            state.dataIPShortCut->cAlphaArgs(3),
     268              :                                            nodeNames);
     269           28 :         state.dataOutsideEnergySrcs->EnergySource(EnergySourceNum).NomCap = state.dataIPShortCut->rNumericArgs(1);
     270           28 :         if (state.dataOutsideEnergySrcs->EnergySource(EnergySourceNum).NomCap == DataSizing::AutoSize) {
     271            0 :             state.dataOutsideEnergySrcs->EnergySource(EnergySourceNum).NomCapWasAutoSized = true;
     272              :         }
     273           28 :         state.dataOutsideEnergySrcs->EnergySource(EnergySourceNum).EnergyTransfer = 0.0;
     274           28 :         state.dataOutsideEnergySrcs->EnergySource(EnergySourceNum).EnergyRate = 0.0;
     275           28 :         state.dataOutsideEnergySrcs->EnergySource(EnergySourceNum).EnergyType = EnergyType;
     276              : 
     277           28 :         if (state.dataIPShortCut->lAlphaFieldBlanks(4)) {
     278           28 :             state.dataOutsideEnergySrcs->EnergySource(EnergySourceNum).capFractionSched =
     279           28 :                 Sched::GetScheduleAlwaysOn(state); // Defaults to constant-1.0
     280            0 :         } else if ((state.dataOutsideEnergySrcs->EnergySource(EnergySourceNum).capFractionSched =
     281            0 :                         Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(4))) == nullptr) {
     282            0 :             ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(4), state.dataIPShortCut->cAlphaArgs(4));
     283            0 :             ErrorsFound = true;
     284            0 :         } else if (!state.dataOutsideEnergySrcs->EnergySource(EnergySourceNum).capFractionSched->checkMinVal(state, Clusive::In, 0.0)) {
     285            0 :             Sched::ShowWarningBadMin(state,
     286              :                                      eoh,
     287            0 :                                      state.dataIPShortCut->cAlphaFieldNames(4),
     288            0 :                                      state.dataIPShortCut->cAlphaArgs(4),
     289              :                                      Clusive::In,
     290              :                                      0.0,
     291              :                                      "Negative values will be treated as zero, and the simulation continues.");
     292              :         }
     293           28 :     }
     294              : 
     295           17 :     if (ErrorsFound) {
     296            0 :         ShowFatalError(
     297              :             state,
     298            0 :             format("Errors found in processing input for {}, Preceding condition caused termination.", state.dataIPShortCut->cCurrentModuleObject));
     299              :     }
     300              : }
     301              : 
     302        85969 : void OutsideEnergySourceSpecs::initialize(EnergyPlusData &state, Real64 MyLoad)
     303              : {
     304              : 
     305              :     // SUBROUTINE INFORMATION:
     306              :     //       AUTHOR:          Dan Fisher
     307              :     //       DATE WRITTEN:    October 1998
     308              :     //       MODIFIED       May 2010; Edwin Lee; Linda Lawrie (consolidation)
     309              :     //       RE-ENGINEERED  Sept 2010, Brent Griffith, plant rewrite
     310              : 
     311              :     // PURPOSE OF THIS SUBROUTINE:
     312              :     // This subroutine does one-time inits and sets the operating mass flow rate of this machine
     313              : 
     314              :     // METHODOLOGY EMPLOYED:
     315              :     // One time inits include validating source type (should happen in getinput?) and locating this
     316              :     //  component on the PlantLoop topology.
     317              :     // The mass flow rate is determined based on component load, and making use of
     318              :     //  the SetComponentFlowRate routine.
     319              :     // The mass flow rate could be an inter-connected-loop side trigger. This is not really the type of
     320              :     //  interconnect that that routine was written for, but it is the clearest example of using it.
     321              : 
     322        85969 :     auto &loop = state.dataPlnt->PlantLoop(this->plantLoc.loopNum);
     323              : 
     324              :     // begin environment inits
     325        85969 :     if (state.dataGlobal->BeginEnvrnFlag && this->BeginEnvrnInitFlag) {
     326              :         // component model has not design flow rates, using data for overall plant loop
     327           40 :         PlantUtilities::InitComponentNodes(state, loop.MinMassFlowRate, loop.MaxMassFlowRate, this->InletNodeNum, this->OutletNodeNum);
     328           40 :         this->BeginEnvrnInitFlag = false;
     329              :     }
     330        85969 :     if (!state.dataGlobal->BeginEnvrnFlag) this->BeginEnvrnInitFlag = true;
     331              : 
     332        85969 :     Real64 TempPlantMassFlow(0.0);
     333        85969 :     if (std::abs(MyLoad) > 0.0) {
     334        41171 :         TempPlantMassFlow = loop.MaxMassFlowRate;
     335              :     }
     336              : 
     337              :     // get actual mass flow to use, hold in MassFlowRate variable
     338        85969 :     PlantUtilities::SetComponentFlowRate(state, TempPlantMassFlow, this->InletNodeNum, this->OutletNodeNum, this->plantLoc);
     339              : 
     340        85969 :     this->InletTemp = state.dataLoopNodes->Node(this->InletNodeNum).Temp;
     341        85969 :     this->MassFlowRate = TempPlantMassFlow;
     342        85969 : }
     343              : 
     344           70 : void OutsideEnergySourceSpecs::size(EnergyPlusData &state)
     345              : {
     346              :     // SUBROUTINE INFORMATION:
     347              :     //       AUTHOR         Daeho Kang
     348              :     //       DATE WRITTEN   April 2014
     349              :     //       MODIFIED       June 2021, Dareum Nam, Add DistrictHeatingSteam
     350              :     //       RE-ENGINEERED  na
     351              : 
     352              :     // PURPOSE OF THIS SUBROUTINE:
     353              :     //  This subroutine is for sizing capacities of district cooling and heating objects.
     354              : 
     355              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     356           70 :     bool ErrorsFound(false); // If errors detected in input
     357              : 
     358              :     // Type name string variable to collapse the sizing for cooling and heating into one block
     359           70 :     std::string_view typeName = DataPlant::PlantEquipTypeNames[static_cast<int>(this->EnergyType)];
     360              : 
     361           70 :     auto &loop = state.dataPlnt->PlantLoop(this->plantLoc.loopNum);
     362           70 :     int const PltSizNum = loop.PlantSizNum;
     363           70 :     if (PltSizNum > 0) {
     364              :         Real64 NomCapDes;
     365           45 :         if (this->EnergyType == DataPlant::PlantEquipmentType::PurchChilledWater ||
     366           30 :             this->EnergyType == DataPlant::PlantEquipmentType::PurchHotWater) {
     367           45 :             Real64 const rho = loop.glycol->getDensity(state, Constant::InitConvTemp, format("Size {}", typeName));
     368           45 :             Real64 const Cp = loop.glycol->getSpecificHeat(state, Constant::InitConvTemp, format("Size {}", typeName));
     369           45 :             NomCapDes = Cp * rho * state.dataSize->PlantSizData(PltSizNum).DeltaT * state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate;
     370           45 :         } else { // this->EnergyType == DataPlant::TypeOf_PurchSteam
     371            0 :             Real64 const tempSteam = loop.steam->getSatTemperature(state, state.dataEnvrn->StdBaroPress, format("Size {}", typeName));
     372            0 :             Real64 const rhoSteam = loop.steam->getSatDensity(state, tempSteam, 1.0, format("Size {}", typeName));
     373            0 :             Real64 const EnthSteamDry = loop.steam->getSatEnthalpy(state, tempSteam, 1.0, format("Size {}", typeName));
     374            0 :             Real64 const EnthSteamWet = loop.steam->getSatEnthalpy(state, tempSteam, 0.0, format("Size {}", typeName));
     375            0 :             Real64 const LatentHeatSteam = EnthSteamDry - EnthSteamWet;
     376            0 :             NomCapDes = rhoSteam * state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate * LatentHeatSteam;
     377              :         }
     378           45 :         if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
     379            9 :             if (this->NomCapWasAutoSized) {
     380            0 :                 this->NomCap = NomCapDes;
     381            0 :                 if (state.dataPlnt->PlantFinalSizesOkayToReport) {
     382            0 :                     BaseSizer::reportSizerOutput(state, typeName, this->Name, "Design Size Nominal Capacity [W]", NomCapDes);
     383              :                 }
     384            0 :                 if (state.dataPlnt->PlantFirstSizesOkayToReport) {
     385            0 :                     BaseSizer::reportSizerOutput(state, typeName, this->Name, "Initial Design Size Nominal Capacity [W]", NomCapDes);
     386              :                 }
     387              :             } else { // Hard-size with sizing data
     388            9 :                 if (this->NomCap > 0.0 && NomCapDes > 0.0) {
     389            9 :                     Real64 const NomCapUser = this->NomCap;
     390            9 :                     if (state.dataPlnt->PlantFinalSizesOkayToReport) {
     391            9 :                         BaseSizer::reportSizerOutput(state,
     392              :                                                      typeName,
     393              :                                                      this->Name,
     394              :                                                      "Design Size Nominal Capacity [W]",
     395              :                                                      NomCapDes,
     396              :                                                      "User-Specified Nominal Capacity [W]",
     397              :                                                      NomCapUser);
     398            9 :                         if (state.dataGlobal->DisplayExtraWarnings) {
     399            0 :                             if ((std::abs(NomCapDes - NomCapUser) / NomCapUser) > state.dataSize->AutoVsHardSizingThreshold) {
     400            0 :                                 ShowMessage(state, format("Size {}: Potential issue with equipment sizing for {}", typeName, this->Name));
     401            0 :                                 ShowContinueError(state, format("User-Specified Nominal Capacity of {:.2R} [W]", NomCapUser));
     402            0 :                                 ShowContinueError(state, format("differs from Design Size Nominal Capacity of {:.2R} [W]", NomCapDes));
     403            0 :                                 ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
     404            0 :                                 ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
     405              :                             }
     406              :                         }
     407              :                     }
     408              :                 }
     409              :             }
     410              :         }
     411              :     } else {
     412           25 :         if (this->NomCapWasAutoSized && state.dataPlnt->PlantFirstSizesOkayToFinalize) {
     413            0 :             ShowSevereError(state, format("Autosizing of {} nominal capacity requires a loop Sizing:Plant object", typeName));
     414            0 :             ShowContinueError(state, format("Occurs in {} object={}", typeName, this->Name));
     415            0 :             ErrorsFound = true;
     416              :         }
     417           25 :         if (!this->NomCapWasAutoSized && this->NomCap > 0.0 && state.dataPlnt->PlantFinalSizesOkayToReport) {
     418            5 :             BaseSizer::reportSizerOutput(state, typeName, this->Name, "User-Specified Nominal Capacity [W]", this->NomCap);
     419              :         }
     420              :     }
     421           70 :     if (ErrorsFound) {
     422            0 :         ShowFatalError(state, "Preceding sizing errors cause program termination");
     423              :     }
     424           70 : }
     425              : 
     426        85899 : void OutsideEnergySourceSpecs::calculate(EnergyPlusData &state, bool runFlag, Real64 MyLoad)
     427              : {
     428              :     // SUBROUTINE INFORMATION:
     429              :     //       AUTHOR         Dan Fisher
     430              :     //       DATE WRITTEN   July 1998
     431              :     //       MODIFIED       May 2010; Edwin Lee; Linda Lawrie (consolidation)
     432              :     //                      June 2021, Dareum Nam, Add DistrictHeatingSteam
     433              :     //       RE-ENGINEERED  Sept 2010, Brent Griffith, plant rewrite
     434              : 
     435              :     // SUBROUTINE PARAMETER DEFINITIONS:
     436              :     static constexpr std::string_view RoutineName("SimDistrictEnergy");
     437              : 
     438        85899 :     auto &loop = state.dataPlnt->PlantLoop(this->plantLoc.loopNum);
     439              : 
     440              :     // set inlet and outlet nodes
     441        85899 :     int const LoopNum = this->plantLoc.loopNum;
     442        85899 :     Real64 const LoopMinTemp = state.dataPlnt->PlantLoop(LoopNum).MinTemp;
     443        85899 :     Real64 const LoopMaxTemp = state.dataPlnt->PlantLoop(LoopNum).MaxTemp;
     444        85899 :     Real64 const LoopMinMdot = state.dataPlnt->PlantLoop(LoopNum).MinMassFlowRate;
     445        85899 :     Real64 const LoopMaxMdot = state.dataPlnt->PlantLoop(LoopNum).MaxMassFlowRate;
     446              : 
     447              :     //  apply power limit from input
     448        85899 :     Real64 CapFraction = this->capFractionSched->getCurrentVal();
     449        85899 :     CapFraction = max(0.0, CapFraction); // ensure non negative
     450        85899 :     Real64 const CurrentCap = this->NomCap * CapFraction;
     451        85899 :     if (std::abs(MyLoad) > CurrentCap) {
     452            0 :         MyLoad = sign(CurrentCap, MyLoad);
     453              :     }
     454              : 
     455        85899 :     if (this->EnergyType == DataPlant::PlantEquipmentType::PurchChilledWater) {
     456        22153 :         if (MyLoad > 0.0) MyLoad = 0.0;
     457        63746 :     } else if (this->EnergyType == DataPlant::PlantEquipmentType::PurchHotWater || this->EnergyType == DataPlant::PlantEquipmentType::PurchSteam) {
     458        63746 :         if (MyLoad < 0.0) MyLoad = 0.0;
     459              :     }
     460              : 
     461              :     // determine outlet temp based on inlet temp, cp, and MyLoad
     462        85899 :     if ((this->MassFlowRate > 0.0) && runFlag) {
     463        41171 :         if (this->EnergyType == DataPlant::PlantEquipmentType::PurchChilledWater ||
     464        27718 :             this->EnergyType == DataPlant::PlantEquipmentType::PurchHotWater) {
     465        41170 :             Real64 const Cp = state.dataPlnt->PlantLoop(LoopNum).glycol->getSpecificHeat(state, this->InletTemp, RoutineName);
     466        41170 :             this->OutletTemp = (MyLoad + this->MassFlowRate * Cp * this->InletTemp) / (this->MassFlowRate * Cp);
     467              :             // apply loop limits on temperature result to keep in check
     468        41170 :             if (this->OutletTemp < LoopMinTemp) {
     469            0 :                 this->OutletTemp = max(this->OutletTemp, LoopMinTemp);
     470            0 :                 MyLoad = this->MassFlowRate * Cp * (this->OutletTemp - this->InletTemp);
     471              :             }
     472        41170 :             if (this->OutletTemp > LoopMaxTemp) {
     473            0 :                 this->OutletTemp = min(this->OutletTemp, LoopMaxTemp);
     474            0 :                 MyLoad = this->MassFlowRate * Cp * (this->OutletTemp - this->InletTemp);
     475              :             }
     476        41171 :         } else if (this->EnergyType == DataPlant::PlantEquipmentType::PurchSteam) { // determine mass flow rate based on inlet temp, saturate temp at
     477              :                                                                                     // atmospheric pressure, Cp of inlet condensate, and MyLoad
     478            1 :             Real64 SatTempAtmPress = loop.steam->getSatTemperature(state, DataEnvironment::StdPressureSeaLevel, RoutineName);
     479            1 :             Real64 CpCondensate = loop.glycol->getSpecificHeat(state, this->InletTemp, RoutineName);
     480            1 :             Real64 deltaTsensible = SatTempAtmPress - this->InletTemp;
     481            1 :             Real64 EnthSteamInDry = loop.steam->getSatEnthalpy(state, this->InletTemp, 1.0, RoutineName);
     482            1 :             Real64 EnthSteamOutWet = loop.steam->getSatEnthalpy(state, this->InletTemp, 0.0, RoutineName);
     483            1 :             Real64 LatentHeatSteam = EnthSteamInDry - EnthSteamOutWet;
     484            1 :             this->MassFlowRate = MyLoad / (LatentHeatSteam + (CpCondensate * deltaTsensible));
     485            1 :             PlantUtilities::SetComponentFlowRate(state, this->MassFlowRate, this->InletNodeNum, this->OutletNodeNum, this->plantLoc);
     486              :             // Like the assumption in Boiler:Steam, assume that it can meet the steam loop setpoint
     487            1 :             this->OutletTemp = state.dataLoopNodes->Node(loop.TempSetPointNodeNum).TempSetPoint;
     488            1 :             this->OutletSteamQuality = 0.0;
     489              :             // apply loop limits on mass flow rate result to keep in check
     490            1 :             if (this->MassFlowRate < LoopMinMdot) {
     491            0 :                 this->MassFlowRate = max(this->MassFlowRate, LoopMinMdot);
     492            0 :                 PlantUtilities::SetComponentFlowRate(state, this->MassFlowRate, this->InletNodeNum, this->OutletNodeNum, this->plantLoc);
     493            0 :                 MyLoad = this->MassFlowRate * LatentHeatSteam;
     494              :             }
     495            1 :             if (this->MassFlowRate > LoopMaxMdot) {
     496            0 :                 this->MassFlowRate = min(this->MassFlowRate, LoopMaxMdot);
     497            0 :                 PlantUtilities::SetComponentFlowRate(state, this->MassFlowRate, this->InletNodeNum, this->OutletNodeNum, this->plantLoc);
     498            0 :                 MyLoad = this->MassFlowRate * LatentHeatSteam;
     499              :             }
     500              :             // Like the assumption in Boiler:Steam, assume that saturated steam is leaving the district heating steam plant
     501            1 :             state.dataLoopNodes->Node(this->OutletNodeNum).Quality = 1.0;
     502              :         }
     503        41171 :     } else {
     504        44728 :         this->OutletTemp = this->InletTemp;
     505        44728 :         MyLoad = 0.0;
     506              :     }
     507        85899 :     int const OutletNode = this->OutletNodeNum;
     508        85899 :     state.dataLoopNodes->Node(OutletNode).Temp = this->OutletTemp;
     509        85899 :     this->EnergyRate = std::abs(MyLoad);
     510        85899 :     this->EnergyTransfer = this->EnergyRate * state.dataHVACGlobal->TimeStepSysSec;
     511        85899 : }
     512              : 
     513           25 : void OutsideEnergySourceSpecs::oneTimeInit_new(EnergyPlusData &state)
     514              : {
     515              :     // Locate the unit on the plant loops for later usage
     516           25 :     bool errFlag = false;
     517           25 :     PlantUtilities::ScanPlantLoopsForObject(state, this->Name, this->EnergyType, this->plantLoc, errFlag, _, _, _, _, _);
     518           25 :     if (errFlag) {
     519            0 :         ShowFatalError(state, "InitSimVars: Program terminated due to previous condition(s).");
     520              :     }
     521              : 
     522           25 :     auto &loop = state.dataPlnt->PlantLoop(this->plantLoc.loopNum);
     523              :     // set limits on outlet node temps to plant loop limits
     524           25 :     DataPlant::CompData::getPlantComponent(state, this->plantLoc).MinOutletTemp = loop.MinTemp;
     525           25 :     DataPlant::CompData::getPlantComponent(state, this->plantLoc).MaxOutletTemp = loop.MaxTemp;
     526              :     // Register design flow rate for inlet node (helps to autosize comp setpoint op scheme flows
     527           25 :     PlantUtilities::RegisterPlantCompDesignFlow(state, this->InletNodeNum, loop.MaxVolFlowRate);
     528              : 
     529           25 :     std::string reportVarPrefix = "District Heating Water ";
     530           25 :     OutputProcessor::EndUseCat heatingOrCooling = OutputProcessor::EndUseCat::Heating;
     531           25 :     Constant::eResource meterTypeKey = Constant::eResource::DistrictHeatingWater;
     532              : 
     533           25 :     if (this->EnergyType == DataPlant::PlantEquipmentType::PurchChilledWater) {
     534            9 :         reportVarPrefix = "District Cooling Water ";
     535            9 :         heatingOrCooling = OutputProcessor::EndUseCat::Cooling;
     536            9 :         meterTypeKey = Constant::eResource::DistrictCooling;
     537           16 :     } else if (this->EnergyType == DataPlant::PlantEquipmentType::PurchSteam) {
     538            0 :         reportVarPrefix = "District Heating Steam ";
     539            0 :         heatingOrCooling = OutputProcessor::EndUseCat::Heating;
     540            0 :         meterTypeKey = Constant::eResource::DistrictHeatingSteam;
     541              :     }
     542           75 :     SetupOutputVariable(state,
     543           50 :                         format("{}Energy", reportVarPrefix),
     544              :                         Constant::Units::J,
     545           25 :                         this->EnergyTransfer,
     546              :                         OutputProcessor::TimeStepType::System,
     547              :                         OutputProcessor::StoreType::Sum,
     548           25 :                         this->Name,
     549              :                         meterTypeKey,
     550              :                         OutputProcessor::Group::Plant,
     551              :                         heatingOrCooling);
     552           75 :     SetupOutputVariable(state,
     553           50 :                         format("{}Rate", reportVarPrefix),
     554              :                         Constant::Units::W,
     555           25 :                         this->EnergyRate,
     556              :                         OutputProcessor::TimeStepType::System,
     557              :                         OutputProcessor::StoreType::Average,
     558           25 :                         this->Name);
     559           75 :     SetupOutputVariable(state,
     560           50 :                         format("{}Inlet Temperature", reportVarPrefix),
     561              :                         Constant::Units::C,
     562           25 :                         this->InletTemp,
     563              :                         OutputProcessor::TimeStepType::System,
     564              :                         OutputProcessor::StoreType::Average,
     565           25 :                         this->Name);
     566           75 :     SetupOutputVariable(state,
     567           50 :                         format("{}Outlet Temperature", reportVarPrefix),
     568              :                         Constant::Units::C,
     569           25 :                         this->OutletTemp,
     570              :                         OutputProcessor::TimeStepType::System,
     571              :                         OutputProcessor::StoreType::Average,
     572           25 :                         this->Name);
     573           75 :     SetupOutputVariable(state,
     574           50 :                         format("{}Mass Flow Rate", reportVarPrefix),
     575              :                         Constant::Units::kg_s,
     576           25 :                         this->MassFlowRate,
     577              :                         OutputProcessor::TimeStepType::System,
     578              :                         OutputProcessor::StoreType::Average,
     579           25 :                         this->Name);
     580           25 : }
     581              : 
     582            0 : void OutsideEnergySourceSpecs::oneTimeInit([[maybe_unused]] EnergyPlusData &state)
     583              : {
     584            0 : }
     585              : 
     586              : } // namespace EnergyPlus::OutsideEnergySources
        

Generated by: LCOV version 2.0-1