LCOV - code coverage report
Current view: top level - EnergyPlus - SplitterComponent.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 211 245 86.1 %
Date: 2024-08-24 18:31:18 Functions: 8 8 100.0 %

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

Generated by: LCOV version 1.14