LCOV - code coverage report
Current view: top level - EnergyPlus - ExhaustAirSystemManager.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 64.2 % 385 247
Test Date: 2025-05-22 16:09:37 Functions: 81.8 % 11 9

            Line data    Source code
       1              : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
       2              : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3              : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4              : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5              : // contributors. All rights reserved.
       6              : //
       7              : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8              : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9              : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10              : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11              : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12              : //
      13              : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14              : // provided that the following conditions are met:
      15              : //
      16              : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17              : //     conditions and the following disclaimer.
      18              : //
      19              : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20              : //     conditions and the following disclaimer in the documentation and/or other materials
      21              : //     provided with the distribution.
      22              : //
      23              : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24              : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25              : //     used to endorse or promote products derived from this software without specific prior
      26              : //     written permission.
      27              : //
      28              : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29              : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30              : //     reference solely to the software portion of its product, Licensee must refer to the
      31              : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32              : //     obtained under this License and may not use a different name for the software. Except as
      33              : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34              : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35              : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36              : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37              : //
      38              : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39              : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40              : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41              : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42              : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43              : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44              : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45              : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46              : // POSSIBILITY OF SUCH DAMAGE.
      47              : 
      48              : // ObjexxFCL Headers
      49              : #include <ObjexxFCL/Array.functions.hh>
      50              : #include <ObjexxFCL/Fmath.hh>
      51              : 
      52              : // EnergyPlus Headers
      53              : #include <AirflowNetwork/Solver.hpp>
      54              : #include <EnergyPlus/Autosizing/Base.hh>
      55              : #include <EnergyPlus/BranchNodeConnections.hh>
      56              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      57              : #include <EnergyPlus/DataContaminantBalance.hh>
      58              : #include <EnergyPlus/DataEnvironment.hh>
      59              : #include <EnergyPlus/DataHVACGlobals.hh>
      60              : #include <EnergyPlus/DataHeatBalance.hh>
      61              : #include <EnergyPlus/DataIPShortCuts.hh>
      62              : #include <EnergyPlus/DataLoopNode.hh>
      63              : #include <EnergyPlus/DataSizing.hh>
      64              : #include <EnergyPlus/DataZoneEquipment.hh>
      65              : #include <EnergyPlus/ExhaustAirSystemManager.hh>
      66              : #include <EnergyPlus/Fans.hh>
      67              : #include <EnergyPlus/GeneralRoutines.hh>
      68              : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      69              : #include <EnergyPlus/MixerComponent.hh>
      70              : #include <EnergyPlus/NodeInputManager.hh>
      71              : #include <EnergyPlus/Psychrometrics.hh>
      72              : #include <EnergyPlus/ScheduleManager.hh>
      73              : #include <EnergyPlus/UtilityRoutines.hh>
      74              : #include <EnergyPlus/ZoneTempPredictorCorrector.hh>
      75              : 
      76              : namespace EnergyPlus {
      77              : 
      78              : namespace ExhaustAirSystemManager {
      79              :     // Module containing the routines dealing with the AirLoopHVAC:ExhaustSystem
      80              : 
      81              :     static constexpr std::array<std::string_view, static_cast<int>(ZoneExhaustControl::FlowControlType::Num)> flowControlTypeNamesUC = {
      82              :         "SCHEDULED", "FOLLOWSUPPLY"};
      83              : 
      84       424465 :     void SimExhaustAirSystem(EnergyPlusData &state, bool FirstHVACIteration)
      85              :     {
      86              :         // Obtains and Allocates Mixer related parameters from input file
      87       424465 :         if (state.dataExhAirSystemMrg->GetInputFlag) { // First time subroutine has been entered
      88          110 :             GetExhaustAirSystemInput(state);
      89          110 :             state.dataExhAirSystemMrg->GetInputFlag = false;
      90              :         }
      91              : 
      92       424465 :         for (int ExhaustAirSystemNum = 1; ExhaustAirSystemNum <= state.dataZoneEquip->NumExhaustAirSystems; ++ExhaustAirSystemNum) {
      93            0 :             CalcExhaustAirSystem(state, ExhaustAirSystemNum, FirstHVACIteration);
      94              :         }
      95              : 
      96              :         // After this, update the exhaust flows according to zone grouping:
      97       424465 :         UpdateZoneExhaustControl(state);
      98       424465 :     }
      99              : 
     100          112 :     void GetExhaustAirSystemInput(EnergyPlusData &state)
     101              :     {
     102          112 :         if (!state.dataExhAirSystemMrg->GetInputFlag) return;
     103              :         // state.dataExhAirSystemMrg->GetInputFlag = false;
     104              : 
     105              :         // Locals
     106          112 :         bool ErrorsFound = false;
     107              : 
     108          112 :         constexpr std::string_view RoutineName("GetExhaustAirSystemInput: ");
     109          112 :         constexpr std::string_view routineName = "GetExhaustAirSystemInput";
     110          112 :         std::string const cCurrentModuleObject = "AirLoopHVAC:ExhaustSystem";
     111              : 
     112          112 :         auto &ip = state.dataInputProcessing->inputProcessor;
     113          112 :         auto const instances = ip->epJSON.find(cCurrentModuleObject);
     114          112 :         if (instances != ip->epJSON.end()) {
     115            2 :             auto const &objectSchemaProps = ip->getObjectSchemaProps(state, cCurrentModuleObject);
     116            2 :             auto &instancesValue = instances.value();
     117            2 :             int numExhaustSystems = instancesValue.size();
     118            2 :             int exhSysNum = 0;
     119              : 
     120            2 :             if (numExhaustSystems > 0) {
     121            2 :                 state.dataZoneEquip->ExhaustAirSystem.allocate(numExhaustSystems);
     122              :             }
     123              : 
     124            6 :             for (auto instance = instancesValue.begin(); instance != instancesValue.end(); ++instance) {
     125            4 :                 ++exhSysNum;
     126            4 :                 auto const &objectFields = instance.value();
     127            4 :                 auto &thisExhSys = state.dataZoneEquip->ExhaustAirSystem(exhSysNum);
     128            4 :                 thisExhSys.Name = Util::makeUPPER(instance.key());
     129            4 :                 ip->markObjectAsUsed(cCurrentModuleObject, instance.key());
     130              : 
     131            8 :                 std::string zoneMixerName = ip->getAlphaFieldValue(objectFields, objectSchemaProps, "zone_mixer_name");
     132            4 :                 int zoneMixerIndex = 0;
     133            4 :                 bool zoneMixerErrFound = false;
     134            4 :                 MixerComponent::GetZoneMixerIndex(state, zoneMixerName, zoneMixerIndex, zoneMixerErrFound, thisExhSys.Name);
     135              : 
     136            4 :                 if (!zoneMixerErrFound) {
     137              :                     // With the correct MixerNum Initialize
     138            4 :                     MixerComponent::InitAirMixer(state, zoneMixerIndex); // Initialize all Mixer related parameters
     139              : 
     140              :                     // See if need to do the zone mixer's CheckEquipName() function
     141            4 :                     bool IsNotOK = false; // Flag to verify name
     142            4 :                     ValidateComponent(state, "AirLoopHVAC:ZoneMixer", zoneMixerName, IsNotOK, "AirLoopHVAC:ExhaustSystem");
     143            4 :                     if (IsNotOK) {
     144            0 :                         ShowSevereError(state, format("{}{}={}", RoutineName, cCurrentModuleObject, thisExhSys.Name));
     145            0 :                         ShowContinueError(state, format("ZoneMixer Name ={} mismatch or not found.", zoneMixerName));
     146            0 :                         ErrorsFound = true;
     147              :                     } else {
     148              :                         // normal conditions
     149              :                     }
     150              :                 } else {
     151            0 :                     ShowSevereError(state, format("{}{}={}", RoutineName, cCurrentModuleObject, thisExhSys.Name));
     152            0 :                     ShowContinueError(state, format("Zone Mixer Name ={} not found.", zoneMixerName));
     153            0 :                     ErrorsFound = true;
     154              :                 }
     155            4 :                 thisExhSys.ZoneMixerName = zoneMixerName;
     156            4 :                 thisExhSys.ZoneMixerIndex = zoneMixerIndex;
     157              : 
     158            4 :                 thisExhSys.centralFanType = static_cast<HVAC::FanType>(
     159            8 :                     getEnumValue(HVAC::fanTypeNamesUC, Util::makeUPPER(ip->getAlphaFieldValue(objectFields, objectSchemaProps, "fan_object_type"))));
     160            4 :                 if (thisExhSys.centralFanType != HVAC::FanType::SystemModel && thisExhSys.centralFanType != HVAC::FanType::ComponentModel) {
     161            0 :                     ShowSevereError(state, format("{}{}={}", RoutineName, cCurrentModuleObject, thisExhSys.Name));
     162            0 :                     ShowContinueError(state, format("Fan Type ={} is not supported.", HVAC::fanTypeNames[(int)thisExhSys.centralFanType]));
     163            0 :                     ShowContinueError(state, "It needs to be either a Fan:SystemModel or a Fan:ComponentModel type.");
     164            0 :                     ErrorsFound = true;
     165              :                 }
     166              : 
     167            8 :                 std::string centralFanName = ip->getAlphaFieldValue(objectFields, objectSchemaProps, "fan_name");
     168              : 
     169            4 :                 ErrorObjectHeader eoh{routineName, cCurrentModuleObject, thisExhSys.Name};
     170            4 :                 int centralFanIndex = Fans::GetFanIndex(state, centralFanName);
     171            4 :                 if (centralFanIndex == 0) {
     172            0 :                     ShowSevereItemNotFound(state, eoh, "fan_name", centralFanName);
     173            0 :                     ErrorsFound = true;
     174              :                 } else {
     175            4 :                     auto *fan = state.dataFans->fans(centralFanIndex);
     176              : 
     177            4 :                     thisExhSys.availSched = fan->availSched;
     178              : 
     179           12 :                     BranchNodeConnections::SetUpCompSets(state,
     180              :                                                          cCurrentModuleObject,
     181              :                                                          thisExhSys.Name,
     182            4 :                                                          HVAC::fanTypeNames[(int)thisExhSys.centralFanType],
     183              :                                                          centralFanName,
     184            4 :                                                          state.dataLoopNodes->NodeID(fan->inletNodeNum),
     185            4 :                                                          state.dataLoopNodes->NodeID(fan->outletNodeNum));
     186              : 
     187            8 :                     SetupOutputVariable(state,
     188              :                                         "Central Exhaust Fan Mass Flow Rate",
     189              :                                         Constant::Units::kg_s,
     190            4 :                                         thisExhSys.centralFan_MassFlowRate,
     191              :                                         OutputProcessor::TimeStepType::System,
     192              :                                         OutputProcessor::StoreType::Average,
     193            4 :                                         thisExhSys.Name);
     194              : 
     195            8 :                     SetupOutputVariable(state,
     196              :                                         "Central Exhaust Fan Volumetric Flow Rate Standard",
     197              :                                         Constant::Units::m3_s,
     198            4 :                                         thisExhSys.centralFan_VolumeFlowRate_Std,
     199              :                                         OutputProcessor::TimeStepType::System,
     200              :                                         OutputProcessor::StoreType::Average,
     201            4 :                                         thisExhSys.Name);
     202              : 
     203            8 :                     SetupOutputVariable(state,
     204              :                                         "Central Exhaust Fan Volumetric Flow Rate Current",
     205              :                                         Constant::Units::m3_s,
     206            4 :                                         thisExhSys.centralFan_VolumeFlowRate_Cur,
     207              :                                         OutputProcessor::TimeStepType::System,
     208              :                                         OutputProcessor::StoreType::Average,
     209            4 :                                         thisExhSys.Name);
     210              : 
     211            8 :                     SetupOutputVariable(state,
     212              :                                         "Central Exhaust Fan Power",
     213              :                                         Constant::Units::W,
     214            4 :                                         thisExhSys.centralFan_Power,
     215              :                                         OutputProcessor::TimeStepType::System,
     216              :                                         OutputProcessor::StoreType::Average,
     217            4 :                                         thisExhSys.Name);
     218              : 
     219            8 :                     SetupOutputVariable(state,
     220              :                                         "Central Exhaust Fan Energy",
     221              :                                         Constant::Units::J,
     222            4 :                                         thisExhSys.centralFan_Energy,
     223              :                                         OutputProcessor::TimeStepType::System,
     224              :                                         OutputProcessor::StoreType::Sum,
     225            4 :                                         thisExhSys.Name);
     226              :                 }
     227              : 
     228            4 :                 thisExhSys.CentralFanName = centralFanName;
     229            4 :                 thisExhSys.CentralFanIndex = centralFanIndex;
     230              : 
     231              :                 // sizing
     232            4 :                 if (thisExhSys.SizingFlag) {
     233            4 :                     SizeExhaustSystem(state, exhSysNum);
     234              :                 }
     235            4 :             }
     236            2 :             state.dataZoneEquip->NumExhaustAirSystems = numExhaustSystems;
     237              :         } else {
     238              :             // If no exhaust systems are defined, then do something <or nothing>:
     239              :         }
     240              : 
     241          112 :         if (ErrorsFound) {
     242            0 :             ShowFatalError(state, "Errors found getting AirLoopHVAC:ExhaustSystem.  Preceding condition(s) causes termination.");
     243              :         }
     244          112 :     }
     245              : 
     246            0 :     void CalcExhaustAirSystem(EnergyPlusData &state, int const ExhaustAirSystemNum, bool FirstHVACIteration)
     247              :     {
     248            0 :         auto &thisExhSys = state.dataZoneEquip->ExhaustAirSystem(ExhaustAirSystemNum);
     249            0 :         constexpr std::string_view RoutineName = "CalExhaustAirSystem: ";
     250            0 :         constexpr std::string_view cCurrentModuleObject = "AirloopHVAC:ExhaustSystem";
     251            0 :         bool ErrorsFound = false;
     252            0 :         if (!(state.afn->AirflowNetworkFanActivated && state.afn->distribution_simulated)) {
     253            0 :             MixerComponent::SimAirMixer(state, thisExhSys.ZoneMixerName, thisExhSys.ZoneMixerIndex);
     254              :         } else {
     255              :             // Give a warning that the current model does not work with AirflowNetwork for now
     256            0 :             ShowSevereError(state, format("{}{}={}", RoutineName, cCurrentModuleObject, thisExhSys.Name));
     257            0 :             ShowContinueError(state, "AirloopHVAC:ExhaustSystem currently does not work with AirflowNetwork.");
     258            0 :             ErrorsFound = true;
     259              :         }
     260              : 
     261            0 :         if (ErrorsFound) {
     262            0 :             ShowFatalError(state, "Errors found conducting CalcExhasutAirSystem(). Preceding condition(s) causes termination.");
     263              :         }
     264              : 
     265            0 :         Real64 mixerFlow_Prior = 0.0;
     266            0 :         int outletNode_index = state.dataMixerComponent->MixerCond(thisExhSys.ZoneMixerIndex).OutletNode;
     267            0 :         mixerFlow_Prior = state.dataLoopNodes->Node(outletNode_index).MassFlowRate;
     268              :         if (mixerFlow_Prior == 0.0) {
     269              :             // No flow coming out from the exhaust controls;
     270              :             // fan should be cut off now;
     271              :         }
     272              : 
     273            0 :         int outletNode_Num = 0;
     274            0 :         Real64 RhoAirCurrent = state.dataEnvrn->StdRhoAir;
     275              : 
     276            0 :         if (thisExhSys.centralFanType == HVAC::FanType::SystemModel) {
     277            0 :             state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
     278            0 :             state.dataFans->fans(thisExhSys.CentralFanIndex)->simulate(state, false, _, _);
     279              : 
     280              :             // Update report variables
     281            0 :             outletNode_Num = state.dataFans->fans(thisExhSys.CentralFanIndex)->outletNodeNum;
     282              : 
     283            0 :             thisExhSys.centralFan_MassFlowRate = state.dataLoopNodes->Node(outletNode_Num).MassFlowRate;
     284              : 
     285            0 :             thisExhSys.centralFan_VolumeFlowRate_Std = state.dataLoopNodes->Node(outletNode_Num).MassFlowRate / state.dataEnvrn->StdRhoAir;
     286              : 
     287            0 :             RhoAirCurrent = EnergyPlus::Psychrometrics::PsyRhoAirFnPbTdbW(state,
     288            0 :                                                                           state.dataEnvrn->OutBaroPress,
     289            0 :                                                                           state.dataLoopNodes->Node(outletNode_Num).Temp,
     290            0 :                                                                           state.dataLoopNodes->Node(outletNode_Num).HumRat);
     291            0 :             if (RhoAirCurrent <= 0.0) RhoAirCurrent = state.dataEnvrn->StdRhoAir;
     292            0 :             thisExhSys.centralFan_VolumeFlowRate_Cur = state.dataLoopNodes->Node(outletNode_Num).MassFlowRate / RhoAirCurrent;
     293              : 
     294            0 :             thisExhSys.centralFan_Power = state.dataFans->fans(thisExhSys.CentralFanIndex)->totalPower;
     295              : 
     296            0 :             thisExhSys.centralFan_Energy = thisExhSys.centralFan_Power * state.dataHVACGlobal->TimeStepSysSec;
     297              : 
     298            0 :         } else if (thisExhSys.centralFanType == HVAC::FanType::ComponentModel) {
     299            0 :             auto *fan = state.dataFans->fans(thisExhSys.CentralFanIndex);
     300            0 :             fan->simulate(state, FirstHVACIteration);
     301              : 
     302              :             // Update output variables
     303              : 
     304            0 :             outletNode_Num = fan->outletNodeNum;
     305              : 
     306            0 :             thisExhSys.centralFan_MassFlowRate = fan->outletAirMassFlowRate;
     307              : 
     308            0 :             thisExhSys.centralFan_VolumeFlowRate_Std = fan->outletAirMassFlowRate / state.dataEnvrn->StdRhoAir;
     309              : 
     310            0 :             RhoAirCurrent = EnergyPlus::Psychrometrics::PsyRhoAirFnPbTdbW(state,
     311            0 :                                                                           state.dataEnvrn->OutBaroPress,
     312            0 :                                                                           state.dataLoopNodes->Node(outletNode_Num).Temp,
     313            0 :                                                                           state.dataLoopNodes->Node(outletNode_Num).HumRat);
     314            0 :             if (RhoAirCurrent <= 0.0) RhoAirCurrent = state.dataEnvrn->StdRhoAir;
     315            0 :             thisExhSys.centralFan_VolumeFlowRate_Cur = fan->outletAirMassFlowRate / RhoAirCurrent;
     316              : 
     317            0 :             thisExhSys.centralFan_Power = fan->totalPower * 1000.0;
     318              : 
     319            0 :             thisExhSys.centralFan_Energy = fan->totalEnergy * 1000.0;
     320              :         }
     321            0 :         thisExhSys.exhTotalHVACReliefHeatLoss = state.dataLoopNodes->Node(outletNode_Num).MassFlowRate *
     322            0 :                                                 (state.dataLoopNodes->Node(outletNode_Num).Enthalpy - state.dataEnvrn->OutEnthalpy);
     323              : 
     324            0 :         Real64 mixerFlow_Posterior = 0.0;
     325            0 :         mixerFlow_Posterior = state.dataLoopNodes->Node(outletNode_index).MassFlowRate;
     326              :         if (mixerFlow_Posterior < HVAC::SmallMassFlow) {
     327              :             // fan flow is nearly zero and should be considered off
     328              :             // but this still can use the ratio
     329              :         }
     330              :         if (mixerFlow_Prior < HVAC::SmallMassFlow) {
     331              :             // this is the case where the fan flow should be resetted to zeros and not run the ratio
     332              :         }
     333            0 :         if ((mixerFlow_Prior - mixerFlow_Posterior > HVAC::SmallMassFlow) || (mixerFlow_Prior - mixerFlow_Posterior < -HVAC::SmallMassFlow)) {
     334              :             // calculate a ratio
     335            0 :             Real64 flowRatio = mixerFlow_Posterior / mixerFlow_Prior;
     336            0 :             if (flowRatio > 1.0) {
     337            0 :                 ShowWarningError(state, format("{}{}={}", RoutineName, cCurrentModuleObject, thisExhSys.Name));
     338            0 :                 ShowContinueError(state, "Requested flow rate is lower than the exhasut fan flow rate.");
     339            0 :                 ShowContinueError(state, "Will scale up the requested flow rate to meet fan flow rate.");
     340              :             }
     341              : 
     342              :             // get the mixer inlet node index
     343            0 :             int zoneMixerIndex = thisExhSys.ZoneMixerIndex;
     344            0 :             for (int i = 1; i <= state.dataMixerComponent->MixerCond(zoneMixerIndex).NumInletNodes; ++i) {
     345            0 :                 int exhLegIndex = state.dataExhAirSystemMrg->mixerIndexMap[state.dataMixerComponent->MixerCond(zoneMixerIndex).InletNode(i)];
     346            0 :                 CalcZoneHVACExhaustControl(state, exhLegIndex, flowRatio);
     347              :             }
     348              : 
     349              :             // Simulate the mixer again to update the flow
     350            0 :             MixerComponent::SimAirMixer(state, thisExhSys.ZoneMixerName, thisExhSys.ZoneMixerIndex);
     351              : 
     352              :             // if the adjustment matches, then no need to run fan simulation again.
     353              :         }
     354            0 :     }
     355              : 
     356          112 :     void GetZoneExhaustControlInput(EnergyPlusData &state)
     357              :     {
     358              :         // Process ZoneExhaust Control inputs
     359              : 
     360              :         // Locals
     361          112 :         bool ErrorsFound = false;
     362              : 
     363              :         // Use the json helper to process input
     364          112 :         constexpr std::string_view RoutineName("GetZoneExhaustControlInput: ");
     365          112 :         constexpr std::string_view routineName = "GetZoneExhaustControlInput";
     366              : 
     367          112 :         std::string const cCurrentModuleObject = "ZoneHVAC:ExhaustControl";
     368          112 :         auto &ip = state.dataInputProcessing->inputProcessor;
     369          112 :         auto const instances = ip->epJSON.find(cCurrentModuleObject);
     370          112 :         if (instances != ip->epJSON.end()) {
     371            2 :             auto const &objectSchemaProps = ip->getObjectSchemaProps(state, cCurrentModuleObject);
     372            2 :             auto &instancesValue = instances.value();
     373            2 :             int numZoneExhaustControls = instancesValue.size();
     374            2 :             int exhCtrlNum = 0;
     375              :             int NumAlphas;
     376              :             int NumNums;
     377              : 
     378            2 :             if (numZoneExhaustControls > 0) {
     379            2 :                 state.dataZoneEquip->ZoneExhaustControlSystem.allocate(numZoneExhaustControls);
     380              :             }
     381              : 
     382           10 :             for (auto instance = instancesValue.begin(); instance != instancesValue.end(); ++instance) {
     383            8 :                 ++exhCtrlNum;
     384            8 :                 auto const &objectFields = instance.value();
     385            8 :                 auto &thisExhCtrl = state.dataZoneEquip->ZoneExhaustControlSystem(exhCtrlNum);
     386              : 
     387            8 :                 ErrorObjectHeader eoh{routineName, cCurrentModuleObject, instance.key()};
     388              : 
     389            8 :                 thisExhCtrl.Name = Util::makeUPPER(instance.key());
     390            8 :                 ip->markObjectAsUsed(cCurrentModuleObject, instance.key());
     391              : 
     392           16 :                 std::string availSchName = ip->getAlphaFieldValue(objectFields, objectSchemaProps, "availability_schedule_name");
     393            8 :                 if (availSchName.empty()) {
     394              :                     // blank
     395            0 :                     thisExhCtrl.availSched = Sched::GetScheduleAlwaysOn(state);
     396            8 :                 } else if ((thisExhCtrl.availSched = Sched::GetSchedule(state, availSchName)) == nullptr) {
     397              :                     // mismatch, reset to always on
     398            0 :                     thisExhCtrl.availSched = Sched::GetScheduleAlwaysOn(state);
     399            0 :                     ShowWarningItemNotFound(state, eoh, "Avaiability Schedule Name", availSchName, "Availability Schedule is reset to Always ON.");
     400              :                 }
     401              : 
     402           16 :                 std::string zoneName = ip->getAlphaFieldValue(objectFields, objectSchemaProps, "zone_name");
     403            8 :                 thisExhCtrl.ZoneName = zoneName;
     404            8 :                 int zoneNum = Util::FindItemInList(zoneName, state.dataHeatBal->Zone);
     405            8 :                 thisExhCtrl.ZoneNum = zoneNum;
     406              : 
     407            8 :                 thisExhCtrl.ControlledZoneNum = Util::FindItemInList(zoneName, state.dataHeatBal->Zone);
     408              : 
     409              :                 // These two nodes are required inputs:
     410           16 :                 std::string inletNodeName = ip->getAlphaFieldValue(objectFields, objectSchemaProps, "inlet_node_name");
     411            8 :                 int inletNodeNum = NodeInputManager::GetOnlySingleNode(state,
     412              :                                                                        inletNodeName,
     413              :                                                                        ErrorsFound,
     414              :                                                                        DataLoopNode::ConnectionObjectType::ZoneHVACExhaustControl,
     415            8 :                                                                        thisExhCtrl.Name,
     416              :                                                                        DataLoopNode::NodeFluidType::Air,
     417              :                                                                        DataLoopNode::ConnectionType::Inlet,
     418              :                                                                        NodeInputManager::CompFluidStream::Primary,
     419              :                                                                        DataLoopNode::ObjectIsParent);
     420            8 :                 thisExhCtrl.InletNodeNum = inletNodeNum;
     421              : 
     422           16 :                 std::string outletNodeName = ip->getAlphaFieldValue(objectFields, objectSchemaProps, "outlet_node_name");
     423              : 
     424            8 :                 int outletNodeNum = NodeInputManager::GetOnlySingleNode(state,
     425              :                                                                         outletNodeName,
     426              :                                                                         ErrorsFound,
     427              :                                                                         DataLoopNode::ConnectionObjectType::ZoneHVACExhaustControl,
     428            8 :                                                                         thisExhCtrl.Name,
     429              :                                                                         DataLoopNode::NodeFluidType::Air,
     430              :                                                                         DataLoopNode::ConnectionType::Outlet,
     431              :                                                                         NodeInputManager::CompFluidStream::Primary,
     432            8 :                                                                         DataLoopNode::ObjectIsParent);
     433            8 :                 thisExhCtrl.OutletNodeNum = outletNodeNum;
     434              : 
     435            8 :                 if (!state.dataExhAirSystemMrg->mappingDone) {
     436            8 :                     state.dataExhAirSystemMrg->mixerIndexMap.emplace(outletNodeNum, exhCtrlNum);
     437              :                 }
     438              : 
     439           16 :                 Real64 designExhaustFlowRate = ip->getRealFieldValue(objectFields, objectSchemaProps, "design_exhaust_flow_rate");
     440            8 :                 thisExhCtrl.DesignExhaustFlowRate = designExhaustFlowRate;
     441              : 
     442           16 :                 std::string flowControlTypeName = Util::makeUPPER(ip->getAlphaFieldValue(objectFields, objectSchemaProps, "flow_control_type"));
     443              :                 // std::string flowControlTypeName = Util::makeUPPER(fields.at("flow_control_type").get<std::string>());
     444            8 :                 thisExhCtrl.FlowControlOption =
     445            8 :                     static_cast<ZoneExhaustControl::FlowControlType>(getEnumValue(flowControlTypeNamesUC, flowControlTypeName));
     446              : 
     447              :                 std::string exhaustFlowFractionSchedName =
     448           16 :                     ip->getAlphaFieldValue(objectFields, objectSchemaProps, "exhaust_flow_fraction_schedule_name");
     449              : 
     450            8 :                 if (exhaustFlowFractionSchedName.empty()) {
     451            2 :                     thisExhCtrl.exhaustFlowFractionSched =
     452            2 :                         Sched::GetScheduleAlwaysOn(state); // Not an availability schedule, but defaults to constant-1.0
     453            6 :                 } else if ((thisExhCtrl.exhaustFlowFractionSched = Sched::GetSchedule(state, exhaustFlowFractionSchedName)) == nullptr) {
     454            0 :                     ShowSevereItemNotFound(state, eoh, "Exhaust Flow Fraction Schedule Name", exhaustFlowFractionSchedName);
     455              :                 }
     456              : 
     457           16 :                 thisExhCtrl.SupplyNodeOrNodelistName = ip->getAlphaFieldValue(objectFields, objectSchemaProps, "supply_node_or_nodelist_name");
     458              : 
     459            8 :                 bool NodeListError = false;
     460            8 :                 int NumParams = 0;
     461            8 :                 int NumNodes = 0;
     462              : 
     463            8 :                 ip->getObjectDefMaxArgs(state, "NodeList", NumParams, NumAlphas, NumNums);
     464            8 :                 thisExhCtrl.SuppNodeNums.dimension(NumParams, 0);
     465            8 :                 NodeInputManager::GetNodeNums(state,
     466            8 :                                               thisExhCtrl.SupplyNodeOrNodelistName,
     467              :                                               NumNodes,
     468            8 :                                               thisExhCtrl.SuppNodeNums,
     469              :                                               NodeListError,
     470              :                                               DataLoopNode::NodeFluidType::Air,
     471              :                                               DataLoopNode::ConnectionObjectType::ZoneHVACExhaustControl, // maybe zone inlets?
     472            8 :                                               thisExhCtrl.Name,
     473              :                                               DataLoopNode::ConnectionType::Sensor,
     474              :                                               NodeInputManager::CompFluidStream::Primary,
     475              :                                               DataLoopNode::ObjectIsNotParent); // , // _, // supplyNodeOrNodelistName);
     476              : 
     477              :                 // Verify these nodes are indeed supply nodes:
     478            8 :                 if (thisExhCtrl.FlowControlOption == ZoneExhaustControl::FlowControlType::FollowSupply) { // FollowSupply
     479            0 :                     bool nodeNotFound = false;
     480            0 :                     for (size_t i = 1; i <= thisExhCtrl.SuppNodeNums.size(); ++i) {
     481            0 :                         CheckForSupplyNode(state, exhCtrlNum, nodeNotFound);
     482            0 :                         if (nodeNotFound) {
     483            0 :                             ShowSevereError(state, format("{}{}={}", RoutineName, cCurrentModuleObject, thisExhCtrl.Name));
     484            0 :                             ShowContinueError(state,
     485            0 :                                               format("Node or NodeList Name ={}. Must all be supply nodes.", thisExhCtrl.SupplyNodeOrNodelistName));
     486            0 :                             ErrorsFound = true;
     487              :                         }
     488              :                     }
     489              :                 }
     490              : 
     491              :                 // Deal with design exhaust autosize here;
     492            8 :                 if (thisExhCtrl.DesignExhaustFlowRate == DataSizing::AutoSize) {
     493            2 :                     SizeExhaustControlFlow(state, exhCtrlNum, thisExhCtrl.SuppNodeNums);
     494              :                 }
     495              : 
     496              :                 std::string minZoneTempLimitSchedName =
     497           16 :                     ip->getAlphaFieldValue(objectFields, objectSchemaProps, "minimum_zone_temperature_limit_schedule_name");
     498            8 :                 if (minZoneTempLimitSchedName.empty()) {
     499            2 :                 } else if ((thisExhCtrl.minZoneTempLimitSched = Sched::GetSchedule(state, minZoneTempLimitSchedName)) == nullptr) {
     500            0 :                     ShowSevereItemNotFound(state, eoh, "Minimum Zone Temperature Limit Schedule Name", minZoneTempLimitSchedName);
     501              :                 }
     502              : 
     503              :                 std::string minExhFlowFracSchedName =
     504           16 :                     ip->getAlphaFieldValue(objectFields, objectSchemaProps, "minimum_exhaust_flow_fraction_schedule_name");
     505              :                 // to do so schedule matching
     506            8 :                 if (minExhFlowFracSchedName.empty()) {
     507            8 :                 } else if ((thisExhCtrl.minExhFlowFracSched = Sched::GetSchedule(state, minExhFlowFracSchedName)) == nullptr) {
     508            0 :                     ShowSevereItemNotFound(state, eoh, "Minimum Exhaust Flow Fraction Schedule Name", minExhFlowFracSchedName);
     509              :                 }
     510              : 
     511              :                 std::string balancedExhFracSchedName =
     512           16 :                     ip->getAlphaFieldValue(objectFields, objectSchemaProps, "balanced_exhaust_fraction_schedule_name");
     513              :                 // to do so schedule matching
     514            8 :                 if (balancedExhFracSchedName.empty()) {
     515            8 :                 } else if ((thisExhCtrl.balancedExhFracSched = Sched::GetSchedule(state, balancedExhFracSchedName)) == nullptr) {
     516            8 :                     ShowSevereItemNotFound(state, eoh, "Balanced Exhaust Fraction Schedule Name", balancedExhFracSchedName);
     517              :                 }
     518              : 
     519              :                 // Maybe an additional check per IORef:
     520              :                 // This input field must be blank when the zone air flow balance is enforced. If user specifies a schedule and zone air flow balance
     521              :                 // is enforced, then EnergyPlus throws a warning error message, ignores the schedule and simulation continues.
     522            8 :             }
     523              : 
     524            2 :             state.dataZoneEquip->NumZoneExhaustControls = numZoneExhaustControls; // or exhCtrlNum
     525              : 
     526              :             // Done with creating a map that contains a table of for each zone to exhasut controls
     527            2 :             state.dataExhAirSystemMrg->mappingDone = true;
     528              :         }
     529              : 
     530          112 :         if (ErrorsFound) {
     531            0 :             ShowFatalError(state, "Errors found getting ZoneHVAC:ExhaustControl.  Preceding condition(s) causes termination.");
     532              :         }
     533          112 :     }
     534              : 
     535       424465 :     void SimZoneHVACExhaustControls(EnergyPlusData &state)
     536              :     {
     537       424465 :         if (state.dataExhCtrlSystemMrg->GetInputFlag) { // First time subroutine has been entered
     538          110 :             GetZoneExhaustControlInput(state);
     539          110 :             state.dataExhCtrlSystemMrg->GetInputFlag = false;
     540              :         }
     541              : 
     542       424465 :         for (int ExhaustControlNum = 1; ExhaustControlNum <= state.dataZoneEquip->NumZoneExhaustControls; ++ExhaustControlNum) {
     543            0 :             CalcZoneHVACExhaustControl(state, ExhaustControlNum);
     544              :         }
     545              : 
     546              :         // report results if needed
     547       424465 :     }
     548              : 
     549            1 :     void CalcZoneHVACExhaustControl(EnergyPlusData &state, int const ZoneHVACExhaustControlNum, Real64 const FlowRatio)
     550              :     {
     551              :         // Calculate a zonehvac exhaust control system
     552              : 
     553            1 :         auto &thisExhCtrl = state.dataZoneEquip->ZoneExhaustControlSystem(ZoneHVACExhaustControlNum);
     554              : 
     555            1 :         int InletNode = thisExhCtrl.InletNodeNum;
     556            1 :         int OutletNode = thisExhCtrl.OutletNodeNum;
     557            1 :         auto &thisExhInlet = state.dataLoopNodes->Node(InletNode);
     558            1 :         auto &thisExhOutlet = state.dataLoopNodes->Node(OutletNode);
     559              :         Real64 MassFlow;
     560            1 :         Real64 Tin = state.dataZoneTempPredictorCorrector->zoneHeatBalance(thisExhCtrl.ZoneNum).ZT;
     561            1 :         Real64 thisExhCtrlAvailScheVal = thisExhCtrl.availSched->getCurrentVal();
     562              : 
     563            1 :         if (FlowRatio >= 0.0) {
     564            0 :             thisExhCtrl.BalancedFlow *= FlowRatio;
     565            0 :             thisExhCtrl.UnbalancedFlow *= FlowRatio;
     566              : 
     567            0 :             thisExhInlet.MassFlowRate *= FlowRatio;
     568              :         } else {
     569              :             // Availability schedule:
     570            1 :             if (thisExhCtrlAvailScheVal <= 0.0) {
     571            1 :                 MassFlow = 0.0;
     572            1 :                 thisExhInlet.MassFlowRate = 0.0;
     573              :             } else {
     574              :                 //
     575              :             }
     576              : 
     577            1 :             Real64 DesignFlowRate = thisExhCtrl.DesignExhaustFlowRate;
     578            1 :             Real64 FlowFrac = 0.0;
     579            1 :             if (thisExhCtrl.minExhFlowFracSched != nullptr) {
     580            1 :                 FlowFrac = thisExhCtrl.exhaustFlowFractionSched->getCurrentVal();
     581            1 :                 if (FlowFrac < 0.0) {
     582            0 :                     ShowWarningError(
     583            0 :                         state, format("Exhaust Flow Fraction Schedule value is negative for Zone Exhaust Control Named: {};", thisExhCtrl.Name));
     584            0 :                     ShowContinueError(state, "Reset value to zero and continue the simulation.");
     585            0 :                     FlowFrac = 0.0;
     586              :                 }
     587              :             }
     588              : 
     589            1 :             Real64 MinFlowFrac = 0.0;
     590            1 :             if (thisExhCtrl.minExhFlowFracSched != nullptr) {
     591            1 :                 MinFlowFrac = thisExhCtrl.minExhFlowFracSched->getCurrentVal();
     592            1 :                 if (MinFlowFrac < 0.0) {
     593            0 :                     ShowWarningError(
     594              :                         state,
     595            0 :                         format("Minimum Exhaust Flow Fraction Schedule value is negative for Zone Exhaust Control Named: {};", thisExhCtrl.Name));
     596            0 :                     ShowContinueError(state, "Reset value to zero and continue the simulation.");
     597            0 :                     MinFlowFrac = 0.0;
     598              :                 }
     599              :             }
     600              : 
     601            1 :             if (FlowFrac < MinFlowFrac) {
     602            0 :                 FlowFrac = MinFlowFrac;
     603              :             }
     604              : 
     605            1 :             if (thisExhCtrlAvailScheVal > 0.0) { // available
     606            0 :                 if (thisExhCtrl.minZoneTempLimitSched != nullptr) {
     607            0 :                     if (Tin >= thisExhCtrl.minZoneTempLimitSched->getCurrentVal()) {
     608              :                     } else {
     609            0 :                         FlowFrac = MinFlowFrac;
     610              :                     }
     611              :                 } else {
     612              :                     // flow not changed
     613              :                 }
     614              :             } else {
     615            1 :                 FlowFrac = 0.0; // directly set flow rate to zero.
     616              :             }
     617              : 
     618            1 :             if (thisExhCtrl.FlowControlOption == ZoneExhaustControl::FlowControlType::FollowSupply) { // follow-supply
     619            0 :                 Real64 supplyFlowRate = 0.0;
     620            0 :                 int numOfSuppNodes = thisExhCtrl.SuppNodeNums.size();
     621            0 :                 for (int i = 1; i <= numOfSuppNodes; ++i) {
     622            0 :                     supplyFlowRate += state.dataLoopNodes->Node(thisExhCtrl.SuppNodeNums(i)).MassFlowRate;
     623              :                 }
     624            0 :                 MassFlow = supplyFlowRate * FlowFrac;
     625              :             } else { // Scheduled or Invalid
     626            1 :                 MassFlow = DesignFlowRate * FlowFrac;
     627              :             }
     628              : 
     629            1 :             if (thisExhCtrl.balancedExhFracSched != nullptr) {
     630            0 :                 thisExhCtrl.BalancedFlow = // state.dataHVACGlobal->BalancedExhMassFlow =
     631            0 :                     MassFlow *             // state.dataHVACGlobal->UnbalExhMassFlow *
     632            0 :                     thisExhCtrl.balancedExhFracSched->getCurrentVal();
     633            0 :                 thisExhCtrl.UnbalancedFlow =  // state.dataHVACGlobal->UnbalExhMassFlow =
     634            0 :                     MassFlow -                // = state.dataHVACGlobal->UnbalExhMassFlow -
     635            0 :                     thisExhCtrl.BalancedFlow; // state.dataHVACGlobal->BalancedExhMassFlow;
     636              :             } else {
     637            1 :                 thisExhCtrl.BalancedFlow = 0.0;
     638            1 :                 thisExhCtrl.UnbalancedFlow = MassFlow;
     639              :             }
     640              : 
     641            1 :             thisExhInlet.MassFlowRate = MassFlow;
     642              :         }
     643              : 
     644            1 :         thisExhOutlet.MassFlowRate = thisExhInlet.MassFlowRate;
     645              : 
     646            1 :         thisExhOutlet.Temp = thisExhInlet.Temp;
     647            1 :         thisExhOutlet.HumRat = thisExhInlet.HumRat;
     648            1 :         thisExhOutlet.Enthalpy = thisExhInlet.Enthalpy;
     649              :         // Set the outlet nodes for properties that just pass through & not used
     650            1 :         thisExhOutlet.Quality = thisExhInlet.Quality;
     651            1 :         thisExhOutlet.Press = thisExhInlet.Press;
     652              : 
     653              :         // Set the Node Flow Control Variables from the Fan Control Variables
     654            1 :         thisExhOutlet.MassFlowRateMax = thisExhInlet.MassFlowRateMax;
     655            1 :         thisExhOutlet.MassFlowRateMaxAvail = thisExhInlet.MassFlowRateMaxAvail;
     656            1 :         thisExhOutlet.MassFlowRateMinAvail = thisExhInlet.MassFlowRateMinAvail;
     657              : 
     658              :         // these might also be useful to pass through
     659            1 :         if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
     660            0 :             thisExhOutlet.CO2 = thisExhInlet.CO2;
     661              :         }
     662              : 
     663            1 :         if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
     664            0 :             thisExhOutlet.GenContam = thisExhInlet.GenContam;
     665              :         }
     666            1 :     }
     667              : 
     668            4 :     void SizeExhaustSystem(EnergyPlusData &state, int const exhSysNum)
     669              :     {
     670            4 :         auto &thisExhSys = state.dataZoneEquip->ExhaustAirSystem(exhSysNum);
     671              : 
     672            4 :         if (!thisExhSys.SizingFlag) {
     673            0 :             return;
     674              :         }
     675              : 
     676              :         // mixer outlet sizing:
     677            4 :         Real64 outletFlowMaxAvail = 0.0;
     678           12 :         for (int i = 1; i <= state.dataMixerComponent->MixerCond(thisExhSys.ZoneMixerIndex).NumInletNodes; ++i) {
     679            8 :             int inletNode_index = state.dataMixerComponent->MixerCond(thisExhSys.ZoneMixerIndex).InletNode(i);
     680            8 :             outletFlowMaxAvail += state.dataLoopNodes->Node(inletNode_index).MassFlowRateMaxAvail;
     681              :         }
     682              : 
     683              :         // mixer outlet considered OutletMassFlowRateMaxAvail?
     684            4 :         int outletNode_index = state.dataMixerComponent->MixerCond(thisExhSys.ZoneMixerIndex).OutletNode;
     685            4 :         state.dataLoopNodes->Node(outletNode_index).MassFlowRateMaxAvail = outletFlowMaxAvail;
     686              : 
     687            4 :         auto *fan = state.dataFans->fans(thisExhSys.CentralFanIndex);
     688              :         // then central exhasut fan sizing here:
     689            4 :         if (thisExhSys.centralFanType == HVAC::FanType::SystemModel) {
     690            4 :             if (fan->maxAirFlowRate == DataSizing::AutoSize) {
     691            0 :                 fan->maxAirFlowRate = outletFlowMaxAvail / state.dataEnvrn->StdRhoAir;
     692              :             }
     693            4 :             BaseSizer::reportSizerOutput(state, "FAN:SYSTEMMODEL", fan->Name, "Design Fan Airflow [m3/s]", fan->maxAirFlowRate);
     694            0 :         } else if (thisExhSys.centralFanType == HVAC::FanType::ComponentModel) {
     695            0 :             if (fan->maxAirMassFlowRate == DataSizing::AutoSize) {
     696            0 :                 fan->maxAirMassFlowRate = outletFlowMaxAvail * dynamic_cast<Fans::FanComponent *>(fan)->sizingFactor;
     697              :             }
     698            0 :             BaseSizer::reportSizerOutput(state,
     699            0 :                                          HVAC::fanTypeNames[(int)fan->type],
     700              :                                          fan->Name,
     701              :                                          "Design Fan Airflow [m3/s]",
     702            0 :                                          fan->maxAirMassFlowRate / state.dataEnvrn->StdRhoAir);
     703              :         } else {
     704              :             //
     705              :         }
     706              : 
     707              :         // after evertyhing sized, set the sizing flag to be false
     708            4 :         thisExhSys.SizingFlag = false;
     709              :     }
     710              : 
     711            2 :     void SizeExhaustControlFlow(EnergyPlusData &state, int const zoneExhCtrlNum, Array1D_int &NodeNums)
     712              :     {
     713            2 :         auto &thisExhCtrl = state.dataZoneEquip->ZoneExhaustControlSystem(zoneExhCtrlNum);
     714              : 
     715            2 :         Real64 designFlow = 0.0;
     716              : 
     717            2 :         if (thisExhCtrl.FlowControlOption == ZoneExhaustControl::FlowControlType::FollowSupply) { // FollowSupply
     718              :             // size based on supply nodelist flow
     719            0 :             for (size_t i = 1; i <= NodeNums.size(); ++i) {
     720            0 :                 designFlow += state.dataLoopNodes->Node(NodeNums(i)).MassFlowRateMax;
     721              :             }
     722              :         } else { // scheduled etc.
     723              :             // based on zone OA.
     724            2 :             designFlow = state.dataSize->FinalZoneSizing(thisExhCtrl.ZoneNum).MinOA;
     725              :         }
     726              : 
     727            2 :         thisExhCtrl.DesignExhaustFlowRate = designFlow;
     728            2 :     }
     729              : 
     730       424465 :     void UpdateZoneExhaustControl(EnergyPlusData &state)
     731              :     {
     732       424465 :         for (int i = 1; i <= state.dataZoneEquip->NumZoneExhaustControls; ++i) {
     733            0 :             int controlledZoneNum = state.dataZoneEquip->ZoneExhaustControlSystem(i).ControlledZoneNum;
     734            0 :             state.dataZoneEquip->ZoneEquipConfig(controlledZoneNum).ZoneExh +=
     735            0 :                 state.dataZoneEquip->ZoneExhaustControlSystem(i).BalancedFlow + state.dataZoneEquip->ZoneExhaustControlSystem(i).UnbalancedFlow;
     736            0 :             state.dataZoneEquip->ZoneEquipConfig(controlledZoneNum).ZoneExhBalanced += state.dataZoneEquip->ZoneExhaustControlSystem(i).BalancedFlow;
     737              :         }
     738       424465 :     }
     739              : 
     740            2 :     void CheckForSupplyNode(EnergyPlusData &state, int const ExhCtrlNum, bool &NodeNotFound)
     741              :     {
     742              :         // Trying to check a node to see if it is truely a supply node
     743              :         // for a nodelist, need a call loop to check each node in the list
     744              : 
     745            2 :         auto &thisExhCtrl = state.dataZoneEquip->ZoneExhaustControlSystem(ExhCtrlNum);
     746              : 
     747              :         // check a node is a zone inlet node.
     748            2 :         std::string_view constexpr RoutineName = "GetExhaustControlInput: ";
     749            2 :         std::string_view constexpr CurrentModuleObject = "ZoneHVAC:ExhaustControl";
     750              : 
     751            2 :         bool ZoneNodeNotFound = true;
     752            2 :         bool ErrorsFound = false;
     753            4 :         for (size_t i = 1; i <= thisExhCtrl.SuppNodeNums.size(); ++i) {
     754            2 :             int supplyNodeNum = thisExhCtrl.SuppNodeNums(i);
     755            3 :             for (int NodeNum = 1; NodeNum <= state.dataZoneEquip->ZoneEquipConfig(thisExhCtrl.ZoneNum).NumInletNodes; ++NodeNum) {
     756            2 :                 if (supplyNodeNum == state.dataZoneEquip->ZoneEquipConfig(thisExhCtrl.ZoneNum).InletNode(NodeNum)) {
     757            1 :                     ZoneNodeNotFound = false;
     758            1 :                     break;
     759              :                 }
     760              :             }
     761            2 :             if (ZoneNodeNotFound) {
     762            1 :                 ShowSevereError(state, format("{}{}={}", RoutineName, CurrentModuleObject, thisExhCtrl.Name));
     763            2 :                 ShowContinueError(
     764              :                     state,
     765            2 :                     format("Supply or supply list = \"{}\" contains at least one node that is not a zone inlet node for Zone Name = \"{}\"",
     766            1 :                            thisExhCtrl.SupplyNodeOrNodelistName,
     767            1 :                            thisExhCtrl.ZoneName));
     768            2 :                 ShowContinueError(state, "..Nodes in the supply node or nodelist must be a zone inlet node.");
     769            1 :                 ErrorsFound = true;
     770              :             }
     771              :         }
     772              : 
     773            2 :         NodeNotFound = ErrorsFound;
     774            2 :     }
     775              : 
     776            0 :     bool ExhaustSystemHasMixer(EnergyPlusData &state, std::string_view CompName) // component (mixer) name
     777              :     {
     778              :         // Given a mixer name, this routine determines if that mixer is found on Exhaust Systems.
     779              : 
     780            0 :         if (state.dataExhAirSystemMrg->GetInputFlag) {
     781            0 :             GetExhaustAirSystemInput(state);
     782            0 :             state.dataExhAirSystemMrg->GetInputFlag = false;
     783              :         }
     784              : 
     785              :         return // ( state.dataZoneEquip->NumExhaustAirSystems > 0) &&
     786            0 :             (Util::FindItemInList(CompName, state.dataZoneEquip->ExhaustAirSystem, &ExhaustAir::ZoneMixerName) > 0);
     787              :     }
     788              : 
     789              : } // namespace ExhaustAirSystemManager
     790              : 
     791              : } // namespace EnergyPlus
        

Generated by: LCOV version 2.0-1