LCOV - code coverage report
Current view: top level - EnergyPlus - SplitterComponent.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 84.5 % 245 207
Test Date: 2025-05-22 16:09:37 Functions: 100.0 % 8 8

            Line data    Source code
       1              : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
       2              : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3              : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4              : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5              : // contributors. All rights reserved.
       6              : //
       7              : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8              : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9              : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10              : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11              : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12              : //
      13              : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14              : // provided that the following conditions are met:
      15              : //
      16              : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17              : //     conditions and the following disclaimer.
      18              : //
      19              : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20              : //     conditions and the following disclaimer in the documentation and/or other materials
      21              : //     provided with the distribution.
      22              : //
      23              : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24              : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25              : //     used to endorse or promote products derived from this software without specific prior
      26              : //     written permission.
      27              : //
      28              : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29              : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30              : //     reference solely to the software portion of its product, Licensee must refer to the
      31              : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32              : //     obtained under this License and may not use a different name for the software. Except as
      33              : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34              : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35              : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36              : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37              : //
      38              : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39              : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40              : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41              : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42              : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43              : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44              : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45              : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46              : // POSSIBILITY OF SUCH DAMAGE.
      47              : 
      48              : // C++ Headers
      49              : #include <cmath>
      50              : 
      51              : // EnergyPlus Headers
      52              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      53              : #include <EnergyPlus/DataContaminantBalance.hh>
      54              : #include <EnergyPlus/DataEnvironment.hh>
      55              : #include <EnergyPlus/DataLoopNode.hh>
      56              : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      57              : #include <EnergyPlus/NodeInputManager.hh>
      58              : #include <EnergyPlus/Psychrometrics.hh>
      59              : #include <EnergyPlus/SplitterComponent.hh>
      60              : #include <EnergyPlus/UtilityRoutines.hh>
      61              : 
      62              : namespace EnergyPlus {
      63              : 
      64              : namespace SplitterComponent {
      65              :     // Module containing the Splitter simulation routines
      66              : 
      67              :     // MODULE INFORMATION:
      68              :     //       AUTHOR         Richard J. Liesen
      69              :     //       DATE WRITTEN   March 2000
      70              :     //       MODIFIED       na
      71              :     //       RE-ENGINEERED  na
      72              : 
      73              :     // PURPOSE OF THIS MODULE:
      74              :     // To encapsulate the data and algorithms required to
      75              :     // manage Air Path Splitter Components
      76              : 
      77              :     using namespace DataLoopNode;
      78              : 
      79       135111 :     void SimAirLoopSplitter(EnergyPlusData &state,
      80              :                             std::string_view CompName,
      81              :                             bool const FirstHVACIteration,
      82              :                             bool const FirstCall,
      83              :                             bool &SplitterInletChanged,
      84              :                             int &CompIndex)
      85              :     {
      86              : 
      87              :         // SUBROUTINE INFORMATION:
      88              :         //       AUTHOR         Richard Liesen
      89              :         //       DATE WRITTEN   March 2000
      90              :         //       MODIFIED       na
      91              :         //       RE-ENGINEERED  na
      92              : 
      93              :         // PURPOSE OF THIS SUBROUTINE:
      94              :         // This subroutine manages Splitter component simulation.
      95              :         // It is called from the SimAirLoopComponent
      96              :         // at the system time step.
      97              : 
      98              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
      99              :         int SplitterNum; // The Splitter that you are currently loading input for
     100              : 
     101              :         // Obtains and Allocates Splitter related parameters from input file
     102       135111 :         if (state.dataSplitterComponent->GetSplitterInputFlag) { // First time subroutine has been entered
     103           34 :             GetSplitterInput(state);
     104              :         }
     105              : 
     106              :         // Find the correct SplitterNumber
     107       135111 :         if (CompIndex == 0) {
     108           35 :             SplitterNum = Util::FindItemInList(CompName, state.dataSplitterComponent->SplitterCond, &SplitterConditions::SplitterName);
     109           35 :             if (SplitterNum == 0) {
     110            0 :                 ShowFatalError(state, format("SimAirLoopSplitter: Splitter not found={}", CompName));
     111              :             }
     112           35 :             CompIndex = SplitterNum;
     113              :         } else {
     114       135076 :             SplitterNum = CompIndex;
     115       135076 :             if (SplitterNum > state.dataSplitterComponent->NumSplitters || SplitterNum < 1) {
     116            0 :                 ShowFatalError(state,
     117            0 :                                format("SimAirLoopSplitter: Invalid CompIndex passed={}, Number of Splitters={}, Splitter name={}",
     118              :                                       SplitterNum,
     119            0 :                                       state.dataSplitterComponent->NumSplitters,
     120              :                                       CompName));
     121              :             }
     122       135076 :             if (state.dataSplitterComponent->CheckEquipName(SplitterNum)) {
     123           35 :                 if (CompName != state.dataSplitterComponent->SplitterCond(SplitterNum).SplitterName) {
     124            0 :                     ShowFatalError(state,
     125            0 :                                    format("SimAirLoopSplitter: Invalid CompIndex passed={}, Splitter name={}, stored Splitter Name for that index={}",
     126              :                                           SplitterNum,
     127              :                                           CompName,
     128            0 :                                           state.dataSplitterComponent->SplitterCond(SplitterNum).SplitterName));
     129              :                 }
     130           35 :                 state.dataSplitterComponent->CheckEquipName(SplitterNum) = false;
     131              :             }
     132              :         }
     133              : 
     134       135111 :         InitAirLoopSplitter(state, SplitterNum, FirstHVACIteration, FirstCall); // Initialize all Splitter related parameters
     135              : 
     136       135111 :         CalcAirLoopSplitter(state, SplitterNum, FirstCall);
     137              : 
     138              :         // Update the current Splitter to the outlet nodes
     139       135111 :         UpdateSplitter(state, SplitterNum, SplitterInletChanged, FirstCall);
     140              : 
     141              :         // Report the current Splitter
     142       135111 :         ReportSplitter(SplitterNum);
     143       135111 :     }
     144              : 
     145              :     //*******************************
     146              : 
     147              :     // Get Input Section of the Module
     148              :     //******************************************************************************
     149              : 
     150           46 :     void GetSplitterInput(EnergyPlusData &state)
     151              :     {
     152              : 
     153              :         // SUBROUTINE INFORMATION:
     154              :         //       AUTHOR         Richard J. Liesen
     155              :         //       DATE WRITTEN   March 2000
     156              :         //       MODIFIED       na
     157              :         //       RE-ENGINEERED  na
     158              : 
     159              :         // PURPOSE OF THIS SUBROUTINE:
     160              :         // This subroutine is the main routine to call other input routines and
     161              :         // Get routines.  The Splitter only gets node connection data and not mass
     162              :         // flow rates.
     163              : 
     164              :         // METHODOLOGY EMPLOYED:
     165              :         // Uses the status flags to trigger events.
     166              : 
     167              :         // Using/Aliasing
     168              :         using NodeInputManager::GetOnlySingleNode;
     169              : 
     170              :         // SUBROUTINE PARAMETER DEFINITIONS:
     171              :         static constexpr std::string_view RoutineName("GetSplitterInput: "); // include trailing blank space
     172              : 
     173              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     174              :         int SplitterNum; // The Splitter that you are currently loading input into
     175              :         int NumAlphas;
     176              :         int NumNums;
     177              :         int NodeNum;
     178              :         int IOStat;
     179           46 :         bool ErrorsFound(false);
     180              :         int NumParams;
     181              :         int OutNodeNum1;
     182              :         int OutNodeNum2;
     183           46 :         std::string CurrentModuleObject; // for ease in getting objects
     184           46 :         Array1D_string AlphArray;        // Alpha input items for object
     185           46 :         Array1D_string cAlphaFields;     // Alpha field names
     186           46 :         Array1D_string cNumericFields;   // Numeric field names
     187           46 :         Array1D<Real64> NumArray;        // Numeric input items for object
     188           46 :         Array1D_bool lAlphaBlanks;       // Logical array, alpha field input BLANK = .TRUE.
     189           46 :         Array1D_bool lNumericBlanks;     // Logical array, numeric field input BLANK = .TRUE.
     190              : 
     191              :         // RESET THE GETINPUT FLAG
     192           46 :         state.dataSplitterComponent->GetSplitterInputFlag = false;
     193              : 
     194           46 :         CurrentModuleObject = "AirLoopHVAC:ZoneSplitter";
     195           46 :         state.dataSplitterComponent->NumSplitters = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
     196              : 
     197           46 :         if (state.dataSplitterComponent->NumSplitters > 0)
     198           46 :             state.dataSplitterComponent->SplitterCond.allocate(state.dataSplitterComponent->NumSplitters);
     199           46 :         state.dataSplitterComponent->CheckEquipName.dimension(state.dataSplitterComponent->NumSplitters, true);
     200              : 
     201           46 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, NumParams, NumAlphas, NumNums);
     202           46 :         AlphArray.allocate(NumAlphas);
     203           46 :         cAlphaFields.allocate(NumAlphas);
     204           46 :         lAlphaBlanks.dimension(NumAlphas, true);
     205           46 :         cNumericFields.allocate(NumNums);
     206           46 :         lNumericBlanks.dimension(NumNums, true);
     207           46 :         NumArray.dimension(NumNums, 0.0);
     208              : 
     209           96 :         for (SplitterNum = 1; SplitterNum <= state.dataSplitterComponent->NumSplitters; ++SplitterNum) {
     210           50 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     211              :                                                                      CurrentModuleObject,
     212              :                                                                      SplitterNum,
     213              :                                                                      AlphArray,
     214              :                                                                      NumAlphas,
     215              :                                                                      NumArray,
     216              :                                                                      NumNums,
     217              :                                                                      IOStat,
     218              :                                                                      lNumericBlanks,
     219              :                                                                      lAlphaBlanks,
     220              :                                                                      cAlphaFields,
     221              :                                                                      cNumericFields);
     222           50 :             Util::IsNameEmpty(state, AlphArray(1), CurrentModuleObject, ErrorsFound);
     223              : 
     224           50 :             state.dataSplitterComponent->SplitterCond(SplitterNum).SplitterName = AlphArray(1);
     225           50 :             state.dataSplitterComponent->SplitterCond(SplitterNum).InletNode =
     226          100 :                 GetOnlySingleNode(state,
     227           50 :                                   AlphArray(2),
     228              :                                   ErrorsFound,
     229              :                                   DataLoopNode::ConnectionObjectType::AirLoopHVACZoneSplitter,
     230           50 :                                   AlphArray(1),
     231              :                                   DataLoopNode::NodeFluidType::Air,
     232              :                                   DataLoopNode::ConnectionType::Inlet,
     233              :                                   NodeInputManager::CompFluidStream::Primary,
     234              :                                   ObjectIsNotParent);
     235           50 :             state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes = NumAlphas - 2;
     236              : 
     237           50 :             state.dataSplitterComponent->SplitterCond(SplitterNum)
     238           50 :                 .OutletNode.allocate(state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes);
     239           50 :             state.dataSplitterComponent->SplitterCond(SplitterNum)
     240           50 :                 .OutletMassFlowRate.allocate(state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes);
     241           50 :             state.dataSplitterComponent->SplitterCond(SplitterNum)
     242           50 :                 .OutletMassFlowRateMaxAvail.allocate(state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes);
     243           50 :             state.dataSplitterComponent->SplitterCond(SplitterNum)
     244           50 :                 .OutletMassFlowRateMinAvail.allocate(state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes);
     245           50 :             state.dataSplitterComponent->SplitterCond(SplitterNum)
     246           50 :                 .OutletTemp.allocate(state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes);
     247           50 :             state.dataSplitterComponent->SplitterCond(SplitterNum)
     248           50 :                 .OutletHumRat.allocate(state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes);
     249           50 :             state.dataSplitterComponent->SplitterCond(SplitterNum)
     250           50 :                 .OutletEnthalpy.allocate(state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes);
     251           50 :             state.dataSplitterComponent->SplitterCond(SplitterNum)
     252           50 :                 .OutletPressure.allocate(state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes);
     253              : 
     254           50 :             state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRate = 0.0;
     255           50 :             state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRateMaxAvail = 0.0;
     256           50 :             state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRateMinAvail = 0.0;
     257              : 
     258          127 :             for (NodeNum = 1; NodeNum <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++NodeNum) {
     259              : 
     260           77 :                 state.dataSplitterComponent->SplitterCond(SplitterNum).OutletNode(NodeNum) =
     261          154 :                     GetOnlySingleNode(state,
     262           77 :                                       AlphArray(2 + NodeNum),
     263              :                                       ErrorsFound,
     264              :                                       DataLoopNode::ConnectionObjectType::AirLoopHVACZoneSplitter,
     265           77 :                                       AlphArray(1),
     266              :                                       DataLoopNode::NodeFluidType::Air,
     267              :                                       DataLoopNode::ConnectionType::Outlet,
     268              :                                       NodeInputManager::CompFluidStream::Primary,
     269              :                                       ObjectIsNotParent);
     270           77 :                 if (lAlphaBlanks(2 + NodeNum)) {
     271            0 :                     ShowSevereError(state, format("{} is Blank, {} = {}", cAlphaFields(2 + NodeNum), CurrentModuleObject, AlphArray(1)));
     272            0 :                     ErrorsFound = true;
     273              :                 }
     274              :             }
     275              : 
     276              :         } // end Number of Splitter Loop
     277              : 
     278              :         // Check for duplicate names specified in Zone Splitter
     279           96 :         for (SplitterNum = 1; SplitterNum <= state.dataSplitterComponent->NumSplitters; ++SplitterNum) {
     280           50 :             NodeNum = state.dataSplitterComponent->SplitterCond(SplitterNum).InletNode;
     281          127 :             for (OutNodeNum1 = 1; OutNodeNum1 <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++OutNodeNum1) {
     282           77 :                 if (NodeNum != state.dataSplitterComponent->SplitterCond(SplitterNum).OutletNode(OutNodeNum1)) continue;
     283            0 :                 ShowSevereError(state,
     284            0 :                                 format("{} = {} specifies an outlet node name the same as the inlet node.",
     285              :                                        CurrentModuleObject,
     286            0 :                                        state.dataSplitterComponent->SplitterCond(SplitterNum).SplitterName));
     287            0 :                 ShowContinueError(state, format("..{}={}", cAlphaFields(2), state.dataLoopNodes->NodeID(NodeNum)));
     288            0 :                 ShowContinueError(state, format("..Outlet Node #{} is duplicate.", OutNodeNum1));
     289            0 :                 ErrorsFound = true;
     290              :             }
     291          127 :             for (OutNodeNum1 = 1; OutNodeNum1 <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++OutNodeNum1) {
     292          120 :                 for (OutNodeNum2 = OutNodeNum1 + 1; OutNodeNum2 <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes;
     293              :                      ++OutNodeNum2) {
     294           43 :                     if (state.dataSplitterComponent->SplitterCond(SplitterNum).OutletNode(OutNodeNum1) !=
     295           43 :                         state.dataSplitterComponent->SplitterCond(SplitterNum).OutletNode(OutNodeNum2))
     296           43 :                         continue;
     297            0 :                     ShowSevereError(state,
     298            0 :                                     format("{} = {} specifies duplicate outlet nodes in its outlet node list.",
     299              :                                            CurrentModuleObject,
     300            0 :                                            state.dataSplitterComponent->SplitterCond(SplitterNum).SplitterName));
     301            0 :                     ShowContinueError(state, format("..Outlet Node #{} Name={}", OutNodeNum1, state.dataLoopNodes->NodeID(OutNodeNum1)));
     302            0 :                     ShowContinueError(state, format("..Outlet Node #{} is duplicate.", OutNodeNum2));
     303            0 :                     ErrorsFound = true;
     304              :                 }
     305              :             }
     306              :         }
     307              : 
     308           46 :         AlphArray.deallocate();
     309           46 :         NumArray.deallocate();
     310           46 :         cAlphaFields.deallocate();
     311           46 :         lAlphaBlanks.deallocate();
     312           46 :         cNumericFields.deallocate();
     313           46 :         lNumericBlanks.deallocate();
     314              : 
     315           46 :         if (ErrorsFound) {
     316            0 :             ShowFatalError(state, format("{}Errors found in getting input.", RoutineName));
     317              :         }
     318           46 :     }
     319              : 
     320       135111 :     void InitAirLoopSplitter(EnergyPlusData &state, int const SplitterNum, bool const FirstHVACIteration, bool const FirstCall)
     321              :     {
     322              : 
     323              :         // SUBROUTINE INFORMATION:
     324              :         //       AUTHOR         Richard J. Liesen
     325              :         //       DATE WRITTEN   March 2000
     326              :         //       MODIFIED       na
     327              :         //       RE-ENGINEERED  na
     328              : 
     329              :         // PURPOSE OF THIS SUBROUTINE:
     330              :         // This subroutine is for initialisations of the Splitter Components.
     331              : 
     332              :         // METHODOLOGY EMPLOYED:
     333              :         // Uses the status flags to trigger events.
     334              : 
     335              :         using Psychrometrics::PsyHFnTdbW;
     336              : 
     337              :         int InletNode;
     338              :         int OutletNode;
     339              :         int NodeNum;
     340              :         Real64 AirEnthalpy; // [J/kg]
     341              : 
     342              :         // Do the Begin Environment initializations
     343       135111 :         if (state.dataGlobal->BeginEnvrnFlag && state.dataSplitterComponent->MyEnvrnFlag) {
     344              : 
     345              :             // Calculate the air density and enthalpy for standard conditions...
     346           84 :             AirEnthalpy = PsyHFnTdbW(20.0, state.dataEnvrn->OutHumRat);
     347              : 
     348              :             // Initialize the inlet node to s standard set of conditions so that the
     349              :             //  flows match around the loop & do not cause convergence problems.
     350           84 :             InletNode = state.dataSplitterComponent->SplitterCond(SplitterNum).InletNode;
     351           84 :             state.dataLoopNodes->Node(InletNode).Temp = 20.0;
     352           84 :             state.dataLoopNodes->Node(InletNode).HumRat = state.dataEnvrn->OutHumRat;
     353           84 :             state.dataLoopNodes->Node(InletNode).Enthalpy = AirEnthalpy;
     354           84 :             state.dataLoopNodes->Node(InletNode).Press = state.dataEnvrn->OutBaroPress;
     355           84 :             if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
     356            0 :                 state.dataLoopNodes->Node(InletNode).CO2 = state.dataContaminantBalance->OutdoorCO2;
     357              :             }
     358           84 :             if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
     359            0 :                 state.dataLoopNodes->Node(InletNode).GenContam = state.dataContaminantBalance->OutdoorGC;
     360              :             }
     361              : 
     362           84 :             state.dataSplitterComponent->MyEnvrnFlag = false;
     363              :         }
     364              : 
     365       135111 :         if (!state.dataGlobal->BeginEnvrnFlag) {
     366       133588 :             state.dataSplitterComponent->MyEnvrnFlag = true;
     367              :         }
     368              : 
     369              :         // Set the inlet node for the Splitter
     370       135111 :         InletNode = state.dataSplitterComponent->SplitterCond(SplitterNum).InletNode;
     371              : 
     372              :         // Do the following initializations (every time step): This should be the info from
     373              :         // the previous components outlets or the node data in this section.
     374              :         // Load the node data in this section for the component simulation
     375              : 
     376              :         // This section is very important to understand.  The system off condition is important
     377              :         // transfer around the loop even if the splitter does not have enough information to
     378              :         // calculate the correct flow rates since the dampers are downstream and there is no pressure
     379              :         // simulation.  What happens in this section is the flow from upstream is not zero is
     380              :         // arbitrarily split by the number of inlet nodes.  This is by no way meant to determine the
     381              :         // correct split flow!  Just to give each outlet a non-zero flow so that the Air Distribution
     382              :         // Unit(ADU) downstream knows that the system is operating or has flow.  This is only done the first
     383              :         // iteration through and the splitter first pass.  After the first iteration the ADU sets the
     384              :         // correct flow and that is used and passed back upstream.
     385       135111 :         if (FirstHVACIteration && FirstCall) {
     386        34392 :             if (state.dataLoopNodes->Node(InletNode).MassFlowRate > 0.0) {
     387        85590 :                 for (NodeNum = 1; NodeNum <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++NodeNum) {
     388        53592 :                     OutletNode = state.dataSplitterComponent->SplitterCond(SplitterNum).OutletNode(NodeNum);
     389        53592 :                     state.dataLoopNodes->Node(OutletNode).MassFlowRate =
     390        53592 :                         state.dataLoopNodes->Node(InletNode).MassFlowRate / state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes;
     391              :                 }
     392              :             }
     393        34392 :             if (state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail > 0.0) {
     394        85608 :                 for (NodeNum = 1; NodeNum <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++NodeNum) {
     395        53606 :                     OutletNode = state.dataSplitterComponent->SplitterCond(SplitterNum).OutletNode(NodeNum);
     396        53606 :                     state.dataLoopNodes->Node(OutletNode).MassFlowRateMaxAvail =
     397        53606 :                         state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail /
     398        53606 :                         state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes;
     399              :                 }
     400              :             }
     401              : 
     402              :         } // For FirstHVACIteration and FirstCall
     403              : 
     404       135111 :         if (FirstCall) {
     405              :             // There is one exception to the rule stated above and that is if the system shuts OFF
     406              :             // for some operational or algorithm dependency.  This IF block should catch that condition
     407              :             // and then pass the NO flow condition downstream to the waiting ADU's.  Most of the time
     408              :             // this IF is jumped over.
     409        67556 :             if (state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail == 0.0) {
     410              : 
     411        17695 :                 for (NodeNum = 1; NodeNum <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++NodeNum) {
     412              : 
     413         9877 :                     OutletNode = state.dataSplitterComponent->SplitterCond(SplitterNum).OutletNode(NodeNum);
     414         9877 :                     state.dataLoopNodes->Node(OutletNode).MassFlowRate = 0.0;
     415         9877 :                     state.dataLoopNodes->Node(OutletNode).MassFlowRateMaxAvail = 0.0;
     416         9877 :                     state.dataLoopNodes->Node(OutletNode).MassFlowRateMinAvail = 0.0;
     417              :                 }
     418              :             } // For Node inlet Max Avail = 0.0
     419              : 
     420              :             // Pass the State Properties through every time.  This is what mainly happens each time
     421              :             // through the splitter,
     422        67556 :             InletNode = state.dataSplitterComponent->SplitterCond(SplitterNum).InletNode;
     423        67556 :             state.dataSplitterComponent->SplitterCond(SplitterNum).InletTemp = state.dataLoopNodes->Node(InletNode).Temp;
     424        67556 :             state.dataSplitterComponent->SplitterCond(SplitterNum).InletHumRat = state.dataLoopNodes->Node(InletNode).HumRat;
     425        67556 :             state.dataSplitterComponent->SplitterCond(SplitterNum).InletEnthalpy = state.dataLoopNodes->Node(InletNode).Enthalpy;
     426        67556 :             state.dataSplitterComponent->SplitterCond(SplitterNum).InletPressure = state.dataLoopNodes->Node(InletNode).Press;
     427              : 
     428              :         } else { // On the second call from the ZoneEquipManager this is where the flows are passed back to
     429              :             // the splitter inlet.
     430       179594 :             for (NodeNum = 1; NodeNum <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++NodeNum) {
     431              : 
     432       112039 :                 OutletNode = state.dataSplitterComponent->SplitterCond(SplitterNum).OutletNode(NodeNum);
     433       112039 :                 state.dataSplitterComponent->SplitterCond(SplitterNum).OutletMassFlowRate(NodeNum) =
     434       112039 :                     state.dataLoopNodes->Node(OutletNode).MassFlowRate;
     435       112039 :                 state.dataSplitterComponent->SplitterCond(SplitterNum).OutletMassFlowRateMaxAvail(NodeNum) =
     436       112039 :                     state.dataLoopNodes->Node(OutletNode).MassFlowRateMaxAvail;
     437       112039 :                 state.dataSplitterComponent->SplitterCond(SplitterNum).OutletMassFlowRateMinAvail(NodeNum) =
     438       112039 :                     state.dataLoopNodes->Node(OutletNode).MassFlowRateMinAvail;
     439              :             }
     440              : 
     441              :         } // For FirstCall
     442       135111 :     }
     443              : 
     444       135111 :     void CalcAirLoopSplitter(EnergyPlusData &state, int const SplitterNum, bool const FirstCall)
     445              :     {
     446              : 
     447              :         // SUBROUTINE INFORMATION:
     448              :         //       AUTHOR         Richard J. Liesen
     449              :         //       DATE WRITTEN   March 2000
     450              :         //       MODIFIED       na
     451              :         //       RE-ENGINEERED  na
     452              : 
     453              :         // PURPOSE OF THIS SUBROUTINE:
     454              :         // This subroutine needs a description.
     455              : 
     456              :         // METHODOLOGY EMPLOYED:
     457              :         // Needs description, as appropriate.
     458              : 
     459              :         int OutletNodeNum;
     460              : 
     461              :         // The first time through the State properties are split and passed through
     462       135111 :         if (FirstCall) {
     463              :             // Moisture balance to get outlet air humidity ratio
     464       179596 :             for (OutletNodeNum = 1; OutletNodeNum <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++OutletNodeNum) {
     465       112040 :                 state.dataSplitterComponent->SplitterCond(SplitterNum).OutletHumRat(OutletNodeNum) =
     466       112040 :                     state.dataSplitterComponent->SplitterCond(SplitterNum).InletHumRat;
     467              :             }
     468              : 
     469              :             // "Momentum balance" to get outlet air pressure
     470       179596 :             for (OutletNodeNum = 1; OutletNodeNum <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++OutletNodeNum) {
     471       112040 :                 state.dataSplitterComponent->SplitterCond(SplitterNum).OutletPressure(OutletNodeNum) =
     472       112040 :                     state.dataSplitterComponent->SplitterCond(SplitterNum).InletPressure;
     473              :             }
     474              : 
     475              :             // Energy balance to get outlet air enthalpy
     476       179596 :             for (OutletNodeNum = 1; OutletNodeNum <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++OutletNodeNum) {
     477       112040 :                 state.dataSplitterComponent->SplitterCond(SplitterNum).OutletEnthalpy(OutletNodeNum) =
     478       112040 :                     state.dataSplitterComponent->SplitterCond(SplitterNum).InletEnthalpy;
     479              :             }
     480              : 
     481              :             // Set outlet temperatures equal to inlet temperature
     482       179596 :             for (OutletNodeNum = 1; OutletNodeNum <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++OutletNodeNum) {
     483       112040 :                 state.dataSplitterComponent->SplitterCond(SplitterNum).OutletTemp(OutletNodeNum) =
     484       112040 :                     state.dataSplitterComponent->SplitterCond(SplitterNum).InletTemp;
     485              :             }
     486              : 
     487              :         } else {
     488              :             // This is the second time through and this is where the mass flows from each outlet are
     489              :             // summed and then assigned upstream to the inlet node.
     490              :             // Overall Mass Continuity Equation to get inlet mass flow rates
     491              :             // Zero the inlet Totals before the Inlets are summed
     492        67555 :             state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRate = 0.0;
     493        67555 :             state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRateMaxAvail = 0.0;
     494        67555 :             state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRateMinAvail = 0.0;
     495              : 
     496       179594 :             for (OutletNodeNum = 1; OutletNodeNum <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++OutletNodeNum) {
     497       112039 :                 state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRate +=
     498       112039 :                     state.dataSplitterComponent->SplitterCond(SplitterNum).OutletMassFlowRate(OutletNodeNum);
     499              : 
     500       112039 :                 state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRateMaxAvail +=
     501       112039 :                     state.dataSplitterComponent->SplitterCond(SplitterNum).OutletMassFlowRateMaxAvail(OutletNodeNum);
     502       112039 :                 state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRateMinAvail +=
     503       112039 :                     state.dataSplitterComponent->SplitterCond(SplitterNum).OutletMassFlowRateMinAvail(OutletNodeNum);
     504              :             }
     505              : 
     506              :             // What happens if Splitter inlet mass flow rate is greater than max available
     507              :         }
     508       135111 :     }
     509              : 
     510              :     // End Algorithm Section of the Module
     511              :     // *****************************************************************************
     512              : 
     513              :     // Beginning of Update subroutines for the Splitter Module
     514              :     // *****************************************************************************
     515              : 
     516       135111 :     void UpdateSplitter(EnergyPlusData &state, int const SplitterNum, bool &SplitterInletChanged, bool const FirstCall)
     517              :     {
     518              :         // SUBROUTINE INFORMATION:
     519              :         //       AUTHOR         Richard J. Liesen
     520              :         //       DATE WRITTEN   March 2000
     521              :         //       MODIFIED       na
     522              :         //       RE-ENGINEERED  na
     523              : 
     524       135111 :         Real64 constexpr FlowRateToler(0.01); // Tolerance for mass flow rate convergence (in kg/s)
     525              : 
     526              :         int InletNode;
     527              :         int OutletNode;
     528              :         int NodeNum;
     529              : 
     530              :         // Set the inlet node for this splitter to be used throughout subroutine for either case
     531       135111 :         InletNode = state.dataSplitterComponent->SplitterCond(SplitterNum).InletNode;
     532              : 
     533              :         // On the FirstCall the State properties are passed through and the mass flows are not dealt with
     534              :         // except for NO flow conditions
     535       135111 :         if (FirstCall) {
     536              :             // Set the outlet nodes for properties that just pass through & not used
     537       179596 :             for (NodeNum = 1; NodeNum <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++NodeNum) {
     538       112040 :                 OutletNode = state.dataSplitterComponent->SplitterCond(SplitterNum).OutletNode(NodeNum);
     539       112040 :                 state.dataLoopNodes->Node(OutletNode).Temp = state.dataSplitterComponent->SplitterCond(SplitterNum).OutletTemp(NodeNum);
     540       112040 :                 state.dataLoopNodes->Node(OutletNode).HumRat = state.dataSplitterComponent->SplitterCond(SplitterNum).OutletHumRat(NodeNum);
     541       112040 :                 state.dataLoopNodes->Node(OutletNode).Enthalpy = state.dataSplitterComponent->SplitterCond(SplitterNum).OutletEnthalpy(NodeNum);
     542       112040 :                 state.dataLoopNodes->Node(OutletNode).Quality = state.dataLoopNodes->Node(InletNode).Quality;
     543       112040 :                 state.dataLoopNodes->Node(OutletNode).Press = state.dataSplitterComponent->SplitterCond(SplitterNum).OutletPressure(NodeNum);
     544       112040 :                 if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
     545            0 :                     state.dataLoopNodes->Node(OutletNode).CO2 = state.dataLoopNodes->Node(InletNode).CO2;
     546              :                 }
     547       112040 :                 if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
     548            0 :                     state.dataLoopNodes->Node(OutletNode).GenContam = state.dataLoopNodes->Node(InletNode).GenContam;
     549              :                 }
     550              :             }
     551              : 
     552              :         } else {
     553              :             // The second time through just updates the mass flow conditions back upstream
     554              :             //  to the inlet.  Before it sets the inlet it checks to see that the flow rate has not
     555              :             //  changed or not.  The tolerance has been relaxed some now that the splitter has been
     556              :             //  re-written
     557              : 
     558              :             // Set the outlet air nodes of the Splitter if the splitter results have changed
     559              :             //  beyond the tolerance.
     560        67555 :             if (std::abs(state.dataLoopNodes->Node(InletNode).MassFlowRate -
     561        67555 :                          state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRate) > FlowRateToler) {
     562        11946 :                 SplitterInletChanged = true;
     563              :             }
     564        67555 :             state.dataLoopNodes->Node(InletNode).MassFlowRate = state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRate;
     565        67555 :             state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail =
     566        67555 :                 state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRateMaxAvail;
     567        67555 :             state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail =
     568        67555 :                 state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRateMinAvail;
     569              : 
     570              :         } // The FirstCall END IF
     571       135111 :     }
     572              : 
     573       135111 :     void ReportSplitter([[maybe_unused]] int const SplitterNum)
     574              :     {
     575              : 
     576              :         // SUBROUTINE INFORMATION:
     577              :         //       AUTHOR         Richard J. Liesen
     578              :         //       DATE WRITTEN   March 2000
     579              :         //       MODIFIED       na
     580              :         //       RE-ENGINEERED  na
     581              : 
     582              :         // Write(*,*)=SplitterCond(SplitterNum)%SplitterPower    Still needs to report the Splitter power from this component
     583       135111 :     }
     584              : 
     585            1 :     int GetSplitterOutletNumber(EnergyPlusData &state,
     586              :                                 std::string const &SplitterName, // must match Splitter names for the Splitter type
     587              :                                 int const SplitterNum,           // Index of Splitters
     588              :                                 bool &ErrorsFound                // set to true if problem
     589              :     )
     590              :     {
     591              : 
     592              :         // FUNCTION INFORMATION:
     593              :         //       AUTHOR         Lixing Gu
     594              :         //       DATE WRITTEN   Feb 2013
     595              :         //       MODIFIED       na
     596              :         //       RE-ENGINEERED  na
     597              : 
     598              :         // PURPOSE OF THIS FUNCTION:
     599              :         // This function looks up the given AirLoopHVAC:ZoneSplitter and returns the number of outlet nodes.  If
     600              :         // incorrect AirLoopHVAC:ZoneSplitter name is given, ErrorsFound is returned as true
     601              :         // as zero.
     602              : 
     603              :         // Return value
     604              :         int SplitterOutletNumber;
     605              : 
     606              :         // FUNCTION LOCAL VARIABLE DECLARATIONS:
     607              :         int WhichSplitter;
     608              : 
     609              :         // Obtains and Allocates AirLoopHVAC:ZoneSplitter related parameters from input file
     610            1 :         if (state.dataSplitterComponent->GetSplitterInputFlag) { // First time subroutine has been entered
     611            0 :             GetSplitterInput(state);
     612            0 :             state.dataSplitterComponent->GetSplitterInputFlag = false;
     613              :         }
     614              : 
     615            1 :         if (SplitterNum == 0) {
     616            0 :             WhichSplitter = Util::FindItemInList(SplitterName, state.dataSplitterComponent->SplitterCond, &SplitterConditions::SplitterName);
     617              :         } else {
     618            1 :             WhichSplitter = SplitterNum;
     619              :         }
     620              : 
     621            1 :         if (WhichSplitter != 0) {
     622            1 :             SplitterOutletNumber = state.dataSplitterComponent->SplitterCond(WhichSplitter).NumOutletNodes;
     623              :         }
     624              : 
     625            1 :         if (WhichSplitter == 0) {
     626            0 :             ShowSevereError(state, format("GetSplitterOuletNumber: Could not find Splitter = \"{}\"", SplitterName));
     627            0 :             ErrorsFound = true;
     628            0 :             SplitterOutletNumber = 0;
     629              :         }
     630              : 
     631            1 :         return SplitterOutletNumber;
     632              :     }
     633              : 
     634            1 :     Array1D_int GetSplitterNodeNumbers(EnergyPlusData &state,
     635              :                                        std::string const &SplitterName, // must match Splitter names for the Splitter type
     636              :                                        int const SplitterNum,           // Index of Splitters
     637              :                                        bool &ErrorsFound                // set to true if problem
     638              :     )
     639              :     {
     640              : 
     641              :         // FUNCTION INFORMATION:
     642              :         //       AUTHOR         Lixing Gu
     643              :         //       DATE WRITTEN   Feb 2013
     644              :         //       MODIFIED       na
     645              :         //       RE-ENGINEERED  na
     646              : 
     647              :         // PURPOSE OF THIS FUNCTION:
     648              :         // This function looks up the given AirLoopHVAC:ZoneSplitter and returns the node numbers.  If
     649              :         // incorrect AirLoopHVAC:ZoneSplitter name is given, ErrorsFound is returned as true
     650              :         // as zero.
     651              : 
     652              :         // Return value
     653            1 :         Array1D_int SplitterNodeNumbers;
     654              : 
     655              :         // FUNCTION LOCAL VARIABLE DECLARATIONS:
     656              :         int WhichSplitter;
     657              :         int i;
     658              : 
     659              :         // Obtains and Allocates AirLoopHVAC:ZoneSplitter related parameters from input file
     660            1 :         if (state.dataSplitterComponent->GetSplitterInputFlag) { // First time subroutine has been entered
     661            0 :             GetSplitterInput(state);
     662            0 :             state.dataSplitterComponent->GetSplitterInputFlag = false;
     663              :         }
     664              : 
     665            1 :         if (SplitterNum == 0) {
     666            0 :             WhichSplitter = Util::FindItemInList(SplitterName, state.dataSplitterComponent->SplitterCond, &SplitterConditions::SplitterName);
     667              :         } else {
     668            1 :             WhichSplitter = SplitterNum;
     669              :         }
     670              : 
     671            1 :         if (WhichSplitter != 0) {
     672            1 :             SplitterNodeNumbers.allocate(state.dataSplitterComponent->SplitterCond(WhichSplitter).NumOutletNodes + 2);
     673            1 :             SplitterNodeNumbers(1) = state.dataSplitterComponent->SplitterCond(WhichSplitter).InletNode;
     674            1 :             SplitterNodeNumbers(2) = state.dataSplitterComponent->SplitterCond(WhichSplitter).NumOutletNodes;
     675            2 :             for (i = 1; i <= SplitterNodeNumbers(2); ++i) {
     676            1 :                 SplitterNodeNumbers(i + 2) = state.dataSplitterComponent->SplitterCond(WhichSplitter).OutletNode(i);
     677              :             }
     678              :         }
     679              : 
     680            1 :         if (WhichSplitter == 0) {
     681            0 :             ShowSevereError(state, format("GetSplitterNodeNumbers: Could not find Splitter = \"{}\"", SplitterName));
     682            0 :             ErrorsFound = true;
     683              :         }
     684              : 
     685            1 :         return SplitterNodeNumbers;
     686            0 :     }
     687              : 
     688              : } // namespace SplitterComponent
     689              : 
     690              : } // namespace EnergyPlus
        

Generated by: LCOV version 2.0-1