LCOV - code coverage report
Current view: top level - EnergyPlus - SplitterComponent.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 214 248 86.3 %
Date: 2023-01-17 19:17:23 Functions: 10 10 100.0 %

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

Generated by: LCOV version 1.13