LCOV - code coverage report
Current view: top level - EnergyPlus - ExhaustAirSystemManager.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 267 439 60.8 %
Date: 2023-01-17 19:17:23 Functions: 12 15 80.0 %

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

Generated by: LCOV version 1.13