LCOV - code coverage report
Current view: top level - EnergyPlus - DualDuct.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 779 954 81.7 %
Date: 2023-01-17 19:17:23 Functions: 15 15 100.0 %

          Line data    Source code
       1             : // EnergyPlus, Copyright (c) 1996-2023, The Board of Trustees of the University of Illinois,
       2             : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3             : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4             : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5             : // contributors. All rights reserved.
       6             : //
       7             : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8             : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9             : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10             : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11             : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12             : //
      13             : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14             : // provided that the following conditions are met:
      15             : //
      16             : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17             : //     conditions and the following disclaimer.
      18             : //
      19             : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20             : //     conditions and the following disclaimer in the documentation and/or other materials
      21             : //     provided with the distribution.
      22             : //
      23             : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24             : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25             : //     used to endorse or promote products derived from this software without specific prior
      26             : //     written permission.
      27             : //
      28             : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29             : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30             : //     reference solely to the software portion of its product, Licensee must refer to the
      31             : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32             : //     obtained under this License and may not use a different name for the software. Except as
      33             : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34             : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35             : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36             : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37             : //
      38             : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39             : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40             : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41             : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42             : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43             : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44             : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45             : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46             : // POSSIBILITY OF SUCH DAMAGE.
      47             : 
      48             : // C++ Headers
      49             : #include <cmath>
      50             : #include <string>
      51             : 
      52             : // ObjexxFCL Headers
      53             : #include <ObjexxFCL/Array.functions.hh>
      54             : #include <ObjexxFCL/Fmath.hh>
      55             : 
      56             : // EnergyPlus Headers
      57             : #include <EnergyPlus/Autosizing/Base.hh>
      58             : #include <EnergyPlus/BranchNodeConnections.hh>
      59             : #include <EnergyPlus/Data/EnergyPlusData.hh>
      60             : #include <EnergyPlus/DataContaminantBalance.hh>
      61             : #include <EnergyPlus/DataConvergParams.hh>
      62             : #include <EnergyPlus/DataDefineEquip.hh>
      63             : #include <EnergyPlus/DataEnvironment.hh>
      64             : #include <EnergyPlus/DataHVACGlobals.hh>
      65             : #include <EnergyPlus/DataHeatBalFanSys.hh>
      66             : #include <EnergyPlus/DataHeatBalance.hh>
      67             : #include <EnergyPlus/DataLoopNode.hh>
      68             : #include <EnergyPlus/DataSizing.hh>
      69             : #include <EnergyPlus/DataZoneEnergyDemands.hh>
      70             : #include <EnergyPlus/DataZoneEquipment.hh>
      71             : #include <EnergyPlus/DualDuct.hh>
      72             : #include <EnergyPlus/GeneralRoutines.hh>
      73             : #include <EnergyPlus/GlobalNames.hh>
      74             : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      75             : #include <EnergyPlus/NodeInputManager.hh>
      76             : #include <EnergyPlus/OutputProcessor.hh>
      77             : #include <EnergyPlus/Psychrometrics.hh>
      78             : #include <EnergyPlus/ScheduleManager.hh>
      79             : #include <EnergyPlus/UtilityRoutines.hh>
      80             : 
      81             : namespace EnergyPlus {
      82             : 
      83             : namespace DualDuct {
      84             :     // Module containing the DualDuct simulation routines
      85             : 
      86             :     // MODULE INFORMATION:
      87             :     //       AUTHOR         Richard J. Liesen
      88             :     //       DATE WRITTEN   February 2000
      89             :     //       MODIFIED       Clayton Miller, Brent Griffith Aug. 2010 - Added DualDuctOA Terminal Unit to Simulate Decoupled OA/RA
      90             :     //       RE-ENGINEERED  na
      91             : 
      92             :     // PURPOSE OF THIS MODULE:
      93             :     // To encapsulate the data and algorithms required to
      94             :     // manage the DualDuct Systems Simulation
      95             : 
      96             :     constexpr std::string_view cCMO_DDConstantVolume = "AirTerminal:DualDuct:ConstantVolume";
      97             :     constexpr std::string_view cCMO_DDVariableVolume = "AirTerminal:DualDuct:VAV";
      98             :     constexpr std::string_view cCMO_DDVarVolOA = "AirTerminal:DualDuct:VAV:OutdoorAir";
      99             :     constexpr Real64 DualDuctMassFlowSetToler = DataConvergParams::HVACFlowRateToler * 0.00001;
     100             :     constexpr std::array<std::string_view, static_cast<int>(PerPersonMode::Num)> modeStrings = {"NOTSET", "CURRENTOCCUPANCY", "DESIGNOCCUPANCY"};
     101             :     constexpr std::array<std::string_view, static_cast<int>(DualDuctDamper::Num)> damperTypeStrings = {"ConstantVolume", "VAV", "VAV:OutdoorAir"};
     102             :     constexpr std::array<std::string_view, static_cast<int>(DualDuctDamper::Num)> cmoNameArray = {
     103             :         cCMO_DDConstantVolume, cCMO_DDVariableVolume, cCMO_DDVarVolOA};
     104             : 
     105      206846 :     void SimulateDualDuct(
     106             :         EnergyPlusData &state, std::string_view CompName, bool const FirstHVACIteration, int const ZoneNum, int const ZoneNodeNum, int &CompIndex)
     107             :     {
     108             : 
     109             :         // SUBROUTINE INFORMATION:
     110             :         //       AUTHOR         Richard Liesen
     111             :         //       DATE WRITTEN   February 2000
     112             :         //       MODIFIED       na
     113             :         //       RE-ENGINEERED  na
     114             : 
     115             :         // PURPOSE OF THIS SUBROUTINE:
     116             :         // This subroutine manages Damper component simulation.
     117             :         // It is called from the SimAirLoopComponent
     118             :         // at the system time step.
     119             : 
     120             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     121             :         int DDNum; // The Damper that you are currently loading input into
     122             : 
     123             :         // Obtains and Allocates Damper related parameters from input file
     124      206846 :         if (state.dataDualDuct->GetDualDuctInputFlag) { // First time subroutine has been entered
     125           8 :             GetDualDuctInput(state);
     126           8 :             state.dataDualDuct->GetDualDuctInputFlag = false;
     127             :         }
     128             : 
     129             :         // Find the correct DDNumber with the AirLoop & CompNum from AirLoop Derived Type
     130      206846 :         if (CompIndex == 0) {
     131          34 :             DDNum = UtilityRoutines::FindItemInList(CompName, state.dataDualDuct->dd_airterminal, &DualDuctAirTerminal::Name);
     132          34 :             if (DDNum == 0) {
     133           0 :                 ShowFatalError(state, format("SimulateDualDuct: Damper not found={}", CompName));
     134             :             }
     135          34 :             CompIndex = DDNum;
     136             :         } else {
     137      206812 :             DDNum = CompIndex;
     138      206812 :             if (DDNum > state.dataDualDuct->NumDDAirTerminal || DDNum < 1) {
     139           0 :                 ShowFatalError(state,
     140           0 :                                format("SimulateDualDuct: Invalid CompIndex passed={}, Number of Dampers={}, Damper name={}",
     141             :                                       CompIndex,
     142           0 :                                       state.dataDualDuct->NumDDAirTerminal,
     143           0 :                                       CompName));
     144             :             }
     145      206812 :             if (state.dataDualDuct->dd_airterminal(DDNum).CheckEquipName) {
     146          34 :                 if (CompName != state.dataDualDuct->dd_airterminal(DDNum).Name) {
     147           0 :                     ShowFatalError(state,
     148           0 :                                    format("SimulateDualDuct: Invalid CompIndex passed={}, Damper name={}, stored Damper Name for that index={}",
     149             :                                           CompIndex,
     150             :                                           CompName,
     151           0 :                                           state.dataDualDuct->dd_airterminal(DDNum).Name));
     152             :                 }
     153          34 :                 state.dataDualDuct->dd_airterminal(DDNum).CheckEquipName = false;
     154             :             }
     155             :         }
     156             : 
     157      206846 :         auto &thisDualDuct(state.dataDualDuct->dd_airterminal(DDNum));
     158             : 
     159      206846 :         if (CompIndex > 0) {
     160      206846 :             state.dataSize->CurTermUnitSizingNum = state.dataDefineEquipment->AirDistUnit(thisDualDuct.ADUNum).TermUnitSizingNum;
     161             :             // With the correct DDNum Initialize
     162      206846 :             thisDualDuct.InitDualDuct(state, FirstHVACIteration); // Initialize all Damper related parameters
     163             : 
     164             :             // Calculate the Correct Damper Model with the current DDNum
     165      206846 :             switch (thisDualDuct.DamperType) {
     166      122805 :             case DualDuctDamper::ConstantVolume: { // 'AirTerminal:DualDuct:ConstantVolume'
     167      122805 :                 thisDualDuct.SimDualDuctConstVol(state, ZoneNum, ZoneNodeNum);
     168      122805 :             } break;
     169       16413 :             case DualDuctDamper::VariableVolume: { // 'AirTerminal:DualDuct:VAV'
     170       16413 :                 thisDualDuct.SimDualDuctVarVol(state, ZoneNum, ZoneNodeNum);
     171       16413 :             } break;
     172       67628 :             case DualDuctDamper::OutdoorAir: {
     173       67628 :                 thisDualDuct.SimDualDuctVAVOutdoorAir(state, ZoneNum, ZoneNodeNum); // 'AirTerminal:DualDuct:VAV:OutdoorAir'
     174       67628 :             } break;
     175           0 :             default:
     176           0 :                 break;
     177             :             }
     178             : 
     179             :             // Update the current Damper to the outlet nodes
     180      206846 :             thisDualDuct.UpdateDualDuct(state);
     181             :         } else {
     182           0 :             ShowFatalError(state, format("SimulateDualDuct: Damper not found={}", CompName));
     183             :         }
     184      206846 :     }
     185             : 
     186           8 :     void GetDualDuctInput(EnergyPlusData &state)
     187             :     {
     188             : 
     189             :         // SUBROUTINE INFORMATION:
     190             :         //       AUTHOR         Richard Liesen
     191             :         //       DATE WRITTEN   April 1998
     192             :         //       MODIFIED       Julien Marrec of EffiBEM, 2017-12-18
     193             :         //       RE-ENGINEERED  na
     194             : 
     195             :         // PURPOSE OF THIS SUBROUTINE:
     196             :         // This subroutine is the main routine to call other input routines and Get routines
     197             : 
     198             :         // METHODOLOGY EMPLOYED:
     199             :         // Uses the status flags to trigger events.
     200             : 
     201             :         // SUBROUTINE PARAMETER DEFINITIONS:
     202             :         static constexpr std::string_view RoutineName("GetDualDuctInput: "); // include trailing bla
     203             : 
     204             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     205             :         int NumAlphas;
     206             :         int NumNums;
     207             :         int IOStat;
     208          16 :         Array1D<Real64> NumArray(2, 0.0);
     209          16 :         Array1D_string AlphArray(7);
     210          16 :         Array1D_string cAlphaFields(7);       // Alpha field names
     211          16 :         Array1D_string cNumericFields(2);     // Numeric field names
     212          16 :         Array1D_bool lAlphaBlanks(7, true);   // Logical array, alpha field input BLANK = .TRUE.
     213          16 :         Array1D_bool lNumericBlanks(2, true); // Logical array, numeric field input BLANK = .TRUE.
     214          16 :         std::string CurrentModuleObject;      // for ease in getting objects
     215           8 :         bool ErrorsFound(false);              // If errors detected in input
     216             :         int SupAirIn;                         // controlled zone supply air inlet index
     217             :         int ADUNum;                           // loop control to search Air Distribution Units
     218           8 :         Real64 DummyOAFlow(0.0);
     219             : 
     220           8 :         int NumDualDuctConstVolDampers = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCMO_DDConstantVolume);
     221           8 :         int NumDualDuctVarVolDampers = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCMO_DDVariableVolume);
     222           8 :         state.dataDualDuct->NumDualDuctVarVolOA = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCMO_DDVarVolOA);
     223           8 :         state.dataDualDuct->NumDDAirTerminal = NumDualDuctConstVolDampers + NumDualDuctVarVolDampers + state.dataDualDuct->NumDualDuctVarVolOA;
     224           8 :         state.dataDualDuct->dd_airterminal.allocate(state.dataDualDuct->NumDDAirTerminal);
     225           8 :         state.dataDualDuct->UniqueDualDuctAirTerminalNames.reserve(state.dataDualDuct->NumDDAirTerminal);
     226             : 
     227           8 :         if (NumDualDuctConstVolDampers > 0) {
     228           6 :             CurrentModuleObject = cCMO_DDConstantVolume;
     229          26 :             for (int DamperIndex = 1; DamperIndex <= NumDualDuctConstVolDampers; ++DamperIndex) {
     230             : 
     231             :                 // Load the info from the damper
     232             : 
     233          20 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
     234             :                                                                          CurrentModuleObject,
     235             :                                                                          DamperIndex,
     236             :                                                                          AlphArray,
     237             :                                                                          NumAlphas,
     238             :                                                                          NumArray,
     239             :                                                                          NumNums,
     240             :                                                                          IOStat,
     241             :                                                                          lNumericBlanks,
     242             :                                                                          lAlphaBlanks,
     243             :                                                                          cAlphaFields,
     244             :                                                                          cNumericFields);
     245             : 
     246             :                 // Anything below this line in this control block should use DDNum
     247          20 :                 int DDNum = DamperIndex;
     248          20 :                 auto &thisDD = state.dataDualDuct->dd_airterminal(DDNum);
     249          40 :                 GlobalNames::VerifyUniqueInterObjectName(
     250          40 :                     state, state.dataDualDuct->UniqueDualDuctAirTerminalNames, AlphArray(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
     251          20 :                 thisDD.Name = AlphArray(1);
     252          20 :                 thisDD.DamperType = DualDuctDamper::ConstantVolume;
     253          20 :                 if (lAlphaBlanks(2)) {
     254           5 :                     thisDD.SchedPtr = DataGlobalConstants::ScheduleAlwaysOn;
     255             :                 } else {
     256          15 :                     thisDD.SchedPtr = ScheduleManager::GetScheduleIndex(state, AlphArray(2));
     257          15 :                     if (thisDD.SchedPtr == 0) {
     258           0 :                         ShowSevereError(state,
     259           0 :                                         format("{}, \"{}\" {} = {} not found.", CurrentModuleObject, thisDD.Name, cAlphaFields(2), AlphArray(2)));
     260           0 :                         ErrorsFound = true;
     261             :                     }
     262             :                 }
     263          40 :                 thisDD.OutletNodeNum = GetOnlySingleNode(state,
     264          20 :                                                          AlphArray(3),
     265             :                                                          ErrorsFound,
     266             :                                                          DataLoopNode::ConnectionObjectType::AirTerminalDualDuctConstantVolume,
     267             :                                                          thisDD.Name,
     268             :                                                          DataLoopNode::NodeFluidType::Air,
     269             :                                                          DataLoopNode::ConnectionType::Outlet,
     270             :                                                          NodeInputManager::CompFluidStream::Primary,
     271             :                                                          DataLoopNode::ObjectIsNotParent,
     272          20 :                                                          cAlphaFields(3));
     273          40 :                 thisDD.HotAirInletNodeNum = GetOnlySingleNode(state,
     274          20 :                                                               AlphArray(4),
     275             :                                                               ErrorsFound,
     276             :                                                               DataLoopNode::ConnectionObjectType::AirTerminalDualDuctConstantVolume,
     277             :                                                               thisDD.Name,
     278             :                                                               DataLoopNode::NodeFluidType::Air,
     279             :                                                               DataLoopNode::ConnectionType::Inlet,
     280             :                                                               NodeInputManager::CompFluidStream::Primary,
     281             :                                                               DataLoopNode::ObjectIsNotParent,
     282          20 :                                                               cAlphaFields(4));
     283          40 :                 thisDD.ColdAirInletNodeNum = GetOnlySingleNode(state,
     284          20 :                                                                AlphArray(5),
     285             :                                                                ErrorsFound,
     286             :                                                                DataLoopNode::ConnectionObjectType::AirTerminalDualDuctConstantVolume,
     287             :                                                                thisDD.Name,
     288             :                                                                DataLoopNode::NodeFluidType::Air,
     289             :                                                                DataLoopNode::ConnectionType::Inlet,
     290             :                                                                NodeInputManager::CompFluidStream::Primary,
     291             :                                                                DataLoopNode::ObjectIsNotParent,
     292          20 :                                                                cAlphaFields(5));
     293             : 
     294          20 :                 thisDD.MaxAirVolFlowRate = NumArray(1);
     295          20 :                 thisDD.ZoneMinAirFracDes = 0.0;
     296             : 
     297             :                 // Register component set data - one for heat and one for cool
     298          20 :                 BranchNodeConnections::TestCompSet(state, CurrentModuleObject + ":HEAT", thisDD.Name, AlphArray(4), AlphArray(3), "Air Nodes");
     299          20 :                 BranchNodeConnections::TestCompSet(state, CurrentModuleObject + ":COOL", thisDD.Name, AlphArray(5), AlphArray(3), "Air Nodes");
     300             : 
     301          90 :                 for (ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) {
     302          70 :                     if (thisDD.OutletNodeNum == state.dataDefineEquipment->AirDistUnit(ADUNum).OutletNodeNum) {
     303          20 :                         state.dataDefineEquipment->AirDistUnit(ADUNum).InletNodeNum = thisDD.ColdAirInletNodeNum;
     304          20 :                         state.dataDefineEquipment->AirDistUnit(ADUNum).InletNodeNum2 = thisDD.HotAirInletNodeNum;
     305          20 :                         thisDD.ADUNum = ADUNum;
     306             :                     }
     307             :                 }
     308             :                 // one assumes if there isn't one assigned, it's an error?
     309          20 :                 if (thisDD.ADUNum == 0) {
     310           0 :                     auto &thisObjType = damperTypeStrings[static_cast<int>(thisDD.DamperType)];
     311           0 :                     ShowSevereError(
     312             :                         state,
     313           0 :                         format("{}No matching List:Zone:AirTerminal for AirTerminal:DualDuct = [{},{}].", RoutineName, thisObjType, thisDD.Name));
     314           0 :                     ShowContinueError(state, "...should have outlet node=" + state.dataLoopNodes->NodeID(thisDD.OutletNodeNum));
     315           0 :                     ErrorsFound = true;
     316             :                 } else {
     317             : 
     318             :                     // Fill the Zone Equipment data with the inlet node numbers of this unit.
     319          95 :                     for (int CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) {
     320          75 :                         auto &thisZoneEquipConfig = state.dataZoneEquip->ZoneEquipConfig(CtrlZone);
     321          75 :                         if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) continue;
     322         140 :                         for (SupAirIn = 1; SupAirIn <= thisZoneEquipConfig.NumInletNodes; ++SupAirIn) {
     323          70 :                             if (thisDD.OutletNodeNum == thisZoneEquipConfig.InletNode(SupAirIn)) {
     324          20 :                                 if (state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode > 0) {
     325           0 :                                     ShowSevereError(state, "Error in connecting a terminal unit to a zone");
     326           0 :                                     ShowContinueError(state, state.dataLoopNodes->NodeID(thisDD.OutletNodeNum) + " already connects to another zone");
     327           0 :                                     ShowContinueError(state, "Occurs for terminal unit " + CurrentModuleObject + " = " + thisDD.Name);
     328           0 :                                     ShowContinueError(state, "Check terminal unit node names for errors");
     329           0 :                                     ErrorsFound = true;
     330             :                                 } else {
     331          20 :                                     thisZoneEquipConfig.AirDistUnitCool(SupAirIn).InNode = thisDD.ColdAirInletNodeNum;
     332          20 :                                     thisZoneEquipConfig.AirDistUnitHeat(SupAirIn).InNode = thisDD.HotAirInletNodeNum;
     333          20 :                                     thisZoneEquipConfig.AirDistUnitCool(SupAirIn).OutNode = thisDD.OutletNodeNum;
     334          20 :                                     thisZoneEquipConfig.AirDistUnitHeat(SupAirIn).OutNode = thisDD.OutletNodeNum;
     335          20 :                                     state.dataDefineEquipment->AirDistUnit(thisDD.ADUNum).TermUnitSizingNum =
     336          20 :                                         thisZoneEquipConfig.AirDistUnitCool(SupAirIn).TermUnitSizingIndex;
     337          20 :                                     state.dataDefineEquipment->AirDistUnit(thisDD.ADUNum).ZoneEqNum = CtrlZone;
     338             :                                 }
     339          20 :                                 thisDD.CtrlZoneNum = CtrlZone;
     340          20 :                                 thisDD.CtrlZoneInNodeIndex = SupAirIn;
     341             :                             }
     342             :                         }
     343             :                     }
     344             :                 }
     345             :                 // Setup the Average damper Position output variable
     346             :                 // CurrentModuleObject='AirTerminal:DualDuct:ConstantVolume'
     347          40 :                 SetupOutputVariable(state,
     348             :                                     "Zone Air Terminal Cold Supply Duct Damper Position",
     349             :                                     OutputProcessor::Unit::None,
     350             :                                     thisDD.ColdAirDamperPosition,
     351             :                                     OutputProcessor::SOVTimeStepType::System,
     352             :                                     OutputProcessor::SOVStoreType::Average,
     353          20 :                                     thisDD.Name);
     354          40 :                 SetupOutputVariable(state,
     355             :                                     "Zone Air Terminal Hot Supply Duct Damper Position",
     356             :                                     OutputProcessor::Unit::None,
     357             :                                     thisDD.HotAirDamperPosition,
     358             :                                     OutputProcessor::SOVTimeStepType::System,
     359             :                                     OutputProcessor::SOVStoreType::Average,
     360          20 :                                     thisDD.Name);
     361             : 
     362             :             } // end Number of Damper Loop
     363             :         }
     364             : 
     365           8 :         if (NumDualDuctVarVolDampers > 0) {
     366           1 :             CurrentModuleObject = cCMO_DDVariableVolume;
     367           4 :             for (int DamperIndex = 1; DamperIndex <= NumDualDuctVarVolDampers; ++DamperIndex) {
     368             : 
     369             :                 // Load the info from the damper
     370             : 
     371           3 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
     372             :                                                                          CurrentModuleObject,
     373             :                                                                          DamperIndex,
     374             :                                                                          AlphArray,
     375             :                                                                          NumAlphas,
     376             :                                                                          NumArray,
     377             :                                                                          NumNums,
     378             :                                                                          IOStat,
     379             :                                                                          lNumericBlanks,
     380             :                                                                          lAlphaBlanks,
     381             :                                                                          cAlphaFields,
     382             :                                                                          cNumericFields);
     383             : 
     384             :                 // Anything below this line in this control block should use DDNum
     385           3 :                 int DDNum = DamperIndex + NumDualDuctConstVolDampers;
     386           3 :                 auto &thisDD = state.dataDualDuct->dd_airterminal(DDNum);
     387           6 :                 GlobalNames::VerifyUniqueInterObjectName(
     388           6 :                     state, state.dataDualDuct->UniqueDualDuctAirTerminalNames, AlphArray(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
     389           3 :                 thisDD.Name = AlphArray(1);
     390           3 :                 thisDD.DamperType = DualDuctDamper::VariableVolume;
     391           3 :                 if (lAlphaBlanks(2)) {
     392           0 :                     thisDD.SchedPtr = DataGlobalConstants::ScheduleAlwaysOn;
     393             :                 } else {
     394           3 :                     thisDD.SchedPtr = ScheduleManager::GetScheduleIndex(state, AlphArray(2));
     395           3 :                     if (thisDD.SchedPtr == 0) {
     396           0 :                         ShowSevereError(state,
     397           0 :                                         format("{}, \"{}\" {} = {} not found.", CurrentModuleObject, thisDD.Name, cAlphaFields(2), AlphArray(2)));
     398           0 :                         ErrorsFound = true;
     399             :                     }
     400             :                 }
     401           6 :                 thisDD.OutletNodeNum = GetOnlySingleNode(state,
     402           3 :                                                          AlphArray(3),
     403             :                                                          ErrorsFound,
     404             :                                                          DataLoopNode::ConnectionObjectType::AirTerminalDualDuctVAV,
     405             :                                                          thisDD.Name,
     406             :                                                          DataLoopNode::NodeFluidType::Air,
     407             :                                                          DataLoopNode::ConnectionType::Outlet,
     408             :                                                          NodeInputManager::CompFluidStream::Primary,
     409             :                                                          DataLoopNode::ObjectIsNotParent,
     410           3 :                                                          cAlphaFields(3));
     411           6 :                 thisDD.HotAirInletNodeNum = GetOnlySingleNode(state,
     412           3 :                                                               AlphArray(4),
     413             :                                                               ErrorsFound,
     414             :                                                               DataLoopNode::ConnectionObjectType::AirTerminalDualDuctVAV,
     415             :                                                               thisDD.Name,
     416             :                                                               DataLoopNode::NodeFluidType::Air,
     417             :                                                               DataLoopNode::ConnectionType::Inlet,
     418             :                                                               NodeInputManager::CompFluidStream::Primary,
     419             :                                                               DataLoopNode::ObjectIsNotParent,
     420           3 :                                                               cAlphaFields(4));
     421           6 :                 thisDD.ColdAirInletNodeNum = GetOnlySingleNode(state,
     422           3 :                                                                AlphArray(5),
     423             :                                                                ErrorsFound,
     424             :                                                                DataLoopNode::ConnectionObjectType::AirTerminalDualDuctVAV,
     425             :                                                                thisDD.Name,
     426             :                                                                DataLoopNode::NodeFluidType::Air,
     427             :                                                                DataLoopNode::ConnectionType::Inlet,
     428             :                                                                NodeInputManager::CompFluidStream::Primary,
     429             :                                                                DataLoopNode::ObjectIsNotParent,
     430           3 :                                                                cAlphaFields(5));
     431             : 
     432           3 :                 thisDD.MaxAirVolFlowRate = NumArray(1);
     433           3 :                 thisDD.ZoneMinAirFracDes = NumArray(2);
     434             : 
     435             :                 // Register component set data - one for heat and one for cool
     436           3 :                 BranchNodeConnections::TestCompSet(state, CurrentModuleObject + ":HEAT", thisDD.Name, AlphArray(4), AlphArray(3), "Air Nodes");
     437           3 :                 BranchNodeConnections::TestCompSet(state, CurrentModuleObject + ":COOL", thisDD.Name, AlphArray(5), AlphArray(3), "Air Nodes");
     438             : 
     439          12 :                 for (ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) {
     440           9 :                     if (thisDD.OutletNodeNum == state.dataDefineEquipment->AirDistUnit(ADUNum).OutletNodeNum) {
     441           3 :                         state.dataDefineEquipment->AirDistUnit(ADUNum).InletNodeNum = thisDD.ColdAirInletNodeNum;
     442           3 :                         state.dataDefineEquipment->AirDistUnit(ADUNum).InletNodeNum2 = thisDD.HotAirInletNodeNum;
     443           3 :                         thisDD.ADUNum = ADUNum;
     444             :                     }
     445             :                 }
     446             :                 // one assumes if there isn't one assigned, it's an error?
     447           3 :                 if (thisDD.ADUNum == 0) {
     448           0 :                     auto &thisObjType = damperTypeStrings[static_cast<int>(thisDD.DamperType)];
     449           0 :                     ShowSevereError(
     450             :                         state,
     451           0 :                         format("{}No matching List:Zone:AirTerminal for AirTerminal:DualDuct = [{},{}].", RoutineName, thisObjType, thisDD.Name));
     452           0 :                     ShowContinueError(state, format("...should have outlet node={}", state.dataLoopNodes->NodeID(thisDD.OutletNodeNum)));
     453           0 :                     ErrorsFound = true;
     454             :                 } else {
     455             : 
     456             :                     // Fill the Zone Equipment data with the inlet node numbers of this unit.
     457          12 :                     for (int CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) {
     458           9 :                         auto &thisZoneEquipConfig = state.dataZoneEquip->ZoneEquipConfig(CtrlZone);
     459           9 :                         if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) continue;
     460          18 :                         for (SupAirIn = 1; SupAirIn <= thisZoneEquipConfig.NumInletNodes; ++SupAirIn) {
     461           9 :                             if (thisDD.OutletNodeNum == thisZoneEquipConfig.InletNode(SupAirIn)) {
     462           3 :                                 thisZoneEquipConfig.AirDistUnitCool(SupAirIn).InNode = thisDD.ColdAirInletNodeNum;
     463           3 :                                 thisZoneEquipConfig.AirDistUnitHeat(SupAirIn).InNode = thisDD.HotAirInletNodeNum;
     464           3 :                                 thisZoneEquipConfig.AirDistUnitCool(SupAirIn).OutNode = thisDD.OutletNodeNum;
     465           3 :                                 thisZoneEquipConfig.AirDistUnitHeat(SupAirIn).OutNode = thisDD.OutletNodeNum;
     466           3 :                                 state.dataDefineEquipment->AirDistUnit(thisDD.ADUNum).TermUnitSizingNum =
     467           3 :                                     thisZoneEquipConfig.AirDistUnitCool(SupAirIn).TermUnitSizingIndex;
     468           3 :                                 state.dataDefineEquipment->AirDistUnit(thisDD.ADUNum).ZoneEqNum = CtrlZone;
     469             : 
     470           3 :                                 thisDD.CtrlZoneNum = CtrlZone;
     471           3 :                                 thisDD.CtrlZoneInNodeIndex = SupAirIn;
     472             :                             }
     473             :                         }
     474             :                     }
     475             :                 }
     476           3 :                 if (!lAlphaBlanks(6)) {
     477           0 :                     thisDD.OARequirementsPtr = UtilityRoutines::FindItemInList(AlphArray(6), state.dataSize->OARequirements);
     478           0 :                     if (thisDD.OARequirementsPtr == 0) {
     479           0 :                         ShowSevereError(state, cAlphaFields(6) + " = " + AlphArray(6) + " not found.");
     480           0 :                         ShowContinueError(state, format("Occurs in {} = {}", cCMO_DDVariableVolume, thisDD.Name));
     481           0 :                         ErrorsFound = true;
     482             :                     } else {
     483           0 :                         thisDD.NoOAFlowInputFromUser = false;
     484             :                     }
     485             :                 }
     486             : 
     487           3 :                 if (lAlphaBlanks(7)) {
     488           3 :                     thisDD.ZoneTurndownMinAirFrac = 1.0;
     489           3 :                     thisDD.ZoneTurndownMinAirFracSchExist = false;
     490             :                 } else {
     491           0 :                     thisDD.ZoneTurndownMinAirFracSchPtr = ScheduleManager::GetScheduleIndex(state, AlphArray(7));
     492           0 :                     if (thisDD.ZoneTurndownMinAirFracSchPtr == 0) {
     493           0 :                         ShowSevereError(state, format("{} = {} not found.", cAlphaFields(7), AlphArray(7)));
     494           0 :                         ShowContinueError(state, format("Occurs in {} = {}", cCMO_DDVariableVolume, thisDD.Name));
     495           0 :                         ErrorsFound = true;
     496             :                     }
     497           0 :                     thisDD.ZoneTurndownMinAirFracSchExist = true;
     498             :                 }
     499             : 
     500             :                 // Setup the Average damper Position output variable
     501             :                 // CurrentModuleObject='AirTerminal:DualDuct:VAV'
     502           6 :                 SetupOutputVariable(state,
     503             :                                     "Zone Air Terminal Cold Supply Duct Damper Position",
     504             :                                     OutputProcessor::Unit::None,
     505             :                                     thisDD.ColdAirDamperPosition,
     506             :                                     OutputProcessor::SOVTimeStepType::System,
     507             :                                     OutputProcessor::SOVStoreType::Average,
     508           3 :                                     thisDD.Name);
     509           6 :                 SetupOutputVariable(state,
     510             :                                     "Zone Air Terminal Hot Supply Duct Damper Position",
     511             :                                     OutputProcessor::Unit::None,
     512             :                                     thisDD.HotAirDamperPosition,
     513             :                                     OutputProcessor::SOVTimeStepType::System,
     514             :                                     OutputProcessor::SOVStoreType::Average,
     515           3 :                                     thisDD.Name);
     516           6 :                 SetupOutputVariable(state,
     517             :                                     "Zone Air Terminal Outdoor Air Volume Flow Rate",
     518             :                                     OutputProcessor::Unit::m3_s,
     519             :                                     thisDD.OutdoorAirFlowRate,
     520             :                                     OutputProcessor::SOVTimeStepType::System,
     521             :                                     OutputProcessor::SOVStoreType::Average,
     522           3 :                                     thisDD.Name);
     523             :             } // end Number of Damper Loop
     524             :         }
     525             : 
     526           8 :         if (state.dataDualDuct->NumDualDuctVarVolOA > 0) {
     527           1 :             CurrentModuleObject = cCMO_DDVarVolOA;
     528          12 :             for (int DamperIndex = 1; DamperIndex <= state.dataDualDuct->NumDualDuctVarVolOA; ++DamperIndex) {
     529             : 
     530             :                 // Load the info from the damper
     531          11 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
     532             :                                                                          CurrentModuleObject,
     533             :                                                                          DamperIndex,
     534             :                                                                          AlphArray,
     535             :                                                                          NumAlphas,
     536             :                                                                          NumArray,
     537             :                                                                          NumNums,
     538             :                                                                          IOStat,
     539             :                                                                          lNumericBlanks,
     540             :                                                                          lAlphaBlanks,
     541             :                                                                          cAlphaFields,
     542             :                                                                          cNumericFields);
     543             : 
     544             :                 // Anything below this line in this control block should use DDNum
     545          11 :                 int DDNum = DamperIndex + NumDualDuctConstVolDampers + NumDualDuctVarVolDampers;
     546          11 :                 auto &thisDD = state.dataDualDuct->dd_airterminal(DDNum);
     547          22 :                 GlobalNames::VerifyUniqueInterObjectName(
     548          22 :                     state, state.dataDualDuct->UniqueDualDuctAirTerminalNames, AlphArray(1), CurrentModuleObject, cAlphaFields(1), ErrorsFound);
     549          11 :                 thisDD.Name = AlphArray(1);
     550          11 :                 thisDD.DamperType = DualDuctDamper::OutdoorAir;
     551          11 :                 if (lAlphaBlanks(2)) {
     552           0 :                     thisDD.SchedPtr = DataGlobalConstants::ScheduleAlwaysOn;
     553             :                 } else {
     554          11 :                     thisDD.SchedPtr = ScheduleManager::GetScheduleIndex(state, AlphArray(2));
     555          11 :                     if (thisDD.SchedPtr == 0) {
     556           0 :                         ShowSevereError(state,
     557           0 :                                         format("{}, \"{}\" {} = {} not found.", CurrentModuleObject, thisDD.Name, cAlphaFields(2), AlphArray(2)));
     558           0 :                         ErrorsFound = true;
     559             :                     }
     560             :                 }
     561          22 :                 thisDD.OutletNodeNum = GetOnlySingleNode(state,
     562          11 :                                                          AlphArray(3),
     563             :                                                          ErrorsFound,
     564             :                                                          DataLoopNode::ConnectionObjectType::AirTerminalDualDuctVAVOutdoorAir,
     565             :                                                          thisDD.Name,
     566             :                                                          DataLoopNode::NodeFluidType::Air,
     567             :                                                          DataLoopNode::ConnectionType::Outlet,
     568             :                                                          NodeInputManager::CompFluidStream::Primary,
     569             :                                                          DataLoopNode::ObjectIsNotParent,
     570          11 :                                                          cAlphaFields(3));
     571          22 :                 thisDD.OAInletNodeNum = GetOnlySingleNode(state,
     572          11 :                                                           AlphArray(4),
     573             :                                                           ErrorsFound,
     574             :                                                           DataLoopNode::ConnectionObjectType::AirTerminalDualDuctVAVOutdoorAir,
     575             :                                                           thisDD.Name,
     576             :                                                           DataLoopNode::NodeFluidType::Air,
     577             :                                                           DataLoopNode::ConnectionType::Inlet,
     578             :                                                           NodeInputManager::CompFluidStream::Primary,
     579             :                                                           DataLoopNode::ObjectIsNotParent,
     580          11 :                                                           cAlphaFields(4));
     581             : 
     582          11 :                 if (!lAlphaBlanks(5)) {
     583          12 :                     thisDD.RecircAirInletNodeNum = GetOnlySingleNode(state,
     584           6 :                                                                      AlphArray(5),
     585             :                                                                      ErrorsFound,
     586             :                                                                      DataLoopNode::ConnectionObjectType::AirTerminalDualDuctVAVOutdoorAir,
     587             :                                                                      thisDD.Name,
     588             :                                                                      DataLoopNode::NodeFluidType::Air,
     589             :                                                                      DataLoopNode::ConnectionType::Inlet,
     590             :                                                                      NodeInputManager::CompFluidStream::Primary,
     591             :                                                                      DataLoopNode::ObjectIsNotParent,
     592           6 :                                                                      cAlphaFields(5));
     593             :                 } else {
     594             :                     // for this model, we intentionally allow not using the recirc side
     595           5 :                     thisDD.RecircIsUsed = false;
     596             :                 }
     597             : 
     598          11 :                 thisDD.MaxAirVolFlowRate = NumArray(1);
     599          11 :                 thisDD.MaxAirMassFlowRate = thisDD.MaxAirVolFlowRate * state.dataEnvrn->StdRhoAir;
     600             : 
     601             :                 // Register component set data - one for OA and one for RA
     602          11 :                 BranchNodeConnections::TestCompSet(state, CurrentModuleObject + ":OutdoorAir", thisDD.Name, AlphArray(4), AlphArray(3), "Air Nodes");
     603          11 :                 if (thisDD.RecircIsUsed) {
     604          24 :                     BranchNodeConnections::TestCompSet(
     605          18 :                         state, CurrentModuleObject + ":RecirculatedAir", thisDD.Name, AlphArray(5), AlphArray(3), "Air Nodes");
     606             :                 }
     607             : 
     608          11 :                 thisDD.OAPerPersonMode = static_cast<PerPersonMode>(getEnumerationValue(modeStrings, AlphArray(7)));
     609          11 :                 if (thisDD.OAPerPersonMode == PerPersonMode::Invalid) {
     610           4 :                     thisDD.OAPerPersonMode = PerPersonMode::ModeNotSet;
     611             :                 }
     612             :                 // checks on this are done later
     613             : 
     614         132 :                 for (ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) {
     615         121 :                     if (thisDD.OutletNodeNum == state.dataDefineEquipment->AirDistUnit(ADUNum).OutletNodeNum) {
     616          11 :                         state.dataDefineEquipment->AirDistUnit(ADUNum).InletNodeNum = thisDD.OAInletNodeNum;
     617          11 :                         state.dataDefineEquipment->AirDistUnit(ADUNum).InletNodeNum2 = thisDD.RecircAirInletNodeNum;
     618          11 :                         thisDD.ADUNum = ADUNum;
     619             :                     }
     620             :                 }
     621             :                 // one assumes if there isn't one assigned, it's an error?
     622          11 :                 if (thisDD.ADUNum == 0) {
     623           0 :                     auto &thisObjType = damperTypeStrings[static_cast<int>(thisDD.DamperType)];
     624           0 :                     ShowSevereError(
     625             :                         state,
     626           0 :                         format("{}No matching List:Zone:AirTerminal for AirTerminal:DualDuct = [{},{}].", RoutineName, thisObjType, thisDD.Name));
     627           0 :                     ShowContinueError(state, format("...should have outlet node={}", state.dataLoopNodes->NodeID(thisDD.OutletNodeNum)));
     628           0 :                     ErrorsFound = true;
     629             :                 } else {
     630             : 
     631             :                     // Fill the Zone Equipment data with the inlet node numbers of this unit.
     632         132 :                     for (int CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) {
     633         121 :                         auto &thisZoneEquipConfig = state.dataZoneEquip->ZoneEquipConfig(CtrlZone);
     634         121 :                         if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) continue;
     635         297 :                         for (SupAirIn = 1; SupAirIn <= thisZoneEquipConfig.NumInletNodes; ++SupAirIn) {
     636         176 :                             if (thisDD.OutletNodeNum == thisZoneEquipConfig.InletNode(SupAirIn)) {
     637          11 :                                 if (thisDD.RecircIsUsed) {
     638           6 :                                     thisZoneEquipConfig.AirDistUnitCool(SupAirIn).InNode = thisDD.RecircAirInletNodeNum;
     639             :                                 } else {
     640           5 :                                     thisZoneEquipConfig.AirDistUnitCool(SupAirIn).InNode = thisDD.OAInletNodeNum;
     641             :                                 }
     642          11 :                                 thisZoneEquipConfig.AirDistUnitHeat(SupAirIn).InNode = thisDD.OAInletNodeNum;
     643          11 :                                 thisZoneEquipConfig.AirDistUnitCool(SupAirIn).OutNode = thisDD.OutletNodeNum;
     644          11 :                                 thisZoneEquipConfig.AirDistUnitHeat(SupAirIn).OutNode = thisDD.OutletNodeNum;
     645          11 :                                 state.dataDefineEquipment->AirDistUnit(thisDD.ADUNum).TermUnitSizingNum =
     646          11 :                                     thisZoneEquipConfig.AirDistUnitCool(SupAirIn).TermUnitSizingIndex;
     647          11 :                                 state.dataDefineEquipment->AirDistUnit(thisDD.ADUNum).ZoneEqNum = CtrlZone;
     648             : 
     649          11 :                                 thisDD.CtrlZoneNum = CtrlZone;
     650          11 :                                 thisDD.CtrlZoneInNodeIndex = SupAirIn;
     651             :                             }
     652             :                         }
     653             :                     }
     654             :                 }
     655          11 :                 thisDD.OARequirementsPtr = UtilityRoutines::FindItemInList(AlphArray(6), state.dataSize->OARequirements);
     656          11 :                 if (thisDD.OARequirementsPtr == 0) {
     657           0 :                     ShowSevereError(state, format("{} = {} not found.", cAlphaFields(6), AlphArray(6)));
     658           0 :                     ShowContinueError(state, format("Occurs in {} = {}", cCMO_DDVarVolOA, thisDD.Name));
     659           0 :                     ErrorsFound = true;
     660             :                 } else {
     661          11 :                     thisDD.NoOAFlowInputFromUser = false;
     662             : 
     663             :                     // now fill design OA rate
     664          11 :                     thisDD.CalcOAOnlyMassFlow(state, DummyOAFlow, thisDD.DesignOAFlowRate);
     665             : 
     666          11 :                     if (thisDD.MaxAirVolFlowRate != DataSizing::AutoSize) {
     667           0 :                         BaseSizer::reportSizerOutput(
     668           0 :                             state, CurrentModuleObject, thisDD.Name, "Maximum Outdoor Air Flow Rate [m3/s]", thisDD.DesignOAFlowRate);
     669             : 
     670           0 :                         if (thisDD.RecircIsUsed) {
     671           0 :                             thisDD.DesignRecircFlowRate = thisDD.MaxAirVolFlowRate - thisDD.DesignOAFlowRate;
     672           0 :                             thisDD.DesignRecircFlowRate = max(0.0, thisDD.DesignRecircFlowRate);
     673           0 :                             BaseSizer::reportSizerOutput(
     674           0 :                                 state, CurrentModuleObject, thisDD.Name, "Maximum Recirculated Air Flow Rate [m3/s]", thisDD.DesignRecircFlowRate);
     675             :                         } else {
     676           0 :                             if (thisDD.MaxAirVolFlowRate < thisDD.DesignOAFlowRate) {
     677           0 :                                 ShowSevereError(state,
     678           0 :                                                 format("The value {:.5R} in {}is lower than the outdoor air requirement.",
     679             :                                                        thisDD.MaxAirVolFlowRate,
     680           0 :                                                        cNumericFields(1)));
     681           0 :                                 ShowContinueError(state, format("Occurs in {} = {}", cCMO_DDVarVolOA, thisDD.Name));
     682           0 :                                 ShowContinueError(state, format("The design outdoor air requirement is {:.5R}", thisDD.DesignOAFlowRate));
     683           0 :                                 ErrorsFound = true;
     684             :                             }
     685             :                         }
     686             :                     }
     687             :                 }
     688             : 
     689          11 :                 if (thisDD.OAPerPersonMode == PerPersonMode::ModeNotSet) {
     690           4 :                     DummyOAFlow = state.dataSize->OARequirements(thisDD.OARequirementsPtr).OAFlowPerPerson;
     691           4 :                     if ((DummyOAFlow == 0.0) && (lAlphaBlanks(7))) {       // no worries
     692             :                                                                            // do nothing, okay since no per person requirement involved
     693           0 :                     } else if ((DummyOAFlow > 0.0) && (lAlphaBlanks(7))) { // missing input
     694           0 :                         ShowSevereError(state, cAlphaFields(7) + " was blank.");
     695           0 :                         ShowContinueError(state, format("Occurs in {} = {}", cCMO_DDVarVolOA, thisDD.Name));
     696           0 :                         ShowContinueError(state, R"(Valid choices are "CurrentOccupancy" or "DesignOccupancy")");
     697           0 :                         ErrorsFound = true;
     698           0 :                     } else if ((DummyOAFlow > 0.0) && !(lAlphaBlanks(7))) { // incorrect input
     699           0 :                         ShowSevereError(state, cAlphaFields(7) + " = " + AlphArray(7) + " not a valid key choice.");
     700           0 :                         ShowContinueError(state, format("Occurs in {} = {}", cCMO_DDVarVolOA, thisDD.Name));
     701           0 :                         ShowContinueError(state, R"(Valid choices are "CurrentOccupancy" or "DesignOccupancy")");
     702           0 :                         ErrorsFound = true;
     703             :                     }
     704             :                 }
     705             : 
     706             :                 // Setup the Average damper Position output variable
     707          22 :                 SetupOutputVariable(state,
     708             :                                     "Zone Air Terminal Outdoor Air Duct Damper Position",
     709             :                                     OutputProcessor::Unit::None,
     710             :                                     thisDD.OADamperPosition,
     711             :                                     OutputProcessor::SOVTimeStepType::System,
     712             :                                     OutputProcessor::SOVStoreType::Average,
     713          11 :                                     thisDD.Name);
     714          22 :                 SetupOutputVariable(state,
     715             :                                     "Zone Air Terminal Recirculated Air Duct Damper Position",
     716             :                                     OutputProcessor::Unit::None,
     717             :                                     thisDD.RecircAirDamperPosition,
     718             :                                     OutputProcessor::SOVTimeStepType::System,
     719             :                                     OutputProcessor::SOVStoreType::Average,
     720          11 :                                     thisDD.Name);
     721          22 :                 SetupOutputVariable(state,
     722             :                                     "Zone Air Terminal Outdoor Air Fraction",
     723             :                                     OutputProcessor::Unit::None,
     724             :                                     thisDD.OAFraction,
     725             :                                     OutputProcessor::SOVTimeStepType::System,
     726             :                                     OutputProcessor::SOVStoreType::Average,
     727          11 :                                     thisDD.Name);
     728             : 
     729             :             } // end Number of Damper Loop
     730             :         }
     731             : 
     732           8 :         if (ErrorsFound) {
     733           0 :             ShowFatalError(state, std::string{RoutineName} + "Errors found in input.  Preceding condition(s) cause termination.");
     734             :         }
     735           8 :     }
     736             : 
     737      206846 :     void DualDuctAirTerminal::InitDualDuct(EnergyPlusData &state, bool const FirstHVACIteration)
     738             :     {
     739             : 
     740             :         // SUBROUTINE INFORMATION:
     741             :         //       AUTHOR         Richard J. Liesen
     742             :         //       DATE WRITTEN   February 1998
     743             :         //       MODIFIED       na
     744             :         //       RE-ENGINEERED  na
     745             : 
     746             :         // PURPOSE OF THIS SUBROUTINE:
     747             :         // This subroutine is for  initializations of the Damper Components.
     748             : 
     749             :         // METHODOLOGY EMPLOYED:
     750             :         // Uses the status flags to trigger events.
     751             : 
     752             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     753             :         int HotInNode;
     754             :         int ColdInNode;
     755             :         int OAInNode; // Outdoor Air Inlet Node for VAV:OutdoorAir units
     756             :         int RAInNode; // Reciruclated Air Inlet Node for VAV:OutdoorAir units
     757             :         int OutNode;
     758             :         int Loop;          // Loop checking control variable
     759             :         Real64 PeopleFlow; // local sum variable, m3/s
     760             : 
     761      206846 :         if (!state.dataDualDuct->ZoneEquipmentListChecked && state.dataZoneEquip->ZoneEquipInputsFilled) {
     762           8 :             state.dataDualDuct->ZoneEquipmentListChecked = true;
     763             :             // Check to see if there is a Air Distribution Unit on the Zone Equipment List
     764          42 :             for (Loop = 1; Loop <= state.dataDualDuct->NumDDAirTerminal; ++Loop) {
     765          34 :                 if (this->ADUNum == 0) continue;
     766         102 :                 if (DataZoneEquipment::CheckZoneEquipmentList(
     767          68 :                         state, "ZONEHVAC:AIRDISTRIBUTIONUNIT", state.dataDefineEquipment->AirDistUnit(this->ADUNum).Name))
     768          34 :                     continue;
     769           0 :                 ShowSevereError(state,
     770           0 :                                 "InitDualDuct: ADU=[Air Distribution Unit," + state.dataDefineEquipment->AirDistUnit(this->ADUNum).Name +
     771             :                                     "] is not on any ZoneHVAC:EquipmentList.");
     772           0 :                 if (this->DamperType == DualDuctDamper::ConstantVolume) {
     773           0 :                     ShowContinueError(state, format("...Dual Duct Damper=[{},{}] will not be simulated.", cCMO_DDConstantVolume, this->Name));
     774           0 :                 } else if (this->DamperType == DualDuctDamper::VariableVolume) {
     775           0 :                     ShowContinueError(state, format("...Dual Duct Damper=[{},{}] will not be simulated.", cCMO_DDVariableVolume, this->Name));
     776           0 :                 } else if (this->DamperType == DualDuctDamper::OutdoorAir) {
     777           0 :                     ShowContinueError(state, format("...Dual Duct Damper=[{},{}] will not be simulated.", cCMO_DDVarVolOA, this->Name));
     778             :                 } else {
     779           0 :                     ShowContinueError(state, "...Dual Duct Damper=[unknown/invalid," + this->Name + "] will not be simulated.");
     780             :                 }
     781             :             }
     782             :         }
     783             : 
     784      206846 :         if (!state.dataGlobal->SysSizingCalc && this->MySizeFlag) {
     785          34 :             this->SizeDualDuct(state);
     786          34 :             this->MySizeFlag = false;
     787             :         }
     788             : 
     789             :         // Do the Begin Environment initializations
     790      206846 :         if (state.dataGlobal->BeginEnvrnFlag && this->MyEnvrnFlag) {
     791             : 
     792         238 :             if (this->DamperType == DualDuctDamper::ConstantVolume || this->DamperType == DualDuctDamper::VariableVolume) {
     793         150 :                 OutNode = this->OutletNodeNum;
     794         150 :                 HotInNode = this->HotAirInletNodeNum;
     795         150 :                 ColdInNode = this->ColdAirInletNodeNum;
     796         150 :                 state.dataLoopNodes->Node(OutNode).MassFlowRateMax = this->MaxAirVolFlowRate * state.dataEnvrn->StdRhoAir;
     797         150 :                 if (this->DamperType == DualDuctDamper::ConstantVolume) {
     798         132 :                     state.dataLoopNodes->Node(OutNode).MassFlowRateMin = 0.0;
     799          18 :                 } else if (this->DamperType == DualDuctDamper::VariableVolume) {
     800             :                     // get dual duct air terminal box minimum flow fraction value
     801          18 :                     if (this->ZoneTurndownMinAirFracSchExist) {
     802           0 :                         this->ZoneTurndownMinAirFrac = ScheduleManager::GetScheduleMinValue(state, this->ZoneTurndownMinAirFracSchPtr);
     803             :                     } else {
     804          18 :                         this->ZoneTurndownMinAirFrac = 1.0;
     805             :                     }
     806          18 :                     state.dataLoopNodes->Node(OutNode).MassFlowRateMin =
     807          18 :                         state.dataLoopNodes->Node(OutNode).MassFlowRateMax * this->ZoneMinAirFracDes * this->ZoneTurndownMinAirFrac;
     808             :                 } else {
     809           0 :                     state.dataLoopNodes->Node(OutNode).MassFlowRateMin = 0.0;
     810             :                 }
     811         150 :                 this->dd_airterminalHotAirInlet.AirMassFlowRateMax = state.dataLoopNodes->Node(OutNode).MassFlowRateMax;
     812         150 :                 this->dd_airterminalColdAirInlet.AirMassFlowRateMax = state.dataLoopNodes->Node(OutNode).MassFlowRateMax;
     813         150 :                 state.dataLoopNodes->Node(HotInNode).MassFlowRateMax = state.dataLoopNodes->Node(OutNode).MassFlowRateMax;
     814         150 :                 state.dataLoopNodes->Node(ColdInNode).MassFlowRateMax = state.dataLoopNodes->Node(OutNode).MassFlowRateMax;
     815         150 :                 state.dataLoopNodes->Node(HotInNode).MassFlowRateMin = 0.0;
     816         150 :                 state.dataLoopNodes->Node(ColdInNode).MassFlowRateMin = 0.0;
     817         150 :                 this->MyEnvrnFlag = false;
     818             : 
     819          88 :             } else if (this->DamperType == DualDuctDamper::OutdoorAir) {
     820             :                 // Initialize for DualDuct:VAV:OutdoorAir
     821          88 :                 OutNode = this->OutletNodeNum;
     822          88 :                 OAInNode = this->OAInletNodeNum;
     823          88 :                 if (this->RecircIsUsed) RAInNode = this->RecircAirInletNodeNum;
     824          88 :                 state.dataLoopNodes->Node(OutNode).MassFlowRateMax = this->MaxAirMassFlowRate;
     825          88 :                 state.dataLoopNodes->Node(OutNode).MassFlowRateMin = 0.0;
     826          88 :                 this->dd_airterminalOAInlet.AirMassFlowRateMax = this->DesignOAFlowRate * state.dataEnvrn->StdRhoAir;
     827          88 :                 if (this->RecircIsUsed) {
     828          48 :                     this->dd_airterminalRecircAirInlet.AirMassFlowRateMax = this->MaxAirMassFlowRate - this->dd_airterminalOAInlet.AirMassFlowRateMax;
     829          48 :                     state.dataLoopNodes->Node(RAInNode).MassFlowRateMax = this->dd_airterminalRecircAirInlet.AirMassFlowRateMax;
     830          48 :                     state.dataLoopNodes->Node(RAInNode).MassFlowRateMin = 0.0;
     831          48 :                     this->dd_airterminalRecircAirInlet.AirMassFlowDiffMag = 1.0e-10 * this->dd_airterminalRecircAirInlet.AirMassFlowRateMax;
     832             :                 }
     833          88 :                 state.dataLoopNodes->Node(OAInNode).MassFlowRateMax = this->dd_airterminalOAInlet.AirMassFlowRateMax;
     834          88 :                 state.dataLoopNodes->Node(OAInNode).MassFlowRateMin = 0.0;
     835             :                 // figure per person by design level for the OA duct.
     836          88 :                 PeopleFlow = 0.0;
     837         616 :                 for (Loop = 1; Loop <= state.dataHeatBal->TotPeople; ++Loop) {
     838         528 :                     if (state.dataHeatBal->People(Loop).ZonePtr != this->CtrlZoneNum) continue;
     839          48 :                     DataSizing::OAFlowCalcMethod damperOAFlowMethod = state.dataSize->OARequirements(this->OARequirementsPtr).OAFlowMethod;
     840          48 :                     if (damperOAFlowMethod == DataSizing::OAFlowCalcMethod::PerPerson || damperOAFlowMethod == DataSizing::OAFlowCalcMethod::Sum ||
     841             :                         damperOAFlowMethod == DataSizing::OAFlowCalcMethod::Max) {
     842          48 :                         PeopleFlow +=
     843          48 :                             state.dataHeatBal->People(Loop).NumberOfPeople * state.dataSize->OARequirements(this->OARequirementsPtr).OAFlowPerPerson;
     844             :                     }
     845             :                 }
     846          88 :                 this->MyEnvrnFlag = false;
     847             :             }
     848             :         }
     849             : 
     850      206846 :         if (!state.dataGlobal->BeginEnvrnFlag) {
     851      204966 :             this->MyEnvrnFlag = true;
     852             :         }
     853             : 
     854             :         // Find air loop associated with this terminal unit
     855      206846 :         if (this->MyAirLoopFlag) {
     856         102 :             if (this->AirLoopNum == 0) {
     857          68 :                 if ((this->CtrlZoneNum > 0) && (this->CtrlZoneInNodeIndex > 0)) {
     858          68 :                     this->AirLoopNum = state.dataZoneEquip->ZoneEquipConfig(this->CtrlZoneNum).InletNodeAirLoopNum(this->CtrlZoneInNodeIndex);
     859          68 :                     state.dataDefineEquipment->AirDistUnit(this->ADUNum).AirLoopNum = this->AirLoopNum;
     860             :                     // Don't set MyAirLoopFlag to false yet because airloopnums might not be populated yet
     861             :                 }
     862             :             } else {
     863          34 :                 this->MyAirLoopFlag = false;
     864             :             }
     865             :         }
     866             : 
     867             :         // Initialize the Inlet Nodes of the Sys
     868      206846 :         if (this->DamperType == DualDuctDamper::ConstantVolume || this->DamperType == DualDuctDamper::VariableVolume) {
     869      139218 :             HotInNode = this->HotAirInletNodeNum;
     870      139218 :             ColdInNode = this->ColdAirInletNodeNum;
     871      139218 :             OutNode = this->OutletNodeNum;
     872       67628 :         } else if (this->DamperType == DualDuctDamper::OutdoorAir) {
     873       67628 :             OAInNode = this->OAInletNodeNum;
     874       67628 :             if (this->RecircIsUsed) RAInNode = this->RecircAirInletNodeNum;
     875       67628 :             OutNode = this->OutletNodeNum;
     876             :         }
     877             : 
     878      206846 :         if (FirstHVACIteration) {
     879             :             //     CALL DisplayString('Init First HVAC Iteration {'//TRIM(  dd_airterminal(DDNum)%DamperName)//'}') !-For debugging - REMOVE
     880             :             // The first time through set the mass flow rate to the Max
     881             :             // Take care of the flow rates first. For Const Vol and VAV.
     882       98800 :             if (this->DamperType == DualDuctDamper::ConstantVolume || this->DamperType == DualDuctDamper::VariableVolume) {
     883       65063 :                 auto &thisHotInNode = state.dataLoopNodes->Node(HotInNode);
     884       65063 :                 auto &thisColdInNode = state.dataLoopNodes->Node(ColdInNode);
     885       65063 :                 Real64 schedValue = ScheduleManager::GetCurrentScheduleValue(state, this->SchedPtr);
     886       65063 :                 if ((thisHotInNode.MassFlowRate > 0.0) && (schedValue > 0.0)) {
     887       49712 :                     thisHotInNode.MassFlowRate = this->dd_airterminalHotAirInlet.AirMassFlowRateMax;
     888             :                 } else {
     889       15351 :                     thisHotInNode.MassFlowRate = 0.0;
     890             :                 }
     891       65063 :                 if ((thisColdInNode.MassFlowRate > 0.0) && (schedValue > 0.0)) {
     892       49707 :                     thisColdInNode.MassFlowRate = this->dd_airterminalColdAirInlet.AirMassFlowRateMax;
     893             :                 } else {
     894       15356 :                     thisColdInNode.MassFlowRate = 0.0;
     895             :                 }
     896             :                 // Next take care of the Max Avail Flow Rates
     897       65063 :                 if ((thisHotInNode.MassFlowRateMaxAvail > 0.0) && (schedValue > 0.0)) {
     898       49712 :                     thisHotInNode.MassFlowRateMaxAvail = this->dd_airterminalHotAirInlet.AirMassFlowRateMax;
     899             :                 } else {
     900       15351 :                     thisHotInNode.MassFlowRateMaxAvail = 0.0;
     901             :                 }
     902       65063 :                 if ((thisColdInNode.MassFlowRateMaxAvail > 0.0) && (schedValue > 0.0)) {
     903       49707 :                     thisColdInNode.MassFlowRateMaxAvail = this->dd_airterminalColdAirInlet.AirMassFlowRateMax;
     904             :                 } else {
     905       15356 :                     thisColdInNode.MassFlowRateMaxAvail = 0.0;
     906             :                 }
     907             :                 // get current time step air terminal box turndown minimum flow fraction
     908       65063 :                 if (this->ZoneTurndownMinAirFracSchExist) {
     909           0 :                     this->ZoneTurndownMinAirFrac = ScheduleManager::GetCurrentScheduleValue(state, this->ZoneTurndownMinAirFracSchPtr);
     910             :                 } else {
     911       65063 :                     this->ZoneTurndownMinAirFrac = 1.0;
     912             :                 }
     913             :                 // update to the current dual duct minimum air flow fraction
     914       65063 :                 this->ZoneMinAirFrac = this->ZoneMinAirFracDes * this->ZoneTurndownMinAirFrac;
     915             :                 // The last item is to take care of the Min Avail Flow Rates
     916       65063 :                 if ((thisHotInNode.MassFlowRate > 0.0) && (schedValue > 0.0)) {
     917       49712 :                     thisHotInNode.MassFlowRateMinAvail = this->dd_airterminalHotAirInlet.AirMassFlowRateMax * this->ZoneMinAirFrac;
     918             :                 } else {
     919       15351 :                     thisHotInNode.MassFlowRateMinAvail = 0.0;
     920             :                 }
     921       65063 :                 if ((thisColdInNode.MassFlowRate > 0.0) && (schedValue > 0.0)) {
     922       49707 :                     thisColdInNode.MassFlowRateMinAvail = this->dd_airterminalColdAirInlet.AirMassFlowRateMax * this->ZoneMinAirFrac;
     923             :                 } else {
     924       15356 :                     thisColdInNode.MassFlowRateMinAvail = 0.0;
     925       65063 :                 }
     926             : 
     927       33737 :             } else if (this->DamperType == DualDuctDamper::OutdoorAir) {
     928       33737 :                 auto &thisOAInNode = state.dataLoopNodes->Node(OAInNode);
     929       33737 :                 Real64 schedValue = ScheduleManager::GetCurrentScheduleValue(state, this->SchedPtr);
     930             :                 // The first time through set the mass flow rate to the Max for VAV:OutdoorAir
     931       33737 :                 if ((thisOAInNode.MassFlowRate > 0.0) && (schedValue > 0.0)) {
     932       33630 :                     thisOAInNode.MassFlowRate = this->dd_airterminalOAInlet.AirMassFlowRateMax;
     933             :                 } else {
     934         107 :                     thisOAInNode.MassFlowRate = 0.0;
     935             :                 }
     936       33737 :                 if (this->RecircIsUsed) {
     937       18402 :                     auto &thisRAInNode = state.dataLoopNodes->Node(RAInNode);
     938       18402 :                     if ((thisRAInNode.MassFlowRate > 0.0) && (schedValue > 0.0)) {
     939       18354 :                         thisRAInNode.MassFlowRate = this->dd_airterminalRecircAirInlet.AirMassFlowRateMax;
     940             :                     } else {
     941          48 :                         thisRAInNode.MassFlowRate = 0.0;
     942             :                     }
     943             :                     // clear flow history
     944       18402 :                     this->dd_airterminalRecircAirInlet.AirMassFlowRateHist1 = 0.0;
     945       18402 :                     this->dd_airterminalRecircAirInlet.AirMassFlowRateHist2 = 0.0;
     946       18402 :                     this->dd_airterminalRecircAirInlet.AirMassFlowRateHist3 = 0.0;
     947             :                 }
     948             :                 // Next take care of the Max Avail Flow Rates
     949       33737 :                 if ((thisOAInNode.MassFlowRateMaxAvail > 0.0) && (schedValue > 0.0)) {
     950       33630 :                     thisOAInNode.MassFlowRateMaxAvail = this->dd_airterminalOAInlet.AirMassFlowRateMax;
     951             :                 } else {
     952         107 :                     thisOAInNode.MassFlowRateMaxAvail = 0.0;
     953             :                 }
     954       33737 :                 if (this->RecircIsUsed) {
     955       18402 :                     auto &thisRAInNode = state.dataLoopNodes->Node(RAInNode);
     956       18402 :                     if ((thisRAInNode.MassFlowRateMaxAvail > 0.0) && (schedValue > 0.0)) {
     957       18354 :                         thisRAInNode.MassFlowRateMaxAvail = this->dd_airterminalRecircAirInlet.AirMassFlowRateMax;
     958             :                     } else {
     959          48 :                         thisRAInNode.MassFlowRateMaxAvail = 0.0;
     960             :                     }
     961             :                 }
     962             :                 // The last item is to take care of the Min Avail Flow Rates. VAV:OutdoorAir
     963       33737 :                 thisOAInNode.MassFlowRateMinAvail = 0.0;
     964       33737 :                 if (this->RecircIsUsed) {
     965       18402 :                     auto &thisRAInNode = state.dataLoopNodes->Node(RAInNode);
     966       18402 :                     thisRAInNode.MassFlowRateMinAvail = 0.0;
     967             :                 }
     968             :             }
     969             :         }
     970             : 
     971             :         // Initialize the Inlet Nodes of the Dampers for Const. Vol and VAV
     972      206846 :         if (this->DamperType == DualDuctDamper::ConstantVolume || this->DamperType == DualDuctDamper::VariableVolume) {
     973             : 
     974      139218 :             this->dd_airterminalHotAirInlet.AirMassFlowRateMaxAvail =
     975      139218 :                 min(state.dataLoopNodes->Node(OutNode).MassFlowRateMax, state.dataLoopNodes->Node(HotInNode).MassFlowRateMaxAvail);
     976      139218 :             this->dd_airterminalHotAirInlet.AirMassFlowRateMinAvail =
     977      139218 :                 min(max(state.dataLoopNodes->Node(OutNode).MassFlowRateMin, state.dataLoopNodes->Node(HotInNode).MassFlowRateMinAvail),
     978      139218 :                     state.dataLoopNodes->Node(HotInNode).MassFlowRateMaxAvail);
     979             : 
     980      139218 :             this->dd_airterminalColdAirInlet.AirMassFlowRateMaxAvail =
     981      139218 :                 min(state.dataLoopNodes->Node(OutNode).MassFlowRateMax, state.dataLoopNodes->Node(ColdInNode).MassFlowRateMaxAvail);
     982      139218 :             this->dd_airterminalColdAirInlet.AirMassFlowRateMinAvail =
     983      139218 :                 min(max(state.dataLoopNodes->Node(OutNode).MassFlowRateMin, state.dataLoopNodes->Node(ColdInNode).MassFlowRateMinAvail),
     984      139218 :                     state.dataLoopNodes->Node(ColdInNode).MassFlowRateMaxAvail);
     985             : 
     986             :             // Do the following initializations (every time step): This should be the info from
     987             :             // the previous components outlets or the node data in this section.
     988             :             // Load the node data in this section for the component simulation
     989      139218 :             this->dd_airterminalHotAirInlet.AirMassFlowRate = state.dataLoopNodes->Node(HotInNode).MassFlowRate;
     990      139218 :             this->dd_airterminalHotAirInlet.AirTemp = state.dataLoopNodes->Node(HotInNode).Temp;
     991      139218 :             this->dd_airterminalHotAirInlet.AirHumRat = state.dataLoopNodes->Node(HotInNode).HumRat;
     992      139218 :             this->dd_airterminalHotAirInlet.AirEnthalpy = state.dataLoopNodes->Node(HotInNode).Enthalpy;
     993      139218 :             this->dd_airterminalColdAirInlet.AirMassFlowRate = state.dataLoopNodes->Node(ColdInNode).MassFlowRate;
     994      139218 :             this->dd_airterminalColdAirInlet.AirTemp = state.dataLoopNodes->Node(ColdInNode).Temp;
     995      139218 :             this->dd_airterminalColdAirInlet.AirHumRat = state.dataLoopNodes->Node(ColdInNode).HumRat;
     996      139218 :             this->dd_airterminalColdAirInlet.AirEnthalpy = state.dataLoopNodes->Node(ColdInNode).Enthalpy;
     997             : 
     998             :             // Initialize the Inlet Nodes of the Dampers for VAV:OutdoorAir
     999       67628 :         } else if (this->DamperType == DualDuctDamper::OutdoorAir) {
    1000       67628 :             this->dd_airterminalOAInlet.AirMassFlowRateMaxAvail = state.dataLoopNodes->Node(OAInNode).MassFlowRateMaxAvail;
    1001       67628 :             this->dd_airterminalOAInlet.AirMassFlowRateMinAvail = state.dataLoopNodes->Node(OAInNode).MassFlowRateMinAvail;
    1002             : 
    1003             :             // Do the following initializations (every time step): This should be the info from
    1004             :             // the previous components outlets or the node data in this section.
    1005             :             // Load the node data in this section for the component simulation
    1006       67628 :             this->dd_airterminalOAInlet.AirMassFlowRate = state.dataLoopNodes->Node(OAInNode).MassFlowRate;
    1007       67628 :             this->dd_airterminalOAInlet.AirTemp = state.dataLoopNodes->Node(OAInNode).Temp;
    1008       67628 :             this->dd_airterminalOAInlet.AirHumRat = state.dataLoopNodes->Node(OAInNode).HumRat;
    1009       67628 :             this->dd_airterminalOAInlet.AirEnthalpy = state.dataLoopNodes->Node(OAInNode).Enthalpy;
    1010       67628 :             if (this->RecircIsUsed) {
    1011       36888 :                 this->dd_airterminalRecircAirInlet.AirMassFlowRateMaxAvail = state.dataLoopNodes->Node(RAInNode).MassFlowRateMaxAvail;
    1012       36888 :                 this->dd_airterminalRecircAirInlet.AirMassFlowRateMinAvail = state.dataLoopNodes->Node(RAInNode).MassFlowRateMinAvail;
    1013       36888 :                 this->dd_airterminalRecircAirInlet.AirMassFlowRate = state.dataLoopNodes->Node(RAInNode).MassFlowRate;
    1014       36888 :                 this->dd_airterminalRecircAirInlet.AirTemp = state.dataLoopNodes->Node(RAInNode).Temp;
    1015       36888 :                 this->dd_airterminalRecircAirInlet.AirHumRat = state.dataLoopNodes->Node(RAInNode).HumRat;
    1016       36888 :                 this->dd_airterminalRecircAirInlet.AirEnthalpy = state.dataLoopNodes->Node(RAInNode).Enthalpy;
    1017             :             }
    1018             :         }
    1019      206846 :     }
    1020             : 
    1021          34 :     void DualDuctAirTerminal::SizeDualDuct(EnergyPlusData &state)
    1022             :     {
    1023             : 
    1024             :         // SUBROUTINE INFORMATION:
    1025             :         //       AUTHOR         Fred Buhl
    1026             :         //       DATE WRITTEN   January 2002
    1027             :         //       MODIFIED       na
    1028             :         //       RE-ENGINEERED  na
    1029             : 
    1030             :         // PURPOSE OF THIS SUBROUTINE:
    1031             :         // This subroutine is for sizing Dual Duct air terminal units for which flow rates have not been
    1032             :         // specified in the input.
    1033             : 
    1034             :         // METHODOLOGY EMPLOYED:
    1035             :         // Obtains flow rates from the zone or system sizing arrays.
    1036             : 
    1037          34 :         if (this->MaxAirVolFlowRate == DataSizing::AutoSize) {
    1038             : 
    1039          19 :             if ((state.dataSize->CurZoneEqNum > 0) && (state.dataSize->CurTermUnitSizingNum > 0)) {
    1040          19 :                 std::string_view damperType = cmoNameArray[static_cast<int>(this->DamperType)];
    1041             :                 // ideally we'd just use a string_view, but there are multiple calls that are not yet set up for string_view, and they pass a
    1042             :                 //  reference, so we just create a string version for now.  When we do more string_view cleanup, we'll end up searching on
    1043             :                 //  std::string() to find usages of it, so this should show up and get cleaned up then.  Regardless, this is only called at
    1044             :                 //  program initialization, so it is not a runtime issue.
    1045          38 :                 std::string damperTypeAsString = std::string(damperType);
    1046          19 :                 CheckZoneSizing(state, damperTypeAsString, this->Name);
    1047          19 :                 this->MaxAirVolFlowRate = max(state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesCoolVolFlow,
    1048          19 :                                               state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlow);
    1049          19 :                 if (this->DamperType == DualDuctDamper::OutdoorAir) {
    1050          11 :                     if (this->RecircIsUsed) {
    1051           6 :                         this->DesignRecircFlowRate =
    1052           6 :                             max(state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesCoolVolFlow,
    1053           6 :                                 state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlow);
    1054           6 :                         this->MaxAirVolFlowRate = this->DesignRecircFlowRate + this->DesignOAFlowRate;
    1055             :                     } else {
    1056           5 :                         this->MaxAirVolFlowRate = this->DesignOAFlowRate;
    1057           5 :                         this->DesignRecircFlowRate = 0.0;
    1058             :                     }
    1059          11 :                     this->MaxAirMassFlowRate = this->MaxAirVolFlowRate * state.dataEnvrn->StdRhoAir;
    1060             :                 }
    1061             : 
    1062          19 :                 if (this->MaxAirVolFlowRate < DataHVACGlobals::SmallAirVolFlow) {
    1063           0 :                     this->MaxAirVolFlowRate = 0.0;
    1064           0 :                     this->MaxAirMassFlowRate = 0.0;
    1065           0 :                     this->DesignOAFlowRate = 0.0;
    1066           0 :                     this->DesignRecircFlowRate = 0.0;
    1067             :                 }
    1068          19 :                 BaseSizer::reportSizerOutput(state, damperTypeAsString, this->Name, "Maximum Air Flow Rate [m3/s]", this->MaxAirVolFlowRate);
    1069          19 :                 if (this->DamperType == DualDuctDamper::OutdoorAir) {
    1070          22 :                     BaseSizer::reportSizerOutput(
    1071          11 :                         state, damperTypeAsString, this->Name, "Maximum Outdoor Air Flow Rate [m3/s]", this->DesignOAFlowRate);
    1072          11 :                     if (this->RecircIsUsed) {
    1073          12 :                         BaseSizer::reportSizerOutput(
    1074           6 :                             state, damperTypeAsString, this->Name, "Maximum Recirculated Air Flow Rate [m3/s]", this->DesignRecircFlowRate);
    1075             :                     }
    1076             :                 }
    1077             :             }
    1078             :         }
    1079          34 :     }
    1080             : 
    1081      122805 :     void DualDuctAirTerminal::SimDualDuctConstVol(EnergyPlusData &state, int const ZoneNum, int const ZoneNodeNum)
    1082             :     {
    1083             : 
    1084             :         // SUBROUTINE INFORMATION:
    1085             :         //       AUTHOR         Richard J. Liesen
    1086             :         //       DATE WRITTEN   Jan 2000
    1087             :         //       MODIFIED       na
    1088             :         //       RE-ENGINEERED  na
    1089             : 
    1090             :         // PURPOSE OF THIS SUBROUTINE:
    1091             :         // This subroutine simulates the simple mixing damper.
    1092             : 
    1093             :         // METHODOLOGY EMPLOYED:
    1094             :         // There is method to this madness.
    1095             : 
    1096             :         // Using/Aliasing
    1097             :         using namespace DataZoneEnergyDemands;
    1098             :         using DataHVACGlobals::SmallTempDiff;
    1099             :         using Psychrometrics::PsyCpAirFnW;
    1100             :         using Psychrometrics::PsyTdbFnHW;
    1101             : 
    1102             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1103             :         Real64 MassFlow;    // [kg/sec]   Total Mass Flow Rate from Hot & Cold Inlets
    1104             :         Real64 HumRat;      // [Kg Moisture / Kg dry air]
    1105             :         Real64 Enthalpy;    // [Watts]
    1106             :         Real64 Temperature; // [C]
    1107             :         Real64 QTotLoad;    // [W]
    1108             :         Real64 QZnReq;      // [W]
    1109             :         Real64 CpAirZn;
    1110             :         Real64 CpAirSysHot;
    1111             :         Real64 CpAirSysCold;
    1112             : 
    1113             :         // Get the calculated load from the Heat Balance from ZoneSysEnergyDemand
    1114      122805 :         QTotLoad = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputRequired;
    1115             :         // Need the design MassFlowRate for calculations
    1116      122805 :         if (ScheduleManager::GetCurrentScheduleValue(state, this->SchedPtr) > 0.0) {
    1117       98484 :             MassFlow = this->dd_airterminalHotAirInlet.AirMassFlowRateMaxAvail / 2.0 + this->dd_airterminalColdAirInlet.AirMassFlowRateMaxAvail / 2.0;
    1118             :         } else {
    1119       24321 :             MassFlow = 0.0;
    1120             :         }
    1121             :         // If there is massflow then need to provide the correct amount of total
    1122             :         //  required zone energy
    1123      122805 :         if (MassFlow > DataHVACGlobals::SmallMassFlow) {
    1124       98337 :             CpAirZn = PsyCpAirFnW(state.dataLoopNodes->Node(ZoneNodeNum).HumRat);
    1125       98337 :             QZnReq = QTotLoad + MassFlow * CpAirZn * state.dataLoopNodes->Node(ZoneNodeNum).Temp;
    1126             :             // If the enthalpy is the same for the hot and cold duct then there would be a
    1127             :             //  divide by zero so for heating or cooling set the damper to one max flow
    1128             :             //  or the other.
    1129       98337 :             if (std::abs(this->dd_airterminalColdAirInlet.AirTemp - this->dd_airterminalHotAirInlet.AirTemp) > SmallTempDiff) {
    1130             :                 // CpAirSysHot = PsyCpAirFnWTdb(dd_airterminalHotAirInlet(DDNum)%AirHumRat,dd_airterminalHotAirInlet(DDNum)%AirTemp)
    1131             :                 // CpAirSysCold= PsyCpAirFnWTdb(dd_airterminalColdAirInlet(DDNum)%AirHumRat,dd_airterminalColdAirInlet(DDNum)%AirTemp)
    1132       97523 :                 CpAirSysHot = CpAirZn;
    1133       97523 :                 CpAirSysCold = CpAirZn;
    1134             :                 // Determine the Cold Air Mass Flow Rate
    1135       97523 :                 this->dd_airterminalColdAirInlet.AirMassFlowRate =
    1136      195046 :                     (QZnReq - MassFlow * CpAirSysHot * this->dd_airterminalHotAirInlet.AirTemp) /
    1137       97523 :                     (CpAirSysCold * this->dd_airterminalColdAirInlet.AirTemp - CpAirSysHot * this->dd_airterminalHotAirInlet.AirTemp);
    1138         814 :             } else if ((QTotLoad > 0.0) && (this->dd_airterminalHotAirInlet.AirMassFlowRate > 0.0)) {
    1139          15 :                 this->dd_airterminalColdAirInlet.AirMassFlowRate = 0.0;
    1140             :             } else {
    1141         799 :                 this->dd_airterminalColdAirInlet.AirMassFlowRate = MassFlow;
    1142             :             }
    1143             :             // Check to make sure that the calculated flow is not greater than the available flows
    1144       98337 :             if (this->dd_airterminalColdAirInlet.AirMassFlowRate > this->dd_airterminalColdAirInlet.AirMassFlowRateMaxAvail) {
    1145        3938 :                 this->dd_airterminalColdAirInlet.AirMassFlowRate = this->dd_airterminalColdAirInlet.AirMassFlowRateMaxAvail;
    1146       94399 :             } else if (this->dd_airterminalColdAirInlet.AirMassFlowRate < this->dd_airterminalColdAirInlet.AirMassFlowRateMinAvail) {
    1147        9074 :                 this->dd_airterminalColdAirInlet.AirMassFlowRate = this->dd_airterminalColdAirInlet.AirMassFlowRateMinAvail;
    1148             :             }
    1149             :             // Using Mass Continuity to determine the other duct flow quantity
    1150       98337 :             this->dd_airterminalHotAirInlet.AirMassFlowRate = MassFlow - this->dd_airterminalColdAirInlet.AirMassFlowRate;
    1151       98337 :             if (this->dd_airterminalHotAirInlet.AirMassFlowRate > this->dd_airterminalHotAirInlet.AirMassFlowRateMaxAvail) {
    1152           0 :                 this->dd_airterminalHotAirInlet.AirMassFlowRate = this->dd_airterminalHotAirInlet.AirMassFlowRateMaxAvail;
    1153       98337 :             } else if (this->dd_airterminalHotAirInlet.AirMassFlowRate < this->dd_airterminalHotAirInlet.AirMassFlowRateMinAvail) {
    1154          10 :                 this->dd_airterminalHotAirInlet.AirMassFlowRate = this->dd_airterminalHotAirInlet.AirMassFlowRateMinAvail;
    1155             :             }
    1156       98337 :             MassFlow = this->dd_airterminalColdAirInlet.AirMassFlowRate + this->dd_airterminalHotAirInlet.AirMassFlowRate;
    1157             :         } else {
    1158             :             // System is Off set massflow to 0.0
    1159       24468 :             MassFlow = 0.0;
    1160             :         }
    1161      122805 :         if (MassFlow > DataHVACGlobals::SmallMassFlow) {
    1162             :             // After flows are calculated then calculate the mixed air flow properties.
    1163      196674 :             HumRat = (this->dd_airterminalHotAirInlet.AirHumRat * this->dd_airterminalHotAirInlet.AirMassFlowRate +
    1164       98337 :                       this->dd_airterminalColdAirInlet.AirHumRat * this->dd_airterminalColdAirInlet.AirMassFlowRate) /
    1165             :                      MassFlow;
    1166      196674 :             Enthalpy = (this->dd_airterminalHotAirInlet.AirEnthalpy * this->dd_airterminalHotAirInlet.AirMassFlowRate +
    1167       98337 :                         this->dd_airterminalColdAirInlet.AirEnthalpy * this->dd_airterminalColdAirInlet.AirMassFlowRate) /
    1168             :                        MassFlow;
    1169             : 
    1170             :             // If there is no air flow than calculate the No Flow conditions
    1171             :         } else {
    1172       24468 :             this->dd_airterminalColdAirInlet.AirMassFlowRate = 0.0;
    1173       24468 :             this->dd_airterminalHotAirInlet.AirMassFlowRate = 0.0;
    1174       24468 :             HumRat = (this->dd_airterminalHotAirInlet.AirHumRat + this->dd_airterminalColdAirInlet.AirHumRat) / 2.0;
    1175       24468 :             Enthalpy = (this->dd_airterminalHotAirInlet.AirEnthalpy + this->dd_airterminalColdAirInlet.AirEnthalpy) / 2.0;
    1176             :         }
    1177      122805 :         Temperature = PsyTdbFnHW(Enthalpy, HumRat);
    1178             : 
    1179             :         // Load all properties in the damper outlet
    1180      122805 :         this->dd_airterminalOutlet.AirTemp = Temperature;
    1181      122805 :         this->dd_airterminalOutlet.AirHumRat = HumRat;
    1182      122805 :         this->dd_airterminalOutlet.AirMassFlowRate = MassFlow;
    1183      122805 :         this->dd_airterminalOutlet.AirMassFlowRateMaxAvail = MassFlow;
    1184      122805 :         this->dd_airterminalOutlet.AirMassFlowRateMinAvail =
    1185      122805 :             min(this->dd_airterminalHotAirInlet.AirMassFlowRateMinAvail, this->dd_airterminalColdAirInlet.AirMassFlowRateMinAvail);
    1186      122805 :         this->dd_airterminalOutlet.AirEnthalpy = Enthalpy;
    1187             : 
    1188             :         // Calculate the hot and cold damper position in %
    1189      122805 :         if ((this->dd_airterminalHotAirInlet.AirMassFlowRateMax == 0.0) || (this->dd_airterminalColdAirInlet.AirMassFlowRateMax == 0.0)) {
    1190           8 :             this->ColdAirDamperPosition = 0.0;
    1191           8 :             this->HotAirDamperPosition = 0.0;
    1192             :         } else {
    1193      122797 :             this->ColdAirDamperPosition = this->dd_airterminalColdAirInlet.AirMassFlowRate / this->dd_airterminalColdAirInlet.AirMassFlowRateMax;
    1194      122797 :             this->HotAirDamperPosition = this->dd_airterminalHotAirInlet.AirMassFlowRate / this->dd_airterminalHotAirInlet.AirMassFlowRateMax;
    1195             :         }
    1196      122805 :     }
    1197             : 
    1198       16413 :     void DualDuctAirTerminal::SimDualDuctVarVol(EnergyPlusData &state, int const ZoneNum, int const ZoneNodeNum)
    1199             :     {
    1200             : 
    1201             :         // SUBROUTINE INFORMATION:
    1202             :         //       AUTHOR         Richard J. Liesen
    1203             :         //       DATE WRITTEN   Jan 2000
    1204             :         //       MODIFIED       na
    1205             :         //                      TH 3/2012: added supply air flow adjustment based on zone maximum outdoor
    1206             :         //                                 air fraction - a TRACE feature
    1207             :         //       RE-ENGINEERED  na
    1208             : 
    1209             :         // PURPOSE OF THIS SUBROUTINE:
    1210             :         // This subroutine simulates the simple mixing damper.
    1211             : 
    1212             :         // METHODOLOGY EMPLOYED:
    1213             :         // There is method to this madness.
    1214             : 
    1215             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1216             :         Real64 MassFlow;    // [kg/sec]   Total Mass Flow Rate from Hot & Cold Inlets
    1217             :         Real64 HumRat;      // [Kg Moisture / Kg dry air]
    1218             :         Real64 Enthalpy;    // [Watts]
    1219             :         Real64 Temperature; // [C]
    1220             :         Real64 QTotLoad;    // [W]
    1221             :         Real64 QZnReq;      // [W]
    1222             :         Real64 CpAirZn;     // specific heat of zone air
    1223             :         Real64 CpAirSysHot;
    1224             :         Real64 CpAirSysCold;
    1225             :         Real64 MassFlowBasedOnOA; // Supply air flow rate based on minimum OA requirement
    1226             :         Real64 AirLoopOAFrac;     // fraction of outdoor air entering air loop outside air system
    1227             : 
    1228             :         // The calculated load from the Heat Balance
    1229       16413 :         QTotLoad = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputRequired;
    1230             :         // Calculate all of the required Cp's
    1231       16413 :         CpAirZn = Psychrometrics::PsyCpAirFnW(state.dataLoopNodes->Node(ZoneNodeNum).HumRat);
    1232             :         // CpAirSysHot = PsyCpAirFnW(DamperHotAirInlet(DDNum)%AirHumRat,DamperHotAirInlet(DDNum)%AirTemp)
    1233             :         // CpAirSysCold= PsyCpAirFnW(DamperColdAirInlet(DDNum)%AirHumRat,DamperColdAirInlet(DDNum)%AirTemp)
    1234       16413 :         CpAirSysHot = CpAirZn;
    1235       16413 :         CpAirSysCold = CpAirZn;
    1236             : 
    1237             :         // calculate supply air flow rate based on user specified OA requirement
    1238       16413 :         this->CalcOAMassFlow(state, MassFlowBasedOnOA, AirLoopOAFrac);
    1239             : 
    1240             :         // Then depending on if the Load is for heating or cooling it is handled differently.  First
    1241             :         // the massflow rate of either heating or cooling is determined to meet the entire load.  Then
    1242             :         // if the massflow is below the minimum or greater than the Max it is set to either the Min
    1243             :         // or the Max as specified for the VAV model.
    1244       16413 :         if (ScheduleManager::GetCurrentScheduleValue(state, this->SchedPtr) == 0.0) {
    1245             :             // System is Off set massflow to 0.0
    1246        6081 :             MassFlow = 0.0;
    1247             : 
    1248       10332 :         } else if ((QTotLoad > 0.0) && (this->dd_airterminalHotAirInlet.AirMassFlowRateMaxAvail > 0.0)) {
    1249             :             // Then heating is needed
    1250             :             // Next check for the denominator equal to zero
    1251       13976 :             if (std::abs((CpAirSysHot * this->dd_airterminalHotAirInlet.AirTemp) - (CpAirZn * state.dataLoopNodes->Node(ZoneNodeNum).Temp)) /
    1252        6988 :                     CpAirZn >
    1253             :                 DataHVACGlobals::SmallTempDiff) {
    1254        6988 :                 MassFlow = QTotLoad / (CpAirSysHot * this->dd_airterminalHotAirInlet.AirTemp - CpAirZn * state.dataLoopNodes->Node(ZoneNodeNum).Temp);
    1255             :             } else {
    1256             :                 // If denominator tends to zero then mass flow would go to infinity thus set to the max for this iteration
    1257           0 :                 MassFlow = this->dd_airterminalHotAirInlet.AirMassFlowRateMaxAvail;
    1258             :             }
    1259             :             // Check to see if the flow is < the Min or > the Max air Fraction to the zone; then set to min or max
    1260        6988 :             if (MassFlow <= (this->dd_airterminalHotAirInlet.AirMassFlowRateMax * this->ZoneMinAirFrac)) {
    1261        5089 :                 MassFlow = this->dd_airterminalHotAirInlet.AirMassFlowRateMax * this->ZoneMinAirFrac;
    1262        5089 :                 MassFlow = max(MassFlow, this->dd_airterminalHotAirInlet.AirMassFlowRateMinAvail);
    1263        1899 :             } else if (MassFlow >= this->dd_airterminalHotAirInlet.AirMassFlowRateMaxAvail) {
    1264          46 :                 MassFlow = this->dd_airterminalHotAirInlet.AirMassFlowRateMaxAvail;
    1265             :             }
    1266             : 
    1267             :             // Apply the zone maximum outdoor air fraction for VAV boxes - a TRACE feature
    1268        6988 :             if (state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).SupplyAirAdjustFactor > 1.0) {
    1269           0 :                 MassFlow *= state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).SupplyAirAdjustFactor;
    1270             :             }
    1271             : 
    1272        6988 :             MassFlow = max(MassFlow, MassFlowBasedOnOA);
    1273        6988 :             MassFlow = min(MassFlow, this->dd_airterminalHotAirInlet.AirMassFlowRateMaxAvail);
    1274             : 
    1275        3344 :         } else if ((QTotLoad < 0.0) && (this->dd_airterminalColdAirInlet.AirMassFlowRateMaxAvail > 0.0)) {
    1276             :             // Then cooling is required
    1277             :             // Next check for the denominator equal to zero
    1278        6670 :             if (std::abs((CpAirSysCold * this->dd_airterminalColdAirInlet.AirTemp) - (CpAirZn * state.dataLoopNodes->Node(ZoneNodeNum).Temp)) /
    1279        3335 :                     CpAirZn >
    1280             :                 DataHVACGlobals::SmallTempDiff) {
    1281        3335 :                 MassFlow =
    1282        3335 :                     QTotLoad / (CpAirSysCold * this->dd_airterminalColdAirInlet.AirTemp - CpAirZn * state.dataLoopNodes->Node(ZoneNodeNum).Temp);
    1283             :             } else {
    1284             :                 // If denominator tends to zero then mass flow would go to infinity thus set to the max for this iteration
    1285           0 :                 MassFlow = this->dd_airterminalColdAirInlet.AirMassFlowRateMaxAvail;
    1286             :             }
    1287             : 
    1288             :             // Check to see if the flow is < the Min or > the Max air Fraction to the zone; then set to min or max
    1289        3335 :             if ((MassFlow <= (this->dd_airterminalColdAirInlet.AirMassFlowRateMax * this->ZoneMinAirFrac)) && (MassFlow >= 0.0)) {
    1290         234 :                 MassFlow = this->dd_airterminalColdAirInlet.AirMassFlowRateMax * this->ZoneMinAirFrac;
    1291         234 :                 MassFlow = max(MassFlow, this->dd_airterminalColdAirInlet.AirMassFlowRateMinAvail);
    1292        3101 :             } else if (MassFlow < 0.0) {
    1293         347 :                 MassFlow = this->dd_airterminalColdAirInlet.AirMassFlowRateMaxAvail;
    1294        2754 :             } else if (MassFlow >= this->dd_airterminalColdAirInlet.AirMassFlowRateMaxAvail) {
    1295         462 :                 MassFlow = this->dd_airterminalColdAirInlet.AirMassFlowRateMaxAvail;
    1296             :             }
    1297             : 
    1298             :             // Apply the zone maximum outdoor air fraction for VAV boxes - a TRACE feature
    1299        3335 :             if (state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).SupplyAirAdjustFactor > 1.0) {
    1300           0 :                 MassFlow *= state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).SupplyAirAdjustFactor;
    1301             :             }
    1302             : 
    1303        3335 :             MassFlow = max(MassFlow, MassFlowBasedOnOA);
    1304        3335 :             MassFlow = min(MassFlow, this->dd_airterminalColdAirInlet.AirMassFlowRateMaxAvail);
    1305             : 
    1306          18 :         } else if ((this->dd_airterminalHotAirInlet.AirMassFlowRateMaxAvail > 0.0) ||
    1307           9 :                    (this->dd_airterminalColdAirInlet.AirMassFlowRateMaxAvail > 0.0)) {
    1308             :             // No Load on Zone set to mixed condition
    1309           0 :             MassFlow = (this->dd_airterminalHotAirInlet.AirMassFlowRateMax / 2.0) * this->ZoneMinAirFrac +
    1310           0 :                        this->dd_airterminalColdAirInlet.AirMassFlowRateMax / 2.0 * this->ZoneMinAirFrac;
    1311             : 
    1312             :             // Apply the zone maximum outdoor air fraction for VAV boxes - a TRACE feature
    1313           0 :             if (state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).SupplyAirAdjustFactor > 1.0) {
    1314           0 :                 MassFlow *= state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).SupplyAirAdjustFactor;
    1315             :             }
    1316             : 
    1317           0 :             MassFlow = max(MassFlow, MassFlowBasedOnOA);
    1318           0 :             MassFlow =
    1319           0 :                 min(MassFlow, (this->dd_airterminalHotAirInlet.AirMassFlowRateMaxAvail + this->dd_airterminalColdAirInlet.AirMassFlowRateMaxAvail));
    1320             : 
    1321             :         } else {
    1322             :             // System is Off set massflow to 0.0
    1323           9 :             MassFlow = 0.0;
    1324             :         }
    1325             : 
    1326             :         // Now the massflow for heating or cooling has been determined and if the massflow was reset to the
    1327             :         // Min or Max we will need to mix the hot and cold deck to meet the zone load.  Knowing the enthalpy
    1328             :         // of the zone and the hot and cold air flows we can determine exactly by using the Energy and Continuity
    1329             :         // Eqns.  Of course we have to make sure that we are within the Min and Max flow conditions.
    1330       16413 :         if (MassFlow > DataHVACGlobals::SmallMassFlow) {
    1331             :             // Determine the enthalpy required from Zone enthalpy and the zone load.
    1332       10323 :             QZnReq = QTotLoad + MassFlow * CpAirZn * state.dataLoopNodes->Node(ZoneNodeNum).Temp;
    1333             :             // Using the known enthalpies the cold air inlet mass flow is determined.  If the enthalpy of the hot and cold
    1334             :             // air streams are equal the IF-Then block handles that condition.
    1335       10323 :             if (std::abs(this->dd_airterminalColdAirInlet.AirTemp - this->dd_airterminalHotAirInlet.AirTemp) > DataHVACGlobals::SmallTempDiff) {
    1336             :                 // Calculate the Cold air mass flow rate
    1337       10152 :                 this->dd_airterminalColdAirInlet.AirMassFlowRate =
    1338       20304 :                     (QZnReq - MassFlow * CpAirSysHot * this->dd_airterminalHotAirInlet.AirTemp) /
    1339       10152 :                     (CpAirSysCold * this->dd_airterminalColdAirInlet.AirTemp - CpAirSysHot * this->dd_airterminalHotAirInlet.AirTemp);
    1340         171 :             } else if ((QTotLoad > 0.0) && (this->dd_airterminalHotAirInlet.AirMassFlowRate > 0.0)) {
    1341           0 :                 this->dd_airterminalColdAirInlet.AirMassFlowRate = 0.0;
    1342             :             } else {
    1343         171 :                 this->dd_airterminalColdAirInlet.AirMassFlowRate = MassFlow;
    1344             :             }
    1345             : 
    1346             :             // Need to make sure that the flows are within limits
    1347       10323 :             if (this->dd_airterminalColdAirInlet.AirMassFlowRate > this->dd_airterminalColdAirInlet.AirMassFlowRateMaxAvail) {
    1348         639 :                 this->dd_airterminalColdAirInlet.AirMassFlowRate = this->dd_airterminalColdAirInlet.AirMassFlowRateMaxAvail;
    1349             : 
    1350             :                 // These are shutoff boxes for either the hot or the cold, therfore one side or other can = 0.0
    1351        9684 :             } else if (this->dd_airterminalColdAirInlet.AirMassFlowRate < 0.0) {
    1352         368 :                 this->dd_airterminalColdAirInlet.AirMassFlowRate = 0.0;
    1353        9316 :             } else if (this->dd_airterminalColdAirInlet.AirMassFlowRate > MassFlow) {
    1354         688 :                 this->dd_airterminalColdAirInlet.AirMassFlowRate = MassFlow;
    1355             :             }
    1356             :             // Using Mass Continuity to determine the other duct flow quantity
    1357       10323 :             this->dd_airterminalHotAirInlet.AirMassFlowRate = MassFlow - this->dd_airterminalColdAirInlet.AirMassFlowRate;
    1358             : 
    1359       10323 :             if (this->dd_airterminalHotAirInlet.AirMassFlowRate < DualDuctMassFlowSetToler) {
    1360        3109 :                 this->dd_airterminalHotAirInlet.AirMassFlowRate = 0.0;
    1361        3109 :                 this->dd_airterminalColdAirInlet.AirMassFlowRate = MassFlow;
    1362        7214 :             } else if (this->dd_airterminalColdAirInlet.AirMassFlowRate < DualDuctMassFlowSetToler) {
    1363        1899 :                 this->dd_airterminalColdAirInlet.AirMassFlowRate = 0.0;
    1364        1899 :                 this->dd_airterminalHotAirInlet.AirMassFlowRate = MassFlow;
    1365             :             }
    1366             : 
    1367             :             // After the flow rates are determined the properties are calculated.
    1368       20646 :             HumRat = (this->dd_airterminalHotAirInlet.AirHumRat * this->dd_airterminalHotAirInlet.AirMassFlowRate +
    1369       10323 :                       this->dd_airterminalColdAirInlet.AirHumRat * this->dd_airterminalColdAirInlet.AirMassFlowRate) /
    1370             :                      MassFlow;
    1371       20646 :             Enthalpy = (this->dd_airterminalHotAirInlet.AirEnthalpy * this->dd_airterminalHotAirInlet.AirMassFlowRate +
    1372       10323 :                         this->dd_airterminalColdAirInlet.AirEnthalpy * this->dd_airterminalColdAirInlet.AirMassFlowRate) /
    1373             :                        MassFlow;
    1374             : 
    1375             :             // IF the system is OFF the properties are calculated for this special case.
    1376             :         } else {
    1377        6090 :             this->dd_airterminalColdAirInlet.AirMassFlowRate = 0.0;
    1378        6090 :             this->dd_airterminalHotAirInlet.AirMassFlowRate = 0.0;
    1379        6090 :             HumRat = (this->dd_airterminalHotAirInlet.AirHumRat + this->dd_airterminalColdAirInlet.AirHumRat) / 2.0;
    1380        6090 :             Enthalpy = (this->dd_airterminalHotAirInlet.AirEnthalpy + this->dd_airterminalColdAirInlet.AirEnthalpy) / 2.0;
    1381             :         }
    1382       16413 :         Temperature = Psychrometrics::PsyTdbFnHW(Enthalpy, HumRat);
    1383             : 
    1384       16413 :         this->dd_airterminalOutlet.AirTemp = Temperature;
    1385       16413 :         this->dd_airterminalOutlet.AirHumRat = HumRat;
    1386       16413 :         this->dd_airterminalOutlet.AirMassFlowRate = MassFlow;
    1387       16413 :         this->dd_airterminalOutlet.AirMassFlowRateMaxAvail = MassFlow;
    1388       16413 :         this->dd_airterminalOutlet.AirMassFlowRateMinAvail = this->ZoneMinAirFrac * this->dd_airterminalHotAirInlet.AirMassFlowRateMax;
    1389       16413 :         this->dd_airterminalOutlet.AirEnthalpy = Enthalpy;
    1390             : 
    1391             :         // Calculate the hot and cold damper position in %
    1392       16413 :         if ((this->dd_airterminalHotAirInlet.AirMassFlowRateMax == 0.0) || (this->dd_airterminalColdAirInlet.AirMassFlowRateMax == 0.0)) {
    1393           0 :             this->ColdAirDamperPosition = 0.0;
    1394           0 :             this->HotAirDamperPosition = 0.0;
    1395             :         } else {
    1396       16413 :             this->ColdAirDamperPosition = this->dd_airterminalColdAirInlet.AirMassFlowRate / this->dd_airterminalColdAirInlet.AirMassFlowRateMax;
    1397       16413 :             this->HotAirDamperPosition = this->dd_airterminalHotAirInlet.AirMassFlowRate / this->dd_airterminalHotAirInlet.AirMassFlowRateMax;
    1398             :         }
    1399       16413 :     }
    1400             : 
    1401       67628 :     void DualDuctAirTerminal::SimDualDuctVAVOutdoorAir(EnergyPlusData &state, int const ZoneNum, int const ZoneNodeNum)
    1402             :     {
    1403             : 
    1404             :         // SUBROUTINE INFORMATION:
    1405             :         //       AUTHOR         Clayton Miller
    1406             :         //       DATE WRITTEN   Aug 2010
    1407             :         //       MODIFIED       B. Griffith, Dec 2010, major rework
    1408             :         //       RE-ENGINEERED  na
    1409             : 
    1410             :         // PURPOSE OF THIS SUBROUTINE:
    1411             :         // Designed to accommodate for systems with outdoor air (OA) and recirculated air (RA)
    1412             :         // as two separate air streams to controlled at the zone level in a dual duct system.
    1413             : 
    1414             :         // METHODOLOGY EMPLOYED:
    1415             :         // The terminal unit is be designed to set the airflow of the of the OA stream at the zone
    1416             :         // level based on the zonal ventilation requirements and the RA stream flowrate of recirculated
    1417             :         // cooling air stream in order to meet the remaining thermal load.
    1418             :         // If the zone calls for cooling but the inlet air temperature is too warm, recirc side set to zero
    1419             :         // if the zone calls for heating and the inlet air is warm enough, modulate damper to meet load
    1420             :         // if the zone calls for heating and the inlet air is too cold, zero flow (will not control sans reheat)
    1421             : 
    1422             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1423             :         Real64 MassFlowMax;     // [kg/sec]   Maximum Mass Flow Rate from OA and Recirc Inlets
    1424             :         Real64 HumRat;          // [Kg Moisture / Kg dry air]
    1425             :         Real64 Enthalpy;        // [Watts]
    1426             :         Real64 Temperature;     // [C]
    1427             :         Real64 QTotLoadRemain;  // [W]
    1428             :         Real64 QtoHeatSPRemain; // [W]
    1429             :         Real64 QtoCoolSPRemain; // [W]
    1430             :         //  REAL(r64) :: QTotRemainAdjust  ! [W]
    1431             :         Real64 QtoHeatSPRemainAdjust; // [W]
    1432             :         Real64 QtoCoolSPRemainAdjust; // [W]
    1433             :         Real64 QOALoadToHeatSP;       // [W]
    1434             :         Real64 QOALoadToCoolSP;       // [W]
    1435             :         Real64 QOALoad;               // Amount of cooling load accounted for by OA Stream [W]
    1436             :         Real64 QRALoad;               // Amount of cooling load accounted for by Recirc Stream [W]
    1437             :         Real64 CpAirZn;               // specific heat of zone air
    1438             :         Real64 CpAirSysOA;            // specific heat of outdoor air
    1439             :         Real64 CpAirSysRA;            // specific heat of recirculated air
    1440             :         Real64 OAMassFlow;            // Supply air flow rate based on minimum OA requirement - for printing
    1441             :         Real64 TotMassFlow;           // [kg/sec]   Total Mass Flow Rate from OA and Recirc Inlets
    1442             :         int OAInletNodeNum;
    1443             :         int RecircInletNodeNum;
    1444             : 
    1445       67628 :         OAInletNodeNum = this->OAInletNodeNum;
    1446       67628 :         if (this->RecircIsUsed) {
    1447       36888 :             RecircInletNodeNum = this->RecircAirInletNodeNum;
    1448             :         }
    1449             :         // Calculate required ventilation air flow rate based on user specified OA requirement
    1450       67628 :         this->CalcOAOnlyMassFlow(state, OAMassFlow);
    1451             : 
    1452             :         // The calculated load from the Heat Balance, adjusted for any equipment sequenced before terminal
    1453       67628 :         QTotLoadRemain = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputRequired;
    1454       67628 :         QtoHeatSPRemain = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputReqToHeatSP;
    1455       67628 :         QtoCoolSPRemain = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputReqToCoolSP;
    1456             : 
    1457             :         // Calculate all of the required Cp's
    1458       67628 :         CpAirZn = Psychrometrics::PsyCpAirFnW(state.dataLoopNodes->Node(ZoneNodeNum).HumRat);
    1459       67628 :         CpAirSysOA = Psychrometrics::PsyCpAirFnW(state.dataLoopNodes->Node(OAInletNodeNum).HumRat);
    1460       67628 :         if (this->RecircIsUsed) CpAirSysRA = Psychrometrics::PsyCpAirFnW(state.dataLoopNodes->Node(RecircInletNodeNum).HumRat);
    1461             : 
    1462             :         // Set the OA Damper to the calculated ventilation flow rate
    1463       67628 :         this->dd_airterminalOAInlet.AirMassFlowRate = OAMassFlow;
    1464             :         // Need to make sure that the OA flows are within limits
    1465       67628 :         if (this->dd_airterminalOAInlet.AirMassFlowRate > this->dd_airterminalOAInlet.AirMassFlowRateMaxAvail) {
    1466          66 :             this->dd_airterminalOAInlet.AirMassFlowRate = this->dd_airterminalOAInlet.AirMassFlowRateMaxAvail;
    1467       67562 :         } else if (this->dd_airterminalOAInlet.AirMassFlowRate < 0.0) {
    1468           0 :             this->dd_airterminalOAInlet.AirMassFlowRate = 0.0;
    1469             :         }
    1470             : 
    1471             :         //..Find the amount of load that the OAMassFlow accounted for
    1472       67628 :         if (std::abs((CpAirSysOA * this->dd_airterminalOAInlet.AirTemp) - (CpAirZn * state.dataLoopNodes->Node(ZoneNodeNum).Temp)) / CpAirZn >
    1473             :             DataHVACGlobals::SmallTempDiff) {
    1474      135086 :             QOALoad = this->dd_airterminalOAInlet.AirMassFlowRate *
    1475       67543 :                       (CpAirSysOA * this->dd_airterminalOAInlet.AirTemp - CpAirZn * state.dataLoopNodes->Node(ZoneNodeNum).Temp);
    1476             : 
    1477      135086 :             QOALoadToHeatSP = this->dd_airterminalOAInlet.AirMassFlowRate * (CpAirSysOA * this->dd_airterminalOAInlet.AirTemp -
    1478       67543 :                                                                              CpAirZn * state.dataHeatBalFanSys->ZoneThermostatSetPointLo(ZoneNum));
    1479      135086 :             QOALoadToCoolSP = this->dd_airterminalOAInlet.AirMassFlowRate * (CpAirSysOA * this->dd_airterminalOAInlet.AirTemp -
    1480       67543 :                                                                              CpAirZn * state.dataHeatBalFanSys->ZoneThermostatSetPointHi(ZoneNum));
    1481             : 
    1482             :         } else {
    1483          85 :             QOALoad = 0.0;
    1484          85 :             QOALoadToHeatSP = 0.0;
    1485          85 :             QOALoadToCoolSP = 0.0;
    1486             :         }
    1487             : 
    1488       67628 :         if (this->RecircIsUsed) {
    1489             : 
    1490             :             // correct load for recirc side to account for impact of OA side
    1491             :             // QTotRemainAdjust      = QTotLoadRemain  - QOALoad
    1492       36888 :             QtoHeatSPRemainAdjust = QtoHeatSPRemain - QOALoadToHeatSP;
    1493       36888 :             QtoCoolSPRemainAdjust = QtoCoolSPRemain - QOALoadToCoolSP;
    1494             : 
    1495       36888 :             if (QtoCoolSPRemainAdjust < 0.0) {
    1496       23594 :                 QRALoad = QtoCoolSPRemainAdjust;
    1497       13294 :             } else if (QtoHeatSPRemainAdjust > 0.0) {
    1498       12180 :                 QRALoad = QtoHeatSPRemainAdjust;
    1499             :             } else {
    1500        1114 :                 QRALoad = 0.0;
    1501             :             }
    1502             : 
    1503       36888 :             if (QRALoad < 0.0) {                                                                                         // cooling
    1504       23594 :                 if ((this->dd_airterminalRecircAirInlet.AirTemp - state.dataLoopNodes->Node(ZoneNodeNum).Temp) < -0.5) { // can cool
    1505             :                     //  Find the Mass Flow Rate of the RA Stream needed to meet the zone cooling load
    1506       70782 :                     if (std::abs((CpAirSysRA * this->dd_airterminalRecircAirInlet.AirTemp) -
    1507       47188 :                                  (CpAirZn * state.dataLoopNodes->Node(ZoneNodeNum).Temp)) /
    1508       23594 :                             CpAirZn >
    1509             :                         DataHVACGlobals::SmallTempDiff) {
    1510       47188 :                         this->dd_airterminalRecircAirInlet.AirMassFlowRate = QRALoad / (CpAirSysRA * this->dd_airterminalRecircAirInlet.AirTemp -
    1511       23594 :                                                                                         CpAirZn * state.dataLoopNodes->Node(ZoneNodeNum).Temp);
    1512             :                     }
    1513             :                 } else {
    1514           0 :                     this->dd_airterminalRecircAirInlet.AirMassFlowRate = 0.0;
    1515             :                 }
    1516             : 
    1517             :             } else { // heating or none needed.
    1518       13294 :                 this->dd_airterminalRecircAirInlet.AirMassFlowRate = 0.0;
    1519             :             }
    1520             : 
    1521             :             // Need to make sure that the RA flows are within limits
    1522       36888 :             if (this->dd_airterminalRecircAirInlet.AirMassFlowRate > this->dd_airterminalRecircAirInlet.AirMassFlowRateMaxAvail) {
    1523          25 :                 this->dd_airterminalRecircAirInlet.AirMassFlowRate = this->dd_airterminalRecircAirInlet.AirMassFlowRateMaxAvail;
    1524             :                 // These are shutoff boxes for either the hot or the cold, therfore one side or other can = 0.0
    1525       36863 :             } else if (this->dd_airterminalRecircAirInlet.AirMassFlowRate < 0.0) {
    1526           0 :                 this->dd_airterminalRecircAirInlet.AirMassFlowRate = 0.0;
    1527             :             }
    1528             : 
    1529             :         } else {
    1530       30740 :             this->dd_airterminalRecircAirInlet.AirMassFlowRate = 0.0;
    1531       30740 :             this->dd_airterminalRecircAirInlet.AirMassFlowRateMaxAvail = 0.0;
    1532             :         } // recirc used
    1533             : 
    1534             :         // look for bang-bang condition: flow rate oscillating between 2 values during the air loop / zone
    1535             :         // equipment iteration. If detected, set flow rate to previous value.
    1536      135256 :         if (((std::abs(this->dd_airterminalRecircAirInlet.AirMassFlowRate - this->dd_airterminalRecircAirInlet.AirMassFlowRateHist2) <
    1537      121947 :               this->dd_airterminalRecircAirInlet.AirMassFlowDiffMag) ||
    1538       54319 :              (std::abs(this->dd_airterminalRecircAirInlet.AirMassFlowRate - this->dd_airterminalRecircAirInlet.AirMassFlowRateHist3) <
    1539      135256 :               this->dd_airterminalRecircAirInlet.AirMassFlowDiffMag)) &&
    1540       13309 :             (std::abs(this->dd_airterminalRecircAirInlet.AirMassFlowRate - this->dd_airterminalRecircAirInlet.AirMassFlowRateHist1) >=
    1541       13309 :              this->dd_airterminalRecircAirInlet.AirMassFlowDiffMag)) {
    1542          16 :             if (this->dd_airterminalRecircAirInlet.AirMassFlowRate > 0.0) {
    1543           0 :                 this->dd_airterminalRecircAirInlet.AirMassFlowRate = this->dd_airterminalRecircAirInlet.AirMassFlowRateHist1;
    1544             :             }
    1545             :         }
    1546             : 
    1547             :         // Find the Max Box Flow Rate.
    1548       67628 :         MassFlowMax = this->dd_airterminalOAInlet.AirMassFlowRateMaxAvail + this->dd_airterminalRecircAirInlet.AirMassFlowRateMaxAvail;
    1549       67628 :         if (ScheduleManager::GetCurrentScheduleValue(state, this->SchedPtr) > 0.0) {
    1550       67628 :             TotMassFlow = this->dd_airterminalOAInlet.AirMassFlowRate + this->dd_airterminalRecircAirInlet.AirMassFlowRate;
    1551             :         } else {
    1552           0 :             TotMassFlow = 0.0;
    1553             :         }
    1554             : 
    1555       67628 :         if (TotMassFlow > DataHVACGlobals::SmallMassFlow) {
    1556             : 
    1557             :             // If the sum of the two air streams' flow is greater than the Max Box Flow Rate then reset the RA Stream
    1558       67408 :             if (TotMassFlow > MassFlowMax) {
    1559           0 :                 this->dd_airterminalRecircAirInlet.AirMassFlowRate = MassFlowMax - this->dd_airterminalOAInlet.AirMassFlowRate;
    1560             :             }
    1561             :             // After the flow rates are determined the properties are calculated.
    1562       67408 :             TotMassFlow = this->dd_airterminalOAInlet.AirMassFlowRate + this->dd_airterminalRecircAirInlet.AirMassFlowRate;
    1563       67408 :             if (TotMassFlow > DataHVACGlobals::SmallMassFlow) {
    1564      134816 :                 HumRat = (this->dd_airterminalOAInlet.AirHumRat * this->dd_airterminalOAInlet.AirMassFlowRate +
    1565       67408 :                           this->dd_airterminalRecircAirInlet.AirHumRat * this->dd_airterminalRecircAirInlet.AirMassFlowRate) /
    1566             :                          TotMassFlow;
    1567      134816 :                 Enthalpy = (this->dd_airterminalOAInlet.AirEnthalpy * this->dd_airterminalOAInlet.AirMassFlowRate +
    1568       67408 :                             this->dd_airterminalRecircAirInlet.AirEnthalpy * this->dd_airterminalRecircAirInlet.AirMassFlowRate) /
    1569             :                            TotMassFlow;
    1570             :             } else {
    1571           0 :                 HumRat = (this->dd_airterminalRecircAirInlet.AirHumRat + this->dd_airterminalOAInlet.AirHumRat) / 2.0;
    1572           0 :                 Enthalpy = (this->dd_airterminalRecircAirInlet.AirEnthalpy + this->dd_airterminalOAInlet.AirEnthalpy) / 2.0;
    1573             :             }
    1574             :         } else {
    1575             : 
    1576             :             // The Max Box Flow Rate is zero and the box is off.
    1577         220 :             this->dd_airterminalRecircAirInlet.AirMassFlowRate = 0.0;
    1578         220 :             this->dd_airterminalOAInlet.AirMassFlowRate = 0.0;
    1579         220 :             HumRat = (this->dd_airterminalRecircAirInlet.AirHumRat + this->dd_airterminalOAInlet.AirHumRat) / 2.0;
    1580         220 :             Enthalpy = (this->dd_airterminalRecircAirInlet.AirEnthalpy + this->dd_airterminalOAInlet.AirEnthalpy) / 2.0;
    1581             :         }
    1582             : 
    1583       67628 :         Temperature = Psychrometrics::PsyTdbFnHW(Enthalpy, HumRat);
    1584             : 
    1585       67628 :         this->dd_airterminalOutlet.AirTemp = Temperature;
    1586       67628 :         this->dd_airterminalOutlet.AirHumRat = HumRat;
    1587       67628 :         this->dd_airterminalOutlet.AirMassFlowRate = TotMassFlow;
    1588       67628 :         this->dd_airterminalOutlet.AirMassFlowRateMaxAvail = MassFlowMax;
    1589       67628 :         this->dd_airterminalOutlet.AirEnthalpy = Enthalpy;
    1590             : 
    1591             :         // Calculate the OA and RA damper position in %
    1592       67628 :         if (this->RecircIsUsed) {
    1593       36888 :             if (this->dd_airterminalRecircAirInlet.AirMassFlowRateMax == 0.0) { // protect div by zero
    1594           6 :                 this->RecircAirDamperPosition = 0.0;
    1595             :             } else {
    1596       36882 :                 this->RecircAirDamperPosition =
    1597       36882 :                     this->dd_airterminalRecircAirInlet.AirMassFlowRate / this->dd_airterminalRecircAirInlet.AirMassFlowRateMax;
    1598             :             }
    1599             :         }
    1600             : 
    1601       67628 :         if (this->dd_airterminalOAInlet.AirMassFlowRateMax == 0.0) { // protect div by zero
    1602          11 :             this->OADamperPosition = 0.0;
    1603             :         } else {
    1604       67617 :             this->OADamperPosition = this->dd_airterminalOAInlet.AirMassFlowRate / this->dd_airterminalOAInlet.AirMassFlowRateMax;
    1605             :         }
    1606             : 
    1607             :         // Calculate OAFraction of mixed air after the box
    1608       67628 :         if (TotMassFlow > 0) {
    1609       67408 :             if (this->RecircIsUsed) {
    1610       36768 :                 if (this->dd_airterminalOAInlet.AirMassFlowRate == 0.0) {
    1611           0 :                     this->OAFraction = 0.0;
    1612       36768 :                 } else if (this->dd_airterminalRecircAirInlet.AirMassFlowRate == 0.0) {
    1613       13193 :                     this->OAFraction = 1.0;
    1614             :                 } else {
    1615       23575 :                     this->OAFraction = this->dd_airterminalOAInlet.AirMassFlowRate / TotMassFlow;
    1616             :                 }
    1617             :             } else {
    1618       30640 :                 this->OAFraction = 1.0;
    1619             :             }
    1620             :         } else {
    1621         220 :             this->OAFraction = 0.0;
    1622             :         }
    1623             : 
    1624       67628 :         this->dd_airterminalRecircAirInlet.AirMassFlowRateHist3 = this->dd_airterminalRecircAirInlet.AirMassFlowRateHist2;
    1625       67628 :         this->dd_airterminalRecircAirInlet.AirMassFlowRateHist2 = this->dd_airterminalRecircAirInlet.AirMassFlowRateHist1;
    1626       67628 :         this->dd_airterminalRecircAirInlet.AirMassFlowRateHist1 = this->dd_airterminalRecircAirInlet.AirMassFlowRate;
    1627       67628 :     }
    1628             : 
    1629       16413 :     void DualDuctAirTerminal::CalcOAMassFlow(EnergyPlusData &state, // NOLINT(readability-make-member-function-const)
    1630             :                                              Real64 &SAMassFlow,    // outside air based on optional user input
    1631             :                                              Real64 &AirLoopOAFrac  // outside air based on optional user input
    1632             :     )
    1633             :     {
    1634             : 
    1635             :         // FUNCTION INFORMATION:
    1636             :         //       AUTHOR         R. Raustad (FSEC)
    1637             :         //       DATE WRITTEN   Mar 2010
    1638             :         //       MODIFIED       Mangesh Basarkar, 06/2011: Modifying outside air based on airloop DCV flag
    1639             :         //       RE-ENGINEERED  na
    1640             : 
    1641             :         // PURPOSE OF THIS FUNCTION:
    1642             :         // Calculates the amount of outside air required based on optional user input.
    1643             :         // Zone multipliers are included and are applied in GetInput.
    1644             : 
    1645             :         // METHODOLOGY EMPLOYED:
    1646             :         // User input defines method used to calculate OA.
    1647             : 
    1648             :         // initialize OA flow rate and OA report variable
    1649       16413 :         SAMassFlow = 0.0;
    1650       16413 :         AirLoopOAFrac = 0.0;
    1651             : 
    1652             :         // Calculate the amount of OA based on optional user inputs
    1653       16413 :         if (AirLoopNum > 0) {
    1654       16410 :             AirLoopOAFrac = state.dataAirLoop->AirLoopFlow(AirLoopNum).OAFrac;
    1655             :             // If no additional input from user, RETURN from subroutine
    1656       16410 :             if (this->NoOAFlowInputFromUser) return;
    1657             :             // Calculate outdoor air flow rate, zone multipliers are applied in GetInput
    1658           0 :             if (AirLoopOAFrac > 0.0) {
    1659           0 :                 bool constexpr UseMinOASchFlag(true); // Always use min OA schedule in calculations.
    1660             :                 Real64 const OAVolumeFlowRate =
    1661           0 :                     DataSizing::calcDesignSpecificationOutdoorAir(state,
    1662             :                                                                   this->OARequirementsPtr,
    1663             :                                                                   this->CtrlZoneNum,
    1664           0 :                                                                   state.dataAirLoop->AirLoopControlInfo(AirLoopNum).AirLoopDCVFlag,
    1665           0 :                                                                   UseMinOASchFlag);
    1666           0 :                 Real64 const OAMassFlow = OAVolumeFlowRate * state.dataEnvrn->StdRhoAir;
    1667             : 
    1668             :                 // convert OA mass flow rate to supply air flow rate based on air loop OA fraction
    1669           0 :                 SAMassFlow = OAMassFlow / AirLoopOAFrac;
    1670             :             }
    1671             :         }
    1672             :     }
    1673             : 
    1674       67639 :     void DualDuctAirTerminal::CalcOAOnlyMassFlow(EnergyPlusData &state,        // NOLINT(readability-make-member-function-const)
    1675             :                                                  Real64 &OAMassFlow,           // outside air flow from user input kg/s
    1676             :                                                  Optional<Real64> MaxOAVolFlow // design level for outside air m3/s
    1677             :     )
    1678             :     {
    1679             : 
    1680             :         // FUNCTION INFORMATION:
    1681             :         //       AUTHOR         C. Miller (Mod of CaclOAMassFlow by R. Raustad (FSEC))
    1682             :         //       DATE WRITTEN   Aug 2010
    1683             :         //       MODIFIED       B. Griffith, Dec 2010 clean up, sizing optional, scheduled OA
    1684             :         //       RE-ENGINEERED  na
    1685             : 
    1686             :         // PURPOSE OF THIS FUNCTION:
    1687             :         // Calculates the amount of outside air required based on optional user input. Returns
    1688             :         // ONLY calculated OAMassFlow without consideration of AirLoopOAFrac. Used for
    1689             :         // the DualDuct:VAV:OutdoorAir object which does not mix OA with RA
    1690             : 
    1691             :         // METHODOLOGY EMPLOYED:
    1692             :         // User input defines method used to calculate OA.
    1693             : 
    1694             :         // Calculate the amount of OA based on optional user inputs
    1695       67639 :         OAMassFlow = 0.0;
    1696             : 
    1697             :         // If no additional input from user, RETURN from subroutine
    1698       67639 :         if (this->NoOAFlowInputFromUser) {
    1699           0 :             ShowSevereError(
    1700           0 :                 state, "CalcOAOnlyMassFlow: Problem in AirTerminal:DualDuct:VAV:OutdoorAir = " + this->Name + ", check outdoor air specification");
    1701           0 :             if (present(MaxOAVolFlow)) MaxOAVolFlow = 0.0;
    1702           0 :             return;
    1703             :         }
    1704             : 
    1705       67639 :         bool UseOccSchFlag = this->OAPerPersonMode == PerPersonMode::DCVByCurrentLevel; // TRUE = use actual occupancy, FALSE = use total zone people
    1706       67639 :         bool PerPersonNotSet = this->OAPerPersonMode != PerPersonMode::DCVByCurrentLevel && this->OAPerPersonMode != PerPersonMode::ByDesignLevel;
    1707             : 
    1708       67639 :         bool constexpr UseMinOASchFlag(true); // Always use min OA schedule in calculations.
    1709       67639 :         Real64 OAVolumeFlowRate = DataSizing::calcDesignSpecificationOutdoorAir(state,
    1710             :                                                                                 this->OARequirementsPtr,
    1711             :                                                                                 this->CtrlZoneNum,
    1712             :                                                                                 UseOccSchFlag,
    1713             :                                                                                 UseMinOASchFlag,
    1714       67639 :                                                                                 PerPersonNotSet); // outside air volume flow rate (m3/s)
    1715             : 
    1716       67639 :         OAMassFlow = OAVolumeFlowRate * state.dataEnvrn->StdRhoAir;
    1717             : 
    1718       67639 :         if (present(MaxOAVolFlow)) {
    1719          11 :             OAVolumeFlowRate = DataSizing::calcDesignSpecificationOutdoorAir(
    1720             :                 state, this->OARequirementsPtr, this->CtrlZoneNum, UseOccSchFlag, UseMinOASchFlag, false, true);
    1721          11 :             MaxOAVolFlow = OAVolumeFlowRate;
    1722             :         }
    1723             :     }
    1724             : 
    1725      206846 :     void DualDuctAirTerminal::UpdateDualDuct(EnergyPlusData &state)
    1726             :     {
    1727             : 
    1728             :         // SUBROUTINE INFORMATION:
    1729             :         //       AUTHOR         Richard J. Liesen
    1730             :         //       DATE WRITTEN   February 2000
    1731             :         //       MODIFIED       Aug 2010 Clayton Miller - Added DualDuctVAVOutdoorAir
    1732             :         //       RE-ENGINEERED  na
    1733             : 
    1734             :         // PURPOSE OF THIS SUBROUTINE:
    1735             :         // This subroutine updates the dampers.
    1736             : 
    1737      206846 :         if (this->DamperType == DualDuctDamper::ConstantVolume || this->DamperType == DualDuctDamper::VariableVolume) {
    1738             : 
    1739      139218 :             int OutletNode = this->OutletNodeNum;
    1740      139218 :             int HotInletNode = this->HotAirInletNodeNum;
    1741      139218 :             int ColdInletNode = this->ColdAirInletNodeNum;
    1742             : 
    1743             :             // Set the outlet air nodes of the Damper
    1744      139218 :             state.dataLoopNodes->Node(HotInletNode).MassFlowRate = this->dd_airterminalHotAirInlet.AirMassFlowRate;
    1745      139218 :             state.dataLoopNodes->Node(ColdInletNode).MassFlowRate = this->dd_airterminalColdAirInlet.AirMassFlowRate;
    1746      139218 :             state.dataLoopNodes->Node(OutletNode).MassFlowRate = this->dd_airterminalOutlet.AirMassFlowRate;
    1747      139218 :             state.dataLoopNodes->Node(OutletNode).MassFlowRateMaxAvail = this->dd_airterminalOutlet.AirMassFlowRate;
    1748      139218 :             state.dataLoopNodes->Node(OutletNode).MassFlowRateMinAvail = this->dd_airterminalOutlet.AirMassFlowRateMinAvail;
    1749      139218 :             state.dataLoopNodes->Node(OutletNode).Temp = this->dd_airterminalOutlet.AirTemp;
    1750      139218 :             state.dataLoopNodes->Node(OutletNode).HumRat = this->dd_airterminalOutlet.AirHumRat;
    1751      139218 :             state.dataLoopNodes->Node(OutletNode).Enthalpy = this->dd_airterminalOutlet.AirEnthalpy;
    1752             :             // Set the outlet nodes for properties that just pass through & not used
    1753             :             // FIX THIS LATER!!!!
    1754      139218 :             state.dataLoopNodes->Node(OutletNode).Quality = state.dataLoopNodes->Node(HotInletNode).Quality;
    1755      139218 :             state.dataLoopNodes->Node(OutletNode).Press = state.dataLoopNodes->Node(HotInletNode).Press;
    1756             : 
    1757      139218 :             if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    1758           0 :                 if (state.dataLoopNodes->Node(OutletNode).MassFlowRate > 0.0) {
    1759           0 :                     state.dataLoopNodes->Node(OutletNode).CO2 =
    1760           0 :                         (state.dataLoopNodes->Node(HotInletNode).CO2 * state.dataLoopNodes->Node(HotInletNode).MassFlowRate +
    1761           0 :                          state.dataLoopNodes->Node(ColdInletNode).CO2 * state.dataLoopNodes->Node(ColdInletNode).MassFlowRate) /
    1762           0 :                         state.dataLoopNodes->Node(OutletNode).MassFlowRate;
    1763             :                 } else {
    1764           0 :                     state.dataLoopNodes->Node(OutletNode).CO2 =
    1765           0 :                         max(state.dataLoopNodes->Node(HotInletNode).CO2, state.dataLoopNodes->Node(ColdInletNode).CO2);
    1766             :                 }
    1767             :             }
    1768      139218 :             if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    1769           0 :                 if (state.dataLoopNodes->Node(OutletNode).MassFlowRate > 0.0) {
    1770           0 :                     state.dataLoopNodes->Node(OutletNode).GenContam =
    1771           0 :                         (state.dataLoopNodes->Node(HotInletNode).GenContam * state.dataLoopNodes->Node(HotInletNode).MassFlowRate +
    1772           0 :                          state.dataLoopNodes->Node(ColdInletNode).GenContam * state.dataLoopNodes->Node(ColdInletNode).MassFlowRate) /
    1773           0 :                         state.dataLoopNodes->Node(OutletNode).MassFlowRate;
    1774             :                 } else {
    1775           0 :                     state.dataLoopNodes->Node(OutletNode).GenContam =
    1776           0 :                         max(state.dataLoopNodes->Node(HotInletNode).GenContam, state.dataLoopNodes->Node(ColdInletNode).GenContam);
    1777             :                 }
    1778             :             }
    1779             : 
    1780      139218 :             this->CalcOutdoorAirVolumeFlowRate(state);
    1781             : 
    1782       67628 :         } else if (this->DamperType == DualDuctDamper::OutdoorAir) {
    1783             : 
    1784       67628 :             int OutletNode = this->OutletNodeNum;
    1785       67628 :             int OAInletNode = this->OAInletNodeNum;
    1786             :             // Set the outlet air nodes of the Damper
    1787       67628 :             state.dataLoopNodes->Node(OAInletNode).MassFlowRate = this->dd_airterminalOAInlet.AirMassFlowRate;
    1788       67628 :             state.dataLoopNodes->Node(OutletNode).MassFlowRate = this->dd_airterminalOutlet.AirMassFlowRate;
    1789       67628 :             state.dataLoopNodes->Node(OutletNode).MassFlowRateMaxAvail = this->dd_airterminalOutlet.AirMassFlowRate;
    1790       67628 :             state.dataLoopNodes->Node(OutletNode).MassFlowRateMinAvail = this->dd_airterminalOutlet.AirMassFlowRateMinAvail;
    1791       67628 :             state.dataLoopNodes->Node(OutletNode).Temp = this->dd_airterminalOutlet.AirTemp;
    1792       67628 :             state.dataLoopNodes->Node(OutletNode).HumRat = this->dd_airterminalOutlet.AirHumRat;
    1793       67628 :             state.dataLoopNodes->Node(OutletNode).Enthalpy = this->dd_airterminalOutlet.AirEnthalpy;
    1794             :             // Set the outlet nodes for properties that just pass through & not used
    1795             :             // FIX THIS LATER!!!!
    1796       67628 :             state.dataLoopNodes->Node(OutletNode).Quality = state.dataLoopNodes->Node(OAInletNode).Quality;
    1797       67628 :             state.dataLoopNodes->Node(OutletNode).Press = state.dataLoopNodes->Node(OAInletNode).Press;
    1798             : 
    1799       67628 :             if (this->RecircIsUsed) {
    1800       36888 :                 int RAInletNode = this->RecircAirInletNodeNum;
    1801       36888 :                 state.dataLoopNodes->Node(RAInletNode).MassFlowRate = this->dd_airterminalRecircAirInlet.AirMassFlowRate;
    1802       36888 :                 if (state.dataLoopNodes->Node(OutletNode).MassFlowRate > 0.0) {
    1803       36768 :                     if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    1804           0 :                         state.dataLoopNodes->Node(OutletNode).CO2 =
    1805           0 :                             (state.dataLoopNodes->Node(OAInletNode).CO2 * state.dataLoopNodes->Node(OAInletNode).MassFlowRate +
    1806           0 :                              state.dataLoopNodes->Node(RAInletNode).CO2 * state.dataLoopNodes->Node(RAInletNode).MassFlowRate) /
    1807           0 :                             state.dataLoopNodes->Node(OutletNode).MassFlowRate;
    1808             :                     }
    1809       36768 :                     if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    1810           0 :                         state.dataLoopNodes->Node(OutletNode).GenContam =
    1811           0 :                             (state.dataLoopNodes->Node(OAInletNode).GenContam * state.dataLoopNodes->Node(OAInletNode).MassFlowRate +
    1812           0 :                              state.dataLoopNodes->Node(RAInletNode).GenContam * state.dataLoopNodes->Node(RAInletNode).MassFlowRate) /
    1813           0 :                             state.dataLoopNodes->Node(OutletNode).MassFlowRate;
    1814             :                     }
    1815             :                 } else {
    1816         120 :                     if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    1817           0 :                         state.dataLoopNodes->Node(OutletNode).CO2 =
    1818           0 :                             max(state.dataLoopNodes->Node(OAInletNode).CO2, state.dataLoopNodes->Node(RAInletNode).CO2);
    1819             :                     }
    1820         120 :                     if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    1821           0 :                         state.dataLoopNodes->Node(OutletNode).GenContam =
    1822           0 :                             max(state.dataLoopNodes->Node(OAInletNode).GenContam, state.dataLoopNodes->Node(RAInletNode).GenContam);
    1823             :                     }
    1824             :                 }
    1825             : 
    1826             :             } else {
    1827       30740 :                 if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
    1828           0 :                     state.dataLoopNodes->Node(OutletNode).CO2 = state.dataLoopNodes->Node(OAInletNode).CO2;
    1829             :                 }
    1830       30740 :                 if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
    1831           0 :                     state.dataLoopNodes->Node(OutletNode).GenContam = state.dataLoopNodes->Node(OAInletNode).GenContam;
    1832             :                 }
    1833             :             }
    1834             :         }
    1835      206846 :     }
    1836             : 
    1837         769 :     void ReportDualDuctConnections(EnergyPlusData &state)
    1838             :     {
    1839             : 
    1840             :         // SUBROUTINE INFORMATION:
    1841             :         //       AUTHOR         Michael J. Witte
    1842             :         //       DATE WRITTEN   February 2004
    1843             :         //       MODIFIED       B. Griffith, DOAS VAV dual duct
    1844             :         //       RE-ENGINEERED  na
    1845             : 
    1846             :         // PURPOSE OF THIS SUBROUTINE:
    1847             :         // Report dual duct damper connections to the BND file.
    1848             : 
    1849             :         // Using/Aliasing
    1850         769 :         auto &NumPrimaryAirSys = state.dataHVACGlobal->NumPrimaryAirSys;
    1851             : 
    1852             :         // Formats
    1853             :         static constexpr std::string_view Format_100("! <#Dual Duct Damper Connections>,<Number of Dual Duct Damper Connections>");
    1854             :         static constexpr std::string_view Format_102(
    1855             :             "! <Dual Duct Damper>,<Dual Duct Damper Count>,<Dual Duct Damper Name>,<Inlet Node>,<Outlet Node>,<Inlet "
    1856             :             "Node Type>,<AirLoopHVAC Name>");
    1857             : 
    1858         769 :         if (!allocated(state.dataDualDuct->dd_airterminal))
    1859         761 :             return; // Autodesk Bug: Can arrive here with Damper unallocated (SimulateDualDuct not yet called) with NumDDAirTerminal either set >0 or
    1860             :                     // uninitialized
    1861             : 
    1862             :         // Report Dual Duct Dampers to BND File
    1863           8 :         print(state.files.bnd, "{}\n", "! ===============================================================");
    1864           8 :         print(state.files.bnd, "{}\n", Format_100);
    1865           8 :         print(state.files.bnd, " #Dual Duct Damper Connections,{}\n", state.dataDualDuct->NumDDAirTerminal * 2);
    1866           8 :         print(state.files.bnd, "{}\n", Format_102);
    1867             : 
    1868          42 :         for (int Count1 = 1; Count1 <= state.dataDualDuct->NumDDAirTerminal; ++Count1) {
    1869             : 
    1870             :             // Determine if this damper is connected to a supply air path
    1871          34 :             int Found = 0;
    1872          34 :             int SupplyAirPathNum = 0;
    1873          40 :             for (int Count2 = 1; Count2 <= state.dataZoneEquip->NumSupplyAirPaths; ++Count2) {
    1874          40 :                 SupplyAirPathNum = Count2;
    1875          40 :                 Found = 0;
    1876         210 :                 for (int Count3 = 1; Count3 <= state.dataZoneEquip->SupplyAirPath(Count2).NumOutletNodes; ++Count3) {
    1877         340 :                     if (state.dataDualDuct->dd_airterminal(Count1).HotAirInletNodeNum ==
    1878         170 :                         state.dataZoneEquip->SupplyAirPath(Count2).OutletNode(Count3))
    1879          23 :                         Found = Count3;
    1880         340 :                     if (state.dataDualDuct->dd_airterminal(Count1).ColdAirInletNodeNum ==
    1881         170 :                         state.dataZoneEquip->SupplyAirPath(Count2).OutletNode(Count3))
    1882           0 :                         Found = Count3;
    1883         170 :                     if (state.dataDualDuct->dd_airterminal(Count1).OAInletNodeNum == state.dataZoneEquip->SupplyAirPath(Count2).OutletNode(Count3))
    1884          11 :                         Found = Count3;
    1885         340 :                     if (state.dataDualDuct->dd_airterminal(Count1).RecircAirInletNodeNum ==
    1886         170 :                         state.dataZoneEquip->SupplyAirPath(Count2).OutletNode(Count3))
    1887           0 :                         Found = Count3;
    1888             :                 }
    1889          40 :                 if (Found != 0) break;
    1890             :             }
    1891          34 :             if (Found == 0) SupplyAirPathNum = 0;
    1892             : 
    1893             :             // Determine which air loop this dual duct damper is connected to
    1894          34 :             Found = 0;
    1895          68 :             std::string ChrName;
    1896          40 :             for (int Count2 = 1; Count2 <= NumPrimaryAirSys; ++Count2) {
    1897          40 :                 ChrName = state.dataAirLoop->AirToZoneNodeInfo(Count2).AirLoopName;
    1898          40 :                 Found = 0;
    1899         109 :                 for (int Count3 = 1; Count3 <= state.dataAirLoop->AirToZoneNodeInfo(Count2).NumSupplyNodes; ++Count3) {
    1900          69 :                     if (SupplyAirPathNum != 0) {
    1901         138 :                         if (state.dataZoneEquip->SupplyAirPath(SupplyAirPathNum).InletNodeNum ==
    1902          69 :                             state.dataAirLoop->AirToZoneNodeInfo(Count2).ZoneEquipSupplyNodeNum(Count3))
    1903          34 :                             Found = Count3;
    1904             :                     } else {
    1905           0 :                         if (state.dataDualDuct->dd_airterminal(Count1).HotAirInletNodeNum ==
    1906           0 :                             state.dataAirLoop->AirToZoneNodeInfo(Count2).ZoneEquipSupplyNodeNum(Count3))
    1907           0 :                             Found = Count3;
    1908           0 :                         if (state.dataDualDuct->dd_airterminal(Count1).ColdAirInletNodeNum ==
    1909           0 :                             state.dataAirLoop->AirToZoneNodeInfo(Count2).ZoneEquipSupplyNodeNum(Count3))
    1910           0 :                             Found = Count3;
    1911           0 :                         if (state.dataDualDuct->dd_airterminal(Count1).OAInletNodeNum ==
    1912           0 :                             state.dataAirLoop->AirToZoneNodeInfo(Count2).ZoneEquipSupplyNodeNum(Count3))
    1913           0 :                             Found = Count3;
    1914           0 :                         if (state.dataDualDuct->dd_airterminal(Count1).RecircAirInletNodeNum ==
    1915           0 :                             state.dataAirLoop->AirToZoneNodeInfo(Count2).ZoneEquipSupplyNodeNum(Count3))
    1916           0 :                             Found = Count3;
    1917             :                     }
    1918             :                 }
    1919          40 :                 if (Found != 0) break;
    1920             :             }
    1921          34 :             if (Found == 0) ChrName = "**Unknown**";
    1922             : 
    1923          34 :             std::string_view damperType = cmoNameArray[static_cast<int>(state.dataDualDuct->dd_airterminal(Count1).DamperType)];
    1924          48 :             if ((state.dataDualDuct->dd_airterminal(Count1).DamperType == DualDuctDamper::ConstantVolume) ||
    1925          14 :                 (state.dataDualDuct->dd_airterminal(Count1).DamperType == DualDuctDamper::VariableVolume)) {
    1926         138 :                 print(state.files.bnd,
    1927             :                       " Dual Duct Damper,{},{},{},{},{},Hot Air,{}\n",
    1928             :                       Count1,
    1929             :                       damperType,
    1930          23 :                       state.dataDualDuct->dd_airterminal(Count1).Name,
    1931          46 :                       state.dataLoopNodes->NodeID(state.dataDualDuct->dd_airterminal(Count1).HotAirInletNodeNum),
    1932          46 :                       state.dataLoopNodes->NodeID(state.dataDualDuct->dd_airterminal(Count1).OutletNodeNum),
    1933          23 :                       ChrName);
    1934             : 
    1935         138 :                 print(state.files.bnd,
    1936             :                       " Dual Duct Damper,{},{},{},{},{},Cold Air,{}\n",
    1937             :                       Count1,
    1938             :                       damperType,
    1939          23 :                       state.dataDualDuct->dd_airterminal(Count1).Name,
    1940          46 :                       state.dataLoopNodes->NodeID(state.dataDualDuct->dd_airterminal(Count1).ColdAirInletNodeNum),
    1941          46 :                       state.dataLoopNodes->NodeID(state.dataDualDuct->dd_airterminal(Count1).OutletNodeNum),
    1942          23 :                       ChrName);
    1943             : 
    1944          11 :             } else if (state.dataDualDuct->dd_airterminal(Count1).DamperType == DualDuctDamper::OutdoorAir) {
    1945          66 :                 print(state.files.bnd,
    1946             :                       "Dual Duct Damper, {},{},{},{},{},Outdoor Air,{}\n",
    1947             :                       Count1,
    1948             :                       damperType,
    1949          11 :                       state.dataDualDuct->dd_airterminal(Count1).Name,
    1950          22 :                       state.dataLoopNodes->NodeID(state.dataDualDuct->dd_airterminal(Count1).OAInletNodeNum),
    1951          22 :                       state.dataLoopNodes->NodeID(state.dataDualDuct->dd_airterminal(Count1).OutletNodeNum),
    1952          11 :                       ChrName);
    1953          66 :                 print(state.files.bnd,
    1954             :                       "Dual Duct Damper, {},{},{},{},{},Recirculated Air,{}\n",
    1955             :                       Count1,
    1956             :                       damperType,
    1957          11 :                       state.dataDualDuct->dd_airterminal(Count1).Name,
    1958          22 :                       state.dataLoopNodes->NodeID(state.dataDualDuct->dd_airterminal(Count1).RecircAirInletNodeNum),
    1959          22 :                       state.dataLoopNodes->NodeID(state.dataDualDuct->dd_airterminal(Count1).OutletNodeNum),
    1960          11 :                       ChrName);
    1961             :             }
    1962             :         }
    1963             :     }
    1964             : 
    1965          11 :     void GetDualDuctOutdoorAirRecircUse(EnergyPlusData &state,
    1966             :                                         [[maybe_unused]] std::string const &CompTypeName,
    1967             :                                         std::string_view CompName,
    1968             :                                         bool &RecircIsUsed)
    1969             :     {
    1970             : 
    1971             :         // SUBROUTINE INFORMATION:
    1972             :         //       AUTHOR         B. Griffith
    1973             :         //       DATE WRITTEN   Aug 2011
    1974             :         //       MODIFIED       na
    1975             :         //       RE-ENGINEERED  na
    1976             : 
    1977             :         // PURPOSE OF THIS SUBROUTINE:
    1978             :         // get routine to learn if a dual duct outdoor air unit is using its recirc deck
    1979             : 
    1980          11 :         RecircIsUsed = true;
    1981          11 :         if (state.dataDualDuct->GetDualDuctOutdoorAirRecircUseFirstTimeOnly) {
    1982           1 :             state.dataDualDuct->NumDualDuctVarVolOA = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCMO_DDVarVolOA);
    1983           1 :             state.dataDualDuct->RecircIsUsedARR.allocate(state.dataDualDuct->NumDualDuctVarVolOA);
    1984           1 :             state.dataDualDuct->DamperNamesARR.allocate(state.dataDualDuct->NumDualDuctVarVolOA);
    1985           1 :             if (state.dataDualDuct->NumDualDuctVarVolOA > 0) {
    1986           2 :                 Array1D<Real64> NumArray(2, 0.0);
    1987           2 :                 Array1D_string AlphArray(7);
    1988           2 :                 Array1D_string cAlphaFields(7);       // Alpha field names
    1989           2 :                 Array1D_string cNumericFields(2);     // Numeric field names
    1990           2 :                 Array1D_bool lAlphaBlanks(7, true);   // Logical array, alpha field input BLANK = .TRUE.
    1991           2 :                 Array1D_bool lNumericBlanks(2, true); // Logical array, numeric field input BLANK = .TRUE.
    1992          12 :                 for (int DamperIndex = 1; DamperIndex <= state.dataDualDuct->NumDualDuctVarVolOA; ++DamperIndex) {
    1993             : 
    1994             :                     int NumAlphas;
    1995             :                     int NumNums;
    1996             :                     int IOStat;
    1997          11 :                     state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1998             :                                                                              cCMO_DDVarVolOA,
    1999             :                                                                              DamperIndex,
    2000             :                                                                              AlphArray,
    2001             :                                                                              NumAlphas,
    2002             :                                                                              NumArray,
    2003             :                                                                              NumNums,
    2004             :                                                                              IOStat,
    2005             :                                                                              lNumericBlanks,
    2006             :                                                                              lAlphaBlanks,
    2007             :                                                                              cAlphaFields,
    2008             :                                                                              cNumericFields);
    2009          11 :                     state.dataDualDuct->DamperNamesARR(DamperIndex) = AlphArray(1);
    2010          11 :                     if (!lAlphaBlanks(5)) {
    2011           6 :                         state.dataDualDuct->RecircIsUsedARR(DamperIndex) = true;
    2012             :                     } else {
    2013           5 :                         state.dataDualDuct->RecircIsUsedARR(DamperIndex) = false;
    2014             :                     }
    2015             :                 }
    2016             :             }
    2017           1 :             state.dataDualDuct->GetDualDuctOutdoorAirRecircUseFirstTimeOnly = false;
    2018             :         }
    2019             : 
    2020          11 :         int DamperIndex = UtilityRoutines::FindItemInList(CompName, state.dataDualDuct->DamperNamesARR, state.dataDualDuct->NumDualDuctVarVolOA);
    2021          11 :         if (DamperIndex > 0) {
    2022          11 :             RecircIsUsed = state.dataDualDuct->RecircIsUsedARR(DamperIndex);
    2023             :         }
    2024          11 :     }
    2025             : 
    2026      139218 :     void DualDuctAirTerminal::CalcOutdoorAirVolumeFlowRate(EnergyPlusData &state)
    2027             :     {
    2028             :         // calculates zone outdoor air volume flow rate using the supply air flow rate and OA fraction, for AirLoopNum > 0 only for now
    2029      139218 :         if (this->AirLoopNum > 0) {
    2030      139195 :             this->OutdoorAirFlowRate =
    2031      139195 :                 (this->dd_airterminalOutlet.AirMassFlowRate / state.dataEnvrn->StdRhoAir) * state.dataAirLoop->AirLoopFlow(this->AirLoopNum).OAFrac;
    2032             :         }
    2033      139218 :     }
    2034             : 
    2035             : } // namespace DualDuct
    2036             : 
    2037        2313 : } // namespace EnergyPlus

Generated by: LCOV version 1.13