LCOV - code coverage report
Current view: top level - EnergyPlus - PoweredInductionUnits.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 1054 1371 76.9 %
Date: 2024-08-24 18:31:18 Functions: 20 21 95.2 %

          Line data    Source code
       1             : // EnergyPlus, Copyright (c) 1996-2024, The Board of Trustees of the University of Illinois,
       2             : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3             : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4             : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5             : // contributors. All rights reserved.
       6             : //
       7             : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8             : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9             : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10             : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11             : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12             : //
      13             : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14             : // provided that the following conditions are met:
      15             : //
      16             : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17             : //     conditions and the following disclaimer.
      18             : //
      19             : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20             : //     conditions and the following disclaimer in the documentation and/or other materials
      21             : //     provided with the distribution.
      22             : //
      23             : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24             : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25             : //     used to endorse or promote products derived from this software without specific prior
      26             : //     written permission.
      27             : //
      28             : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29             : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30             : //     reference solely to the software portion of its product, Licensee must refer to the
      31             : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32             : //     obtained under this License and may not use a different name for the software. Except as
      33             : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34             : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35             : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36             : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37             : //
      38             : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39             : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40             : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41             : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42             : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43             : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44             : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45             : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46             : // POSSIBILITY OF SUCH DAMAGE.
      47             : 
      48             : // C++ Headers
      49             : #include <cmath>
      50             : 
      51             : // ObjexxFCL Headers
      52             : #include <ObjexxFCL/Array.functions.hh>
      53             : #include <ObjexxFCL/Fmath.hh>
      54             : 
      55             : // EnergyPlus Headers
      56             : #include <EnergyPlus/Autosizing/Base.hh>
      57             : #include <EnergyPlus/BranchNodeConnections.hh>
      58             : #include <EnergyPlus/Data/EnergyPlusData.hh>
      59             : #include <EnergyPlus/DataDefineEquip.hh>
      60             : #include <EnergyPlus/DataEnvironment.hh>
      61             : #include <EnergyPlus/DataHeatBalFanSys.hh>
      62             : #include <EnergyPlus/DataIPShortCuts.hh>
      63             : #include <EnergyPlus/DataLoopNode.hh>
      64             : #include <EnergyPlus/DataPrecisionGlobals.hh>
      65             : #include <EnergyPlus/DataSizing.hh>
      66             : #include <EnergyPlus/DataZoneEnergyDemands.hh>
      67             : #include <EnergyPlus/DataZoneEquipment.hh>
      68             : #include <EnergyPlus/Fans.hh>
      69             : #include <EnergyPlus/FluidProperties.hh>
      70             : #include <EnergyPlus/General.hh>
      71             : #include <EnergyPlus/GeneralRoutines.hh>
      72             : #include <EnergyPlus/GlobalNames.hh>
      73             : #include <EnergyPlus/HeatingCoils.hh>
      74             : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      75             : #include <EnergyPlus/MixerComponent.hh>
      76             : #include <EnergyPlus/NodeInputManager.hh>
      77             : #include <EnergyPlus/OutputProcessor.hh>
      78             : #include <EnergyPlus/OutputReportPredefined.hh>
      79             : #include <EnergyPlus/Plant/DataPlant.hh>
      80             : #include <EnergyPlus/PlantUtilities.hh>
      81             : #include <EnergyPlus/PoweredInductionUnits.hh>
      82             : #include <EnergyPlus/Psychrometrics.hh>
      83             : #include <EnergyPlus/ScheduleManager.hh>
      84             : #include <EnergyPlus/SteamCoils.hh>
      85             : #include <EnergyPlus/UtilityRoutines.hh>
      86             : #include <EnergyPlus/WaterCoils.hh>
      87             : #include <EnergyPlus/ZoneAirLoopEquipmentManager.hh>
      88             : 
      89             : namespace EnergyPlus::PoweredInductionUnits {
      90             : 
      91             : // Module containing routines dealing with Series and Parallel fan powered terminal boxes
      92             : 
      93             : // MODULE INFORMATION:
      94             : //       AUTHOR         Fred Buhl
      95             : //       DATE WRITTEN   August 2000
      96             : //       MODIFIED       Brent Griffith, Sept 2010, plant upgrades, fluid properties
      97             : //       RE-ENGINEERED  na
      98             : 
      99             : // PURPOSE OF THIS MODULE:
     100             : // To encapsulate the data and algorithms needed to simulate Series and Parallel
     101             : // fan powered induction terminal boxes.
     102             : 
     103             : // METHODOLOGY EMPLOYED:
     104             : // The terminal boxes are modeled as a collection of components: air mixer,
     105             : // fan, and heating coil plus an integrated control
     106             : // algorithm that adjusts the primary air flow and the heating coil output
     107             : // to meet the zone load.
     108             : 
     109             : // Using/Aliasing
     110             : using namespace DataLoopNode;
     111             : using HVAC::SmallAirVolFlow;
     112             : using HVAC::SmallLoad;
     113             : using HVAC::SmallMassFlow;
     114             : using HVAC::SmallTempDiff;
     115             : using namespace ScheduleManager;
     116             : using Psychrometrics::PsyCpAirFnW;
     117             : using Psychrometrics::PsyHFnTdbW;
     118             : using SteamCoils::SimulateSteamCoilComponents;
     119             : 
     120             : constexpr const char *fluidNameSteam("STEAM");
     121             : constexpr const char *fluidNameWater("WATER");
     122             : 
     123      308748 : void SimPIU(EnergyPlusData &state,
     124             :             std::string_view CompName,     // name of the PIU
     125             :             bool const FirstHVACIteration, // TRUE if first HVAC iteration in time step
     126             :             int const ZoneNum,             // index of zone served by PIU
     127             :             int const ZoneNodeNum,         // zone node number of zone served by PIU
     128             :             int &CompIndex                 // PIU Index in PIU names
     129             : )
     130             : {
     131             : 
     132             :     // SUBROUTINE INFORMATION:
     133             :     //       AUTHOR         Fred Buhl
     134             :     //       DATE WRITTEN   March 2000
     135             :     //       MODIFIED       na
     136             :     //       RE-ENGINEERED  na
     137             : 
     138             :     // PURPOSE OF THIS SUBROUTINE:
     139             :     // Manages the simulation of a fan powered induction terminal unit.
     140             :     // Called from SimZoneAirLoopEquipmentin module ZoneAirLoopEquipmentManager.
     141             : 
     142             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     143      308748 :     int PIUNum = 0; // index of powered induction unit being simulated
     144             : 
     145             :     // First time SimPIU is called, get the input for all the fan coil units
     146      308748 :     if (state.dataPowerInductionUnits->GetPIUInputFlag) {
     147          14 :         GetPIUs(state);
     148          14 :         state.dataPowerInductionUnits->GetPIUInputFlag = false;
     149             :     }
     150             : 
     151             :     // Get the powered induction unit index
     152      308748 :     if (CompIndex == 0) {
     153          57 :         PIUNum = Util::FindItemInList(CompName, state.dataPowerInductionUnits->PIU);
     154          57 :         if (PIUNum == 0) {
     155           0 :             ShowFatalError(state, format("SimPIU: PIU Unit not found={}", CompName));
     156             :         }
     157          57 :         CompIndex = PIUNum;
     158             :     } else {
     159      308691 :         PIUNum = CompIndex;
     160      308691 :         if (PIUNum > state.dataPowerInductionUnits->NumPIUs || PIUNum < 1) {
     161           0 :             ShowFatalError(state,
     162           0 :                            format("SimPIU: Invalid CompIndex passed={}, Number of PIU Units={}, PIU Unit name={}",
     163             :                                   CompIndex,
     164           0 :                                   state.dataPowerInductionUnits->NumPIUs,
     165             :                                   CompName));
     166             :         }
     167      308691 :         if (state.dataPowerInductionUnits->CheckEquipName(PIUNum)) {
     168          57 :             if (CompName != state.dataPowerInductionUnits->PIU(PIUNum).Name) {
     169           0 :                 ShowFatalError(state,
     170           0 :                                format("SimPIU: Invalid CompIndex passed={}, PIU Unit name={}, stored PIU Unit Name for that index={}",
     171             :                                       CompIndex,
     172             :                                       CompName,
     173           0 :                                       state.dataPowerInductionUnits->PIU(PIUNum).Name));
     174             :             }
     175          57 :             state.dataPowerInductionUnits->CheckEquipName(PIUNum) = false;
     176             :         }
     177             :     }
     178             : 
     179      617496 :     state.dataSize->CurTermUnitSizingNum =
     180      308748 :         state.dataDefineEquipment->AirDistUnit(state.dataPowerInductionUnits->PIU(PIUNum).ADUNum).TermUnitSizingNum;
     181             :     // initialize the unit
     182      308748 :     InitPIU(state, PIUNum, FirstHVACIteration);
     183             : 
     184      308748 :     state.dataSize->TermUnitPIU = true;
     185             : 
     186             :     // Select the correct unit type
     187      308748 :     switch (state.dataPowerInductionUnits->PIU(PIUNum).UnitType_Num) {
     188             : 
     189      287202 :     case DataDefineEquip::ZnAirLoopEquipType::SingleDuct_SeriesPIU_Reheat: { //  'AirTerminal:SingleDuct:SeriesPIU:Reheat'
     190             : 
     191      287202 :         CalcSeriesPIU(state, PIUNum, ZoneNum, ZoneNodeNum, FirstHVACIteration);
     192      287202 :         break;
     193             :     }
     194       21546 :     case DataDefineEquip::ZnAirLoopEquipType::SingleDuct_ParallelPIU_Reheat: { // 'AirTerminal:SingleDuct:ParallelPIU:Reheat'
     195             : 
     196       21546 :         CalcParallelPIU(state, PIUNum, ZoneNum, ZoneNodeNum, FirstHVACIteration);
     197       21546 :         break;
     198             :     }
     199           0 :     default:
     200           0 :         ShowSevereError(state, format("Illegal PI Unit Type used={}", state.dataPowerInductionUnits->PIU(PIUNum).UnitType));
     201           0 :         ShowContinueError(state, format("Occurs in PI Unit={}", state.dataPowerInductionUnits->PIU(PIUNum).Name));
     202           0 :         ShowFatalError(state, "Preceding condition causes termination.");
     203           0 :         break;
     204             :     }
     205             : 
     206      308748 :     state.dataSize->TermUnitPIU = false;
     207             : 
     208             :     // Update the current unit's outlet nodes
     209             :     // no update needed: reheat coil updates outlet node; inlet nodes' mass flow rate set by Calc routine
     210             : 
     211             :     // Fill the report variables
     212      308748 :     ReportPIU(state, PIUNum);
     213      308748 : }
     214             : 
     215          18 : void GetPIUs(EnergyPlusData &state)
     216             : {
     217             : 
     218             :     // SUBROUTINE INFORMATION:
     219             :     //       AUTHOR         Fred Buhl
     220             :     //       DATE WRITTEN   August 2000
     221             :     //       MODIFIED       na
     222             :     //       RE-ENGINEERED  na
     223             : 
     224             :     // PURPOSE OF THIS SUBROUTINE:
     225             :     // Obtains input data for powered induction unit terminal boxes and stores it
     226             :     // in PIU data structures
     227             : 
     228             :     // METHODOLOGY EMPLOYED:
     229             :     // Uses "Get" routines to read in data.
     230             : 
     231             :     // Using/Aliasing
     232             :     using BranchNodeConnections::SetUpCompSets;
     233             :     using BranchNodeConnections::TestCompSet;
     234             : 
     235             :     using NodeInputManager::GetOnlySingleNode;
     236             :     using SteamCoils::GetCoilSteamInletNode;
     237             :     using WaterCoils::GetCoilWaterInletNode;
     238             : 
     239             :     static constexpr std::string_view routineName = "GetPIUs";
     240             : 
     241             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     242          18 :     bool ErrorsFound(false);                                    // Set to true if errors in input, fatal at end of routine
     243             :     static constexpr std::string_view RoutineName("GetPIUs: "); // include trailing blank space
     244          18 :     bool SteamMessageNeeded = true;
     245             : 
     246             :     // find the number of each type of fan coil unit
     247          36 :     state.dataPowerInductionUnits->NumSeriesPIUs =
     248          18 :         state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "AirTerminal:SingleDuct:SeriesPIU:Reheat");
     249          36 :     state.dataPowerInductionUnits->NumParallelPIUs =
     250          18 :         state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "AirTerminal:SingleDuct:ParallelPIU:Reheat");
     251          18 :     state.dataPowerInductionUnits->NumPIUs = state.dataPowerInductionUnits->NumSeriesPIUs + state.dataPowerInductionUnits->NumParallelPIUs;
     252             : 
     253          18 :     if (state.dataPowerInductionUnits->NumPIUs > 0) {
     254             :         // GetZonePlenumInput might call this routine before the AirDistUnit has been populated
     255          14 :         if (state.dataZoneAirLoopEquipmentManager->GetAirDistUnitsFlag) {
     256           0 :             ZoneAirLoopEquipmentManager::GetZoneAirLoopEquipment(state);
     257           0 :             state.dataZoneAirLoopEquipmentManager->GetAirDistUnitsFlag = false;
     258             :         }
     259             :     }
     260             : 
     261             :     // allocate the data structures
     262          18 :     state.dataPowerInductionUnits->PIU.allocate(state.dataPowerInductionUnits->NumPIUs);
     263          18 :     state.dataPowerInductionUnits->PiuUniqueNames.reserve(static_cast<unsigned>(state.dataPowerInductionUnits->NumPIUs));
     264          18 :     state.dataPowerInductionUnits->CheckEquipName.dimension(state.dataPowerInductionUnits->NumPIUs, true);
     265             : 
     266          18 :     int PIUNum{0};
     267          18 :     auto &ip = state.dataInputProcessing->inputProcessor;
     268             :     // loop over Series PIUs; get and load the input data
     269          54 :     for (const std::string cCurrentModuleObject : {"AirTerminal:SingleDuct:SeriesPIU:Reheat", "AirTerminal:SingleDuct:ParallelPIU:Reheat"}) {
     270          36 :         auto const &objectSchemaProps = ip->getObjectSchemaProps(state, cCurrentModuleObject);
     271          36 :         auto const &PIUsInstances = ip->epJSON.find(cCurrentModuleObject);
     272          36 :         if (PIUsInstances != ip->epJSON.end()) {
     273          18 :             auto &PIUInstances = PIUsInstances.value();
     274          75 :             for (auto instance = PIUInstances.begin(); instance != PIUInstances.end(); ++instance) {
     275          57 :                 ++PIUNum;
     276          57 :                 auto const &fields = instance.value();
     277             : 
     278          57 :                 GlobalNames::VerifyUniqueInterObjectName(
     279          57 :                     state, state.dataPowerInductionUnits->PiuUniqueNames, Util::makeUPPER(instance.key()), cCurrentModuleObject, "Name", ErrorsFound);
     280          57 :                 auto &thisPIU = state.dataPowerInductionUnits->PIU(PIUNum);
     281          57 :                 thisPIU.Name = Util::makeUPPER(instance.key());
     282          57 :                 thisPIU.UnitType = cCurrentModuleObject;
     283          57 :                 ip->markObjectAsUsed(cCurrentModuleObject, instance.key());
     284          57 :                 if (cCurrentModuleObject == "AirTerminal:SingleDuct:SeriesPIU:Reheat") {
     285          51 :                     thisPIU.UnitType_Num = DataDefineEquip::ZnAirLoopEquipType::SingleDuct_SeriesPIU_Reheat;
     286           6 :                 } else if (cCurrentModuleObject == "AirTerminal:SingleDuct:ParallelPIU:Reheat") {
     287           6 :                     thisPIU.UnitType_Num = DataDefineEquip::ZnAirLoopEquipType::SingleDuct_ParallelPIU_Reheat;
     288             :                 }
     289          57 :                 thisPIU.Sched = ip->getAlphaFieldValue(fields, objectSchemaProps, "availability_schedule_name");
     290          57 :                 if (!thisPIU.Sched.empty()) {
     291          53 :                     thisPIU.SchedPtr = ScheduleManager::GetScheduleIndex(state, thisPIU.Sched);
     292          53 :                     if (thisPIU.SchedPtr == 0) {
     293           0 :                         ShowWarningError(
     294             :                             state,
     295           0 :                             format("GetPIUs {}=\"{}\", invalid Availability Schedule Name = {}", cCurrentModuleObject, thisPIU.Name, thisPIU.Sched));
     296           0 :                         ShowContinueError(state, "Set the default as Always On. Simulation continues.");
     297           0 :                         thisPIU.SchedPtr = ScheduleManager::ScheduleAlwaysOn;
     298             :                     }
     299             :                 } else {
     300           4 :                     thisPIU.SchedPtr = ScheduleManager::ScheduleAlwaysOn;
     301             :                 }
     302          57 :                 if (cCurrentModuleObject == "AirTerminal:SingleDuct:SeriesPIU:Reheat") {
     303          51 :                     thisPIU.MaxTotAirVolFlow = ip->getRealFieldValue(fields, objectSchemaProps, "maximum_air_flow_rate");
     304             :                 }
     305          57 :                 if (cCurrentModuleObject == "AirTerminal:SingleDuct:ParallelPIU:Reheat") {
     306           6 :                     thisPIU.MaxSecAirVolFlow = ip->getRealFieldValue(fields, objectSchemaProps, "maximum_secondary_air_flow_rate");
     307             :                 }
     308          57 :                 thisPIU.MaxPriAirVolFlow = ip->getRealFieldValue(fields, objectSchemaProps, "maximum_primary_air_flow_rate");
     309          57 :                 thisPIU.MinPriAirFlowFrac = ip->getRealFieldValue(fields, objectSchemaProps, "minimum_primary_air_flow_fraction");
     310          57 :                 if (cCurrentModuleObject == "AirTerminal:SingleDuct:ParallelPIU:Reheat") {
     311           6 :                     thisPIU.FanOnFlowFrac = ip->getRealFieldValue(fields, objectSchemaProps, "fan_on_flow_fraction");
     312             :                 }
     313          57 :                 thisPIU.HCoilType = static_cast<HtgCoilType>(
     314          57 :                     getEnumValue(HCoilNamesUC, Util::makeUPPER(ip->getAlphaFieldValue(fields, objectSchemaProps, "reheat_coil_object_type"))));
     315          57 :                 switch (thisPIU.HCoilType) {
     316          56 :                 case HtgCoilType::SimpleHeating: {
     317          56 :                     thisPIU.HCoil_PlantType = DataPlant::PlantEquipmentType::CoilWaterSimpleHeating;
     318          56 :                     break;
     319             :                 }
     320           1 :                 case HtgCoilType::Electric:
     321             :                 case HtgCoilType::Gas: {
     322           1 :                     break;
     323             :                 }
     324           0 :                 case HtgCoilType::SteamAirHeating: {
     325           0 :                     thisPIU.HCoil_PlantType = DataPlant::PlantEquipmentType::CoilSteamAirHeating;
     326           0 :                     thisPIU.HCoil_FluidIndex = FluidProperties::GetRefrigNum(state, "STEAM");
     327           0 :                     if (thisPIU.HCoil_FluidIndex == 0) {
     328           0 :                         ShowSevereError(state, format("{} Steam Properties for {} not found.", RoutineName, thisPIU.Name));
     329           0 :                         if (SteamMessageNeeded) {
     330           0 :                             ShowContinueError(state, "Steam Fluid Properties should have been included in the input file.");
     331             :                         }
     332           0 :                         ErrorsFound = true;
     333           0 :                         SteamMessageNeeded = false;
     334             :                     }
     335           0 :                     break;
     336             :                 }
     337           0 :                 default: {
     338           0 :                     ShowSevereError(state, format("Illegal Reheat Coil Type = {}", thisPIU.HCoilType));
     339           0 :                     ShowContinueError(state, format("Occurs in {} = {}", cCurrentModuleObject, thisPIU.Name));
     340           0 :                     ErrorsFound = true;
     341             :                 }
     342             :                 }
     343             : 
     344          57 :                 auto connectionType = DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctSeriesPIUReheat;
     345          57 :                 if (cCurrentModuleObject == "AirTerminal:SingleDuct:ParallelPIU:Reheat") {
     346           6 :                     connectionType = DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctParallelPIUReheat;
     347             :                 }
     348         114 :                 thisPIU.PriAirInNode = GetOnlySingleNode(state,
     349         114 :                                                          ip->getAlphaFieldValue(fields, objectSchemaProps, "supply_air_inlet_node_name"),
     350             :                                                          ErrorsFound,
     351             :                                                          connectionType,
     352          57 :                                                          thisPIU.Name,
     353             :                                                          DataLoopNode::NodeFluidType::Air,
     354             :                                                          DataLoopNode::ConnectionType::Inlet,
     355             :                                                          NodeInputManager::CompFluidStream::Primary,
     356             :                                                          ObjectIsParent,
     357             :                                                          "Supply Air Inlet Node Name");
     358             : 
     359         114 :                 thisPIU.SecAirInNode = GetOnlySingleNode(state,
     360         114 :                                                          ip->getAlphaFieldValue(fields, objectSchemaProps, "secondary_air_inlet_node_name"),
     361             :                                                          ErrorsFound,
     362             :                                                          connectionType,
     363          57 :                                                          thisPIU.Name,
     364             :                                                          DataLoopNode::NodeFluidType::Air,
     365             :                                                          DataLoopNode::ConnectionType::Inlet,
     366             :                                                          NodeInputManager::CompFluidStream::Primary,
     367             :                                                          ObjectIsParent,
     368             :                                                          "Secondary Air Inlet Node Name");
     369             : 
     370         114 :                 thisPIU.OutAirNode = GetOnlySingleNode(state,
     371         114 :                                                        ip->getAlphaFieldValue(fields, objectSchemaProps, "outlet_node_name"),
     372             :                                                        ErrorsFound,
     373             :                                                        connectionType,
     374          57 :                                                        thisPIU.Name,
     375             :                                                        DataLoopNode::NodeFluidType::Air,
     376             :                                                        DataLoopNode::ConnectionType::Outlet,
     377             :                                                        NodeInputManager::CompFluidStream::Primary,
     378             :                                                        ObjectIsParent,
     379             :                                                        "Outlet Node Name");
     380             : 
     381         114 :                 thisPIU.HCoilInAirNode = GetOnlySingleNode(state,
     382         114 :                                                            ip->getAlphaFieldValue(fields, objectSchemaProps, "reheat_coil_air_inlet_node_name"),
     383             :                                                            ErrorsFound,
     384             :                                                            connectionType,
     385          57 :                                                            thisPIU.Name,
     386             :                                                            DataLoopNode::NodeFluidType::Air,
     387             :                                                            DataLoopNode::ConnectionType::Internal,
     388             :                                                            NodeInputManager::CompFluidStream::Primary,
     389             :                                                            ObjectIsParent,
     390             :                                                            "Reheat Coil Air Inlet Node Name");
     391             :                 // The reheat coil control node is necessary for hot water reheat, but not necessary for
     392             :                 // electric or gas reheat.
     393          57 :                 if (thisPIU.HCoilType == HtgCoilType::SimpleHeating) {
     394          56 :                     thisPIU.HotControlNode = GetCoilWaterInletNode(state,
     395         112 :                                                                    ip->getAlphaFieldValue(fields, objectSchemaProps, "reheat_coil_object_type"),
     396         112 :                                                                    ip->getAlphaFieldValue(fields, objectSchemaProps, "reheat_coil_name"),
     397             :                                                                    ErrorsFound);
     398             :                 }
     399          57 :                 if (thisPIU.HCoilType == HtgCoilType::SteamAirHeating) {
     400           0 :                     thisPIU.HotControlNode = GetCoilSteamInletNode(state,
     401           0 :                                                                    ip->getAlphaFieldValue(fields, objectSchemaProps, "reheat_coil_object_type"),
     402           0 :                                                                    ip->getAlphaFieldValue(fields, objectSchemaProps, "reheat_coil_name"),
     403             :                                                                    ErrorsFound);
     404             :                 }
     405          57 :                 thisPIU.MixerName = ip->getAlphaFieldValue(fields, objectSchemaProps, "zone_mixer_name");
     406          57 :                 thisPIU.FanName = ip->getAlphaFieldValue(fields, objectSchemaProps, "fan_name");
     407             : 
     408             :                 // find fan type
     409             :                 // test if Fan:SystemModel fan of this name exists
     410          57 :                 ErrorObjectHeader eoh{routineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(8)};
     411          57 :                 if ((thisPIU.Fan_Index = Fans::GetFanIndex(state, thisPIU.FanName)) == 0) {
     412           0 :                     ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(8), thisPIU.FanName);
     413           0 :                     ErrorsFound = true;
     414             :                 } else {
     415             :                     // Assert that this is a constant volume fan?
     416          57 :                     auto *fan = state.dataFans->fans(thisPIU.Fan_Index);
     417          57 :                     thisPIU.fanType = fan->type;
     418          57 :                     thisPIU.FanAvailSchedPtr = fan->availSchedNum;
     419             :                 }
     420             : 
     421          57 :                 thisPIU.HCoil = ip->getAlphaFieldValue(fields, objectSchemaProps, "reheat_coil_name");
     422          57 :                 bool IsNotOK = false;
     423         114 :                 ValidateComponent(
     424         171 :                     state, HCoilNamesUC[static_cast<int>(thisPIU.HCoilType)], thisPIU.HCoil, IsNotOK, cCurrentModuleObject + " - Heating Coil");
     425          57 :                 if (IsNotOK) {
     426           0 :                     ShowContinueError(state, format("In {} = {}", cCurrentModuleObject, thisPIU.Name));
     427           0 :                     ErrorsFound = true;
     428             :                 }
     429          57 :                 thisPIU.MaxVolHotWaterFlow = ip->getRealFieldValue(fields, objectSchemaProps, "maximum_hot_water_or_steam_flow_rate");
     430          57 :                 thisPIU.MinVolHotWaterFlow = ip->getRealFieldValue(fields, objectSchemaProps, "minimum_hot_water_or_steam_flow_rate");
     431          57 :                 thisPIU.HotControlOffset = ip->getRealFieldValue(fields, objectSchemaProps, "convergence_tolerance");
     432             :                 // Set default convergence tolerance
     433          57 :                 if (thisPIU.HotControlOffset <= 0.0) {
     434           0 :                     thisPIU.HotControlOffset = 0.001;
     435             :                 }
     436             : 
     437             :                 // Variable speed fan inputs
     438         114 :                 std::string fan_control_type = "ConstantSpeed";
     439          57 :                 fan_control_type = ip->getAlphaFieldValue(fields, objectSchemaProps, "fan_control_type");
     440          57 :                 thisPIU.fanControlType = FanCntrlType::ConstantSpeedFan;
     441          57 :                 if (Util::SameString(fan_control_type, "VariableSpeed")) {
     442           4 :                     thisPIU.fanControlType = FanCntrlType::VariableSpeedFan;
     443           4 :                     if (thisPIU.fanType != HVAC::FanType::SystemModel) {
     444           0 :                         ErrorsFound = true;
     445           0 :                         ShowSevereError(state, format("Fan type must be Fan:SystemModel when Fan Control Type = {}", fan_control_type));
     446           0 :                         ShowContinueError(state, format("Occurs in {} = {}", cCurrentModuleObject, thisPIU.Name));
     447             :                     }
     448          53 :                 } else if (Util::SameString(fan_control_type, "ConstantSpeed")) {
     449          53 :                     thisPIU.fanControlType = FanCntrlType::ConstantSpeedFan;
     450             :                 } else {
     451           0 :                     ShowSevereError(state, format("Illegal Fan Control Type = {}", fan_control_type));
     452           0 :                     ShowContinueError(state, format("Occurs in {} = {}", cCurrentModuleObject, thisPIU.Name));
     453           0 :                     ErrorsFound = true;
     454             :                 }
     455             : 
     456         171 :                 std::string const heating_control_type = ip->getAlphaFieldValue(fields, objectSchemaProps, "heating_control_type");
     457          57 :                 thisPIU.heatingControlType = HeatCntrlBehaviorType::Invalid;
     458          57 :                 if (thisPIU.fanControlType == FanCntrlType::VariableSpeedFan) {
     459           4 :                     if (Util::SameString(heating_control_type, "Staged")) {
     460           2 :                         thisPIU.heatingControlType = HeatCntrlBehaviorType::StagedHeaterBehavior;
     461           2 :                     } else if (Util::SameString(heating_control_type, "Modulated")) {
     462           2 :                         thisPIU.heatingControlType = HeatCntrlBehaviorType::ModulatedHeaterBehavior;
     463             :                     } else {
     464           0 :                         ShowSevereError(state, format("Illegal Heating Control Type = {}", heating_control_type));
     465           0 :                         ShowContinueError(state, format("Occurs in {} = {}", cCurrentModuleObject, thisPIU.Name));
     466           0 :                         ErrorsFound = true;
     467             :                     }
     468             :                 }
     469             : 
     470          57 :                 thisPIU.MinFanTurnDownRatio = ip->getRealFieldValue(fields, objectSchemaProps, "minimum_fan_turn_down_ratio");
     471          57 :                 thisPIU.designHeatingDAT = ip->getRealFieldValue(fields, objectSchemaProps, "design_heating_discharge_air_temperature");
     472          57 :                 thisPIU.highLimitDAT = ip->getRealFieldValue(fields, objectSchemaProps, "high_limit_heating_discharge_air_temperature");
     473             : 
     474             :                 // Add fan to component sets array
     475          57 :                 if (cCurrentModuleObject == "AirTerminal:SingleDuct:SeriesPIU:Reheat") {
     476         102 :                     SetUpCompSets(state,
     477             :                                   thisPIU.UnitType,
     478             :                                   thisPIU.Name,
     479             :                                   "UNDEFINED",
     480             :                                   thisPIU.FanName,
     481             :                                   "UNDEFINED",
     482         102 :                                   ip->getAlphaFieldValue(fields, objectSchemaProps, "reheat_coil_air_inlet_node_name"));
     483           6 :                 } else if (cCurrentModuleObject == "AirTerminal:SingleDuct:ParallelPIU:Reheat") {
     484          12 :                     SetUpCompSets(state,
     485             :                                   thisPIU.UnitType,
     486             :                                   thisPIU.Name,
     487             :                                   "UNDEFINED",
     488             :                                   thisPIU.FanName,
     489          12 :                                   ip->getAlphaFieldValue(fields, objectSchemaProps, "secondary_air_inlet_node_name"),
     490             :                                   "UNDEFINED");
     491             :                 }
     492             : 
     493             :                 // Add reheat coil to component sets array
     494         285 :                 SetUpCompSets(state,
     495             :                               thisPIU.UnitType,
     496             :                               thisPIU.Name,
     497         114 :                               ip->getAlphaFieldValue(fields, objectSchemaProps, "reheat_coil_object_type"),
     498         114 :                               ip->getAlphaFieldValue(fields, objectSchemaProps, "reheat_coil_name"),
     499         114 :                               ip->getAlphaFieldValue(fields, objectSchemaProps, "reheat_coil_air_inlet_node_name"),
     500         114 :                               ip->getAlphaFieldValue(fields, objectSchemaProps, "outlet_node_name"));
     501             : 
     502             :                 // Register component set data
     503         114 :                 TestCompSet(state,
     504             :                             thisPIU.UnitType,
     505             :                             thisPIU.Name,
     506          57 :                             state.dataLoopNodes->NodeID(thisPIU.PriAirInNode),
     507          57 :                             state.dataLoopNodes->NodeID(thisPIU.OutAirNode),
     508             :                             "Air Nodes");
     509             : 
     510         499 :                 for (int ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) {
     511         442 :                     if (thisPIU.OutAirNode == state.dataDefineEquipment->AirDistUnit(ADUNum).OutletNodeNum) {
     512          57 :                         thisPIU.ADUNum = ADUNum;
     513          57 :                         state.dataDefineEquipment->AirDistUnit(ADUNum).InletNodeNum = thisPIU.PriAirInNode;
     514             :                     }
     515             :                 }
     516             :                 // one assumes if there isn't one assigned, it's an error?
     517          57 :                 if (thisPIU.ADUNum == 0) {
     518           0 :                     ShowSevereError(state,
     519           0 :                                     format("{}No matching Air Distribution Unit, for PIU = [{},{}].", RoutineName, thisPIU.UnitType, thisPIU.Name));
     520           0 :                     ShowContinueError(state, format("...should have outlet node = {}", state.dataLoopNodes->NodeID(thisPIU.OutAirNode)));
     521           0 :                     ErrorsFound = true;
     522             :                 } else {
     523             : 
     524          57 :                     bool AirNodeFound = false;
     525             :                     // Fill the Zone Equipment data with the supply air inlet node number of this unit.
     526         580 :                     for (int CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) {
     527         523 :                         if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) {
     528          81 :                             continue;
     529             :                         }
     530        1037 :                         for (int SupAirIn = 1; SupAirIn <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumInletNodes; ++SupAirIn) {
     531         652 :                             if (thisPIU.OutAirNode == state.dataZoneEquip->ZoneEquipConfig(CtrlZone).InletNode(SupAirIn)) {
     532          57 :                                 state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).InNode = thisPIU.PriAirInNode;
     533          57 :                                 state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode = thisPIU.OutAirNode;
     534          57 :                                 state.dataDefineEquipment->AirDistUnit(thisPIU.ADUNum).TermUnitSizingNum =
     535          57 :                                     state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).TermUnitSizingIndex;
     536          57 :                                 state.dataDefineEquipment->AirDistUnit(thisPIU.ADUNum).ZoneEqNum = CtrlZone;
     537          57 :                                 AirNodeFound = true;
     538          57 :                                 thisPIU.CtrlZoneNum = CtrlZone; // fill index for later use in finding air loop index
     539          57 :                                 thisPIU.ctrlZoneInNodeIndex = SupAirIn;
     540          57 :                                 break;
     541             :                             }
     542             :                         }
     543             :                     }
     544          57 :                     if (!AirNodeFound) {
     545           0 :                         ShowSevereError(state, format("The outlet air node from the {} Unit = {}", cCurrentModuleObject, thisPIU.Name));
     546           0 :                         ShowContinueError(
     547           0 :                             state, format("did not have a matching Zone Equipment Inlet Node, Node = {}", state.dataIPShortCut->cAlphaArgs(5)));
     548           0 :                         ErrorsFound = true;
     549             :                     }
     550             :                 }
     551          18 :             }
     552             :         }
     553          36 :     }
     554             : 
     555          18 :     if (ErrorsFound) {
     556           0 :         ShowFatalError(state, format("{} Errors found in getting input.  Preceding conditions cause termination.", RoutineName));
     557             :     }
     558             : 
     559          75 :     for (int PIUNum = 1; PIUNum <= state.dataPowerInductionUnits->NumPIUs; ++PIUNum) {
     560          57 :         auto &thisPIU = state.dataPowerInductionUnits->PIU(PIUNum);
     561             : 
     562             :         // Setup Report variables for the PIUs
     563         114 :         SetupOutputVariable(state,
     564             :                             "Zone Air Terminal Primary Damper Position",
     565             :                             Constant::Units::None,
     566          57 :                             thisPIU.PriDamperPosition,
     567             :                             OutputProcessor::TimeStepType::System,
     568             :                             OutputProcessor::StoreType::Average,
     569          57 :                             thisPIU.Name);
     570         114 :         SetupOutputVariable(state,
     571             :                             "Zone Air Terminal Heating Rate",
     572             :                             Constant::Units::W,
     573          57 :                             thisPIU.HeatingRate,
     574             :                             OutputProcessor::TimeStepType::System,
     575             :                             OutputProcessor::StoreType::Average,
     576          57 :                             thisPIU.Name);
     577         114 :         SetupOutputVariable(state,
     578             :                             "Zone Air Terminal Heating Energy",
     579             :                             Constant::Units::J,
     580          57 :                             thisPIU.HeatingEnergy,
     581             :                             OutputProcessor::TimeStepType::System,
     582             :                             OutputProcessor::StoreType::Sum,
     583          57 :                             thisPIU.Name);
     584         114 :         SetupOutputVariable(state,
     585             :                             "Zone Air Terminal Sensible Cooling Rate",
     586             :                             Constant::Units::W,
     587          57 :                             thisPIU.SensCoolRate,
     588             :                             OutputProcessor::TimeStepType::System,
     589             :                             OutputProcessor::StoreType::Average,
     590          57 :                             thisPIU.Name);
     591         114 :         SetupOutputVariable(state,
     592             :                             "Zone Air Terminal Sensible Cooling Energy",
     593             :                             Constant::Units::J,
     594          57 :                             thisPIU.SensCoolEnergy,
     595             :                             OutputProcessor::TimeStepType::System,
     596             :                             OutputProcessor::StoreType::Sum,
     597          57 :                             thisPIU.Name);
     598         114 :         SetupOutputVariable(state,
     599             :                             "Zone Air Terminal Outdoor Air Volume Flow Rate",
     600             :                             Constant::Units::m3_s,
     601          57 :                             thisPIU.OutdoorAirFlowRate,
     602             :                             OutputProcessor::TimeStepType::System,
     603             :                             OutputProcessor::StoreType::Average,
     604          57 :                             thisPIU.Name);
     605         114 :         SetupOutputVariable(state,
     606             :                             "Zone Air Terminal Total Air Mass Flow Rate",
     607             :                             Constant::Units::kg_s,
     608          57 :                             thisPIU.TotMassFlowRate,
     609             :                             OutputProcessor::TimeStepType::System,
     610             :                             OutputProcessor::StoreType::Average,
     611          57 :                             state.dataPowerInductionUnits->PIU(PIUNum).Name);
     612         114 :         SetupOutputVariable(state,
     613             :                             "Zone Air Terminal Primary Air Mass Flow Rate",
     614             :                             Constant::Units::kg_s,
     615          57 :                             thisPIU.PriMassFlowRate,
     616             :                             OutputProcessor::TimeStepType::System,
     617             :                             OutputProcessor::StoreType::Average,
     618          57 :                             state.dataPowerInductionUnits->PIU(PIUNum).Name);
     619         114 :         SetupOutputVariable(state,
     620             :                             "Zone Air Terminal Secondary Air Mass Flow Rate",
     621             :                             Constant::Units::kg_s,
     622          57 :                             thisPIU.SecMassFlowRate,
     623             :                             OutputProcessor::TimeStepType::System,
     624             :                             OutputProcessor::StoreType::Average,
     625          57 :                             state.dataPowerInductionUnits->PIU(PIUNum).Name);
     626         114 :         SetupOutputVariable(state,
     627             :                             "Zone Air Terminal Outlet Discharge Air Temperature",
     628             :                             Constant::Units::C,
     629          57 :                             thisPIU.DischargeAirTemp,
     630             :                             OutputProcessor::TimeStepType::System,
     631             :                             OutputProcessor::StoreType::Average,
     632          57 :                             state.dataPowerInductionUnits->PIU(PIUNum).Name);
     633          57 :         SetupOutputVariable(state,
     634             :                             "Zone Air Terminal Current Operation Control Stage",
     635             :                             Constant::Units::unknown,
     636          57 :                             thisPIU.CurOperationControlStage,
     637             :                             OutputProcessor::TimeStepType::System,
     638             :                             OutputProcessor::StoreType::Average,
     639          57 :                             state.dataPowerInductionUnits->PIU(PIUNum).Name);
     640             :     }
     641          18 : }
     642             : 
     643      308748 : void InitPIU(EnergyPlusData &state,
     644             :              int const PIUNum,             // number of the current fan coil unit being simulated
     645             :              bool const FirstHVACIteration // TRUE if first zone equip this HVAC step
     646             : )
     647             : {
     648             : 
     649             :     // SUBROUTINE INFORMATION:
     650             :     //       AUTHOR         Fred Buhl
     651             :     //       DATE WRITTEN   August 2000
     652             :     //       MODIFIED       na
     653             :     //       RE-ENGINEERED  na
     654             : 
     655             :     // PURPOSE OF THIS SUBROUTINE:
     656             :     // This subroutine is for initializations of the powered induction unit
     657             :     // terminal boxe.
     658             : 
     659             :     // METHODOLOGY EMPLOYED:
     660             :     // Uses the status flags to trigger initializations.
     661             : 
     662             :     // Using/Aliasing
     663             : 
     664             :     using DataZoneEquipment::CheckZoneEquipmentList;
     665             :     using PlantUtilities::InitComponentNodes;
     666             :     using PlantUtilities::ScanPlantLoopsForObject;
     667             : 
     668      308748 :     auto &thisPIU = state.dataPowerInductionUnits->PIU(PIUNum);
     669             :     // SUBROUTINE PARAMETER DEFINITIONS:
     670             :     static constexpr std::string_view RoutineName("InitPIU");
     671             : 
     672             :     // Do the one time initializations
     673      308748 :     if (state.dataPowerInductionUnits->MyOneTimeFlag) {
     674          14 :         state.dataPowerInductionUnits->MyEnvrnFlag.dimension(state.dataPowerInductionUnits->NumPIUs, true);
     675          14 :         state.dataPowerInductionUnits->MySizeFlag.dimension(state.dataPowerInductionUnits->NumPIUs, true);
     676          14 :         state.dataPowerInductionUnits->MyPlantScanFlag.dimension(state.dataPowerInductionUnits->NumPIUs, true);
     677          14 :         state.dataPowerInductionUnits->MyOneTimeFlag = false;
     678             :     }
     679             : 
     680      308748 :     if (state.dataPowerInductionUnits->MyPlantScanFlag(PIUNum) && allocated(state.dataPlnt->PlantLoop)) {
     681          57 :         if ((thisPIU.HCoil_PlantType == DataPlant::PlantEquipmentType::CoilWaterSimpleHeating) ||
     682           1 :             (thisPIU.HCoil_PlantType == DataPlant::PlantEquipmentType::CoilSteamAirHeating)) {
     683          56 :             bool errFlag = false;
     684          56 :             ScanPlantLoopsForObject(state, thisPIU.HCoil, thisPIU.HCoil_PlantType, thisPIU.HWplantLoc, errFlag, _, _, _, _, _);
     685          56 :             if (errFlag) {
     686           0 :                 ShowFatalError(state, "InitPIU: Program terminated due to previous condition(s).");
     687             :             }
     688          56 :             thisPIU.HotCoilOutNodeNum = DataPlant::CompData::getPlantComponent(state, thisPIU.HWplantLoc).NodeNumOut;
     689             :         }
     690          57 :         state.dataPowerInductionUnits->MyPlantScanFlag(PIUNum) = false;
     691      308691 :     } else if (state.dataPowerInductionUnits->MyPlantScanFlag(PIUNum) && !state.dataGlobal->AnyPlantInModel) {
     692           0 :         state.dataPowerInductionUnits->MyPlantScanFlag(PIUNum) = false;
     693             :     }
     694             : 
     695      308748 :     if (!state.dataPowerInductionUnits->ZoneEquipmentListChecked && state.dataZoneEquip->ZoneEquipInputsFilled) {
     696          14 :         state.dataPowerInductionUnits->ZoneEquipmentListChecked = true;
     697             :         // Check to see if there is a Air Distribution Unit on the Zone Equipment List
     698          71 :         for (int Loop = 1; Loop <= state.dataPowerInductionUnits->NumPIUs; ++Loop) {
     699          57 :             if (state.dataPowerInductionUnits->PIU(Loop).ADUNum == 0) {
     700           0 :                 continue;
     701             :             }
     702         114 :             if (CheckZoneEquipmentList(state,
     703             :                                        "ZoneHVAC:AirDistributionUnit",
     704          57 :                                        state.dataDefineEquipment->AirDistUnit(state.dataPowerInductionUnits->PIU(Loop).ADUNum).Name)) {
     705          57 :                 continue;
     706             :             }
     707           0 :             ShowSevereError(state,
     708           0 :                             format("InitPIU: ADU=[Air Distribution Unit,{}] is not on any ZoneHVAC:EquipmentList.",
     709           0 :                                    state.dataDefineEquipment->AirDistUnit(state.dataPowerInductionUnits->PIU(Loop).ADUNum).Name));
     710           0 :             ShowContinueError(state,
     711           0 :                               format("...PIU=[{},{}] will not be simulated.",
     712           0 :                                      state.dataPowerInductionUnits->PIU(Loop).UnitType,
     713           0 :                                      state.dataPowerInductionUnits->PIU(Loop).Name));
     714             :         }
     715             :     }
     716             : 
     717      308805 :     if (!state.dataGlobal->SysSizingCalc && state.dataPowerInductionUnits->MySizeFlag(PIUNum) &&
     718          57 :         !state.dataPowerInductionUnits->MyPlantScanFlag(PIUNum)) {
     719             : 
     720          57 :         SizePIU(state, PIUNum);
     721             : 
     722             :         // If there's a hot water control node number defined in PIU
     723          57 :         if (thisPIU.HotControlNode > 0) {
     724             :             // plant upgrade note? why no separate handling of steam coil? add it ?
     725             :             // local plant fluid density
     726          56 :             Real64 const rho = FluidProperties::GetDensityGlycol(state,
     727          56 :                                                                  state.dataPlnt->PlantLoop(thisPIU.HWplantLoc.loopNum).FluidName,
     728             :                                                                  Constant::HWInitConvTemp,
     729          56 :                                                                  state.dataPlnt->PlantLoop(thisPIU.HWplantLoc.loopNum).FluidIndex,
     730             :                                                                  RoutineName);
     731             : 
     732          56 :             thisPIU.MaxHotWaterFlow = rho * thisPIU.MaxVolHotWaterFlow;
     733          56 :             thisPIU.MinHotWaterFlow = rho * thisPIU.MinVolHotWaterFlow;
     734          56 :             InitComponentNodes(state, thisPIU.MinHotWaterFlow, thisPIU.MaxHotWaterFlow, thisPIU.HotControlNode, thisPIU.HotCoilOutNodeNum);
     735             :         }
     736             : 
     737          57 :         state.dataPowerInductionUnits->MySizeFlag(PIUNum) = false;
     738             :     }
     739             : 
     740      308748 :     int const PriNode = thisPIU.PriAirInNode;
     741      308748 :     int const SecNode = thisPIU.SecAirInNode;
     742             : 
     743             :     // Do the Begin Environment initializations
     744      308748 :     if (state.dataGlobal->BeginEnvrnFlag && state.dataPowerInductionUnits->MyEnvrnFlag(PIUNum)) {
     745         321 :         Real64 const RhoAir = state.dataEnvrn->StdRhoAir;
     746         321 :         int const OutletNode = thisPIU.OutAirNode;
     747             :         // set the mass flow rates from the input volume flow rates
     748         321 :         if (thisPIU.UnitType == "AirTerminal:SingleDuct:SeriesPIU:Reheat") {
     749         287 :             thisPIU.MaxTotAirMassFlow = RhoAir * thisPIU.MaxTotAirVolFlow;
     750         287 :             thisPIU.MaxPriAirMassFlow = RhoAir * thisPIU.MaxPriAirVolFlow;
     751         287 :             thisPIU.MinPriAirMassFlow = RhoAir * thisPIU.MinPriAirFlowFrac * thisPIU.MaxPriAirVolFlow;
     752         287 :             state.dataLoopNodes->Node(PriNode).MassFlowRateMax = thisPIU.MaxPriAirMassFlow;
     753         287 :             state.dataLoopNodes->Node(PriNode).MassFlowRateMin = thisPIU.MinPriAirMassFlow;
     754         287 :             state.dataLoopNodes->Node(OutletNode).MassFlowRateMax = thisPIU.MaxTotAirMassFlow;
     755             :         } else {
     756             :             // parallel
     757          34 :             thisPIU.MaxPriAirMassFlow = RhoAir * thisPIU.MaxPriAirVolFlow;
     758          34 :             thisPIU.MinPriAirMassFlow = RhoAir * thisPIU.MinPriAirFlowFrac * thisPIU.MaxPriAirVolFlow;
     759          34 :             thisPIU.MaxSecAirMassFlow = RhoAir * thisPIU.MaxSecAirVolFlow;
     760          34 :             thisPIU.FanOnAirMassFlow = RhoAir * thisPIU.FanOnFlowFrac * thisPIU.MaxPriAirVolFlow;
     761          34 :             state.dataLoopNodes->Node(PriNode).MassFlowRateMax = thisPIU.MaxPriAirMassFlow;
     762          34 :             state.dataLoopNodes->Node(PriNode).MassFlowRateMin = thisPIU.MinPriAirMassFlow;
     763          34 :             state.dataLoopNodes->Node(OutletNode).MassFlowRateMax = thisPIU.MaxPriAirMassFlow;
     764             :         }
     765         321 :         if (thisPIU.fanControlType == FanCntrlType::VariableSpeedFan) {
     766          20 :             if (thisPIU.UnitType == "AirTerminal:SingleDuct:SeriesPIU:Reheat") {
     767          10 :                 thisPIU.MinTotAirMassFlow = thisPIU.MaxTotAirMassFlow * thisPIU.MinFanTurnDownRatio;
     768          10 :                 thisPIU.MaxSecAirVolFlow = thisPIU.MaxTotAirMassFlow - thisPIU.MinPriAirMassFlow;
     769          10 :                 thisPIU.MaxSecAirMassFlow = RhoAir * thisPIU.MaxSecAirVolFlow;
     770          10 :                 thisPIU.MinSecAirMassFlow = max(0.0, thisPIU.MinTotAirMassFlow - thisPIU.MinPriAirMassFlow);
     771             :             } else {
     772          10 :                 thisPIU.MaxSecAirMassFlow = RhoAir * thisPIU.MaxSecAirVolFlow;
     773          10 :                 thisPIU.MinSecAirMassFlow = max(0.0, thisPIU.MaxSecAirMassFlow * thisPIU.MinFanTurnDownRatio);
     774          10 :                 thisPIU.MinTotAirMassFlow = thisPIU.MinSecAirMassFlow + thisPIU.MinPriAirMassFlow;
     775             :             }
     776             :         }
     777             : 
     778         637 :         if (((thisPIU.HCoilType == HtgCoilType::SimpleHeating) || (thisPIU.HCoilType == HtgCoilType::SteamAirHeating)) &&
     779         316 :             !state.dataPowerInductionUnits->MyPlantScanFlag(PIUNum)) {
     780         316 :             InitComponentNodes(state, thisPIU.MinHotWaterFlow, thisPIU.MaxHotWaterFlow, thisPIU.HotControlNode, thisPIU.HotCoilOutNodeNum);
     781             :         }
     782             : 
     783         321 :         if (thisPIU.AirLoopNum == 0) { // fill air loop index
     784          57 :             if (thisPIU.CtrlZoneNum > 0 && thisPIU.ctrlZoneInNodeIndex > 0) {
     785          57 :                 thisPIU.AirLoopNum = state.dataZoneEquip->ZoneEquipConfig(thisPIU.CtrlZoneNum).InletNodeAirLoopNum(thisPIU.ctrlZoneInNodeIndex);
     786          57 :                 state.dataDefineEquipment->AirDistUnit(thisPIU.ADUNum).AirLoopNum = thisPIU.AirLoopNum;
     787             :             }
     788             :         }
     789             : 
     790         321 :         state.dataPowerInductionUnits->MyEnvrnFlag(PIUNum) = false;
     791             :     } // end one time inits
     792             : 
     793      308748 :     if (!state.dataGlobal->BeginEnvrnFlag) {
     794      305926 :         state.dataPowerInductionUnits->MyEnvrnFlag(PIUNum) = true;
     795             :     }
     796             : 
     797             :     // Do the start of HVAC time step initializations
     798      308748 :     if (FirstHVACIteration) {
     799             :         // check for upstream zero flow. If nonzero and schedule ON, set primary flow to max
     800      144051 :         if (GetCurrentScheduleValue(state, thisPIU.SchedPtr) > 0.0 && state.dataLoopNodes->Node(PriNode).MassFlowRate > 0.0) {
     801      113738 :             if (thisPIU.UnitType == "AirTerminal:SingleDuct:SeriesPIU:Reheat") {
     802      103002 :                 state.dataLoopNodes->Node(PriNode).MassFlowRate = thisPIU.MaxPriAirMassFlow;
     803      103002 :                 state.dataLoopNodes->Node(SecNode).MassFlowRate = max(0.0, thisPIU.MaxTotAirMassFlow - thisPIU.MaxPriAirMassFlow);
     804             :             } else {
     805       10736 :                 state.dataLoopNodes->Node(PriNode).MassFlowRate = thisPIU.MaxPriAirMassFlow;
     806       10736 :                 state.dataLoopNodes->Node(SecNode).MassFlowRate = thisPIU.MaxSecAirMassFlow;
     807             :             }
     808             :         } else {
     809       30313 :             state.dataLoopNodes->Node(PriNode).MassFlowRate = 0.0;
     810       30313 :             state.dataLoopNodes->Node(SecNode).MassFlowRate = 0.0;
     811             :         }
     812             :         // reset the max and min avail flows
     813      144051 :         if (GetCurrentScheduleValue(state, thisPIU.SchedPtr) > 0.0 && state.dataLoopNodes->Node(PriNode).MassFlowRateMaxAvail > 0.0) {
     814      113738 :             if (thisPIU.UnitType == "AirTerminal:SingleDuct:SeriesPIU:Reheat") {
     815      103002 :                 state.dataLoopNodes->Node(PriNode).MassFlowRateMaxAvail = thisPIU.MaxPriAirMassFlow;
     816      103002 :                 state.dataLoopNodes->Node(PriNode).MassFlowRateMinAvail = thisPIU.MinPriAirMassFlow;
     817      103002 :                 state.dataLoopNodes->Node(SecNode).MassFlowRateMaxAvail = max(0.0, thisPIU.MaxTotAirMassFlow - thisPIU.MinPriAirMassFlow);
     818      103002 :                 state.dataLoopNodes->Node(SecNode).MassFlowRateMinAvail = max(0.0, thisPIU.MaxTotAirMassFlow - thisPIU.MaxPriAirMassFlow);
     819             :             } else {
     820       10736 :                 state.dataLoopNodes->Node(PriNode).MassFlowRateMaxAvail = thisPIU.MaxPriAirMassFlow;
     821       10736 :                 state.dataLoopNodes->Node(PriNode).MassFlowRateMinAvail = thisPIU.MinPriAirMassFlow;
     822       10736 :                 state.dataLoopNodes->Node(SecNode).MassFlowRateMaxAvail = thisPIU.MaxSecAirMassFlow;
     823       10736 :                 state.dataLoopNodes->Node(SecNode).MassFlowRateMinAvail = 0.0;
     824             :             }
     825             :         } else {
     826       30313 :             state.dataLoopNodes->Node(PriNode).MassFlowRateMaxAvail = 0.0;
     827       30313 :             state.dataLoopNodes->Node(PriNode).MassFlowRateMinAvail = 0.0;
     828       30313 :             state.dataLoopNodes->Node(SecNode).MassFlowRateMaxAvail = 0.0;
     829       30313 :             state.dataLoopNodes->Node(SecNode).MassFlowRateMinAvail = 0.0;
     830             :         }
     831             :     }
     832             : 
     833             :     // Do the following initializations every time step
     834             : 
     835             :     // None needed
     836      308748 : }
     837             : 
     838          57 : void SizePIU(EnergyPlusData &state, int const PIUNum)
     839             : {
     840             : 
     841             :     // SUBROUTINE INFORMATION:
     842             :     //       AUTHOR         Fred Buhl
     843             :     //       DATE WRITTEN   January 2002
     844             :     //       MODIFIED       August 2013 Daeho Kang, add component sizing table entries
     845             :     //       RE-ENGINEERED  na
     846             : 
     847             :     // PURPOSE OF THIS SUBROUTINE:
     848             :     // This subroutine is for sizing PIU terminal units for which flow rates have not been
     849             :     // specified in the input.
     850             : 
     851             :     // METHODOLOGY EMPLOYED:
     852             :     // Obtains flow rates from the zone or system sizing arrays.
     853             : 
     854             :     // Using/Aliasing
     855             :     using namespace DataSizing;
     856             :     using FluidProperties::GetDensityGlycol;
     857             :     using FluidProperties::GetSpecificHeatGlycol;
     858             :     using SteamCoils::GetCoilSteamInletNode;
     859             :     using SteamCoils::GetCoilSteamOutletNode;
     860             :     using WaterCoils::GetCoilWaterInletNode;
     861             :     using WaterCoils::GetCoilWaterOutletNode;
     862             :     using WaterCoils::SetCoilDesFlow;
     863             : 
     864             :     using PlantUtilities::MyPlantSizingIndex;
     865             : 
     866             :     // SUBROUTINE PARAMETER DEFINITIONS:
     867             :     static constexpr std::string_view RoutineName("SizePIU");
     868             : 
     869             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     870          57 :     bool IsAutoSize = false;           // Indicator to autosize
     871          57 :     bool IsMaxPriFlowAutoSize = false; // Indicate if the maximum terminal flow is autosize
     872          57 :     int SysSizNum = 0;                 // System sizing number
     873          57 :     Real64 DesCoilLoad = 0.0;
     874          57 :     bool ErrorsFound = false;
     875             : 
     876          57 :     auto &TermUnitSizing(state.dataSize->TermUnitSizing);
     877          57 :     auto &CurTermUnitSizingNum(state.dataSize->CurTermUnitSizingNum);
     878          57 :     auto &thisPIU = state.dataPowerInductionUnits->PIU(PIUNum);
     879             : 
     880          57 :     if (thisPIU.MaxPriAirVolFlow == AutoSize) {
     881          57 :         IsAutoSize = true;
     882             :     }
     883          57 :     if ((state.dataSize->CurZoneEqNum > 0) && (CurTermUnitSizingNum > 0)) {
     884          57 :         if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // Simulation continue
     885           0 :             if (thisPIU.MaxPriAirVolFlow > 0.0) {
     886           0 :                 BaseSizer::reportSizerOutput(
     887             :                     state, thisPIU.UnitType, thisPIU.Name, "User-Specified Maximum Primary Air Flow Rate [m3/s]", thisPIU.MaxPriAirVolFlow);
     888             :             }
     889             :         } else {
     890          57 :             CheckZoneSizing(state, thisPIU.UnitType, thisPIU.Name);
     891             :             // Autosized maximum primary air flow for reporting
     892          57 :             Real64 MaxPriAirVolFlowDes = max(state.dataSize->TermUnitFinalZoneSizing(CurTermUnitSizingNum).DesCoolVolFlow,
     893          57 :                                              state.dataSize->TermUnitFinalZoneSizing(CurTermUnitSizingNum).DesHeatVolFlow);
     894          57 :             if (MaxPriAirVolFlowDes < SmallAirVolFlow) {
     895           0 :                 MaxPriAirVolFlowDes = 0.0;
     896             :             }
     897             : 
     898          57 :             if (IsAutoSize) {
     899          57 :                 thisPIU.MaxPriAirVolFlow = MaxPriAirVolFlowDes;
     900          57 :                 IsMaxPriFlowAutoSize = true;
     901          57 :                 BaseSizer::reportSizerOutput(
     902             :                     state, thisPIU.UnitType, thisPIU.Name, "Design Size Maximum Primary Air Flow Rate [m3/s]", MaxPriAirVolFlowDes);
     903             :             } else {
     904           0 :                 if (thisPIU.MaxPriAirVolFlow > 0.0 && MaxPriAirVolFlowDes > 0.0) {
     905             :                     // Hardsized maximum primary air flow for reporting
     906           0 :                     Real64 const MaxPriAirVolFlowUser = thisPIU.MaxPriAirVolFlow;
     907           0 :                     BaseSizer::reportSizerOutput(state,
     908             :                                                  thisPIU.UnitType,
     909             :                                                  thisPIU.Name,
     910             :                                                  "Design Size Maximum Primary Air Flow Rate [m3/s]",
     911             :                                                  MaxPriAirVolFlowDes,
     912             :                                                  "User-Specified Maximum Primary Air Flow Rate [m3/s]",
     913             :                                                  MaxPriAirVolFlowUser);
     914           0 :                     if (state.dataGlobal->DisplayExtraWarnings) {
     915           0 :                         if ((std::abs(MaxPriAirVolFlowDes - MaxPriAirVolFlowUser) / MaxPriAirVolFlowUser) >
     916           0 :                             state.dataSize->AutoVsHardSizingThreshold) {
     917           0 :                             ShowMessage(state, format("SizePIU: Potential issue with equipment sizing for {} {}", thisPIU.UnitType, thisPIU.Name));
     918           0 :                             ShowContinueError(state, format("User-Specified Primary Air Flow Rate of {:.5R} [m3/s]", MaxPriAirVolFlowUser));
     919           0 :                             ShowContinueError(state, format("differs from Design Size Primary Air Flow Rate of {:.5R} [m3/s]", MaxPriAirVolFlowDes));
     920           0 :                             ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
     921           0 :                             ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
     922             :                         }
     923             :                     }
     924             :                 }
     925             :             }
     926             :         }
     927             :     }
     928             : 
     929          57 :     IsAutoSize = false;
     930          57 :     if (thisPIU.MaxTotAirVolFlow == AutoSize) {
     931          51 :         IsAutoSize = true;
     932             :     }
     933          57 :     if ((state.dataSize->CurZoneEqNum > 0) && (CurTermUnitSizingNum > 0)) {
     934          57 :         if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // Simulation continue
     935           0 :             if (thisPIU.MaxTotAirVolFlow > 0.0) {
     936           0 :                 BaseSizer::reportSizerOutput(
     937             :                     state, thisPIU.UnitType, thisPIU.Name, "User-Specified Maximum Air Flow Rate [m3/s]", thisPIU.MaxTotAirVolFlow);
     938             :             }
     939             :         } else {
     940          57 :             CheckZoneSizing(state, thisPIU.UnitType, thisPIU.Name);
     941             :             // Autosized maximum air flow for reporting
     942          57 :             Real64 MaxTotAirVolFlowDes = max(state.dataSize->TermUnitFinalZoneSizing(CurTermUnitSizingNum).DesCoolVolFlow,
     943          57 :                                              state.dataSize->TermUnitFinalZoneSizing(CurTermUnitSizingNum).DesHeatVolFlow);
     944          57 :             if (MaxTotAirVolFlowDes < SmallAirVolFlow) {
     945           0 :                 MaxTotAirVolFlowDes = 0.0;
     946             :             }
     947          57 :             if (IsAutoSize) {
     948          51 :                 thisPIU.MaxTotAirVolFlow = MaxTotAirVolFlowDes;
     949          51 :                 BaseSizer::reportSizerOutput(state, thisPIU.UnitType, thisPIU.Name, "Design Size Maximum Air Flow Rate [m3/s]", MaxTotAirVolFlowDes);
     950             :             } else {
     951           6 :                 if (thisPIU.MaxTotAirVolFlow > 0.0 && MaxTotAirVolFlowDes > 0.0) {
     952             :                     // Hardsized maximum air flow for reporting
     953           0 :                     Real64 const MaxTotAirVolFlowUser = thisPIU.MaxTotAirVolFlow;
     954           0 :                     BaseSizer::reportSizerOutput(state,
     955             :                                                  thisPIU.UnitType,
     956             :                                                  thisPIU.Name,
     957             :                                                  "Design Size Maximum Air Flow Rate [m3/s]",
     958             :                                                  MaxTotAirVolFlowDes,
     959             :                                                  "User-Specified Maximum Air Flow Rate [m3/s]",
     960             :                                                  MaxTotAirVolFlowUser);
     961           0 :                     if (state.dataGlobal->DisplayExtraWarnings) {
     962           0 :                         if ((std::abs(MaxTotAirVolFlowDes - MaxTotAirVolFlowUser) / MaxTotAirVolFlowUser) >
     963           0 :                             state.dataSize->AutoVsHardSizingThreshold) {
     964           0 :                             ShowMessage(state, format("SizePIU: Potential issue with equipment sizing for {} {}", thisPIU.UnitType, thisPIU.Name));
     965           0 :                             ShowContinueError(state, format("User-Specified Maximum Air Flow Rate of {:.5R} [m3/s]", MaxTotAirVolFlowUser));
     966           0 :                             ShowContinueError(state, format("differs from Design Size Maximum Air Flow Rate of {:.5R} [m3/s]", MaxTotAirVolFlowDes));
     967           0 :                             ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
     968           0 :                             ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
     969             :                         }
     970             :                     }
     971             :                 }
     972             :             }
     973             :         }
     974             :     }
     975             : 
     976             :     // if a sizing run has been done, check if system sizing has been done for this system
     977          57 :     bool SizingDesRunThisAirSys = false;
     978          57 :     if (state.dataSize->SysSizingRunDone) {
     979          57 :         int const AirLoopNum = state.dataZoneEquip->ZoneEquipConfig(thisPIU.CtrlZoneNum).InletNodeAirLoopNum(thisPIU.ctrlZoneInNodeIndex);
     980          57 :         if (AirLoopNum > 0) {
     981          57 :             CheckThisAirSystemForSizing(state, AirLoopNum, SizingDesRunThisAirSys);
     982             :         }
     983             : 
     984             :         // get system sizing id if a sizing run has been done for this system
     985          57 :         if (SizingDesRunThisAirSys) {
     986          57 :             SysSizNum = Util::FindItemInList(
     987          57 :                 state.dataSize->FinalSysSizing(AirLoopNum).AirPriLoopName, state.dataSize->SysSizInput, &SystemSizingInputData::AirPriLoopName);
     988          57 :             if (SysSizNum == 0) {
     989           0 :                 SysSizNum = 1; // use first when none applicable
     990             :             }
     991             :         }
     992             :     }
     993             : 
     994          57 :     IsAutoSize = false;
     995          57 :     if (thisPIU.MaxSecAirVolFlow == AutoSize) {
     996           6 :         IsAutoSize = true;
     997             :     }
     998          57 :     if ((state.dataSize->CurZoneEqNum > 0) && (CurTermUnitSizingNum > 0)) {
     999          57 :         if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // Simulation continue
    1000           0 :             if (thisPIU.MaxSecAirVolFlow > 0.0) {
    1001           0 :                 BaseSizer::reportSizerOutput(
    1002             :                     state, thisPIU.UnitType, thisPIU.Name, "User-Specified Maximum Secondary Air Flow Rate [m3/s]", thisPIU.MaxSecAirVolFlow);
    1003             :             }
    1004             :         } else {
    1005          57 :             CheckZoneSizing(state, thisPIU.UnitType, thisPIU.Name);
    1006             :             // Autosized maximum secondary air flow for reporting
    1007          57 :             Real64 MaxSecAirVolFlowDes = max(state.dataSize->TermUnitFinalZoneSizing(CurTermUnitSizingNum).DesCoolVolFlow,
    1008          57 :                                              state.dataSize->TermUnitFinalZoneSizing(CurTermUnitSizingNum).DesHeatVolFlow);
    1009          57 :             if (MaxSecAirVolFlowDes < SmallAirVolFlow) {
    1010           0 :                 MaxSecAirVolFlowDes = 0.0;
    1011             :             }
    1012          57 :             if (IsAutoSize) {
    1013           6 :                 thisPIU.MaxSecAirVolFlow = MaxSecAirVolFlowDes;
    1014           6 :                 BaseSizer::reportSizerOutput(
    1015             :                     state, thisPIU.UnitType, thisPIU.Name, "Design Size Maximum Secondary Air Flow Rate [m3/s]", MaxSecAirVolFlowDes);
    1016             :             } else {
    1017          51 :                 if (thisPIU.MaxSecAirVolFlow > 0.0 && MaxSecAirVolFlowDes > 0.0) {
    1018             :                     // Harsized maximum secondary air flow for reporting
    1019           0 :                     Real64 const MaxSecAirVolFlowUser = thisPIU.MaxSecAirVolFlow;
    1020           0 :                     BaseSizer::reportSizerOutput(state,
    1021             :                                                  thisPIU.UnitType,
    1022             :                                                  thisPIU.Name,
    1023             :                                                  "Design Size Maximum Secondary Air Flow Rate [m3/s]",
    1024             :                                                  MaxSecAirVolFlowDes,
    1025             :                                                  "User-Specified Maximum Secondary Air Flow Rate [m3/s]",
    1026             :                                                  MaxSecAirVolFlowUser);
    1027           0 :                     if (state.dataGlobal->DisplayExtraWarnings) {
    1028           0 :                         if ((std::abs(MaxSecAirVolFlowDes - MaxSecAirVolFlowUser) / MaxSecAirVolFlowUser) >
    1029           0 :                             state.dataSize->AutoVsHardSizingThreshold) {
    1030           0 :                             ShowMessage(state, format("SizePIU: Potential issue with equipment sizing for {} {}", thisPIU.UnitType, thisPIU.Name));
    1031           0 :                             ShowContinueError(state, format("User-Specified Maximum Secondary Air Flow Rate of {:.5R} [m3/s]", MaxSecAirVolFlowUser));
    1032           0 :                             ShowContinueError(
    1033           0 :                                 state, format("differs from Design Size Maximum Secondary Air Flow Rate of {:.5R} [m3/s]", MaxSecAirVolFlowDes));
    1034           0 :                             ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
    1035           0 :                             ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
    1036             :                         }
    1037             :                     }
    1038             :                 }
    1039             :             }
    1040             :         }
    1041             :     }
    1042             : 
    1043          57 :     IsAutoSize = false;
    1044          57 :     if (thisPIU.MinPriAirFlowFrac == AutoSize) {
    1045          57 :         IsAutoSize = true;
    1046             :     }
    1047          57 :     if ((state.dataSize->CurZoneEqNum > 0) && (CurTermUnitSizingNum > 0)) {
    1048          57 :         if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // Simulation continue
    1049           0 :             if (thisPIU.MinPriAirFlowFrac > 0.0) {
    1050           0 :                 BaseSizer::reportSizerOutput(
    1051             :                     state, thisPIU.UnitType, thisPIU.Name, "User-Specified Minimum Primary Air Flow Fraction", thisPIU.MinPriAirFlowFrac);
    1052             :             }
    1053             :         } else {
    1054          57 :             CheckZoneSizing(state, thisPIU.UnitType, thisPIU.Name);
    1055             :             // Autosized minimum primary air flow fraction for reporting
    1056          57 :             Real64 MinPriAirFlowFracDes = 0.0;
    1057         114 :             if (thisPIU.MaxPriAirVolFlow >= SmallAirVolFlow &&
    1058          57 :                 state.dataSize->TermUnitFinalZoneSizing(CurTermUnitSizingNum).MinOA >= SmallAirVolFlow) {
    1059          57 :                 MinPriAirFlowFracDes = state.dataSize->TermUnitFinalZoneSizing(CurTermUnitSizingNum).MinOA / thisPIU.MaxPriAirVolFlow;
    1060             :             }
    1061          57 :             if (SizingDesRunThisAirSys) {
    1062          57 :                 if (state.dataSize->SysSizInput(SysSizNum).SystemOAMethod == SysOAMethod::SP) { // 62.1 simplified procedure
    1063           2 :                     if (thisPIU.MaxPriAirVolFlow > 0.0) {
    1064           2 :                         MinPriAirFlowFracDes = 1.5 *
    1065           2 :                                                max(state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).VozClgByZone,
    1066           2 :                                                    state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).VozHtgByZone) /
    1067           2 :                                                thisPIU.MaxPriAirVolFlow;
    1068             : 
    1069             :                         // adjust maximum flow rate
    1070           2 :                         if (MinPriAirFlowFracDes > 1.0 && IsMaxPriFlowAutoSize) {
    1071           0 :                             thisPIU.MaxPriAirVolFlow *= MinPriAirFlowFracDes;
    1072           0 :                             MinPriAirFlowFracDes = 1.0;
    1073           0 :                             ShowWarningError(state,
    1074           0 :                                              format("SingleDuctSystem:SizeSys: Autosized maximum air flow rate for {} was increased to meet the zone "
    1075             :                                                     "primary air flow determined according to the ASHRAE Standard 62.1 Simplified Procedure.",
    1076           0 :                                                     thisPIU.Name));
    1077           2 :                         } else if (MinPriAirFlowFracDes > 1.0) {
    1078           0 :                             ShowWarningError(
    1079             :                                 state,
    1080           0 :                                 format("SingleDuctSystem:SizeSys: Maximum primary air flow rate for {} is potentially too low.", thisPIU.Name));
    1081           0 :                             ShowContinueError(state,
    1082             :                                               "The flow is lower than the minimum primary air flow rate calculated following the ASHRAE Standard "
    1083             :                                               "62.1 Simplified Procedure:");
    1084           0 :                             ShowContinueError(state, format(" User-specified maximum primary air flow rate: {:.3R} m3/s.", thisPIU.MaxPriAirVolFlow));
    1085           0 :                             ShowContinueError(
    1086             :                                 state,
    1087           0 :                                 format(" Calculated minimum primary air flow rate: {:.3R} m3/s.", thisPIU.MaxPriAirVolFlow * MinPriAirFlowFracDes));
    1088           0 :                             MinPriAirFlowFracDes = 1.0;
    1089             :                         }
    1090             :                     }
    1091             :                 }
    1092             :             }
    1093          57 :             if (IsAutoSize) {
    1094          57 :                 if (SizingDesRunThisAirSys) {
    1095          57 :                     if (state.dataSize->SysSizInput(SysSizNum).SystemOAMethod == SysOAMethod::SP) {
    1096           2 :                         state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).VpzMinByZoneSPSized = true;
    1097             :                     }
    1098             :                 }
    1099          57 :                 thisPIU.MinPriAirFlowFrac = MinPriAirFlowFracDes;
    1100          57 :                 BaseSizer::reportSizerOutput(
    1101             :                     state, thisPIU.UnitType, thisPIU.Name, "Design Size Minimum Primary Air Flow Fraction", MinPriAirFlowFracDes);
    1102             :             } else {
    1103           0 :                 if (thisPIU.MinPriAirFlowFrac > 0.0 && MinPriAirFlowFracDes > 0.0) {
    1104             :                     // Hardsized minimum primary air flow fraction for reporting
    1105           0 :                     Real64 const MinPriAirFlowFracUser = thisPIU.MinPriAirFlowFrac;
    1106           0 :                     BaseSizer::reportSizerOutput(state,
    1107             :                                                  thisPIU.UnitType,
    1108             :                                                  thisPIU.Name,
    1109             :                                                  "Design Size Minimum Primary Air Flow Fraction",
    1110             :                                                  MinPriAirFlowFracDes,
    1111             :                                                  "User-Specified Minimum Primary Air Flow Fraction",
    1112             :                                                  MinPriAirFlowFracUser);
    1113           0 :                     if (state.dataGlobal->DisplayExtraWarnings) {
    1114           0 :                         if ((std::abs(MinPriAirFlowFracDes - MinPriAirFlowFracUser) / MinPriAirFlowFracUser) >
    1115           0 :                             state.dataSize->AutoVsHardSizingThreshold) {
    1116           0 :                             ShowMessage(state, format("SizePIU: Potential issue with equipment sizing for {} {}", thisPIU.UnitType, thisPIU.Name));
    1117           0 :                             ShowContinueError(state, format("User-Specified Minimum Primary Air Flow Fraction of {:.1R}", MinPriAirFlowFracUser));
    1118           0 :                             ShowContinueError(state,
    1119           0 :                                               format("differs from Design Size Minimum Primary Air Flow Fraction of {:.1R}", MinPriAirFlowFracDes));
    1120           0 :                             ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
    1121           0 :                             ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
    1122             :                         }
    1123             :                     }
    1124             :                 }
    1125             :             }
    1126             :         }
    1127             :     }
    1128             : 
    1129          57 :     if (CurTermUnitSizingNum > 0) {
    1130             : 
    1131          57 :         if (thisPIU.UnitType_Num == DataDefineEquip::ZnAirLoopEquipType::SingleDuct_SeriesPIU_Reheat) {
    1132          51 :             TermUnitSizing(CurTermUnitSizingNum).AirVolFlow = thisPIU.MaxTotAirVolFlow;
    1133           6 :         } else if (thisPIU.UnitType_Num == DataDefineEquip::ZnAirLoopEquipType::SingleDuct_ParallelPIU_Reheat) {
    1134           6 :             TermUnitSizing(CurTermUnitSizingNum).AirVolFlow = thisPIU.MaxSecAirVolFlow + thisPIU.MinPriAirFlowFrac * thisPIU.MaxPriAirVolFlow;
    1135             :         }
    1136             :     }
    1137             : 
    1138          57 :     IsAutoSize = false;
    1139          57 :     if (thisPIU.FanOnFlowFrac == AutoSize) {
    1140           4 :         IsAutoSize = true;
    1141             :     }
    1142          57 :     if (state.dataSize->CurZoneEqNum > 0) {
    1143          57 :         if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // Simulation continue
    1144           0 :             if (thisPIU.FanOnFlowFrac > 0.0) {
    1145           0 :                 BaseSizer::reportSizerOutput(state, thisPIU.UnitType, thisPIU.Name, "User-Specified Fan On Flow Fraction", thisPIU.FanOnFlowFrac);
    1146             :             }
    1147             :         } else {
    1148          57 :             CheckZoneSizing(state, thisPIU.UnitType, thisPIU.Name);
    1149             :             // Autosized fan on flow fraction for reporting
    1150          57 :             Real64 FanOnFlowFracDes = thisPIU.MinPriAirFlowFrac;
    1151          57 :             if (IsAutoSize) {
    1152           4 :                 thisPIU.FanOnFlowFrac = FanOnFlowFracDes;
    1153           4 :                 BaseSizer::reportSizerOutput(state, thisPIU.UnitType, thisPIU.Name, "Design Size Fan On Flow Fraction", FanOnFlowFracDes);
    1154             :             } else {
    1155          53 :                 if (thisPIU.FanOnFlowFrac > 0.0 && FanOnFlowFracDes > 0.0) {
    1156             :                     // Hardsized fan on flow fraction for reporting
    1157           0 :                     Real64 const FanOnFlowFracUser = thisPIU.FanOnFlowFrac;
    1158           0 :                     BaseSizer::reportSizerOutput(state,
    1159             :                                                  thisPIU.UnitType,
    1160             :                                                  thisPIU.Name,
    1161             :                                                  "Design Size Fan On Flow Fraction",
    1162             :                                                  FanOnFlowFracDes,
    1163             :                                                  "User-Specified Fan On Flow Fraction",
    1164             :                                                  FanOnFlowFracUser);
    1165           0 :                     if (state.dataGlobal->DisplayExtraWarnings) {
    1166           0 :                         if ((std::abs(FanOnFlowFracDes - FanOnFlowFracUser) / FanOnFlowFracUser) > state.dataSize->AutoVsHardSizingThreshold) {
    1167           0 :                             ShowMessage(state, format("SizePIU: Potential issue with equipment sizing for {} {}", thisPIU.UnitType, thisPIU.Name));
    1168           0 :                             ShowContinueError(state, format("User-Specified Fan On Flow Fraction of {:.1R}", FanOnFlowFracUser));
    1169           0 :                             ShowContinueError(state, format("differs from Design Size Fan On Flow Fraction of {:.1R}", FanOnFlowFracDes));
    1170           0 :                             ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
    1171           0 :                             ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
    1172             :                         }
    1173             :                     }
    1174             :                 }
    1175             :             }
    1176             :         }
    1177             :     }
    1178             : 
    1179          57 :     IsAutoSize = false;
    1180          57 :     if (thisPIU.MaxVolHotWaterFlow == AutoSize) { //.or.()) THEN
    1181          57 :         IsAutoSize = true;
    1182             :     }
    1183          57 :     if ((state.dataSize->CurZoneEqNum > 0) && (CurTermUnitSizingNum > 0)) {
    1184          57 :         if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // Simulation continue
    1185           0 :             if (thisPIU.MaxVolHotWaterFlow > 0.0) {
    1186           0 :                 BaseSizer::reportSizerOutput(
    1187             :                     state, thisPIU.UnitType, thisPIU.Name, "User-Specified Maximum Reheat Water Flow Rate [m3/s]", thisPIU.MaxVolHotWaterFlow);
    1188             :             }
    1189             :         } else {
    1190          57 :             CheckZoneSizing(state, thisPIU.UnitType, thisPIU.Name);
    1191          57 :             if (Util::SameString(HCoilNamesUC[static_cast<int>(thisPIU.HCoilType)], "Coil:Heating:Water")) {
    1192             : 
    1193          56 :                 int const CoilWaterInletNode = GetCoilWaterInletNode(state, "Coil:Heating:Water", thisPIU.HCoil, ErrorsFound);
    1194          56 :                 int const CoilWaterOutletNode = GetCoilWaterOutletNode(state, "Coil:Heating:Water", thisPIU.HCoil, ErrorsFound);
    1195             : 
    1196             :                 // Autosized maximum hot water flow for reporting
    1197          56 :                 Real64 MaxVolHotWaterFlowDes = 0.0;
    1198             : 
    1199          56 :                 if (IsAutoSize) {
    1200             :                     int const PltSizHeatNum =
    1201          56 :                         MyPlantSizingIndex(state, "Coil:Heating:Water", thisPIU.HCoil, CoilWaterInletNode, CoilWaterOutletNode, ErrorsFound);
    1202          56 :                     if (PltSizHeatNum > 0) {
    1203             : 
    1204          56 :                         if (state.dataSize->TermUnitFinalZoneSizing(CurTermUnitSizingNum).DesHeatMassFlow >= SmallAirVolFlow) {
    1205             :                             Real64 const CoilInTemp =
    1206          56 :                                 state.dataSize->TermUnitFinalZoneSizing(CurTermUnitSizingNum).DesHeatCoilInTempTU * thisPIU.MinPriAirFlowFrac +
    1207          56 :                                 state.dataSize->TermUnitFinalZoneSizing(CurTermUnitSizingNum).ZoneTempAtHeatPeak * (1.0 - thisPIU.MinPriAirFlowFrac);
    1208          56 :                             Real64 const CoilOutTemp = state.dataSize->TermUnitFinalZoneSizing(CurTermUnitSizingNum).HeatDesTemp;
    1209          56 :                             Real64 const CoilOutHumRat = state.dataSize->TermUnitFinalZoneSizing(CurTermUnitSizingNum).HeatDesHumRat;
    1210          56 :                             Real64 const DesMassFlow = state.dataEnvrn->StdRhoAir * TermUnitSizing(CurTermUnitSizingNum).AirVolFlow;
    1211          56 :                             DesCoilLoad = PsyCpAirFnW(CoilOutHumRat) * DesMassFlow * (CoilOutTemp - CoilInTemp);
    1212             : 
    1213          56 :                             Real64 const rho = GetDensityGlycol(state,
    1214          56 :                                                                 state.dataPlnt->PlantLoop(thisPIU.HWplantLoc.loopNum).FluidName,
    1215             :                                                                 Constant::HWInitConvTemp,
    1216          56 :                                                                 state.dataPlnt->PlantLoop(thisPIU.HWplantLoc.loopNum).FluidIndex,
    1217             :                                                                 RoutineName);
    1218          56 :                             Real64 const Cp = GetSpecificHeatGlycol(state,
    1219          56 :                                                                     state.dataPlnt->PlantLoop(thisPIU.HWplantLoc.loopNum).FluidName,
    1220             :                                                                     Constant::HWInitConvTemp,
    1221          56 :                                                                     state.dataPlnt->PlantLoop(thisPIU.HWplantLoc.loopNum).FluidIndex,
    1222             :                                                                     RoutineName);
    1223             : 
    1224          56 :                             MaxVolHotWaterFlowDes = DesCoilLoad / (state.dataSize->PlantSizData(PltSizHeatNum).DeltaT * Cp * rho);
    1225             :                         } else {
    1226           0 :                             MaxVolHotWaterFlowDes = 0.0;
    1227             :                         }
    1228             :                     } else {
    1229           0 :                         ShowSevereError(state, "Autosizing of water flow requires a heating loop Sizing:Plant object");
    1230           0 :                         ShowContinueError(state, format("Occurs in{} Object={}", thisPIU.UnitType, thisPIU.Name));
    1231           0 :                         ErrorsFound = true;
    1232             :                     }
    1233             :                 }
    1234          56 :                 if (IsAutoSize) {
    1235          56 :                     thisPIU.MaxVolHotWaterFlow = MaxVolHotWaterFlowDes;
    1236          56 :                     BaseSizer::reportSizerOutput(
    1237             :                         state, thisPIU.UnitType, thisPIU.Name, "Design Size Maximum Reheat Water Flow Rate [m3/s]", MaxVolHotWaterFlowDes);
    1238         112 :                     BaseSizer::reportSizerOutput(state,
    1239             :                                                  thisPIU.UnitType,
    1240             :                                                  thisPIU.Name,
    1241             :                                                  "Design Size Reheat Coil Inlet Air Temperature [C]",
    1242          56 :                                                  state.dataSize->TermUnitFinalZoneSizing(CurTermUnitSizingNum).DesHeatCoilInTempTU);
    1243         112 :                     BaseSizer::reportSizerOutput(state,
    1244             :                                                  thisPIU.UnitType,
    1245             :                                                  thisPIU.Name,
    1246             :                                                  "Design Size Reheat Coil Inlet Air Humidity Ratio [kgWater/kgDryAir]",
    1247          56 :                                                  state.dataSize->TermUnitFinalZoneSizing(CurTermUnitSizingNum).DesHeatCoilInHumRatTU);
    1248             :                 } else { // Hardsize with sizing data
    1249           0 :                     if (thisPIU.MaxVolHotWaterFlow > 0.0 && MaxVolHotWaterFlowDes > 0.0) {
    1250             :                         // Hardsized maximum hot water flow for reporting
    1251           0 :                         Real64 const MaxVolHotWaterFlowUser = thisPIU.MaxVolHotWaterFlow;
    1252           0 :                         BaseSizer::reportSizerOutput(state,
    1253             :                                                      thisPIU.UnitType,
    1254             :                                                      thisPIU.Name,
    1255             :                                                      "Design Size Maximum Reheat Water Flow Rate [m3/s]",
    1256             :                                                      MaxVolHotWaterFlowDes,
    1257             :                                                      "User-Specified Maximum Reheat Water Flow Rate [m3/s]",
    1258             :                                                      MaxVolHotWaterFlowUser);
    1259           0 :                         if (state.dataGlobal->DisplayExtraWarnings) {
    1260           0 :                             if ((std::abs(MaxVolHotWaterFlowDes - MaxVolHotWaterFlowUser) / MaxVolHotWaterFlowUser) >
    1261           0 :                                 state.dataSize->AutoVsHardSizingThreshold) {
    1262           0 :                                 ShowMessage(state,
    1263           0 :                                             format("SizePIU: Potential issue with equipment sizing for {} {}", thisPIU.UnitType, thisPIU.Name));
    1264           0 :                                 ShowContinueError(state,
    1265           0 :                                                   format("User-Specified Maximum Reheat Water Flow Rate of {:.5R} [m3/s]", MaxVolHotWaterFlowUser));
    1266           0 :                                 ShowContinueError(
    1267           0 :                                     state, format("differs from Design Size Maximum Reheat Water Flow Rate of {:.5R} [m3/s]", MaxVolHotWaterFlowDes));
    1268           0 :                                 ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
    1269           0 :                                 ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
    1270             :                             }
    1271             :                         }
    1272             :                     }
    1273             :                 }
    1274             :             } else {
    1275           1 :                 thisPIU.MaxVolHotWaterFlow = 0.0;
    1276             :             }
    1277             :         }
    1278             :     }
    1279             : 
    1280          57 :     IsAutoSize = false;
    1281          57 :     if (thisPIU.MaxVolHotSteamFlow == AutoSize) {
    1282           0 :         IsAutoSize = true;
    1283             :     }
    1284          57 :     if ((state.dataSize->CurZoneEqNum > 0) && (CurTermUnitSizingNum > 0)) {
    1285          57 :         if (!IsAutoSize && !state.dataSize->ZoneSizingRunDone) { // Simulation continue
    1286           0 :             if (thisPIU.MaxVolHotWaterFlow > 0.0) {
    1287           0 :                 BaseSizer::reportSizerOutput(
    1288             :                     state, thisPIU.UnitType, thisPIU.Name, "User-Specified Maximum Reheat Steam Flow Rate [m3/s]", thisPIU.MaxVolHotWaterFlow);
    1289             :             }
    1290             :         } else {
    1291          57 :             if (Util::SameString(HCoilNames[static_cast<int>(thisPIU.HCoilType)], "Coil:Heating:Steam")) {
    1292             : 
    1293           0 :                 int const CoilSteamInletNode = GetCoilSteamInletNode(state, "Coil:Heating:Steam", thisPIU.HCoil, ErrorsFound);
    1294           0 :                 int const CoilSteamOutletNode = GetCoilSteamOutletNode(state, "Coil:Heating:Steam", thisPIU.HCoil, ErrorsFound);
    1295           0 :                 Real64 MaxVolHotSteamFlowDes = 0.0; // Autosized maximum hot steam flow for reporting
    1296             : 
    1297           0 :                 if (IsAutoSize) {
    1298             :                     int const PltSizHeatNum =
    1299           0 :                         MyPlantSizingIndex(state, "Coil:Heating:Steam", thisPIU.HCoil, CoilSteamInletNode, CoilSteamOutletNode, ErrorsFound);
    1300           0 :                     if (PltSizHeatNum > 0) {
    1301           0 :                         if (state.dataSize->TermUnitFinalZoneSizing(CurTermUnitSizingNum).DesHeatMassFlow >= SmallAirVolFlow) {
    1302             :                             Real64 const CoilInTemp =
    1303           0 :                                 state.dataSize->TermUnitFinalZoneSizing(CurTermUnitSizingNum).DesHeatCoilInTempTU * thisPIU.MinPriAirFlowFrac +
    1304           0 :                                 state.dataSize->TermUnitFinalZoneSizing(CurTermUnitSizingNum).ZoneTempAtHeatPeak * (1.0 - thisPIU.MinPriAirFlowFrac);
    1305           0 :                             Real64 const CoilOutTemp = state.dataSize->TermUnitFinalZoneSizing(CurTermUnitSizingNum).HeatDesTemp;
    1306           0 :                             Real64 const CoilOutHumRat = state.dataSize->TermUnitFinalZoneSizing(CurTermUnitSizingNum).HeatDesHumRat;
    1307           0 :                             Real64 const DesMassFlow = state.dataEnvrn->StdRhoAir * TermUnitSizing(CurTermUnitSizingNum).AirVolFlow;
    1308           0 :                             DesCoilLoad = PsyCpAirFnW(CoilOutHumRat) * DesMassFlow * (CoilOutTemp - CoilInTemp);
    1309           0 :                             Real64 constexpr TempSteamIn = 100.00;
    1310             :                             Real64 const EnthSteamInDry =
    1311           0 :                                 FluidProperties::GetSatEnthalpyRefrig(state, fluidNameSteam, TempSteamIn, 1.0, thisPIU.HCoil_FluidIndex, RoutineName);
    1312             :                             Real64 const EnthSteamOutWet =
    1313           0 :                                 FluidProperties::GetSatEnthalpyRefrig(state, fluidNameSteam, TempSteamIn, 0.0, thisPIU.HCoil_FluidIndex, RoutineName);
    1314           0 :                             Real64 const LatentHeatSteam = EnthSteamInDry - EnthSteamOutWet;
    1315             :                             Real64 const SteamDensity =
    1316           0 :                                 FluidProperties::GetSatDensityRefrig(state, fluidNameSteam, TempSteamIn, 1.0, thisPIU.HCoil_FluidIndex, RoutineName);
    1317           0 :                             int DummyWaterIndex = 1;
    1318           0 :                             Real64 const Cp = GetSpecificHeatGlycol(
    1319           0 :                                 state, fluidNameWater, state.dataSize->PlantSizData(PltSizHeatNum).ExitTemp, DummyWaterIndex, RoutineName);
    1320           0 :                             MaxVolHotSteamFlowDes =
    1321           0 :                                 DesCoilLoad / (SteamDensity * (LatentHeatSteam + state.dataSize->PlantSizData(PltSizHeatNum).DeltaT * Cp));
    1322             :                         } else {
    1323           0 :                             MaxVolHotSteamFlowDes = 0.0;
    1324             :                         }
    1325             :                     } else {
    1326           0 :                         ShowSevereError(state, "Autosizing of Steam flow requires a heating loop Sizing:Plant object");
    1327           0 :                         ShowContinueError(state, format("Occurs in{} Object={}", thisPIU.UnitType, thisPIU.Name));
    1328           0 :                         ErrorsFound = true;
    1329             :                     }
    1330             :                 }
    1331           0 :                 if (IsAutoSize) {
    1332           0 :                     thisPIU.MaxVolHotSteamFlow = MaxVolHotSteamFlowDes;
    1333           0 :                     BaseSizer::reportSizerOutput(
    1334             :                         state, thisPIU.UnitType, thisPIU.Name, "Design Size Maximum Reheat Steam Flow [m3/s]", MaxVolHotSteamFlowDes);
    1335             :                 } else {
    1336           0 :                     if (thisPIU.MaxVolHotSteamFlow > 0.0 && MaxVolHotSteamFlowDes > 0.0) {
    1337           0 :                         Real64 const MaxVolHotSteamFlowUser = thisPIU.MaxVolHotSteamFlow;
    1338           0 :                         BaseSizer::reportSizerOutput(state,
    1339             :                                                      thisPIU.UnitType,
    1340             :                                                      thisPIU.Name,
    1341             :                                                      "Design Size Maximum Reheat Steam Flow [m3/s]",
    1342             :                                                      MaxVolHotSteamFlowDes,
    1343             :                                                      "User-Specified Maximum Reheat Steam Flow [m3/s]",
    1344             :                                                      MaxVolHotSteamFlowUser);
    1345           0 :                         if (state.dataGlobal->DisplayExtraWarnings) {
    1346           0 :                             if ((std::abs(MaxVolHotSteamFlowDes - MaxVolHotSteamFlowUser) / MaxVolHotSteamFlowUser) >
    1347           0 :                                 state.dataSize->AutoVsHardSizingThreshold) {
    1348           0 :                                 ShowMessage(state,
    1349           0 :                                             format("SizePIU: Potential issue with equipment sizing for {} {}", thisPIU.UnitType, thisPIU.Name));
    1350           0 :                                 ShowContinueError(state, format("User-Specified Maximum Reheat Steam Flow of {:.5R} [m3/s]", MaxVolHotSteamFlowUser));
    1351           0 :                                 ShowContinueError(
    1352           0 :                                     state, format("differs from Design Size Maximum Reheat Steam Flow of {:.5R} [m3/s]", MaxVolHotSteamFlowDes));
    1353           0 :                                 ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
    1354           0 :                                 ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
    1355             :                             }
    1356             :                         }
    1357             :                     }
    1358             :                 }
    1359             :             } else {
    1360          57 :                 thisPIU.MaxVolHotSteamFlow = 0.0;
    1361             :             }
    1362             :         }
    1363             :     }
    1364             : 
    1365          57 :     if (CurTermUnitSizingNum > 0) {
    1366          57 :         TermUnitSizing(CurTermUnitSizingNum).MinPriFlowFrac = thisPIU.MinPriAirFlowFrac;
    1367          57 :         TermUnitSizing(CurTermUnitSizingNum).plenumIndex = thisPIU.plenumIndex;
    1368          57 :         TermUnitSizing(CurTermUnitSizingNum).MaxHWVolFlow = thisPIU.MaxVolHotWaterFlow;
    1369          57 :         TermUnitSizing(CurTermUnitSizingNum).MaxSTVolFlow = thisPIU.MaxVolHotSteamFlow;
    1370          57 :         TermUnitSizing(CurTermUnitSizingNum).DesHeatingLoad = DesCoilLoad; // coil report
    1371          57 :         TermUnitSizing(CurTermUnitSizingNum).InducesPlenumAir = thisPIU.InducesPlenumAir;
    1372          57 :         if (thisPIU.HCoilType == HtgCoilType::SimpleHeating) {
    1373          56 :             SetCoilDesFlow(state,
    1374          56 :                            HCoilNamesUC[static_cast<int>(thisPIU.HCoilType)],
    1375          56 :                            thisPIU.HCoil,
    1376          56 :                            TermUnitSizing(CurTermUnitSizingNum).AirVolFlow,
    1377             :                            ErrorsFound);
    1378             :         }
    1379             :     }
    1380             : 
    1381          57 :     if (ErrorsFound) {
    1382           0 :         ShowFatalError(state, "Preceding sizing errors cause program termination");
    1383             :     }
    1384          57 : }
    1385             : 
    1386      287202 : void CalcSeriesPIU(EnergyPlusData &state,
    1387             :                    int const PIUNum,             // number of the current PIU being simulated
    1388             :                    int const ZoneNum,            // number of zone being served
    1389             :                    int const ZoneNode,           // zone node number
    1390             :                    bool const FirstHVACIteration // TRUE if 1st HVAC simulation of system timestep
    1391             : )
    1392             : {
    1393             : 
    1394             :     // SUBROUTINE INFORMATION:
    1395             :     //       AUTHOR         Fred Buhl
    1396             :     //       DATE WRITTEN   August 2000
    1397             :     //       MODIFIED       na
    1398             :     //       RE-ENGINEERED  na
    1399             : 
    1400             :     // PURPOSE OF THIS SUBROUTINE:
    1401             :     // Simulate a series powered induction unit; adjust its primary air flow
    1402             :     // and reheat coil output to match the zone load.
    1403             : 
    1404             :     // METHODOLOGY EMPLOYED:
    1405             :     // If unit is on and there is a cooling load:
    1406             :     // (1) simulates mixer and fan at max secondary air flow and heating coil
    1407             :     //     off. Obtains fan temperature increase.
    1408             :     // (2) Calculates primary and secomdary air flow to meet zone load and
    1409             :     //     resimulates mixer, fan, and (off) coil.
    1410             :     // If unit is on and there is a heating load
    1411             :     // (1) sets primary air flow to a minimum.
    1412             :     // (2) simulates mixer and fan
    1413             :     // (3) if reheat is hot water, calls ControlCompOutput to simulate hot
    1414             :     //     water coil and adjust water flow to match coil output to the zone load.
    1415             :     // (4) if reheat is electric or gas calls SimulateHeatingCoilComponents to
    1416             :     //     simulate coil at coil output that matches the zone load
    1417             : 
    1418             :     // REFERENCES:
    1419             :     // na
    1420             : 
    1421             :     // Using/Aliasing
    1422             :     using namespace DataZoneEnergyDemands;
    1423             :     using FluidProperties::GetDensityGlycol;
    1424             :     using FluidProperties::GetSpecificHeatGlycol;
    1425             :     using HeatingCoils::SimulateHeatingCoilComponents;
    1426             :     using MixerComponent::SimAirMixer;
    1427             :     using PlantUtilities::SetComponentFlowRate;
    1428             :     using SteamCoils::SimulateSteamCoilComponents;
    1429             :     using WaterCoils::SimulateWaterCoilComponents;
    1430             : 
    1431             :     // Locals
    1432             :     // SUBROUTINE ARGUMENT DEFINITIONS:
    1433             : 
    1434             :     // SUBROUTINE PARAMETER DEFINITIONS:
    1435             : 
    1436             :     // INTERFACE BLOCK SPECIFICATIONS
    1437             : 
    1438             :     // DERIVED TYPE DEFINITIONS
    1439             :     // na
    1440             : 
    1441             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1442      287202 :     bool UnitOn(true); // TRUE if unit is on
    1443      287202 :     bool PriOn(true);  // TRUE if primary air available
    1444             : 
    1445      287202 :     Real64 QCoilReq = 0.0;     // required heating coil outlet to meet zone load
    1446      287202 :     Real64 MaxWaterFlow = 0.0; // maximum water flow for heating or cooling [kg/s]
    1447      287202 :     Real64 MinWaterFlow = 0.0; // minimum water flow for heating or cooling [kg/s]
    1448             : 
    1449             :     // initialize local variables
    1450      287202 :     auto &thisPIU = state.dataPowerInductionUnits->PIU(PIUNum);
    1451             : 
    1452      287202 :     Real64 const PriAirMassFlowMax = state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRateMaxAvail; // max primary air mass flow rate [kg/s]
    1453      287202 :     Real64 const PriAirMassFlowMin = state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRateMinAvail; // min primary air mass flow rate [kg/s]
    1454             :     Real64 const QZnReq =
    1455      287202 :         state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputRequired; // heating or cooling needed by zone [Watts]
    1456             :     Real64 const QToHeatSetPt =
    1457      287202 :         state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputReqToHeatSP; // [W]  remaining load to heating setpoint
    1458      287202 :     Real64 const CpAirZn = PsyCpAirFnW(state.dataLoopNodes->Node(ZoneNode).HumRat);          // zone air specific heat [J/kg-C]
    1459      287202 :     thisPIU.PriAirMassFlow = state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRate;   // primary air mass flow rate [kg/s]
    1460      287202 :     thisPIU.SecAirMassFlow = state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate;   // secondary air mass flow rate [kg/s]
    1461      287202 :     if (thisPIU.fanControlType == FanCntrlType::VariableSpeedFan) {
    1462        7366 :         thisPIU.heatingOperatingMode = HeatOpModeType::HeaterOff;
    1463             :     } else {
    1464      279836 :         thisPIU.heatingOperatingMode = HeatOpModeType::ConstantVolumeHeat;
    1465             :     }
    1466      287202 :     thisPIU.coolingOperatingMode = CoolOpModeType::CoolerOff;
    1467             : 
    1468             :     // On the first HVAC iteration the system values are given to the controller, but after that
    1469             :     // the demand limits are in place and there needs to be feedback to the Zone Equipment
    1470      287202 :     if (thisPIU.HotControlNode > 0) {
    1471      276483 :         if (FirstHVACIteration) {
    1472      128437 :             MaxWaterFlow = thisPIU.MaxHotWaterFlow;
    1473      128437 :             MinWaterFlow = thisPIU.MinHotWaterFlow;
    1474             :         } else {
    1475      148046 :             MaxWaterFlow = state.dataLoopNodes->Node(thisPIU.HotControlNode).MassFlowRateMaxAvail;
    1476      148046 :             MinWaterFlow = state.dataLoopNodes->Node(thisPIU.HotControlNode).MassFlowRateMinAvail;
    1477             :         }
    1478             :     }
    1479      287202 :     if (GetCurrentScheduleValue(state, thisPIU.SchedPtr) <= 0.0) {
    1480          14 :         UnitOn = false;
    1481             :     }
    1482      287202 :     if ((GetCurrentScheduleValue(state, thisPIU.FanAvailSchedPtr) <= 0.0 || state.dataHVACGlobal->TurnFansOff) && !state.dataHVACGlobal->TurnFansOn) {
    1483       56933 :         UnitOn = false;
    1484             :     }
    1485      287202 :     if (thisPIU.PriAirMassFlow <= SmallMassFlow || PriAirMassFlowMax <= SmallMassFlow) {
    1486       61409 :         PriOn = false;
    1487             :     }
    1488             :     // Set the mass flow rates
    1489      287202 :     if (UnitOn) {
    1490             :         // unit is on
    1491      230269 :         if (!PriOn) {
    1492             :             // no primary air flow
    1493        4497 :             thisPIU.PriAirMassFlow = 0.0;
    1494             :             // PIU fan off if there is no heating load, also reset fan flag if fan should be off
    1495        4497 :             if (QZnReq <= SmallLoad) {
    1496        2095 :                 thisPIU.SecAirMassFlow = 0.0;
    1497        2095 :                 state.dataHVACGlobal->TurnFansOn = false;
    1498             :             } else {
    1499        2402 :                 if (thisPIU.fanControlType == FanCntrlType::VariableSpeedFan &&
    1500           6 :                     thisPIU.heatingControlType == HeatCntrlBehaviorType::StagedHeaterBehavior) {
    1501           3 :                     CalcVariableSpeedPIUStagedHeatingBehavior(state, PIUNum, ZoneNode, QZnReq, PriOn, thisPIU.PriAirMassFlow);
    1502        2399 :                 } else if (thisPIU.fanControlType == FanCntrlType::VariableSpeedFan &&
    1503           3 :                            thisPIU.heatingControlType == HeatCntrlBehaviorType::ModulatedHeaterBehavior) {
    1504           3 :                     CalcVariableSpeedPIUModulatedHeatingBehavior(state, PIUNum, ZoneNode, QZnReq, PriOn, thisPIU.PriAirMassFlow);
    1505        2396 :                 } else if (thisPIU.fanControlType == FanCntrlType::ConstantSpeedFan) {
    1506        2396 :                     thisPIU.heatingOperatingMode = HeatOpModeType::ConstantVolumeHeat;
    1507        2396 :                     thisPIU.SecAirMassFlow = thisPIU.MaxTotAirMassFlow;
    1508             :                 }
    1509             :             }
    1510      225772 :         } else if (state.dataZoneEnergyDemand->CurDeadBandOrSetback(ZoneNum) || std::abs(QZnReq) < SmallLoad) {
    1511             :             // in deadband or very small load: set primary air flow to the minimum
    1512       44030 :             thisPIU.PriAirMassFlow = PriAirMassFlowMin;
    1513       44030 :             if (thisPIU.fanControlType == FanCntrlType::ConstantSpeedFan) {
    1514       41168 :                 thisPIU.heatingOperatingMode = HeatOpModeType::ConstantVolumeHeat;
    1515       41168 :                 thisPIU.SecAirMassFlow = max(0.0, thisPIU.MaxTotAirMassFlow - thisPIU.PriAirMassFlow);
    1516        2862 :             } else if (thisPIU.fanControlType == FanCntrlType::VariableSpeedFan) {
    1517        2862 :                 thisPIU.SecAirMassFlow = max(0.0, thisPIU.MinTotAirMassFlow - thisPIU.PriAirMassFlow);
    1518             :             }
    1519      181742 :         } else if (QZnReq > SmallLoad) {
    1520             :             // heating: set primary air flow to the minimum
    1521      116368 :             thisPIU.PriAirMassFlow = PriAirMassFlowMin;
    1522             :             // determine secondary flow rate
    1523      116368 :             if (thisPIU.fanControlType == FanCntrlType::VariableSpeedFan &&
    1524        2702 :                 thisPIU.heatingControlType == HeatCntrlBehaviorType::StagedHeaterBehavior) {
    1525        1352 :                 CalcVariableSpeedPIUStagedHeatingBehavior(state, PIUNum, ZoneNode, QZnReq, PriOn, thisPIU.PriAirMassFlow);
    1526      115016 :             } else if (thisPIU.fanControlType == FanCntrlType::VariableSpeedFan &&
    1527        1350 :                        thisPIU.heatingControlType == HeatCntrlBehaviorType::ModulatedHeaterBehavior) {
    1528        1350 :                 CalcVariableSpeedPIUModulatedHeatingBehavior(state, PIUNum, ZoneNode, QZnReq, PriOn, thisPIU.PriAirMassFlow);
    1529      113666 :             } else if (thisPIU.fanControlType == FanCntrlType::ConstantSpeedFan) {
    1530      113666 :                 thisPIU.heatingOperatingMode = HeatOpModeType::ConstantVolumeHeat;
    1531      113666 :                 thisPIU.SecAirMassFlow = max(0.0, thisPIU.MaxTotAirMassFlow - thisPIU.PriAirMassFlow);
    1532             :             }
    1533             :         } else {
    1534       65374 :             if (thisPIU.fanControlType == FanCntrlType::ConstantSpeedFan) {
    1535             :                 // cooling: set the primary air flow rate to meet the load.
    1536             :                 // First calculate the fan temperature rise
    1537             :                 // use only secondary air for this calculation
    1538       63582 :                 state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRate = 0.0;
    1539       63582 :                 state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate = thisPIU.MaxTotAirMassFlow;
    1540       63582 :                 SimAirMixer(state, thisPIU.MixerName, thisPIU.Mixer_Num); // fire the mixer
    1541       63582 :                 state.dataFans->fans(thisPIU.Fan_Index)->simulate(state, FirstHVACIteration, _, _);
    1542             : 
    1543             :                 // fan temperature rise [C]
    1544             :                 Real64 const FanDeltaTemp =
    1545       63582 :                     state.dataLoopNodes->Node(thisPIU.HCoilInAirNode).Temp - state.dataLoopNodes->Node(thisPIU.SecAirInNode).Temp;
    1546             : 
    1547             :                 // using the required zone load, calculate the air temperature needed to meet the load
    1548       63582 :                 Real64 const OutletTempNeeded = state.dataLoopNodes->Node(ZoneNode).Temp + QZnReq / (thisPIU.MaxTotAirMassFlow * CpAirZn);
    1549             : 
    1550             :                 // mixer outlet temperature needed to meet cooling load
    1551       63582 :                 Real64 const MixTempNeeded = OutletTempNeeded - FanDeltaTemp;
    1552             : 
    1553       63582 :                 if (MixTempNeeded <= state.dataLoopNodes->Node(thisPIU.PriAirInNode).Temp) { //
    1554       19746 :                     thisPIU.PriAirMassFlow = PriAirMassFlowMax;
    1555       87672 :                 } else if (MixTempNeeded >= state.dataLoopNodes->Node(thisPIU.PriAirInNode).Temp &&
    1556       43836 :                            MixTempNeeded >= state.dataLoopNodes->Node(thisPIU.SecAirInNode).Temp) {
    1557         462 :                     thisPIU.PriAirMassFlow = PriAirMassFlowMin;
    1558             :                 } else {
    1559       43374 :                     thisPIU.PriAirMassFlow =
    1560       43374 :                         thisPIU.MaxTotAirMassFlow * (state.dataLoopNodes->Node(thisPIU.SecAirInNode).Temp - MixTempNeeded) /
    1561       43374 :                         max(SmallTempDiff,
    1562       43374 :                             state.dataLoopNodes->Node(thisPIU.SecAirInNode).Temp - state.dataLoopNodes->Node(thisPIU.PriAirInNode).Temp);
    1563       43374 :                     thisPIU.PriAirMassFlow = min(max(thisPIU.PriAirMassFlow, PriAirMassFlowMin), PriAirMassFlowMax);
    1564             :                 }
    1565       63582 :                 thisPIU.SecAirMassFlow = max(0.0, thisPIU.MaxTotAirMassFlow - thisPIU.PriAirMassFlow);
    1566       63582 :                 if (QZnReq < 0) {
    1567       63582 :                     thisPIU.coolingOperatingMode = CoolOpModeType::ConstantVolumeCool;
    1568             :                 }
    1569        1792 :             } else if (thisPIU.fanControlType == FanCntrlType::VariableSpeedFan) {
    1570        1792 :                 CalcVariableSpeedPIUCoolingBehavior(state, PIUNum, ZoneNode, QZnReq, QToHeatSetPt, PriAirMassFlowMin, PriAirMassFlowMax);
    1571             :             }
    1572             :         }
    1573             :     } else {
    1574             :         // unit is off ; no flow
    1575       56933 :         thisPIU.PriAirMassFlow = 0.0;
    1576       56933 :         thisPIU.SecAirMassFlow = 0.0;
    1577             :     }
    1578             :     // set inlet node flowrates
    1579      287202 :     state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRate = thisPIU.PriAirMassFlow;
    1580      287202 :     state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate = thisPIU.SecAirMassFlow;
    1581      287202 :     if (PriAirMassFlowMax == 0) {
    1582       61409 :         thisPIU.PriDamperPosition = 0;
    1583             :     } else {
    1584      225793 :         thisPIU.PriDamperPosition = thisPIU.PriAirMassFlow / PriAirMassFlowMax;
    1585             :     }
    1586             : 
    1587             :     // now that inlet airflows have been set, the terminal components can be simulated.
    1588             :     // fire the mixer
    1589      287202 :     SimAirMixer(state, thisPIU.MixerName, thisPIU.Mixer_Num);
    1590             : 
    1591             :     // fire the fan
    1592      287202 :     if (thisPIU.fanType == HVAC::FanType::SystemModel) {
    1593      175093 :         if (thisPIU.fanControlType == FanCntrlType::VariableSpeedFan) {
    1594             :             // calculate fan speed ratio
    1595        7366 :             Real64 fanFlowRatio(1.0);
    1596        7366 :             if (thisPIU.MaxTotAirMassFlow > 0.0) {
    1597        7364 :                 fanFlowRatio = (thisPIU.PriAirMassFlow + thisPIU.SecAirMassFlow) / thisPIU.MaxTotAirMassFlow;
    1598             :             }
    1599        7366 :             state.dataFans->fans(thisPIU.Fan_Index)->simulate(state, FirstHVACIteration, fanFlowRatio, _);
    1600             :         } else {
    1601      167727 :             state.dataFans->fans(thisPIU.Fan_Index)->simulate(state, FirstHVACIteration, _, _);
    1602             :         }
    1603      112109 :     } else if (thisPIU.fanType == HVAC::FanType::Constant) {
    1604      112109 :         state.dataFans->fans(thisPIU.Fan_Index)->simulate(state, FirstHVACIteration, _, _);
    1605             :     }
    1606             : 
    1607             :     // the heating load seen by the reheat coil [W]
    1608      287202 :     Real64 QActualHeating = QToHeatSetPt - state.dataLoopNodes->Node(thisPIU.HCoilInAirNode).MassFlowRate * CpAirZn *
    1609      287202 :                                                (state.dataLoopNodes->Node(thisPIU.HCoilInAirNode).Temp - state.dataLoopNodes->Node(ZoneNode).Temp);
    1610             : 
    1611             :     // check if heating coil is off
    1612      230269 :     if (((!UnitOn) || (QActualHeating < SmallLoad) || (state.dataHeatBalFanSys->TempControlType(ZoneNum) == HVAC::ThermostatType::SingleCooling) ||
    1613      574404 :          (thisPIU.PriAirMassFlow > PriAirMassFlowMin)) &&
    1614      168042 :         (thisPIU.heatingOperatingMode != HeatOpModeType::StagedHeatFirstStage)) { // reheat is off during the first stage of heating
    1615      168042 :         thisPIU.heatingOperatingMode = HeatOpModeType::HeaterOff;
    1616             :     }
    1617             : 
    1618             :     // determine what is required of heater for current operating stage
    1619      287202 :     if (thisPIU.heatingOperatingMode == HeatOpModeType::HeaterOff) {
    1620      168044 :         QCoilReq = 0.0;
    1621      119158 :     } else if (thisPIU.heatingOperatingMode == HeatOpModeType::StagedHeatFirstStage) {
    1622           0 :         QCoilReq = 0.0;
    1623      119158 :     } else if (thisPIU.heatingOperatingMode == HeatOpModeType::ConstantVolumeHeat) {
    1624      116464 :         QCoilReq = QActualHeating;
    1625        2694 :     } else if (thisPIU.heatingOperatingMode == HeatOpModeType::StagedHeatSecondStage) {
    1626        1348 :         QCoilReq = QActualHeating;
    1627        1346 :     } else if (thisPIU.heatingOperatingMode == HeatOpModeType::ModulatedHeatFirstStage) {
    1628        1346 :         QCoilReq = QActualHeating;
    1629           0 :     } else if (thisPIU.heatingOperatingMode == HeatOpModeType::ModulatedHeatSecondStage) {
    1630             :         // find heater power to deliver design discharge air temperature
    1631           0 :         Real64 targetDATEnthalpy = Psychrometrics::PsyHFnTdbW(thisPIU.designHeatingDAT, state.dataLoopNodes->Node(ZoneNode).HumRat);
    1632             :         Real64 mixAirEnthalpy =
    1633           0 :             Psychrometrics::PsyHFnTdbW(state.dataLoopNodes->Node(thisPIU.HCoilInAirNode).Temp, state.dataLoopNodes->Node(ZoneNode).HumRat);
    1634           0 :         QCoilReq = state.dataLoopNodes->Node(thisPIU.HCoilInAirNode).MassFlowRate * (targetDATEnthalpy - mixAirEnthalpy);
    1635           0 :     } else if (thisPIU.heatingOperatingMode == HeatOpModeType::ModulatedHeatThirdStage) {
    1636             :         // find heater power to deliver maximum discharge air temperature
    1637           0 :         Real64 HiLimitDATEnthalpy = Psychrometrics::PsyHFnTdbW(thisPIU.highLimitDAT, state.dataLoopNodes->Node(ZoneNode).HumRat);
    1638             :         Real64 mixAirEnthalpy =
    1639           0 :             Psychrometrics::PsyHFnTdbW(state.dataLoopNodes->Node(thisPIU.HCoilInAirNode).Temp, state.dataLoopNodes->Node(ZoneNode).HumRat);
    1640           0 :         Real64 QcoilLimit = state.dataLoopNodes->Node(thisPIU.HCoilInAirNode).MassFlowRate * (HiLimitDATEnthalpy - mixAirEnthalpy);
    1641           0 :         if (QcoilLimit < QActualHeating) { // if requried power is too high use limit of coil discharge
    1642           0 :             QCoilReq = QcoilLimit;
    1643             :         } else {
    1644           0 :             QCoilReq = QActualHeating;
    1645             :         }
    1646             :     } else {
    1647           0 :         ShowSevereError(state, "Incorrect series PIU heating operation.");
    1648           0 :         ShowFatalError(state, format("Series PIU control failed for {}:{}", thisPIU.UnitType, thisPIU.Name));
    1649             :     }
    1650      287202 :     if ((QCoilReq < SmallLoad) &&
    1651      168044 :         (thisPIU.heatingOperatingMode != HeatOpModeType::StagedHeatFirstStage)) { // reheat is off during the first stage of heating
    1652      168044 :         thisPIU.heatingOperatingMode = HeatOpModeType::HeaterOff;
    1653      168044 :         QCoilReq = 0.0;
    1654             :     }
    1655             : 
    1656             :     // fire the heating coil
    1657      287202 :     switch (thisPIU.HCoilType) {
    1658      276483 :     case HtgCoilType::SimpleHeating: { // COIL:WATER:SIMPLEHEATING
    1659      276483 :         if ((thisPIU.heatingOperatingMode == HeatOpModeType::HeaterOff) || (thisPIU.heatingOperatingMode == HeatOpModeType::StagedHeatFirstStage)) {
    1660             :             // call the reheat coil with the NO FLOW condition
    1661      161631 :             Real64 mdot = 0.0;
    1662      161631 :             SetComponentFlowRate(state, mdot, thisPIU.HotControlNode, thisPIU.HotCoilOutNodeNum, thisPIU.HWplantLoc);
    1663             : 
    1664      161631 :             SimulateWaterCoilComponents(state, thisPIU.HCoil, FirstHVACIteration, thisPIU.HCoil_Index);
    1665      161631 :         } else {
    1666             :             // control water flow to obtain output matching QZnReq
    1667      344556 :             ControlCompOutput(state,
    1668      114852 :                               thisPIU.HCoil,
    1669      114852 :                               thisPIU.UnitType,
    1670      114852 :                               thisPIU.HCoil_Index,
    1671             :                               FirstHVACIteration,
    1672             :                               QCoilReq,
    1673             :                               thisPIU.HotControlNode,
    1674             :                               MaxWaterFlow,
    1675             :                               MinWaterFlow,
    1676             :                               thisPIU.HotControlOffset,
    1677      114852 :                               thisPIU.ControlCompTypeNum,
    1678      114852 :                               thisPIU.CompErrIndex,
    1679      114852 :                               thisPIU.HCoilInAirNode,
    1680      114852 :                               thisPIU.OutAirNode,
    1681             :                               _,
    1682             :                               _,
    1683             :                               _,
    1684      114852 :                               thisPIU.HWplantLoc);
    1685             :         }
    1686      276483 :         break;
    1687             :     }
    1688           0 :     case HtgCoilType::SteamAirHeating: { // COIL:STEAM:AIRHEATING
    1689           0 :         SimulateSteamCoilComponents(state, thisPIU.HCoil, FirstHVACIteration, thisPIU.HCoil_Index, QCoilReq);
    1690           0 :         break;
    1691             :     }
    1692       10719 :     case HtgCoilType::Electric: { // COIL:ELECTRIC:HEATING
    1693       10719 :         SimulateHeatingCoilComponents(state, thisPIU.HCoil, FirstHVACIteration, QCoilReq, thisPIU.HCoil_Index);
    1694       10719 :         break;
    1695             :     }
    1696           0 :     case HtgCoilType::Gas: { // COIL:GAS:HEATING
    1697           0 :         SimulateHeatingCoilComponents(state, thisPIU.HCoil, FirstHVACIteration, QCoilReq, thisPIU.HCoil_Index);
    1698           0 :         break;
    1699             :     }
    1700           0 :     default:
    1701           0 :         break;
    1702             :     }
    1703             : 
    1704             :     // Power supplied
    1705      287202 :     Real64 PowerMet = state.dataLoopNodes->Node(thisPIU.OutAirNode).MassFlowRate *
    1706      287202 :                       (PsyHFnTdbW(state.dataLoopNodes->Node(thisPIU.OutAirNode).Temp, state.dataLoopNodes->Node(ZoneNode).HumRat) -
    1707      287202 :                        PsyHFnTdbW(state.dataLoopNodes->Node(ZoneNode).Temp, state.dataLoopNodes->Node(ZoneNode).HumRat));
    1708      287202 :     thisPIU.HeatingRate = max(0.0, PowerMet);
    1709      287202 :     thisPIU.SensCoolRate = std::abs(min(DataPrecisionGlobals::constant_zero, PowerMet));
    1710      287202 :     thisPIU.TotMassFlowRate = state.dataLoopNodes->Node(thisPIU.OutAirNode).MassFlowRate;
    1711      287202 :     thisPIU.SecMassFlowRate = state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate;
    1712      287202 :     thisPIU.PriMassFlowRate = state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRate;
    1713      287202 :     thisPIU.DischargeAirTemp = state.dataLoopNodes->Node(thisPIU.OutAirNode).Temp;
    1714      287202 :     if (state.dataLoopNodes->Node(thisPIU.OutAirNode).MassFlowRate == 0.0) {
    1715       59032 :         state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRate = 0.0;
    1716       59032 :         state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate = 0.0;
    1717             :     }
    1718      287202 :     if (thisPIU.InducesPlenumAir) {
    1719      168070 :         state.dataHVACGlobal->PlenumInducedMassFlow = state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate;
    1720             :     } else {
    1721      119132 :         state.dataHVACGlobal->PlenumInducedMassFlow = 0.0;
    1722             :     }
    1723      287202 :     state.dataDefineEquipment->AirDistUnit(thisPIU.ADUNum).MassFlowRatePlenInd = state.dataHVACGlobal->PlenumInducedMassFlow;
    1724      287202 :     state.dataLoopNodes->Node(thisPIU.OutAirNode).MassFlowRateMax = thisPIU.MaxTotAirMassFlow;
    1725             : 
    1726      287202 :     ReportCurOperatingControlStage(state, PIUNum, UnitOn, thisPIU.heatingOperatingMode, thisPIU.coolingOperatingMode);
    1727      287202 : }
    1728             : 
    1729       21546 : void CalcParallelPIU(EnergyPlusData &state,
    1730             :                      int const PIUNum,             // number of the current PIU being simulated
    1731             :                      int const ZoneNum,            // number of zone being served
    1732             :                      int const ZoneNode,           // zone node number
    1733             :                      bool const FirstHVACIteration // TRUE if 1st HVAC simulation of system timestep
    1734             : )
    1735             : {
    1736             : 
    1737             :     // SUBROUTINE INFORMATION:
    1738             :     //       AUTHOR         Fred Buhl
    1739             :     //       DATE WRITTEN   August 2000
    1740             :     //       MODIFIED       September 2016, March 2017
    1741             : 
    1742             :     // PURPOSE OF THIS SUBROUTINE:
    1743             :     // Simulate a parallel powered induction unit; adjust its primary air flow
    1744             :     // and reheat coil output to match the zone load.
    1745             : 
    1746             :     // METHODOLOGY EMPLOYED:
    1747             :     // If unit is on and there is a cooling load:
    1748             :     // (1) simulate fan at max secondary air flow and heating coil
    1749             :     //     off. Obtains fan temperature increase.
    1750             :     // (2) Calculates primary and secomdary air flow to meet zone load.
    1751             :     //     (a) Assume fan is off and calculate primary air flow to meet cooling load.
    1752             :     //     (b1) If calculated primary air flow is above the fan turn on ratio, fan is off.
    1753             :     //         Otherwise fan is on; calculate mixed secondary and primary air flow that
    1754             :     //         will meet the zone load
    1755             :     //     (b2) If the fan turn on ratio is zero, then the fan is on only if reheat is needed.
    1756             :     //  (3) Simulate fan, mixer, and (off) heating coil to obtain zone inlet conditions.
    1757             :     // If unit is on and there is a heating load
    1758             :     // (1) sets primary air flow to a minimum.
    1759             :     // (2) simulates fan and mixer
    1760             :     // (3) if reheat is hot water, calls ControlCompOutput to simulate hot
    1761             :     //     water coil and adjust water flow to match coil output to the zone load.
    1762             :     // (4) if reheat is electric or gas calls SimulateHeatingCoilComponents to
    1763             :     //     simulate coil at coil output that matches the zone load
    1764             : 
    1765             :     using namespace DataZoneEnergyDemands;
    1766             :     using HeatingCoils::SimulateHeatingCoilComponents;
    1767             :     using MixerComponent::SimAirMixer;
    1768             :     using PlantUtilities::SetComponentFlowRate;
    1769             :     using SteamCoils::SimulateSteamCoilComponents;
    1770             :     using WaterCoils::SimulateWaterCoilComponents;
    1771             : 
    1772       21546 :     bool UnitOn(true); // TRUE if unit is on
    1773       21546 :     bool PriOn(true);  // TRUE if primary air available
    1774             : 
    1775       21546 :     Real64 QCoilReq = 0.0;     // required heating coil outlet to meet zone load
    1776       21546 :     Real64 MaxWaterFlow = 0.0; // maximum water flow for heating or cooling [kg/s]
    1777       21546 :     Real64 MinWaterFlow = 0.0; // minimum water flow for heating or cooling [kg/s]
    1778             : 
    1779             :     // initialize local variables
    1780       21546 :     auto &thisPIU = state.dataPowerInductionUnits->PIU(PIUNum);
    1781             : 
    1782       21546 :     Real64 const PriAirMassFlowMax = state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRateMaxAvail; // max primary air mass flow rate [kg/s]
    1783       21546 :     Real64 const PriAirMassFlowMin = state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRateMinAvail; // min primary air mass flow rate [kg/s]
    1784       21546 :     thisPIU.PriAirMassFlow = state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRate;                 // primary air mass flow rate [kg/s]
    1785       21546 :     thisPIU.SecAirMassFlow = state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate;                 // secondary air mass flow rate [kg/s]
    1786             :     Real64 const QZnReq =
    1787       21546 :         state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputRequired; // heating or cooling needed by zone [Watts]
    1788             :     Real64 const QToHeatSetPt =
    1789       21546 :         state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputReqToHeatSP; // [W]  remaining load to heating setpoint
    1790       21546 :     Real64 const CpAirZn = PsyCpAirFnW(state.dataLoopNodes->Node(ZoneNode).HumRat);          // zone air specific heat [J/kg-C]
    1791       21546 :     thisPIU.heatingOperatingMode = HeatOpModeType::HeaterOff;
    1792       21546 :     thisPIU.coolingOperatingMode = CoolOpModeType::CoolerOff;
    1793             : 
    1794             :     // On the first HVAC iteration the system values are given to the controller, but after that
    1795             :     // the demand limits are in place and there needs to be feedback to the Zone Equipment
    1796       21546 :     if (thisPIU.HotControlNode > 0) {
    1797       21546 :         if (FirstHVACIteration) {
    1798       10789 :             MaxWaterFlow = thisPIU.MaxHotWaterFlow;
    1799       10789 :             MinWaterFlow = thisPIU.MinHotWaterFlow;
    1800             :         } else {
    1801       10757 :             MaxWaterFlow = state.dataLoopNodes->Node(thisPIU.HotControlNode).MassFlowRateMaxAvail;
    1802       10757 :             MinWaterFlow = state.dataLoopNodes->Node(thisPIU.HotControlNode).MassFlowRateMinAvail;
    1803             :         }
    1804             :     }
    1805       21546 :     if (GetCurrentScheduleValue(state, thisPIU.SchedPtr) <= 0.0) {
    1806          14 :         UnitOn = false;
    1807             :     }
    1808       21546 :     if (thisPIU.PriAirMassFlow <= SmallMassFlow || PriAirMassFlowMax <= SmallMassFlow) {
    1809         788 :         PriOn = false;
    1810             :     }
    1811             :     // Set the mass flow rates
    1812       21546 :     if (UnitOn) {
    1813             :         // unit is on
    1814             :         // Calculate if reheat is needed
    1815       21532 :         bool ReheatRequired = false;
    1816             :         Real64 const qMinPrimary =
    1817             :             PriAirMassFlowMin *
    1818       21532 :             (CpAirZn * min(-SmallTempDiff, (state.dataLoopNodes->Node(thisPIU.PriAirInNode).Temp - state.dataLoopNodes->Node(ZoneNode).Temp)));
    1819       21532 :         if (qMinPrimary < QToHeatSetPt) {
    1820       14997 :             ReheatRequired = true;
    1821             :         }
    1822             : 
    1823       21532 :         if (!PriOn) {
    1824             :             // no primary air flow
    1825         774 :             thisPIU.PriAirMassFlow = 0.0;
    1826             :             // PIU fan off if there is no heating load, also reset fan flag if fan should be off
    1827         774 :             if (QZnReq <= SmallLoad) {
    1828          49 :                 thisPIU.SecAirMassFlow = 0.0;
    1829          49 :                 state.dataHVACGlobal->TurnFansOn = false;
    1830             :             } else {
    1831         725 :                 if (thisPIU.fanControlType == FanCntrlType::VariableSpeedFan &&
    1832           6 :                     thisPIU.heatingControlType == HeatCntrlBehaviorType::StagedHeaterBehavior) {
    1833           3 :                     CalcVariableSpeedPIUStagedHeatingBehavior(state, PIUNum, ZoneNode, QZnReq, PriOn, thisPIU.PriAirMassFlow);
    1834         722 :                 } else if (thisPIU.fanControlType == FanCntrlType::VariableSpeedFan &&
    1835           3 :                            thisPIU.heatingControlType == HeatCntrlBehaviorType::ModulatedHeaterBehavior) {
    1836           3 :                     CalcVariableSpeedPIUModulatedHeatingBehavior(state, PIUNum, ZoneNode, QZnReq, PriOn, thisPIU.PriAirMassFlow);
    1837         719 :                 } else if (thisPIU.fanControlType == FanCntrlType::ConstantSpeedFan) {
    1838         719 :                     thisPIU.heatingOperatingMode = HeatOpModeType::ConstantVolumeHeat;
    1839         719 :                     thisPIU.SecAirMassFlow = thisPIU.MaxSecAirMassFlow;
    1840             :                 }
    1841             :             }
    1842       20758 :         } else if (state.dataZoneEnergyDemand->CurDeadBandOrSetback(ZoneNum) || std::abs(QZnReq) < SmallLoad) {
    1843             :             // in deadband or very small load: set primary air flow to the minimum
    1844        5161 :             thisPIU.PriAirMassFlow = PriAirMassFlowMin;
    1845             :             // PIU fan off if reheat is not needed, also reset fan flag if fan should be off
    1846        5161 :             if (ReheatRequired) {
    1847        5011 :                 state.dataHVACGlobal->TurnFansOn = true;
    1848        5011 :                 if (thisPIU.fanControlType == FanCntrlType::ConstantSpeedFan) {
    1849        2493 :                     thisPIU.heatingOperatingMode = HeatOpModeType::ConstantVolumeHeat;
    1850        2493 :                     thisPIU.SecAirMassFlow = thisPIU.MaxSecAirMassFlow;
    1851        2518 :                 } else if (thisPIU.fanControlType == FanCntrlType::VariableSpeedFan) {
    1852        2518 :                     if (thisPIU.heatingControlType == HeatCntrlBehaviorType::StagedHeaterBehavior) {
    1853        1387 :                         thisPIU.heatingOperatingMode = HeatOpModeType::StagedHeatFirstStage;
    1854             :                     } else {
    1855        1131 :                         thisPIU.heatingOperatingMode = HeatOpModeType::ModulatedHeatFirstStage;
    1856             :                     }
    1857        2518 :                     thisPIU.SecAirMassFlow = thisPIU.MinSecAirMassFlow;
    1858             :                 }
    1859             :             } else {
    1860         150 :                 thisPIU.SecAirMassFlow = 0.0;
    1861         150 :                 state.dataHVACGlobal->TurnFansOn = false;
    1862         150 :                 thisPIU.heatingOperatingMode = HeatOpModeType::HeaterOff;
    1863             :             }
    1864       15597 :         } else if (QZnReq > SmallLoad) {
    1865             :             // heating
    1866             :             // set primary air flow to the minimum
    1867        8199 :             thisPIU.PriAirMassFlow = PriAirMassFlowMin;
    1868             :             // determine secondary flow rate
    1869        8199 :             if (thisPIU.fanControlType == FanCntrlType::VariableSpeedFan &&
    1870        2706 :                 thisPIU.heatingControlType == HeatCntrlBehaviorType::StagedHeaterBehavior) {
    1871        1356 :                 CalcVariableSpeedPIUStagedHeatingBehavior(state, PIUNum, ZoneNode, QZnReq, PriOn, thisPIU.PriAirMassFlow);
    1872        6843 :             } else if (thisPIU.fanControlType == FanCntrlType::VariableSpeedFan &&
    1873        1350 :                        thisPIU.heatingControlType == HeatCntrlBehaviorType::ModulatedHeaterBehavior) {
    1874        1350 :                 CalcVariableSpeedPIUModulatedHeatingBehavior(state, PIUNum, ZoneNode, QZnReq, PriOn, thisPIU.PriAirMassFlow);
    1875        5493 :             } else if (thisPIU.fanControlType == FanCntrlType::ConstantSpeedFan) {
    1876        5493 :                 thisPIU.heatingOperatingMode = HeatOpModeType::ConstantVolumeHeat;
    1877        5493 :                 thisPIU.SecAirMassFlow = thisPIU.MaxSecAirMassFlow;
    1878             :             }
    1879             :         } else {
    1880             :             // cooling: set the primary air flow rate to meet the load.
    1881             :             // First calculate the fan temperature rise
    1882        7398 :             state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate = thisPIU.MaxSecAirMassFlow;
    1883        7398 :             state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRateMaxAvail = thisPIU.MaxSecAirMassFlow;
    1884        7398 :             state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRate = 0.0;
    1885             : 
    1886        7398 :             state.dataFans->fans(thisPIU.Fan_Index)->simulate(state, FirstHVACIteration, _, _);
    1887             : 
    1888        7398 :             SimAirMixer(state, thisPIU.MixerName, thisPIU.Mixer_Num); // fire the mixer
    1889             :             // fan temperature rise [C]
    1890        7398 :             Real64 const FanDeltaTemp = state.dataLoopNodes->Node(thisPIU.HCoilInAirNode).Temp - state.dataLoopNodes->Node(thisPIU.SecAirInNode).Temp;
    1891             :             // Assuming the fan is off, calculate the primary air flow needed to meet the zone cooling demand.
    1892        7398 :             thisPIU.PriAirMassFlow =
    1893        7398 :                 QZnReq /
    1894        7398 :                 (CpAirZn * min(-SmallTempDiff, (state.dataLoopNodes->Node(thisPIU.PriAirInNode).Temp - state.dataLoopNodes->Node(ZoneNode).Temp)));
    1895        7398 :             thisPIU.PriAirMassFlow = min(max(thisPIU.PriAirMassFlow, PriAirMassFlowMin), PriAirMassFlowMax);
    1896             :             // check for fan on or off
    1897        7398 :             if ((thisPIU.PriAirMassFlow > thisPIU.FanOnAirMassFlow) && !ReheatRequired) {
    1898        6336 :                 thisPIU.SecAirMassFlow = 0.0; // Fan is off unless reheat is required; no secondary air; also reset fan flag
    1899        6336 :                 state.dataHVACGlobal->TurnFansOn = false;
    1900             :             } else {
    1901             :                 // fan is on; recalc primary air flow
    1902        1062 :                 thisPIU.PriAirMassFlow =
    1903        2124 :                     (QZnReq - CpAirZn * thisPIU.SecAirMassFlow *
    1904        1062 :                                   (state.dataLoopNodes->Node(thisPIU.SecAirInNode).Temp + FanDeltaTemp - state.dataLoopNodes->Node(ZoneNode).Temp)) /
    1905        1062 :                     (CpAirZn *
    1906        1062 :                      min(-SmallTempDiff, (state.dataLoopNodes->Node(thisPIU.PriAirInNode).Temp - state.dataLoopNodes->Node(ZoneNode).Temp)));
    1907        1062 :                 thisPIU.PriAirMassFlow = min(max(thisPIU.PriAirMassFlow, PriAirMassFlowMin), PriAirMassFlowMax);
    1908        1062 :                 thisPIU.SecAirMassFlow = thisPIU.MaxSecAirMassFlow;
    1909             :             }
    1910        7398 :             if (QZnReq < 0) {
    1911        7398 :                 if (thisPIU.fanControlType == FanCntrlType::VariableSpeedFan) {
    1912        2076 :                     if (thisPIU.PriAirMassFlow == PriAirMassFlowMax) {
    1913           0 :                         thisPIU.coolingOperatingMode = CoolOpModeType::CoolSecondStage;
    1914             :                     } else {
    1915        2076 :                         thisPIU.coolingOperatingMode = CoolOpModeType::CoolFirstStage;
    1916             :                     }
    1917             :                 } else {
    1918        5322 :                     thisPIU.coolingOperatingMode = CoolOpModeType::ConstantVolumeCool;
    1919             :                 }
    1920             :             }
    1921             :         }
    1922             :     } else {
    1923             :         // unit is off; no flow
    1924          14 :         thisPIU.PriAirMassFlow = 0.0;
    1925          14 :         thisPIU.SecAirMassFlow = 0.0;
    1926             :     }
    1927             :     // set inlet node flowrates
    1928       21546 :     state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRate = thisPIU.PriAirMassFlow;
    1929       21546 :     state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate = thisPIU.SecAirMassFlow;
    1930       21546 :     state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRateMaxAvail = thisPIU.SecAirMassFlow;
    1931       21546 :     if (PriAirMassFlowMax == 0) {
    1932         787 :         thisPIU.PriDamperPosition = 0;
    1933             :     } else {
    1934       20759 :         thisPIU.PriDamperPosition = thisPIU.PriAirMassFlow / PriAirMassFlowMax;
    1935             :     }
    1936             : 
    1937             :     // now that inlet airflows have been set, the terminal box components can be simulated.
    1938             :     // fire the fan
    1939       21546 :     if (thisPIU.fanType == HVAC::FanType::SystemModel) {
    1940       14308 :         if (thisPIU.fanControlType == FanCntrlType::VariableSpeedFan) {
    1941             :             // calculate fan speed ratio
    1942        7366 :             Real64 fanFlowRatio(1.0);
    1943        7366 :             if (thisPIU.MaxSecAirMassFlow > 0.0) {
    1944        7364 :                 fanFlowRatio = thisPIU.SecAirMassFlow / thisPIU.MaxSecAirMassFlow;
    1945             :             }
    1946        7366 :             state.dataFans->fans(thisPIU.Fan_Index)->simulate(state, FirstHVACIteration, fanFlowRatio, _);
    1947             :         } else {
    1948        6942 :             state.dataFans->fans(thisPIU.Fan_Index)->simulate(state, FirstHVACIteration, _, _);
    1949             :         }
    1950        7238 :     } else if (thisPIU.fanType == HVAC::FanType::Constant) {
    1951        7238 :         state.dataFans->fans(thisPIU.Fan_Index)->simulate(state, FirstHVACIteration, _, _);
    1952             :     }
    1953             : 
    1954             :     // fire the mixer
    1955       21546 :     SimAirMixer(state, thisPIU.MixerName, thisPIU.Mixer_Num);
    1956             : 
    1957             :     // the heating load seen by the reheat coil [W]
    1958       21546 :     Real64 QActualHeating = QToHeatSetPt - state.dataLoopNodes->Node(thisPIU.HCoilInAirNode).MassFlowRate * CpAirZn *
    1959       21546 :                                                (state.dataLoopNodes->Node(thisPIU.HCoilInAirNode).Temp - state.dataLoopNodes->Node(ZoneNode).Temp);
    1960             : 
    1961             :     // check if heating coil is off
    1962       21532 :     if (((!UnitOn) || (QActualHeating < SmallLoad) || (state.dataHeatBalFanSys->TempControlType(ZoneNum) == HVAC::ThermostatType::SingleCooling) ||
    1963       43092 :          (thisPIU.PriAirMassFlow > PriAirMassFlowMin)) &&
    1964       12659 :         (thisPIU.heatingOperatingMode != HeatOpModeType::StagedHeatFirstStage)) { // reheat is off during the first stage of heating
    1965       11261 :         thisPIU.heatingOperatingMode = HeatOpModeType::HeaterOff;
    1966             :     }
    1967             : 
    1968             :     // determine what is required of heater for current operating stage
    1969       21546 :     if (thisPIU.heatingOperatingMode == HeatOpModeType::HeaterOff) {
    1970       11271 :         QCoilReq = 0.0;
    1971       10275 :     } else if (thisPIU.heatingOperatingMode == HeatOpModeType::StagedHeatFirstStage) {
    1972        1400 :         QCoilReq = 0.0;
    1973        8875 :     } else if (thisPIU.heatingOperatingMode == HeatOpModeType::ConstantVolumeHeat) {
    1974        6199 :         QCoilReq = QActualHeating;
    1975        2676 :     } else if (thisPIU.heatingOperatingMode == HeatOpModeType::StagedHeatSecondStage) {
    1976        1330 :         QCoilReq = QActualHeating;
    1977        1346 :     } else if (thisPIU.heatingOperatingMode == HeatOpModeType::ModulatedHeatFirstStage) {
    1978        1346 :         QCoilReq = QActualHeating;
    1979           0 :     } else if (thisPIU.heatingOperatingMode == HeatOpModeType::ModulatedHeatSecondStage) {
    1980             :         // find heater power to deliver design discharge air temperature
    1981           0 :         Real64 targetDATEnthalpy = Psychrometrics::PsyHFnTdbW(thisPIU.designHeatingDAT, state.dataLoopNodes->Node(ZoneNode).HumRat);
    1982             :         Real64 mixAirEnthalpy =
    1983           0 :             Psychrometrics::PsyHFnTdbW(state.dataLoopNodes->Node(thisPIU.HCoilInAirNode).Temp, state.dataLoopNodes->Node(ZoneNode).HumRat);
    1984           0 :         QCoilReq = state.dataLoopNodes->Node(thisPIU.HCoilInAirNode).MassFlowRate * (targetDATEnthalpy - mixAirEnthalpy);
    1985           0 :     } else if (thisPIU.heatingOperatingMode == HeatOpModeType::ModulatedHeatThirdStage) {
    1986             :         // find heater power to deliver maximum discharge air temperature
    1987           0 :         Real64 HiLimitDATEnthalpy = Psychrometrics::PsyHFnTdbW(thisPIU.highLimitDAT, state.dataLoopNodes->Node(ZoneNode).HumRat);
    1988             :         Real64 mixAirEnthalpy =
    1989           0 :             Psychrometrics::PsyHFnTdbW(state.dataLoopNodes->Node(thisPIU.HCoilInAirNode).Temp, state.dataLoopNodes->Node(ZoneNode).HumRat);
    1990           0 :         Real64 QcoilLimit = state.dataLoopNodes->Node(thisPIU.HCoilInAirNode).MassFlowRate * (HiLimitDATEnthalpy - mixAirEnthalpy);
    1991           0 :         if (QcoilLimit < QActualHeating) { // if requried power is too high use limit of coil discharge
    1992           0 :             QCoilReq = QcoilLimit;
    1993             :         } else {
    1994           0 :             QCoilReq = QActualHeating;
    1995             :         }
    1996             :     } else {
    1997           0 :         ShowSevereError(state, "Incorrect parallel PIU heating operation.");
    1998           0 :         ShowFatalError(state, format("Parallel PIU control failed for {}:{}", thisPIU.UnitType, thisPIU.Name));
    1999             :     }
    2000       21546 :     if ((QCoilReq < SmallLoad) &&
    2001       12671 :         (thisPIU.heatingOperatingMode != HeatOpModeType::StagedHeatFirstStage)) { // reheat is off during the first stage of heating
    2002       11271 :         thisPIU.heatingOperatingMode = HeatOpModeType::HeaterOff;
    2003       11271 :         QCoilReq = 0.0;
    2004             :     }
    2005             : 
    2006             :     // fire the heating coil
    2007       21546 :     switch (thisPIU.HCoilType) {
    2008       21546 :     case HtgCoilType::SimpleHeating: { // COIL:WATER:SIMPLEHEATING
    2009       21546 :         if ((thisPIU.heatingOperatingMode == HeatOpModeType::HeaterOff) || (thisPIU.heatingOperatingMode == HeatOpModeType::StagedHeatFirstStage)) {
    2010             :             // call the reheat coil with the NO FLOW condition
    2011       12671 :             Real64 mdot = 0.0;
    2012       12671 :             SetComponentFlowRate(state, mdot, thisPIU.HotControlNode, thisPIU.HotCoilOutNodeNum, thisPIU.HWplantLoc);
    2013       12671 :             SimulateWaterCoilComponents(state, thisPIU.HCoil, FirstHVACIteration, thisPIU.HCoil_Index);
    2014       12671 :         } else {
    2015             :             // control water flow to obtain output matching QZnReq
    2016       26625 :             ControlCompOutput(state,
    2017        8875 :                               thisPIU.HCoil,
    2018        8875 :                               thisPIU.UnitType,
    2019        8875 :                               thisPIU.HCoil_Index,
    2020             :                               FirstHVACIteration,
    2021             :                               QCoilReq,
    2022             :                               thisPIU.HotControlNode,
    2023             :                               MaxWaterFlow,
    2024             :                               MinWaterFlow,
    2025             :                               thisPIU.HotControlOffset,
    2026        8875 :                               thisPIU.ControlCompTypeNum,
    2027        8875 :                               thisPIU.CompErrIndex,
    2028        8875 :                               thisPIU.HCoilInAirNode,
    2029        8875 :                               thisPIU.OutAirNode,
    2030             :                               _,
    2031             :                               _,
    2032             :                               _,
    2033        8875 :                               thisPIU.HWplantLoc);
    2034             :         }
    2035       21546 :         break;
    2036             :     }
    2037           0 :     case HtgCoilType::SteamAirHeating: { // COIL:STEAM:AIRHEATING
    2038           0 :         SimulateSteamCoilComponents(state, thisPIU.HCoil, FirstHVACIteration, thisPIU.HCoil_Index, QCoilReq);
    2039           0 :         break;
    2040             :     }
    2041           0 :     case HtgCoilType::Electric: { // COIL:ELECTRIC:HEATING
    2042           0 :         SimulateHeatingCoilComponents(state, thisPIU.HCoil, FirstHVACIteration, QCoilReq, thisPIU.HCoil_Index);
    2043           0 :         break;
    2044             :     }
    2045           0 :     case HtgCoilType::Gas: { // COIL:GAS:HEATING
    2046           0 :         SimulateHeatingCoilComponents(state, thisPIU.HCoil, FirstHVACIteration, QCoilReq, thisPIU.HCoil_Index);
    2047           0 :         break;
    2048             :     }
    2049           0 :     default:
    2050           0 :         break;
    2051             :     }
    2052             :     // Power supplied
    2053       21546 :     Real64 PowerMet = state.dataLoopNodes->Node(thisPIU.OutAirNode).MassFlowRate *
    2054       21546 :                       (PsyHFnTdbW(state.dataLoopNodes->Node(thisPIU.OutAirNode).Temp, state.dataLoopNodes->Node(ZoneNode).HumRat) -
    2055       21546 :                        PsyHFnTdbW(state.dataLoopNodes->Node(ZoneNode).Temp, state.dataLoopNodes->Node(ZoneNode).HumRat));
    2056       21546 :     thisPIU.HeatingRate = max(0.0, PowerMet);
    2057       21546 :     thisPIU.SensCoolRate = std::abs(min(DataPrecisionGlobals::constant_zero, PowerMet));
    2058       21546 :     thisPIU.TotMassFlowRate = state.dataLoopNodes->Node(thisPIU.OutAirNode).MassFlowRate;
    2059       21546 :     thisPIU.SecMassFlowRate = state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate;
    2060       21546 :     thisPIU.PriMassFlowRate = state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRate;
    2061       21546 :     thisPIU.DischargeAirTemp = state.dataLoopNodes->Node(thisPIU.OutAirNode).Temp;
    2062       21546 :     if (state.dataLoopNodes->Node(thisPIU.OutAirNode).MassFlowRate == 0.0) {
    2063          74 :         state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRate = 0.0;
    2064          74 :         state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate = 0.0;
    2065             :     }
    2066       21546 :     if (thisPIU.InducesPlenumAir) {
    2067        7300 :         state.dataHVACGlobal->PlenumInducedMassFlow = state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate;
    2068             :     } else {
    2069       14246 :         state.dataHVACGlobal->PlenumInducedMassFlow = 0.0;
    2070             :     }
    2071       21546 :     state.dataDefineEquipment->AirDistUnit(thisPIU.ADUNum).MassFlowRatePlenInd = state.dataHVACGlobal->PlenumInducedMassFlow;
    2072       21546 :     state.dataLoopNodes->Node(thisPIU.OutAirNode).MassFlowRateMax = thisPIU.MaxPriAirMassFlow;
    2073             : 
    2074       21546 :     ReportCurOperatingControlStage(state, PIUNum, UnitOn, thisPIU.heatingOperatingMode, thisPIU.coolingOperatingMode);
    2075       21546 : }
    2076             : 
    2077      308748 : void ReportCurOperatingControlStage(EnergyPlusData &state, int const piuNum, bool const unitOn, HeatOpModeType heaterMode, CoolOpModeType coolingMode)
    2078             : {
    2079      308748 :     int undetermined(-1);
    2080      308748 :     int off(0);
    2081      308748 :     int constantVolumeCooling(1);
    2082      308748 :     int constantVolumeHeating(2);
    2083      308748 :     int deadband(3);
    2084      308748 :     int variableSpeedFirstStageCooling(4);
    2085      308748 :     int variableSpeedSecondStageCooling(5);
    2086      308748 :     int variableSpeedStagedHeatFirstStageHeating(6);
    2087      308748 :     int variableSpeedStagedHeatSecondStageHeating(7);
    2088      308748 :     int variableSpeedModulatedHeatFirstStageHeating(8);
    2089      308748 :     int variableSpeedModulatedHeatSecondStageHeating(9);
    2090      308748 :     int variableSpeedModulatedHeatThirdStageHeating(10);
    2091             : 
    2092      308748 :     state.dataPowerInductionUnits->PIU(piuNum).CurOperationControlStage = undetermined;
    2093             : 
    2094      308748 :     if (!unitOn) {
    2095       56947 :         state.dataPowerInductionUnits->PIU(piuNum).CurOperationControlStage = off;
    2096             :     } else {
    2097      251801 :         if (state.dataPowerInductionUnits->PIU(piuNum).fanControlType == FanCntrlType::ConstantSpeedFan) {
    2098      237069 :             if (heaterMode != HeatOpModeType::HeaterOff && coolingMode == CoolOpModeType::CoolerOff) {
    2099      122663 :                 state.dataPowerInductionUnits->PIU(piuNum).CurOperationControlStage = constantVolumeHeating;
    2100      114406 :             } else if (coolingMode != CoolOpModeType::CoolerOff && heaterMode == HeatOpModeType::HeaterOff) {
    2101       68904 :                 state.dataPowerInductionUnits->PIU(piuNum).CurOperationControlStage = constantVolumeCooling;
    2102             :             } else {
    2103       45502 :                 state.dataPowerInductionUnits->PIU(piuNum).CurOperationControlStage = deadband;
    2104             :             }
    2105             :         }
    2106      251801 :         if (state.dataPowerInductionUnits->PIU(piuNum).fanControlType == FanCntrlType::VariableSpeedFan) {
    2107       14732 :             if (heaterMode != HeatOpModeType::HeaterOff) {
    2108        6770 :                 if (state.dataPowerInductionUnits->PIU(piuNum).heatingControlType == HeatCntrlBehaviorType::StagedHeaterBehavior) {
    2109        4078 :                     if (heaterMode == HeatOpModeType::StagedHeatFirstStage) {
    2110        1400 :                         state.dataPowerInductionUnits->PIU(piuNum).CurOperationControlStage = variableSpeedStagedHeatFirstStageHeating;
    2111        2678 :                     } else if (heaterMode == HeatOpModeType::StagedHeatSecondStage) {
    2112        2678 :                         state.dataPowerInductionUnits->PIU(piuNum).CurOperationControlStage = variableSpeedStagedHeatSecondStageHeating;
    2113             :                     }
    2114        2692 :                 } else if (state.dataPowerInductionUnits->PIU(piuNum).heatingControlType == HeatCntrlBehaviorType::ModulatedHeaterBehavior) {
    2115        2692 :                     if (heaterMode == HeatOpModeType::ModulatedHeatFirstStage) {
    2116        2692 :                         state.dataPowerInductionUnits->PIU(piuNum).CurOperationControlStage = variableSpeedModulatedHeatFirstStageHeating;
    2117           0 :                     } else if (heaterMode == HeatOpModeType::ModulatedHeatSecondStage) {
    2118           0 :                         state.dataPowerInductionUnits->PIU(piuNum).CurOperationControlStage = variableSpeedModulatedHeatSecondStageHeating;
    2119           0 :                     } else if (heaterMode == HeatOpModeType::ModulatedHeatThirdStage) {
    2120           0 :                         state.dataPowerInductionUnits->PIU(piuNum).CurOperationControlStage = variableSpeedModulatedHeatThirdStageHeating;
    2121             :                     }
    2122             :                 }
    2123        7962 :             } else if (coolingMode == CoolOpModeType::CoolFirstStage) {
    2124        3492 :                 state.dataPowerInductionUnits->PIU(piuNum).CurOperationControlStage = variableSpeedFirstStageCooling;
    2125        4470 :             } else if (coolingMode == CoolOpModeType::CoolSecondStage) {
    2126           0 :                 state.dataPowerInductionUnits->PIU(piuNum).CurOperationControlStage = variableSpeedSecondStageCooling;
    2127        4470 :             } else if (heaterMode == HeatOpModeType::HeaterOff && coolingMode == CoolOpModeType::CoolerOff) {
    2128        4470 :                 state.dataPowerInductionUnits->PIU(piuNum).CurOperationControlStage = deadband;
    2129             :             }
    2130             :         }
    2131             :     }
    2132      308748 : }
    2133             : 
    2134        1792 : void CalcVariableSpeedPIUCoolingBehavior(EnergyPlusData &state,
    2135             :                                          int const piuNum,   // number of the current PIU being simulated
    2136             :                                          int const zoneNode, // zone node number
    2137             :                                          Real64 const zoneLoad,
    2138             :                                          Real64 const loadToHeatSetPt,
    2139             :                                          Real64 const priAirMassFlowMin,
    2140             :                                          Real64 const priAirMassFlowMax)
    2141             : {
    2142        1792 :     auto &thisPIU = state.dataPowerInductionUnits->PIU(piuNum);
    2143        1792 :     thisPIU.coolingOperatingMode = CoolOpModeType::CoolerOff;
    2144             : 
    2145             :     // set min primary flow and low secondary
    2146        1792 :     state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRate = priAirMassFlowMin;
    2147        1792 :     Real64 TotAirMassFlow = thisPIU.MinTotAirMassFlow;
    2148        1792 :     state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate = max(0.0, TotAirMassFlow - priAirMassFlowMin);
    2149             : 
    2150             :     // calculate cooling provided to zone at minimum fan speed and minimum primary air mass flow
    2151        1792 :     Real64 qdotDelivMinPrim = CalcVariableSpeedPIUQdotDelivered(state, piuNum, zoneNode, false, TotAirMassFlow, thisPIU.MinFanTurnDownRatio);
    2152             : 
    2153        1792 :     if (qdotDelivMinPrim <= zoneLoad) { // will provide more cooling than required at minimum primary flow
    2154         376 :         thisPIU.PriAirMassFlow = priAirMassFlowMin;
    2155         376 :         if (qdotDelivMinPrim >=
    2156             :             loadToHeatSetPt) { // will provide more cooling than required but not enough to drop below the heating thermostat setpoint
    2157           0 :             thisPIU.SecAirMassFlow = max(0.0, thisPIU.MinTotAirMassFlow - thisPIU.PriAirMassFlow);
    2158           0 :             thisPIU.heatingOperatingMode = HeatOpModeType::HeaterOff;
    2159             :         } else {
    2160         376 :             if (thisPIU.heatingControlType == HeatCntrlBehaviorType::StagedHeaterBehavior) {
    2161         208 :                 CalcVariableSpeedPIUStagedHeatingBehavior(state, piuNum, zoneNode, loadToHeatSetPt, true, thisPIU.PriAirMassFlow);
    2162         168 :             } else if (thisPIU.heatingControlType == HeatCntrlBehaviorType::ModulatedHeaterBehavior) {
    2163         168 :                 CalcVariableSpeedPIUModulatedHeatingBehavior(state, piuNum, zoneNode, loadToHeatSetPt, true, thisPIU.PriAirMassFlow);
    2164             :             }
    2165             :         }
    2166             :     } else {
    2167             :         // check how much cooling provided at max fan and primary air
    2168        1416 :         state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRate = thisPIU.MaxPriAirMassFlow;
    2169        1416 :         Real64 TotAirMassFlow = thisPIU.MaxTotAirMassFlow;
    2170        1416 :         state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate = max(0.0, TotAirMassFlow - thisPIU.MaxPriAirMassFlow);
    2171        1416 :         Real64 qdotDelivMaxFan = CalcVariableSpeedPIUQdotDelivered(state, piuNum, zoneNode, false, TotAirMassFlow, 1.0);
    2172             : 
    2173        1416 :         if (zoneLoad <= qdotDelivMaxFan) { // not going to make it just run at max
    2174           0 :             thisPIU.PriAirMassFlow = thisPIU.PriAirMassFlow;
    2175           0 :             Real64 TotAirMassFlow = thisPIU.MaxTotAirMassFlow;
    2176           0 :             thisPIU.SecAirMassFlow = max(0.0, TotAirMassFlow - thisPIU.PriAirMassFlow);
    2177           0 :             thisPIU.heatingOperatingMode = HeatOpModeType::HeaterOff;
    2178           0 :             thisPIU.coolingOperatingMode = CoolOpModeType::CoolSecondStage;
    2179             :         } else {
    2180             :             // call regula falsi solver, vary a coooling control signal for fan speed and primary air flow together from min to max.
    2181        1416 :             int constexpr MaxIte(500);    // Maximum number of iterations
    2182        1416 :             Real64 constexpr Acc(0.0001); // Accuracy of result
    2183        1416 :             int SolFla(0);                // Flag of solver
    2184        1416 :             Real64 coolSignal = 0.5;      // starting value
    2185        7001 :             auto f = [&state, piuNum, zoneLoad, zoneNode](Real64 const coolSignal) {
    2186        7001 :                 return CalcVariableSpeedPIUCoolingResidual(state, coolSignal, piuNum, zoneLoad, zoneNode);
    2187        1416 :             };
    2188             : 
    2189        1416 :             General::SolveRoot(state, Acc, MaxIte, SolFla, coolSignal, f, 0.0, 1.0);
    2190             : 
    2191        1416 :             if (SolFla == -1) {
    2192           0 :                 ShowSevereError(state, "Iteration limit exceeded in calculating variable speed fan powered box cooling signal");
    2193           0 :                 ShowContinueErrorTimeStamp(state, "");
    2194           0 :                 ShowFatalError(state, format("Series PIU control failed for {}:{} ", thisPIU.UnitType, thisPIU.Name));
    2195        1416 :             } else if (SolFla == -2) {
    2196           0 :                 ShowSevereError(state, "Bad starting values for in calculating variable speed fan powered box cooling signal");
    2197           0 :                 ShowContinueError(state, format("Zone Load to Cooling Setpoint = {:.2R} [W]", zoneLoad));
    2198           0 :                 ShowContinueError(state, format("Load Delivered to Zone at Minimum Fan Speed  = {:.2R} [W]", qdotDelivMinPrim));
    2199           0 :                 ShowContinueErrorTimeStamp(state, "");
    2200           0 :                 ShowFatalError(state, format("Series PIU control failed for {}:{}", thisPIU.UnitType, thisPIU.Name));
    2201             :             } else {
    2202        1416 :                 thisPIU.PriAirMassFlow = coolSignal * (thisPIU.MaxPriAirMassFlow - thisPIU.MinPriAirMassFlow) + thisPIU.MinPriAirMassFlow;
    2203        1416 :                 Real64 TotAirMassFlow = coolSignal * (thisPIU.MaxTotAirMassFlow - thisPIU.MinTotAirMassFlow) + thisPIU.MinTotAirMassFlow;
    2204        1416 :                 thisPIU.SecAirMassFlow = max(0.0, TotAirMassFlow - thisPIU.PriAirMassFlow);
    2205        1416 :                 thisPIU.heatingOperatingMode = HeatOpModeType::HeaterOff;
    2206        1416 :                 thisPIU.coolingOperatingMode = CoolOpModeType::CoolFirstStage;
    2207             :             }
    2208             :         }
    2209             :     }
    2210        1792 : }
    2211             : 
    2212        2922 : void CalcVariableSpeedPIUStagedHeatingBehavior(EnergyPlusData &state,
    2213             :                                                int const piuNum,   // number of the current PIU being simulated
    2214             :                                                int const zoneNode, // zone node number
    2215             :                                                Real64 const zoneLoad,
    2216             :                                                bool const pri,
    2217             :                                                Real64 const primaryAirMassFlow)
    2218             : {
    2219        2922 :     auto &thisPIU = state.dataPowerInductionUnits->PIU(piuNum);
    2220             : 
    2221             :     // Calculate heating provided to zone with no coil at the maximum secondary flow rate: "1st stage, max fan"
    2222        2922 :     if (pri) {
    2223        2916 :         if (thisPIU.UnitType == "AirTerminal:SingleDuct:SeriesPIU:Reheat") {
    2224        1560 :             state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRate = thisPIU.MinPriAirMassFlow;
    2225        1560 :             state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate = max(0.0, thisPIU.MaxTotAirMassFlow - thisPIU.MinPriAirMassFlow);
    2226        1356 :         } else if (thisPIU.UnitType == "AirTerminal:SingleDuct:ParallelPIU:Reheat") {
    2227        1356 :             state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRate = thisPIU.MinPriAirMassFlow;
    2228        1356 :             state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate = thisPIU.MaxSecAirMassFlow;
    2229             :         }
    2230             :     } else {
    2231           6 :         if (thisPIU.UnitType == "AirTerminal:SingleDuct:SeriesPIU:Reheat") {
    2232           3 :             state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRate = 0.0;
    2233           3 :             state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate = thisPIU.MaxTotAirMassFlow;
    2234           3 :         } else if (thisPIU.UnitType == "AirTerminal:SingleDuct:ParallelPIU:Reheat") {
    2235           3 :             state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRate = 0.0;
    2236           3 :             state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate = thisPIU.MaxSecAirMassFlow;
    2237             :         }
    2238             :     }
    2239             :     Real64 TotAirMassFlow =
    2240        2922 :         state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRate + state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate;
    2241        2922 :     Real64 qdotDelivered1stStageMaxFan = CalcVariableSpeedPIUQdotDelivered(state, piuNum, zoneNode, false, TotAirMassFlow, 1.0);
    2242             : 
    2243             :     // Calculate heating provided to zone with no coil at the minimum secondary flow rate: "1st stage, min fan"
    2244        2922 :     if (pri) {
    2245        2916 :         if (thisPIU.UnitType == "AirTerminal:SingleDuct:SeriesPIU:Reheat") {
    2246        1560 :             state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRate = thisPIU.MinPriAirMassFlow;
    2247        1560 :             state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate = max(0.0, thisPIU.MinTotAirMassFlow - thisPIU.MinPriAirMassFlow);
    2248        1356 :         } else if (thisPIU.UnitType == "AirTerminal:SingleDuct:ParallelPIU:Reheat") {
    2249        1356 :             state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRate = thisPIU.MinPriAirMassFlow;
    2250        1356 :             state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate = thisPIU.MinSecAirMassFlow;
    2251             :         }
    2252             :     } else {
    2253           6 :         if (thisPIU.UnitType == "AirTerminal:SingleDuct:SeriesPIU:Reheat") {
    2254           3 :             state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRate = 0.0;
    2255           3 :             state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate = thisPIU.MinTotAirMassFlow;
    2256           3 :         } else if (thisPIU.UnitType == "AirTerminal:SingleDuct:ParallelPIU:Reheat") {
    2257           3 :             state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRate = 0.0;
    2258           3 :             state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate = thisPIU.MinSecAirMassFlow;
    2259             :         }
    2260             :     }
    2261        2922 :     TotAirMassFlow = state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRate + state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate;
    2262             :     Real64 qdotDelivered1stStageMinFan =
    2263        2922 :         CalcVariableSpeedPIUQdotDelivered(state, piuNum, zoneNode, false, TotAirMassFlow, thisPIU.MinFanTurnDownRatio);
    2264             : 
    2265        2922 :     if (qdotDelivered1stStageMinFan <= zoneLoad && qdotDelivered1stStageMaxFan >= zoneLoad) { // 1st of heating (no coil) can meet the load
    2266             :         // Find fan speed/flow that meets the load through iteration
    2267          13 :         thisPIU.heatingOperatingMode = HeatOpModeType::StagedHeatFirstStage;
    2268          13 :         int constexpr MaxIte(500);   // Maximum number of iterations
    2269          13 :         Real64 constexpr Acc(0.001); // Accuracy of result
    2270          13 :         int SolFla(0);               // Flag of solver
    2271          13 :         Real64 fanSignal = 0.0;
    2272          13 :         fanSignal = (1.0 - thisPIU.MinFanTurnDownRatio) * 0.5 + thisPIU.MinFanTurnDownRatio; // average speed as the initial value
    2273          67 :         auto f = [&state, piuNum, zoneLoad, zoneNode, primaryAirMassFlow](Real64 const fanSignal) {
    2274          67 :             return CalcVariableSpeedPIUHeatingResidual(state, fanSignal, piuNum, zoneLoad, zoneNode, primaryAirMassFlow, false, fanSignal);
    2275          13 :         };
    2276             : 
    2277          13 :         General::SolveRoot(state, Acc, MaxIte, SolFla, fanSignal, f, thisPIU.MinFanTurnDownRatio, 1.0);
    2278             : 
    2279          13 :         if (SolFla == -1) {
    2280           0 :             ShowSevereError(state, "Iteration limit exceeded in calculating variable speed fan powered box 1st stage heating fan speed");
    2281           0 :             ShowContinueErrorTimeStamp(state, "");
    2282           0 :             ShowFatalError(state, format("PIU control failed for {}:{} ", thisPIU.UnitType, thisPIU.Name));
    2283          13 :         } else if (SolFla == -2) {
    2284           0 :             ShowSevereError(state, "Bad starting values in calculating variable speed fan powered box 1st stage heating fan speed");
    2285           0 :             ShowContinueErrorTimeStamp(state, "");
    2286           0 :             ShowFatalError(state, format("PIU control failed for {}:{}", thisPIU.UnitType, thisPIU.Name));
    2287             :         } else {
    2288          13 :             if (thisPIU.UnitType == "AirTerminal:SingleDuct:SeriesPIU:Reheat") {
    2289           0 :                 thisPIU.SecAirMassFlow = max(0.0, fanSignal * thisPIU.MaxTotAirMassFlow - primaryAirMassFlow);
    2290          13 :             } else if (thisPIU.UnitType == "AirTerminal:SingleDuct:ParallelPIU:Reheat") {
    2291          13 :                 thisPIU.SecAirMassFlow = max(0.0, fanSignal * thisPIU.MaxSecAirMassFlow);
    2292             :             }
    2293             :         }
    2294        2922 :     } else if (qdotDelivered1stStageMaxFan < zoneLoad) {
    2295        2892 :         thisPIU.heatingOperatingMode = HeatOpModeType::StagedHeatSecondStage;
    2296        2892 :         if (thisPIU.UnitType == "AirTerminal:SingleDuct:SeriesPIU:Reheat") {
    2297        1559 :             thisPIU.SecAirMassFlow = max(0.0, thisPIU.MaxTotAirMassFlow - primaryAirMassFlow);
    2298        1333 :         } else if (thisPIU.UnitType == "AirTerminal:SingleDuct:ParallelPIU:Reheat") {
    2299        1333 :             thisPIU.SecAirMassFlow = thisPIU.MaxSecAirMassFlow;
    2300             :         }
    2301          17 :     } else if (qdotDelivered1stStageMinFan > zoneLoad) {
    2302          17 :         thisPIU.heatingOperatingMode = HeatOpModeType::HeaterOff;
    2303          17 :         if (thisPIU.UnitType == "AirTerminal:SingleDuct:SeriesPIU:Reheat") {
    2304           4 :             thisPIU.SecAirMassFlow = max(0.0, thisPIU.MinTotAirMassFlow - thisPIU.MinPriAirMassFlow);
    2305          13 :         } else if (thisPIU.UnitType == "AirTerminal:SingleDuct:ParallelPIU:Reheat") {
    2306          13 :             thisPIU.SecAirMassFlow = 0.0;
    2307             :         }
    2308             :     }
    2309        2922 : }
    2310             : 
    2311       18996 : Real64 CalcVariableSpeedPIUQdotDelivered(EnergyPlusData &state,
    2312             :                                          int const piuNum,   // number of the current PIU being simulated
    2313             :                                          int const zoneNode, // zone node number
    2314             :                                          bool const useDAT,
    2315             :                                          Real64 const totAirMassFlow,
    2316             :                                          Real64 const fanTurnDown)
    2317             : {
    2318       18996 :     Real64 qdotDelivered = 0.0;
    2319       18996 :     auto &thisPIU = state.dataPowerInductionUnits->PIU(piuNum);
    2320       18996 :     if (thisPIU.UnitType == "AirTerminal:SingleDuct:SeriesPIU:Reheat") {
    2321       14857 :         MixerComponent::SimAirMixer(state, thisPIU.MixerName, thisPIU.Mixer_Num);
    2322       14857 :         state.dataFans->fans(thisPIU.Fan_Index)->simulate(state, false, fanTurnDown, _);
    2323             :     } else {
    2324        4139 :         state.dataFans->fans(thisPIU.Fan_Index)->simulate(state, false, fanTurnDown, _);
    2325        4139 :         MixerComponent::SimAirMixer(state, thisPIU.MixerName, thisPIU.Mixer_Num);
    2326             :     }
    2327       18996 :     Real64 zoneEnthalpy = Psychrometrics::PsyHFnTdbW(state.dataLoopNodes->Node(zoneNode).Temp, state.dataLoopNodes->Node(zoneNode).HumRat);
    2328       18996 :     Real64 piuTemp = 0.0;
    2329       18996 :     if (useDAT) {
    2330        2876 :         piuTemp = thisPIU.designHeatingDAT;
    2331             :     } else {
    2332       16120 :         piuTemp = state.dataLoopNodes->Node(thisPIU.HCoilInAirNode).Temp;
    2333             :     }
    2334       18996 :     Real64 piuEnthalpy = Psychrometrics::PsyHFnTdbW(piuTemp, state.dataLoopNodes->Node(zoneNode).HumRat);
    2335       18996 :     qdotDelivered = totAirMassFlow * (piuEnthalpy - zoneEnthalpy);
    2336       18996 :     return qdotDelivered;
    2337             : }
    2338             : 
    2339        2874 : void CalcVariableSpeedPIUModulatedHeatingBehavior(EnergyPlusData &state,
    2340             :                                                   int const piuNum,   // number of the current PIU being simulated
    2341             :                                                   int const zoneNode, // zone node number
    2342             :                                                   Real64 const zoneLoad,
    2343             :                                                   bool const pri,
    2344             :                                                   Real64 const primaryAirMassFlow)
    2345             : {
    2346        2874 :     auto &thisPIU = state.dataPowerInductionUnits->PIU(piuNum);
    2347             : 
    2348             :     // Calculate heating provided to zone with no coil at the minimum secondary flow rate: "1st stage, min fan"
    2349        2874 :     if (pri) {
    2350        2868 :         if (thisPIU.UnitType == "AirTerminal:SingleDuct:SeriesPIU:Reheat") {
    2351        1518 :             state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRate = thisPIU.MinPriAirMassFlow;
    2352        1518 :             state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate = max(0.0, thisPIU.MinTotAirMassFlow - thisPIU.MinPriAirMassFlow);
    2353        1350 :         } else if (thisPIU.UnitType == "AirTerminal:SingleDuct:ParallelPIU:Reheat") {
    2354        1350 :             state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRate = thisPIU.MinPriAirMassFlow;
    2355        1350 :             state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate = thisPIU.MinSecAirMassFlow;
    2356             :         }
    2357             :     } else {
    2358           6 :         if (thisPIU.UnitType == "AirTerminal:SingleDuct:SeriesPIU:Reheat") {
    2359           3 :             state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRate = 0.0;
    2360           3 :             state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate = thisPIU.MinTotAirMassFlow;
    2361           3 :         } else if (thisPIU.UnitType == "AirTerminal:SingleDuct:ParallelPIU:Reheat") {
    2362           3 :             state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRate = 0.0;
    2363           3 :             state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate = thisPIU.MinSecAirMassFlow;
    2364             :         }
    2365             :     }
    2366             :     Real64 TotAirMassFlow =
    2367        2874 :         state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRate + state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate;
    2368        2874 :     Real64 qdotDeliveredEnd1stStage = CalcVariableSpeedPIUQdotDelivered(state, piuNum, zoneNode, true, TotAirMassFlow, thisPIU.MinFanTurnDownRatio);
    2369        2874 :     if (qdotDeliveredEnd1stStage >= zoneLoad) { // 1st stage, find heating power at minimum fan speed
    2370        2872 :         thisPIU.heatingOperatingMode = HeatOpModeType::ModulatedHeatFirstStage;
    2371        2872 :         if (thisPIU.UnitType == "AirTerminal:SingleDuct:SeriesPIU:Reheat") {
    2372        1520 :             thisPIU.SecAirMassFlow = thisPIU.MinSecAirMassFlow;
    2373        1352 :         } else if (thisPIU.UnitType == "AirTerminal:SingleDuct:ParallelPIU:Reheat") {
    2374        1352 :             thisPIU.SecAirMassFlow = thisPIU.MinSecAirMassFlow;
    2375             :         }
    2376             :     } else {
    2377           2 :         if (pri) {
    2378           0 :             if (thisPIU.UnitType == "AirTerminal:SingleDuct:SeriesPIU:Reheat") {
    2379           0 :                 state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRate = thisPIU.MinPriAirMassFlow;
    2380           0 :                 state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate = max(0.0, thisPIU.MaxTotAirMassFlow - thisPIU.MinPriAirMassFlow);
    2381           0 :             } else if (thisPIU.UnitType == "AirTerminal:SingleDuct:ParallelPIU:Reheat") {
    2382           0 :                 state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRate = thisPIU.MinPriAirMassFlow;
    2383           0 :                 state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate = thisPIU.MaxSecAirMassFlow;
    2384             :             }
    2385             :         } else {
    2386           2 :             if (thisPIU.UnitType == "AirTerminal:SingleDuct:SeriesPIU:Reheat") {
    2387           1 :                 state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRate = 0.0;
    2388           1 :                 state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate = thisPIU.MaxTotAirMassFlow;
    2389           1 :             } else if (thisPIU.UnitType == "AirTerminal:SingleDuct:ParallelPIU:Reheat") {
    2390           1 :                 state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRate = 0.0;
    2391           1 :                 state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate = thisPIU.MaxSecAirMassFlow;
    2392             :             }
    2393             :         }
    2394           2 :         TotAirMassFlow = state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRate + state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate;
    2395             :         Real64 qdotDeliveredEnd2ndStage =
    2396           2 :             CalcVariableSpeedPIUQdotDelivered(state, piuNum, zoneNode, true, TotAirMassFlow, thisPIU.MinFanTurnDownRatio);
    2397           2 :         if (qdotDeliveredEnd2ndStage > zoneLoad) { // 2nd stage
    2398           0 :             thisPIU.heatingOperatingMode = HeatOpModeType::ModulatedHeatSecondStage;
    2399             :             // Find fan speed that meets zone heating load
    2400           0 :             int constexpr MaxIte(500);                                                                  // Maximum number of iterations
    2401           0 :             Real64 constexpr Acc(0.0001);                                                               // Accuracy of result
    2402           0 :             int SolFla(0);                                                                              // Flag of solver
    2403           0 :             Real64 fanSignal = (1.0 - thisPIU.MinFanTurnDownRatio) * 0.5 + thisPIU.MinFanTurnDownRatio; // starting value in middle
    2404           0 :             auto f = [&state, piuNum, zoneLoad, zoneNode, primaryAirMassFlow](Real64 const fanSignal) {
    2405           0 :                 return CalcVariableSpeedPIUHeatingResidual(state, fanSignal, piuNum, zoneLoad, zoneNode, primaryAirMassFlow, true, fanSignal);
    2406           0 :             };
    2407             : 
    2408           0 :             General::SolveRoot(state, Acc, MaxIte, SolFla, fanSignal, f, thisPIU.MinFanTurnDownRatio, 1.0);
    2409             : 
    2410           0 :             if (SolFla == -1) {
    2411           0 :                 ShowSevereError(state, "Iteration limit exceeded in calculating variable speed fan powered box 2nd stage heating fan speed");
    2412           0 :                 ShowContinueErrorTimeStamp(state, "");
    2413           0 :                 ShowFatalError(state, format("PIU control failed for {}:{}", thisPIU.UnitType, thisPIU.Name));
    2414           0 :             } else if (SolFla == -2) {
    2415           0 :                 ShowSevereError(state, "Bad starting values for in calculating variable speed fan powered box 2nd stage heating fan speed");
    2416           0 :                 ShowContinueErrorTimeStamp(state, "");
    2417           0 :                 ShowFatalError(state, format("PIU control failed for {}:{}", thisPIU.UnitType, thisPIU.Name));
    2418             :             } else {
    2419           0 :                 if (thisPIU.UnitType == "AirTerminal:SingleDuct:SeriesPIU:Reheat") {
    2420           0 :                     thisPIU.SecAirMassFlow = max(0.0, fanSignal * thisPIU.MaxTotAirMassFlow - primaryAirMassFlow);
    2421           0 :                 } else if (thisPIU.UnitType == "AirTerminal:SingleDuct:ParallelPIU:Reheat") {
    2422           0 :                     thisPIU.SecAirMassFlow = max(0.0, fanSignal * thisPIU.MaxSecAirMassFlow);
    2423             :                 }
    2424             :             }
    2425             :         } else { // 3rd stage, full fan speed
    2426           2 :             thisPIU.heatingOperatingMode = HeatOpModeType::ModulatedHeatThirdStage;
    2427           2 :             if (thisPIU.UnitType == "AirTerminal:SingleDuct:SeriesPIU:Reheat") {
    2428           1 :                 thisPIU.SecAirMassFlow = thisPIU.MaxTotAirMassFlow - thisPIU.MinPriAirMassFlow;
    2429           1 :             } else if (thisPIU.UnitType == "AirTerminal:SingleDuct:ParallelPIU:Reheat") {
    2430           1 :                 thisPIU.SecAirMassFlow = thisPIU.MaxSecAirMassFlow;
    2431             :             }
    2432             :         }
    2433             :     }
    2434        2874 : }
    2435             : 
    2436          67 : Real64 CalcVariableSpeedPIUHeatingResidual(EnergyPlusData &state,
    2437             :                                            Real64 const fanSignal,
    2438             :                                            int const piuNum,
    2439             :                                            Real64 const targetQznReq,
    2440             :                                            int const zoneNodeNum,
    2441             :                                            Real64 const primaryMassFlow,
    2442             :                                            bool useDAT,
    2443             :                                            Real64 const fanTurnDown)
    2444             : 
    2445             : {
    2446             :     // used to find a fan speed to meet load to heating setpoint with no heater power
    2447             :     // 1st stage heating for staged heat, also used for undershoot case where cooling at min primary flow would push below heating
    2448             :     // setpoint.
    2449          67 :     auto &thisPIU = state.dataPowerInductionUnits->PIU(piuNum);
    2450          67 :     state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRate = primaryMassFlow;
    2451          67 :     Real64 TotAirMassFlow = 0.0;
    2452          67 :     if (thisPIU.UnitType == "AirTerminal:SingleDuct:SeriesPIU:Reheat") {
    2453           0 :         TotAirMassFlow = fanSignal * thisPIU.MaxTotAirMassFlow;
    2454           0 :         state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate = max(0.0, TotAirMassFlow - primaryMassFlow);
    2455             :     } else {
    2456             :         // parallel
    2457          67 :         TotAirMassFlow = fanSignal * thisPIU.MaxSecAirMassFlow + primaryMassFlow;
    2458          67 :         state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate = fanSignal * thisPIU.MaxSecAirMassFlow;
    2459             :     }
    2460             : 
    2461             :     // calculate heating provided to zone
    2462          67 :     Real64 qdotDelivered = CalcVariableSpeedPIUQdotDelivered(state, piuNum, zoneNodeNum, useDAT, TotAirMassFlow, fanTurnDown);
    2463             :     // formulate residual and return
    2464          67 :     Real64 Residuum = (targetQznReq - qdotDelivered);
    2465          67 :     return Residuum;
    2466             : }
    2467             : 
    2468        7001 : Real64 CalcVariableSpeedPIUCoolingResidual(EnergyPlusData &state, Real64 const coolSignal, int piuNum, Real64 targetQznReq, int zoneNodeNum)
    2469             : {
    2470             :     // used for cooling control with VS fan.  Simultaneous control of fan speed and primary air damper
    2471             :     // given trial cooling signal, calculate the cooling provided and a residual that compares what is delivered vs what the zone
    2472             :     // needs. set the flows, controller acts on fan and damper simultaneously
    2473        7001 :     auto &thisPIU = state.dataPowerInductionUnits->PIU(piuNum);
    2474        7001 :     Real64 PriAirMassFlow = coolSignal * (thisPIU.MaxPriAirMassFlow - thisPIU.MinPriAirMassFlow) + thisPIU.MinPriAirMassFlow;
    2475        7001 :     Real64 TotAirMassFlow = coolSignal * (thisPIU.MaxTotAirMassFlow - thisPIU.MinTotAirMassFlow) + thisPIU.MinTotAirMassFlow;
    2476        7001 :     Real64 SecAirMassFlow = max(0.0, TotAirMassFlow - PriAirMassFlow);
    2477        7001 :     state.dataLoopNodes->Node(thisPIU.PriAirInNode).MassFlowRate = PriAirMassFlow;
    2478        7001 :     state.dataLoopNodes->Node(thisPIU.SecAirInNode).MassFlowRate = SecAirMassFlow;
    2479             : 
    2480        7001 :     Real64 fanTurnDown = coolSignal * (1.0 - thisPIU.MinFanTurnDownRatio) + thisPIU.MinFanTurnDownRatio;
    2481        7001 :     Real64 qdotDelivered = CalcVariableSpeedPIUQdotDelivered(state, piuNum, zoneNodeNum, false, TotAirMassFlow, fanTurnDown);
    2482             :     // formulate residual and return
    2483        7001 :     Real64 Residuum = (targetQznReq - qdotDelivered);
    2484        7001 :     return Residuum;
    2485             : }
    2486             : 
    2487      308748 : void ReportPIU(EnergyPlusData &state, int const PIUNum) // number of the current fan coil unit being simulated
    2488             : {
    2489             : 
    2490             :     // SUBROUTINE INFORMATION:
    2491             :     //       AUTHOR         Fred Buhl
    2492             :     //       DATE WRITTEN   August 2000
    2493             :     //       MODIFIED       na
    2494             :     //       RE-ENGINEERED  na
    2495             : 
    2496             :     // PURPOSE OF THIS SUBROUTINE:
    2497             :     // Fills some report variables for the PIU terminal boxes
    2498             : 
    2499             :     // Using/Aliasing
    2500      308748 :     Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
    2501             : 
    2502      308748 :     auto &thisPIU = state.dataPowerInductionUnits->PIU(PIUNum);
    2503      308748 :     thisPIU.HeatingEnergy = thisPIU.HeatingRate * TimeStepSysSec;
    2504      308748 :     thisPIU.SensCoolEnergy = thisPIU.SensCoolRate * TimeStepSysSec;
    2505             : 
    2506             :     // set zone OA Volume flow rate
    2507      308748 :     thisPIU.CalcOutdoorAirVolumeFlowRate(state);
    2508      308748 : }
    2509             : 
    2510             : // ===================== Utilities =====================================
    2511             : 
    2512          63 : bool PIUnitHasMixer(EnergyPlusData &state, std::string_view CompName) // component (mixer) name
    2513             : {
    2514             : 
    2515             :     // FUNCTION INFORMATION:
    2516             :     //       AUTHOR         Linda Lawrie
    2517             :     //       DATE WRITTEN   September 2011
    2518             :     //       MODIFIED       na
    2519             :     //       RE-ENGINEERED  na
    2520             : 
    2521             :     // PURPOSE OF THIS FUNCTION:
    2522             :     // Given a mixer name, this routine determines if that mixer is found on
    2523             :     // PIUnits.
    2524             : 
    2525             :     // Return value
    2526          63 :     bool YesNo = false; // True if found
    2527             : 
    2528          63 :     if (state.dataPowerInductionUnits->GetPIUInputFlag) {
    2529           2 :         GetPIUs(state);
    2530           2 :         state.dataPowerInductionUnits->GetPIUInputFlag = false;
    2531             :     }
    2532             : 
    2533          63 :     if (state.dataPowerInductionUnits->NumPIUs > 0) {
    2534          57 :         int const ItemNum = Util::FindItemInList(CompName, state.dataPowerInductionUnits->PIU, &PowIndUnitData::MixerName);
    2535          57 :         if (ItemNum > 0) {
    2536          57 :             YesNo = true;
    2537             :         }
    2538             :     }
    2539             : 
    2540          63 :     return YesNo;
    2541             : }
    2542             : 
    2543          26 : void PIUInducesPlenumAir(EnergyPlusData &state, int const NodeNum, int const plenumNum) // induced air node number
    2544             : {
    2545             : 
    2546             :     // SUBROUTINE INFORMATION:
    2547             :     //       AUTHOR         Fred Buhl
    2548             :     //       DATE WRITTEN   January 2012
    2549             :     //       MODIFIED       na
    2550             :     //       RE-ENGINEERED  na
    2551             : 
    2552             :     // PURPOSE OF THIS FUNCTION:
    2553             :     // Marks a PIU air terminal unit as obtaining its induced air from
    2554             :     // a plenum.
    2555             : 
    2556          26 :     if (state.dataPowerInductionUnits->GetPIUInputFlag) {
    2557           2 :         GetPIUs(state);
    2558           2 :         state.dataPowerInductionUnits->GetPIUInputFlag = false;
    2559             :     }
    2560             : 
    2561         137 :     for (int PIUIndex = 1; PIUIndex <= state.dataPowerInductionUnits->NumPIUs; ++PIUIndex) {
    2562         130 :         if (NodeNum == state.dataPowerInductionUnits->PIU(PIUIndex).SecAirInNode) {
    2563          19 :             state.dataPowerInductionUnits->PIU(PIUIndex).InducesPlenumAir = true;
    2564          19 :             state.dataPowerInductionUnits->PIU(PIUIndex).plenumIndex = plenumNum;
    2565          19 :             break;
    2566             :         }
    2567             :     }
    2568          26 : }
    2569             : 
    2570      308748 : void PowIndUnitData::CalcOutdoorAirVolumeFlowRate(EnergyPlusData &state)
    2571             : {
    2572             :     // calculates zone outdoor air volume flow rate using the supply air flow rate and OA fraction
    2573      308748 :     if (this->AirLoopNum > 0) {
    2574      308691 :         this->OutdoorAirFlowRate = (state.dataLoopNodes->Node(this->PriAirInNode).MassFlowRate / state.dataEnvrn->StdRhoAir) *
    2575      308691 :                                    state.dataAirLoop->AirLoopFlow(this->AirLoopNum).OAFrac;
    2576             :     } else {
    2577          57 :         this->OutdoorAirFlowRate = 0.0;
    2578             :     }
    2579      308748 : }
    2580             : 
    2581          57 : void PowIndUnitData::reportTerminalUnit(EnergyPlusData &state)
    2582             : {
    2583             :     // populate the predefined equipment summary report related to air terminals
    2584          57 :     auto &orp = state.dataOutRptPredefined;
    2585          57 :     auto &adu = state.dataDefineEquipment->AirDistUnit(this->ADUNum);
    2586          57 :     if (!state.dataSize->TermUnitFinalZoneSizing.empty()) {
    2587          57 :         auto &sizing = state.dataSize->TermUnitFinalZoneSizing(adu.TermUnitSizingNum);
    2588          57 :         OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermMinFlow, adu.Name, sizing.DesCoolVolFlowMin);
    2589          57 :         OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermMinOutdoorFlow, adu.Name, sizing.MinOA);
    2590          57 :         OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermSupCoolingSP, adu.Name, sizing.CoolDesTemp);
    2591          57 :         OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermSupHeatingSP, adu.Name, sizing.HeatDesTemp);
    2592          57 :         OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermHeatingCap, adu.Name, sizing.DesHeatLoad);
    2593          57 :         OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermCoolingCap, adu.Name, sizing.DesCoolLoad);
    2594             :     }
    2595          57 :     OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermTypeInp, adu.Name, this->UnitType);
    2596          57 :     OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermPrimFlow, adu.Name, this->MaxPriAirVolFlow);
    2597          57 :     OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermSecdFlow, adu.Name, this->MaxSecAirVolFlow);
    2598          57 :     OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermMinFlowSch, adu.Name, "n/a");
    2599          57 :     OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermMaxFlowReh, adu.Name, "n/a");
    2600          57 :     OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermMinOAflowSch, adu.Name, "n/a");
    2601          57 :     OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermHeatCoilType, adu.Name, HCoilNamesUC[(int)this->HCoilType]);
    2602          57 :     OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermCoolCoilType, adu.Name, "n/a");
    2603          57 :     OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermFanType, adu.Name, HVAC::fanTypeNames[(int)this->fanType]);
    2604          57 :     OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermFanName, adu.Name, this->FanName);
    2605          57 : }
    2606             : 
    2607             : } // namespace EnergyPlus::PoweredInductionUnits

Generated by: LCOV version 1.14