LCOV - code coverage report
Current view: top level - EnergyPlus - TranspiredCollector.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 37.9 % 911 345
Test Date: 2025-06-02 12:03:30 Functions: 30.8 % 13 4

            Line data    Source code
       1              : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
       2              : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3              : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4              : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5              : // contributors. All rights reserved.
       6              : //
       7              : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8              : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9              : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10              : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11              : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12              : //
      13              : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14              : // provided that the following conditions are met:
      15              : //
      16              : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17              : //     conditions and the following disclaimer.
      18              : //
      19              : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20              : //     conditions and the following disclaimer in the documentation and/or other materials
      21              : //     provided with the distribution.
      22              : //
      23              : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24              : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25              : //     used to endorse or promote products derived from this software without specific prior
      26              : //     written permission.
      27              : //
      28              : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29              : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30              : //     reference solely to the software portion of its product, Licensee must refer to the
      31              : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32              : //     obtained under this License and may not use a different name for the software. Except as
      33              : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34              : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35              : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36              : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37              : //
      38              : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39              : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40              : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41              : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42              : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43              : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44              : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45              : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46              : // POSSIBILITY OF SUCH DAMAGE.
      47              : 
      48              : // C++ Headers
      49              : #include <cassert>
      50              : #include <cmath>
      51              : 
      52              : // ObjexxFCL Headers
      53              : #include <ObjexxFCL/Array.functions.hh>
      54              : #include <ObjexxFCL/member.functions.hh>
      55              : 
      56              : // EnergyPlus Headers
      57              : #include <EnergyPlus/BranchNodeConnections.hh>
      58              : #include <EnergyPlus/Construction.hh>
      59              : #include <EnergyPlus/ConvectionCoefficients.hh>
      60              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      61              : #include <EnergyPlus/DataEnvironment.hh>
      62              : #include <EnergyPlus/DataHVACGlobals.hh>
      63              : #include <EnergyPlus/DataHeatBalSurface.hh>
      64              : #include <EnergyPlus/DataHeatBalance.hh>
      65              : #include <EnergyPlus/DataIPShortCuts.hh>
      66              : #include <EnergyPlus/DataLoopNode.hh>
      67              : #include <EnergyPlus/DataSurfaces.hh>
      68              : #include <EnergyPlus/EMSManager.hh>
      69              : #include <EnergyPlus/General.hh>
      70              : #include <EnergyPlus/GeneralRoutines.hh>
      71              : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      72              : #include <EnergyPlus/Material.hh>
      73              : #include <EnergyPlus/NodeInputManager.hh>
      74              : #include <EnergyPlus/OutputProcessor.hh>
      75              : #include <EnergyPlus/Psychrometrics.hh>
      76              : #include <EnergyPlus/ScheduleManager.hh>
      77              : #include <EnergyPlus/SolarCollectors.hh>
      78              : #include <EnergyPlus/TranspiredCollector.hh>
      79              : #include <EnergyPlus/UtilityRoutines.hh>
      80              : 
      81              : namespace EnergyPlus {
      82              : 
      83              : namespace TranspiredCollector {
      84              : 
      85              :     // Module containing routines and data dealing with the Transpired Collectors
      86              : 
      87              :     // MODULE INFORMATION:
      88              :     //       AUTHOR         B.T. Griffith
      89              :     //       DATE WRITTEN   November 2004
      90              :     //       MODIFIED       na
      91              :     //       RE-ENGINEERED  na
      92              : 
      93              :     // PURPOSE OF THIS MODULE:
      94              :     // Encapsulates data and routines for simulating unglazed transpired solar collectors (UTSC)
      95              :     //   as a component on the HVAC air system.
      96              : 
      97              :     // METHODOLOGY EMPLOYED:
      98              :     // Two modes, passive and active.  Active is when air is purposely drawn through collector.
      99              :     // Passive is when air exchanges are driven by Natural Ventilation rather than outside air system
     100              : 
     101              :     // REFERENCES:
     102              :     // Heat Exchange effectiveness relations:
     103              :     // Kutscher, C.F. 1994. Heat exchange effectiveness and pressure drop for air flow through perforated plates
     104              :     //     with and without crosswind. Journal of Heat Transfer. May 1994, Vol. 116, p. 391.
     105              :     //     American Society of Mechanical Engineers.
     106              :     // Van Decker, G.W.E., K.G.T. Hollands, and A.P. Brunger. 2001. Heat-exchange relations for unglazed transpired
     107              :     //     solar collectors with circular holes on a square of triangular pitch. Solar Energy. Vol. 71, No. 1. pp 33-45, 2001.
     108              :     // .
     109              : 
     110              :     // OTHER NOTES:
     111              :     // EnergyPlus implementation is unique and adds new modeling not described in Literature.
     112              :     //   See EngineeringReference for details
     113              : 
     114              :     // Using/Aliasing
     115              :     using DataVectorTypes::Vector;
     116              : 
     117              :     int constexpr Layout_Square = 1;
     118              :     int constexpr Layout_Triangle = 2;
     119              :     int constexpr Correlation_Kutscher1994 = 1;
     120              :     int constexpr Correlation_VanDeckerHollandsBrunger2001 = 2;
     121              : 
     122            0 :     void SimTranspiredCollector(EnergyPlusData &state,
     123              :                                 std::string_view CompName, // component name
     124              :                                 int &CompIndex             // component index (to reduce string compares during simulation)
     125              :     )
     126              :     {
     127              : 
     128              :         // SUBROUTINE INFORMATION:
     129              :         //       AUTHOR         B.T. Griffith
     130              :         //       DATE WRITTEN   November 2004
     131              :         //       MODIFIED       na
     132              :         //       RE-ENGINEERED  na
     133              : 
     134              :         // PURPOSE OF THIS SUBROUTINE:
     135              :         // Manage simulation of Transpired Collectors
     136              : 
     137              :         // METHODOLOGY EMPLOYED:
     138              :         // Setup to avoid string comparisons after first call
     139              : 
     140              :         // Using/Aliasing
     141              :         using HVAC::TempControlTol;
     142              : 
     143              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     144              : 
     145            0 :         int UTSCNum(0); // local number index for UTSC
     146              : 
     147            0 :         if (state.dataTranspiredCollector->GetInputFlag) {
     148            0 :             GetTranspiredCollectorInput(state);
     149            0 :             state.dataTranspiredCollector->GetInputFlag = false;
     150              :         }
     151              : 
     152              :         // Find the correct transpired collector with the Component name and/or index
     153            0 :         if (CompIndex == 0) {
     154            0 :             UTSCNum = Util::FindItemInList(CompName, state.dataTranspiredCollector->UTSC);
     155            0 :             if (UTSCNum == 0) {
     156            0 :                 ShowFatalError(state, format("Transpired Collector not found={}", CompName));
     157              :             }
     158            0 :             CompIndex = UTSCNum;
     159              :         } else {
     160            0 :             UTSCNum = CompIndex;
     161            0 :             if (UTSCNum > state.dataTranspiredCollector->NumUTSC || UTSCNum < 1) {
     162            0 :                 ShowFatalError(state,
     163            0 :                                format("SimTranspiredCollector: Invalid CompIndex passed={}, Number of Transpired Collectors={}, UTSC name={}",
     164              :                                       UTSCNum,
     165            0 :                                       state.dataTranspiredCollector->NumUTSC,
     166              :                                       CompName));
     167              :             }
     168            0 :             if (state.dataTranspiredCollector->CheckEquipName(UTSCNum)) {
     169            0 :                 if (CompName != state.dataTranspiredCollector->UTSC(UTSCNum).Name) {
     170            0 :                     ShowFatalError(state,
     171            0 :                                    format("SimTranspiredCollector: Invalid CompIndex passed={}, Transpired Collector name={}, stored Transpired "
     172              :                                           "Collector Name for that index={}",
     173              :                                           UTSCNum,
     174              :                                           CompName,
     175            0 :                                           state.dataTranspiredCollector->UTSC(UTSCNum).Name));
     176              :                 }
     177            0 :                 state.dataTranspiredCollector->CheckEquipName(UTSCNum) = false;
     178              :             }
     179              :         }
     180              : 
     181            0 :         InitTranspiredCollector(state, CompIndex);
     182              : 
     183              :         // Control point of deciding if transpired collector is active or not.
     184            0 :         auto &UTSC_CI = state.dataTranspiredCollector->UTSC(CompIndex);
     185            0 :         auto &InletNode = UTSC_CI.InletNode;
     186            0 :         auto &ControlNode = UTSC_CI.ControlNode;
     187            0 :         UTSC_CI.IsOn = false;
     188            0 :         if ((UTSC_CI.availSched->getCurrentVal() > 0.0) && (UTSC_CI.InletMDot > 0.0)) { // availability Schedule | OA system is setting mass flow
     189            0 :             bool ControlLTSet(false);
     190            0 :             bool ControlLTSchedule(false);
     191            0 :             bool ZoneLTSchedule(false);
     192            0 :             assert(equal_dimensions(InletNode, ControlNode));
     193            0 :             assert(equal_dimensions(InletNode, UTSC_CI.ZoneNode));
     194            0 :             for (int i = InletNode.l(), e = InletNode.u(); i <= e; ++i) {
     195            0 :                 if (state.dataLoopNodes->Node(InletNode(i)).Temp + TempControlTol < state.dataLoopNodes->Node(ControlNode(i)).TempSetPoint) {
     196            0 :                     ControlLTSet = true;
     197              :                 }
     198            0 :                 if (state.dataLoopNodes->Node(InletNode(i)).Temp + TempControlTol < UTSC_CI.freeHeatSetPointSched->getCurrentVal()) {
     199            0 :                     ControlLTSchedule = true;
     200              :                 }
     201            0 :                 if (state.dataLoopNodes->Node(UTSC_CI.ZoneNode(i)).Temp + TempControlTol < UTSC_CI.freeHeatSetPointSched->getCurrentVal()) {
     202            0 :                     ZoneLTSchedule = true;
     203              :                 }
     204              :             }
     205            0 :             if (ControlLTSet || (ControlLTSchedule && ZoneLTSchedule)) {
     206            0 :                 UTSC_CI.IsOn = true; // heating required | free heating helpful | free heating helpful
     207              :             }
     208              :         }
     209              : 
     210            0 :         if (state.dataTranspiredCollector->UTSC(UTSCNum).IsOn) {
     211            0 :             CalcActiveTranspiredCollector(state, UTSCNum);
     212              :         } else {
     213            0 :             CalcPassiveTranspiredCollector(state, UTSCNum);
     214              :         }
     215              : 
     216            0 :         UpdateTranspiredCollector(state, UTSCNum);
     217            0 :     }
     218              : 
     219            1 :     void GetTranspiredCollectorInput(EnergyPlusData &state)
     220              :     {
     221              : 
     222              :         // SUBROUTINE INFORMATION:
     223              :         //       AUTHOR         B.T. Griffith
     224              :         //       DATE WRITTEN   November 2004
     225              :         //       MODIFIED       na
     226              :         //       RE-ENGINEERED  na
     227              : 
     228              :         // PURPOSE OF THIS SUBROUTINE:
     229              :         //  Retrieve user input and set up data structure
     230              : 
     231              :         // METHODOLOGY EMPLOYED:
     232              :         // usual EnergyPlus input
     233              :         // Extensible UTSC object for underlying heat transfer surfaces and for multisystem
     234              : 
     235              :         static constexpr std::string_view routineName = "GetTranspiredCollectorInput";
     236              : 
     237              :         // Using/Aliasing
     238              :         using BranchNodeConnections::TestCompSet;
     239              :         using DataLoopNode::ObjectIsNotParent;
     240              :         using DataSurfaces::OtherSideCondModeledExt;
     241              :         using DataSurfaces::SurfaceData;
     242              :         using NodeInputManager::GetOnlySingleNode;
     243              : 
     244              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     245              : 
     246            1 :         Array1D_string Alphas; // Alpha items for extensible
     247              :         // Solar Collectors:Unglazed Transpired object
     248              :         int Item;                    // Item to be "gotten"
     249            1 :         Array1D<Real64> Numbers(11); // Numeric items for object
     250              :         int NumAlphas;               // Number of Alphas for each GetObjectItem call
     251              :         int NumNumbers;              // Number of Numbers for each GetObjectItem call
     252              :         int MaxNumAlphas;            // argument for call to GetObjectDefMaxArgs
     253              :         int MaxNumNumbers;           // argument for call to GetObjectDefMaxArgs
     254              :         int Dummy;                   // argument for call to GetObjectDefMaxArgs
     255              :         int IOStatus;                // Used in GetObjectItem
     256            1 :         bool ErrorsFound(false);     // Set to true if errors in input, fatal at end of routine
     257              :         int Found;
     258              :         int AlphaOffset; // local temp var
     259            1 :         std::string Roughness;
     260              :         int ThisSurf;         // do loop counter
     261              :         Real64 AvgAzimuth;    // temp for error checking
     262              :         Real64 AvgTilt;       // temp for error checking
     263              :         int SurfID;           // local surface "pointer"
     264              :         Real64 TiltRads;      // average tilt of collector in radians
     265              :         Real64 tempHdeltaNPL; // temporary variable for buoyancy length scale
     266            1 :         int NumUTSCSplitter(0);
     267            1 :         Array1D_string AlphasSplit; // Alpha items for extensible
     268              :         // Solar Collectors:Unglazed Transpired object
     269              :         int ItemSplit;                        // Item to be "gotten"
     270            1 :         Array1D<Real64> NumbersSplit(1);      // Numeric items for object
     271              :         int NumAlphasSplit;                   // Number of Alphas for each GetObjectItem call
     272              :         int NumNumbersSplit;                  // Number of Numbers for each GetObjectItem call
     273              :         int MaxNumAlphasSplit;                // argument for call to GetObjectDefMaxArgs
     274              :         int MaxNumNumbersSplit;               // argument for call to GetObjectDefMaxArgs
     275              :         int IOStatusSplit;                    // Used in GetObjectItem
     276              :         int NumOASys;                         // do loop counter
     277              :         int ACountBase;                       // counter for alhpasSplit
     278            1 :         Array1D_bool SplitterNameOK;          // check for correct association of
     279            1 :         std::string CurrentModuleObject;      // for ease in renaming.
     280            1 :         std::string CurrentModuleMultiObject; // for ease in renaming.
     281              : 
     282            1 :         CurrentModuleObject = "SolarCollector:UnglazedTranspired";
     283            1 :         state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, Dummy, MaxNumAlphas, MaxNumNumbers);
     284              : 
     285            1 :         if (MaxNumNumbers != 11) {
     286            0 :             ShowSevereError(state,
     287            0 :                             format("GetTranspiredCollectorInput: {} Object Definition indicates not = 11 Number Objects, Number Indicated={}",
     288              :                                    CurrentModuleObject,
     289              :                                    MaxNumNumbers));
     290            0 :             ErrorsFound = true;
     291              :         }
     292            1 :         Alphas.allocate(MaxNumAlphas);
     293            1 :         Numbers = 0.0;
     294            1 :         Alphas = "";
     295              : 
     296            1 :         state.dataTranspiredCollector->NumUTSC = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
     297            1 :         CurrentModuleMultiObject = "SolarCollector:UnglazedTranspired:Multisystem";
     298            1 :         NumUTSCSplitter = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleMultiObject);
     299              : 
     300            1 :         state.dataTranspiredCollector->UTSC.allocate(state.dataTranspiredCollector->NumUTSC);
     301            1 :         state.dataTranspiredCollector->CheckEquipName.dimension(state.dataTranspiredCollector->NumUTSC, true);
     302            1 :         SplitterNameOK.dimension(NumUTSCSplitter, false);
     303              : 
     304            2 :         for (Item = 1; Item <= state.dataTranspiredCollector->NumUTSC; ++Item) {
     305            2 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     306              :                                                                      CurrentModuleObject,
     307              :                                                                      Item,
     308              :                                                                      Alphas,
     309              :                                                                      NumAlphas,
     310              :                                                                      Numbers,
     311              :                                                                      NumNumbers,
     312              :                                                                      IOStatus,
     313            1 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
     314            1 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
     315            1 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
     316            1 :                                                                      state.dataIPShortCut->cNumericFieldNames);
     317              : 
     318            1 :             ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
     319              : 
     320              :             // first handle alphas
     321            1 :             state.dataTranspiredCollector->UTSC(Item).Name = Alphas(1);
     322              : 
     323              :             // now check for multisystem
     324            1 :             if (NumUTSCSplitter > 0) {
     325            0 :                 state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
     326              :                     state, CurrentModuleMultiObject, Dummy, MaxNumAlphasSplit, MaxNumNumbersSplit);
     327              : 
     328            0 :                 if (MaxNumNumbersSplit != 0) {
     329            0 :                     ShowSevereError(state,
     330            0 :                                     format("GetTranspiredCollectorInput: {} Object Definition indicates not = 0 Number Objects, Number Indicated={}",
     331              :                                            CurrentModuleMultiObject,
     332              :                                            MaxNumNumbersSplit));
     333            0 :                     ErrorsFound = true;
     334              :                 }
     335            0 :                 if (!allocated(AlphasSplit)) {
     336            0 :                     AlphasSplit.allocate(MaxNumAlphasSplit);
     337              :                 }
     338            0 :                 NumbersSplit = 0.0;
     339            0 :                 AlphasSplit = "";
     340            0 :                 for (ItemSplit = 1; ItemSplit <= NumUTSCSplitter; ++ItemSplit) {
     341            0 :                     state.dataInputProcessing->inputProcessor->getObjectItem(
     342              :                         state, CurrentModuleMultiObject, ItemSplit, AlphasSplit, NumAlphasSplit, NumbersSplit, NumNumbersSplit, IOStatusSplit);
     343            0 :                     if (!(Util::SameString(AlphasSplit(1), Alphas(1)))) {
     344            0 :                         continue;
     345              :                     }
     346            0 :                     SplitterNameOK(ItemSplit) = true;
     347            0 :                     state.dataTranspiredCollector->UTSC(Item).NumOASysAttached = std::floor(NumAlphasSplit / 4.0);
     348            0 :                     if (mod((NumAlphasSplit), 4) != 1) {
     349            0 :                         ShowSevereError(state,
     350            0 :                                         format("GetTranspiredCollectorInput: {} Object Definition indicates not uniform quadtuples of nodes for {}",
     351              :                                                CurrentModuleMultiObject,
     352              :                                                AlphasSplit(1)));
     353            0 :                         ErrorsFound = true;
     354              :                     }
     355            0 :                     state.dataTranspiredCollector->UTSC(Item).InletNode.allocate(state.dataTranspiredCollector->UTSC(Item).NumOASysAttached);
     356            0 :                     state.dataTranspiredCollector->UTSC(Item).InletNode = 0;
     357            0 :                     state.dataTranspiredCollector->UTSC(Item).OutletNode.allocate(state.dataTranspiredCollector->UTSC(Item).NumOASysAttached);
     358            0 :                     state.dataTranspiredCollector->UTSC(Item).OutletNode = 0;
     359            0 :                     state.dataTranspiredCollector->UTSC(Item).ControlNode.allocate(state.dataTranspiredCollector->UTSC(Item).NumOASysAttached);
     360            0 :                     state.dataTranspiredCollector->UTSC(Item).ControlNode = 0;
     361            0 :                     state.dataTranspiredCollector->UTSC(Item).ZoneNode.allocate(state.dataTranspiredCollector->UTSC(Item).NumOASysAttached);
     362            0 :                     state.dataTranspiredCollector->UTSC(Item).ZoneNode = 0;
     363            0 :                     for (NumOASys = 1; NumOASys <= state.dataTranspiredCollector->UTSC(Item).NumOASysAttached; ++NumOASys) {
     364            0 :                         ACountBase = (NumOASys - 1) * 4 + 2;
     365            0 :                         state.dataTranspiredCollector->UTSC(Item).InletNode(NumOASys) =
     366            0 :                             GetOnlySingleNode(state,
     367            0 :                                               AlphasSplit(ACountBase),
     368              :                                               ErrorsFound,
     369              :                                               DataLoopNode::ConnectionObjectType::SolarCollectorUnglazedTranspired,
     370            0 :                                               AlphasSplit(1),
     371              :                                               DataLoopNode::NodeFluidType::Air,
     372              :                                               DataLoopNode::ConnectionType::Inlet,
     373              :                                               static_cast<NodeInputManager::CompFluidStream>(NumOASys),
     374              :                                               ObjectIsNotParent);
     375              : 
     376            0 :                         state.dataTranspiredCollector->UTSC(Item).OutletNode(NumOASys) =
     377            0 :                             GetOnlySingleNode(state,
     378            0 :                                               AlphasSplit(ACountBase + 1),
     379              :                                               ErrorsFound,
     380              :                                               DataLoopNode::ConnectionObjectType::SolarCollectorUnglazedTranspired,
     381            0 :                                               AlphasSplit(1),
     382              :                                               DataLoopNode::NodeFluidType::Air,
     383              :                                               DataLoopNode::ConnectionType::Outlet,
     384              :                                               static_cast<NodeInputManager::CompFluidStream>(NumOASys),
     385              :                                               ObjectIsNotParent);
     386            0 :                         TestCompSet(state,
     387              :                                     CurrentModuleObject,
     388            0 :                                     AlphasSplit(1),
     389            0 :                                     AlphasSplit(ACountBase),
     390            0 :                                     AlphasSplit(ACountBase + 1),
     391              :                                     "Transpired Collector Air Nodes"); // appears that test fails by design??
     392            0 :                         state.dataTranspiredCollector->UTSC(Item).ControlNode(NumOASys) =
     393            0 :                             GetOnlySingleNode(state,
     394            0 :                                               AlphasSplit(ACountBase + 2),
     395              :                                               ErrorsFound,
     396              :                                               DataLoopNode::ConnectionObjectType::SolarCollectorUnglazedTranspired,
     397            0 :                                               AlphasSplit(1),
     398              :                                               DataLoopNode::NodeFluidType::Air,
     399              :                                               DataLoopNode::ConnectionType::Sensor,
     400              :                                               NodeInputManager::CompFluidStream::Primary,
     401              :                                               ObjectIsNotParent);
     402              : 
     403            0 :                         state.dataTranspiredCollector->UTSC(Item).ZoneNode(NumOASys) =
     404            0 :                             GetOnlySingleNode(state,
     405            0 :                                               AlphasSplit(ACountBase + 3),
     406              :                                               ErrorsFound,
     407              :                                               DataLoopNode::ConnectionObjectType::SolarCollectorUnglazedTranspired,
     408            0 :                                               AlphasSplit(1),
     409              :                                               DataLoopNode::NodeFluidType::Air,
     410              :                                               DataLoopNode::ConnectionType::Sensor,
     411              :                                               NodeInputManager::CompFluidStream::Primary,
     412              :                                               ObjectIsNotParent);
     413              : 
     414              :                     } // Each OA System in a Multisystem
     415              :                       // DEALLOCATE(AlphasSplit)
     416              :                 } // each Multisystem present
     417              :             } // any UTSC Multisystem present
     418              : 
     419            1 :             state.dataTranspiredCollector->UTSC(Item).OSCMName = Alphas(2);
     420            1 :             Found = Util::FindItemInList(state.dataTranspiredCollector->UTSC(Item).OSCMName, state.dataSurface->OSCM);
     421            1 :             if (Found == 0) {
     422            0 :                 ShowSevereError(state,
     423            0 :                                 format("{} not found={} in {} ={}",
     424            0 :                                        state.dataIPShortCut->cAlphaFieldNames(2),
     425            0 :                                        state.dataTranspiredCollector->UTSC(Item).OSCMName,
     426              :                                        CurrentModuleObject,
     427            0 :                                        state.dataTranspiredCollector->UTSC(Item).Name));
     428            0 :                 ErrorsFound = true;
     429              :             }
     430            1 :             state.dataTranspiredCollector->UTSC(Item).OSCMPtr = Found;
     431            1 :             if (state.dataIPShortCut->lAlphaFieldBlanks(3)) {
     432            0 :                 state.dataTranspiredCollector->UTSC(Item).availSched = Sched::GetScheduleAlwaysOn(state);
     433            1 :             } else if ((state.dataTranspiredCollector->UTSC(Item).availSched = Sched::GetSchedule(state, Alphas(3))) == nullptr) {
     434            0 :                 ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3), Alphas(3));
     435            0 :                 ErrorsFound = true;
     436            0 :                 continue;
     437              :             }
     438              : 
     439              :             // now if UTSC(Item)%NumOASysAttached still not set, assume no multisystem
     440            1 :             if (state.dataTranspiredCollector->UTSC(Item).NumOASysAttached == 0) {
     441            1 :                 state.dataTranspiredCollector->UTSC(Item).NumOASysAttached = 1;
     442            1 :                 state.dataTranspiredCollector->UTSC(Item).InletNode.allocate(1);
     443            1 :                 state.dataTranspiredCollector->UTSC(Item).InletNode(1) = 0;
     444            1 :                 state.dataTranspiredCollector->UTSC(Item).OutletNode.allocate(1);
     445            1 :                 state.dataTranspiredCollector->UTSC(Item).OutletNode(1) = 0;
     446            1 :                 state.dataTranspiredCollector->UTSC(Item).ControlNode.allocate(1);
     447            1 :                 state.dataTranspiredCollector->UTSC(Item).ControlNode(1) = 0;
     448            1 :                 state.dataTranspiredCollector->UTSC(Item).ZoneNode.allocate(1);
     449            1 :                 state.dataTranspiredCollector->UTSC(Item).ZoneNode(1) = 0;
     450              : 
     451            1 :                 state.dataTranspiredCollector->UTSC(Item).InletNode(1) =
     452            2 :                     GetOnlySingleNode(state,
     453            1 :                                       Alphas(4),
     454              :                                       ErrorsFound,
     455              :                                       DataLoopNode::ConnectionObjectType::SolarCollectorUnglazedTranspired,
     456            1 :                                       Alphas(1),
     457              :                                       DataLoopNode::NodeFluidType::Air,
     458              :                                       DataLoopNode::ConnectionType::Inlet,
     459              :                                       NodeInputManager::CompFluidStream::Primary,
     460              :                                       ObjectIsNotParent);
     461            1 :                 state.dataTranspiredCollector->UTSC(Item).OutletNode(1) =
     462            3 :                     GetOnlySingleNode(state,
     463            1 :                                       Alphas(5),
     464              :                                       ErrorsFound,
     465              :                                       DataLoopNode::ConnectionObjectType::SolarCollectorUnglazedTranspired,
     466            1 :                                       Alphas(1),
     467              :                                       DataLoopNode::NodeFluidType::Air,
     468              :                                       DataLoopNode::ConnectionType::Outlet,
     469              :                                       NodeInputManager::CompFluidStream::Primary,
     470              :                                       ObjectIsNotParent);
     471            1 :                 TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(4), Alphas(5), "Transpired Collector Air Nodes");
     472              : 
     473            1 :                 state.dataTranspiredCollector->UTSC(Item).ControlNode(1) =
     474            2 :                     GetOnlySingleNode(state,
     475            1 :                                       Alphas(6),
     476              :                                       ErrorsFound,
     477              :                                       DataLoopNode::ConnectionObjectType::SolarCollectorUnglazedTranspired,
     478            1 :                                       Alphas(1),
     479              :                                       DataLoopNode::NodeFluidType::Air,
     480              :                                       DataLoopNode::ConnectionType::Sensor,
     481              :                                       NodeInputManager::CompFluidStream::Primary,
     482              :                                       ObjectIsNotParent);
     483            1 :                 state.dataTranspiredCollector->UTSC(Item).ZoneNode(1) =
     484            3 :                     GetOnlySingleNode(state,
     485            1 :                                       Alphas(7),
     486              :                                       ErrorsFound,
     487              :                                       DataLoopNode::ConnectionObjectType::SolarCollectorUnglazedTranspired,
     488            1 :                                       Alphas(1),
     489              :                                       DataLoopNode::NodeFluidType::Air,
     490              :                                       DataLoopNode::ConnectionType::Sensor,
     491              :                                       NodeInputManager::CompFluidStream::Primary,
     492              :                                       ObjectIsNotParent);
     493              :             } // no splitter
     494              : 
     495            1 :             if (state.dataIPShortCut->lAlphaFieldBlanks(8)) {
     496            0 :                 ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(8));
     497            0 :                 ErrorsFound = true;
     498            1 :             } else if ((state.dataTranspiredCollector->UTSC(Item).freeHeatSetPointSched = Sched::GetSchedule(state, Alphas(8))) == nullptr) {
     499            0 :                 ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(8), Alphas(8));
     500            0 :                 ErrorsFound = true;
     501            0 :                 continue;
     502              :             }
     503              : 
     504            1 :             if (Util::SameString(Alphas(9), "Triangle")) {
     505            1 :                 state.dataTranspiredCollector->UTSC(Item).Layout = Layout_Triangle;
     506            0 :             } else if (Util::SameString(Alphas(9), "Square")) {
     507            0 :                 state.dataTranspiredCollector->UTSC(Item).Layout = Layout_Square;
     508              :             } else {
     509            0 :                 ShowSevereError(state,
     510            0 :                                 format("{} has incorrect entry of {} in {} ={}",
     511            0 :                                        state.dataIPShortCut->cAlphaFieldNames(9),
     512              :                                        Alphas(9),
     513              :                                        CurrentModuleObject,
     514            0 :                                        state.dataTranspiredCollector->UTSC(Item).Name));
     515            0 :                 ErrorsFound = true;
     516            0 :                 continue;
     517              :             }
     518              : 
     519            1 :             if (Util::SameString(Alphas(10), "Kutscher1994")) {
     520            1 :                 state.dataTranspiredCollector->UTSC(Item).Correlation = Correlation_Kutscher1994;
     521            0 :             } else if (Util::SameString(Alphas(10), "VanDeckerHollandsBrunger2001")) {
     522            0 :                 state.dataTranspiredCollector->UTSC(Item).Correlation = Correlation_VanDeckerHollandsBrunger2001;
     523              :             } else {
     524            0 :                 ShowSevereError(state,
     525            0 :                                 format("{} has incorrect entry of {} in {} ={}",
     526            0 :                                        state.dataIPShortCut->cAlphaFieldNames(10),
     527              :                                        Alphas(9),
     528              :                                        CurrentModuleObject,
     529            0 :                                        state.dataTranspiredCollector->UTSC(Item).Name));
     530            0 :                 ErrorsFound = true;
     531            0 :                 continue;
     532              :             }
     533              : 
     534            1 :             Roughness = Alphas(11);
     535              :             // Select the correct Number for the associated ascii name for the roughness type
     536            1 :             if (Util::SameString(Roughness, "VeryRough")) {
     537            0 :                 state.dataTranspiredCollector->UTSC(Item).CollRoughness = Material::SurfaceRoughness::VeryRough;
     538              :             }
     539            1 :             if (Util::SameString(Roughness, "Rough")) {
     540            0 :                 state.dataTranspiredCollector->UTSC(Item).CollRoughness = Material::SurfaceRoughness::Rough;
     541              :             }
     542            1 :             if (Util::SameString(Roughness, "MediumRough")) {
     543            1 :                 state.dataTranspiredCollector->UTSC(Item).CollRoughness = Material::SurfaceRoughness::MediumRough;
     544              :             }
     545            1 :             if (Util::SameString(Roughness, "MediumSmooth")) {
     546            0 :                 state.dataTranspiredCollector->UTSC(Item).CollRoughness = Material::SurfaceRoughness::MediumSmooth;
     547              :             }
     548            1 :             if (Util::SameString(Roughness, "Smooth")) {
     549            0 :                 state.dataTranspiredCollector->UTSC(Item).CollRoughness = Material::SurfaceRoughness::Smooth;
     550              :             }
     551            1 :             if (Util::SameString(Roughness, "VerySmooth")) {
     552            0 :                 state.dataTranspiredCollector->UTSC(Item).CollRoughness = Material::SurfaceRoughness::VerySmooth;
     553              :             }
     554              : 
     555              :             // Was it set?
     556            1 :             if (state.dataTranspiredCollector->UTSC(Item).CollRoughness == Material::SurfaceRoughness::Invalid) {
     557            0 :                 ShowSevereError(state,
     558            0 :                                 format("{} has incorrect entry of {} in {} ={}",
     559            0 :                                        state.dataIPShortCut->cAlphaFieldNames(11),
     560              :                                        Alphas(11),
     561              :                                        CurrentModuleObject,
     562            0 :                                        state.dataTranspiredCollector->UTSC(Item).Name));
     563            0 :                 ErrorsFound = true;
     564              :             }
     565              : 
     566            1 :             AlphaOffset = 11;
     567            1 :             state.dataTranspiredCollector->UTSC(Item).NumSurfs = NumAlphas - AlphaOffset;
     568            1 :             if (state.dataTranspiredCollector->UTSC(Item).NumSurfs == 0) {
     569            0 :                 ShowSevereError(
     570            0 :                     state, format("No underlying surfaces specified in {} ={}", CurrentModuleObject, state.dataTranspiredCollector->UTSC(Item).Name));
     571            0 :                 ErrorsFound = true;
     572            0 :                 continue;
     573              :             }
     574            1 :             state.dataTranspiredCollector->UTSC(Item).SurfPtrs.allocate(state.dataTranspiredCollector->UTSC(Item).NumSurfs);
     575            1 :             state.dataTranspiredCollector->UTSC(Item).SurfPtrs = 0;
     576            3 :             for (ThisSurf = 1; ThisSurf <= state.dataTranspiredCollector->UTSC(Item).NumSurfs; ++ThisSurf) {
     577            2 :                 Found = Util::FindItemInList(Alphas(ThisSurf + AlphaOffset), state.dataSurface->Surface);
     578            2 :                 if (Found == 0) {
     579            0 :                     ShowSevereError(state,
     580            0 :                                     format("Surface Name not found={} in {} ={}",
     581              :                                            Alphas(ThisSurf + AlphaOffset),
     582              :                                            CurrentModuleObject,
     583            0 :                                            state.dataTranspiredCollector->UTSC(Item).Name));
     584            0 :                     ErrorsFound = true;
     585            0 :                     continue;
     586              :                 }
     587              :                 // check that surface is appropriate, Heat transfer, Sun, Wind,
     588            2 :                 if (!state.dataSurface->Surface(Found).HeatTransSurf) {
     589            0 :                     ShowSevereError(state,
     590            0 :                                     format("Surface {} not of Heat Transfer type in {} ={}",
     591              :                                            Alphas(ThisSurf + AlphaOffset),
     592              :                                            CurrentModuleObject,
     593            0 :                                            state.dataTranspiredCollector->UTSC(Item).Name));
     594            0 :                     ErrorsFound = true;
     595            0 :                     continue;
     596              :                 }
     597            2 :                 if (!state.dataSurface->Surface(Found).ExtSolar) {
     598            0 :                     ShowSevereError(state,
     599            0 :                                     format("Surface {} not exposed to sun in {} ={}",
     600              :                                            Alphas(ThisSurf + AlphaOffset),
     601              :                                            CurrentModuleObject,
     602            0 :                                            state.dataTranspiredCollector->UTSC(Item).Name));
     603            0 :                     ErrorsFound = true;
     604            0 :                     continue;
     605              :                 }
     606            2 :                 if (!state.dataSurface->Surface(Found).ExtWind) {
     607            0 :                     ShowSevereError(state,
     608            0 :                                     format("Surface {} not exposed to wind in {} ={}",
     609              :                                            Alphas(ThisSurf + AlphaOffset),
     610              :                                            CurrentModuleObject,
     611            0 :                                            state.dataTranspiredCollector->UTSC(Item).Name));
     612            0 :                     ErrorsFound = true;
     613            0 :                     continue;
     614              :                 }
     615            2 :                 if (state.dataSurface->Surface(Found).ExtBoundCond != OtherSideCondModeledExt) {
     616            0 :                     ShowSevereError(state,
     617            0 :                                     format("Surface {} does not have OtherSideConditionsModel for exterior boundary conditions in {} ={}",
     618              :                                            Alphas(ThisSurf + AlphaOffset),
     619              :                                            CurrentModuleObject,
     620            0 :                                            state.dataTranspiredCollector->UTSC(Item).Name));
     621            0 :                     ErrorsFound = true;
     622            0 :                     continue;
     623              :                 }
     624              :                 // check surface orientation, warn if upside down
     625            2 :                 if ((state.dataSurface->Surface(Found).Tilt < -95.0) || (state.dataSurface->Surface(Found).Tilt > 95.0)) {
     626            0 :                     ShowWarningError(state, format("Suspected input problem with collector surface = {}", Alphas(ThisSurf + AlphaOffset)));
     627            0 :                     ShowContinueError(
     628              :                         state,
     629            0 :                         format("Entered in {} = {}", state.dataIPShortCut->cCurrentModuleObject, state.dataTranspiredCollector->UTSC(Item).Name));
     630            0 :                     ShowContinueError(state, "Surface used for solar collector faces down");
     631            0 :                     ShowContinueError(
     632            0 :                         state, format("Surface tilt angle (degrees from ground outward normal) = {:.2R}", state.dataSurface->Surface(Found).Tilt));
     633              :                 }
     634              : 
     635            2 :                 state.dataTranspiredCollector->UTSC(Item).SurfPtrs(ThisSurf) = Found;
     636              :             }
     637              : 
     638            1 :             if (ErrorsFound) {
     639            0 :                 continue; // previous inner do loop may have detected problems that need to be cycle'd again to avoid crash
     640              :             }
     641              : 
     642              :             // now that we should have all the surfaces, do some preparations and checks.
     643              : 
     644              :             // are they all similar tilt and azimuth? Issue warnings so people can do it if they really want
     645            1 :             Real64 const surfaceArea(sum_sub(state.dataSurface->Surface, &SurfaceData::Area, state.dataTranspiredCollector->UTSC(Item).SurfPtrs));
     646              :             //            AvgAzimuth = sum( Surface( UTSC( Item ).SurfPtrs ).Azimuth * Surface( UTSC( Item ).SurfPtrs ).Area ) / sum( Surface(
     647              :             // UTSC(  Item
     648              :             //).SurfPtrs ).Area ); //Autodesk:F2C++ Array subscript usage: Replaced by below
     649            1 :             AvgAzimuth =
     650            2 :                 sum_product_sub(
     651            1 :                     state.dataSurface->Surface, &SurfaceData::Azimuth, &SurfaceData::Area, state.dataTranspiredCollector->UTSC(Item).SurfPtrs) /
     652              :                 surfaceArea; // Autodesk:F2C++ Functions handle array subscript usage
     653              :             //            AvgTilt = sum( Surface( UTSC( Item ).SurfPtrs ).Tilt * Surface( UTSC( Item ).SurfPtrs ).Area ) / sum( Surface( UTSC(
     654              :             // Item
     655              :             //).SurfPtrs ).Area ); //Autodesk:F2C++ Array subscript usage: Replaced by below
     656            2 :             AvgTilt = sum_product_sub(
     657            1 :                           state.dataSurface->Surface, &SurfaceData::Tilt, &SurfaceData::Area, state.dataTranspiredCollector->UTSC(Item).SurfPtrs) /
     658              :                       surfaceArea; // Autodesk:F2C++ Functions handle array subscript usage
     659            3 :             for (ThisSurf = 1; ThisSurf <= state.dataTranspiredCollector->UTSC(Item).NumSurfs; ++ThisSurf) {
     660            2 :                 SurfID = state.dataTranspiredCollector->UTSC(Item).SurfPtrs(ThisSurf);
     661            2 :                 if (General::rotAzmDiffDeg(state.dataSurface->Surface(SurfID).Azimuth, AvgAzimuth) > 15.0) {
     662            0 :                     ShowWarningError(state,
     663            0 :                                      format("Surface {} has Azimuth different from others in the group associated with {} ={}",
     664            0 :                                             state.dataSurface->Surface(SurfID).Name,
     665              :                                             CurrentModuleObject,
     666            0 :                                             state.dataTranspiredCollector->UTSC(Item).Name));
     667              :                 }
     668            2 :                 if (std::abs(state.dataSurface->Surface(SurfID).Tilt - AvgTilt) > 10.0) {
     669            0 :                     ShowWarningError(state,
     670            0 :                                      format("Surface {} has Tilt different from others in the group associated with {} ={}",
     671            0 :                                             state.dataSurface->Surface(SurfID).Name,
     672              :                                             CurrentModuleObject,
     673            0 :                                             state.dataTranspiredCollector->UTSC(Item).Name));
     674              :                 }
     675              : 
     676              :                 // test that there are no windows.  Now allow windows
     677              :                 // If (Surface(SurfID)%GrossArea >  Surface(SurfID)%Area) Then
     678              :                 //      Call ShowWarningError(state, 'Surface '//TRIM(Surface(SurfID)%name)//' has a subsurface whose area is not being ' &
     679              :                 //         //'subtracted in the group of surfaces associated with '//TRIM(UTSC(Item)%Name))
     680              :                 // endif
     681              :             }
     682            1 :             state.dataTranspiredCollector->UTSC(Item).Tilt = AvgTilt;
     683            1 :             state.dataTranspiredCollector->UTSC(Item).Azimuth = AvgAzimuth;
     684              : 
     685              :             // find area weighted centroid.
     686              :             //    UTSC(Item)%Centroid%x = SUM(Surface(UTSC(Item)%SurfPtrs)%Centroid%x*Surface(UTSC(Item)%SurfPtrs)%Area) &
     687              :             //                            /SUM(Surface(UTSC(Item)%SurfPtrs)%Area)
     688              :             //    UTSC(Item)%Centroid%y = SUM(Surface(UTSC(Item)%SurfPtrs)%Centroid%y*Surface(UTSC(Item)%SurfPtrs)%Area) &
     689              :             //                            /SUM(Surface(UTSC(Item)%SurfPtrs)%Area)
     690              :             //            UTSC( Item ).Centroid.z = sum( Surface( UTSC( Item ).SurfPtrs ).Centroid.z * Surface( UTSC( Item ).SurfPtrs ).Area ) /
     691              :             // sum(  Surface( UTSC( Item ).SurfPtrs ).Area ); //Autodesk:F2C++ Array subscript usage: Replaced by below
     692            2 :             state.dataTranspiredCollector->UTSC(Item).Centroid.z = sum_product_sub(state.dataSurface->Surface,
     693              :                                                                                    &SurfaceData::Centroid,
     694              :                                                                                    &Vector::z,
     695            1 :                                                                                    state.dataSurface->Surface,
     696              :                                                                                    &SurfaceData::Area,
     697            2 :                                                                                    state.dataTranspiredCollector->UTSC(Item).SurfPtrs) /
     698              :                                                                    surfaceArea; // Autodesk:F2C++ Functions handle array subscript usage
     699              : 
     700              :             // now handle numbers from input object
     701            1 :             state.dataTranspiredCollector->UTSC(Item).HoleDia = Numbers(1);
     702            1 :             state.dataTranspiredCollector->UTSC(Item).Pitch = Numbers(2);
     703            1 :             state.dataTranspiredCollector->UTSC(Item).LWEmitt = Numbers(3);
     704            1 :             state.dataTranspiredCollector->UTSC(Item).SolAbsorp = Numbers(4);
     705            1 :             state.dataTranspiredCollector->UTSC(Item).Height = Numbers(5);
     706            1 :             state.dataTranspiredCollector->UTSC(Item).PlenGapThick = Numbers(6);
     707            1 :             if (state.dataTranspiredCollector->UTSC(Item).PlenGapThick <= 0.0) {
     708            0 :                 ShowSevereError(
     709              :                     state,
     710            0 :                     format("Plenum gap must be greater than Zero in {} ={}", CurrentModuleObject, state.dataTranspiredCollector->UTSC(Item).Name));
     711            0 :                 continue;
     712              :             }
     713            1 :             state.dataTranspiredCollector->UTSC(Item).PlenCrossArea = Numbers(7);
     714            1 :             state.dataTranspiredCollector->UTSC(Item).AreaRatio = Numbers(8);
     715            1 :             state.dataTranspiredCollector->UTSC(Item).CollectThick = Numbers(9);
     716            1 :             state.dataTranspiredCollector->UTSC(Item).Cv = Numbers(10);
     717            1 :             state.dataTranspiredCollector->UTSC(Item).Cd = Numbers(11);
     718              : 
     719              :             // Fill out data we now know
     720              :             // sum areas of HT surface areas
     721              :             //            UTSC( Item ).ProjArea = sum( Surface( UTSC( Item ).SurfPtrs ).Area ); //Autodesk:F2C++ Array subscript usage: Replaced
     722              :             // by  below
     723            1 :             state.dataTranspiredCollector->UTSC(Item).ProjArea = surfaceArea;
     724            1 :             if (state.dataTranspiredCollector->UTSC(Item).ProjArea == 0) {
     725            0 :                 ShowSevereError(state,
     726            0 :                                 format("Gross area of underlying surfaces is zero in {} ={}",
     727              :                                        CurrentModuleObject,
     728            0 :                                        state.dataTranspiredCollector->UTSC(Item).Name));
     729            0 :                 continue;
     730              :             }
     731            1 :             state.dataTranspiredCollector->UTSC(Item).ActualArea =
     732            1 :                 state.dataTranspiredCollector->UTSC(Item).ProjArea * state.dataTranspiredCollector->UTSC(Item).AreaRatio;
     733              :             //  need to update this for slots as well as holes
     734            1 :             switch (state.dataTranspiredCollector->UTSC(Item).Layout) {
     735            1 :             case Layout_Triangle: { // 'TRIANGLE'
     736            1 :                 state.dataTranspiredCollector->UTSC(Item).Porosity =
     737            2 :                     0.907 * pow_2(state.dataTranspiredCollector->UTSC(Item).HoleDia /
     738            1 :                                   state.dataTranspiredCollector->UTSC(Item).Pitch); // Kutscher equation, Triangle layout
     739            1 :             } break;
     740            0 :             case Layout_Square: { // 'SQUARE'
     741            0 :                 state.dataTranspiredCollector->UTSC(Item).Porosity =
     742            0 :                     (Constant::Pi / 4.0) * pow_2(state.dataTranspiredCollector->UTSC(Item).HoleDia) /
     743            0 :                     pow_2(state.dataTranspiredCollector->UTSC(Item).Pitch); // Waterloo equation, square layout
     744            0 :             } break;
     745            0 :             default:
     746            0 :                 break;
     747              :             }
     748            1 :             TiltRads = std::abs(AvgTilt) * Constant::DegToRad;
     749            1 :             tempHdeltaNPL = std::sin(TiltRads) * state.dataTranspiredCollector->UTSC(Item).Height / 4.0;
     750            1 :             state.dataTranspiredCollector->UTSC(Item).HdeltaNPL = max(tempHdeltaNPL, state.dataTranspiredCollector->UTSC(Item).PlenGapThick);
     751              : 
     752            2 :             SetupOutputVariable(state,
     753              :                                 "Solar Collector Heat Exchanger Effectiveness",
     754              :                                 Constant::Units::None,
     755            1 :                                 state.dataTranspiredCollector->UTSC(Item).HXeff,
     756              :                                 OutputProcessor::TimeStepType::System,
     757              :                                 OutputProcessor::StoreType::Average,
     758            1 :                                 state.dataTranspiredCollector->UTSC(Item).Name);
     759            2 :             SetupOutputVariable(state,
     760              :                                 "Solar Collector Leaving Air Temperature",
     761              :                                 Constant::Units::C,
     762            1 :                                 state.dataTranspiredCollector->UTSC(Item).TairHX,
     763              :                                 OutputProcessor::TimeStepType::System,
     764              :                                 OutputProcessor::StoreType::Average,
     765            1 :                                 state.dataTranspiredCollector->UTSC(Item).Name);
     766            2 :             SetupOutputVariable(state,
     767              :                                 "Solar Collector Outside Face Suction Velocity",
     768              :                                 Constant::Units::m_s,
     769            1 :                                 state.dataTranspiredCollector->UTSC(Item).Vsuction,
     770              :                                 OutputProcessor::TimeStepType::System,
     771              :                                 OutputProcessor::StoreType::Average,
     772            1 :                                 state.dataTranspiredCollector->UTSC(Item).Name);
     773            2 :             SetupOutputVariable(state,
     774              :                                 "Solar Collector Surface Temperature",
     775              :                                 Constant::Units::C,
     776            1 :                                 state.dataTranspiredCollector->UTSC(Item).Tcoll,
     777              :                                 OutputProcessor::TimeStepType::System,
     778              :                                 OutputProcessor::StoreType::Average,
     779            1 :                                 state.dataTranspiredCollector->UTSC(Item).Name);
     780            2 :             SetupOutputVariable(state,
     781              :                                 "Solar Collector Plenum Air Temperature",
     782              :                                 Constant::Units::C,
     783            1 :                                 state.dataTranspiredCollector->UTSC(Item).Tplen,
     784              :                                 OutputProcessor::TimeStepType::System,
     785              :                                 OutputProcessor::StoreType::Average,
     786            1 :                                 state.dataTranspiredCollector->UTSC(Item).Name);
     787            2 :             SetupOutputVariable(state,
     788              :                                 "Solar Collector Sensible Heating Rate",
     789              :                                 Constant::Units::W,
     790            1 :                                 state.dataTranspiredCollector->UTSC(Item).SensHeatingRate,
     791              :                                 OutputProcessor::TimeStepType::System,
     792              :                                 OutputProcessor::StoreType::Average,
     793            1 :                                 state.dataTranspiredCollector->UTSC(Item).Name);
     794            2 :             SetupOutputVariable(state,
     795              :                                 "Solar Collector Sensible Heating Energy",
     796              :                                 Constant::Units::J,
     797            1 :                                 state.dataTranspiredCollector->UTSC(Item).SensHeatingEnergy,
     798              :                                 OutputProcessor::TimeStepType::System,
     799              :                                 OutputProcessor::StoreType::Sum,
     800            1 :                                 state.dataTranspiredCollector->UTSC(Item).Name,
     801              :                                 Constant::eResource::SolarAir,
     802              :                                 OutputProcessor::Group::HVAC,
     803              :                                 OutputProcessor::EndUseCat::HeatProduced);
     804              : 
     805            2 :             SetupOutputVariable(state,
     806              :                                 "Solar Collector Natural Ventilation Air Change Rate",
     807              :                                 Constant::Units::ach,
     808            1 :                                 state.dataTranspiredCollector->UTSC(Item).PassiveACH,
     809              :                                 OutputProcessor::TimeStepType::System,
     810              :                                 OutputProcessor::StoreType::Average,
     811            1 :                                 state.dataTranspiredCollector->UTSC(Item).Name);
     812            2 :             SetupOutputVariable(state,
     813              :                                 "Solar Collector Natural Ventilation Mass Flow Rate",
     814              :                                 Constant::Units::kg_s,
     815            1 :                                 state.dataTranspiredCollector->UTSC(Item).PassiveMdotVent,
     816              :                                 OutputProcessor::TimeStepType::System,
     817              :                                 OutputProcessor::StoreType::Average,
     818            1 :                                 state.dataTranspiredCollector->UTSC(Item).Name);
     819            2 :             SetupOutputVariable(state,
     820              :                                 "Solar Collector Wind Natural Ventilation Mass Flow Rate",
     821              :                                 Constant::Units::kg_s,
     822            1 :                                 state.dataTranspiredCollector->UTSC(Item).PassiveMdotWind,
     823              :                                 OutputProcessor::TimeStepType::System,
     824              :                                 OutputProcessor::StoreType::Average,
     825            1 :                                 state.dataTranspiredCollector->UTSC(Item).Name);
     826            2 :             SetupOutputVariable(state,
     827              :                                 "Solar Collector Buoyancy Natural Ventilation Mass Flow Rate",
     828              :                                 Constant::Units::kg_s,
     829            1 :                                 state.dataTranspiredCollector->UTSC(Item).PassiveMdotTherm,
     830              :                                 OutputProcessor::TimeStepType::System,
     831              :                                 OutputProcessor::StoreType::Average,
     832            1 :                                 state.dataTranspiredCollector->UTSC(Item).Name);
     833            2 :             SetupOutputVariable(state,
     834              :                                 "Solar Collector Incident Solar Radiation",
     835              :                                 Constant::Units::W_m2,
     836            1 :                                 state.dataTranspiredCollector->UTSC(Item).Isc,
     837              :                                 OutputProcessor::TimeStepType::System,
     838              :                                 OutputProcessor::StoreType::Average,
     839            1 :                                 state.dataTranspiredCollector->UTSC(Item).Name);
     840            2 :             SetupOutputVariable(state,
     841              :                                 "Solar Collector System Efficiency",
     842              :                                 Constant::Units::None,
     843            1 :                                 state.dataTranspiredCollector->UTSC(Item).UTSCEfficiency,
     844              :                                 OutputProcessor::TimeStepType::System,
     845              :                                 OutputProcessor::StoreType::Average,
     846            1 :                                 state.dataTranspiredCollector->UTSC(Item).Name);
     847            2 :             SetupOutputVariable(state,
     848              :                                 "Solar Collector Surface Efficiency",
     849              :                                 Constant::Units::None,
     850            1 :                                 state.dataTranspiredCollector->UTSC(Item).UTSCCollEff,
     851              :                                 OutputProcessor::TimeStepType::System,
     852              :                                 OutputProcessor::StoreType::Average,
     853            1 :                                 state.dataTranspiredCollector->UTSC(Item).Name);
     854              :         }
     855              : 
     856            1 :         for (ItemSplit = 1; ItemSplit <= NumUTSCSplitter; ++ItemSplit) {
     857            0 :             if (!SplitterNameOK(ItemSplit)) {
     858            0 :                 ShowSevereError(state, "Did not find a match, check names for Solar Collectors:Transpired Collector:Multisystem");
     859            0 :                 ErrorsFound = true;
     860              :             }
     861              :         }
     862              : 
     863            1 :         if (ErrorsFound) {
     864            0 :             ShowFatalError(state, "GetTranspiredCollectorInput: Errors found in input");
     865              :         }
     866              : 
     867            1 :         Alphas.deallocate();
     868            1 :     }
     869              : 
     870            1 :     void InitTranspiredCollector(EnergyPlusData &state, int const UTSCNum) // compindex already checked in calling routine
     871              :     {
     872              : 
     873              :         // SUBROUTINE INFORMATION:
     874              :         //       AUTHOR         B.T. Griffith
     875              :         //       DATE WRITTEN   November 2004
     876              :         //       MODIFIED       B. Griffith, May 2009, added EMS setpoint check
     877              :         //       RE-ENGINEERED  na
     878              : 
     879              :         // Using/Aliasing
     880            1 :         bool DoSetPointTest = state.dataHVACGlobal->DoSetPointTest;
     881              :         using namespace DataLoopNode;
     882              :         using DataSurfaces::SurfaceData;
     883              :         using EMSManager::CheckIfNodeSetPointManagedByEMS;
     884              : 
     885              :         int UTSCUnitNum;
     886              :         int ControlNode;
     887              :         int SplitBranch;
     888              :         int thisUTSC;
     889              :         Real64 Tamb;
     890              : 
     891            1 :         if (state.dataTranspiredCollector->MyOneTimeFlag) {
     892              :             // do various one time setups and pitch adjustments across all UTSC
     893            2 :             for (thisUTSC = 1; thisUTSC <= state.dataTranspiredCollector->NumUTSC; ++thisUTSC) {
     894            1 :                 if (state.dataTranspiredCollector->UTSC(thisUTSC).Layout == Layout_Triangle) {
     895            1 :                     switch (state.dataTranspiredCollector->UTSC(thisUTSC).Correlation) {
     896            1 :                     case Correlation_Kutscher1994: { // Kutscher1994
     897            1 :                         state.dataTranspiredCollector->UTSC(thisUTSC).Pitch = state.dataTranspiredCollector->UTSC(thisUTSC).Pitch;
     898            1 :                     } break;
     899            0 :                     case Correlation_VanDeckerHollandsBrunger2001: { // VanDeckerHollandsBrunger2001
     900            0 :                         state.dataTranspiredCollector->UTSC(thisUTSC).Pitch /= 1.6;
     901            0 :                     } break;
     902            0 :                     default:
     903            0 :                         break;
     904              :                     }
     905              :                 }
     906            1 :                 if (state.dataTranspiredCollector->UTSC(thisUTSC).Layout == Layout_Square) {
     907            0 :                     switch (state.dataTranspiredCollector->UTSC(thisUTSC).Correlation) {
     908            0 :                     case Correlation_Kutscher1994: { // Kutscher1994
     909            0 :                         state.dataTranspiredCollector->UTSC(thisUTSC).Pitch *= 1.6;
     910            0 :                     } break;
     911            0 :                     case Correlation_VanDeckerHollandsBrunger2001: { // VanDeckerHollandsBrunger2001
     912            0 :                         state.dataTranspiredCollector->UTSC(thisUTSC).Pitch = state.dataTranspiredCollector->UTSC(thisUTSC).Pitch;
     913            0 :                     } break;
     914            0 :                     default:
     915            0 :                         break;
     916              :                     }
     917              :                 }
     918              :             }
     919              : 
     920            1 :             state.dataTranspiredCollector->MyEnvrnFlag.dimension(state.dataTranspiredCollector->NumUTSC, true);
     921            1 :             state.dataTranspiredCollector->MyOneTimeFlag = false;
     922              :         } // first time
     923              : 
     924              :         // Check that setpoint is active (from test by RJL in HVACEvapComponent)
     925            1 :         if (!state.dataGlobal->SysSizingCalc && state.dataTranspiredCollector->MySetPointCheckFlag && DoSetPointTest) {
     926            0 :             for (UTSCUnitNum = 1; UTSCUnitNum <= state.dataTranspiredCollector->NumUTSC; ++UTSCUnitNum) {
     927            0 :                 for (SplitBranch = 1; SplitBranch <= state.dataTranspiredCollector->UTSC(UTSCUnitNum).NumOASysAttached; ++SplitBranch) {
     928            0 :                     ControlNode = state.dataTranspiredCollector->UTSC(UTSCUnitNum).ControlNode(SplitBranch);
     929            0 :                     if (ControlNode > 0) {
     930            0 :                         if (state.dataLoopNodes->Node(ControlNode).TempSetPoint == SensedNodeFlagValue) {
     931            0 :                             if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
     932            0 :                                 ShowSevereError(
     933            0 :                                     state, format("Missing temperature setpoint for UTSC {}", state.dataTranspiredCollector->UTSC(UTSCUnitNum).Name));
     934            0 :                                 ShowContinueError(state, " use a Setpoint Manager to establish a setpoint at the unit control node.");
     935            0 :                                 state.dataHVACGlobal->SetPointErrorFlag = true;
     936              :                             } else {
     937              :                                 // need call to EMS to check node
     938            0 :                                 CheckIfNodeSetPointManagedByEMS(state, ControlNode, HVAC::CtrlVarType::Temp, state.dataHVACGlobal->SetPointErrorFlag);
     939            0 :                                 if (state.dataHVACGlobal->SetPointErrorFlag) {
     940            0 :                                     ShowSevereError(
     941              :                                         state,
     942            0 :                                         format("Missing temperature setpoint for UTSC {}", state.dataTranspiredCollector->UTSC(UTSCUnitNum).Name));
     943            0 :                                     ShowContinueError(state, " use a Setpoint Manager to establish a setpoint at the unit control node.");
     944            0 :                                     ShowContinueError(state, "Or add EMS Actuator to provide temperature setpoint at this node");
     945              :                                 }
     946              :                             }
     947              :                         }
     948              :                     }
     949              :                 }
     950              :             }
     951            0 :             state.dataTranspiredCollector->MySetPointCheckFlag = false;
     952              :         }
     953              : 
     954            1 :         if (state.dataGlobal->BeginEnvrnFlag && state.dataTranspiredCollector->MyEnvrnFlag(UTSCNum)) {
     955            1 :             state.dataTranspiredCollector->UTSC(UTSCNum).TplenLast = 22.5;
     956            1 :             state.dataTranspiredCollector->UTSC(UTSCNum).TcollLast = 22.0;
     957              : 
     958            1 :             state.dataTranspiredCollector->MyEnvrnFlag(UTSCNum) = false;
     959              :         }
     960            1 :         if (!state.dataGlobal->BeginEnvrnFlag) {
     961            0 :             state.dataTranspiredCollector->MyEnvrnFlag(UTSCNum) = true;
     962              :         }
     963              : 
     964              :         // determine average ambient temperature
     965            1 :         Real64 sum_area = 0.0;
     966            3 :         for (int SurfNum : state.dataTranspiredCollector->UTSC(UTSCNum).SurfPtrs) {
     967            2 :             sum_area += state.dataSurface->Surface(SurfNum).Area;
     968              :         }
     969            1 :         if (!state.dataEnvrn->IsRain) {
     970            1 :             Real64 sum_produc_area_drybulb = 0.0;
     971            3 :             for (int SurfNum : state.dataTranspiredCollector->UTSC(UTSCNum).SurfPtrs) {
     972            2 :                 sum_produc_area_drybulb += state.dataSurface->Surface(SurfNum).Area * state.dataSurface->SurfOutDryBulbTemp(SurfNum);
     973              :             }
     974            1 :             Tamb = sum_produc_area_drybulb / sum_area;
     975              :         } else { // when raining we use wet bulb not drybulb
     976            0 :             Real64 sum_produc_area_wetbulb = 0.0;
     977            0 :             for (int SurfNum : state.dataTranspiredCollector->UTSC(UTSCNum).SurfPtrs) {
     978            0 :                 sum_produc_area_wetbulb += state.dataSurface->Surface(SurfNum).Area * state.dataSurface->SurfOutWetBulbTemp(SurfNum);
     979              :             }
     980            0 :             Tamb = sum_produc_area_wetbulb / sum_area;
     981              :         }
     982              : 
     983              :         // inits for each iteration
     984              :         //        UTSC( UTSCNum ).InletMDot = sum( Node( UTSC( UTSCNum ).InletNode ).MassFlowRate ); //Autodesk:F2C++ Array subscript usage:
     985              :         // Replaced by below
     986            1 :         state.dataTranspiredCollector->UTSC(UTSCNum).InletMDot =
     987            1 :             sum_sub(state.dataLoopNodes->Node,
     988              :                     &DataLoopNode::NodeData::MassFlowRate,
     989            1 :                     state.dataTranspiredCollector->UTSC(UTSCNum).InletNode); // Autodesk:F2C++ Functions handle array subscript usage
     990            1 :         state.dataTranspiredCollector->UTSC(UTSCNum).IsOn = false;           // initialize then turn on if appropriate
     991            1 :         state.dataTranspiredCollector->UTSC(UTSCNum).Tplen = state.dataTranspiredCollector->UTSC(UTSCNum).TplenLast;
     992            1 :         state.dataTranspiredCollector->UTSC(UTSCNum).Tcoll = state.dataTranspiredCollector->UTSC(UTSCNum).TcollLast;
     993            1 :         state.dataTranspiredCollector->UTSC(UTSCNum).TairHX = Tamb;
     994            1 :         state.dataTranspiredCollector->UTSC(UTSCNum).MdotVent = 0.0;
     995            1 :         state.dataTranspiredCollector->UTSC(UTSCNum).HXeff = 0.0;
     996            1 :         state.dataTranspiredCollector->UTSC(UTSCNum).Isc = 0.0;
     997              : 
     998            1 :         state.dataTranspiredCollector->UTSC(UTSCNum).UTSCEfficiency = 0.0;
     999            1 :         state.dataTranspiredCollector->UTSC(UTSCNum).UTSCCollEff = 0.0;
    1000            1 :     }
    1001              : 
    1002            0 :     void CalcActiveTranspiredCollector(EnergyPlusData &state, int const UTSCNum)
    1003              :     {
    1004              : 
    1005              :         // SUBROUTINE INFORMATION:
    1006              :         //       AUTHOR         B.T. Griffith
    1007              :         //       DATE WRITTEN   November 2004
    1008              :         //       MODIFIED       na
    1009              :         //       RE-ENGINEERED  na
    1010              : 
    1011              :         // Using/Aliasing
    1012            0 :         Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
    1013              :         using DataSurfaces::SurfaceData;
    1014              :         using Psychrometrics::PsyCpAirFnW;
    1015              :         using Psychrometrics::PsyHFnTdbW;
    1016              :         using Psychrometrics::PsyRhoAirFnPbTdbW;
    1017              :         using namespace DataHeatBalance; // , ONLY: SurfQRadSWOutIncident, Construct, Material
    1018              : 
    1019              :         // SUBROUTINE PARAMETER DEFINITIONS:
    1020            0 :         Real64 constexpr nu(15.66e-6); // kinematic viscosity (m**2/s) for air at 300 K
    1021              :         // (Mills 1999 Heat Transfer)
    1022            0 :         Real64 constexpr k(0.0267); // thermal conductivity (W/m K) for air at 300 K
    1023              :         // (Mills 1999 Heat Transfer)
    1024            0 :         Real64 constexpr Sigma(5.6697e-08); // Stefan-Boltzmann constant
    1025              : 
    1026              :         // following arrays are used to temporarily hold results from multiple underlying surfaces
    1027            0 :         Array1D<Real64> HSkyARR;
    1028            0 :         Array1D<Real64> HGroundARR;
    1029            0 :         Array1D<Real64> HAirARR;
    1030            0 :         Array1D<Real64> HPlenARR;
    1031            0 :         Array1D<Real64> LocalWindArr;
    1032            0 :         Array1D<Real64> HSrdSurfARR;
    1033              : 
    1034              :         // working variables
    1035              :         Real64 RhoAir;                        // density of air
    1036              :         Real64 CpAir;                         // specific heat of air
    1037              :         Real64 holeArea;                      // area of perforations, includes corrugation of surface
    1038              :         Real64 Tamb;                          // outdoor drybulb
    1039              :         Real64 A;                             // projected area of collector, from sum of underlying surfaces
    1040              :         Real64 Vholes;                        // mean velocity of air as it passes through collector holes
    1041              :         Real64 Vsuction;                      // mean velocity of air as is approaches the collector
    1042              :         Real64 Vplen;                         // mean velocity of air inside plenum
    1043              :         Real64 HcPlen;                        // surface convection heat transfer coefficient for plenum surfaces
    1044              :         Real64 D;                             // hole diameter
    1045              :         Real64 ReD;                           // Reynolds number for holes
    1046              :         Real64 P;                             // pitch, distance between holes
    1047              :         Real64 Por;                           // porosity, area fraction of collector that is open because of holes
    1048              :         Real64 Mdot;                          // mass flow rate of suction air
    1049              :         Real64 QdotSource;                    // energy flux for source/sink inside collector surface (for hybrid PV UTSC)
    1050              :         int ThisSurf;                         // do loop counter
    1051              :         int NumSurfs;                         // number of underlying HT surfaces associated with UTSC
    1052              :         Material::SurfaceRoughness Roughness; // parameters for surface roughness, defined in DataHeatBalance
    1053              :         Real64 SolAbs;                        // solar absorptivity of collector
    1054              :         Real64 AbsExt;                        // thermal emittance of collector
    1055              :         Real64 TempExt;                       // collector temperature
    1056              :         int SurfPtr;                          // index of surface in main surface structure
    1057              :         Real64 HMovInsul;                     // dummy for call to InitExteriorConvectionCoeff
    1058              :         Real64 HExt;                          // dummy for call to InitExteriorConvectionCoeff
    1059              :         int ConstrNum;                        // index of construction in main construction structure
    1060              :         Real64 AbsThermSurf;                  // thermal emittance of underlying wall.
    1061              :         Real64 TsoK;                          // underlying surface temperature in Kelvin
    1062              :         Real64 TscollK;                       // collector temperature in Kelvin  (lagged)
    1063              :         Real64 AreaSum;                       // sum of contributing surfaces for area-weighted averages.
    1064              :         Real64 Vwind;                         // localized, and area-weighted average for wind speed
    1065              :         Real64 HrSky;                         // radiation coeff for sky, area-weighted average
    1066              :         Real64 HrGround;                      // radiation coeff for ground, area-weighted average
    1067              :         Real64 HrAtm;                         // radiation coeff for air (bulk atmosphere), area-weighted average
    1068              :         Real64 Isc;                           // Incoming combined solar radiation, area-weighted average
    1069              :         Real64 HrPlen;                        // radiation coeff for plenum surfaces, area-weighted average
    1070              :         Real64 Tso;                           // temperature of underlying surface, area-weighted average
    1071              :         Real64 HcWind;                        // convection coeff for high speed wind situations
    1072              :         Real64 NuD;                           // nusselt number for Reynolds based on hole
    1073              :         Real64 U;                             // overall heat exchanger coefficient
    1074              :         Real64 HXeff;                         // effectiveness for heat exchanger
    1075              :         Real64 t;                             // collector thickness
    1076              :         Real64 ReS;                           // Reynolds number based on suction velocity and pitch
    1077              :         Real64 ReW;                           // Reynolds number based on Wind and pitch
    1078              :         Real64 ReB;                           // Reynolds number based on hole velocity and pitch
    1079              :         Real64 ReH;                           // Reynolds number based on hole velocity and diameter
    1080              :         Real64 Tscoll;                        // temperature of collector
    1081              :         Real64 TaHX;                          // leaving air temperature from heat exchanger (entering plenum)
    1082              :         Real64 Taplen;                        // Air temperature in plen and outlet node.
    1083              :         Real64 SensHeatingRate;               // Rate at which the system is heating outdoor air
    1084              :         Real64 AlessHoles;                    // Area for Kutscher's relation
    1085              : 
    1086            0 :         auto &s_mat = state.dataMaterial;
    1087              :         // Active UTSC calculation
    1088              :         // first do common things for both correlations
    1089            0 :         Real64 sum_area = 0.0;
    1090            0 :         for (int SurfNum : state.dataTranspiredCollector->UTSC(UTSCNum).SurfPtrs) {
    1091            0 :             sum_area += state.dataSurface->Surface(SurfNum).Area;
    1092              :         }
    1093            0 :         if (!state.dataEnvrn->IsRain) {
    1094            0 :             Real64 sum_produc_area_drybulb = 0.0;
    1095            0 :             for (int SurfNum : state.dataTranspiredCollector->UTSC(UTSCNum).SurfPtrs) {
    1096            0 :                 sum_produc_area_drybulb += state.dataSurface->Surface(SurfNum).Area * state.dataSurface->SurfOutDryBulbTemp(SurfNum);
    1097              :             }
    1098            0 :             Tamb = sum_produc_area_drybulb / sum_area;
    1099              :         } else { // when raining we use wet bulb not drybulb
    1100            0 :             Real64 sum_produc_area_wetbulb = 0.0;
    1101            0 :             for (int SurfNum : state.dataTranspiredCollector->UTSC(UTSCNum).SurfPtrs) {
    1102            0 :                 sum_produc_area_wetbulb += state.dataSurface->Surface(SurfNum).Area * state.dataSurface->SurfOutWetBulbTemp(SurfNum);
    1103              :             }
    1104            0 :             Tamb = sum_produc_area_wetbulb / sum_area;
    1105              :         }
    1106              : 
    1107            0 :         RhoAir = PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, Tamb, state.dataEnvrn->OutHumRat);
    1108              : 
    1109            0 :         CpAir = PsyCpAirFnW(state.dataEnvrn->OutHumRat);
    1110              : 
    1111            0 :         holeArea = state.dataTranspiredCollector->UTSC(UTSCNum).ActualArea * state.dataTranspiredCollector->UTSC(UTSCNum).Porosity;
    1112              : 
    1113            0 :         A = state.dataTranspiredCollector->UTSC(UTSCNum).ProjArea;
    1114              : 
    1115            0 :         Vholes = state.dataTranspiredCollector->UTSC(UTSCNum).InletMDot / RhoAir / holeArea;
    1116              : 
    1117            0 :         Vplen = state.dataTranspiredCollector->UTSC(UTSCNum).InletMDot / RhoAir / state.dataTranspiredCollector->UTSC(UTSCNum).PlenCrossArea;
    1118              : 
    1119            0 :         Vsuction = state.dataTranspiredCollector->UTSC(UTSCNum).InletMDot / RhoAir / A;
    1120              : 
    1121            0 :         if ((Vsuction < 0.001) || (Vsuction > 0.08)) { // warn that collector is not sized well
    1122            0 :             if (state.dataTranspiredCollector->UTSC(UTSCNum).VsucErrIndex == 0) {
    1123            0 :                 ShowWarningMessage(state,
    1124            0 :                                    format("Solar Collector:Unglazed Transpired=\"{}\", Suction velocity is outside of range for a good design",
    1125            0 :                                           state.dataTranspiredCollector->UTSC(UTSCNum).Name));
    1126            0 :                 ShowContinueErrorTimeStamp(state, format("Suction velocity ={:.4R}", Vsuction));
    1127            0 :                 if (Vsuction < 0.003) {
    1128            0 :                     ShowContinueError(state, "Velocity is low -- suggest decreasing area of transpired collector");
    1129              :                 }
    1130            0 :                 if (Vsuction > 0.08) {
    1131            0 :                     ShowContinueError(state, "Velocity is high -- suggest increasing area of transpired collector");
    1132              :                 }
    1133            0 :                 ShowContinueError(state, "Occasional suction velocity messages are not unexpected when simulating actual conditions");
    1134              :             }
    1135            0 :             ShowRecurringWarningErrorAtEnd(state,
    1136            0 :                                            "Solar Collector:Unglazed Transpired=\"" + state.dataTranspiredCollector->UTSC(UTSCNum).Name +
    1137              :                                                "\", Suction velocity is outside of range",
    1138            0 :                                            state.dataTranspiredCollector->UTSC(UTSCNum).VsucErrIndex,
    1139              :                                            Vsuction,
    1140              :                                            Vsuction,
    1141              :                                            _,
    1142              :                                            "[m/s]",
    1143              :                                            "[m/s]");
    1144              :         }
    1145              : 
    1146            0 :         HcPlen = 5.62 + 3.92 * Vplen;
    1147              : 
    1148            0 :         D = state.dataTranspiredCollector->UTSC(UTSCNum).HoleDia;
    1149              : 
    1150            0 :         ReD = Vholes * D / nu;
    1151              : 
    1152            0 :         P = state.dataTranspiredCollector->UTSC(UTSCNum).Pitch;
    1153              : 
    1154            0 :         Por = state.dataTranspiredCollector->UTSC(UTSCNum).Porosity;
    1155              : 
    1156            0 :         Mdot = state.dataTranspiredCollector->UTSC(UTSCNum).InletMDot;
    1157              : 
    1158            0 :         QdotSource = state.dataTranspiredCollector->UTSC(UTSCNum).QdotSource; // for hybrid PV transpired collectors
    1159              : 
    1160              :         // loop through underlying surfaces and collect needed data
    1161              :         // now collect average values for things associated with the underlying surface(s)
    1162            0 :         NumSurfs = state.dataTranspiredCollector->UTSC(UTSCNum).NumSurfs;
    1163            0 :         HSkyARR.dimension(NumSurfs, 0.0);
    1164            0 :         HGroundARR.dimension(NumSurfs, 0.0);
    1165            0 :         HAirARR.dimension(NumSurfs, 0.0);
    1166            0 :         LocalWindArr.dimension(NumSurfs, 0.0);
    1167              :         // ALLOCATE(IscARR(NumSurfs))
    1168              :         // IscARR = 0.0
    1169            0 :         HPlenARR.dimension(NumSurfs, 0.0);
    1170              :         //  ALLOCATE(TsoARR(NumSurfs))
    1171              :         //  TsoARR = 0.0
    1172            0 :         HSrdSurfARR.dimension(NumSurfs, 0.0);
    1173              : 
    1174            0 :         Roughness = state.dataTranspiredCollector->UTSC(UTSCNum).CollRoughness;
    1175            0 :         SolAbs = state.dataTranspiredCollector->UTSC(UTSCNum).SolAbsorp;
    1176            0 :         AbsExt = state.dataTranspiredCollector->UTSC(UTSCNum).LWEmitt;
    1177            0 :         TempExt = state.dataTranspiredCollector->UTSC(UTSCNum).TcollLast;
    1178            0 :         for (ThisSurf = 1; ThisSurf <= NumSurfs; ++ThisSurf) {
    1179            0 :             SurfPtr = state.dataTranspiredCollector->UTSC(UTSCNum).SurfPtrs(ThisSurf);
    1180              :             // Initializations for this surface
    1181            0 :             HMovInsul = 0.0;
    1182            0 :             HExt = 0.0;
    1183            0 :             LocalWindArr(ThisSurf) = state.dataSurface->SurfOutWindSpeed(SurfPtr);
    1184            0 :             Convect::InitExtConvCoeff(state,
    1185              :                                       SurfPtr,
    1186              :                                       HMovInsul,
    1187              :                                       Roughness,
    1188              :                                       AbsExt,
    1189              :                                       TempExt,
    1190              :                                       HExt,
    1191            0 :                                       HSkyARR(ThisSurf),
    1192            0 :                                       HGroundARR(ThisSurf),
    1193            0 :                                       HAirARR(ThisSurf),
    1194            0 :                                       HSrdSurfARR(ThisSurf));
    1195            0 :             ConstrNum = state.dataSurface->Surface(SurfPtr).Construction;
    1196            0 :             AbsThermSurf = s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(1))->AbsorpThermal;
    1197            0 :             TsoK = state.dataHeatBalSurf->SurfOutsideTempHist(1)(SurfPtr) + Constant::Kelvin;
    1198            0 :             TscollK = state.dataTranspiredCollector->UTSC(UTSCNum).TcollLast + Constant::Kelvin;
    1199            0 :             HPlenARR(ThisSurf) = Sigma * AbsExt * AbsThermSurf * (pow_4(TscollK) - pow_4(TsoK)) / (TscollK - TsoK);
    1200              :         }
    1201              :         //        AreaSum = sum( Surface( UTSC( UTSCNum ).SurfPtrs ).Area ); //Autodesk:F2C++ Array subscript usage: Replaced by below
    1202              :         auto Area = // (AUTO_OK_OBJ)
    1203            0 :             array_sub(state.dataSurface->Surface,
    1204              :                       &SurfaceData::Area,
    1205            0 :                       state.dataTranspiredCollector->UTSC(UTSCNum)
    1206            0 :                           .SurfPtrs); // Autodesk:F2C++ Copy of subscripted Area array for use below: This makes a copy so review wrt performance
    1207            0 :         AreaSum = sum(Area);
    1208              :         // now figure area-weighted averages from underlying surfaces.
    1209              :         //        Vwind = sum( LocalWindArr * Surface( UTSC( UTSCNum ).SurfPtrs ).Area ) / AreaSum; //Autodesk:F2C++ Array subscript usage:
    1210              :         // Replaced by below
    1211            0 :         Vwind = sum(LocalWindArr * Area) / AreaSum;
    1212            0 :         LocalWindArr.deallocate();
    1213              :         //        HrSky = sum( HSkyARR * Surface( UTSC( UTSCNum ).SurfPtrs ).Area ) / AreaSum; //Autodesk:F2C++ Array subscript usage: Replaced
    1214              :         // by  below
    1215            0 :         HrSky = sum(HSkyARR * Area) / AreaSum;
    1216            0 :         HSkyARR.deallocate();
    1217              :         //        HrGround = sum( HGroundARR * Surface( UTSC( UTSCNum ).SurfPtrs ).Area ) / AreaSum; //Autodesk:F2C++ Array subscript usage:
    1218              :         // Replaced by below
    1219            0 :         HrGround = sum(HGroundARR * Area) / AreaSum;
    1220            0 :         HGroundARR.deallocate();
    1221              :         //        HrAtm = sum( HAirARR * Surface( UTSC( UTSCNum ).SurfPtrs ).Area ) / AreaSum; //Autodesk:F2C++ Array subscript usage: Replaced
    1222              :         // by  below
    1223            0 :         HrAtm = sum(HAirARR * Area) / AreaSum;
    1224            0 :         HAirARR.deallocate();
    1225              :         //        HrPlen = sum( HPlenARR * Surface( UTSC( UTSCNum ).SurfPtrs ).Area ) / AreaSum; //Autodesk:F2C++ Array subscript usage:
    1226              :         // Replaced  by below
    1227            0 :         HrPlen = sum(HPlenARR * Area) / AreaSum;
    1228            0 :         HPlenARR.deallocate();
    1229              : 
    1230              :         //        Isc = sum( SurfQRadSWOutIncident( UTSC( UTSCNum ).SurfPtrs ) * Surface( UTSC( UTSCNum ).SurfPtrs ).Area ) / AreaSum;
    1231              :         ////Autodesk:F2C++ Array subscript usage: Replaced by below
    1232            0 :         Isc = sum_product_sub(state.dataHeatBal->SurfQRadSWOutIncident,
    1233            0 :                               state.dataSurface->Surface,
    1234              :                               &SurfaceData::Area,
    1235            0 :                               state.dataTranspiredCollector->UTSC(UTSCNum).SurfPtrs) /
    1236              :               AreaSum; // Autodesk:F2C++ Functions handle array subscript usage
    1237              :         //        Tso = sum( TH( UTSC( UTSCNum ).SurfPtrs, 1, 1 ) * Surface( UTSC( UTSCNum ).SurfPtrs ).Area ) / AreaSum; //Autodesk:F2C++ Array
    1238              :         // subscript usage: Replaced by below
    1239            0 :         Tso = sum_product_sub(state.dataHeatBalSurf->SurfOutsideTempHist(1),
    1240            0 :                               state.dataSurface->Surface,
    1241              :                               &SurfaceData::Area,
    1242            0 :                               state.dataTranspiredCollector->UTSC(UTSCNum).SurfPtrs) /
    1243              :               AreaSum; // Autodesk:F2C++ Functions handle array subscript usage
    1244              : 
    1245            0 :         if (Vwind > 5.0) {
    1246            0 :             HcWind = 5.62 + 3.9 * (Vwind - 5.0); // McAdams forced convection correlation
    1247              :         } else {
    1248            0 :             HcWind = 0.0;
    1249              :         }
    1250              : 
    1251            0 :         if (state.dataEnvrn->IsRain) {
    1252            0 :             HcWind = 1000.0;
    1253              :         }
    1254              : 
    1255            0 :         HXeff = 0.0; // init
    1256              : 
    1257            0 :         switch (state.dataTranspiredCollector->UTSC(UTSCNum).Correlation) {
    1258            0 :         case Correlation_Kutscher1994: { // Kutscher1994
    1259            0 :             AlessHoles = A - holeArea;
    1260              : 
    1261            0 :             NuD = 2.75 * ((std::pow(P / D, -1.2) * std::pow(ReD, 0.43)) + (0.011 * Por * ReD * std::pow(Vwind / Vsuction, 0.48)));
    1262            0 :             U = k * NuD / D;
    1263            0 :             HXeff = 1.0 - std::exp(-1.0 * ((U * AlessHoles) / (Mdot * CpAir)));
    1264            0 :         } break;
    1265            0 :         case Correlation_VanDeckerHollandsBrunger2001: { // VanDeckerHollandsBrunger2001
    1266            0 :             t = state.dataTranspiredCollector->UTSC(UTSCNum).CollectThick;
    1267            0 :             ReS = Vsuction * P / nu;
    1268            0 :             ReW = Vwind * P / nu;
    1269            0 :             ReB = Vholes * P / nu;
    1270            0 :             ReH = (Vsuction * D) / (nu * Por);
    1271            0 :             if (ReD > 0.0) {
    1272            0 :                 if (ReW > 0.0) {
    1273            0 :                     HXeff = (1.0 - std::pow(1.0 + ReS * max(1.733 * std::pow(ReW, -0.5), 0.02136), -1.0)) *
    1274            0 :                             (1.0 - std::pow(1.0 + 0.2273 * std::sqrt(ReB), -1.0)) * std::exp(-0.01895 * (P / D) - (20.62 / ReH) * (t / D));
    1275              :                 } else {
    1276            0 :                     HXeff = (1.0 - std::pow(1.0 + ReS * 0.02136, -1.0)) * (1.0 - std::pow(1.0 + 0.2273 * std::sqrt(ReB), -1.0)) *
    1277            0 :                             std::exp(-0.01895 * (P / D) - (20.62 / ReH) * (t / D));
    1278              :                 }
    1279              :             } else {
    1280            0 :                 HXeff = 0.0;
    1281              :             }
    1282            0 :         } break;
    1283            0 :         default:
    1284            0 :             break;
    1285              :         }
    1286              : 
    1287              :         // now calculate collector temperature
    1288              : 
    1289            0 :         Tscoll = (Isc * SolAbs + HrAtm * Tamb + HrSky * state.dataEnvrn->SkyTemp + HrGround * Tamb + HrPlen * Tso + HcWind * Tamb +
    1290            0 :                   (Mdot * CpAir / A) * Tamb - (Mdot * CpAir / A) * (1.0 - HXeff) * Tamb + QdotSource) /
    1291            0 :                  (HrAtm + HrSky + HrGround + HrPlen + HcWind + (Mdot * CpAir / A) * HXeff);
    1292              : 
    1293              :         // Heat exchanger leaving temperature
    1294            0 :         TaHX = HXeff * Tscoll + (1.0 - HXeff) * Tamb;
    1295              : 
    1296              :         // now calculate plenum air temperature
    1297              : 
    1298            0 :         Taplen = (Mdot * CpAir * TaHX + HcPlen * A * Tso) / (Mdot * CpAir + HcPlen * A);
    1299              : 
    1300              :         // calculate Sensible Heating Rate
    1301            0 :         if (Taplen > Tamb) {
    1302            0 :             SensHeatingRate = Mdot * CpAir * (Taplen - Tamb);
    1303              :         } else {
    1304            0 :             SensHeatingRate = 0.0;
    1305              :         }
    1306              : 
    1307              :         // now fill results into derived types
    1308            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).Isc = Isc;
    1309            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).HXeff = HXeff;
    1310            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).Tplen = Taplen;
    1311            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).Tcoll = Tscoll;
    1312            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).HrPlen = HrPlen;
    1313            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).HcPlen = HcPlen;
    1314            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).TairHX = TaHX;
    1315            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).InletMDot = Mdot;
    1316            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).InletTempDB = Tamb;
    1317            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).Vsuction = Vsuction;
    1318            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).PlenumVelocity = Vplen;
    1319            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).SupOutTemp = Taplen;
    1320            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).SupOutHumRat = state.dataEnvrn->OutHumRat; // stays the same with sensible heating
    1321            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).SupOutEnth =
    1322            0 :             PsyHFnTdbW(state.dataTranspiredCollector->UTSC(UTSCNum).SupOutTemp, state.dataTranspiredCollector->UTSC(UTSCNum).SupOutHumRat);
    1323            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).SupOutMassFlow = Mdot;
    1324            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).SensHeatingRate = SensHeatingRate;
    1325            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).SensHeatingEnergy = SensHeatingRate * TimeStepSysSec;
    1326            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).PassiveACH = 0.0;
    1327            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).PassiveMdotVent = 0.0;
    1328            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).PassiveMdotWind = 0.0;
    1329            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).PassiveMdotTherm = 0.0;
    1330            0 :         if (Isc > 10.0) {
    1331            0 :             state.dataTranspiredCollector->UTSC(UTSCNum).UTSCEfficiency = SensHeatingRate / (Isc * A);
    1332            0 :             if (TaHX > Tamb) {
    1333            0 :                 state.dataTranspiredCollector->UTSC(UTSCNum).UTSCCollEff = Mdot * CpAir * (TaHX - Tamb) / (Isc * A);
    1334              :             } else {
    1335            0 :                 state.dataTranspiredCollector->UTSC(UTSCNum).UTSCCollEff = 0.0;
    1336              :             }
    1337              :         } else {
    1338            0 :             state.dataTranspiredCollector->UTSC(UTSCNum).UTSCEfficiency = 0.0;
    1339            0 :             state.dataTranspiredCollector->UTSC(UTSCNum).UTSCCollEff = 0.0;
    1340              :         }
    1341            0 :     }
    1342              : 
    1343            0 :     void CalcPassiveTranspiredCollector(EnergyPlusData &state, int const UTSCNum)
    1344              :     {
    1345              : 
    1346              :         // SUBROUTINE INFORMATION:
    1347              :         //       AUTHOR         B.T. Griffith
    1348              :         //       DATE WRITTEN   November 2004
    1349              :         //       MODIFIED       na
    1350              :         //       RE-ENGINEERED  na
    1351              : 
    1352              :         // PURPOSE OF THIS SUBROUTINE:
    1353              :         // model the effect of the a ventilated baffle covering the outside of a heat transfer surface.
    1354              : 
    1355              :         // METHODOLOGY EMPLOYED:
    1356              :         // All the work is done in a subroutine .
    1357              : 
    1358              :         // REFERENCES:
    1359              :         // Nat. Vent. equations from ASHRAE HoF 2001 Chapt. 26
    1360              : 
    1361              :         // Using/Aliasing
    1362              :         using DataSurfaces::SurfaceData;
    1363              :         using Psychrometrics::PsyHFnTdbW;
    1364              :         using Psychrometrics::PsyRhoAirFnPbTdbW;
    1365              :         using Psychrometrics::PsyWFnTdbTwbPb;
    1366              : 
    1367              :         // local working variables
    1368              :         Real64 AspRat; // Aspect Ratio of gap
    1369              :         Real64 TmpTscoll;
    1370              :         Real64 TmpTaPlen;
    1371              :         Real64 RhoAir;
    1372              :         Real64 holeArea;
    1373              :         Real64 Tamb;
    1374              :         Real64 HrPlen;
    1375              :         Real64 HcPlen;
    1376              :         Real64 Isc;
    1377              :         Real64 MdotVent;
    1378              :         Real64 VdotWind;
    1379              :         Real64 VdotThermal;
    1380              :         Real64 Twbamb;
    1381              :         Real64 OutHumRatAmb;
    1382              : 
    1383              :         //        Tamb = sum( Surface( UTSC( UTSCNum ).SurfPtrs ).OutDryBulbTemp * Surface( UTSC( UTSCNum ).SurfPtrs ).Area ) / sum( Surface(
    1384              :         // UTSC( UTSCNum ).SurfPtrs ).Area ); //Autodesk:F2C++ Array subscript usage: Replaced by below
    1385            0 :         Real64 sum_area = 0.0;
    1386            0 :         Real64 sum_produc_area_drybulb = 0.0;
    1387            0 :         Real64 sum_produc_area_wetbulb = 0.0;
    1388            0 :         for (int SurfNum : state.dataTranspiredCollector->UTSC(UTSCNum).SurfPtrs) {
    1389            0 :             sum_area += state.dataSurface->Surface(SurfNum).Area;
    1390            0 :             sum_produc_area_wetbulb += state.dataSurface->Surface(SurfNum).Area * state.dataSurface->SurfOutWetBulbTemp(SurfNum);
    1391            0 :             sum_produc_area_drybulb += state.dataSurface->Surface(SurfNum).Area * state.dataSurface->SurfOutDryBulbTemp(SurfNum);
    1392              :         }
    1393            0 :         Tamb = sum_produc_area_drybulb / sum_area;
    1394            0 :         Twbamb = sum_produc_area_wetbulb / sum_area;
    1395              : 
    1396            0 :         OutHumRatAmb = PsyWFnTdbTwbPb(state, Tamb, Twbamb, state.dataEnvrn->OutBaroPress);
    1397              : 
    1398            0 :         RhoAir = PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, Tamb, OutHumRatAmb);
    1399            0 :         holeArea = state.dataTranspiredCollector->UTSC(UTSCNum).ActualArea * state.dataTranspiredCollector->UTSC(UTSCNum).Porosity;
    1400              : 
    1401            0 :         AspRat = state.dataTranspiredCollector->UTSC(UTSCNum).Height / state.dataTranspiredCollector->UTSC(UTSCNum).PlenGapThick;
    1402            0 :         TmpTscoll = state.dataTranspiredCollector->UTSC(UTSCNum).TcollLast;
    1403            0 :         TmpTaPlen = state.dataTranspiredCollector->UTSC(UTSCNum).TplenLast;
    1404              : 
    1405              :         // all the work is done in this routine located in GeneralRoutines.cc
    1406              : 
    1407            0 :         CalcPassiveExteriorBaffleGap(state,
    1408            0 :                                      state.dataTranspiredCollector->UTSC(UTSCNum).SurfPtrs,
    1409              :                                      holeArea,
    1410            0 :                                      state.dataTranspiredCollector->UTSC(UTSCNum).Cv,
    1411            0 :                                      state.dataTranspiredCollector->UTSC(UTSCNum).Cd,
    1412            0 :                                      state.dataTranspiredCollector->UTSC(UTSCNum).HdeltaNPL,
    1413            0 :                                      state.dataTranspiredCollector->UTSC(UTSCNum).SolAbsorp,
    1414            0 :                                      state.dataTranspiredCollector->UTSC(UTSCNum).LWEmitt,
    1415            0 :                                      state.dataTranspiredCollector->UTSC(UTSCNum).Tilt,
    1416              :                                      AspRat,
    1417            0 :                                      state.dataTranspiredCollector->UTSC(UTSCNum).PlenGapThick,
    1418            0 :                                      state.dataTranspiredCollector->UTSC(UTSCNum).CollRoughness,
    1419            0 :                                      state.dataTranspiredCollector->UTSC(UTSCNum).QdotSource,
    1420              :                                      TmpTscoll,
    1421              :                                      TmpTaPlen,
    1422              :                                      HcPlen,
    1423              :                                      HrPlen,
    1424              :                                      Isc,
    1425              :                                      MdotVent,
    1426              :                                      VdotWind,
    1427              :                                      VdotThermal);
    1428              : 
    1429              :         // now fill results into derived types
    1430            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).Isc = Isc;
    1431            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).Tplen = TmpTaPlen;
    1432            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).Tcoll = TmpTscoll;
    1433            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).HrPlen = HrPlen;
    1434            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).HcPlen = HcPlen;
    1435            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).TairHX = Tamb;
    1436            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).InletMDot = 0.0;
    1437            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).InletTempDB = Tamb;
    1438            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).Vsuction = 0.0;
    1439            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).PlenumVelocity = 0.0;
    1440            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).SupOutTemp = TmpTaPlen;
    1441            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).SupOutHumRat = OutHumRatAmb;
    1442            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).SupOutEnth = PsyHFnTdbW(TmpTaPlen, OutHumRatAmb);
    1443            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).SupOutMassFlow = 0.0;
    1444            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).SensHeatingRate = 0.0;
    1445            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).SensHeatingEnergy = 0.0;
    1446            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).PassiveACH =
    1447            0 :             (MdotVent / RhoAir) *
    1448            0 :             (1.0 / (state.dataTranspiredCollector->UTSC(UTSCNum).ProjArea * state.dataTranspiredCollector->UTSC(UTSCNum).PlenGapThick)) *
    1449              :             Constant::rSecsInHour;
    1450            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).PassiveMdotVent = MdotVent;
    1451            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).PassiveMdotWind = VdotWind * RhoAir;
    1452            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).PassiveMdotTherm = VdotThermal * RhoAir;
    1453            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).UTSCEfficiency = 0.0;
    1454            0 :     }
    1455              : 
    1456            0 :     void UpdateTranspiredCollector(EnergyPlusData &state, int const UTSCNum)
    1457              :     {
    1458              : 
    1459              :         // SUBROUTINE INFORMATION:
    1460              :         //       AUTHOR         B.T. Griffith
    1461              :         //       DATE WRITTEN   November 2004
    1462              :         //       MODIFIED       na
    1463              :         //       RE-ENGINEERED  na
    1464              : 
    1465              :         int OutletNode;
    1466              :         int InletNode;
    1467              :         int thisOSCM;
    1468              :         int thisOASys;
    1469              : 
    1470              :         // update "last" values in Derived type
    1471            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).TplenLast = state.dataTranspiredCollector->UTSC(UTSCNum).Tplen;
    1472            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).TcollLast = state.dataTranspiredCollector->UTSC(UTSCNum).Tcoll;
    1473              : 
    1474              :         // Set the outlet air nodes of the UTSC
    1475              : 
    1476            0 :         if (state.dataTranspiredCollector->UTSC(UTSCNum).IsOn) { // Active
    1477            0 :             if (state.dataTranspiredCollector->UTSC(UTSCNum).NumOASysAttached == 1) {
    1478            0 :                 OutletNode = state.dataTranspiredCollector->UTSC(UTSCNum).OutletNode(1);
    1479            0 :                 InletNode = state.dataTranspiredCollector->UTSC(UTSCNum).InletNode(1);
    1480            0 :                 state.dataLoopNodes->Node(OutletNode).MassFlowRate = state.dataTranspiredCollector->UTSC(UTSCNum).SupOutMassFlow;
    1481            0 :                 state.dataLoopNodes->Node(OutletNode).Temp = state.dataTranspiredCollector->UTSC(UTSCNum).SupOutTemp;
    1482            0 :                 state.dataLoopNodes->Node(OutletNode).HumRat = state.dataTranspiredCollector->UTSC(UTSCNum).SupOutHumRat;
    1483            0 :                 state.dataLoopNodes->Node(OutletNode).Enthalpy = state.dataTranspiredCollector->UTSC(UTSCNum).SupOutEnth;
    1484            0 :             } else if (state.dataTranspiredCollector->UTSC(UTSCNum).NumOASysAttached > 1) {
    1485            0 :                 for (thisOASys = 1; thisOASys <= state.dataTranspiredCollector->UTSC(UTSCNum).NumOASysAttached; ++thisOASys) {
    1486            0 :                     state.dataLoopNodes->Node(state.dataTranspiredCollector->UTSC(UTSCNum).OutletNode(thisOASys)).MassFlowRate =
    1487            0 :                         state.dataLoopNodes->Node(state.dataTranspiredCollector->UTSC(UTSCNum).InletNode(thisOASys))
    1488            0 :                             .MassFlowRate; // system gets what it asked for at inlet
    1489            0 :                     state.dataLoopNodes->Node(state.dataTranspiredCollector->UTSC(UTSCNum).OutletNode(thisOASys)).Temp =
    1490            0 :                         state.dataTranspiredCollector->UTSC(UTSCNum).SupOutTemp;
    1491            0 :                     state.dataLoopNodes->Node(state.dataTranspiredCollector->UTSC(UTSCNum).OutletNode(thisOASys)).HumRat =
    1492            0 :                         state.dataTranspiredCollector->UTSC(UTSCNum).SupOutHumRat;
    1493            0 :                     state.dataLoopNodes->Node(state.dataTranspiredCollector->UTSC(UTSCNum).OutletNode(thisOASys)).Enthalpy =
    1494            0 :                         state.dataTranspiredCollector->UTSC(UTSCNum).SupOutEnth;
    1495              :                 }
    1496              :             }
    1497              :         } else { // Passive and/or bypassed           Note Array assignments in following
    1498              :                  // Autodesk:F2C++ Array subscript usage: Replaced by below
    1499              :             //            Node( UTSC( UTSCNum ).OutletNode ).MassFlowRate = Node( UTSC( UTSCNum ).InletNode ).MassFlowRate;
    1500              :             //            Node( UTSC( UTSCNum ).OutletNode ).Temp = Node( UTSC( UTSCNum ).InletNode ).Temp;
    1501              :             //            Node( UTSC( UTSCNum ).OutletNode ).HumRat = Node( UTSC( UTSCNum ).InletNode ).HumRat;
    1502              :             //            Node( UTSC( UTSCNum ).OutletNode ).Enthalpy = Node( UTSC( UTSCNum ).InletNode ).Enthalpy;
    1503            0 :             auto const &OutletNode = state.dataTranspiredCollector->UTSC(UTSCNum).OutletNode;
    1504            0 :             auto const &InletNode = state.dataTranspiredCollector->UTSC(UTSCNum).InletNode;
    1505            0 :             assert(OutletNode.size() == InletNode.size());
    1506            0 :             for (int io = OutletNode.l(), ii = InletNode.l(), eo = OutletNode.u(); io <= eo; ++io, ++ii) {
    1507            0 :                 auto &outNode = state.dataLoopNodes->Node(OutletNode(io));
    1508            0 :                 auto const &inNode = state.dataLoopNodes->Node(InletNode(ii));
    1509            0 :                 outNode.MassFlowRate = inNode.MassFlowRate;
    1510            0 :                 outNode.Temp = inNode.Temp;
    1511            0 :                 outNode.HumRat = inNode.HumRat;
    1512            0 :                 outNode.Enthalpy = inNode.Enthalpy;
    1513              :             }
    1514              :         }
    1515              : 
    1516              :         // update the OtherSideConditionsModel coefficients.
    1517            0 :         thisOSCM = state.dataTranspiredCollector->UTSC(UTSCNum).OSCMPtr;
    1518              : 
    1519            0 :         state.dataSurface->OSCM(thisOSCM).TConv = state.dataTranspiredCollector->UTSC(UTSCNum).Tplen;
    1520            0 :         state.dataSurface->OSCM(thisOSCM).HConv = state.dataTranspiredCollector->UTSC(UTSCNum).HcPlen;
    1521            0 :         state.dataSurface->OSCM(thisOSCM).TRad = state.dataTranspiredCollector->UTSC(UTSCNum).Tcoll;
    1522            0 :         state.dataSurface->OSCM(thisOSCM).HRad = state.dataTranspiredCollector->UTSC(UTSCNum).HrPlen;
    1523            0 :     }
    1524              : 
    1525            0 :     void SetUTSCQdotSource(EnergyPlusData &state,
    1526              :                            int const UTSCNum,
    1527              :                            Real64 const QSource // source term in Watts
    1528              :     )
    1529              :     {
    1530              : 
    1531              :         // SUBROUTINE INFORMATION:
    1532              :         //       AUTHOR         B. Griffith
    1533              :         //       DATE WRITTEN   November 2004
    1534              :         //       MODIFIED       na
    1535              :         //       RE-ENGINEERED  na
    1536              : 
    1537              :         // PURPOSE OF THIS SUBROUTINE:
    1538              :         // object oriented "Set" routine for updating sink term without exposing variables
    1539              : 
    1540              :         // METHODOLOGY EMPLOYED:
    1541              :         // update derived type with new data , turn power into W/m2
    1542              : 
    1543            0 :         state.dataTranspiredCollector->UTSC(UTSCNum).QdotSource = QSource / state.dataTranspiredCollector->UTSC(UTSCNum).ProjArea;
    1544            0 :     }
    1545              : 
    1546            0 :     void GetTranspiredCollectorIndex(EnergyPlusData &state, int const SurfacePtr, int &UTSCIndex)
    1547              :     {
    1548              : 
    1549              :         // SUBROUTINE INFORMATION:
    1550              :         //       AUTHOR         B. Griffith
    1551              :         //       DATE WRITTEN   November 2004
    1552              :         //       MODIFIED       na
    1553              :         //       RE-ENGINEERED  na
    1554              : 
    1555              :         // PURPOSE OF THIS SUBROUTINE:
    1556              :         // object oriented "Get" routine for establishing correct integer index from outside this module
    1557              : 
    1558              :         // METHODOLOGY EMPLOYED:
    1559              :         // mine Surface derived type for correct index/number of surface
    1560              :         // mine UTSC derived type that has the surface.
    1561              : 
    1562              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1563              :         int UTSCNum;  // temporary
    1564              :         int ThisSurf; // temporary
    1565              :         int thisUTSC;
    1566              :         bool Found;
    1567              : 
    1568            0 :         if (state.dataTranspiredCollector->GetInputFlag) {
    1569            0 :             GetTranspiredCollectorInput(state);
    1570            0 :             state.dataTranspiredCollector->GetInputFlag = false;
    1571              :         }
    1572              : 
    1573            0 :         if (SurfacePtr == 0) {
    1574            0 :             ShowFatalError(
    1575              :                 state,
    1576            0 :                 format("Invalid surface passed to GetTranspiredCollectorIndex, Surface name = {}", state.dataSurface->Surface(SurfacePtr).Name));
    1577              :         }
    1578              : 
    1579            0 :         UTSCNum = 0;
    1580            0 :         Found = false;
    1581            0 :         for (thisUTSC = 1; thisUTSC <= state.dataTranspiredCollector->NumUTSC; ++thisUTSC) {
    1582            0 :             for (ThisSurf = 1; ThisSurf <= state.dataTranspiredCollector->UTSC(thisUTSC).NumSurfs; ++ThisSurf) {
    1583            0 :                 if (SurfacePtr == state.dataTranspiredCollector->UTSC(thisUTSC).SurfPtrs(ThisSurf)) {
    1584            0 :                     Found = true;
    1585            0 :                     UTSCNum = thisUTSC;
    1586              :                 }
    1587              :             }
    1588              :         }
    1589              : 
    1590            0 :         if (!Found) {
    1591            0 :             ShowFatalError(state,
    1592            0 :                            format("Did not find surface in UTSC description in GetTranspiredCollectorIndex, Surface name = {}",
    1593            0 :                                   state.dataSurface->Surface(SurfacePtr).Name));
    1594              :         } else {
    1595              : 
    1596            0 :             UTSCIndex = UTSCNum;
    1597              :         }
    1598            0 :     }
    1599              : 
    1600            0 :     void GetUTSCTsColl(EnergyPlusData &state, int const UTSCNum, Real64 &TsColl)
    1601              :     {
    1602              : 
    1603              :         // SUBROUTINE INFORMATION:
    1604              :         //       AUTHOR         <author>
    1605              :         //       DATE WRITTEN   <date_written>
    1606              :         //       MODIFIED       na
    1607              :         //       RE-ENGINEERED  na
    1608              : 
    1609              :         // PURPOSE OF THIS SUBROUTINE:
    1610              :         // object oriented "Get" routine for collector surface temperature
    1611              : 
    1612              :         // METHODOLOGY EMPLOYED:
    1613              :         // access derived type
    1614              : 
    1615            0 :         TsColl = state.dataTranspiredCollector->UTSC(UTSCNum).Tcoll;
    1616            0 :     }
    1617              : 
    1618            0 :     int GetAirInletNodeNum(EnergyPlusData &state, std::string const &UTSCName, bool &ErrorsFound)
    1619              :     {
    1620              :         // FUNCTION INFORMATION:
    1621              :         //       AUTHOR         Lixing Gu
    1622              :         //       DATE WRITTEN   May 2019
    1623              :         //       MODIFIED       na
    1624              :         //       RE-ENGINEERED  na
    1625              : 
    1626              :         // PURPOSE OF THIS FUNCTION:
    1627              :         // This function looks up the given UTSC and returns the air inlet node number.
    1628              :         // If incorrect UTSC name is given, ErrorsFound is returned as true and node number as zero.
    1629              : 
    1630              :         // Return value
    1631              :         int NodeNum; // node number returned
    1632              : 
    1633              :         // FUNCTION LOCAL VARIABLE DECLARATIONS:
    1634              :         int WhichUTSC;
    1635              : 
    1636            0 :         if (state.dataTranspiredCollector->GetInputFlag) {
    1637            0 :             GetTranspiredCollectorInput(state);
    1638            0 :             state.dataTranspiredCollector->GetInputFlag = false;
    1639              :         }
    1640              : 
    1641            0 :         WhichUTSC = Util::FindItemInList(UTSCName, state.dataTranspiredCollector->UTSC);
    1642            0 :         if (WhichUTSC != 0) {
    1643            0 :             NodeNum = state.dataTranspiredCollector->UTSC(WhichUTSC).InletNode(1);
    1644              :         } else {
    1645            0 :             ShowSevereError(state, format("GetAirInletNodeNum: Could not find TranspiredCollector = \"{}\"", UTSCName));
    1646            0 :             ErrorsFound = true;
    1647            0 :             NodeNum = 0;
    1648              :         }
    1649              : 
    1650            0 :         return NodeNum;
    1651              :     }
    1652              : 
    1653            0 :     int GetAirOutletNodeNum(EnergyPlusData &state, std::string const &UTSCName, bool &ErrorsFound)
    1654              :     {
    1655              :         // FUNCTION INFORMATION:
    1656              :         //       AUTHOR         Lixing Gu
    1657              :         //       DATE WRITTEN   May 2019
    1658              :         //       MODIFIED       na
    1659              :         //       RE-ENGINEERED  na
    1660              : 
    1661              :         // PURPOSE OF THIS FUNCTION:
    1662              :         // This function looks up the given UTSC and returns the air outlet node number.
    1663              :         // If incorrect UTSC name is given, ErrorsFound is returned as true and node number as zero.
    1664              : 
    1665              :         // Return value
    1666              :         int NodeNum; // node number returned
    1667              : 
    1668              :         // FUNCTION LOCAL VARIABLE DECLARATIONS:
    1669              :         int WhichUTSC;
    1670              : 
    1671            0 :         if (state.dataTranspiredCollector->GetInputFlag) {
    1672            0 :             GetTranspiredCollectorInput(state);
    1673            0 :             state.dataTranspiredCollector->GetInputFlag = false;
    1674              :         }
    1675              : 
    1676            0 :         WhichUTSC = Util::FindItemInList(UTSCName, state.dataTranspiredCollector->UTSC);
    1677            0 :         if (WhichUTSC != 0) {
    1678            0 :             NodeNum = state.dataTranspiredCollector->UTSC(WhichUTSC).OutletNode(1);
    1679              :         } else {
    1680            0 :             ShowSevereError(state, format("GetAirOutletNodeNum: Could not find TranspiredCollector = \"{}\"", UTSCName));
    1681            0 :             ErrorsFound = true;
    1682            0 :             NodeNum = 0;
    1683              :         }
    1684              : 
    1685            0 :         return NodeNum;
    1686              :     }
    1687              : 
    1688            1 :     void CalcPassiveExteriorBaffleGap(EnergyPlusData &state,
    1689              :                                       const Array1D_int &SurfPtrARR, // Array of indexes pointing to Surface structure in DataSurfaces
    1690              :                                       Real64 const VentArea,         // Area available for venting the gap [m2]
    1691              :                                       Real64 const Cv,               // Orifice coefficient for volume-based discharge, wind-driven [--]
    1692              :                                       Real64 const Cd,               // Orifice coefficient for discharge,  buoyancy-driven [--]
    1693              :                                       Real64 const HdeltaNPL,        // Height difference from neutral pressure level [m]
    1694              :                                       Real64 const SolAbs,           // solar absorptivity of baffle [--]
    1695              :                                       Real64 const AbsExt,           // thermal absorptance/emittance of baffle material [--]
    1696              :                                       Real64 const Tilt,             // Tilt of gap [Degrees]
    1697              :                                       Real64 const AspRat,           // aspect ratio of gap  Height/gap [--]
    1698              :                                       Real64 const GapThick,         // Thickness of air space between baffle and underlying heat transfer surface
    1699              :                                       Material::SurfaceRoughness const Roughness, // Roughness index (1-6), see DataHeatBalance parameters
    1700              :                                       Real64 const QdotSource,                    // Source/sink term, e.g. electricity exported from solar cell [W]
    1701              :                                       Real64 &TsBaffle,                           // Temperature of baffle (both sides) use lagged value on input [C]
    1702              :                                       Real64 &TaGap, // Temperature of air gap (assumed mixed) use lagged value on input [C]
    1703              :                                       ObjexxFCL::Optional<Real64> HcGapRpt,
    1704              :                                       ObjexxFCL::Optional<Real64> HrGapRpt,
    1705              :                                       ObjexxFCL::Optional<Real64> IscRpt,
    1706              :                                       ObjexxFCL::Optional<Real64> MdotVentRpt,
    1707              :                                       ObjexxFCL::Optional<Real64> VdotWindRpt,
    1708              :                                       ObjexxFCL::Optional<Real64> VdotBuoyRpt)
    1709              :     {
    1710              : 
    1711              :         // SUBROUTINE INFORMATION:
    1712              :         //       AUTHOR         B.T. Griffith
    1713              :         //       DATE WRITTEN   November 2004
    1714              :         //       MODIFIED       BG March 2007 outdoor conditions from surface for height-dependent conditions
    1715              : 
    1716              :         // PURPOSE OF THIS SUBROUTINE:
    1717              :         // model the effect of the a ventilated baffle covering the outside of a heat transfer surface.
    1718              :         // return calculated temperatures and certain intermediate values for reporting
    1719              : 
    1720              :         // METHODOLOGY EMPLOYED:
    1721              :         // Heat balances on baffle and air space.
    1722              :         // Natural ventilation calculations use buoyancy and wind.
    1723              : 
    1724              :         // REFERENCES:
    1725              :         // Nat. Vent. equations from ASHRAE HoF 2001 Chapt. 26
    1726              : 
    1727              :         // SUBROUTINE PARAMETER DEFINITIONS:
    1728            1 :         Real64 constexpr g = 9.807;          // gravitational constant (m/s**2)
    1729            1 :         Real64 constexpr nu = 15.66e-6;      // kinematic viscosity (m**2/s) for air at 300 K (Mills 1999 Heat Transfer)
    1730            1 :         Real64 constexpr k = 0.0267;         // thermal conductivity (W/m K) for air at 300 K (Mills 1999 Heat Transfer)
    1731            1 :         Real64 constexpr Sigma = 5.6697e-08; // Stefan-Boltzmann constant
    1732              :         static constexpr std::string_view RoutineName = "CalcPassiveExteriorBaffleGap";
    1733              :         // INTERFACE BLOCK SPECIFICATIONS:
    1734              : 
    1735              :         // DERIVED TYPE DEFINITIONS:
    1736              : 
    1737              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1738              : 
    1739              :         // following arrays are used to temporarily hold results from multiple underlying surfaces
    1740            1 :         Array1D<Real64> HSkyARR;
    1741            1 :         Array1D<Real64> HGroundARR;
    1742            1 :         Array1D<Real64> HAirARR;
    1743            1 :         Array1D<Real64> HPlenARR;
    1744            1 :         Array1D<Real64> HExtARR;
    1745            1 :         Array1D<Real64> LocalWindArr;
    1746            1 :         Array1D<Real64> HSrdSurfARR;
    1747              : 
    1748              :         // local working variables
    1749              :         Real64 Tamb;                  // outdoor drybulb
    1750              :         Real64 VdotThermal;           // Volume flow rate of nat. vent due to buoyancy
    1751              :         Real64 LocalOutDryBulbTemp;   // OutDryBulbTemp for here
    1752              :         Real64 LocalWetBulbTemp;      // OutWetBulbTemp for here
    1753              :         Real64 LocalOutHumRat;        // OutHumRat for here
    1754            1 :         bool ICSCollectorIsOn(false); // ICS collector has OSCM on
    1755              :         int CollectorNum;             // current solar collector index
    1756              :         Real64 ICSWaterTemp;          // ICS solar collector water temp
    1757              :         Real64 ICSULossbottom;        // ICS solar collector bottom loss Conductance
    1758            1 :         Real64 sum_area = 0.0;
    1759            1 :         Real64 sum_produc_area_drybulb = 0.0;
    1760            1 :         Real64 sum_produc_area_wetbulb = 0.0;
    1761              : 
    1762            1 :         auto &s_mat = state.dataMaterial;
    1763              : 
    1764            2 :         for (int SurfNum : SurfPtrARR) {
    1765            1 :             sum_area += state.dataSurface->Surface(SurfNum).Area;
    1766            1 :             sum_produc_area_drybulb += state.dataSurface->Surface(SurfNum).Area * state.dataSurface->SurfOutDryBulbTemp(SurfNum);
    1767            1 :             sum_produc_area_wetbulb += state.dataSurface->Surface(SurfNum).Area * state.dataSurface->SurfOutWetBulbTemp(SurfNum);
    1768              :         }
    1769              :         //    LocalOutDryBulbTemp = sum( Surface( SurfPtrARR ).Area * Surface( SurfPtrARR ).OutDryBulbTemp ) / sum( Surface( SurfPtrARR ).Area );
    1770            1 :         LocalOutDryBulbTemp = sum_produc_area_drybulb / sum_area; // Autodesk:F2C++ Functions handle array subscript usage
    1771              :         //    LocalWetBulbTemp = sum( Surface( SurfPtrARR ).Area * Surface( SurfPtrARR ).OutWetBulbTemp ) / sum( Surface( SurfPtrARR ).Area );
    1772            1 :         LocalWetBulbTemp = sum_produc_area_wetbulb / sum_area;
    1773              : 
    1774            1 :         LocalOutHumRat = Psychrometrics::PsyWFnTdbTwbPb(state, LocalOutDryBulbTemp, LocalWetBulbTemp, state.dataEnvrn->OutBaroPress, RoutineName);
    1775              : 
    1776            1 :         Real64 RhoAir = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, LocalOutDryBulbTemp, LocalOutHumRat, RoutineName);
    1777            1 :         Real64 CpAir = Psychrometrics::PsyCpAirFnW(LocalOutHumRat);
    1778            1 :         if (!state.dataEnvrn->IsRain) {
    1779            1 :             Tamb = LocalOutDryBulbTemp;
    1780              :         } else { // when raining we use wetbulb not drybulb
    1781            0 :             Tamb = LocalWetBulbTemp;
    1782              :         }
    1783            1 :         Real64 A = sum_area;        // projected area of baffle from sum of underlying surfaces
    1784            1 :         Real64 TmpTsBaf = TsBaffle; // baffle temperature
    1785              : 
    1786              :         // loop through underlying surfaces and collect needed data
    1787            1 :         int NumSurfs = size(SurfPtrARR); // number of underlying HT surfaces associated with UTSC
    1788            1 :         HSkyARR.dimension(NumSurfs, 0.0);
    1789            1 :         HGroundARR.dimension(NumSurfs, 0.0);
    1790            1 :         HAirARR.dimension(NumSurfs, 0.0);
    1791            1 :         LocalWindArr.dimension(NumSurfs, 0.0);
    1792            1 :         HPlenARR.dimension(NumSurfs, 0.0);
    1793            1 :         HExtARR.dimension(NumSurfs, 0.0);
    1794            1 :         HSrdSurfARR.dimension(NumSurfs, 0.0);
    1795              : 
    1796            2 :         for (int ThisSurf = 1; ThisSurf <= NumSurfs; ++ThisSurf) {
    1797            1 :             int SurfPtr = SurfPtrARR(ThisSurf);
    1798              :             // Initializations for this surface
    1799            1 :             Real64 HMovInsul = 0.0;
    1800            1 :             LocalWindArr(ThisSurf) = state.dataSurface->SurfOutWindSpeed(SurfPtr);
    1801            1 :             Convect::InitExtConvCoeff(state,
    1802              :                                       SurfPtr,
    1803              :                                       HMovInsul,
    1804              :                                       Roughness,
    1805              :                                       AbsExt,
    1806              :                                       TmpTsBaf,
    1807            1 :                                       HExtARR(ThisSurf),
    1808            1 :                                       HSkyARR(ThisSurf),
    1809            1 :                                       HGroundARR(ThisSurf),
    1810            1 :                                       HAirARR(ThisSurf),
    1811            1 :                                       HSrdSurfARR(ThisSurf));
    1812            1 :             int ConstrNum = state.dataSurface->Surface(SurfPtr).Construction;
    1813            1 :             Real64 AbsThermSurf = s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(1))->AbsorpThermal;
    1814            1 :             Real64 TsoK = state.dataHeatBalSurf->SurfOutsideTempHist(1)(SurfPtr) + Constant::Kelvin;
    1815            1 :             Real64 TsBaffK = TmpTsBaf + Constant::Kelvin;
    1816            1 :             if (TsBaffK == TsoK) {        // avoid divide by zero
    1817            0 :                 HPlenARR(ThisSurf) = 0.0; // no net heat transfer if same temperature
    1818              :             } else {
    1819            1 :                 HPlenARR(ThisSurf) = Sigma * AbsExt * AbsThermSurf * (pow_4(TsBaffK) - pow_4(TsoK)) / (TsBaffK - TsoK);
    1820              :             }
    1821              :             // Added for ICS collector OSCM
    1822            1 :             if (state.dataSurface->SurfIsICS(SurfPtr)) {
    1823            1 :                 ICSCollectorIsOn = true;
    1824            1 :                 CollectorNum = state.dataSurface->SurfICSPtr(SurfPtr);
    1825              :             }
    1826              :         }
    1827              : 
    1828            1 :         if (ICSCollectorIsOn) {
    1829            1 :             if (state.dataGlobal->BeginEnvrnFlag && state.dataGeneralRoutines->MyICSEnvrnFlag) {
    1830            1 :                 ICSULossbottom = 0.40;
    1831            1 :                 ICSWaterTemp = 20.0;
    1832              :             } else {
    1833            0 :                 if (!state.dataSolarCollectors->Collector.allocated()) {
    1834            0 :                     ICSULossbottom = 0.40;
    1835            0 :                     ICSWaterTemp = 20.0;
    1836              :                 } else {
    1837            0 :                     ICSULossbottom = state.dataSolarCollectors->Collector(CollectorNum).UbLoss;
    1838            0 :                     ICSWaterTemp = state.dataSolarCollectors->Collector(CollectorNum).TempOfWater;
    1839            0 :                     state.dataGeneralRoutines->MyICSEnvrnFlag = false;
    1840              :                 }
    1841              :             }
    1842              :         }
    1843            1 :         if (!state.dataGlobal->BeginEnvrnFlag) {
    1844            0 :             state.dataGeneralRoutines->MyICSEnvrnFlag = true;
    1845              :         }
    1846              :         if (A == 0.0) { // should have been caught earlier
    1847              :         }
    1848              :         Array1D<Real64> Area(
    1849            1 :             array_sub(state.dataSurface->Surface,
    1850              :                       &DataSurfaces::SurfaceData::Area,
    1851            1 :                       SurfPtrARR)); // Autodesk:F2C++ Copy of subscripted Area array for use below: This makes a copy so review wrt performance
    1852              :         // now figure area-weighted averages from underlying surfaces.
    1853            1 :         Real64 Vwind = sum(LocalWindArr * Area) / A; // area weighted average of wind velocity
    1854            1 :         LocalWindArr.deallocate();
    1855            1 :         Real64 HrSky = sum(HSkyARR * Area) / A; // radiation coeff for sky, area-weighted average
    1856            1 :         HSkyARR.deallocate();
    1857            1 :         Real64 HrGround = sum(HGroundARR * Area) / A; // radiation coeff for ground, area-weighted average
    1858            1 :         HGroundARR.deallocate();
    1859            1 :         Real64 HrAtm = sum(HAirARR * Area) / A; // radiation coeff for air (bulk atmosphere), area-weighted average
    1860            1 :         HAirARR.deallocate();
    1861            1 :         Real64 HrPlen = sum(HPlenARR * Area) / A; // radiation coeff for plenum surfaces, area-weighted average
    1862            1 :         HPlenARR.deallocate();
    1863            1 :         Real64 HExt = sum(HExtARR * Area) / A; // dummy for call to InitExteriorConvectionCoeff
    1864            1 :         HExtARR.deallocate();
    1865            1 :         HSrdSurfARR.deallocate();
    1866              : 
    1867            1 :         if (state.dataEnvrn->IsRain) {
    1868            0 :             HExt = 1000.0;
    1869              :         }
    1870              : 
    1871              :         // temperature of underlying surface, area-weighted average
    1872              :         Real64 Tso =
    1873            1 :             sum_product_sub(state.dataHeatBalSurf->SurfOutsideTempHist(1), state.dataSurface->Surface, &DataSurfaces::SurfaceData::Area, SurfPtrARR) /
    1874            1 :             A;
    1875              :         // Incoming combined solar radiation, area-weighted average
    1876              :         Real64 Isc =
    1877            1 :             sum_product_sub(state.dataHeatBal->SurfQRadSWOutIncident, state.dataSurface->Surface, &DataSurfaces::SurfaceData::Area, SurfPtrARR) / A;
    1878              :         // average of surface temps , for Beta in Grashoff no.
    1879            1 :         Real64 TmeanK = 0.5 * (TmpTsBaf + Tso) + Constant::Kelvin;
    1880              :         // Grasshof number for natural convection calc
    1881            1 :         Real64 Gr = g * pow_3(GapThick) * std::abs(Tso - TmpTsBaf) * pow_2(RhoAir) / (TmeanK * pow_2(nu));
    1882              : 
    1883            1 :         Real64 NuPlen = PassiveGapNusseltNumber(AspRat, Tilt, TmpTsBaf, Tso, Gr); // intentionally switch Tso to Tsi
    1884            1 :         Real64 HcPlen = NuPlen * (k / GapThick);                                  // surface convection heat transfer coefficient for plenum surfaces
    1885              : 
    1886              :         // now model natural ventilation of plenum gap.
    1887            1 :         Real64 VdotWind = Cv * (VentArea / 2.0) * Vwind; // volume flow rate of nat. vent due to wind
    1888              : 
    1889            1 :         if (TaGap > Tamb) {
    1890            1 :             VdotThermal = Cd * (VentArea / 2.0) * std::sqrt(2.0 * g * HdeltaNPL * (TaGap - Tamb) / (TaGap + Constant::Kelvin));
    1891            0 :         } else if (TaGap == Tamb) {
    1892            0 :             VdotThermal = 0.0;
    1893              :         } else {
    1894            0 :             if ((std::abs(Tilt) < 5.0) || (std::abs(Tilt - 180.0) < 5.0)) {
    1895            0 :                 VdotThermal = 0.0; // stable buoyancy situation
    1896              :             } else {
    1897            0 :                 VdotThermal = Cd * (VentArea / 2.0) * std::sqrt(2.0 * g * HdeltaNPL * (Tamb - TaGap) / (Tamb + Constant::Kelvin));
    1898              :             }
    1899              :         }
    1900              : 
    1901            1 :         Real64 VdotVent = VdotWind + VdotThermal; // total volume flow rate of nat vent
    1902            1 :         Real64 MdotVent = VdotVent * RhoAir;      // total mass flow rate of nat vent
    1903              : 
    1904              :         // now calculate baffle temperature
    1905            1 :         if (!ICSCollectorIsOn) {
    1906            0 :             TsBaffle = (Isc * SolAbs + HExt * Tamb + HrAtm * Tamb + HrSky * state.dataEnvrn->SkyTemp + HrGround * Tamb + HrPlen * Tso +
    1907            0 :                         HcPlen * TaGap + QdotSource) /
    1908            0 :                        (HExt + HrAtm + HrSky + HrGround + HrPlen + HcPlen);
    1909              :         } else {
    1910              : 
    1911            1 :             TsBaffle = (ICSULossbottom * ICSWaterTemp + HrPlen * Tso + HcPlen * TaGap + QdotSource) / (ICSULossbottom + HrPlen + HcPlen);
    1912              :         }
    1913              :         // now calculate gap air temperature
    1914              : 
    1915            1 :         TaGap = (HcPlen * A * Tso + MdotVent * CpAir * Tamb + HcPlen * A * TsBaffle) / (HcPlen * A + MdotVent * CpAir + HcPlen * A);
    1916              : 
    1917            1 :         if (present(HcGapRpt)) {
    1918            1 :             HcGapRpt = HcPlen;
    1919              :         }
    1920            1 :         if (present(HrGapRpt)) {
    1921            1 :             HrGapRpt = HrPlen;
    1922              :         }
    1923            1 :         if (present(IscRpt)) {
    1924            1 :             IscRpt = Isc;
    1925              :         }
    1926            1 :         if (present(MdotVentRpt)) {
    1927            1 :             MdotVentRpt = MdotVent;
    1928              :         }
    1929            1 :         if (present(VdotWindRpt)) {
    1930            1 :             VdotWindRpt = VdotWind;
    1931              :         }
    1932            1 :         if (present(VdotBuoyRpt)) {
    1933            1 :             VdotBuoyRpt = VdotThermal;
    1934              :         }
    1935            1 :     }
    1936              : 
    1937              :     //****************************************************************************
    1938              : 
    1939            1 :     Real64 PassiveGapNusseltNumber(Real64 const AspRat, // Aspect Ratio of Gap height to gap width
    1940              :                                    Real64 const Tilt,   // Tilt of gap, degrees
    1941              :                                    Real64 const Tso,    // Temperature of gap surface closest to outside (K)
    1942              :                                    Real64 const Tsi,    // Temperature of gap surface closest to zone (K)
    1943              :                                    Real64 const Gr      // Gap gas Grashof number
    1944              :     )
    1945              :     {
    1946              : 
    1947              :         // SUBROUTINE INFORMATION:
    1948              :         //       AUTHOR         Adapted by B. Griffith from Fred Winkelmann's from NusseltNumber in WindowManager.cc
    1949              :         //       DATE WRITTEN   September 2001
    1950              :         //       MODIFIED       B. Griffith November 2004  (same models but slightly different for general use)
    1951              : 
    1952              :         // PURPOSE OF THIS SUBROUTINE:
    1953              :         // Finds the Nusselt number for air-filled gaps between isothermal solid layers.
    1954              : 
    1955              :         // METHODOLOGY EMPLOYED:
    1956              :         // Based on methodology in Chapter 5 of the July 18, 2001 draft of ISO 15099,
    1957              :         // "Thermal Performance of Windows, Doors and Shading Devices--Detailed Calculations."
    1958              :         // The equation numbers below correspond to those in the standard.
    1959              : 
    1960              :         // REFERENCES:
    1961              :         // Window5 source code; ISO 15099
    1962              : 
    1963              :         // SUBROUTINE PARAMETER DEFINITIONS:
    1964            1 :         Real64 constexpr Pr(0.71); // Prandtl number for air
    1965              : 
    1966              :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS
    1967              :         Real64 gnu901; // Nusselt number temporary variables for
    1968              : 
    1969            1 :         Real64 tiltr = Tilt * Constant::DegToRad;
    1970            1 :         Real64 Ra = Gr * Pr; // Rayleigh number
    1971              : 
    1972            1 :         if (Ra <= 1.0e4) {
    1973            0 :             gnu901 = 1.0 + 1.7596678e-10 * std::pow(Ra, 2.2984755); // eq. 51
    1974              :         }
    1975            1 :         if (Ra > 1.0e4 && Ra <= 5.0e4) {
    1976            1 :             gnu901 = 0.028154 * std::pow(Ra, 0.4134); // eq. 50
    1977              :         }
    1978            1 :         if (Ra > 5.0e4) {
    1979            0 :             gnu901 = 0.0673838 * std::pow(Ra, 1.0 / 3.0); // eq. 49
    1980              :         }
    1981              : 
    1982            1 :         Real64 gnu902 = 0.242 * std::pow(Ra / AspRat, 0.272); // eq. 52
    1983            1 :         Real64 gnu90 = max(gnu901, gnu902);
    1984              : 
    1985            1 :         if (Tso > Tsi) {                                  // window heated from above
    1986            0 :             return 1.0 + (gnu90 - 1.0) * std::sin(tiltr); // eq. 53
    1987            1 :         } else if (Tilt >= 60.0) {
    1988            0 :             Real64 g = 0.5 * std::pow(1.0 + std::pow(Ra / 3160.0, 20.6), -0.1);     // eq. 47
    1989            0 :             Real64 gnu601a = 1.0 + pow_7(0.0936 * std::pow(Ra, 0.314) / (1.0 + g)); // eq. 45
    1990            0 :             Real64 gnu601 = std::pow(gnu601a, 0.142857);
    1991              : 
    1992              :             // For any aspect ratio
    1993            0 :             Real64 gnu602 = (0.104 + 0.175 / AspRat) * std::pow(Ra, 0.283); // eq. 46
    1994            0 :             Real64 gnu60 = max(gnu601, gnu602);
    1995              : 
    1996              :             // linear interpolation for layers inclined at angles between 60 and 90 deg
    1997            0 :             return ((90.0 - Tilt) * gnu60 + (Tilt - 60.0) * gnu90) / 30.0;
    1998              :         } else { // eq. 42
    1999            1 :             Real64 cra = Ra * std::cos(tiltr);
    2000            1 :             Real64 a = 1.0 - 1708.0 / cra;
    2001            1 :             Real64 b = std::pow(cra / 5830.0, 0.33333) - 1.0;
    2002            1 :             Real64 gnua = (std::abs(a) + a) / 2.0;
    2003            1 :             Real64 gnub = (std::abs(b) + b) / 2.0;
    2004            1 :             Real64 ang = 1708.0 * std::pow(std::sin(1.8 * tiltr), 1.6);
    2005            1 :             return 1.0 + 1.44 * gnua * (1.0 - ang / cra) + gnub;
    2006              :         }
    2007              :     }
    2008              : 
    2009              : } // namespace TranspiredCollector
    2010              : 
    2011              : } // namespace EnergyPlus
        

Generated by: LCOV version 2.0-1