LCOV - code coverage report
Current view: top level - EnergyPlus - SplitterComponent.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 84.6 % 246 208
Test Date: 2025-06-02 12:03:30 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              :         }
     200           46 :         state.dataSplitterComponent->CheckEquipName.dimension(state.dataSplitterComponent->NumSplitters, true);
     201              : 
     202           46 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, NumParams, NumAlphas, NumNums);
     203           46 :         AlphArray.allocate(NumAlphas);
     204           46 :         cAlphaFields.allocate(NumAlphas);
     205           46 :         lAlphaBlanks.dimension(NumAlphas, true);
     206           46 :         cNumericFields.allocate(NumNums);
     207           46 :         lNumericBlanks.dimension(NumNums, true);
     208           46 :         NumArray.dimension(NumNums, 0.0);
     209              : 
     210           96 :         for (SplitterNum = 1; SplitterNum <= state.dataSplitterComponent->NumSplitters; ++SplitterNum) {
     211           50 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     212              :                                                                      CurrentModuleObject,
     213              :                                                                      SplitterNum,
     214              :                                                                      AlphArray,
     215              :                                                                      NumAlphas,
     216              :                                                                      NumArray,
     217              :                                                                      NumNums,
     218              :                                                                      IOStat,
     219              :                                                                      lNumericBlanks,
     220              :                                                                      lAlphaBlanks,
     221              :                                                                      cAlphaFields,
     222              :                                                                      cNumericFields);
     223           50 :             Util::IsNameEmpty(state, AlphArray(1), CurrentModuleObject, ErrorsFound);
     224              : 
     225           50 :             state.dataSplitterComponent->SplitterCond(SplitterNum).SplitterName = AlphArray(1);
     226           50 :             state.dataSplitterComponent->SplitterCond(SplitterNum).InletNode =
     227          100 :                 GetOnlySingleNode(state,
     228           50 :                                   AlphArray(2),
     229              :                                   ErrorsFound,
     230              :                                   DataLoopNode::ConnectionObjectType::AirLoopHVACZoneSplitter,
     231           50 :                                   AlphArray(1),
     232              :                                   DataLoopNode::NodeFluidType::Air,
     233              :                                   DataLoopNode::ConnectionType::Inlet,
     234              :                                   NodeInputManager::CompFluidStream::Primary,
     235              :                                   ObjectIsNotParent);
     236           50 :             state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes = NumAlphas - 2;
     237              : 
     238           50 :             state.dataSplitterComponent->SplitterCond(SplitterNum)
     239           50 :                 .OutletNode.allocate(state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes);
     240           50 :             state.dataSplitterComponent->SplitterCond(SplitterNum)
     241           50 :                 .OutletMassFlowRate.allocate(state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes);
     242           50 :             state.dataSplitterComponent->SplitterCond(SplitterNum)
     243           50 :                 .OutletMassFlowRateMaxAvail.allocate(state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes);
     244           50 :             state.dataSplitterComponent->SplitterCond(SplitterNum)
     245           50 :                 .OutletMassFlowRateMinAvail.allocate(state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes);
     246           50 :             state.dataSplitterComponent->SplitterCond(SplitterNum)
     247           50 :                 .OutletTemp.allocate(state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes);
     248           50 :             state.dataSplitterComponent->SplitterCond(SplitterNum)
     249           50 :                 .OutletHumRat.allocate(state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes);
     250           50 :             state.dataSplitterComponent->SplitterCond(SplitterNum)
     251           50 :                 .OutletEnthalpy.allocate(state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes);
     252           50 :             state.dataSplitterComponent->SplitterCond(SplitterNum)
     253           50 :                 .OutletPressure.allocate(state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes);
     254              : 
     255           50 :             state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRate = 0.0;
     256           50 :             state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRateMaxAvail = 0.0;
     257           50 :             state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRateMinAvail = 0.0;
     258              : 
     259          127 :             for (NodeNum = 1; NodeNum <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++NodeNum) {
     260              : 
     261           77 :                 state.dataSplitterComponent->SplitterCond(SplitterNum).OutletNode(NodeNum) =
     262          154 :                     GetOnlySingleNode(state,
     263           77 :                                       AlphArray(2 + NodeNum),
     264              :                                       ErrorsFound,
     265              :                                       DataLoopNode::ConnectionObjectType::AirLoopHVACZoneSplitter,
     266           77 :                                       AlphArray(1),
     267              :                                       DataLoopNode::NodeFluidType::Air,
     268              :                                       DataLoopNode::ConnectionType::Outlet,
     269              :                                       NodeInputManager::CompFluidStream::Primary,
     270              :                                       ObjectIsNotParent);
     271           77 :                 if (lAlphaBlanks(2 + NodeNum)) {
     272            0 :                     ShowSevereError(state, format("{} is Blank, {} = {}", cAlphaFields(2 + NodeNum), CurrentModuleObject, AlphArray(1)));
     273            0 :                     ErrorsFound = true;
     274              :                 }
     275              :             }
     276              : 
     277              :         } // end Number of Splitter Loop
     278              : 
     279              :         // Check for duplicate names specified in Zone Splitter
     280           96 :         for (SplitterNum = 1; SplitterNum <= state.dataSplitterComponent->NumSplitters; ++SplitterNum) {
     281           50 :             NodeNum = state.dataSplitterComponent->SplitterCond(SplitterNum).InletNode;
     282          127 :             for (OutNodeNum1 = 1; OutNodeNum1 <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++OutNodeNum1) {
     283           77 :                 if (NodeNum != state.dataSplitterComponent->SplitterCond(SplitterNum).OutletNode(OutNodeNum1)) {
     284           77 :                     continue;
     285              :                 }
     286            0 :                 ShowSevereError(state,
     287            0 :                                 format("{} = {} specifies an outlet node name the same as the inlet node.",
     288              :                                        CurrentModuleObject,
     289            0 :                                        state.dataSplitterComponent->SplitterCond(SplitterNum).SplitterName));
     290            0 :                 ShowContinueError(state, format("..{}={}", cAlphaFields(2), state.dataLoopNodes->NodeID(NodeNum)));
     291            0 :                 ShowContinueError(state, format("..Outlet Node #{} is duplicate.", OutNodeNum1));
     292            0 :                 ErrorsFound = true;
     293              :             }
     294          127 :             for (OutNodeNum1 = 1; OutNodeNum1 <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++OutNodeNum1) {
     295          120 :                 for (OutNodeNum2 = OutNodeNum1 + 1; OutNodeNum2 <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes;
     296              :                      ++OutNodeNum2) {
     297           43 :                     if (state.dataSplitterComponent->SplitterCond(SplitterNum).OutletNode(OutNodeNum1) !=
     298           43 :                         state.dataSplitterComponent->SplitterCond(SplitterNum).OutletNode(OutNodeNum2)) {
     299           43 :                         continue;
     300              :                     }
     301            0 :                     ShowSevereError(state,
     302            0 :                                     format("{} = {} specifies duplicate outlet nodes in its outlet node list.",
     303              :                                            CurrentModuleObject,
     304            0 :                                            state.dataSplitterComponent->SplitterCond(SplitterNum).SplitterName));
     305            0 :                     ShowContinueError(state, format("..Outlet Node #{} Name={}", OutNodeNum1, state.dataLoopNodes->NodeID(OutNodeNum1)));
     306            0 :                     ShowContinueError(state, format("..Outlet Node #{} is duplicate.", OutNodeNum2));
     307            0 :                     ErrorsFound = true;
     308              :                 }
     309              :             }
     310              :         }
     311              : 
     312           46 :         AlphArray.deallocate();
     313           46 :         NumArray.deallocate();
     314           46 :         cAlphaFields.deallocate();
     315           46 :         lAlphaBlanks.deallocate();
     316           46 :         cNumericFields.deallocate();
     317           46 :         lNumericBlanks.deallocate();
     318              : 
     319           46 :         if (ErrorsFound) {
     320            0 :             ShowFatalError(state, format("{}Errors found in getting input.", RoutineName));
     321              :         }
     322           46 :     }
     323              : 
     324       135111 :     void InitAirLoopSplitter(EnergyPlusData &state, int const SplitterNum, bool const FirstHVACIteration, bool const FirstCall)
     325              :     {
     326              : 
     327              :         // SUBROUTINE INFORMATION:
     328              :         //       AUTHOR         Richard J. Liesen
     329              :         //       DATE WRITTEN   March 2000
     330              :         //       MODIFIED       na
     331              :         //       RE-ENGINEERED  na
     332              : 
     333              :         // PURPOSE OF THIS SUBROUTINE:
     334              :         // This subroutine is for initialisations of the Splitter Components.
     335              : 
     336              :         // METHODOLOGY EMPLOYED:
     337              :         // Uses the status flags to trigger events.
     338              : 
     339              :         using Psychrometrics::PsyHFnTdbW;
     340              : 
     341              :         int InletNode;
     342              :         int OutletNode;
     343              :         int NodeNum;
     344              :         Real64 AirEnthalpy; // [J/kg]
     345              : 
     346              :         // Do the Begin Environment initializations
     347       135111 :         if (state.dataGlobal->BeginEnvrnFlag && state.dataSplitterComponent->MyEnvrnFlag) {
     348              : 
     349              :             // Calculate the air density and enthalpy for standard conditions...
     350           84 :             AirEnthalpy = PsyHFnTdbW(20.0, state.dataEnvrn->OutHumRat);
     351              : 
     352              :             // Initialize the inlet node to s standard set of conditions so that the
     353              :             //  flows match around the loop & do not cause convergence problems.
     354           84 :             InletNode = state.dataSplitterComponent->SplitterCond(SplitterNum).InletNode;
     355           84 :             state.dataLoopNodes->Node(InletNode).Temp = 20.0;
     356           84 :             state.dataLoopNodes->Node(InletNode).HumRat = state.dataEnvrn->OutHumRat;
     357           84 :             state.dataLoopNodes->Node(InletNode).Enthalpy = AirEnthalpy;
     358           84 :             state.dataLoopNodes->Node(InletNode).Press = state.dataEnvrn->OutBaroPress;
     359           84 :             if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
     360            0 :                 state.dataLoopNodes->Node(InletNode).CO2 = state.dataContaminantBalance->OutdoorCO2;
     361              :             }
     362           84 :             if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
     363            0 :                 state.dataLoopNodes->Node(InletNode).GenContam = state.dataContaminantBalance->OutdoorGC;
     364              :             }
     365              : 
     366           84 :             state.dataSplitterComponent->MyEnvrnFlag = false;
     367              :         }
     368              : 
     369       135111 :         if (!state.dataGlobal->BeginEnvrnFlag) {
     370       133588 :             state.dataSplitterComponent->MyEnvrnFlag = true;
     371              :         }
     372              : 
     373              :         // Set the inlet node for the Splitter
     374       135111 :         InletNode = state.dataSplitterComponent->SplitterCond(SplitterNum).InletNode;
     375              : 
     376              :         // Do the following initializations (every time step): This should be the info from
     377              :         // the previous components outlets or the node data in this section.
     378              :         // Load the node data in this section for the component simulation
     379              : 
     380              :         // This section is very important to understand.  The system off condition is important
     381              :         // transfer around the loop even if the splitter does not have enough information to
     382              :         // calculate the correct flow rates since the dampers are downstream and there is no pressure
     383              :         // simulation.  What happens in this section is the flow from upstream is not zero is
     384              :         // arbitrarily split by the number of inlet nodes.  This is by no way meant to determine the
     385              :         // correct split flow!  Just to give each outlet a non-zero flow so that the Air Distribution
     386              :         // Unit(ADU) downstream knows that the system is operating or has flow.  This is only done the first
     387              :         // iteration through and the splitter first pass.  After the first iteration the ADU sets the
     388              :         // correct flow and that is used and passed back upstream.
     389       135111 :         if (FirstHVACIteration && FirstCall) {
     390        34392 :             if (state.dataLoopNodes->Node(InletNode).MassFlowRate > 0.0) {
     391        85590 :                 for (NodeNum = 1; NodeNum <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++NodeNum) {
     392        53592 :                     OutletNode = state.dataSplitterComponent->SplitterCond(SplitterNum).OutletNode(NodeNum);
     393        53592 :                     state.dataLoopNodes->Node(OutletNode).MassFlowRate =
     394        53592 :                         state.dataLoopNodes->Node(InletNode).MassFlowRate / state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes;
     395              :                 }
     396              :             }
     397        34392 :             if (state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail > 0.0) {
     398        85608 :                 for (NodeNum = 1; NodeNum <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++NodeNum) {
     399        53606 :                     OutletNode = state.dataSplitterComponent->SplitterCond(SplitterNum).OutletNode(NodeNum);
     400        53606 :                     state.dataLoopNodes->Node(OutletNode).MassFlowRateMaxAvail =
     401        53606 :                         state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail /
     402        53606 :                         state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes;
     403              :                 }
     404              :             }
     405              : 
     406              :         } // For FirstHVACIteration and FirstCall
     407              : 
     408       135111 :         if (FirstCall) {
     409              :             // There is one exception to the rule stated above and that is if the system shuts OFF
     410              :             // for some operational or algorithm dependency.  This IF block should catch that condition
     411              :             // and then pass the NO flow condition downstream to the waiting ADU's.  Most of the time
     412              :             // this IF is jumped over.
     413        67556 :             if (state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail == 0.0) {
     414              : 
     415        17695 :                 for (NodeNum = 1; NodeNum <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++NodeNum) {
     416              : 
     417         9877 :                     OutletNode = state.dataSplitterComponent->SplitterCond(SplitterNum).OutletNode(NodeNum);
     418         9877 :                     state.dataLoopNodes->Node(OutletNode).MassFlowRate = 0.0;
     419         9877 :                     state.dataLoopNodes->Node(OutletNode).MassFlowRateMaxAvail = 0.0;
     420         9877 :                     state.dataLoopNodes->Node(OutletNode).MassFlowRateMinAvail = 0.0;
     421              :                 }
     422              :             } // For Node inlet Max Avail = 0.0
     423              : 
     424              :             // Pass the State Properties through every time.  This is what mainly happens each time
     425              :             // through the splitter,
     426        67556 :             InletNode = state.dataSplitterComponent->SplitterCond(SplitterNum).InletNode;
     427        67556 :             state.dataSplitterComponent->SplitterCond(SplitterNum).InletTemp = state.dataLoopNodes->Node(InletNode).Temp;
     428        67556 :             state.dataSplitterComponent->SplitterCond(SplitterNum).InletHumRat = state.dataLoopNodes->Node(InletNode).HumRat;
     429        67556 :             state.dataSplitterComponent->SplitterCond(SplitterNum).InletEnthalpy = state.dataLoopNodes->Node(InletNode).Enthalpy;
     430        67556 :             state.dataSplitterComponent->SplitterCond(SplitterNum).InletPressure = state.dataLoopNodes->Node(InletNode).Press;
     431              : 
     432              :         } else { // On the second call from the ZoneEquipManager this is where the flows are passed back to
     433              :             // the splitter inlet.
     434       179594 :             for (NodeNum = 1; NodeNum <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++NodeNum) {
     435              : 
     436       112039 :                 OutletNode = state.dataSplitterComponent->SplitterCond(SplitterNum).OutletNode(NodeNum);
     437       112039 :                 state.dataSplitterComponent->SplitterCond(SplitterNum).OutletMassFlowRate(NodeNum) =
     438       112039 :                     state.dataLoopNodes->Node(OutletNode).MassFlowRate;
     439       112039 :                 state.dataSplitterComponent->SplitterCond(SplitterNum).OutletMassFlowRateMaxAvail(NodeNum) =
     440       112039 :                     state.dataLoopNodes->Node(OutletNode).MassFlowRateMaxAvail;
     441       112039 :                 state.dataSplitterComponent->SplitterCond(SplitterNum).OutletMassFlowRateMinAvail(NodeNum) =
     442       112039 :                     state.dataLoopNodes->Node(OutletNode).MassFlowRateMinAvail;
     443              :             }
     444              : 
     445              :         } // For FirstCall
     446       135111 :     }
     447              : 
     448       135111 :     void CalcAirLoopSplitter(EnergyPlusData &state, int const SplitterNum, bool const FirstCall)
     449              :     {
     450              : 
     451              :         // SUBROUTINE INFORMATION:
     452              :         //       AUTHOR         Richard J. Liesen
     453              :         //       DATE WRITTEN   March 2000
     454              :         //       MODIFIED       na
     455              :         //       RE-ENGINEERED  na
     456              : 
     457              :         // PURPOSE OF THIS SUBROUTINE:
     458              :         // This subroutine needs a description.
     459              : 
     460              :         // METHODOLOGY EMPLOYED:
     461              :         // Needs description, as appropriate.
     462              : 
     463              :         int OutletNodeNum;
     464              : 
     465              :         // The first time through the State properties are split and passed through
     466       135111 :         if (FirstCall) {
     467              :             // Moisture balance to get outlet air humidity ratio
     468       179596 :             for (OutletNodeNum = 1; OutletNodeNum <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++OutletNodeNum) {
     469       112040 :                 state.dataSplitterComponent->SplitterCond(SplitterNum).OutletHumRat(OutletNodeNum) =
     470       112040 :                     state.dataSplitterComponent->SplitterCond(SplitterNum).InletHumRat;
     471              :             }
     472              : 
     473              :             // "Momentum balance" to get outlet air pressure
     474       179596 :             for (OutletNodeNum = 1; OutletNodeNum <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++OutletNodeNum) {
     475       112040 :                 state.dataSplitterComponent->SplitterCond(SplitterNum).OutletPressure(OutletNodeNum) =
     476       112040 :                     state.dataSplitterComponent->SplitterCond(SplitterNum).InletPressure;
     477              :             }
     478              : 
     479              :             // Energy balance to get outlet air enthalpy
     480       179596 :             for (OutletNodeNum = 1; OutletNodeNum <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++OutletNodeNum) {
     481       112040 :                 state.dataSplitterComponent->SplitterCond(SplitterNum).OutletEnthalpy(OutletNodeNum) =
     482       112040 :                     state.dataSplitterComponent->SplitterCond(SplitterNum).InletEnthalpy;
     483              :             }
     484              : 
     485              :             // Set outlet temperatures equal to inlet temperature
     486       179596 :             for (OutletNodeNum = 1; OutletNodeNum <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++OutletNodeNum) {
     487       112040 :                 state.dataSplitterComponent->SplitterCond(SplitterNum).OutletTemp(OutletNodeNum) =
     488       112040 :                     state.dataSplitterComponent->SplitterCond(SplitterNum).InletTemp;
     489              :             }
     490              : 
     491              :         } else {
     492              :             // This is the second time through and this is where the mass flows from each outlet are
     493              :             // summed and then assigned upstream to the inlet node.
     494              :             // Overall Mass Continuity Equation to get inlet mass flow rates
     495              :             // Zero the inlet Totals before the Inlets are summed
     496        67555 :             state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRate = 0.0;
     497        67555 :             state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRateMaxAvail = 0.0;
     498        67555 :             state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRateMinAvail = 0.0;
     499              : 
     500       179594 :             for (OutletNodeNum = 1; OutletNodeNum <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++OutletNodeNum) {
     501       112039 :                 state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRate +=
     502       112039 :                     state.dataSplitterComponent->SplitterCond(SplitterNum).OutletMassFlowRate(OutletNodeNum);
     503              : 
     504       112039 :                 state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRateMaxAvail +=
     505       112039 :                     state.dataSplitterComponent->SplitterCond(SplitterNum).OutletMassFlowRateMaxAvail(OutletNodeNum);
     506       112039 :                 state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRateMinAvail +=
     507       112039 :                     state.dataSplitterComponent->SplitterCond(SplitterNum).OutletMassFlowRateMinAvail(OutletNodeNum);
     508              :             }
     509              : 
     510              :             // What happens if Splitter inlet mass flow rate is greater than max available
     511              :         }
     512       135111 :     }
     513              : 
     514              :     // End Algorithm Section of the Module
     515              :     // *****************************************************************************
     516              : 
     517              :     // Beginning of Update subroutines for the Splitter Module
     518              :     // *****************************************************************************
     519              : 
     520       135111 :     void UpdateSplitter(EnergyPlusData &state, int const SplitterNum, bool &SplitterInletChanged, bool const FirstCall)
     521              :     {
     522              :         // SUBROUTINE INFORMATION:
     523              :         //       AUTHOR         Richard J. Liesen
     524              :         //       DATE WRITTEN   March 2000
     525              :         //       MODIFIED       na
     526              :         //       RE-ENGINEERED  na
     527              : 
     528       135111 :         Real64 constexpr FlowRateToler(0.01); // Tolerance for mass flow rate convergence (in kg/s)
     529              : 
     530              :         int InletNode;
     531              :         int OutletNode;
     532              :         int NodeNum;
     533              : 
     534              :         // Set the inlet node for this splitter to be used throughout subroutine for either case
     535       135111 :         InletNode = state.dataSplitterComponent->SplitterCond(SplitterNum).InletNode;
     536              : 
     537              :         // On the FirstCall the State properties are passed through and the mass flows are not dealt with
     538              :         // except for NO flow conditions
     539       135111 :         if (FirstCall) {
     540              :             // Set the outlet nodes for properties that just pass through & not used
     541       179596 :             for (NodeNum = 1; NodeNum <= state.dataSplitterComponent->SplitterCond(SplitterNum).NumOutletNodes; ++NodeNum) {
     542       112040 :                 OutletNode = state.dataSplitterComponent->SplitterCond(SplitterNum).OutletNode(NodeNum);
     543       112040 :                 state.dataLoopNodes->Node(OutletNode).Temp = state.dataSplitterComponent->SplitterCond(SplitterNum).OutletTemp(NodeNum);
     544       112040 :                 state.dataLoopNodes->Node(OutletNode).HumRat = state.dataSplitterComponent->SplitterCond(SplitterNum).OutletHumRat(NodeNum);
     545       112040 :                 state.dataLoopNodes->Node(OutletNode).Enthalpy = state.dataSplitterComponent->SplitterCond(SplitterNum).OutletEnthalpy(NodeNum);
     546       112040 :                 state.dataLoopNodes->Node(OutletNode).Quality = state.dataLoopNodes->Node(InletNode).Quality;
     547       112040 :                 state.dataLoopNodes->Node(OutletNode).Press = state.dataSplitterComponent->SplitterCond(SplitterNum).OutletPressure(NodeNum);
     548       112040 :                 if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
     549            0 :                     state.dataLoopNodes->Node(OutletNode).CO2 = state.dataLoopNodes->Node(InletNode).CO2;
     550              :                 }
     551       112040 :                 if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
     552            0 :                     state.dataLoopNodes->Node(OutletNode).GenContam = state.dataLoopNodes->Node(InletNode).GenContam;
     553              :                 }
     554              :             }
     555              : 
     556              :         } else {
     557              :             // The second time through just updates the mass flow conditions back upstream
     558              :             //  to the inlet.  Before it sets the inlet it checks to see that the flow rate has not
     559              :             //  changed or not.  The tolerance has been relaxed some now that the splitter has been
     560              :             //  re-written
     561              : 
     562              :             // Set the outlet air nodes of the Splitter if the splitter results have changed
     563              :             //  beyond the tolerance.
     564        67555 :             if (std::abs(state.dataLoopNodes->Node(InletNode).MassFlowRate -
     565        67555 :                          state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRate) > FlowRateToler) {
     566        11946 :                 SplitterInletChanged = true;
     567              :             }
     568        67555 :             state.dataLoopNodes->Node(InletNode).MassFlowRate = state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRate;
     569        67555 :             state.dataLoopNodes->Node(InletNode).MassFlowRateMaxAvail =
     570        67555 :                 state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRateMaxAvail;
     571        67555 :             state.dataLoopNodes->Node(InletNode).MassFlowRateMinAvail =
     572        67555 :                 state.dataSplitterComponent->SplitterCond(SplitterNum).InletMassFlowRateMinAvail;
     573              : 
     574              :         } // The FirstCall END IF
     575       135111 :     }
     576              : 
     577       135111 :     void ReportSplitter([[maybe_unused]] int const SplitterNum)
     578              :     {
     579              : 
     580              :         // SUBROUTINE INFORMATION:
     581              :         //       AUTHOR         Richard J. Liesen
     582              :         //       DATE WRITTEN   March 2000
     583              :         //       MODIFIED       na
     584              :         //       RE-ENGINEERED  na
     585              : 
     586              :         // Write(*,*)=SplitterCond(SplitterNum)%SplitterPower    Still needs to report the Splitter power from this component
     587       135111 :     }
     588              : 
     589            1 :     int GetSplitterOutletNumber(EnergyPlusData &state,
     590              :                                 std::string const &SplitterName, // must match Splitter names for the Splitter type
     591              :                                 int const SplitterNum,           // Index of Splitters
     592              :                                 bool &ErrorsFound                // set to true if problem
     593              :     )
     594              :     {
     595              : 
     596              :         // FUNCTION INFORMATION:
     597              :         //       AUTHOR         Lixing Gu
     598              :         //       DATE WRITTEN   Feb 2013
     599              :         //       MODIFIED       na
     600              :         //       RE-ENGINEERED  na
     601              : 
     602              :         // PURPOSE OF THIS FUNCTION:
     603              :         // This function looks up the given AirLoopHVAC:ZoneSplitter and returns the number of outlet nodes.  If
     604              :         // incorrect AirLoopHVAC:ZoneSplitter name is given, ErrorsFound is returned as true
     605              :         // as zero.
     606              : 
     607              :         // Return value
     608              :         int SplitterOutletNumber;
     609              : 
     610              :         // FUNCTION LOCAL VARIABLE DECLARATIONS:
     611              :         int WhichSplitter;
     612              : 
     613              :         // Obtains and Allocates AirLoopHVAC:ZoneSplitter related parameters from input file
     614            1 :         if (state.dataSplitterComponent->GetSplitterInputFlag) { // First time subroutine has been entered
     615            0 :             GetSplitterInput(state);
     616            0 :             state.dataSplitterComponent->GetSplitterInputFlag = false;
     617              :         }
     618              : 
     619            1 :         if (SplitterNum == 0) {
     620            0 :             WhichSplitter = Util::FindItemInList(SplitterName, state.dataSplitterComponent->SplitterCond, &SplitterConditions::SplitterName);
     621              :         } else {
     622            1 :             WhichSplitter = SplitterNum;
     623              :         }
     624              : 
     625            1 :         if (WhichSplitter != 0) {
     626            1 :             SplitterOutletNumber = state.dataSplitterComponent->SplitterCond(WhichSplitter).NumOutletNodes;
     627              :         }
     628              : 
     629            1 :         if (WhichSplitter == 0) {
     630            0 :             ShowSevereError(state, format("GetSplitterOuletNumber: Could not find Splitter = \"{}\"", SplitterName));
     631            0 :             ErrorsFound = true;
     632            0 :             SplitterOutletNumber = 0;
     633              :         }
     634              : 
     635            1 :         return SplitterOutletNumber;
     636              :     }
     637              : 
     638            1 :     Array1D_int GetSplitterNodeNumbers(EnergyPlusData &state,
     639              :                                        std::string const &SplitterName, // must match Splitter names for the Splitter type
     640              :                                        int const SplitterNum,           // Index of Splitters
     641              :                                        bool &ErrorsFound                // set to true if problem
     642              :     )
     643              :     {
     644              : 
     645              :         // FUNCTION INFORMATION:
     646              :         //       AUTHOR         Lixing Gu
     647              :         //       DATE WRITTEN   Feb 2013
     648              :         //       MODIFIED       na
     649              :         //       RE-ENGINEERED  na
     650              : 
     651              :         // PURPOSE OF THIS FUNCTION:
     652              :         // This function looks up the given AirLoopHVAC:ZoneSplitter and returns the node numbers.  If
     653              :         // incorrect AirLoopHVAC:ZoneSplitter name is given, ErrorsFound is returned as true
     654              :         // as zero.
     655              : 
     656              :         // Return value
     657            1 :         Array1D_int SplitterNodeNumbers;
     658              : 
     659              :         // FUNCTION LOCAL VARIABLE DECLARATIONS:
     660              :         int WhichSplitter;
     661              :         int i;
     662              : 
     663              :         // Obtains and Allocates AirLoopHVAC:ZoneSplitter related parameters from input file
     664            1 :         if (state.dataSplitterComponent->GetSplitterInputFlag) { // First time subroutine has been entered
     665            0 :             GetSplitterInput(state);
     666            0 :             state.dataSplitterComponent->GetSplitterInputFlag = false;
     667              :         }
     668              : 
     669            1 :         if (SplitterNum == 0) {
     670            0 :             WhichSplitter = Util::FindItemInList(SplitterName, state.dataSplitterComponent->SplitterCond, &SplitterConditions::SplitterName);
     671              :         } else {
     672            1 :             WhichSplitter = SplitterNum;
     673              :         }
     674              : 
     675            1 :         if (WhichSplitter != 0) {
     676            1 :             SplitterNodeNumbers.allocate(state.dataSplitterComponent->SplitterCond(WhichSplitter).NumOutletNodes + 2);
     677            1 :             SplitterNodeNumbers(1) = state.dataSplitterComponent->SplitterCond(WhichSplitter).InletNode;
     678            1 :             SplitterNodeNumbers(2) = state.dataSplitterComponent->SplitterCond(WhichSplitter).NumOutletNodes;
     679            2 :             for (i = 1; i <= SplitterNodeNumbers(2); ++i) {
     680            1 :                 SplitterNodeNumbers(i + 2) = state.dataSplitterComponent->SplitterCond(WhichSplitter).OutletNode(i);
     681              :             }
     682              :         }
     683              : 
     684            1 :         if (WhichSplitter == 0) {
     685            0 :             ShowSevereError(state, format("GetSplitterNodeNumbers: Could not find Splitter = \"{}\"", SplitterName));
     686            0 :             ErrorsFound = true;
     687              :         }
     688              : 
     689            1 :         return SplitterNodeNumbers;
     690            0 :     }
     691              : 
     692              : } // namespace SplitterComponent
     693              : 
     694              : } // namespace EnergyPlus
        

Generated by: LCOV version 2.0-1