LCOV - code coverage report
Current view: top level - EnergyPlus - ExhaustAirSystemManager.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 63.7 % 388 247
Test Date: 2025-06-02 12:03:30 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) {
     103            0 :             return;
     104              :         }
     105              :         // state.dataExhAirSystemMrg->GetInputFlag = false;
     106              : 
     107              :         // Locals
     108          112 :         bool ErrorsFound = false;
     109              : 
     110          112 :         constexpr std::string_view RoutineName("GetExhaustAirSystemInput: ");
     111          112 :         constexpr std::string_view routineName = "GetExhaustAirSystemInput";
     112          112 :         std::string const cCurrentModuleObject = "AirLoopHVAC:ExhaustSystem";
     113              : 
     114          112 :         auto &ip = state.dataInputProcessing->inputProcessor;
     115          112 :         auto const instances = ip->epJSON.find(cCurrentModuleObject);
     116          112 :         if (instances != ip->epJSON.end()) {
     117            2 :             auto const &objectSchemaProps = ip->getObjectSchemaProps(state, cCurrentModuleObject);
     118            2 :             auto &instancesValue = instances.value();
     119            2 :             int numExhaustSystems = instancesValue.size();
     120            2 :             int exhSysNum = 0;
     121              : 
     122            2 :             if (numExhaustSystems > 0) {
     123            2 :                 state.dataZoneEquip->ExhaustAirSystem.allocate(numExhaustSystems);
     124              :             }
     125              : 
     126            6 :             for (auto instance = instancesValue.begin(); instance != instancesValue.end(); ++instance) {
     127            4 :                 ++exhSysNum;
     128            4 :                 auto const &objectFields = instance.value();
     129            4 :                 auto &thisExhSys = state.dataZoneEquip->ExhaustAirSystem(exhSysNum);
     130            4 :                 thisExhSys.Name = Util::makeUPPER(instance.key());
     131            4 :                 ip->markObjectAsUsed(cCurrentModuleObject, instance.key());
     132              : 
     133            8 :                 std::string zoneMixerName = ip->getAlphaFieldValue(objectFields, objectSchemaProps, "zone_mixer_name");
     134            4 :                 int zoneMixerIndex = 0;
     135            4 :                 bool zoneMixerErrFound = false;
     136            4 :                 MixerComponent::GetZoneMixerIndex(state, zoneMixerName, zoneMixerIndex, zoneMixerErrFound, thisExhSys.Name);
     137              : 
     138            4 :                 if (!zoneMixerErrFound) {
     139              :                     // With the correct MixerNum Initialize
     140            4 :                     MixerComponent::InitAirMixer(state, zoneMixerIndex); // Initialize all Mixer related parameters
     141              : 
     142              :                     // See if need to do the zone mixer's CheckEquipName() function
     143            4 :                     bool IsNotOK = false; // Flag to verify name
     144            4 :                     ValidateComponent(state, "AirLoopHVAC:ZoneMixer", zoneMixerName, IsNotOK, "AirLoopHVAC:ExhaustSystem");
     145            4 :                     if (IsNotOK) {
     146            0 :                         ShowSevereError(state, format("{}{}={}", RoutineName, cCurrentModuleObject, thisExhSys.Name));
     147            0 :                         ShowContinueError(state, format("ZoneMixer Name ={} mismatch or not found.", zoneMixerName));
     148            0 :                         ErrorsFound = true;
     149              :                     } else {
     150              :                         // normal conditions
     151              :                     }
     152              :                 } else {
     153            0 :                     ShowSevereError(state, format("{}{}={}", RoutineName, cCurrentModuleObject, thisExhSys.Name));
     154            0 :                     ShowContinueError(state, format("Zone Mixer Name ={} not found.", zoneMixerName));
     155            0 :                     ErrorsFound = true;
     156              :                 }
     157            4 :                 thisExhSys.ZoneMixerName = zoneMixerName;
     158            4 :                 thisExhSys.ZoneMixerIndex = zoneMixerIndex;
     159              : 
     160            4 :                 thisExhSys.centralFanType = static_cast<HVAC::FanType>(
     161            8 :                     getEnumValue(HVAC::fanTypeNamesUC, Util::makeUPPER(ip->getAlphaFieldValue(objectFields, objectSchemaProps, "fan_object_type"))));
     162            4 :                 if (thisExhSys.centralFanType != HVAC::FanType::SystemModel && thisExhSys.centralFanType != HVAC::FanType::ComponentModel) {
     163            0 :                     ShowSevereError(state, format("{}{}={}", RoutineName, cCurrentModuleObject, thisExhSys.Name));
     164            0 :                     ShowContinueError(state, format("Fan Type ={} is not supported.", HVAC::fanTypeNames[(int)thisExhSys.centralFanType]));
     165            0 :                     ShowContinueError(state, "It needs to be either a Fan:SystemModel or a Fan:ComponentModel type.");
     166            0 :                     ErrorsFound = true;
     167              :                 }
     168              : 
     169            8 :                 std::string centralFanName = ip->getAlphaFieldValue(objectFields, objectSchemaProps, "fan_name");
     170              : 
     171            4 :                 ErrorObjectHeader eoh{routineName, cCurrentModuleObject, thisExhSys.Name};
     172            4 :                 int centralFanIndex = Fans::GetFanIndex(state, centralFanName);
     173            4 :                 if (centralFanIndex == 0) {
     174            0 :                     ShowSevereItemNotFound(state, eoh, "fan_name", centralFanName);
     175            0 :                     ErrorsFound = true;
     176              :                 } else {
     177            4 :                     auto *fan = state.dataFans->fans(centralFanIndex);
     178              : 
     179            4 :                     thisExhSys.availSched = fan->availSched;
     180              : 
     181           12 :                     BranchNodeConnections::SetUpCompSets(state,
     182              :                                                          cCurrentModuleObject,
     183              :                                                          thisExhSys.Name,
     184            4 :                                                          HVAC::fanTypeNames[(int)thisExhSys.centralFanType],
     185              :                                                          centralFanName,
     186            4 :                                                          state.dataLoopNodes->NodeID(fan->inletNodeNum),
     187            4 :                                                          state.dataLoopNodes->NodeID(fan->outletNodeNum));
     188              : 
     189            8 :                     SetupOutputVariable(state,
     190              :                                         "Central Exhaust Fan Mass Flow Rate",
     191              :                                         Constant::Units::kg_s,
     192            4 :                                         thisExhSys.centralFan_MassFlowRate,
     193              :                                         OutputProcessor::TimeStepType::System,
     194              :                                         OutputProcessor::StoreType::Average,
     195            4 :                                         thisExhSys.Name);
     196              : 
     197            8 :                     SetupOutputVariable(state,
     198              :                                         "Central Exhaust Fan Volumetric Flow Rate Standard",
     199              :                                         Constant::Units::m3_s,
     200            4 :                                         thisExhSys.centralFan_VolumeFlowRate_Std,
     201              :                                         OutputProcessor::TimeStepType::System,
     202              :                                         OutputProcessor::StoreType::Average,
     203            4 :                                         thisExhSys.Name);
     204              : 
     205            8 :                     SetupOutputVariable(state,
     206              :                                         "Central Exhaust Fan Volumetric Flow Rate Current",
     207              :                                         Constant::Units::m3_s,
     208            4 :                                         thisExhSys.centralFan_VolumeFlowRate_Cur,
     209              :                                         OutputProcessor::TimeStepType::System,
     210              :                                         OutputProcessor::StoreType::Average,
     211            4 :                                         thisExhSys.Name);
     212              : 
     213            8 :                     SetupOutputVariable(state,
     214              :                                         "Central Exhaust Fan Power",
     215              :                                         Constant::Units::W,
     216            4 :                                         thisExhSys.centralFan_Power,
     217              :                                         OutputProcessor::TimeStepType::System,
     218              :                                         OutputProcessor::StoreType::Average,
     219            4 :                                         thisExhSys.Name);
     220              : 
     221            8 :                     SetupOutputVariable(state,
     222              :                                         "Central Exhaust Fan Energy",
     223              :                                         Constant::Units::J,
     224            4 :                                         thisExhSys.centralFan_Energy,
     225              :                                         OutputProcessor::TimeStepType::System,
     226              :                                         OutputProcessor::StoreType::Sum,
     227            4 :                                         thisExhSys.Name);
     228              :                 }
     229              : 
     230            4 :                 thisExhSys.CentralFanName = centralFanName;
     231            4 :                 thisExhSys.CentralFanIndex = centralFanIndex;
     232              : 
     233              :                 // sizing
     234            4 :                 if (thisExhSys.SizingFlag) {
     235            4 :                     SizeExhaustSystem(state, exhSysNum);
     236              :                 }
     237            6 :             }
     238            2 :             state.dataZoneEquip->NumExhaustAirSystems = numExhaustSystems;
     239              :         } else {
     240              :             // If no exhaust systems are defined, then do something <or nothing>:
     241              :         }
     242              : 
     243          112 :         if (ErrorsFound) {
     244            0 :             ShowFatalError(state, "Errors found getting AirLoopHVAC:ExhaustSystem.  Preceding condition(s) causes termination.");
     245              :         }
     246          112 :     }
     247              : 
     248            0 :     void CalcExhaustAirSystem(EnergyPlusData &state, int const ExhaustAirSystemNum, bool FirstHVACIteration)
     249              :     {
     250            0 :         auto &thisExhSys = state.dataZoneEquip->ExhaustAirSystem(ExhaustAirSystemNum);
     251            0 :         constexpr std::string_view RoutineName = "CalExhaustAirSystem: ";
     252            0 :         constexpr std::string_view cCurrentModuleObject = "AirloopHVAC:ExhaustSystem";
     253            0 :         bool ErrorsFound = false;
     254            0 :         if (!(state.afn->AirflowNetworkFanActivated && state.afn->distribution_simulated)) {
     255            0 :             MixerComponent::SimAirMixer(state, thisExhSys.ZoneMixerName, thisExhSys.ZoneMixerIndex);
     256              :         } else {
     257              :             // Give a warning that the current model does not work with AirflowNetwork for now
     258            0 :             ShowSevereError(state, format("{}{}={}", RoutineName, cCurrentModuleObject, thisExhSys.Name));
     259            0 :             ShowContinueError(state, "AirloopHVAC:ExhaustSystem currently does not work with AirflowNetwork.");
     260            0 :             ErrorsFound = true;
     261              :         }
     262              : 
     263            0 :         if (ErrorsFound) {
     264            0 :             ShowFatalError(state, "Errors found conducting CalcExhasutAirSystem(). Preceding condition(s) causes termination.");
     265              :         }
     266              : 
     267            0 :         Real64 mixerFlow_Prior = 0.0;
     268            0 :         int outletNode_index = state.dataMixerComponent->MixerCond(thisExhSys.ZoneMixerIndex).OutletNode;
     269            0 :         mixerFlow_Prior = state.dataLoopNodes->Node(outletNode_index).MassFlowRate;
     270              :         if (mixerFlow_Prior == 0.0) {
     271              :             // No flow coming out from the exhaust controls;
     272              :             // fan should be cut off now;
     273              :         }
     274              : 
     275            0 :         int outletNode_Num = 0;
     276            0 :         Real64 RhoAirCurrent = state.dataEnvrn->StdRhoAir;
     277              : 
     278            0 :         if (thisExhSys.centralFanType == HVAC::FanType::SystemModel) {
     279            0 :             state.dataHVACGlobal->OnOffFanPartLoadFraction = 1.0;
     280            0 :             state.dataFans->fans(thisExhSys.CentralFanIndex)->simulate(state, false, _, _);
     281              : 
     282              :             // Update report variables
     283            0 :             outletNode_Num = state.dataFans->fans(thisExhSys.CentralFanIndex)->outletNodeNum;
     284              : 
     285            0 :             thisExhSys.centralFan_MassFlowRate = state.dataLoopNodes->Node(outletNode_Num).MassFlowRate;
     286              : 
     287            0 :             thisExhSys.centralFan_VolumeFlowRate_Std = state.dataLoopNodes->Node(outletNode_Num).MassFlowRate / state.dataEnvrn->StdRhoAir;
     288              : 
     289            0 :             RhoAirCurrent = EnergyPlus::Psychrometrics::PsyRhoAirFnPbTdbW(state,
     290            0 :                                                                           state.dataEnvrn->OutBaroPress,
     291            0 :                                                                           state.dataLoopNodes->Node(outletNode_Num).Temp,
     292            0 :                                                                           state.dataLoopNodes->Node(outletNode_Num).HumRat);
     293            0 :             if (RhoAirCurrent <= 0.0) {
     294            0 :                 RhoAirCurrent = state.dataEnvrn->StdRhoAir;
     295              :             }
     296            0 :             thisExhSys.centralFan_VolumeFlowRate_Cur = state.dataLoopNodes->Node(outletNode_Num).MassFlowRate / RhoAirCurrent;
     297              : 
     298            0 :             thisExhSys.centralFan_Power = state.dataFans->fans(thisExhSys.CentralFanIndex)->totalPower;
     299              : 
     300            0 :             thisExhSys.centralFan_Energy = thisExhSys.centralFan_Power * state.dataHVACGlobal->TimeStepSysSec;
     301              : 
     302            0 :         } else if (thisExhSys.centralFanType == HVAC::FanType::ComponentModel) {
     303            0 :             auto *fan = state.dataFans->fans(thisExhSys.CentralFanIndex);
     304            0 :             fan->simulate(state, FirstHVACIteration);
     305              : 
     306              :             // Update output variables
     307              : 
     308            0 :             outletNode_Num = fan->outletNodeNum;
     309              : 
     310            0 :             thisExhSys.centralFan_MassFlowRate = fan->outletAirMassFlowRate;
     311              : 
     312            0 :             thisExhSys.centralFan_VolumeFlowRate_Std = fan->outletAirMassFlowRate / state.dataEnvrn->StdRhoAir;
     313              : 
     314            0 :             RhoAirCurrent = EnergyPlus::Psychrometrics::PsyRhoAirFnPbTdbW(state,
     315            0 :                                                                           state.dataEnvrn->OutBaroPress,
     316            0 :                                                                           state.dataLoopNodes->Node(outletNode_Num).Temp,
     317            0 :                                                                           state.dataLoopNodes->Node(outletNode_Num).HumRat);
     318            0 :             if (RhoAirCurrent <= 0.0) {
     319            0 :                 RhoAirCurrent = state.dataEnvrn->StdRhoAir;
     320              :             }
     321            0 :             thisExhSys.centralFan_VolumeFlowRate_Cur = fan->outletAirMassFlowRate / RhoAirCurrent;
     322              : 
     323            0 :             thisExhSys.centralFan_Power = fan->totalPower * 1000.0;
     324              : 
     325            0 :             thisExhSys.centralFan_Energy = fan->totalEnergy * 1000.0;
     326              :         }
     327            0 :         thisExhSys.exhTotalHVACReliefHeatLoss = state.dataLoopNodes->Node(outletNode_Num).MassFlowRate *
     328            0 :                                                 (state.dataLoopNodes->Node(outletNode_Num).Enthalpy - state.dataEnvrn->OutEnthalpy);
     329              : 
     330            0 :         Real64 mixerFlow_Posterior = 0.0;
     331            0 :         mixerFlow_Posterior = state.dataLoopNodes->Node(outletNode_index).MassFlowRate;
     332              :         if (mixerFlow_Posterior < HVAC::SmallMassFlow) {
     333              :             // fan flow is nearly zero and should be considered off
     334              :             // but this still can use the ratio
     335              :         }
     336              :         if (mixerFlow_Prior < HVAC::SmallMassFlow) {
     337              :             // this is the case where the fan flow should be resetted to zeros and not run the ratio
     338              :         }
     339            0 :         if ((mixerFlow_Prior - mixerFlow_Posterior > HVAC::SmallMassFlow) || (mixerFlow_Prior - mixerFlow_Posterior < -HVAC::SmallMassFlow)) {
     340              :             // calculate a ratio
     341            0 :             Real64 flowRatio = mixerFlow_Posterior / mixerFlow_Prior;
     342            0 :             if (flowRatio > 1.0) {
     343            0 :                 ShowWarningError(state, format("{}{}={}", RoutineName, cCurrentModuleObject, thisExhSys.Name));
     344            0 :                 ShowContinueError(state, "Requested flow rate is lower than the exhasut fan flow rate.");
     345            0 :                 ShowContinueError(state, "Will scale up the requested flow rate to meet fan flow rate.");
     346              :             }
     347              : 
     348              :             // get the mixer inlet node index
     349            0 :             int zoneMixerIndex = thisExhSys.ZoneMixerIndex;
     350            0 :             for (int i = 1; i <= state.dataMixerComponent->MixerCond(zoneMixerIndex).NumInletNodes; ++i) {
     351            0 :                 int exhLegIndex = state.dataExhAirSystemMrg->mixerIndexMap[state.dataMixerComponent->MixerCond(zoneMixerIndex).InletNode(i)];
     352            0 :                 CalcZoneHVACExhaustControl(state, exhLegIndex, flowRatio);
     353              :             }
     354              : 
     355              :             // Simulate the mixer again to update the flow
     356            0 :             MixerComponent::SimAirMixer(state, thisExhSys.ZoneMixerName, thisExhSys.ZoneMixerIndex);
     357              : 
     358              :             // if the adjustment matches, then no need to run fan simulation again.
     359              :         }
     360            0 :     }
     361              : 
     362          112 :     void GetZoneExhaustControlInput(EnergyPlusData &state)
     363              :     {
     364              :         // Process ZoneExhaust Control inputs
     365              : 
     366              :         // Locals
     367          112 :         bool ErrorsFound = false;
     368              : 
     369              :         // Use the json helper to process input
     370          112 :         constexpr std::string_view RoutineName("GetZoneExhaustControlInput: ");
     371          112 :         constexpr std::string_view routineName = "GetZoneExhaustControlInput";
     372              : 
     373          112 :         std::string const cCurrentModuleObject = "ZoneHVAC:ExhaustControl";
     374          112 :         auto &ip = state.dataInputProcessing->inputProcessor;
     375          112 :         auto const instances = ip->epJSON.find(cCurrentModuleObject);
     376          112 :         if (instances != ip->epJSON.end()) {
     377            2 :             auto const &objectSchemaProps = ip->getObjectSchemaProps(state, cCurrentModuleObject);
     378            2 :             auto &instancesValue = instances.value();
     379            2 :             int numZoneExhaustControls = instancesValue.size();
     380            2 :             int exhCtrlNum = 0;
     381              :             int NumAlphas;
     382              :             int NumNums;
     383              : 
     384            2 :             if (numZoneExhaustControls > 0) {
     385            2 :                 state.dataZoneEquip->ZoneExhaustControlSystem.allocate(numZoneExhaustControls);
     386              :             }
     387              : 
     388           10 :             for (auto instance = instancesValue.begin(); instance != instancesValue.end(); ++instance) {
     389            8 :                 ++exhCtrlNum;
     390            8 :                 auto const &objectFields = instance.value();
     391            8 :                 auto &thisExhCtrl = state.dataZoneEquip->ZoneExhaustControlSystem(exhCtrlNum);
     392              : 
     393            8 :                 ErrorObjectHeader eoh{routineName, cCurrentModuleObject, instance.key()};
     394              : 
     395            8 :                 thisExhCtrl.Name = Util::makeUPPER(instance.key());
     396            8 :                 ip->markObjectAsUsed(cCurrentModuleObject, instance.key());
     397              : 
     398           16 :                 std::string availSchName = ip->getAlphaFieldValue(objectFields, objectSchemaProps, "availability_schedule_name");
     399            8 :                 if (availSchName.empty()) {
     400              :                     // blank
     401            0 :                     thisExhCtrl.availSched = Sched::GetScheduleAlwaysOn(state);
     402            8 :                 } else if ((thisExhCtrl.availSched = Sched::GetSchedule(state, availSchName)) == nullptr) {
     403              :                     // mismatch, reset to always on
     404            0 :                     thisExhCtrl.availSched = Sched::GetScheduleAlwaysOn(state);
     405            0 :                     ShowWarningItemNotFound(state, eoh, "Avaiability Schedule Name", availSchName, "Availability Schedule is reset to Always ON.");
     406              :                 }
     407              : 
     408           16 :                 std::string zoneName = ip->getAlphaFieldValue(objectFields, objectSchemaProps, "zone_name");
     409            8 :                 thisExhCtrl.ZoneName = zoneName;
     410            8 :                 int zoneNum = Util::FindItemInList(zoneName, state.dataHeatBal->Zone);
     411            8 :                 thisExhCtrl.ZoneNum = zoneNum;
     412              : 
     413            8 :                 thisExhCtrl.ControlledZoneNum = Util::FindItemInList(zoneName, state.dataHeatBal->Zone);
     414              : 
     415              :                 // These two nodes are required inputs:
     416           16 :                 std::string inletNodeName = ip->getAlphaFieldValue(objectFields, objectSchemaProps, "inlet_node_name");
     417            8 :                 int inletNodeNum = NodeInputManager::GetOnlySingleNode(state,
     418              :                                                                        inletNodeName,
     419              :                                                                        ErrorsFound,
     420              :                                                                        DataLoopNode::ConnectionObjectType::ZoneHVACExhaustControl,
     421            8 :                                                                        thisExhCtrl.Name,
     422              :                                                                        DataLoopNode::NodeFluidType::Air,
     423              :                                                                        DataLoopNode::ConnectionType::Inlet,
     424              :                                                                        NodeInputManager::CompFluidStream::Primary,
     425              :                                                                        DataLoopNode::ObjectIsParent);
     426            8 :                 thisExhCtrl.InletNodeNum = inletNodeNum;
     427              : 
     428           16 :                 std::string outletNodeName = ip->getAlphaFieldValue(objectFields, objectSchemaProps, "outlet_node_name");
     429              : 
     430            8 :                 int outletNodeNum = NodeInputManager::GetOnlySingleNode(state,
     431              :                                                                         outletNodeName,
     432              :                                                                         ErrorsFound,
     433              :                                                                         DataLoopNode::ConnectionObjectType::ZoneHVACExhaustControl,
     434            8 :                                                                         thisExhCtrl.Name,
     435              :                                                                         DataLoopNode::NodeFluidType::Air,
     436              :                                                                         DataLoopNode::ConnectionType::Outlet,
     437              :                                                                         NodeInputManager::CompFluidStream::Primary,
     438            8 :                                                                         DataLoopNode::ObjectIsParent);
     439            8 :                 thisExhCtrl.OutletNodeNum = outletNodeNum;
     440              : 
     441            8 :                 if (!state.dataExhAirSystemMrg->mappingDone) {
     442            8 :                     state.dataExhAirSystemMrg->mixerIndexMap.emplace(outletNodeNum, exhCtrlNum);
     443              :                 }
     444              : 
     445           16 :                 Real64 designExhaustFlowRate = ip->getRealFieldValue(objectFields, objectSchemaProps, "design_exhaust_flow_rate");
     446            8 :                 thisExhCtrl.DesignExhaustFlowRate = designExhaustFlowRate;
     447              : 
     448           16 :                 std::string flowControlTypeName = Util::makeUPPER(ip->getAlphaFieldValue(objectFields, objectSchemaProps, "flow_control_type"));
     449              :                 // std::string flowControlTypeName = Util::makeUPPER(fields.at("flow_control_type").get<std::string>());
     450            8 :                 thisExhCtrl.FlowControlOption =
     451            8 :                     static_cast<ZoneExhaustControl::FlowControlType>(getEnumValue(flowControlTypeNamesUC, flowControlTypeName));
     452              : 
     453              :                 std::string exhaustFlowFractionSchedName =
     454           16 :                     ip->getAlphaFieldValue(objectFields, objectSchemaProps, "exhaust_flow_fraction_schedule_name");
     455              : 
     456            8 :                 if (exhaustFlowFractionSchedName.empty()) {
     457            2 :                     thisExhCtrl.exhaustFlowFractionSched =
     458            2 :                         Sched::GetScheduleAlwaysOn(state); // Not an availability schedule, but defaults to constant-1.0
     459            6 :                 } else if ((thisExhCtrl.exhaustFlowFractionSched = Sched::GetSchedule(state, exhaustFlowFractionSchedName)) == nullptr) {
     460            0 :                     ShowSevereItemNotFound(state, eoh, "Exhaust Flow Fraction Schedule Name", exhaustFlowFractionSchedName);
     461              :                 }
     462              : 
     463           16 :                 thisExhCtrl.SupplyNodeOrNodelistName = ip->getAlphaFieldValue(objectFields, objectSchemaProps, "supply_node_or_nodelist_name");
     464              : 
     465            8 :                 bool NodeListError = false;
     466            8 :                 int NumParams = 0;
     467            8 :                 int NumNodes = 0;
     468              : 
     469            8 :                 ip->getObjectDefMaxArgs(state, "NodeList", NumParams, NumAlphas, NumNums);
     470            8 :                 thisExhCtrl.SuppNodeNums.dimension(NumParams, 0);
     471            8 :                 NodeInputManager::GetNodeNums(state,
     472            8 :                                               thisExhCtrl.SupplyNodeOrNodelistName,
     473              :                                               NumNodes,
     474            8 :                                               thisExhCtrl.SuppNodeNums,
     475              :                                               NodeListError,
     476              :                                               DataLoopNode::NodeFluidType::Air,
     477              :                                               DataLoopNode::ConnectionObjectType::ZoneHVACExhaustControl, // maybe zone inlets?
     478            8 :                                               thisExhCtrl.Name,
     479              :                                               DataLoopNode::ConnectionType::Sensor,
     480              :                                               NodeInputManager::CompFluidStream::Primary,
     481              :                                               DataLoopNode::ObjectIsNotParent); // , // _, // supplyNodeOrNodelistName);
     482              : 
     483              :                 // Verify these nodes are indeed supply nodes:
     484            8 :                 if (thisExhCtrl.FlowControlOption == ZoneExhaustControl::FlowControlType::FollowSupply) { // FollowSupply
     485            0 :                     bool nodeNotFound = false;
     486            0 :                     for (size_t i = 1; i <= thisExhCtrl.SuppNodeNums.size(); ++i) {
     487            0 :                         CheckForSupplyNode(state, exhCtrlNum, nodeNotFound);
     488            0 :                         if (nodeNotFound) {
     489            0 :                             ShowSevereError(state, format("{}{}={}", RoutineName, cCurrentModuleObject, thisExhCtrl.Name));
     490            0 :                             ShowContinueError(state,
     491            0 :                                               format("Node or NodeList Name ={}. Must all be supply nodes.", thisExhCtrl.SupplyNodeOrNodelistName));
     492            0 :                             ErrorsFound = true;
     493              :                         }
     494              :                     }
     495              :                 }
     496              : 
     497              :                 // Deal with design exhaust autosize here;
     498            8 :                 if (thisExhCtrl.DesignExhaustFlowRate == DataSizing::AutoSize) {
     499            2 :                     SizeExhaustControlFlow(state, exhCtrlNum, thisExhCtrl.SuppNodeNums);
     500              :                 }
     501              : 
     502              :                 std::string minZoneTempLimitSchedName =
     503           16 :                     ip->getAlphaFieldValue(objectFields, objectSchemaProps, "minimum_zone_temperature_limit_schedule_name");
     504            8 :                 if (minZoneTempLimitSchedName.empty()) {
     505            2 :                 } else if ((thisExhCtrl.minZoneTempLimitSched = Sched::GetSchedule(state, minZoneTempLimitSchedName)) == nullptr) {
     506            0 :                     ShowSevereItemNotFound(state, eoh, "Minimum Zone Temperature Limit Schedule Name", minZoneTempLimitSchedName);
     507              :                 }
     508              : 
     509              :                 std::string minExhFlowFracSchedName =
     510           16 :                     ip->getAlphaFieldValue(objectFields, objectSchemaProps, "minimum_exhaust_flow_fraction_schedule_name");
     511              :                 // to do so schedule matching
     512            8 :                 if (minExhFlowFracSchedName.empty()) {
     513            8 :                 } else if ((thisExhCtrl.minExhFlowFracSched = Sched::GetSchedule(state, minExhFlowFracSchedName)) == nullptr) {
     514            0 :                     ShowSevereItemNotFound(state, eoh, "Minimum Exhaust Flow Fraction Schedule Name", minExhFlowFracSchedName);
     515              :                 }
     516              : 
     517              :                 std::string balancedExhFracSchedName =
     518           16 :                     ip->getAlphaFieldValue(objectFields, objectSchemaProps, "balanced_exhaust_fraction_schedule_name");
     519              :                 // to do so schedule matching
     520            8 :                 if (balancedExhFracSchedName.empty()) {
     521            8 :                 } else if ((thisExhCtrl.balancedExhFracSched = Sched::GetSchedule(state, balancedExhFracSchedName)) == nullptr) {
     522            8 :                     ShowSevereItemNotFound(state, eoh, "Balanced Exhaust Fraction Schedule Name", balancedExhFracSchedName);
     523              :                 }
     524              : 
     525              :                 // Maybe an additional check per IORef:
     526              :                 // This input field must be blank when the zone air flow balance is enforced. If user specifies a schedule and zone air flow balance
     527              :                 // is enforced, then EnergyPlus throws a warning error message, ignores the schedule and simulation continues.
     528           10 :             }
     529              : 
     530            2 :             state.dataZoneEquip->NumZoneExhaustControls = numZoneExhaustControls; // or exhCtrlNum
     531              : 
     532              :             // Done with creating a map that contains a table of for each zone to exhasut controls
     533            2 :             state.dataExhAirSystemMrg->mappingDone = true;
     534              :         }
     535              : 
     536          112 :         if (ErrorsFound) {
     537            0 :             ShowFatalError(state, "Errors found getting ZoneHVAC:ExhaustControl.  Preceding condition(s) causes termination.");
     538              :         }
     539          112 :     }
     540              : 
     541       424465 :     void SimZoneHVACExhaustControls(EnergyPlusData &state)
     542              :     {
     543       424465 :         if (state.dataExhCtrlSystemMrg->GetInputFlag) { // First time subroutine has been entered
     544          110 :             GetZoneExhaustControlInput(state);
     545          110 :             state.dataExhCtrlSystemMrg->GetInputFlag = false;
     546              :         }
     547              : 
     548       424465 :         for (int ExhaustControlNum = 1; ExhaustControlNum <= state.dataZoneEquip->NumZoneExhaustControls; ++ExhaustControlNum) {
     549            0 :             CalcZoneHVACExhaustControl(state, ExhaustControlNum);
     550              :         }
     551              : 
     552              :         // report results if needed
     553       424465 :     }
     554              : 
     555            1 :     void CalcZoneHVACExhaustControl(EnergyPlusData &state, int const ZoneHVACExhaustControlNum, Real64 const FlowRatio)
     556              :     {
     557              :         // Calculate a zonehvac exhaust control system
     558              : 
     559            1 :         auto &thisExhCtrl = state.dataZoneEquip->ZoneExhaustControlSystem(ZoneHVACExhaustControlNum);
     560              : 
     561            1 :         int InletNode = thisExhCtrl.InletNodeNum;
     562            1 :         int OutletNode = thisExhCtrl.OutletNodeNum;
     563            1 :         auto &thisExhInlet = state.dataLoopNodes->Node(InletNode);
     564            1 :         auto &thisExhOutlet = state.dataLoopNodes->Node(OutletNode);
     565              :         Real64 MassFlow;
     566            1 :         Real64 Tin = state.dataZoneTempPredictorCorrector->zoneHeatBalance(thisExhCtrl.ZoneNum).ZT;
     567            1 :         Real64 thisExhCtrlAvailScheVal = thisExhCtrl.availSched->getCurrentVal();
     568              : 
     569            1 :         if (FlowRatio >= 0.0) {
     570            0 :             thisExhCtrl.BalancedFlow *= FlowRatio;
     571            0 :             thisExhCtrl.UnbalancedFlow *= FlowRatio;
     572              : 
     573            0 :             thisExhInlet.MassFlowRate *= FlowRatio;
     574              :         } else {
     575              :             // Availability schedule:
     576            1 :             if (thisExhCtrlAvailScheVal <= 0.0) {
     577            1 :                 MassFlow = 0.0;
     578            1 :                 thisExhInlet.MassFlowRate = 0.0;
     579              :             } else {
     580              :                 //
     581              :             }
     582              : 
     583            1 :             Real64 DesignFlowRate = thisExhCtrl.DesignExhaustFlowRate;
     584            1 :             Real64 FlowFrac = 0.0;
     585            1 :             if (thisExhCtrl.minExhFlowFracSched != nullptr) {
     586            1 :                 FlowFrac = thisExhCtrl.exhaustFlowFractionSched->getCurrentVal();
     587            1 :                 if (FlowFrac < 0.0) {
     588            0 :                     ShowWarningError(
     589            0 :                         state, format("Exhaust Flow Fraction Schedule value is negative for Zone Exhaust Control Named: {};", thisExhCtrl.Name));
     590            0 :                     ShowContinueError(state, "Reset value to zero and continue the simulation.");
     591            0 :                     FlowFrac = 0.0;
     592              :                 }
     593              :             }
     594              : 
     595            1 :             Real64 MinFlowFrac = 0.0;
     596            1 :             if (thisExhCtrl.minExhFlowFracSched != nullptr) {
     597            1 :                 MinFlowFrac = thisExhCtrl.minExhFlowFracSched->getCurrentVal();
     598            1 :                 if (MinFlowFrac < 0.0) {
     599            0 :                     ShowWarningError(
     600              :                         state,
     601            0 :                         format("Minimum Exhaust Flow Fraction Schedule value is negative for Zone Exhaust Control Named: {};", thisExhCtrl.Name));
     602            0 :                     ShowContinueError(state, "Reset value to zero and continue the simulation.");
     603            0 :                     MinFlowFrac = 0.0;
     604              :                 }
     605              :             }
     606              : 
     607            1 :             if (FlowFrac < MinFlowFrac) {
     608            0 :                 FlowFrac = MinFlowFrac;
     609              :             }
     610              : 
     611            1 :             if (thisExhCtrlAvailScheVal > 0.0) { // available
     612            0 :                 if (thisExhCtrl.minZoneTempLimitSched != nullptr) {
     613            0 :                     if (Tin >= thisExhCtrl.minZoneTempLimitSched->getCurrentVal()) {
     614              :                     } else {
     615            0 :                         FlowFrac = MinFlowFrac;
     616              :                     }
     617              :                 } else {
     618              :                     // flow not changed
     619              :                 }
     620              :             } else {
     621            1 :                 FlowFrac = 0.0; // directly set flow rate to zero.
     622              :             }
     623              : 
     624            1 :             if (thisExhCtrl.FlowControlOption == ZoneExhaustControl::FlowControlType::FollowSupply) { // follow-supply
     625            0 :                 Real64 supplyFlowRate = 0.0;
     626            0 :                 int numOfSuppNodes = thisExhCtrl.SuppNodeNums.size();
     627            0 :                 for (int i = 1; i <= numOfSuppNodes; ++i) {
     628            0 :                     supplyFlowRate += state.dataLoopNodes->Node(thisExhCtrl.SuppNodeNums(i)).MassFlowRate;
     629              :                 }
     630            0 :                 MassFlow = supplyFlowRate * FlowFrac;
     631              :             } else { // Scheduled or Invalid
     632            1 :                 MassFlow = DesignFlowRate * FlowFrac;
     633              :             }
     634              : 
     635            1 :             if (thisExhCtrl.balancedExhFracSched != nullptr) {
     636            0 :                 thisExhCtrl.BalancedFlow = // state.dataHVACGlobal->BalancedExhMassFlow =
     637            0 :                     MassFlow *             // state.dataHVACGlobal->UnbalExhMassFlow *
     638            0 :                     thisExhCtrl.balancedExhFracSched->getCurrentVal();
     639            0 :                 thisExhCtrl.UnbalancedFlow =  // state.dataHVACGlobal->UnbalExhMassFlow =
     640            0 :                     MassFlow -                // = state.dataHVACGlobal->UnbalExhMassFlow -
     641            0 :                     thisExhCtrl.BalancedFlow; // state.dataHVACGlobal->BalancedExhMassFlow;
     642              :             } else {
     643            1 :                 thisExhCtrl.BalancedFlow = 0.0;
     644            1 :                 thisExhCtrl.UnbalancedFlow = MassFlow;
     645              :             }
     646              : 
     647            1 :             thisExhInlet.MassFlowRate = MassFlow;
     648              :         }
     649              : 
     650            1 :         thisExhOutlet.MassFlowRate = thisExhInlet.MassFlowRate;
     651              : 
     652            1 :         thisExhOutlet.Temp = thisExhInlet.Temp;
     653            1 :         thisExhOutlet.HumRat = thisExhInlet.HumRat;
     654            1 :         thisExhOutlet.Enthalpy = thisExhInlet.Enthalpy;
     655              :         // Set the outlet nodes for properties that just pass through & not used
     656            1 :         thisExhOutlet.Quality = thisExhInlet.Quality;
     657            1 :         thisExhOutlet.Press = thisExhInlet.Press;
     658              : 
     659              :         // Set the Node Flow Control Variables from the Fan Control Variables
     660            1 :         thisExhOutlet.MassFlowRateMax = thisExhInlet.MassFlowRateMax;
     661            1 :         thisExhOutlet.MassFlowRateMaxAvail = thisExhInlet.MassFlowRateMaxAvail;
     662            1 :         thisExhOutlet.MassFlowRateMinAvail = thisExhInlet.MassFlowRateMinAvail;
     663              : 
     664              :         // these might also be useful to pass through
     665            1 :         if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
     666            0 :             thisExhOutlet.CO2 = thisExhInlet.CO2;
     667              :         }
     668              : 
     669            1 :         if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
     670            0 :             thisExhOutlet.GenContam = thisExhInlet.GenContam;
     671              :         }
     672            1 :     }
     673              : 
     674            4 :     void SizeExhaustSystem(EnergyPlusData &state, int const exhSysNum)
     675              :     {
     676            4 :         auto &thisExhSys = state.dataZoneEquip->ExhaustAirSystem(exhSysNum);
     677              : 
     678            4 :         if (!thisExhSys.SizingFlag) {
     679            0 :             return;
     680              :         }
     681              : 
     682              :         // mixer outlet sizing:
     683            4 :         Real64 outletFlowMaxAvail = 0.0;
     684           12 :         for (int i = 1; i <= state.dataMixerComponent->MixerCond(thisExhSys.ZoneMixerIndex).NumInletNodes; ++i) {
     685            8 :             int inletNode_index = state.dataMixerComponent->MixerCond(thisExhSys.ZoneMixerIndex).InletNode(i);
     686            8 :             outletFlowMaxAvail += state.dataLoopNodes->Node(inletNode_index).MassFlowRateMaxAvail;
     687              :         }
     688              : 
     689              :         // mixer outlet considered OutletMassFlowRateMaxAvail?
     690            4 :         int outletNode_index = state.dataMixerComponent->MixerCond(thisExhSys.ZoneMixerIndex).OutletNode;
     691            4 :         state.dataLoopNodes->Node(outletNode_index).MassFlowRateMaxAvail = outletFlowMaxAvail;
     692              : 
     693            4 :         auto *fan = state.dataFans->fans(thisExhSys.CentralFanIndex);
     694              :         // then central exhasut fan sizing here:
     695            4 :         if (thisExhSys.centralFanType == HVAC::FanType::SystemModel) {
     696            4 :             if (fan->maxAirFlowRate == DataSizing::AutoSize) {
     697            0 :                 fan->maxAirFlowRate = outletFlowMaxAvail / state.dataEnvrn->StdRhoAir;
     698              :             }
     699            4 :             BaseSizer::reportSizerOutput(state, "FAN:SYSTEMMODEL", fan->Name, "Design Fan Airflow [m3/s]", fan->maxAirFlowRate);
     700            0 :         } else if (thisExhSys.centralFanType == HVAC::FanType::ComponentModel) {
     701            0 :             if (fan->maxAirMassFlowRate == DataSizing::AutoSize) {
     702            0 :                 fan->maxAirMassFlowRate = outletFlowMaxAvail * dynamic_cast<Fans::FanComponent *>(fan)->sizingFactor;
     703              :             }
     704            0 :             BaseSizer::reportSizerOutput(state,
     705            0 :                                          HVAC::fanTypeNames[(int)fan->type],
     706              :                                          fan->Name,
     707              :                                          "Design Fan Airflow [m3/s]",
     708            0 :                                          fan->maxAirMassFlowRate / state.dataEnvrn->StdRhoAir);
     709              :         } else {
     710              :             //
     711              :         }
     712              : 
     713              :         // after evertyhing sized, set the sizing flag to be false
     714            4 :         thisExhSys.SizingFlag = false;
     715              :     }
     716              : 
     717            2 :     void SizeExhaustControlFlow(EnergyPlusData &state, int const zoneExhCtrlNum, Array1D_int &NodeNums)
     718              :     {
     719            2 :         auto &thisExhCtrl = state.dataZoneEquip->ZoneExhaustControlSystem(zoneExhCtrlNum);
     720              : 
     721            2 :         Real64 designFlow = 0.0;
     722              : 
     723            2 :         if (thisExhCtrl.FlowControlOption == ZoneExhaustControl::FlowControlType::FollowSupply) { // FollowSupply
     724              :             // size based on supply nodelist flow
     725            0 :             for (size_t i = 1; i <= NodeNums.size(); ++i) {
     726            0 :                 designFlow += state.dataLoopNodes->Node(NodeNums(i)).MassFlowRateMax;
     727              :             }
     728              :         } else { // scheduled etc.
     729              :             // based on zone OA.
     730            2 :             designFlow = state.dataSize->FinalZoneSizing(thisExhCtrl.ZoneNum).MinOA;
     731              :         }
     732              : 
     733            2 :         thisExhCtrl.DesignExhaustFlowRate = designFlow;
     734            2 :     }
     735              : 
     736       424465 :     void UpdateZoneExhaustControl(EnergyPlusData &state)
     737              :     {
     738       424465 :         for (int i = 1; i <= state.dataZoneEquip->NumZoneExhaustControls; ++i) {
     739            0 :             int controlledZoneNum = state.dataZoneEquip->ZoneExhaustControlSystem(i).ControlledZoneNum;
     740            0 :             state.dataZoneEquip->ZoneEquipConfig(controlledZoneNum).ZoneExh +=
     741            0 :                 state.dataZoneEquip->ZoneExhaustControlSystem(i).BalancedFlow + state.dataZoneEquip->ZoneExhaustControlSystem(i).UnbalancedFlow;
     742            0 :             state.dataZoneEquip->ZoneEquipConfig(controlledZoneNum).ZoneExhBalanced += state.dataZoneEquip->ZoneExhaustControlSystem(i).BalancedFlow;
     743              :         }
     744       424465 :     }
     745              : 
     746            2 :     void CheckForSupplyNode(EnergyPlusData &state, int const ExhCtrlNum, bool &NodeNotFound)
     747              :     {
     748              :         // Trying to check a node to see if it is truely a supply node
     749              :         // for a nodelist, need a call loop to check each node in the list
     750              : 
     751            2 :         auto &thisExhCtrl = state.dataZoneEquip->ZoneExhaustControlSystem(ExhCtrlNum);
     752              : 
     753              :         // check a node is a zone inlet node.
     754            2 :         std::string_view constexpr RoutineName = "GetExhaustControlInput: ";
     755            2 :         std::string_view constexpr CurrentModuleObject = "ZoneHVAC:ExhaustControl";
     756              : 
     757            2 :         bool ZoneNodeNotFound = true;
     758            2 :         bool ErrorsFound = false;
     759            4 :         for (size_t i = 1; i <= thisExhCtrl.SuppNodeNums.size(); ++i) {
     760            2 :             int supplyNodeNum = thisExhCtrl.SuppNodeNums(i);
     761            3 :             for (int NodeNum = 1; NodeNum <= state.dataZoneEquip->ZoneEquipConfig(thisExhCtrl.ZoneNum).NumInletNodes; ++NodeNum) {
     762            2 :                 if (supplyNodeNum == state.dataZoneEquip->ZoneEquipConfig(thisExhCtrl.ZoneNum).InletNode(NodeNum)) {
     763            1 :                     ZoneNodeNotFound = false;
     764            1 :                     break;
     765              :                 }
     766              :             }
     767            2 :             if (ZoneNodeNotFound) {
     768            1 :                 ShowSevereError(state, format("{}{}={}", RoutineName, CurrentModuleObject, thisExhCtrl.Name));
     769            2 :                 ShowContinueError(
     770              :                     state,
     771            2 :                     format("Supply or supply list = \"{}\" contains at least one node that is not a zone inlet node for Zone Name = \"{}\"",
     772            1 :                            thisExhCtrl.SupplyNodeOrNodelistName,
     773            1 :                            thisExhCtrl.ZoneName));
     774            2 :                 ShowContinueError(state, "..Nodes in the supply node or nodelist must be a zone inlet node.");
     775            1 :                 ErrorsFound = true;
     776              :             }
     777              :         }
     778              : 
     779            2 :         NodeNotFound = ErrorsFound;
     780            2 :     }
     781              : 
     782            0 :     bool ExhaustSystemHasMixer(EnergyPlusData &state, std::string_view CompName) // component (mixer) name
     783              :     {
     784              :         // Given a mixer name, this routine determines if that mixer is found on Exhaust Systems.
     785              : 
     786            0 :         if (state.dataExhAirSystemMrg->GetInputFlag) {
     787            0 :             GetExhaustAirSystemInput(state);
     788            0 :             state.dataExhAirSystemMrg->GetInputFlag = false;
     789              :         }
     790              : 
     791              :         return // ( state.dataZoneEquip->NumExhaustAirSystems > 0) &&
     792            0 :             (Util::FindItemInList(CompName, state.dataZoneEquip->ExhaustAirSystem, &ExhaustAir::ZoneMixerName) > 0);
     793              :     }
     794              : 
     795              : } // namespace ExhaustAirSystemManager
     796              : 
     797              : } // namespace EnergyPlus
        

Generated by: LCOV version 2.0-1