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

Generated by: LCOV version 2.0-1