LCOV - code coverage report
Current view: top level - EnergyPlus - WindowEquivalentLayer.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 1472 3329 44.2 %
Date: 2024-08-24 18:31:18 Functions: 59 99 59.6 %

          Line data    Source code
       1             : // EnergyPlus, Copyright (c) 1996-2024, The Board of Trustees of the University of Illinois,
       2             : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3             : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4             : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5             : // contributors. All rights reserved.
       6             : //
       7             : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8             : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9             : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10             : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11             : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12             : //
      13             : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14             : // provided that the following conditions are met:
      15             : //
      16             : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17             : //     conditions and the following disclaimer.
      18             : //
      19             : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20             : //     conditions and the following disclaimer in the documentation and/or other materials
      21             : //     provided with the distribution.
      22             : //
      23             : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24             : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25             : //     used to endorse or promote products derived from this software without specific prior
      26             : //     written permission.
      27             : //
      28             : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29             : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30             : //     reference solely to the software portion of its product, Licensee must refer to the
      31             : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32             : //     obtained under this License and may not use a different name for the software. Except as
      33             : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34             : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35             : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36             : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37             : //
      38             : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39             : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40             : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41             : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42             : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43             : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44             : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45             : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46             : // POSSIBILITY OF SUCH DAMAGE.
      47             : 
      48             : // C++ Headers
      49             : #include <cmath>
      50             : 
      51             : // ObjexxFCL Headers
      52             : #include <ObjexxFCL/Array.functions.hh>
      53             : #include <ObjexxFCL/Fmath.hh>
      54             : 
      55             : // EnergyPlus Headers
      56             : #include <EnergyPlus/Construction.hh>
      57             : #include <EnergyPlus/Data/EnergyPlusData.hh>
      58             : #include <EnergyPlus/DataBSDFWindow.hh>
      59             : #include <EnergyPlus/DataEnvironment.hh>
      60             : #include <EnergyPlus/DataHeatBalSurface.hh>
      61             : #include <EnergyPlus/DataHeatBalance.hh>
      62             : #include <EnergyPlus/DataLoopNode.hh>
      63             : #include <EnergyPlus/DataSurfaces.hh>
      64             : #include <EnergyPlus/DataViewFactorInformation.hh>
      65             : #include <EnergyPlus/DataWindowEquivalentLayer.hh>
      66             : #include <EnergyPlus/DataZoneEquipment.hh>
      67             : #include <EnergyPlus/DaylightingManager.hh>
      68             : #include <EnergyPlus/General.hh>
      69             : #include <EnergyPlus/HeatBalanceSurfaceManager.hh>
      70             : #include <EnergyPlus/Material.hh>
      71             : #include <EnergyPlus/Psychrometrics.hh>
      72             : #include <EnergyPlus/ScheduleManager.hh>
      73             : #include <EnergyPlus/UtilityRoutines.hh>
      74             : #include <EnergyPlus/WindowEquivalentLayer.hh>
      75             : 
      76             : namespace EnergyPlus::WindowEquivalentLayer {
      77             : 
      78             : // MODULE INFORMATION
      79             : //       AUTHOR         Bereket A. Nigusse, FSEC/UCF
      80             : //       DATE WRITTEN   May 2013
      81             : //       MODIFIED       na
      82             : //       RE-ENGINEERED  na
      83             : 
      84             : // PURPOSE OF THIS MODULE:
      85             : //  Manages the equivalent layer (ASHWAT) window model optical and thermal
      86             : //  calculations
      87             : // METHODOLOGY EMPLOYED:
      88             : //  Uses net radiation method to calculate the optical properties of a multi-layer
      89             : //  window construction. Most of the routines in this module were adopted directly
      90             : //  from ASHRAE 1311-RP.
      91             : // REFERENCES:
      92             : // John L. Wright,    Charles S. Barnaby, Michael R. Collins, and Nathan A. Kotey.
      93             : // Improving Cooling Load Calculations for Fenestration with Shading Devices
      94             : // ASHRAE 1311-RP, Final Report, February 11, 2009.
      95             : // Edwards, D.K. 1977.  Solar absorption by each element in an absorber-coverglass
      96             : //  array,Technical Note, Solar Energy, Vol. 19, pp. 401-402.
      97             : // Kotey, N. A., J. L. Wright, and M. R. Collins.  2008.  "Determining Longwave
      98             : //  RadiativeProperties of Flat Shading Materials," 33rd Annual SESCI / 3rd CSBC
      99             : //  Conference Proceedings, Fredericton, NB.
     100             : // Kotey, N.A., Wright, J.L., M. R. Collins. 2009a. "Determination of Angle-Dependent
     101             : //  SolarOptical Properties of Roller Blind Materials," drafted for submission to
     102             : //  ASHRAE Transactions, Vol. 115, Pt. 1.
     103             : 
     104             : // Kotey, N.A., Wright, J.L., M. R. Collins. 2009b. "Determination of Angle-Dependent
     105             : //  Solar Optical Properties of Drapery Fabrics," in review, ASHRAE Transactions,
     106             : //  Vol. 115, Pt. 2.
     107             : // Wright, J. L.  2008.  "Calculating Centre-Glass Performance Indices of Glazing
     108             : //  Systems with Shading Devices," ASHRAE Transactions, Vol. 114, Pt. 2.
     109             : // Wright, J. L., N. Y. T. Huang, and M. R. Collins.  2008.  "Thermal Resistance
     110             : //  of a Window with an Enclosed Venetian Blind: A Simplified Model,"
     111             : //  ASHRAE Transactions, Vol. 114, Pt. 1.
     112             : 
     113             : // Yahoda, D. S. and J. L. Wright.  2004.  "Methods for Calculating the Effective
     114             : //  Longwave Radiative Properties of a Venetian Blind Layer," ASHRAE Transactions,
     115             : //  Vol. 110, Pt. 1., pp. 463-473.
     116             : // Yahoda, D. S. and J. L. Wright.  2005.  "Methods for Calculating the Effective
     117             : //  Solar-Optical Properties of a Venetian Blind Layer," ASHRAE Transactions,
     118             : //  Vol. 111, Pt. 1, pp. 572-586.
     119             : // Yahoda, D. S. and J. L. Wright.  2004.  "Heat Transfer Analysis of a Between-Panes
     120             : //  Venetian Blind Using Effective Longwave Radiative Properties," ASHRAE Transactions,
     121             : //  Vol. 110, Pt. 1., pp. 455-462.
     122             : // Using/Aliasing
     123             : using namespace DataHeatBalance;
     124             : using namespace DataSurfaces;
     125         796 : void InitEquivalentLayerWindowCalculations(EnergyPlusData &state)
     126             : {
     127             : 
     128             :     // SUBROUTINE INFORMATION:
     129             :     //       AUTHOR         Bereket Nigusse
     130             :     //       DATE WRITTEN   May 2013
     131             : 
     132             :     // PURPOSE OF THIS SUBROUTINE:
     133             :     // Initializes the optical properties for the Equivalent Layer (ASHWAT) Window
     134             :     // model
     135             :     // METHODOLOGY EMPLOYED:
     136             :     // Gets the EquivalentLayer Window Layers Inputs.  Fills in the derived data type
     137             :     // based on the inputs specified.
     138             : 
     139         796 :     if (state.dataWindowEquivLayer->TotWinEquivLayerConstructs < 1) return;
     140           1 :     if (!allocated(state.dataWindowEquivLayer->CFS)) state.dataWindowEquivLayer->CFS.allocate(state.dataWindowEquivLayer->TotWinEquivLayerConstructs);
     141           1 :     if (!allocated(state.dataWindowEquivalentLayer->EQLDiffPropFlag))
     142           1 :         state.dataWindowEquivalentLayer->EQLDiffPropFlag.allocate(state.dataWindowEquivLayer->TotWinEquivLayerConstructs);
     143           1 :     if (!allocated(state.dataWindowEquivalentLayer->CFSDiffAbsTrans))
     144           1 :         state.dataWindowEquivalentLayer->CFSDiffAbsTrans.allocate(2, CFSMAXNL + 1, state.dataWindowEquivLayer->TotWinEquivLayerConstructs);
     145             : 
     146           1 :     state.dataWindowEquivalentLayer->EQLDiffPropFlag = true;
     147           1 :     state.dataWindowEquivalentLayer->CFSDiffAbsTrans = 0.0;
     148             : 
     149           8 :     for (int ConstrNum = 1; ConstrNum <= state.dataHeatBal->TotConstructs; ++ConstrNum) {
     150           7 :         if (!state.dataConstruction->Construct(ConstrNum).TypeIsWindow) continue;
     151           3 :         if (!state.dataConstruction->Construct(ConstrNum).WindowTypeEQL) continue; // skip if not equivalent layer window
     152             : 
     153           3 :         SetEquivalentLayerWindowProperties(state, ConstrNum);
     154             : 
     155             :     } //  end do for TotConstructs
     156             : 
     157           4 :     for (int SurfNum : state.dataSurface->AllHTWindowSurfaceList) {
     158           3 :         if (!state.dataConstruction->Construct(state.dataSurface->Surface(SurfNum).Construction).WindowTypeEQL) continue;
     159             : 
     160           3 :         state.dataSurface->SurfWinWindowModelType(SurfNum) = WindowModel::EQL;
     161             : 
     162           1 :     } //  end do for SurfNum
     163             : }
     164             : 
     165           3 : void SetEquivalentLayerWindowProperties(EnergyPlusData &state, int const ConstrNum)
     166             : {
     167             : 
     168             :     // SUBROUTINE INFORMATION:
     169             :     //       AUTHOR         Bereket Nigusse
     170             :     //       DATE WRITTEN   May 2013
     171             :     //       MODIFIED       na
     172             :     //       RE-ENGINEERED  na
     173             : 
     174             :     // PURPOSE OF THIS SUBROUTINE:
     175             :     // Populates the the equivalent layer window model optical and thermal
     176             :     // properties, fills default values and shades geomterical calculations
     177             : 
     178             :     // METHODOLOGY EMPLOYED:
     179             :     // uses some routine developed for ASHRAE RP-1311 (ASHWAT Model)
     180             : 
     181             :     int Layer;                                // layer index
     182             :     int MaterNum;                             // material index of a layer in a construction
     183             :     int gLayer;                               // gap layer index
     184             :     int sLayer;                               // glazing and shade layers (non-gas layers) index
     185             :     int EQLNum;                               // equivalent layer window construction index
     186             :     int NumGLayers;                           // number of gap layers
     187             :     int NumSLayers;                           // number of glazing and shade layers (non-gas layers)
     188           6 :     Array2D<Real64> SysAbs1(2, CFSMAXNL + 1); // layers absorptance and system transmittance
     189             : 
     190           3 :     if (!allocated(state.dataWindowEquivLayer->CFSLayers))
     191           1 :         state.dataWindowEquivLayer->CFSLayers.allocate(state.dataConstruction->Construct(ConstrNum).TotLayers);
     192             : 
     193           3 :     sLayer = 0;
     194           3 :     gLayer = 0;
     195           3 :     EQLNum = state.dataConstruction->Construct(ConstrNum).EQLConsPtr;
     196             : 
     197           3 :     auto &CFS = state.dataWindowEquivLayer->CFS;
     198             : 
     199           3 :     CFS(EQLNum).Name = state.dataConstruction->Construct(ConstrNum).Name;
     200             : 
     201          22 :     for (Layer = 1; Layer <= state.dataConstruction->Construct(ConstrNum).TotLayers; ++Layer) {
     202             : 
     203          19 :         Material::Group group1 = state.dataMaterial->Material(state.dataConstruction->Construct(ConstrNum).LayerPoint(1))->group;
     204          19 :         if (group1 != Material::Group::GlassEquivalentLayer && group1 != Material::Group::ShadeEquivalentLayer &&
     205          11 :             group1 != Material::Group::DrapeEquivalentLayer && group1 != Material::Group::ScreenEquivalentLayer &&
     206           0 :             group1 != Material::Group::BlindEquivalentLayer && group1 != Material::Group::GapEquivalentLayer)
     207           0 :             continue;
     208             : 
     209          19 :         MaterNum = state.dataConstruction->Construct(ConstrNum).LayerPoint(Layer);
     210          19 :         auto const *mat = state.dataMaterial->Material(MaterNum);
     211             : 
     212          19 :         if (mat->group == Material::Group::GapEquivalentLayer) {
     213             :             // Gap or Gas Layer
     214           8 :             ++gLayer;
     215             :         } else {
     216          11 :             auto const *thisMaterial = dynamic_cast<Material::MaterialChild const *>(mat);
     217          11 :             assert(thisMaterial != nullptr);
     218             :             // Solid (Glazing or Shade) Layer
     219          11 :             ++sLayer;
     220          11 :             CFS(EQLNum).L(sLayer).Name = thisMaterial->Name;
     221             :             // longwave property input
     222          11 :             CFS(EQLNum).L(sLayer).LWP_MAT.EPSLF = thisMaterial->EmissThermalFront;
     223          11 :             CFS(EQLNum).L(sLayer).LWP_MAT.EPSLB = thisMaterial->EmissThermalBack;
     224          11 :             CFS(EQLNum).L(sLayer).LWP_MAT.TAUL = thisMaterial->TausThermal;
     225             :         }
     226             : 
     227          19 :         if (mat->group == Material::Group::BlindEquivalentLayer) {
     228           0 :             auto const *thisMaterial = dynamic_cast<Material::MaterialChild const *>(mat);
     229           0 :             assert(thisMaterial != nullptr);
     230             : 
     231           0 :             CFS(EQLNum).VBLayerPtr = sLayer;
     232           0 :             if (thisMaterial->SlatOrientation == DataWindowEquivalentLayer::Orientation::Horizontal) {
     233           0 :                 CFS(EQLNum).L(sLayer).LTYPE = LayerType::VBHOR;
     234           0 :             } else if (thisMaterial->SlatOrientation == DataWindowEquivalentLayer::Orientation::Vertical) {
     235           0 :                 CFS(EQLNum).L(sLayer).LTYPE = LayerType::VBVER;
     236             :             }
     237           0 :             CFS(EQLNum).L(sLayer).SWP_MAT.RHOSFBD = thisMaterial->ReflFrontBeamDiff;
     238           0 :             CFS(EQLNum).L(sLayer).SWP_MAT.RHOSBBD = thisMaterial->ReflBackBeamDiff;
     239           0 :             CFS(EQLNum).L(sLayer).SWP_MAT.TAUSFBD = thisMaterial->TausFrontBeamDiff;
     240           0 :             CFS(EQLNum).L(sLayer).SWP_MAT.TAUSBBD = thisMaterial->TausBackBeamDiff;
     241             : 
     242           0 :             CFS(EQLNum).L(sLayer).SWP_MAT.RHOSFDD = thisMaterial->ReflFrontDiffDiff;
     243           0 :             CFS(EQLNum).L(sLayer).SWP_MAT.RHOSBDD = thisMaterial->ReflBackDiffDiff;
     244           0 :             CFS(EQLNum).L(sLayer).SWP_MAT.TAUS_DD = thisMaterial->TausDiffDiff;
     245           0 :             CFS(EQLNum).L(sLayer).PHI_DEG = thisMaterial->SlatAngle;
     246           0 :             CFS(EQLNum).L(sLayer).CNTRL = static_cast<int>(thisMaterial->slatAngleType);
     247           0 :             CFS(EQLNum).L(sLayer).S = thisMaterial->SlatSeparation;
     248           0 :             CFS(EQLNum).L(sLayer).W = thisMaterial->SlatWidth;
     249           0 :             CFS(EQLNum).L(sLayer).C = thisMaterial->SlatCrown;
     250          19 :         } else if (mat->group == Material::Group::GlassEquivalentLayer) {
     251           8 :             auto const *thisMaterial = dynamic_cast<Material::MaterialChild const *>(mat);
     252           8 :             assert(thisMaterial != nullptr);
     253             :             // glazing
     254           8 :             CFS(EQLNum).L(sLayer).LTYPE = LayerType::GLAZE;
     255           8 :             CFS(EQLNum).L(sLayer).SWP_MAT.RHOSFBB = thisMaterial->ReflFrontBeamBeam;
     256           8 :             CFS(EQLNum).L(sLayer).SWP_MAT.RHOSBBB = thisMaterial->ReflBackBeamBeam;
     257           8 :             CFS(EQLNum).L(sLayer).SWP_MAT.TAUSFBB = thisMaterial->TausFrontBeamBeam;
     258             : 
     259           8 :             CFS(EQLNum).L(sLayer).SWP_MAT.RHOSFBD = thisMaterial->ReflFrontBeamDiff;
     260           8 :             CFS(EQLNum).L(sLayer).SWP_MAT.RHOSBBD = thisMaterial->ReflBackBeamDiff;
     261           8 :             CFS(EQLNum).L(sLayer).SWP_MAT.TAUSFBD = thisMaterial->TausFrontBeamDiff;
     262           8 :             CFS(EQLNum).L(sLayer).SWP_MAT.TAUSBBD = thisMaterial->TausBackBeamDiff;
     263             : 
     264           8 :             CFS(EQLNum).L(sLayer).SWP_MAT.RHOSFDD = thisMaterial->ReflFrontDiffDiff;
     265           8 :             CFS(EQLNum).L(sLayer).SWP_MAT.RHOSBDD = thisMaterial->ReflBackDiffDiff;
     266           8 :             CFS(EQLNum).L(sLayer).SWP_MAT.TAUS_DD = thisMaterial->TausDiffDiff;
     267          11 :         } else if (mat->group == Material::Group::ShadeEquivalentLayer) {
     268           2 :             auto const *thisMaterial = dynamic_cast<Material::MaterialChild const *>(mat);
     269           2 :             assert(thisMaterial != nullptr);
     270             :             // roller blind
     271           2 :             CFS(EQLNum).L(sLayer).LTYPE = LayerType::ROLLB;
     272           2 :             CFS(EQLNum).L(sLayer).SWP_MAT.TAUSFBB = thisMaterial->TausFrontBeamBeam;
     273           2 :             CFS(EQLNum).L(sLayer).SWP_MAT.TAUSBBB = thisMaterial->TausBackBeamBeam;
     274           2 :             CFS(EQLNum).L(sLayer).SWP_MAT.RHOSFBD = thisMaterial->ReflFrontBeamDiff;
     275           2 :             CFS(EQLNum).L(sLayer).SWP_MAT.RHOSBBD = thisMaterial->ReflBackBeamDiff;
     276           2 :             CFS(EQLNum).L(sLayer).SWP_MAT.TAUSFBD = thisMaterial->TausFrontBeamDiff;
     277           2 :             CFS(EQLNum).L(sLayer).SWP_MAT.TAUSBBD = thisMaterial->TausBackBeamDiff;
     278             : 
     279           9 :         } else if (mat->group == Material::Group::DrapeEquivalentLayer) {
     280           0 :             auto const *thisMaterial = dynamic_cast<Material::MaterialChild const *>(mat);
     281           0 :             assert(thisMaterial != nullptr);
     282             :             // drapery fabric
     283           0 :             CFS(EQLNum).L(sLayer).LTYPE = LayerType::DRAPE;
     284           0 :             CFS(EQLNum).L(sLayer).SWP_MAT.TAUSFBB = thisMaterial->TausFrontBeamBeam;
     285           0 :             CFS(EQLNum).L(sLayer).SWP_MAT.TAUSBBB = thisMaterial->TausBackBeamBeam;
     286           0 :             CFS(EQLNum).L(sLayer).SWP_MAT.RHOSFBD = thisMaterial->ReflFrontBeamDiff;
     287           0 :             CFS(EQLNum).L(sLayer).SWP_MAT.RHOSBBD = thisMaterial->ReflBackBeamDiff;
     288           0 :             CFS(EQLNum).L(sLayer).SWP_MAT.TAUSFBD = thisMaterial->TausFrontBeamDiff;
     289           0 :             CFS(EQLNum).L(sLayer).SWP_MAT.TAUSBBD = thisMaterial->TausBackBeamDiff;
     290             : 
     291           0 :             CFS(EQLNum).L(sLayer).S = thisMaterial->PleatedDrapeLength;
     292           0 :             CFS(EQLNum).L(sLayer).W = thisMaterial->PleatedDrapeWidth;
     293             :             // init diffuse SWP to force default derivation
     294           0 :             CFS(EQLNum).L(sLayer).SWP_MAT.RHOSFDD = -1.0;
     295           0 :             CFS(EQLNum).L(sLayer).SWP_MAT.RHOSBDD = -1.0;
     296           0 :             CFS(EQLNum).L(sLayer).SWP_MAT.TAUS_DD = -1.0;
     297           9 :         } else if (mat->group == Material::Group::ScreenEquivalentLayer) {
     298           1 :             auto const *thisMaterial = dynamic_cast<Material::MaterialChild const *>(mat);
     299           1 :             assert(thisMaterial != nullptr);
     300             :             // insect screen
     301           1 :             CFS(EQLNum).L(sLayer).LTYPE = LayerType::INSCRN;
     302           1 :             CFS(EQLNum).L(sLayer).SWP_MAT.TAUSFBB = thisMaterial->TausFrontBeamBeam;
     303           1 :             CFS(EQLNum).L(sLayer).SWP_MAT.TAUSBBB = thisMaterial->TausBackBeamBeam;
     304           1 :             CFS(EQLNum).L(sLayer).SWP_MAT.RHOSFBD = thisMaterial->ReflFrontBeamDiff;
     305           1 :             CFS(EQLNum).L(sLayer).SWP_MAT.RHOSBBD = thisMaterial->ReflBackBeamDiff;
     306             : 
     307           1 :             CFS(EQLNum).L(sLayer).SWP_MAT.TAUSFBD = thisMaterial->TausFrontBeamDiff;
     308           1 :             CFS(EQLNum).L(sLayer).SWP_MAT.TAUSBBD = thisMaterial->TausBackBeamDiff;
     309             :             // wire geometry
     310           1 :             CFS(EQLNum).L(sLayer).S = thisMaterial->ScreenWireSpacing;
     311           1 :             CFS(EQLNum).L(sLayer).W = thisMaterial->ScreenWireDiameter;
     312           8 :         } else if (mat->group == Material::Group::GapEquivalentLayer) {
     313           8 :             auto const *matGas = dynamic_cast<Material::MaterialGasMix const *>(mat);
     314           8 :             assert(matGas != nullptr);
     315             : 
     316             :             // This layer is a gap.  Fill in the parameters
     317           8 :             CFS(EQLNum).G(gLayer).Name = matGas->Name;
     318             :             // previously the values of the levels are 1-3, now it's 0-2
     319           8 :             CFS(EQLNum).G(gLayer).GTYPE = (int)matGas->gapVentType + 1;
     320           8 :             CFS(EQLNum).G(gLayer).TAS = matGas->Thickness;
     321             : 
     322           8 :             auto const &gas = matGas->gases[0];
     323           8 :             CFS(EQLNum).G(gLayer).FG.Name = Material::gasTypeNames[(int)gas.type];
     324           8 :             CFS(EQLNum).G(gLayer).FG.AK = gas.con.c0;
     325           8 :             CFS(EQLNum).G(gLayer).FG.BK = gas.con.c1;
     326           8 :             CFS(EQLNum).G(gLayer).FG.CK = gas.con.c2;
     327           8 :             CFS(EQLNum).G(gLayer).FG.ACP = gas.cp.c0;
     328           8 :             CFS(EQLNum).G(gLayer).FG.BCP = gas.cp.c1;
     329           8 :             CFS(EQLNum).G(gLayer).FG.CCP = gas.cp.c2;
     330           8 :             CFS(EQLNum).G(gLayer).FG.AVISC = gas.cp.c0;
     331           8 :             CFS(EQLNum).G(gLayer).FG.BVISC = gas.cp.c1;
     332           8 :             CFS(EQLNum).G(gLayer).FG.CVISC = gas.cp.c2;
     333           8 :             CFS(EQLNum).G(gLayer).FG.MHAT = gas.wght;
     334             :             // fills gas density and effective gap thickness
     335           8 :             BuildGap(state, CFS(EQLNum).G(gLayer), CFS(EQLNum).G(gLayer).GTYPE, CFS(EQLNum).G(gLayer).TAS);
     336             :         } else {
     337           0 :             CFS(EQLNum).L(sLayer).LTYPE = LayerType::NONE;
     338             :         }
     339             :         // beam beam transmittance is the same for front and back side
     340          19 :         CFS(EQLNum).L(sLayer).SWP_MAT.TAUSBBB = CFS(EQLNum).L(sLayer).SWP_MAT.TAUSFBB;
     341          19 :         NumSLayers = sLayer;
     342          19 :         NumGLayers = gLayer;
     343          19 :         CFS(EQLNum).NL = sLayer;
     344             : 
     345             :         // checks optical properties and fill in default values for diffuse optical
     346             :         // properties by calculating from other optical inputs, also fills in geometrical inputs
     347          19 :         CheckAndFixCFSLayer(state, CFS(EQLNum).L(sLayer));
     348             : 
     349             :     } // end do for Construct(ConstrNum)%TotLayers
     350             : 
     351             :     // Finalize CFS after get input.  Correct effective gap thickness for VB
     352           3 :     FinalizeCFS(state, CFS(EQLNum));
     353             : 
     354             :     // get total solid layers (glazing layers + shade layers)
     355           3 :     state.dataConstruction->Construct(ConstrNum).TotSolidLayers = CFS(EQLNum).NL;
     356             : 
     357             :     // Calculate layers diffuse absorptance and system diffuse transmittance
     358           3 :     CalcEQLWindowOpticalProperty(state, CFS(EQLNum), SolarArrays::DIFF, SysAbs1, 0.0, 0.0, 0.0);
     359           3 :     state.dataConstruction->Construct(ConstrNum).TransDiffFrontEQL = SysAbs1(1, CFS(EQLNum).NL + 1);
     360           3 :     state.dataWindowEquivalentLayer->CFSDiffAbsTrans(_, _, EQLNum) = SysAbs1;
     361           3 :     state.dataConstruction->Construct(ConstrNum).AbsDiffFrontEQL({1, CFSMAXNL}) = SysAbs1(1, {1, CFSMAXNL});
     362           3 :     state.dataConstruction->Construct(ConstrNum).AbsDiffBackEQL({1, CFSMAXNL}) = SysAbs1(2, {1, CFSMAXNL});
     363             :     // get construction front and back diffuse effective reflectance
     364           3 :     state.dataConstruction->Construct(ConstrNum).ReflectSolDiffFront = CFS(EQLNum).L(1).SWP_EL.RHOSFDD;
     365           3 :     state.dataConstruction->Construct(ConstrNum).ReflectSolDiffBack = CFS(EQLNum).L(CFS(EQLNum).NL).SWP_EL.RHOSBDD;
     366             :     // calculate U-Value, SHGC and Normal Transmittance of EQL Window
     367           3 :     CalcEQLWindowStandardRatings(state, ConstrNum);
     368             : 
     369           3 :     if (CFSHasControlledShade(state, CFS(EQLNum)) > 0) CFS(EQLNum).ISControlled = true; // is controlled
     370             : 
     371             :     // set internal face emissivity
     372           3 :     state.dataConstruction->Construct(ConstrNum).InsideAbsorpThermal = EffectiveEPSLB(CFS(EQLNum));
     373           3 : }
     374             : 
     375           3 : void CalcEQLWindowUvalue(EnergyPlusData &state,
     376             :                          CFSTY const &FS, // CFS to be calculated
     377             :                          Real64 &UNFRC    // NFRC U-factor, W/m2-K
     378             : )
     379             : {
     380             :     // SUBROUTINE INFORMATION:
     381             :     //       AUTHOR         JOHN L. WRIGHT/Chip Barnaby
     382             :     //       DATE WRITTEN   Last Modified February 2008
     383             :     //       MODIFIED       Bereket Nigusse, May 2013
     384             :     //                      Replaced inside convection calculation
     385             :     //                      with ISO Std 15099
     386             :     //       RE-ENGINEERED   na
     387             : 
     388             :     // PURPOSE OF THIS SUBROUTINE:
     389             :     // Calculates U-value of equivalent layer window at standard
     390             :     // fenestration winter rating conditions
     391             : 
     392             :     // METHODOLOGY EMPLOYED:
     393             :     // uses routine developed for ASHRAE RP-1311 (ASHWAT Model)
     394             :     // NFRC rated *HEATING* U-factor or Winter Rating Condition
     395             :     // tin = 294.15d0   ! Inside air temperature (69.8F, 21.0C)
     396             :     // tout = 255.15d0  ! Outside air temperature (-0.4F, -18C)
     397             :     // hcout = 26.d0    ! Outside convective film conductance at 5.5 m/s (12.3 mph)
     398             :     //                  ! wind speed (the value used in Window 5)
     399             :     // BeamSolarInc = 0.0
     400             : 
     401           3 :     Real64 constexpr Height(1.0); // window height, m
     402           3 :     Real64 constexpr TOUT(-18.0); // outdoor air temperature, C
     403           3 :     Real64 constexpr TIN(21.0);   // indoor air temperature, C
     404             :     static constexpr std::string_view RoutineName("CalcEQLWindowUvalue: ");
     405             : 
     406             :     Real64 U;    // U-factor, W/m2-K
     407             :     Real64 UOld; // U-factor during pevious iteration step, W/m2-K
     408             :     Real64 HXO;  // outdoor combined conv+rad surf coeff, W/m2-K
     409             :     Real64 HXI;  // indoor combined conf+rad surf coeff, W/m2-K
     410             :     Real64 HRO;  // outdoor side radiation surf coeff, W/m2-K
     411             :     Real64 HCO;  // outdoor side convection surf coeff, W/m2-K
     412             :     Real64 HRI;  // indoor side radiation surf coeff, W/m2-K
     413             :     Real64 HCI;  // indoor side convection surf coeff, W/m2-K
     414             :     Real64 TGO;
     415             :     Real64 TGI;
     416             :     Real64 TGIK;
     417             :     Real64 TIK;
     418             :     Real64 DT;      // temperature difference, K
     419             :     Real64 EO;      // outside face effective emissivity, (-)
     420             :     Real64 EI;      // inside face effective emissivity, (-)
     421             :     int I;          // index
     422             :     bool CFSURated; // false if U-Value calculation failed
     423             : 
     424           3 :     CFSURated = false;
     425             : 
     426             :     // Intial guess value for combined conductance
     427           3 :     HXO = 29.0; // 1/FenROut
     428           3 :     HXI = 7.0;  // 1/FenRIn
     429           3 :     HCO = 26.0;
     430           3 :     HCI = 3.0; // Initial guess
     431             : 
     432           3 :     DT = TIN - TOUT;               // note DT == 0 detected in CFSUFactor()
     433           3 :     EO = FS.L(1).LWP_EL.EPSLF;     // emissivities outside
     434           3 :     EI = FS.L(FS.NL).LWP_EL.EPSLB; // emissivities inside
     435           3 :     U = 5.0 / FS.NL;               // initial guess
     436             : 
     437             :     // Iterate: find surface temperature, update coeffs, converge to U
     438           6 :     for (I = 1; I <= 10; ++I) {
     439           6 :         TGO = TOUT + U * DT / HXO; // update glazing surface temps
     440           6 :         TGI = TIN - U * DT / HXI;
     441           6 :         HRO = Constant::StefanBoltzmann * EO * (pow_2(TGO + Constant::Kelvin) + pow_2(TOUT + Constant::Kelvin)) *
     442           6 :               ((TGO + Constant::Kelvin) + (TOUT + Constant::Kelvin));
     443           6 :         HRI = Constant::StefanBoltzmann * EI * (pow_2(TGI + Constant::Kelvin) + pow_2(TIN + Constant::Kelvin)) *
     444           6 :               ((TGI + Constant::Kelvin) + (TIN + Constant::Kelvin));
     445             :         // HCI = HIC_ASHRAE( Height, TGI, TI)  ! BAN June 2103 Raplaced with ISO Std 15099
     446           6 :         TGIK = TGI + Constant::Kelvin;
     447           6 :         TIK = TIN + Constant::Kelvin;
     448           6 :         HCI = HCInWindowStandardRatings(state, Height, TGIK, TIK);
     449           6 :         if (HCI < 0.001) break;
     450           6 :         HXI = HCI + HRI;
     451           6 :         HXO = HCO + HRO;
     452           6 :         UOld = U;
     453           6 :         if (!CFSUFactor(state, FS, TOUT, HCO, TIN, HCI, U)) break;
     454           6 :         if (I > 1 && FEQX(U, UOld, 0.001)) {
     455           3 :             CFSURated = true;
     456           3 :             break;
     457             :         }
     458             :     }
     459           3 :     if (!CFSURated) {
     460           0 :         ShowWarningMessage(state, format("{}Fenestration U-Value calculation failed for {}", RoutineName, FS.Name));
     461           0 :         ShowContinueError(state, format("...Calculated U-value = {:.4T}", U));
     462           0 :         ShowContinueError(state, "...Check consistency of inputs");
     463             :     }
     464           3 :     UNFRC = U;
     465           3 : }
     466             : 
     467           3 : void CalcEQLWindowSHGCAndTransNormal(EnergyPlusData &state,
     468             :                                      CFSTY const &FS,    // fenestration system
     469             :                                      Real64 &SHGCSummer, // solar heat gain coefficient
     470             :                                      Real64 &TransNormal // transmittance at normal incidence
     471             : )
     472             : {
     473             : 
     474             :     // SUBROUTINE INFORMATION:
     475             :     //       AUTHOR         Bereket Nigusse
     476             :     //       DATE WRITTEN   May 2013
     477             :     //       MODIFIED       na
     478             :     //       RE-ENGINEERED  na
     479             : 
     480             :     // PURPOSE OF THIS SUBROUTINE:
     481             :     // Calculates SHGC and Normal Transmittance of equivalent layer
     482             :     // fenestration.
     483             : 
     484             :     // METHODOLOGY EMPLOYED:
     485             :     // Uses routine developed for ASHRAE RP-1311 (ASHWAT Model)
     486             :     // Summer Window Rating Conditoions
     487             :     // tin = 297.15d0         ! indoor air condition (75.2F,  24.0C)
     488             :     // tout = 305.15d0        ! Outside air temperature (89.6F, 32C)
     489             :     // hcout = 15.d0          ! Outside convective film conductance at 2.8 m/s (6.2 mph) wind speed
     490             :     // BeamSolarInc = 783.0d0 ! Direct normal incident solar radiation, W/m2
     491             : 
     492           3 :     constexpr Real64 TOL(0.01);
     493           3 :     constexpr Real64 TIN(297.15);
     494           3 :     constexpr Real64 TOUT(305.15);
     495           3 :     constexpr Real64 BeamSolarInc(783.0);
     496             :     static constexpr std::string_view RoutineName("CalcEQLWindowSHGCAndTransNormal: ");
     497             : 
     498             :     Real64 HCOUT;
     499             :     Real64 TRMOUT;
     500             :     Real64 TRMIN;
     501             :     Real64 HCIN;
     502           3 :     Array1D<Real64> QOCF(CFSMAXNL);
     503           3 :     Array1D<Real64> JB({0, CFSMAXNL});
     504           3 :     Array1D<Real64> JF({1, CFSMAXNL + 1});
     505           3 :     Array1D<Real64> T(CFSMAXNL);
     506           3 :     Array1D<Real64> Q({0, CFSMAXNL});
     507           3 :     Array1D<Real64> H({0, CFSMAXNL + 1});
     508           6 :     Array2D<Real64> Abs1(2, CFSMAXNL + 1);
     509             :     Real64 QOCFRoom;
     510             :     Real64 UCG;
     511             :     Real64 SHGC;
     512             :     Real64 IncA;
     513             :     Real64 VProfA;
     514             :     Real64 HProfA;
     515             :     int NL;
     516             :     int I;
     517             :     bool CFSSHGC;
     518             : 
     519             :     // Object Data
     520           3 :     Array1D<CFSSWP> SWP_ON(CFSMAXNL);
     521             : 
     522           3 :     CFSSHGC = true;
     523           3 :     NL = FS.NL;
     524           3 :     IncA = 0.0;
     525           3 :     VProfA = 0.0;
     526           3 :     HProfA = 0.0;
     527           3 :     Abs1 = 0.0;
     528           3 :     HCIN = 3.0; // Initial guess
     529           3 :     HCOUT = 15.0;
     530           6 :     if (FS.L(1).LTYPE == LayerType::ROLLB || FS.L(1).LTYPE == LayerType::DRAPE || FS.L(1).LTYPE == LayerType::INSCRN ||
     531           6 :         FS.L(1).LTYPE == LayerType::VBHOR || FS.L(1).LTYPE == LayerType::VBVER) { // Exterior Roller Blind Present | Exterior Drape Fabric | Exterior
     532             :                                                                                   // Insect Screen Present | Exterior Venetian Blind Present
     533             :         // Reduced convection coefficient due to external attachment
     534           1 :         HCOUT = 12.25;
     535             :     }
     536             : 
     537             :     // Temperatures
     538           3 :     TRMOUT = TOUT;
     539           3 :     TRMIN = TIN;
     540             : 
     541             :     //  Convert direct-normal solar properties for beam incidence to current incident angle
     542          14 :     for (I = 1; I <= NL; ++I) {
     543          11 :         ASHWAT_OffNormalProperties(state, FS.L(I), IncA, VProfA, HProfA, SWP_ON(I));
     544             :     }
     545           3 :     ASHWAT_Solar(FS.NL, SWP_ON, state.dataWindowEquivLayer->SWP_ROOMBLK, 1.0, 0.0, 0.0, Abs1(1, {1, FS.NL + 1}), Abs1(2, {1, FS.NL + 1}));
     546           3 :     TransNormal = Abs1(1, NL + 1);
     547             : 
     548             :     // Calculate SHGC using net radiation method (ASHWAT Model)
     549           3 :     CFSSHGC = ASHWAT_ThermalRatings(state,
     550             :                                     FS,
     551             :                                     TIN,
     552             :                                     TOUT,
     553             :                                     HCIN,
     554             :                                     HCOUT,
     555             :                                     TRMOUT,
     556             :                                     TRMIN,
     557             :                                     BeamSolarInc,
     558           6 :                                     BeamSolarInc * Abs1(1, {1, NL + 1}),
     559             :                                     TOL,
     560             :                                     QOCF,
     561             :                                     QOCFRoom,
     562             :                                     T,
     563             :                                     Q,
     564             :                                     JF,
     565             :                                     JB,
     566             :                                     H,
     567             :                                     UCG,
     568             :                                     SHGC,
     569             :                                     true);
     570             : 
     571           3 :     if (!CFSSHGC) {
     572           0 :         ShowWarningMessage(state, format("{}Solar heat gain coefficient calculation failed for {}", RoutineName, FS.Name));
     573           0 :         ShowContinueError(state, format("...Calculated SHGC = {:.4T}", SHGC));
     574           0 :         ShowContinueError(state, format("...Calculated U-Value = {:.4T}", UCG));
     575           0 :         ShowContinueError(state, "...Check consistency of inputs.");
     576           0 :         return;
     577             :     }
     578           3 :     SHGCSummer = SHGC;
     579           3 : }
     580             : 
     581        1392 : void CalcEQLWindowOpticalProperty(EnergyPlusData &state,
     582             :                                   CFSTY &FS,                      // fenestration system
     583             :                                   SolarArrays const DiffBeamFlag, // isDIFF: calc diffuse properties
     584             :                                   Array2A<Real64> Abs1,
     585             :                                   Real64 const IncA,   // angle of incidence, radians
     586             :                                   Real64 const VProfA, // inc solar vertical profile angle, radians
     587             :                                   Real64 const HProfA  // inc solar horizontal profile angle, radians
     588             : )
     589             : {
     590             :     // SUBROUTINE INFORMATION:
     591             :     //       AUTHOR         University of WaterLoo
     592             :     //       DATE WRITTEN   unknown
     593             :     //       MODIFIED       Bereket Nigusse, May 2013
     594             :     //       RE-ENGINEERED  na
     595             : 
     596             :     // PURPOSE OF THIS SUBROUTINE:
     597             :     // Calculates absorptance for each layer, and transmittance of the
     598             :     // fenestration for beam and diffuse solar radiation
     599             : 
     600             :     // METHODOLOGY EMPLOYED:
     601             :     // uses routine developed for ASHRAE RP-1311 (ASHWAT Model).  Uses net radiation
     602             :     // method.
     603             : 
     604             :     // Argument array dimensioning
     605        1392 :     Abs1.dim(2, CFSMAXNL + 1);
     606             : 
     607             :     // Locals
     608             :     // SUBROUTINE ARGUMENT DEFINITIONS:
     609             :     // else: isBEAM
     610             :     // returned: layer abs for unit (1 W/m2) incident
     611             :     //   if beam, Abs1( :, 1) = abs for IncA
     612             :     //            Abs1( :, 2) = trans Beam-Diffuse only
     613             :     //   if diff, Abs1( :, 1) = abs for outside diff
     614             :     //            Abs1( :, 2) = abs for inside diff
     615             :     //   + = up-from-horizontal
     616             :     //   + = west-of-normal
     617             :     // convect coefficients, W/m2-K
     618             : 
     619             :     int NL;
     620             :     int I;
     621             :     int iL;
     622             :     bool DoShadeControlR;
     623             : 
     624             :     // Object Data
     625        1392 :     Array1D<CFSSWP> SWP_ON(CFSMAXNL);
     626             : 
     627        1392 :     NL = FS.NL;
     628        1392 :     Abs1 = 0.0;
     629             : 
     630        1392 :     if (FS.ISControlled) { // at least 1 controlled layer found
     631           0 :         for (iL = 1; iL <= NL; ++iL) {
     632             :             // If there is shade control (Venetian Blind Only).
     633           0 :             if (IsControlledShade(state, FS.L(iL))) {
     634           0 :                 DoShadeControlR = DoShadeControl(state, FS.L(iL), IncA, VProfA, HProfA);
     635             :             }
     636             :         }
     637             :     }
     638             : 
     639        1392 :     if (DiffBeamFlag != SolarArrays::DIFF) {
     640             :         //  Beam: Convert direct-normal solar properties to off-normal properties
     641        6272 :         for (I = 1; I <= NL; ++I) {
     642        4886 :             ASHWAT_OffNormalProperties(state, FS.L(I), IncA, VProfA, HProfA, SWP_ON(I));
     643             :         }
     644        1386 :         ASHWAT_Solar(FS.NL, SWP_ON, state.dataWindowEquivLayer->SWP_ROOMBLK, 1.0, 0.0, 0.0, Abs1(1, {1, FS.NL + 1}), Abs1(2, {1, FS.NL + 1}));
     645             :     } else {
     646             :         // diffuse
     647           6 :         Array1D<CFSSWP> const SWP_EL(FS.L.ma(&CFSLAYER::SWP_EL)); // Autodesk:F2C++ Can't slice a member array so we create a temporary: Inefficient
     648           6 :         ASHWAT_Solar(FS.NL, SWP_EL, state.dataWindowEquivLayer->SWP_ROOMBLK, 0.0, 1.0, 0.0, Abs1(1, {1, FS.NL + 1}));
     649           6 :         ASHWAT_Solar(FS.NL, SWP_EL, state.dataWindowEquivLayer->SWP_ROOMBLK, 0.0, 0.0, 1.0, Abs1(2, {1, FS.NL + 1}));
     650             :         // CFSFenProp = LOK1 .AND. LOK2
     651           6 :     }
     652        1392 : }
     653             : 
     654        8064 : void EQLWindowSurfaceHeatBalance(EnergyPlusData &state,
     655             :                                  int const SurfNum,       // Surface number
     656             :                                  Real64 const HcOut,      // outside convection coeficient at this timestep, W/m2K
     657             :                                  Real64 &SurfInsideTemp,  // Inside window surface temperature (innermost face) [C]
     658             :                                  Real64 &SurfOutsideTemp, // Outside surface temperature (C)
     659             :                                  Real64 &SurfOutsideEmiss,
     660             :                                  DataBSDFWindow::Condition const CalcCondition // Calucation condition (summer, winter or no condition)
     661             : )
     662             : {
     663             :     // SUBROUTINE INFORMATION:
     664             :     //       AUTHOR         Bereket Nigusse
     665             :     //       DATE WRITTEN   May 2013
     666             :     //       MODIFIED       na
     667             :     //       RE-ENGINEERED  na
     668             : 
     669             :     // PURPOSE OF THIS SUBROUTINE:
     670             :     // performs surface heat balance and returns in the inside and outside surface
     671             :     // temperatures
     672             : 
     673             :     // METHODOLOGY EMPLOYED:
     674             :     // uses the solar-thermal routine developed for ASHRAE RP-1311 (ASHWAT Model).
     675             : 
     676             :     using Psychrometrics::PsyCpAirFnW;
     677             :     using Psychrometrics::PsyTdpFnWPb;
     678             :     using ScheduleManager::GetCurrentScheduleValue;
     679             : 
     680        8064 :     Real64 constexpr TOL(0.0001); // convergence tolerance
     681             : 
     682             :     int NL; // Number of layers
     683        8064 :     Real64 TIN(0);
     684             :     Real64 TRMIN;
     685        8064 :     Real64 Tout(0);
     686             :     Real64 TRMOUT;
     687             :     Real64 QCONV;
     688        8064 :     Array1D<Real64> QOCF(CFSMAXNL);
     689             :     Real64 QOCFRoom;
     690        8064 :     Array1D<Real64> JB({0, CFSMAXNL});
     691        8064 :     Array1D<Real64> JF({1, CFSMAXNL + 1});
     692        8064 :     Array1D<Real64> T(CFSMAXNL);
     693        8064 :     Array1D<Real64> Q({0, CFSMAXNL});
     694        8064 :     Array1D<Real64> H({0, CFSMAXNL + 1});
     695        8064 :     Array1D<Real64> QAllSWwinAbs({1, CFSMAXNL + 1});
     696             : 
     697             :     int EQLNum;    // equivalent layer window index
     698             :     int ZoneNum;   // Zone number corresponding to SurfNum
     699             :     int ConstrNum; // Construction number
     700             : 
     701             :     int SurfNumAdj;  // An interzone surface's number in the adjacent zone
     702             :     Real64 LWAbsIn;  // effective long wave absorptance/emissivity back side
     703             :     Real64 LWAbsOut; // effective long wave absorptance/emissivity front side
     704        8064 :     Real64 outir(0);
     705             :     Real64 rmir;
     706             :     Real64 Ebout;
     707             :     Real64 QXConv;              // extra convective gain from this surface
     708        8064 :     Real64 TaIn(0);             // zone air temperature
     709             :     Real64 tsky;                // sky temperature
     710             :     Real64 HcIn;                // inside convection coeficient at this timestep, W/m2K
     711             :     Real64 ConvHeatFlowNatural; // Convective heat flow from gap between glass and interior shade or blind (W)
     712             :     Real64 NetIRHeatGainWindow; // net radiation gain from the window surface to the zone (W)
     713             :     Real64 ConvHeatGainWindow;  // net convection heat gain from inside surface of window to zone air (W)
     714             :     LayerType InSideLayerType;  // interior shade type
     715             : 
     716             :     Real64 SrdSurfTempAbs; // Absolute temperature of a surrounding surface
     717             :     Real64 OutSrdIR;
     718             : 
     719        8064 :     if (CalcCondition != DataBSDFWindow::Condition::Invalid) return;
     720             : 
     721        8064 :     ConstrNum = state.dataSurface->Surface(SurfNum).Construction;
     722        8064 :     QXConv = 0.0;
     723        8064 :     ConvHeatFlowNatural = 0.0;
     724             : 
     725        8064 :     EQLNum = state.dataConstruction->Construct(ConstrNum).EQLConsPtr;
     726        8064 :     HcIn = state.dataHeatBalSurf->SurfHConvInt(SurfNum); // windows inside surface convective film conductance
     727             : 
     728        8064 :     if (CalcCondition == DataBSDFWindow::Condition::Invalid) {
     729        8064 :         ZoneNum = state.dataSurface->Surface(SurfNum).Zone;
     730        8064 :         SurfNumAdj = state.dataSurface->Surface(SurfNum).ExtBoundCond;
     731        8064 :         Real64 RefAirTemp = state.dataSurface->Surface(SurfNum).getInsideAirTemperature(state, SurfNum);
     732        8064 :         TaIn = RefAirTemp;
     733        8064 :         TIN = TaIn + Constant::Kelvin; // Inside air temperature, K
     734             : 
     735             :         // now get "outside" air temperature
     736        8064 :         if (SurfNumAdj > 0) {
     737             :             // this is interzone window. the outside condition is determined from the adjacent zone
     738             :             // condition
     739           0 :             int enclNumAdj = state.dataSurface->Surface(SurfNumAdj).RadEnclIndex;
     740           0 :             RefAirTemp = state.dataSurface->Surface(SurfNumAdj).getInsideAirTemperature(state, SurfNumAdj);
     741           0 :             Tout = RefAirTemp + Constant::Kelvin; // outside air temperature
     742           0 :             tsky = state.dataViewFactor->EnclRadInfo(enclNumAdj).MRT +
     743             :                    Constant::Kelvin; // TODO this misses IR from sources such as high temp radiant and baseboards
     744             : 
     745             :             // The IR radiance of this window's "exterior" surround is the IR radiance
     746             :             // from surfaces and high-temp radiant sources in the adjacent zone
     747           0 :             outir = state.dataSurface->SurfWinIRfromParentZone(SurfNumAdj) + state.dataHeatBalSurf->SurfQdotRadHVACInPerArea(SurfNumAdj) +
     748           0 :                     state.dataHeatBal->SurfQdotRadIntGainsInPerArea(SurfNumAdj);
     749             : 
     750             :         } else { // Exterior window (ExtBoundCond = 0)
     751             :                  // Calculate LWR from surrounding surfaces if defined for an exterior window
     752        8064 :             OutSrdIR = 0;
     753        8064 :             if (state.dataGlobal->AnyLocalEnvironmentsInModel) {
     754           0 :                 if (state.dataSurface->Surface(SurfNum).SurfHasSurroundingSurfProperty) {
     755           0 :                     SrdSurfTempAbs = state.dataSurface->Surface(SurfNum).SrdSurfTemp + Constant::Kelvin;
     756           0 :                     OutSrdIR = Constant::StefanBoltzmann * state.dataSurface->Surface(SurfNum).ViewFactorSrdSurfs * pow_4(SrdSurfTempAbs);
     757             :                 }
     758             :             }
     759        8064 :             if (state.dataSurface->Surface(SurfNum).ExtWind) { // Window is exposed to wind (and possibly rain)
     760        8064 :                 if (state.dataEnvrn->IsRain) {                 // Raining: since wind exposed, outside window surface gets wet
     761           0 :                     Tout = state.dataSurface->SurfOutWetBulbTemp(SurfNum) + Constant::Kelvin;
     762             :                 } else { // Dry
     763        8064 :                     Tout = state.dataSurface->SurfOutDryBulbTemp(SurfNum) + Constant::Kelvin;
     764             :                 }
     765             :             } else { // Window not exposed to wind
     766           0 :                 Tout = state.dataSurface->SurfOutDryBulbTemp(SurfNum) + Constant::Kelvin;
     767             :             }
     768        8064 :             tsky = state.dataEnvrn->SkyTempKelvin;
     769        8064 :             Ebout = Constant::StefanBoltzmann * pow_4(Tout);
     770             :             // ASHWAT model may be slightly different
     771        8064 :             outir = state.dataSurface->Surface(SurfNum).ViewFactorSkyIR *
     772        8064 :                         (state.dataSurface->SurfAirSkyRadSplit(SurfNum) * Constant::StefanBoltzmann * pow_4(tsky) +
     773        8064 :                          (1.0 - state.dataSurface->SurfAirSkyRadSplit(SurfNum)) * Ebout) +
     774        8064 :                     state.dataSurface->Surface(SurfNum).ViewFactorGroundIR * Ebout + OutSrdIR;
     775             :         }
     776             :     }
     777             :     // Outdoor conditions
     778        8064 :     TRMOUT = root_4(outir / Constant::StefanBoltzmann); // it is in Kelvin scale
     779             :     // indoor conditions
     780        8064 :     LWAbsIn = EffectiveEPSLB(state.dataWindowEquivLayer->CFS(EQLNum));  // windows inside face effective thermal emissivity
     781        8064 :     LWAbsOut = EffectiveEPSLF(state.dataWindowEquivLayer->CFS(EQLNum)); // windows outside face effective thermal emissivity
     782        8064 :     SurfOutsideEmiss = LWAbsOut;
     783             :     // Indoor mean radiant temperature.
     784             :     // IR incident on window from zone surfaces and high-temp radiant sources
     785        8064 :     rmir = state.dataSurface->SurfWinIRfromParentZone(SurfNum) + state.dataHeatBalSurf->SurfQdotRadHVACInPerArea(SurfNum) +
     786        8064 :            state.dataHeatBal->SurfQdotRadIntGainsInPerArea(SurfNum);
     787        8064 :     TRMIN = root_4(rmir / Constant::StefanBoltzmann); // TODO check model equation.
     788             : 
     789        8064 :     NL = state.dataWindowEquivLayer->CFS(EQLNum).NL;
     790        8064 :     QAllSWwinAbs({1, NL + 1}) = state.dataHeatBal->SurfWinQRadSWwinAbs(SurfNum, {1, NL + 1});
     791             :     //  Solve energy balance(s) for temperature at each node/layer and
     792             :     //  heat flux, including components, between each pair of nodes/layers
     793        8064 :     ASHWAT_ThermalCalc(state,
     794        8064 :                        state.dataWindowEquivLayer->CFS(EQLNum),
     795             :                        TIN,
     796             :                        Tout,
     797             :                        HcIn,
     798             :                        HcOut,
     799             :                        TRMOUT,
     800             :                        TRMIN,
     801       16128 :                        QAllSWwinAbs({1, NL + 1}),
     802             :                        TOL,
     803             :                        QOCF,
     804             :                        QOCFRoom,
     805             :                        T,
     806             :                        Q,
     807             :                        JF,
     808             :                        JB,
     809             :                        H);
     810             : 
     811             :     // effective surface temperature is set to surface temperature calculated
     812             :     // by the fenestration layers temperature solver
     813        8064 :     SurfInsideTemp = T(NL) - Constant::Kelvin;
     814             :     // Convective to room
     815        8064 :     QCONV = H(NL) * (T(NL) - TIN);
     816             :     // Other convective = total conv - standard model prediction
     817        8064 :     QXConv = QCONV - HcIn * (SurfInsideTemp - TaIn);
     818             :     // Save the extra convection term. This term is added to the zone air heat
     819             :     // balance equation
     820        8064 :     state.dataSurface->SurfWinOtherConvHeatGain(SurfNum) = state.dataSurface->Surface(SurfNum).Area * QXConv;
     821        8064 :     SurfOutsideTemp = T(1) - Constant::Kelvin;
     822             :     // Various reporting calculations
     823        8064 :     InSideLayerType = state.dataWindowEquivLayer->CFS(EQLNum).L(NL).LTYPE;
     824        8064 :     if (InSideLayerType == LayerType::GLAZE) {
     825        5376 :         ConvHeatFlowNatural = 0.0;
     826             :     } else {
     827        2688 :         ConvHeatFlowNatural = state.dataSurface->Surface(SurfNum).Area * QOCFRoom;
     828             :     }
     829        8064 :     state.dataSurface->SurfWinEffInsSurfTemp(SurfNum) = SurfInsideTemp;
     830        8064 :     NetIRHeatGainWindow =
     831        8064 :         state.dataSurface->Surface(SurfNum).Area * LWAbsIn * (Constant::StefanBoltzmann * pow_4(SurfInsideTemp + Constant::Kelvin) - rmir);
     832        8064 :     ConvHeatGainWindow = state.dataSurface->Surface(SurfNum).Area * HcIn * (SurfInsideTemp - TaIn);
     833             :     // Window heat gain (or loss) is calculated here
     834        8064 :     state.dataSurface->SurfWinHeatGain(SurfNum) =
     835        8064 :         state.dataSurface->SurfWinTransSolar(SurfNum) + ConvHeatGainWindow + NetIRHeatGainWindow + ConvHeatFlowNatural -
     836        8064 :         (state.dataSurface->SurfWinLossSWZoneToOutWinRep(SurfNum) +
     837        8064 :          state.dataHeatBalSurf->SurfWinInitialDifSolInTrans(SurfNum) * state.dataSurface->Surface(SurfNum).Area);
     838        8064 :     state.dataSurface->SurfWinConvHeatFlowNatural(SurfNum) = ConvHeatFlowNatural;
     839        8064 :     state.dataSurface->SurfWinGainConvShadeToZoneRep(SurfNum) = ConvHeatGainWindow;
     840        8064 :     state.dataSurface->SurfWinGainIRGlazToZoneRep(SurfNum) = NetIRHeatGainWindow;
     841        8064 :     state.dataSurface->SurfWinGainIRShadeToZoneRep(SurfNum) = NetIRHeatGainWindow;
     842        8064 :     if (InSideLayerType == LayerType::GLAZE) {
     843             :         // no interior sade
     844        5376 :         state.dataSurface->SurfWinGainIRShadeToZoneRep(SurfNum) = 0.0;
     845             :     } else {
     846             :         // Interior shade exists
     847        2688 :         state.dataSurface->SurfWinGainIRGlazToZoneRep(SurfNum) = 0.0;
     848             :     }
     849        8064 : }
     850             : 
     851          10 : void OPENNESS_LW(Real64 const OPENNESS, // shade openness (=tausbb at normal incidence)
     852             :                  Real64 const EPSLW0,   // apparent LW emittance of shade at 0 openness
     853             :                  Real64 const TAULW0,   // apparent LW transmittance of shade at 0 openness
     854             :                  Real64 &EPSLW,         // returned: effective LW emittance of shade
     855             :                  Real64 &TAULW          // returned: effective LW transmittance of shade
     856             : )
     857             : {
     858             :     // SUBROUTINE INFORMATION:
     859             :     //       AUTHOR         John L. Wright and Nathan Kotey, University of Waterloo,
     860             :     //                      Mechanical Engineering, Advanced Glazing System Laboratory
     861             :     //       DATE WRITTEN   unknown
     862             :     //       MODIFIED       na
     863             :     //       RE-ENGINEERED  na
     864             : 
     865             :     // PURPOSE OF THIS SUBROUTINE:
     866             :     // Modifies long wave properties for shade types characterized by openness.
     867             :     // Applies to shade type: insect screen, roller blind, drape fabric
     868             : 
     869             :     //   (= wire or thread emittance)
     870             :     //   typical (default) values
     871             :     //      dark insect screen = .93
     872             :     //      metalic insect screen = .32
     873             :     //      roller blinds = .91
     874             :     //      drape fabric = .87
     875             :     //   typical (default) values
     876             :     //      dark insect screen = .02
     877             :     //      metalic insect screen = .19
     878             :     //      roller blinds = .05
     879             :     //      drape fabric = .05
     880             : 
     881          10 :     EPSLW = EPSLW0 * (1.0 - OPENNESS);
     882          10 :     TAULW = TAULW0 * (1.0 - OPENNESS) + OPENNESS;
     883          10 : }
     884             : 
     885        5366 : Real64 P01(EnergyPlusData &state,
     886             :            Real64 const P,             // property
     887             :            std::string_view const WHAT // identifier for err msg
     888             : )
     889             : {
     890             :     //       AUTHOR         ASHRAE 1311-RP
     891             :     //       DATE WRITTEN   unknown
     892             :     //       MODIFIED       Bereket Nigusse, May 2013
     893             :     //                      Added error messages
     894             :     //       RE-ENGINEERED  na
     895             : 
     896             :     // PURPOSE OF THIS FUNCTION:
     897             :     // Constrains property to range 0 - 1
     898             : 
     899             :     // Return value
     900             :     Real64 P01;
     901             : 
     902             :     static constexpr std::string_view RoutineName("P01: ");
     903             : 
     904        5366 :     if (P < -0.05 || P > 1.05) {
     905           0 :         ShowWarningMessage(state, format("{}property value should have been between 0 and 1", RoutineName));
     906           0 :         ShowContinueError(state, format("{}=:  property value is ={:.4T}", WHAT, P));
     907           0 :         if (P < 0.0) {
     908           0 :             ShowContinueError(state, "property value is reset to 0.0");
     909           0 :         } else if (P > 1.0) {
     910           0 :             ShowContinueError(state, "property value is reset to 1.0");
     911             :         }
     912             :     }
     913        5366 :     P01 = max(0.0, min(1.0, P));
     914             : 
     915        5366 :     return P01;
     916             : }
     917             : 
     918             : Real64
     919          14 : HEMINT(EnergyPlusData &state,
     920             :        std::function<Real64(EnergyPlusData &state, Real64 const THETA, int const OPT, const Array1D<Real64> &)> F, // property integrand function
     921             :        int const F_Opt,           // options passed to F() (hipRHO, hipTAU)
     922             :        const Array1D<Real64> &F_P // parameters passed to F()
     923             : )
     924             : {
     925             :     //       AUTHOR         ASHRAE 1311-RP
     926             :     //       DATE WRITTEN   unknown
     927             :     //       MODIFIED       na
     928             :     //       RE-ENGINEERED  na
     929             : 
     930             :     // PURPOSE OF THIS FUNCTION:
     931             :     // Romberg Integration of Property function over hemispeherical dome
     932             :     // METHODOLOGY EMPLOYED:
     933             :     //  Romberg Integration.
     934             : 
     935             :     // Argument array dimensioning
     936          14 :     EP_SIZE_CHECK(F_P, state.dataWindowEquivalentLayer->hipDIM);
     937             : 
     938          14 :     constexpr Real64 KMAX(8); // max steps
     939          14 :     int const NPANMAX(std::pow(2, KMAX));
     940          14 :     Real64 constexpr TOL(0.0005); // convergence tolerance
     941             :     static constexpr std::string_view RoutineName("HEMINT");
     942             : 
     943          28 :     Array2D<Real64> T(KMAX, KMAX);
     944             :     Real64 FX;
     945             :     Real64 X1;
     946             :     Real64 X2;
     947             :     Real64 X;
     948             :     Real64 DX;
     949             :     Real64 SUM;
     950             :     Real64 DIFF;
     951             :     int nPan;
     952             :     int I;
     953             :     int K;
     954             :     int L;
     955             :     int iPX;
     956             : 
     957          14 :     X1 = 0.0; // integration limits
     958          14 :     X2 = Constant::PiOvr2;
     959          14 :     nPan = 1;
     960          14 :     SUM = 0.0;
     961          56 :     for (K = 1; K <= KMAX; ++K) {
     962          56 :         DX = (X2 - X1) / nPan;
     963          56 :         iPX = NPANMAX / nPan;
     964         322 :         for (I = 0; I <= nPan; ++I) {
     965         266 :             if (K == 1 || mod(I * iPX, iPX * 2) != 0) {
     966             :                 //   evaluate integrand function for new X values
     967             :                 //   2 * sin( x) * cos( x) covers hemisphere with single integral
     968         126 :                 X = X1 + I * DX;
     969         126 :                 FX = 2.0 * std::sin(X) * std::cos(X) * F(state, X, F_Opt, F_P);
     970         126 :                 if (K == 1) FX /= 2.0;
     971         126 :                 SUM += FX;
     972             :             }
     973             :         }
     974             : 
     975          56 :         T(K, 1) = DX * SUM;
     976             :         // trapezoid result - i.e., first column Romberg entry
     977             :         // Now complete the row
     978          56 :         if (K > 1) {
     979         126 :             for (L = 2; L <= K; ++L) {
     980          84 :                 Real64 const pow_4_L_1(std::pow(4.0, L - 1));
     981          84 :                 T(K, L) = (pow_4_L_1 * T(K, L - 1) - T(K - 1, L - 1)) / (pow_4_L_1 - 1.0);
     982             :             }
     983             :             //    check for convergence
     984             :             //    do 8 panels minimum, else can miss F() features
     985          42 :             if (nPan >= 8) {
     986          14 :                 DIFF = std::abs(T(K, K) - T(K - 1, K - 1));
     987          14 :                 if (DIFF < TOL) break;
     988             :             }
     989             :         }
     990          42 :         nPan *= 2;
     991             :     }
     992          14 :     if (K > KMAX) {
     993           0 :         K = KMAX;
     994             :     }
     995          28 :     return P01(state, T(K, K), RoutineName);
     996          14 : }
     997             : 
     998           6 : void RB_DIFF(EnergyPlusData &state,
     999             :              Real64 const RHO_BT0, // normal incidence beam-total reflectance
    1000             :              Real64 const TAU_BT0, // normal incidence beam-total transmittance
    1001             :              Real64 const TAU_BB0, // normal incidence beam-beam transmittance
    1002             :              Real64 &RHO_DD,       // returned: diffuse-diffuse reflectance
    1003             :              Real64 &TAU_DD        // returned: diffuse-diffuse transmittance
    1004             : )
    1005             : {
    1006             :     // SUBROUTINE INFORMATION:
    1007             :     //       AUTHOR         John L. Wright and Nathan Kotey, University of Waterloo,
    1008             :     //                      Mechanical Engineering, Advanced Glazing System Laboratory
    1009             :     //       DATE WRITTEN   Unknown
    1010             :     //       MODIFIED       na
    1011             :     //       RE-ENGINEERED  na
    1012             : 
    1013             :     // PURPOSE OF THIS SUBROUTINE:
    1014             :     // Calculates roller blind diffuse-diffuse solar optical properties by integrating
    1015             :     // the corresponding properties over the hemisphere
    1016             : 
    1017             :     static constexpr std::string_view RoutineName("RB_DIFF: ");
    1018             : 
    1019           6 :     Array1D<Real64> P(state.dataWindowEquivalentLayer->hipDIM);
    1020             :     Real64 SumRefAndTran; // sum of the reflectance and transmittance
    1021             : 
    1022           6 :     RHO_DD = RHO_BT0;
    1023           6 :     P(state.dataWindowEquivalentLayer->hipRHO_BT0) = RHO_BT0;
    1024           6 :     P(state.dataWindowEquivalentLayer->hipTAU_BT0) = TAU_BT0;
    1025           6 :     P(state.dataWindowEquivalentLayer->hipTAU_BB0) = TAU_BB0;
    1026             : 
    1027           6 :     TAU_DD = HEMINT(state, RB_F, 0, P);
    1028             : 
    1029           6 :     if (RHO_DD + TAU_DD > 1.0) {
    1030           0 :         SumRefAndTran = RHO_DD + TAU_DD;
    1031           0 :         ShowWarningMessage(state, format("{}Roller blind diffuse-diffuse properties are inconsistent", RoutineName));
    1032           0 :         ShowContinueError(state, format("...The diffuse-diffuse reflectance = {:.4T}", RHO_DD));
    1033           0 :         ShowContinueError(state, format("...The diffuse-diffuse tansmittance = {:.4T}", TAU_DD));
    1034           0 :         ShowContinueError(state, format("...Sum of diffuse reflectance and tansmittance = {:.4T}", SumRefAndTran));
    1035           0 :         ShowContinueError(state, "...This sum cannot be > 1.0. Transmittance will be reset to 1 minus reflectance");
    1036           0 :         TAU_DD = 1.0 - RHO_DD;
    1037             :     }
    1038           6 : }
    1039             : 
    1040          54 : Real64 RB_F(EnergyPlusData &state,
    1041             :             Real64 const THETA,             // incidence angle, radians
    1042             :             [[maybe_unused]] int const OPT, // options (unused)
    1043             :             const Array1D<Real64> &P        // parameters
    1044             : )
    1045             : {
    1046             :     //       AUTHOR         ASHRAE 1311-RP
    1047             :     //       DATE WRITTEN   unknown
    1048             :     //       MODIFIED       na
    1049             :     //       RE-ENGINEERED  na
    1050             : 
    1051             :     // PURPOSE OF THIS FUNCTION:
    1052             :     //  Roller blind integrand
    1053             : 
    1054             :     // Argument array dimensioning
    1055          54 :     EP_SIZE_CHECK(P, state.dataWindowEquivalentLayer->hipDIM);
    1056             : 
    1057             :     Real64 RHO_BD;
    1058             :     Real64 TAU_BB;
    1059             :     Real64 TAU_BD;
    1060             : 
    1061         162 :     RB_BEAM(state,
    1062             :             THETA,
    1063          54 :             P(state.dataWindowEquivalentLayer->hipRHO_BT0),
    1064          54 :             P(state.dataWindowEquivalentLayer->hipTAU_BT0),
    1065          54 :             P(state.dataWindowEquivalentLayer->hipTAU_BB0),
    1066             :             RHO_BD,
    1067             :             TAU_BB,
    1068             :             TAU_BD);
    1069             : 
    1070          54 :     return TAU_BB + TAU_BD;
    1071             : }
    1072             : 
    1073        1856 : void RB_BEAM(EnergyPlusData &state,
    1074             :              Real64 const xTHETA,  // angle of incidence, radians (0 - PI/2)
    1075             :              Real64 const RHO_BT0, // normal incidence beam-total front reflectance
    1076             :              Real64 const TAU_BT0, // normal incidence beam-total transmittance
    1077             :              Real64 const TAU_BB0, // normal incidence beam-beam transmittance
    1078             :              Real64 &RHO_BD,       // returned: beam-diffuse front reflectance
    1079             :              Real64 &TAU_BB,       // returned: beam-beam transmittance
    1080             :              Real64 &TAU_BD        // returned: beam-diffuse transmittance
    1081             : )
    1082             : {
    1083             :     // SUBROUTINE INFORMATION:
    1084             :     //       AUTHOR         John L. Wright, University of Waterloo,
    1085             :     //                      Mechanical Engineering, Advanced Glazing System Laboratory
    1086             :     //       DATE WRITTEN   Unknown
    1087             :     //       MODIFIED       na
    1088             :     //       RE-ENGINEERED  na
    1089             : 
    1090             :     // PURPOSE OF THIS SUBROUTINE:
    1091             :     // Calculates the roller blind off-normal properties using semi-empirical relations
    1092             : 
    1093             :     // SUBROUTINE ARGUMENT DEFINITIONS:
    1094             :     //   TAU_BT0 = TAU_BB0 + TAU_BD0
    1095             :     //   (openness)
    1096             : 
    1097             :     static constexpr std::string_view ContextName("RB_BEAM TauBD");
    1098             : 
    1099             :     Real64 THETA;        // working angle of incidence (limited < 90 deg)
    1100             :     Real64 TAUM0;        // apparent blind material transmittance at normal incidence
    1101             :     Real64 THETA_CUTOFF; // cutoff angle, radians (angle beyond which total transmittance goes to zero)
    1102             :     Real64 TAUBT_EXPO;   // exponent in the beam-total transmittance model
    1103             :     Real64 TAUBB_EXPO;   // exponent in the beam-beam transmittance model
    1104             :     Real64 TAU_BT;       // beam-total transmittance
    1105             : 
    1106        1856 :     THETA = min(89.99 * Constant::DegToRadians, xTHETA);
    1107             : 
    1108        1856 :     if (TAU_BB0 > 0.9999) {
    1109           0 :         TAU_BB = 1.0;
    1110           0 :         TAU_BT = 1.0;
    1111             :     } else {
    1112             :         // beam total
    1113        1856 :         TAUM0 = min(1.0, (TAU_BT0 - TAU_BB0) / (1.0 - TAU_BB0));
    1114        1856 :         if (TAUM0 <= 0.33) {
    1115        1022 :             TAUBT_EXPO = 0.133 * std::pow(TAUM0 + 0.003, -0.467);
    1116             :         } else {
    1117         834 :             TAUBT_EXPO = 0.33 * (1.0 - TAUM0);
    1118             :         }
    1119        1856 :         TAU_BT = TAU_BT0 * std::pow(std::cos(THETA), TAUBT_EXPO); // always 0 - 1
    1120             : 
    1121        1856 :         Real64 const cos_TAU_BB0(std::cos(TAU_BB0 * Constant::PiOvr2));
    1122        1856 :         THETA_CUTOFF = Constant::DegToRadians * (90.0 - 25.0 * cos_TAU_BB0);
    1123        1856 :         if (THETA >= THETA_CUTOFF) {
    1124        1166 :             TAU_BB = 0.0;
    1125             :         } else {
    1126         690 :             TAUBB_EXPO = 0.6 * std::pow(cos_TAU_BB0, 0.3);
    1127         690 :             TAU_BB = TAU_BB0 * std::pow(std::cos(Constant::PiOvr2 * THETA / THETA_CUTOFF), TAUBB_EXPO);
    1128             :             // BB correlation can produce results slightly larger than BT
    1129             :             // Enforce consistency
    1130         690 :             TAU_BB = min(TAU_BT, TAU_BB);
    1131             :         }
    1132             :     }
    1133             : 
    1134        1856 :     RHO_BD = RHO_BT0;
    1135        1856 :     TAU_BD = P01(state, TAU_BT - TAU_BB, ContextName);
    1136        1856 : }
    1137             : 
    1138           4 : void IS_DIFF(EnergyPlusData &state,
    1139             :              Real64 const RHO_BT0, // normal incidence beam-total reflectance
    1140             :              Real64 const TAU_BT0, // normal incidence beam-total transmittance
    1141             :              Real64 const TAU_BB0, // normal incidence beam-beam transmittance
    1142             :              Real64 &RHO_DD,       // returned: diffuse-diffuse reflectance
    1143             :              Real64 &TAU_DD        // returned: diffuse-diffuse transmittance
    1144             : )
    1145             : {
    1146             :     // SUBROUTINE INFORMATION:
    1147             :     //       AUTHOR         John L. Wright, University of Waterloo,
    1148             :     //                      Mechanical Engineering, Advanced Glazing System Laboratory
    1149             :     //       DATE WRITTEN   Unknown
    1150             :     //       MODIFIED       na
    1151             :     //       RE-ENGINEERED  na
    1152             : 
    1153             :     // PURPOSE OF THIS SUBROUTINE:
    1154             :     // Calculates insect screen diffuse-diffuse solar optical properties by integrating
    1155             :     // the corresponding properties over the hemisphere
    1156             : 
    1157             :     // SUBROUTINE ARGUMENT DEFINITIONS:
    1158             :     //   TAU_BT0 = TAU_BB0 + TAU_BD0
    1159           4 :     Array1D<Real64> P(state.dataWindowEquivalentLayer->hipDIM);
    1160             : 
    1161             :     static constexpr std::string_view RoutineName("IS_DIFF: ");
    1162             : 
    1163             :     Real64 SumRefAndTran;
    1164             : 
    1165           4 :     P(state.dataWindowEquivalentLayer->hipRHO_BT0) = RHO_BT0;
    1166           4 :     P(state.dataWindowEquivalentLayer->hipTAU_BT0) = TAU_BT0;
    1167           4 :     P(state.dataWindowEquivalentLayer->hipTAU_BB0) = TAU_BB0;
    1168             : 
    1169           4 :     RHO_DD = HEMINT(state, IS_F, state.dataWindowEquivalentLayer->hipRHO, P);
    1170           4 :     TAU_DD = HEMINT(state, IS_F, state.dataWindowEquivalentLayer->hipTAU, P);
    1171             : 
    1172           4 :     if (RHO_DD + TAU_DD > 1.0) {
    1173           0 :         SumRefAndTran = RHO_DD + TAU_DD;
    1174           0 :         ShowWarningMessage(state, format("{}Calculated insect screen diffuse-diffuse properties are inconsistent", RoutineName));
    1175           0 :         ShowContinueError(state, format("...The diffuse-diffuse reflectance = {:.4T}", RHO_DD));
    1176           0 :         ShowContinueError(state, format("...The diffuse-diffuse tansmittance = {:.4T}", TAU_DD));
    1177           0 :         ShowContinueError(state, format("...Sum of diffuse reflectance and tansmittance = {:.4T}", SumRefAndTran));
    1178           0 :         ShowContinueError(state, "...This sum cannot be > 1.0. Transmittance will be reset to 1 minus reflectance");
    1179           0 :         TAU_DD = 1.0 - RHO_DD;
    1180             :     }
    1181           4 : }
    1182             : 
    1183          72 : Real64 IS_F(EnergyPlusData &state,
    1184             :             Real64 const THETA,      // incidence angle, radians
    1185             :             int const OPT,           // options (1=reflectance, 2=transmittance)
    1186             :             const Array1D<Real64> &P // parameters
    1187             : )
    1188             : {
    1189             :     //       AUTHOR         ASHRAE 1311-RP
    1190             :     //       DATE WRITTEN   unknown
    1191             :     //       MODIFIED       na
    1192             :     //       RE-ENGINEERED  na
    1193             : 
    1194             :     // PURPOSE OF THIS FUNCTION:
    1195             :     //  Insect screen integrand
    1196             : 
    1197             :     // Return value
    1198             :     Real64 IS_F;
    1199             : 
    1200             :     // Argument array dimensioning
    1201          72 :     EP_SIZE_CHECK(P, state.dataWindowEquivalentLayer->hipDIM);
    1202             : 
    1203             :     Real64 RHO_BD;
    1204             :     Real64 TAU_BB;
    1205             :     Real64 TAU_BD;
    1206             : 
    1207         216 :     IS_BEAM(state,
    1208             :             THETA,
    1209          72 :             P(state.dataWindowEquivalentLayer->hipRHO_BT0),
    1210          72 :             P(state.dataWindowEquivalentLayer->hipTAU_BT0),
    1211          72 :             P(state.dataWindowEquivalentLayer->hipTAU_BB0),
    1212             :             RHO_BD,
    1213             :             TAU_BB,
    1214             :             TAU_BD);
    1215             : 
    1216          72 :     if (OPT == state.dataWindowEquivalentLayer->hipRHO) {
    1217          36 :         IS_F = RHO_BD;
    1218          36 :     } else if (OPT == state.dataWindowEquivalentLayer->hipTAU) {
    1219          36 :         IS_F = TAU_BB + TAU_BD;
    1220             :     } else {
    1221           0 :         IS_F = -1.0;
    1222             :     }
    1223          72 :     return IS_F;
    1224             : }
    1225             : 
    1226         890 : void IS_BEAM(EnergyPlusData &state,
    1227             :              Real64 const xTHETA,  // incidence angle, radians (0 - PI/2)
    1228             :              Real64 const RHO_BT0, // beam-total reflectance
    1229             :              Real64 const TAU_BT0, // beam-total transmittance at normal incidence
    1230             :              Real64 const TAU_BB0, // beam-beam transmittance at normal incidence
    1231             :              Real64 &RHO_BD,       // returned: beam-diffuse reflectance
    1232             :              Real64 &TAU_BB,       // returned: beam-beam transmittance
    1233             :              Real64 &TAU_BD        // returned: beam-diffuse transmittance
    1234             : )
    1235             : {
    1236             :     // SUBROUTINE INFORMATION:
    1237             :     //       AUTHOR         John L. Wright, University of Waterloo,
    1238             :     //                      Mechanical Engineering, Advanced Glazing System Laboratory
    1239             :     //       DATE WRITTEN   Unknown
    1240             :     //       MODIFIED       na
    1241             :     //       RE-ENGINEERED  na
    1242             : 
    1243             :     // PURPOSE OF THIS SUBROUTINE:
    1244             :     // Calculates insect screen off-normal solar optical properties
    1245             :     // using semi-empirical relations.
    1246             : 
    1247             :     // SUBROUTINE ARGUMENT DEFINITIONS:
    1248             :     //   TAU_BTO = TAU_BB0 + TAU_BD0
    1249             : 
    1250             :     static constexpr std::string_view RhoBD_Name("IS_BEAM RhoBD");
    1251             :     static constexpr std::string_view TauBB_Name("IS_BEAM TauBB");
    1252             :     static constexpr std::string_view TauBT_Name("IS_BEAM TauBT");
    1253             :     static constexpr std::string_view TauBD_Name("IS_BEAM TauBD");
    1254             : 
    1255             :     Real64 THETA_CUTOFF; // cutoff angle, radians (beyond which TAU_BB = 0)
    1256             :     Real64 B;            // working temp
    1257             :     Real64 RHO_W;        // apparent wire reflectance
    1258             :     Real64 RHO_BT90;     // beam-total reflectance at 90 deg incidence
    1259             :     Real64 TAU_BT;       // beam-total transmittance
    1260             : 
    1261         890 :     Real64 const THETA(min(89.99 * Constant::DegToRadians, xTHETA)); // working incident angle, radians
    1262         890 :     Real64 const COSTHETA(std::cos(THETA));
    1263             : 
    1264         890 :     RHO_W = RHO_BT0 / max(0.00001, 1.0 - TAU_BB0);
    1265         890 :     B = -0.45 * std::log(max(RHO_W, 0.01));
    1266             : 
    1267         890 :     RHO_BT90 = RHO_BT0 + (1.0 - RHO_BT0) * (0.35 * RHO_W);
    1268             : 
    1269         890 :     RHO_BD = P01(state, RHO_BT0 + (RHO_BT90 - RHO_BT0) * (1.0 - std::pow(COSTHETA, B)), RhoBD_Name);
    1270             : 
    1271         890 :     if (TAU_BT0 < 0.00001) {
    1272           0 :         TAU_BB = 0.0;
    1273           0 :         TAU_BT = 0.0;
    1274             :     } else {
    1275         890 :         THETA_CUTOFF = std::acos(IS_DSRATIO(TAU_BB0));
    1276             : 
    1277         890 :         if (THETA >= THETA_CUTOFF) {
    1278          64 :             TAU_BB = 0.0;
    1279             :         } else {
    1280         826 :             B = -0.45 * std::log(max(TAU_BB0, 0.01)) + 0.1;
    1281         826 :             TAU_BB = P01(state, TAU_BB0 * std::pow(std::cos(Constant::PiOvr2 * THETA / THETA_CUTOFF), B), TauBB_Name);
    1282             :         }
    1283             : 
    1284         890 :         B = -0.65 * std::log(max(TAU_BT0, 0.01)) + 0.1;
    1285         890 :         TAU_BT = P01(state, TAU_BT0 * std::pow(COSTHETA, B), TauBT_Name);
    1286             :     }
    1287             : 
    1288         890 :     TAU_BD = P01(state, TAU_BT - TAU_BB, TauBD_Name);
    1289         890 : }
    1290             : 
    1291           0 : Real64 IS_OPENNESS(Real64 const D, // wire diameter
    1292             :                    Real64 const S  // wire spacing
    1293             : )
    1294             : {
    1295             :     //       AUTHOR         ASHRAE 1311-RP
    1296             :     //       DATE WRITTEN   unknown
    1297             :     //       MODIFIED       na
    1298             :     //       RE-ENGINEERED  na
    1299             : 
    1300             :     // PURPOSE OF THIS FUNCTION:
    1301             :     //  Returns openness from wire geometry.
    1302             : 
    1303           0 :     if (S > 0.0) {
    1304           0 :         return pow_2(max(S - D, 0.0) / S);
    1305             :     } else {
    1306           0 :         return 0.0;
    1307             :     }
    1308             : }
    1309             : 
    1310         890 : Real64 IS_DSRATIO(Real64 const OPENNESS) // openness
    1311             : {
    1312             :     //       AUTHOR         ASHRAE 1311-RP
    1313             :     //       DATE WRITTEN   unknown
    1314             :     //       MODIFIED       na
    1315             :     //       RE-ENGINEERED  na
    1316             : 
    1317             :     // PURPOSE OF THIS FUNCTION:
    1318             :     //  Returns ratio of diameter to spacing
    1319             : 
    1320         890 :     if (OPENNESS > 0.0) {
    1321         890 :         return 1.0 - min(std::sqrt(OPENNESS), 1.0);
    1322             :     } else {
    1323           0 :         return 0.0;
    1324             :     }
    1325             : }
    1326             : 
    1327           0 : void FM_DIFF(EnergyPlusData &state,
    1328             :              Real64 const RHO_BT0, // fabric beam-total reflectance at normal incidence
    1329             :              Real64 const TAU_BT0, // fabric beam-total transmittance at normal incidence
    1330             :              Real64 const TAU_BB0, // forward facing fabric beam-beam transmittance at normal incidence
    1331             :              Real64 &RHO_DD,       // returned: fabric diffuse-diffuse reflectance
    1332             :              Real64 &TAU_DD        // returned: fabric diffuse-diffuse transmittance
    1333             : )
    1334             : {
    1335             :     // SUBROUTINE INFORMATION:
    1336             :     //       AUTHOR         John L. Wright, University of Waterloo,
    1337             :     //                      Mechanical Engineering, Advanced Glazing System Laboratory
    1338             :     //       DATE WRITTEN   Unknown
    1339             :     //       MODIFIED       na
    1340             :     //       RE-ENGINEERED  na
    1341             : 
    1342             :     // PURPOSE OF THIS SUBROUTINE:
    1343             :     // Calculates drape fabric diffuse-diffuse solar optical properties by integrating
    1344             :     // the corresponding beam properties over the hemisphere.
    1345             : 
    1346             :     // SUBROUTINE ARGUMENT DEFINITIONS:
    1347             :     //   (TAU_BT0 = TAU_BB0 + TAU_BD0)
    1348             :     // SUBROUTINE PARAMETER DEFINITIONS:
    1349             :     static constexpr std::string_view RoutineName("FM_DIFF: ");
    1350             : 
    1351             :     Real64 TAU_BD0;
    1352           0 :     Array1D<Real64> P(state.dataWindowEquivalentLayer->hipDIM);
    1353             :     Real64 SumRefAndTran;
    1354             : 
    1355           0 :     TAU_BD0 = TAU_BT0 - TAU_BB0;
    1356             : 
    1357           0 :     P(state.dataWindowEquivalentLayer->hipRHO_BT0) = RHO_BT0;
    1358           0 :     P(state.dataWindowEquivalentLayer->hipTAU_BT0) = TAU_BT0;
    1359           0 :     P(state.dataWindowEquivalentLayer->hipTAU_BB0) = TAU_BB0;
    1360             : 
    1361           0 :     RHO_DD = HEMINT(state, FM_F, state.dataWindowEquivalentLayer->hipRHO, P);
    1362           0 :     TAU_DD = HEMINT(state, FM_F, state.dataWindowEquivalentLayer->hipTAU, P);
    1363             : 
    1364           0 :     if (RHO_DD + TAU_DD > 1.0) {
    1365           0 :         SumRefAndTran = RHO_DD + TAU_DD;
    1366           0 :         ShowWarningMessage(state, format("{}Calculated drape fabric diffuse-diffuse properties are inconsistent", RoutineName));
    1367           0 :         ShowContinueError(state, format("...The diffuse-diffuse reflectance = {:.4T}", RHO_DD));
    1368           0 :         ShowContinueError(state, format("...The diffuse-diffuse tansmittance = {:.4T}", TAU_DD));
    1369           0 :         ShowContinueError(state, format("...Sum of diffuse reflectance and tansmittance = {:.4T}", SumRefAndTran));
    1370           0 :         ShowContinueError(state, "...This sum cannot be > 1.0. Transmittance will be reset to 1 minus reflectance");
    1371           0 :         TAU_DD = 1.0 - RHO_DD;
    1372             :     }
    1373           0 : }
    1374             : 
    1375           0 : Real64 FM_F(EnergyPlusData &state,
    1376             :             Real64 const THETA,      // incidence angle, radians
    1377             :             int const Opt,           // options (hipRHO, hipTAU)
    1378             :             const Array1D<Real64> &P // parameters
    1379             : )
    1380             : {
    1381             :     //       AUTHOR         ASHRAE 1311-RP
    1382             :     //       DATE WRITTEN   unknown
    1383             :     //       MODIFIED       na
    1384             :     //       RE-ENGINEERED  na
    1385             : 
    1386             :     // PURPOSE OF THIS FUNCTION:
    1387             :     //  Drape fabric property integrand.
    1388             : 
    1389             :     // Return value
    1390             :     Real64 FM_F;
    1391             : 
    1392             :     // Argument array dimensioning
    1393           0 :     EP_SIZE_CHECK(P, state.dataWindowEquivalentLayer->hipDIM);
    1394             : 
    1395             :     Real64 RHO_BD;
    1396             :     Real64 TAU_BB;
    1397             :     Real64 TAU_BD;
    1398             : 
    1399           0 :     FM_BEAM(state,
    1400             :             THETA,
    1401           0 :             P(state.dataWindowEquivalentLayer->hipRHO_BT0),
    1402           0 :             P(state.dataWindowEquivalentLayer->hipTAU_BT0),
    1403           0 :             P(state.dataWindowEquivalentLayer->hipTAU_BB0),
    1404             :             RHO_BD,
    1405             :             TAU_BB,
    1406             :             TAU_BD);
    1407             : 
    1408           0 :     if (Opt == state.dataWindowEquivalentLayer->hipRHO) {
    1409           0 :         FM_F = RHO_BD;
    1410           0 :     } else if (Opt == state.dataWindowEquivalentLayer->hipTAU) {
    1411           0 :         FM_F = TAU_BB + TAU_BD;
    1412             :     } else {
    1413           0 :         FM_F = -1.0;
    1414             :     }
    1415           0 :     return FM_F;
    1416             : }
    1417             : 
    1418           0 : void FM_BEAM(EnergyPlusData &state,
    1419             :              Real64 const xTHETA,  // incidence angle, radians (0 - PI/2)
    1420             :              Real64 const RHO_BT0, // fabric beam-total reflectance
    1421             :              Real64 const TAU_BT0, // fabric beam-total transmittance at normal incidence
    1422             :              Real64 const TAU_BB0, // fabric beam-beam transmittance at normal incidence
    1423             :              Real64 &RHO_BD,       // returned: fabric beam-diffuse reflectance
    1424             :              Real64 &TAU_BB,       // returned: fabric beam-beam transmittance
    1425             :              Real64 &TAU_BD        // returned: fabric beam-diffuse transmittance
    1426             : )
    1427             : {
    1428             : 
    1429             :     // SUBROUTINE INFORMATION:
    1430             :     //       AUTHOR         John L. Wright, University of Waterloo,
    1431             :     //                      Mechanical Engineering, Advanced Glazing System Laboratory
    1432             :     //       DATE WRITTEN   Unknown
    1433             :     //       MODIFIED       na
    1434             :     //       RE-ENGINEERED  na
    1435             : 
    1436             :     // PURPOSE OF THIS SUBROUTINE:
    1437             :     // Calculates the solar optical properties of a fabric for beam radiation incident
    1438             :     // on the forward facingsurface using optical properties at normal incidence and
    1439             :     // semi-empirical relations.
    1440             : 
    1441             :     // SUBROUTINE ARGUMENT DEFINITIONS:
    1442             :     //   TAU_BTO = TAU_BB0 + TAU_BD0
    1443             :     //   = openness
    1444             : 
    1445             :     Real64 THETA; // working incident angle, radians
    1446             :     Real64 R;     // working temps
    1447             :     Real64 B;
    1448             :     Real64 RHO_Y;    // apparent yarn reflectance
    1449             :     Real64 RHO_BT90; // beam-total reflectance at 90 deg incidence
    1450             :     Real64 TAU_BT;   // beam-total transmittance
    1451             : 
    1452           0 :     THETA = std::abs(max(-89.99 * Constant::DegToRadians, min(89.99 * Constant::DegToRadians, xTHETA)));
    1453             :     // limit -89.99 - +89.99
    1454             :     // by symmetry, optical properties same at +/- theta
    1455           0 :     Real64 const COSTHETA(std::cos(THETA));
    1456             : 
    1457           0 :     RHO_Y = RHO_BT0 / max(0.00001, 1.0 - TAU_BB0);
    1458           0 :     R = 0.7 * std::pow(RHO_Y, 0.7);
    1459           0 :     RHO_BT90 = RHO_BT0 + (1.0 - RHO_BT0) * R;
    1460           0 :     B = 0.6;
    1461           0 :     RHO_BD = P01(state, RHO_BT0 + (RHO_BT90 - RHO_BT0) * (1.0 - std::pow(COSTHETA, B)), "FM_BEAM RhoBD");
    1462             : 
    1463           0 :     if (TAU_BT0 < 0.00001) {
    1464           0 :         TAU_BB = 0.0;
    1465           0 :         TAU_BD = 0.0;
    1466             :     } else {
    1467           0 :         B = max(-0.5 * std::log(max(TAU_BB0, 0.01)), 0.35);
    1468           0 :         TAU_BB = TAU_BB0 * std::pow(COSTHETA, B);
    1469             : 
    1470           0 :         B = max(-0.5 * std::log(max(TAU_BT0, 0.01)), 0.35);
    1471           0 :         TAU_BT = TAU_BT0 * std::pow(COSTHETA, B);
    1472             : 
    1473           0 :         TAU_BD = P01(state, TAU_BT - TAU_BB, "FM_BEAM TauBD");
    1474             :     }
    1475           0 : }
    1476             : 
    1477           0 : void PD_LW(EnergyPlusData &state,
    1478             :            Real64 const S,               // pleat spacing (> 0)
    1479             :            Real64 const W,               // pleat depth (>=0, same units as S)
    1480             :            Real64 const OPENNESS_FABRIC, // fabric openness, 0-1 (=tausbb at normal incidence)
    1481             :            Real64 const EPSLWF0_FABRIC,  // fabric LW front emittance at 0 openness
    1482             :            Real64 const EPSLWB0_FABRIC,  // fabric LW back emittance at 0 openness
    1483             :            Real64 const TAULW0_FABRIC,   // fabric LW transmittance at 0 openness
    1484             :            Real64 &EPSLWF_PD,            // returned: drape front effective LW emittance
    1485             :            Real64 &TAULW_PD              // returned: drape effective LW transmittance
    1486             : )
    1487             : {
    1488             : 
    1489             :     // SUBROUTINE INFORMATION:
    1490             :     //       AUTHOR         John L. Wright, University of Waterloo,
    1491             :     //                      Mechanical Engineering, Advanced Glazing System Laboratory
    1492             :     //       DATE WRITTEN   Unknown
    1493             :     //       MODIFIED       na
    1494             :     //       RE-ENGINEERED  na
    1495             : 
    1496             :     // PURPOSE OF THIS SUBROUTINE:
    1497             :     //  Calculates the effective longwave emittance and transmittance of a drapery layer
    1498             : 
    1499             :     // SUBROUTINE ARGUMENT DEFINITIONS:
    1500             :     //    typical (default) = 0.92
    1501             :     //    typical (default) = 0.92
    1502             :     //    nearly always 0
    1503             :     static constexpr std::string_view RhoLWF_Name("PD_LW RhoLWF");
    1504             :     static constexpr std::string_view RhoLWB_Name("PD_LW RhoLWB");
    1505             :     static constexpr std::string_view EpsLWF_Name("PD_LW EpsLWF");
    1506             : 
    1507             :     Real64 RHOLWF_FABRIC;
    1508             :     Real64 RHOLWB_FABRIC;
    1509             :     Real64 TAULW_FABRIC;
    1510             :     Real64 EPSLWF_FABRIC;
    1511             :     Real64 EPSLWB_FABRIC;
    1512             :     Real64 TAULX;
    1513             :     Real64 RHOLWF_PD;
    1514             : 
    1515           0 :     OPENNESS_LW(OPENNESS_FABRIC, EPSLWF0_FABRIC, TAULW0_FABRIC, EPSLWF_FABRIC, TAULW_FABRIC);
    1516           0 :     OPENNESS_LW(OPENNESS_FABRIC, EPSLWB0_FABRIC, TAULW0_FABRIC, EPSLWB_FABRIC, TAULX);
    1517             : 
    1518           0 :     RHOLWF_FABRIC = P01(state, 1.0 - EPSLWF_FABRIC - TAULW_FABRIC, RhoLWF_Name);
    1519           0 :     RHOLWB_FABRIC = P01(state, 1.0 - EPSLWB_FABRIC - TAULW_FABRIC, RhoLWB_Name);
    1520             : 
    1521           0 :     PD_DIFF(state, S, W, RHOLWF_FABRIC, RHOLWB_FABRIC, TAULW_FABRIC, RHOLWF_PD, TAULW_PD);
    1522             : 
    1523           0 :     EPSLWF_PD = P01(state, 1.0 - TAULW_PD - RHOLWF_PD, EpsLWF_Name);
    1524           0 : }
    1525             : 
    1526           0 : void PD_DIFF(EnergyPlusData &state,
    1527             :              Real64 const S,        // pleat spacing (> 0)
    1528             :              Real64 const W,        // pleat depth (>=0, same units as S)
    1529             :              Real64 const RHOFF_DD, // fabric front diffuse-diffuse reflectance
    1530             :              Real64 const RHOBF_DD, // fabric back diffuse-diffuse reflectance
    1531             :              Real64 const TAUF_DD,  // fabric diffuse-diffuse transmittance
    1532             :              Real64 &RHOFDD,        // returned: drape diffuse-diffuse reflectance
    1533             :              Real64 &TAUFDD         // returned: drape diffuse-diffuse transmittance
    1534             : )
    1535             : {
    1536             :     // SUBROUTINE INFORMATION:
    1537             :     //       AUTHOR         John L. Wright, University of Waterloo,
    1538             :     //                      Mechanical Engineering, Advanced Glazing System Laboratory
    1539             :     //       DATE WRITTEN   Unknown
    1540             :     //       MODIFIED       na
    1541             :     //       RE-ENGINEERED  na
    1542             : 
    1543             :     // PURPOSE OF THIS SUBROUTINE:
    1544             :     //  Calculates the effective diffuse transmittance and reflectance of a drapery layer.
    1545             :     //  Used for both LW and solar diffuse.
    1546             :     // METHODOLOGY EMPLOYED:
    1547             :     // Eight surface flat-fabric model with rectangular enclosure. If you want the back-side
    1548             :     // reflectance call this routine a second time with reversed front and back properties
    1549             : 
    1550           0 :     constexpr int N(6);
    1551             :     static constexpr std::string_view TauDD_Name("PD_DIFF TauDD");
    1552             :     static constexpr std::string_view RhoDD_Name("PD_DIFF RhoDD");
    1553             : 
    1554             :     Real64 AK; // length of diagonal strings of the rectangular enclosure
    1555             :     Real64 CG;
    1556             :     Real64 F12; // shape factors
    1557             :     Real64 F14;
    1558             :     Real64 F32;
    1559             :     Real64 F21;
    1560             :     Real64 F31;
    1561             :     Real64 F34;
    1562             :     Real64 F24;
    1563             :     Real64 F41;
    1564             :     Real64 F42;
    1565             :     Real64 F57;
    1566             :     Real64 F56;
    1567             :     Real64 F58;
    1568             :     Real64 F67;
    1569             :     Real64 F65;
    1570             :     Real64 F68;
    1571             :     Real64 F75;
    1572             :     Real64 F76;
    1573             :     Real64 F78;
    1574             :     Real64 F85;
    1575             :     Real64 F87;
    1576             :     Real64 F86;
    1577             :     Real64 J1; // radiosity, surface i
    1578             :     Real64 J2;
    1579             :     Real64 J4;
    1580             :     Real64 J7;
    1581             :     Real64 J6;
    1582             :     Real64 J8;
    1583             :     Real64 G1; // irradiance, surface i
    1584             :     Real64 G3;
    1585             :     Real64 G5;
    1586             :     Real64 G7;
    1587           0 :     Array2D<Real64> A(N + 2, N);
    1588           0 :     Array1D<Real64> XSOL(N);
    1589             : 
    1590           0 :     if (W / S < state.dataWindowEquivalentLayer->SMALL_ERROR) {
    1591             :         // flat drape (no pleats)
    1592           0 :         RHOFDD = RHOFF_DD;
    1593           0 :         TAUFDD = TAUF_DD;
    1594           0 :         return;
    1595             :     }
    1596             : 
    1597             :     // SOLVE FOR DIAGONAL STRINGS AND SHAPE FACTORS
    1598             : 
    1599           0 :     AK = std::sqrt(S * S + W * W);
    1600           0 :     CG = AK;
    1601           0 :     F12 = (S + W - AK) / (2.0 * S);
    1602           0 :     F14 = (S + W - CG) / (2.0 * S);
    1603           0 :     F32 = F14;
    1604           0 :     F31 = (AK + CG - 2.0 * W) / (2.0 * S);
    1605           0 :     F34 = F12;
    1606           0 :     F21 = (S + W - AK) / (2.0 * W);
    1607           0 :     F24 = (AK + CG - 2.0 * S) / (2.0 * W);
    1608           0 :     F41 = (S + W - CG) / (2.0 * W);
    1609           0 :     F42 = F24;
    1610           0 :     F57 = F31;
    1611           0 :     F56 = F12;
    1612           0 :     F58 = F14;
    1613           0 :     F75 = F31;
    1614           0 :     F76 = F32;
    1615           0 :     F78 = F34;
    1616           0 :     F67 = F41;
    1617           0 :     F65 = F21;
    1618           0 :     F68 = F24;
    1619           0 :     F85 = F41;
    1620           0 :     F87 = F21;
    1621           0 :     F86 = F42;
    1622             : 
    1623           0 :     A = 0.0;    // INITIALIZE RADIOSITY MATRIX COEFFICIENTS
    1624           0 :     XSOL = 0.0; // INITIALIZE SOLUTION VECTOR COEFFICIENTS
    1625             : 
    1626             :     // POPULATE THE COEFFICIENTS OF THE RADIOSITY MATRIX
    1627             : 
    1628           0 :     A(1, 1) = 1.0;
    1629           0 :     A(2, 1) = -RHOBF_DD * F12;
    1630           0 :     A(3, 1) = -RHOBF_DD * F14;
    1631           0 :     A(4, 1) = 0.0;
    1632           0 :     A(5, 1) = 0.0;
    1633           0 :     A(6, 1) = 0.0;
    1634           0 :     A(7, 1) = TAUF_DD;
    1635           0 :     A(1, 2) = -RHOBF_DD * F21;
    1636           0 :     A(2, 2) = 1.0;
    1637           0 :     A(3, 2) = -RHOBF_DD * F24;
    1638           0 :     A(4, 2) = -TAUF_DD * F87;
    1639           0 :     A(5, 2) = -TAUF_DD * F86;
    1640           0 :     A(6, 2) = 0.0;
    1641           0 :     A(7, 2) = TAUF_DD * F85;
    1642           0 :     A(1, 3) = -RHOBF_DD * F41;
    1643           0 :     A(2, 3) = -RHOBF_DD * F42;
    1644           0 :     A(3, 3) = 1.0;
    1645           0 :     A(4, 3) = -TAUF_DD * F67;
    1646           0 :     A(5, 3) = 0.0;
    1647           0 :     A(6, 3) = -TAUF_DD * F68;
    1648           0 :     A(7, 3) = TAUF_DD * F65;
    1649           0 :     A(1, 4) = 0.0;
    1650           0 :     A(2, 4) = 0.0;
    1651           0 :     A(3, 4) = 0.0;
    1652           0 :     A(4, 4) = 1.0;
    1653           0 :     A(5, 4) = -RHOFF_DD * F76;
    1654           0 :     A(6, 4) = -RHOFF_DD * F78;
    1655           0 :     A(7, 4) = RHOFF_DD * F75;
    1656           0 :     A(1, 5) = -TAUF_DD * F41;
    1657           0 :     A(2, 5) = -TAUF_DD * F42;
    1658           0 :     A(3, 5) = 0.0;
    1659           0 :     A(4, 5) = -RHOFF_DD * F67;
    1660           0 :     A(5, 5) = 1.0;
    1661           0 :     A(6, 5) = -RHOFF_DD * F68;
    1662           0 :     A(7, 5) = RHOFF_DD * F65;
    1663           0 :     A(1, 6) = -TAUF_DD * F21;
    1664           0 :     A(2, 6) = 0.0;
    1665           0 :     A(3, 6) = -TAUF_DD * F24;
    1666           0 :     A(4, 6) = -RHOFF_DD * F87;
    1667           0 :     A(5, 6) = -RHOFF_DD * F86;
    1668           0 :     A(6, 6) = 1.0;
    1669           0 :     A(7, 6) = RHOFF_DD * F85;
    1670             : 
    1671           0 :     SOLMATS(N, A, XSOL);
    1672             : 
    1673           0 :     J1 = XSOL(1);
    1674           0 :     J2 = XSOL(2);
    1675           0 :     J4 = XSOL(3);
    1676           0 :     J7 = XSOL(4);
    1677           0 :     J6 = XSOL(5);
    1678           0 :     J8 = XSOL(6);
    1679             : 
    1680           0 :     G1 = F12 * J2 + F14 * J4;
    1681           0 :     G3 = F32 * J2 + F31 * J1 + F34 * J4;
    1682           0 :     G5 = F57 * J7 + F56 * J6 + F58 * J8;
    1683           0 :     G7 = F75 + F76 * J6 + F78 * J8;
    1684             : 
    1685           0 :     TAUFDD = P01(state, (G3 + TAUF_DD * G7) / 2.0, TauDD_Name);
    1686           0 :     RHOFDD = P01(state, (RHOFF_DD + TAUF_DD * G1 + G5) / 2.0, RhoDD_Name);
    1687           0 : }
    1688             : 
    1689           0 : void PD_BEAM(EnergyPlusData &state,
    1690             :              Real64 const S,         // pleat spacing (> 0)
    1691             :              Real64 const W,         // pleat depth (>=0, same units as S)
    1692             :              Real64 const OHM_V_RAD, // vertical profile angle, radians +=above horiz
    1693             :              Real64 const OHM_H_RAD, // horizontal profile angle, radians=clockwise when viewed from above
    1694             :              Real64 const RHOFF_BT0, // beam total reflectance front (outside)
    1695             :              Real64 const TAUFF_BB0, // beam beam transmittance front (outside)
    1696             :              Real64 const TAUFF_BD0, // beam diffuse transmittance front (outside)
    1697             :              Real64 const RHOFF_DD,  // diffuse-diffuse reflectance front (outside)
    1698             :              Real64 const TAUFF_DD,  // diffuse-diffuse transmittance front (outside)
    1699             :              Real64 const RHOBF_BT0, // beam total reflectance back (inside)
    1700             :              Real64 const TAUBF_BB0, // beam beam total transmittance back (inside)
    1701             :              Real64 const TAUBF_BD0, // beam diffuse transmittance back (inside)
    1702             :              Real64 const RHOBF_DD,  // diffuse-diffuse reflectance front (outside)
    1703             :              Real64 const TAUBF_DD,  // diffuse-diffuse transmittance front (outside)
    1704             :              Real64 &RHO_BD,         // returned: drape front beam-diffuse reflectance
    1705             :              Real64 &TAU_BB,         // returned: drape beam-beam transmittance
    1706             :              Real64 &TAU_BD          // returned: drape beam-diffuse transmittance
    1707             : )
    1708             : {
    1709             :     // SUBROUTINE INFORMATION:
    1710             :     //       AUTHOR         John L. Wright, University of Waterloo,
    1711             :     //                      Mechanical Engineering, Advanced Glazing System Laboratory
    1712             :     //       DATE WRITTEN   Unknown
    1713             :     //       MODIFIED       na
    1714             :     //       RE-ENGINEERED  na
    1715             : 
    1716             :     // PURPOSE OF THIS SUBROUTINE:
    1717             :     //  calculates the effective front-side solar optical properties of a drapery layer.
    1718             :     // METHODOLOGY EMPLOYED:
    1719             :     // Pleated drape flat-fabric model with rectangular enclosure
    1720             : 
    1721             :     Real64 DE; // length of directly illuminated surface on side of pleat that
    1722             :     //   is open on front (same units as S and W)
    1723             :     Real64 EF;      // length of pleat side shaded surface (W-DE) (same units as S and W)
    1724             :     Real64 OMEGA_V; // profile angles limited to +/- PI/2
    1725             :     Real64 OMEGA_H;
    1726             :     Real64 TAUFF_BT0;
    1727             :     Real64 TAUBF_BT0;
    1728             :     Real64 THETA_PARL; // beam incidence angles on pleat surface parallel / perpendicular
    1729             :     Real64 THETA_PERP;
    1730             :     // to window plane
    1731             :     Real64 RHOFF_BT_PARL;
    1732             :     Real64 TAUFF_BB_PARL;
    1733             :     Real64 TAUFF_BD_PARL;
    1734             :     Real64 RHOBF_BT_PARL;
    1735             :     Real64 TAUBF_BB_PARL;
    1736             :     Real64 TAUBF_BD_PARL;
    1737             :     Real64 RHOFF_BT_PERP;
    1738             :     Real64 TAUFF_BB_PERP;
    1739             :     Real64 TAUFF_BD_PERP;
    1740             :     Real64 RHOBF_BT_PERP;
    1741             :     Real64 TAUBF_BB_PERP;
    1742             :     Real64 TAUBF_BD_PERP;
    1743             : 
    1744           0 :     OMEGA_V = std::abs(max(-89.5 * Constant::DegToRadians, min(89.5 * Constant::DegToRadians, OHM_V_RAD)));
    1745           0 :     OMEGA_H = std::abs(max(-89.5 * Constant::DegToRadians, min(89.5 * Constant::DegToRadians, OHM_H_RAD)));
    1746             :     // limit profile angles -89.5 - +89.5
    1747             :     // by symmetry, properties same for +/- profile angle
    1748             : 
    1749             :     // incidence angles on pleat front/back (_PARL) and sides (_PERP)
    1750           0 :     Real64 const tan_OMEGA_V(std::tan(OMEGA_V));
    1751           0 :     Real64 const cos_OMEGA_H(std::cos(OMEGA_H));
    1752           0 :     Real64 const sin_OMEGA_H(std::sin(OMEGA_H));
    1753           0 :     THETA_PARL = std::acos(std::abs(std::cos(std::atan(tan_OMEGA_V * cos_OMEGA_H)) * cos_OMEGA_H));
    1754           0 :     THETA_PERP = std::acos(std::abs(std::cos(std::atan(tan_OMEGA_V * sin_OMEGA_H)) * sin_OMEGA_H));
    1755             : 
    1756             :     // off-normal fabric properties, front surface
    1757           0 :     TAUFF_BT0 = TAUFF_BB0 + TAUFF_BD0;
    1758           0 :     FM_BEAM(state, THETA_PARL, RHOFF_BT0, TAUFF_BT0, TAUFF_BB0, RHOFF_BT_PARL, TAUFF_BB_PARL, TAUFF_BD_PARL);
    1759           0 :     if (W / S < state.dataWindowEquivalentLayer->SMALL_ERROR) {
    1760             :         // flat drape (no pleats) -- return fabric properties
    1761           0 :         RHO_BD = RHOFF_BT_PARL;
    1762           0 :         TAU_BD = TAUFF_BD_PARL;
    1763           0 :         TAU_BB = TAUFF_BB_PARL;
    1764           0 :         return;
    1765             :     }
    1766             : 
    1767           0 :     FM_BEAM(state, THETA_PERP, RHOFF_BT0, TAUFF_BT0, TAUFF_BB0, RHOFF_BT_PERP, TAUFF_BB_PERP, TAUFF_BD_PERP);
    1768             : 
    1769             :     // Off-normal fabric properties, back surface
    1770           0 :     TAUBF_BT0 = TAUBF_BB0 + TAUBF_BD0;
    1771           0 :     FM_BEAM(state, THETA_PARL, RHOBF_BT0, TAUBF_BT0, TAUBF_BB0, RHOBF_BT_PARL, TAUBF_BB_PARL, TAUBF_BD_PARL);
    1772           0 :     FM_BEAM(state, THETA_PERP, RHOBF_BT0, TAUBF_BT0, TAUBF_BB0, RHOBF_BT_PERP, TAUBF_BB_PERP, TAUBF_BD_PERP);
    1773             : 
    1774           0 :     DE = S * std::abs(cos_OMEGA_H / max(0.000001, sin_OMEGA_H));
    1775           0 :     EF = W - DE;
    1776             : 
    1777             :     // select geometric case
    1778           0 :     if (DE < W - state.dataWindowEquivalentLayer->SMALL_ERROR) {
    1779             :         // illuminated length less than pleat depth
    1780           0 :         if (DE < EF - state.dataWindowEquivalentLayer->SMALL_ERROR) {
    1781             :             // illum < shade
    1782           0 :             PD_BEAM_CASE_I(S,
    1783             :                            W,
    1784             :                            OMEGA_H,
    1785             :                            DE,
    1786             :                            RHOFF_BT_PARL,
    1787             :                            TAUFF_BB_PARL,
    1788             :                            TAUFF_BD_PARL,
    1789             :                            RHOBF_BT_PARL,
    1790             :                            TAUBF_BB_PARL,
    1791             :                            TAUBF_BD_PARL,
    1792             :                            RHOFF_BT_PERP,
    1793             :                            TAUFF_BB_PERP,
    1794             :                            TAUFF_BD_PERP,
    1795             :                            RHOBF_BT_PERP,
    1796             :                            TAUBF_BB_PERP,
    1797             :                            TAUBF_BD_PERP,
    1798             :                            RHOBF_DD,
    1799             :                            RHOFF_DD,
    1800             :                            TAUFF_DD,
    1801             :                            TAUBF_DD,
    1802             :                            RHO_BD,
    1803             :                            TAU_BD,
    1804             :                            TAU_BB);
    1805           0 :         } else if (DE <= EF + state.dataWindowEquivalentLayer->SMALL_ERROR) {
    1806             :             // illum and shade equal
    1807           0 :             PD_BEAM_CASE_II(S,
    1808             :                             W,
    1809             :                             OMEGA_H,
    1810             :                             DE,
    1811             :                             RHOFF_BT_PARL,
    1812             :                             TAUFF_BB_PARL,
    1813             :                             TAUFF_BD_PARL,
    1814             :                             RHOBF_BT_PARL,
    1815             :                             TAUBF_BB_PARL,
    1816             :                             TAUBF_BD_PARL,
    1817             :                             RHOFF_BT_PERP,
    1818             :                             TAUFF_BB_PERP,
    1819             :                             TAUFF_BD_PERP,
    1820             :                             RHOBF_BT_PERP,
    1821             :                             TAUBF_BB_PERP,
    1822             :                             TAUBF_BD_PERP,
    1823             :                             RHOBF_DD,
    1824             :                             RHOFF_DD,
    1825             :                             TAUFF_DD,
    1826             :                             TAUBF_DD,
    1827             :                             RHO_BD,
    1828             :                             TAU_BD,
    1829             :                             TAU_BB);
    1830             :         } else {
    1831             :             // illum > shade
    1832           0 :             PD_BEAM_CASE_III(S,
    1833             :                              W,
    1834             :                              OMEGA_H,
    1835             :                              DE,
    1836             :                              RHOFF_BT_PARL,
    1837             :                              TAUFF_BB_PARL,
    1838             :                              TAUFF_BD_PARL,
    1839             :                              RHOBF_BT_PARL,
    1840             :                              TAUBF_BB_PARL,
    1841             :                              TAUBF_BD_PARL,
    1842             :                              RHOFF_BT_PERP,
    1843             :                              TAUFF_BB_PERP,
    1844             :                              TAUFF_BD_PERP,
    1845             :                              RHOBF_BT_PERP,
    1846             :                              TAUBF_BB_PERP,
    1847             :                              TAUBF_BD_PERP,
    1848             :                              RHOBF_DD,
    1849             :                              RHOFF_DD,
    1850             :                              TAUFF_DD,
    1851             :                              TAUBF_DD,
    1852             :                              RHO_BD,
    1853             :                              TAU_BD,
    1854             :                              TAU_BB);
    1855             :         }
    1856           0 :     } else if (DE <= W + state.dataWindowEquivalentLayer->SMALL_ERROR) {
    1857             :         // illum length same as pleat depth
    1858           0 :         PD_BEAM_CASE_IV(S,
    1859             :                         W,
    1860             :                         OMEGA_H,
    1861             :                         DE,
    1862             :                         RHOFF_BT_PARL,
    1863             :                         TAUFF_BB_PARL,
    1864             :                         TAUFF_BD_PARL,
    1865             :                         RHOBF_BT_PARL,
    1866             :                         TAUBF_BB_PARL,
    1867             :                         TAUBF_BD_PARL,
    1868             :                         RHOFF_BT_PERP,
    1869             :                         TAUFF_BB_PERP,
    1870             :                         TAUFF_BD_PERP,
    1871             :                         RHOBF_BT_PERP,
    1872             :                         TAUBF_BB_PERP,
    1873             :                         TAUBF_BD_PERP,
    1874             :                         RHOBF_DD,
    1875             :                         RHOFF_DD,
    1876             :                         TAUFF_DD,
    1877             :                         TAUBF_DD,
    1878             :                         RHO_BD,
    1879             :                         TAU_BD,
    1880             :                         TAU_BB);
    1881           0 :     } else if (DE < 9000.0 * S) {
    1882             :         // some direct illum on pleat back
    1883           0 :         PD_BEAM_CASE_V(S,
    1884             :                        W,
    1885             :                        OMEGA_H,
    1886             :                        DE,
    1887             :                        RHOFF_BT_PARL,
    1888             :                        TAUFF_BB_PARL,
    1889             :                        TAUFF_BD_PARL,
    1890             :                        RHOBF_BT_PARL,
    1891             :                        TAUBF_BB_PARL,
    1892             :                        TAUBF_BD_PARL,
    1893             :                        RHOFF_BT_PERP,
    1894             :                        TAUFF_BB_PERP,
    1895             :                        TAUFF_BD_PERP,
    1896             :                        RHOBF_BT_PERP,
    1897             :                        TAUBF_BB_PERP,
    1898             :                        TAUBF_BD_PERP,
    1899             :                        RHOBF_DD,
    1900             :                        RHOFF_DD,
    1901             :                        TAUFF_DD,
    1902             :                        TAUBF_DD,
    1903             :                        RHO_BD,
    1904             :                        TAU_BD,
    1905             :                        TAU_BB);
    1906             :     } else {
    1907             :         // beam parallel to pleat sides (no direct illum on pleat back)
    1908           0 :         PD_BEAM_CASE_VI(S,
    1909             :                         W,
    1910             :                         OMEGA_H,
    1911             :                         DE,
    1912             :                         RHOFF_BT_PARL,
    1913             :                         TAUFF_BB_PARL,
    1914             :                         TAUFF_BD_PARL,
    1915             :                         RHOBF_BT_PARL,
    1916             :                         TAUBF_BB_PARL,
    1917             :                         TAUBF_BD_PARL,
    1918             :                         RHOFF_BT_PERP,
    1919             :                         TAUFF_BB_PERP,
    1920             :                         TAUFF_BD_PERP,
    1921             :                         RHOBF_BT_PERP,
    1922             :                         TAUBF_BB_PERP,
    1923             :                         TAUBF_BD_PERP,
    1924             :                         RHOBF_DD,
    1925             :                         RHOFF_DD,
    1926             :                         TAUFF_DD,
    1927             :                         TAUBF_DD,
    1928             :                         RHO_BD,
    1929             :                         TAU_BD,
    1930             :                         TAU_BB);
    1931             :     }
    1932             : }
    1933             : 
    1934           0 : void PD_BEAM_CASE_I(Real64 const S,                        // pleat spacing (> 0)
    1935             :                     Real64 const W,                        // pleat depth (>=0, same units as S)
    1936             :                     [[maybe_unused]] Real64 const OMEGA_H, // horizontal profile angle, radians
    1937             :                     Real64 const DE,                       // width of illumination on pleat bottom (same units as S)
    1938             :                     Real64 const RHOFF_BT_PARL,
    1939             :                     Real64 const TAUFF_BB_PARL,
    1940             :                     Real64 const TAUFF_BD_PARL,
    1941             :                     [[maybe_unused]] Real64 const RHOBF_BT_PARL,
    1942             :                     [[maybe_unused]] Real64 const TAUBF_BB_PARL,
    1943             :                     [[maybe_unused]] Real64 const TAUBF_BD_PARL,
    1944             :                     Real64 const RHOFF_BT_PERP,
    1945             :                     Real64 const TAUFF_BB_PERP,
    1946             :                     Real64 const TAUFF_BD_PERP,
    1947             :                     Real64 const RHOBF_BT_PERP,
    1948             :                     Real64 const TAUBF_BB_PERP,
    1949             :                     Real64 const TAUBF_BD_PERP,
    1950             :                     Real64 const RHOBF_DD, // fabric back diffuse-diffuse reflectance
    1951             :                     Real64 const RHOFF_DD, // fabric front diffuse-diffuse reflectance
    1952             :                     Real64 const TAUFF_DD, // fabric front diffuse-diffuse transmittance
    1953             :                     Real64 const TAUBF_DD, // fabric back diffuse-diffuse transmittance
    1954             :                     Real64 &RHO_BD,        // returned: drape front beam-diffuse reflectance
    1955             :                     Real64 &TAU_BD,        // returned: drape front beam-diffuse transmittance
    1956             :                     Real64 &TAU_BB         // returned: drape front beam-beam transmittance
    1957             : )
    1958             : {
    1959             : 
    1960             :     // SUBROUTINE INFORMATION:
    1961             :     //       AUTHOR         John L. Wright, University of Waterloo,
    1962             :     //                      Mechanical Engineering, Advanced Glazing System Laboratory
    1963             :     //       DATE WRITTEN   Unknown
    1964             :     //       MODIFIED       na
    1965             :     //       RE-ENGINEERED  na
    1966             : 
    1967             :     // PURPOSE OF THIS SUBROUTINE:
    1968             :     //  calculates the effective front-side solar optical properties of a drapery layer.
    1969             :     // METHODOLOGY EMPLOYED:
    1970             :     // FOURTEEN SURFACE FLAT-FABRIC MODEL WITH RECTANGULAR ENCLOSURE
    1971             : 
    1972             :     // SUBROUTINE ARGUMENT DEFINITIONS:
    1973             :     // fabric properties at current (off-normal) incidence
    1974             :     //   _PARL = surface parallel to window (pleat top/bot)
    1975             :     //   _PERP = surface perpendicular to window (pleat side)
    1976             : 
    1977           0 :     int constexpr N(12);
    1978             : 
    1979             :     Real64 TAUBF_BT_PERP;
    1980             :     Real64 AB; // lengths of surfaces and diagonal strings
    1981             :     Real64 GN;
    1982             :     Real64 NP;
    1983             :     Real64 GP;
    1984             :     Real64 NK;
    1985             :     Real64 PK;
    1986             :     Real64 BC;
    1987             :     Real64 AN;
    1988             :     Real64 AP;
    1989             :     Real64 AK;
    1990             :     Real64 BG;
    1991             :     Real64 BP;
    1992             :     Real64 CG;
    1993             :     Real64 BK;
    1994             :     Real64 CP;
    1995             :     Real64 CN;
    1996             :     Real64 Z1_BB; // beam source terms
    1997             :     Real64 Z7_BB;
    1998             :     Real64 Z1_BD; // diffuse source terms due to incident beam radiation
    1999             :     Real64 Z2_BD;
    2000             :     Real64 Z7_BD;
    2001             :     Real64 Z3_BD;
    2002             :     Real64 Z9_BD;
    2003             :     Real64 Z13_BD;
    2004             :     Real64 Z14_BD;
    2005             :     // shape factors
    2006             :     Real64 F12;
    2007             :     Real64 F13;
    2008             :     Real64 F14;
    2009             :     Real64 F16;
    2010             :     Real64 F17;
    2011             :     Real64 F21;
    2012             :     Real64 F25;
    2013             :     Real64 F26;
    2014             :     Real64 F27;
    2015             :     Real64 F31;
    2016             :     Real64 F35;
    2017             :     Real64 F36;
    2018             :     Real64 F37;
    2019             :     Real64 F41;
    2020             :     Real64 F45;
    2021             :     Real64 F46;
    2022             :     Real64 F47;
    2023             :     Real64 F51;
    2024             :     Real64 F52;
    2025             :     Real64 F53;
    2026             :     Real64 F54;
    2027             :     Real64 F56;
    2028             :     Real64 F57;
    2029             :     Real64 F61;
    2030             :     Real64 F62;
    2031             :     Real64 F63;
    2032             :     Real64 F64;
    2033             :     Real64 F71;
    2034             :     Real64 F72;
    2035             :     Real64 F73;
    2036             :     Real64 F74;
    2037             :     Real64 F89;
    2038             :     Real64 F810;
    2039             :     Real64 F811;
    2040             :     Real64 F812;
    2041             :     Real64 F813;
    2042             :     Real64 F814;
    2043             :     Real64 F911;
    2044             :     Real64 F912;
    2045             :     Real64 F913;
    2046             :     Real64 F914;
    2047             :     Real64 F1011;
    2048             :     Real64 F1012;
    2049             :     Real64 F1013;
    2050             :     Real64 F1014;
    2051             :     Real64 F119;
    2052             :     Real64 F1110;
    2053             :     Real64 F1112;
    2054             :     Real64 F1113;
    2055             :     Real64 F1114;
    2056             :     Real64 F129;
    2057             :     Real64 F1210;
    2058             :     Real64 F1211;
    2059             :     Real64 F139;
    2060             :     Real64 F1310;
    2061             :     Real64 F1311;
    2062             :     Real64 F149;
    2063             :     Real64 F1410;
    2064             :     Real64 F1411;
    2065             :     Real64 J1; // radiosity, surface i
    2066             :     Real64 J2;
    2067             :     Real64 J3;
    2068             :     Real64 J4;
    2069             :     Real64 J6;
    2070             :     Real64 J7;
    2071             :     Real64 J9;
    2072             :     Real64 J10;
    2073             :     Real64 J11;
    2074             :     Real64 J12;
    2075             :     Real64 J13;
    2076             :     Real64 J14;
    2077             :     Real64 G1; // irradiance, surface i
    2078             :     Real64 G5;
    2079             :     Real64 G8;
    2080             :     Real64 G11;
    2081           0 :     Array2D<Real64> A(N + 2, N); // coefficients of the radiosity equations matrix
    2082           0 :     Array1D<Real64> XSOL(N);     // solution vector (obtained after solving the radiosity equations matrix)
    2083             : 
    2084           0 :     TAUBF_BT_PERP = TAUBF_BD_PERP + TAUBF_BB_PERP;
    2085             : 
    2086           0 :     AB = DE;
    2087           0 :     GN = DE;
    2088           0 :     NP = DE;
    2089           0 :     GP = 2.0 * DE;
    2090           0 :     NK = W - DE;
    2091           0 :     PK = W - 2.0 * DE;
    2092           0 :     BC = NK;
    2093           0 :     AN = std::sqrt(S * S + DE * DE);
    2094           0 :     AP = std::sqrt(S * S + GP * GP);
    2095           0 :     AK = std::sqrt(W * W + S * S);
    2096           0 :     BG = AN;
    2097           0 :     BP = AN;
    2098           0 :     CG = AK;
    2099           0 :     BK = std::sqrt(S * S + BC * BC);
    2100           0 :     CP = std::sqrt(S * S + PK * PK);
    2101           0 :     CN = std::sqrt(S * S + NK * NK);
    2102             : 
    2103           0 :     Z1_BB = TAUFF_BB_PARL;
    2104           0 :     Z1_BD = TAUFF_BD_PARL;
    2105           0 :     Z2_BD = Z1_BB * RHOBF_BT_PERP * S / GN;
    2106           0 :     Z7_BB = TAUFF_BB_PERP * S / DE;
    2107           0 :     Z7_BD = TAUFF_BD_PERP * S / DE;
    2108           0 :     Z3_BD = Z7_BB * RHOBF_BT_PERP;
    2109           0 :     Z9_BD = RHOFF_BT_PERP * S / DE;
    2110           0 :     Z13_BD = Z7_BB * TAUBF_BT_PERP;
    2111           0 :     Z14_BD = Z1_BB * TAUBF_BT_PERP * S / GN;
    2112             : 
    2113           0 :     F12 = (S + GN - AN) / (2.0 * S);
    2114           0 :     F13 = (AN + GP - (GN + AP)) / (2.0 * S);
    2115           0 :     F14 = (AP + W - (GP + AK)) / (2.0 * S);
    2116           0 :     F16 = (W + BG - (AB + CG)) / (2.0 * S);
    2117           0 :     F17 = (S + AB - BG) / (2.0 * S);
    2118           0 :     F21 = (S + GN - AN) / (2.0 * GN);
    2119           0 :     F25 = (W + CN - (CG + NK)) / (2.0 * GN);
    2120           0 :     F26 = (CG + S - (BG + CN)) / (2.0 * GN);
    2121           0 :     F27 = (AN + BG - 2.0 * S) / (2.0 * GN);
    2122           0 :     F31 = (AN + GP - (GN + AP)) / (2.0 * NP);
    2123           0 :     F35 = (NK + CP - (CN + PK)) / (2.0 * NP);
    2124           0 :     F36 = (CN + BP - (S + CP)) / (2.0 * NP);
    2125           0 :     F37 = (S + AP - (AN + BP)) / (2.0 * NP);
    2126           0 :     F41 = (W + AP - (GP + AK)) / (2.0 * PK);
    2127           0 :     F45 = (S + PK - CP) / (2.0 * PK);
    2128           0 :     F46 = (CP + BK - (S + BP)) / (2.0 * PK);
    2129           0 :     F47 = (BP + AK - (AP + BK)) / (2.0 * PK);
    2130           0 :     F51 = (AK + CG - 2.0 * W) / (2.0 * S);
    2131           0 :     F52 = (W + CN - (CG + NK)) / (2.0 * S);
    2132           0 :     F53 = (NK + CP - (CN + PK)) / (2.0 * S);
    2133           0 :     F54 = (S + PK - CP) / (2.0 * S);
    2134           0 :     F56 = (S + BC - BK) / (2.0 * S);
    2135           0 :     F57 = (W + BK - (BC + AK)) / (2.0 * S);
    2136           0 :     F61 = (W + BG - (AB + CG)) / (2.0 * BC);
    2137           0 :     F62 = (S + CG - (BG + CN)) / (2.0 * BC);
    2138           0 :     F63 = (CN + BP - (S + CP)) / (2.0 * BC);
    2139           0 :     F64 = (BK + CP - (S + BP)) / (2.0 * BC);
    2140           0 :     F71 = F21;
    2141           0 :     F72 = F27;
    2142           0 :     F73 = F37;
    2143           0 :     F74 = (BP + AK - (BK + AP)) / (2.0 * AB);
    2144           0 :     F89 = F12;
    2145           0 :     F810 = F16;
    2146           0 :     F811 = F51;
    2147           0 :     F812 = F14;
    2148           0 :     F813 = F13;
    2149           0 :     F814 = F12;
    2150           0 :     F911 = F25;
    2151           0 :     F912 = F74;
    2152           0 :     F913 = F73;
    2153           0 :     F914 = F27;
    2154           0 :     F1011 = (BC + S - BK) / (2.0 * BC);
    2155           0 :     F1012 = F64;
    2156           0 :     F1013 = F63;
    2157           0 :     F1014 = F62;
    2158           0 :     F119 = F57;
    2159           0 :     F1110 = F56;
    2160           0 :     F1112 = F54;
    2161           0 :     F1113 = F53;
    2162           0 :     F1114 = F52;
    2163           0 :     F129 = F47;
    2164           0 :     F1210 = F46;
    2165           0 :     F1211 = F45;
    2166           0 :     F139 = F37;
    2167           0 :     F1310 = F36;
    2168           0 :     F1311 = F35;
    2169           0 :     F149 = F27;
    2170           0 :     F1410 = F26;
    2171           0 :     F1411 = F25;
    2172             : 
    2173           0 :     A = 0.0;    // INITIALIZE RADIOSITY MATRIX COEFFICIENTS
    2174           0 :     XSOL = 0.0; // INITIALIZE SOLUTION VECTOR COEFFICIENTS
    2175             : 
    2176             :     // POPULATE THE COEFFICIENTS OF THE RADIOSITY MATRIX
    2177             : 
    2178           0 :     A(1, 1) = 1.0;
    2179           0 :     A(2, 1) = -RHOBF_DD * F12;
    2180           0 :     A(3, 1) = -RHOBF_DD * F13;
    2181           0 :     A(4, 1) = -RHOBF_DD * F14;
    2182           0 :     A(5, 1) = -RHOBF_DD * F16;
    2183           0 :     A(6, 1) = -RHOBF_DD * F17;
    2184           0 :     A(7, 1) = 0.0;
    2185           0 :     A(8, 1) = 0.0;
    2186           0 :     A(9, 1) = 0.0;
    2187           0 :     A(10, 1) = 0.0;
    2188           0 :     A(11, 1) = 0.0;
    2189           0 :     A(12, 1) = 0.0;
    2190           0 :     A(13, 1) = Z1_BD;
    2191           0 :     A(1, 2) = -RHOBF_DD * F21;
    2192           0 :     A(2, 2) = 1.0;
    2193           0 :     A(3, 2) = 0.0;
    2194           0 :     A(4, 2) = 0.0;
    2195           0 :     A(5, 2) = -RHOBF_DD * F26;
    2196           0 :     A(6, 2) = -RHOBF_DD * F27;
    2197           0 :     A(7, 2) = -TAUFF_DD * F149;
    2198           0 :     A(8, 2) = -TAUFF_DD * F1410;
    2199           0 :     A(9, 2) = -TAUFF_DD * F1411;
    2200           0 :     A(10, 2) = 0.0;
    2201           0 :     A(11, 2) = 0.0;
    2202           0 :     A(12, 2) = 0.0;
    2203           0 :     A(13, 2) = Z2_BD;
    2204           0 :     A(1, 3) = -RHOBF_DD * F31;
    2205           0 :     A(2, 3) = 0.0;
    2206           0 :     A(3, 3) = 1.0;
    2207           0 :     A(4, 3) = 0.0;
    2208           0 :     A(5, 3) = -RHOBF_DD * F36;
    2209           0 :     A(6, 3) = -RHOBF_DD * F37;
    2210           0 :     A(7, 3) = -TAUFF_DD * F139;
    2211           0 :     A(8, 3) = -TAUFF_DD * F1310;
    2212           0 :     A(9, 3) = -TAUFF_DD * F1311;
    2213           0 :     A(10, 3) = 0.0;
    2214           0 :     A(11, 3) = 0.0;
    2215           0 :     A(12, 3) = 0.0;
    2216           0 :     A(13, 3) = Z3_BD;
    2217           0 :     A(1, 4) = -RHOBF_DD * F41;
    2218           0 :     A(2, 4) = 0.0;
    2219           0 :     A(3, 4) = 0.0;
    2220           0 :     A(4, 4) = 1.0;
    2221           0 :     A(5, 4) = -RHOBF_DD * F46;
    2222           0 :     A(6, 4) = -RHOBF_DD * F47;
    2223           0 :     A(7, 4) = -TAUFF_DD * F129;
    2224           0 :     A(8, 4) = -TAUFF_DD * F1210;
    2225           0 :     A(9, 4) = -TAUFF_DD * F1211;
    2226           0 :     A(10, 4) = 0.0;
    2227           0 :     A(11, 4) = 0.0;
    2228           0 :     A(12, 4) = 0.0;
    2229           0 :     A(13, 4) = 0.0;
    2230           0 :     A(1, 5) = -RHOBF_DD * F61;
    2231           0 :     A(2, 5) = -RHOBF_DD * F62;
    2232           0 :     A(3, 5) = -RHOBF_DD * F63;
    2233           0 :     A(4, 5) = -RHOBF_DD * F64;
    2234           0 :     A(5, 5) = 1.0;
    2235           0 :     A(6, 5) = 0.0;
    2236           0 :     A(7, 5) = 0.0;
    2237           0 :     A(8, 5) = 0.0;
    2238           0 :     A(9, 5) = -TAUFF_DD * F1011;
    2239           0 :     A(10, 5) = -TAUFF_DD * F1012;
    2240           0 :     A(11, 5) = -TAUFF_DD * F1013;
    2241           0 :     A(12, 5) = -TAUFF_DD * F1014;
    2242           0 :     A(13, 5) = 0.0;
    2243           0 :     A(1, 6) = -RHOBF_DD * F71;
    2244           0 :     A(2, 6) = -RHOBF_DD * F72;
    2245           0 :     A(3, 6) = -RHOBF_DD * F73;
    2246           0 :     A(4, 6) = -RHOBF_DD * F74;
    2247           0 :     A(5, 6) = 0.0;
    2248           0 :     A(6, 6) = 1.0;
    2249           0 :     A(7, 6) = 0.0;
    2250           0 :     A(8, 6) = 0.0;
    2251           0 :     A(9, 6) = -TAUFF_DD * F911;
    2252           0 :     A(10, 6) = -TAUFF_DD * F912;
    2253           0 :     A(11, 6) = -TAUFF_DD * F913;
    2254           0 :     A(12, 6) = -TAUFF_DD * F914;
    2255           0 :     A(13, 6) = Z7_BD;
    2256           0 :     A(1, 7) = -TAUBF_DD * F71;
    2257           0 :     A(2, 7) = -TAUBF_DD * F72;
    2258           0 :     A(3, 7) = -TAUBF_DD * F73;
    2259           0 :     A(4, 7) = -TAUBF_DD * F74;
    2260           0 :     A(5, 7) = 0.0;
    2261           0 :     A(6, 7) = 0.0;
    2262           0 :     A(7, 7) = 1.0;
    2263           0 :     A(8, 7) = 0.0;
    2264           0 :     A(9, 7) = -RHOFF_DD * F911;
    2265           0 :     A(10, 7) = -RHOFF_DD * F912;
    2266           0 :     A(11, 7) = -RHOFF_DD * F913;
    2267           0 :     A(12, 7) = -RHOFF_DD * F914;
    2268           0 :     A(13, 7) = Z9_BD;
    2269           0 :     A(1, 8) = -TAUBF_DD * F61;
    2270           0 :     A(2, 8) = -TAUBF_DD * F62;
    2271           0 :     A(3, 8) = -TAUBF_DD * F63;
    2272           0 :     A(4, 8) = -TAUBF_DD * F64;
    2273           0 :     A(5, 8) = 0.0;
    2274           0 :     A(6, 8) = 0.0;
    2275           0 :     A(7, 8) = 0.0;
    2276           0 :     A(8, 8) = 1.0;
    2277           0 :     A(9, 8) = -RHOFF_DD * F1011;
    2278           0 :     A(10, 8) = -RHOFF_DD * F1012;
    2279           0 :     A(11, 8) = -RHOFF_DD * F1013;
    2280           0 :     A(12, 8) = -RHOFF_DD * F1014;
    2281           0 :     A(13, 8) = 0.0;
    2282           0 :     A(1, 9) = 0.0;
    2283           0 :     A(2, 9) = 0.0;
    2284           0 :     A(3, 9) = 0.0;
    2285           0 :     A(4, 9) = 0.0;
    2286           0 :     A(5, 9) = 0.0;
    2287           0 :     A(6, 9) = 0.0;
    2288           0 :     A(7, 9) = -RHOFF_DD * F119;
    2289           0 :     A(8, 9) = -RHOFF_DD * F1110;
    2290           0 :     A(9, 9) = 1.0;
    2291           0 :     A(10, 9) = -RHOFF_DD * F1112;
    2292           0 :     A(11, 9) = -RHOFF_DD * F1113;
    2293           0 :     A(12, 9) = -RHOFF_DD * F1114;
    2294           0 :     A(13, 9) = 0.0;
    2295           0 :     A(1, 10) = -TAUBF_DD * F41;
    2296           0 :     A(2, 10) = 0.0;
    2297           0 :     A(3, 10) = 0.0;
    2298           0 :     A(4, 10) = 0.0;
    2299           0 :     A(5, 10) = -TAUBF_DD * F46;
    2300           0 :     A(6, 10) = -TAUBF_DD * F47;
    2301           0 :     A(7, 10) = -RHOFF_DD * F129;
    2302           0 :     A(8, 10) = -RHOFF_DD * F1210;
    2303           0 :     A(9, 10) = -RHOFF_DD * F1211;
    2304           0 :     A(10, 10) = 1.0;
    2305           0 :     A(11, 10) = 0.0;
    2306           0 :     A(12, 10) = 0.0;
    2307           0 :     A(13, 10) = 0.0;
    2308           0 :     A(1, 11) = -TAUBF_DD * F31;
    2309           0 :     A(2, 11) = 0.0;
    2310           0 :     A(3, 11) = 0.0;
    2311           0 :     A(4, 11) = 0.0;
    2312           0 :     A(5, 11) = -TAUBF_DD * F36;
    2313           0 :     A(6, 11) = -TAUBF_DD * F37;
    2314           0 :     A(7, 11) = -RHOFF_DD * F139;
    2315           0 :     A(8, 11) = -RHOFF_DD * F1310;
    2316           0 :     A(9, 11) = -RHOFF_DD * F1311;
    2317           0 :     A(10, 11) = 0.0;
    2318           0 :     A(11, 11) = 1.0;
    2319           0 :     A(12, 11) = 0.0;
    2320           0 :     A(13, 11) = Z13_BD;
    2321           0 :     A(1, 12) = -TAUBF_DD * F21;
    2322           0 :     A(2, 12) = 0.0;
    2323           0 :     A(3, 12) = 0.0;
    2324           0 :     A(4, 12) = 0.0;
    2325           0 :     A(5, 12) = -TAUBF_DD * F26;
    2326           0 :     A(6, 12) = -TAUBF_DD * F27;
    2327           0 :     A(7, 12) = -RHOFF_DD * F149;
    2328           0 :     A(8, 12) = -RHOFF_DD * F1410;
    2329           0 :     A(9, 12) = -RHOFF_DD * F1411;
    2330           0 :     A(10, 12) = 0.0;
    2331           0 :     A(11, 12) = 0.0;
    2332           0 :     A(12, 12) = 1.0;
    2333           0 :     A(13, 12) = Z14_BD;
    2334             : 
    2335           0 :     SOLMATS(N, A, XSOL);
    2336             : 
    2337           0 :     J1 = XSOL(1);
    2338           0 :     J2 = XSOL(2);
    2339           0 :     J3 = XSOL(3);
    2340           0 :     J4 = XSOL(4);
    2341           0 :     J6 = XSOL(5);
    2342           0 :     J7 = XSOL(6);
    2343           0 :     J9 = XSOL(7);
    2344           0 :     J10 = XSOL(8);
    2345           0 :     J11 = XSOL(9);
    2346           0 :     J12 = XSOL(10);
    2347           0 :     J13 = XSOL(11);
    2348           0 :     J14 = XSOL(12);
    2349             : 
    2350           0 :     G1 = F12 * J2 + F13 * J3 + F14 * J4 + F16 * J6 + F17 * J7;
    2351           0 :     G5 = F56 * J6 + F57 * J7 + F51 * J1 + F52 * J2 + F53 * J3 + F54 * J4;
    2352           0 :     G8 = F89 * J9 + F810 * J10 + F811 * J11 + F812 * J12 + F813 * J13 + F814 * J14;
    2353           0 :     G11 = F1112 * J12 + F1113 * J13 + F1114 * J14 + F119 * J9 + F1110 * J10;
    2354             : 
    2355           0 :     TAU_BB = 0.0;
    2356           0 :     TAU_BD = (G5 + TAUFF_DD * G11) / 2.0;
    2357           0 :     RHO_BD = (RHOFF_BT_PARL + TAUBF_DD * G1 + G8) / 2.0;
    2358           0 : }
    2359             : 
    2360           0 : void PD_BEAM_CASE_II(Real64 const S,                        // pleat spacing (> 0)
    2361             :                      Real64 const W,                        // pleat depth (>=0, same units as S)
    2362             :                      [[maybe_unused]] Real64 const OMEGA_H, // horizontal profile angle, radians
    2363             :                      Real64 const DE,                       // width of illumination on pleat bottom (same units as S)
    2364             :                      Real64 const RHOFF_BT_PARL,
    2365             :                      Real64 const TAUFF_BB_PARL,
    2366             :                      Real64 const TAUFF_BD_PARL,
    2367             :                      [[maybe_unused]] Real64 const RHOBF_BT_PARL,
    2368             :                      [[maybe_unused]] Real64 const TAUBF_BB_PARL,
    2369             :                      [[maybe_unused]] Real64 const TAUBF_BD_PARL,
    2370             :                      Real64 const RHOFF_BT_PERP,
    2371             :                      Real64 const TAUFF_BB_PERP,
    2372             :                      Real64 const TAUFF_BD_PERP,
    2373             :                      Real64 const RHOBF_BT_PERP,
    2374             :                      Real64 const TAUBF_BB_PERP,
    2375             :                      Real64 const TAUBF_BD_PERP,
    2376             :                      Real64 const RHOBF_DD, // fabric back diffuse-diffuse reflectance
    2377             :                      Real64 const RHOFF_DD, // fabric front diffuse-diffuse reflectance
    2378             :                      Real64 const TAUFF_DD, // fabric front diffuse-diffuse transmittance
    2379             :                      Real64 const TAUBF_DD, // fabric back diffuse-diffuse transmittance
    2380             :                      Real64 &RHO_BD,        // returned: drape front beam-diffuse reflectance
    2381             :                      Real64 &TAU_BD,        // returned: drape front beam-diffuse transmittance
    2382             :                      Real64 &TAU_BB         // returned: drape front beam-beam transmittance
    2383             : )
    2384             : {
    2385             : 
    2386             :     // SUBROUTINE INFORMATION:
    2387             :     //       AUTHOR         John L. Wright, University of Waterloo,
    2388             :     //                      Mechanical Engineering, Advanced Glazing System Laboratory
    2389             :     //       DATE WRITTEN   Unknown
    2390             :     //       MODIFIED       na
    2391             :     //       RE-ENGINEERED  na
    2392             : 
    2393             :     // PURPOSE OF THIS SUBROUTINE:
    2394             :     //  calculates the effective front-side solar optical properties of a drapery layer.
    2395             :     // METHODOLOGY EMPLOYED:
    2396             :     // TWELVE SURFACE FLAT-FABRIC MODEL WITH RECTANGULAR ENCLOSURE
    2397             : 
    2398             :     // fabric properties at current (off-normal) incidence
    2399             :     //   _PARL = surface parallel to window (pleat top/bot)
    2400             :     //   _PERP = surface perpendicular to window (pleat side)
    2401             : 
    2402           0 :     int constexpr N(10);
    2403             : 
    2404             :     Real64 TAUBF_BT_PERP;
    2405             :     Real64 AB; // lengths of surfaces and diagonal strings
    2406             :     Real64 GN;
    2407             :     Real64 NK;
    2408             :     Real64 BC;
    2409             :     Real64 AN;
    2410             :     Real64 AK;
    2411             :     Real64 BG;
    2412             :     Real64 CG;
    2413             :     Real64 BK;
    2414             :     Real64 CN;
    2415             :     Real64 Z1_BD; // diffuse source terms due to incident beam radiation
    2416             :     Real64 Z2_BD;
    2417             :     Real64 Z3_BD;
    2418             :     Real64 Z6_BD;
    2419             :     Real64 Z8_BD;
    2420             :     Real64 Z11_BD;
    2421             :     Real64 Z12_BD;
    2422             :     Real64 Z1_BB; // beam source terms due to incident beam radiation
    2423             :     Real64 Z6_BB;
    2424             :     // shape factors
    2425             :     Real64 F12;
    2426             :     Real64 F13;
    2427             :     Real64 F15;
    2428             :     Real64 F16;
    2429             :     Real64 F21;
    2430             :     Real64 F25;
    2431             :     Real64 F26;
    2432             :     Real64 F31;
    2433             :     Real64 F35;
    2434             :     Real64 F36;
    2435             :     Real64 F41;
    2436             :     Real64 F42;
    2437             :     Real64 F43;
    2438             :     Real64 F45;
    2439             :     Real64 F46;
    2440             :     Real64 F51;
    2441             :     Real64 F52;
    2442             :     Real64 F53;
    2443             :     Real64 F54;
    2444             :     Real64 F61;
    2445             :     Real64 F62;
    2446             :     Real64 F63;
    2447             :     Real64 F78;
    2448             :     Real64 F79;
    2449             :     Real64 F710;
    2450             :     Real64 F711;
    2451             :     Real64 F712;
    2452             :     Real64 F810;
    2453             :     Real64 F811;
    2454             :     Real64 F812;
    2455             :     Real64 F910;
    2456             :     Real64 F911;
    2457             :     Real64 F912;
    2458             :     Real64 F108;
    2459             :     Real64 F109;
    2460             :     Real64 F1011;
    2461             :     Real64 F1012;
    2462             :     Real64 F118;
    2463             :     Real64 F119;
    2464             :     Real64 F1110;
    2465             :     Real64 F128;
    2466             :     Real64 F129;
    2467             :     Real64 F1210;
    2468             : 
    2469             :     Real64 J1; // radiosity, surface i
    2470             :     Real64 J2;
    2471             :     Real64 J3;
    2472             :     Real64 J5;
    2473             :     Real64 J6;
    2474             :     Real64 J8;
    2475             :     Real64 J9;
    2476             :     Real64 J10;
    2477             :     Real64 J11;
    2478             :     Real64 J12;
    2479             :     Real64 G1; // irradiance, surface i
    2480             :     Real64 G4;
    2481             :     Real64 G7;
    2482             :     Real64 G10;
    2483           0 :     Array2D<Real64> A(N + 2, N); // coefficients of the radiosity equations matrix
    2484           0 :     Array1D<Real64> XSOL(N);     // solution vector (obtained after solving the radiosity equations matrix)
    2485             : 
    2486           0 :     TAUBF_BT_PERP = TAUBF_BD_PERP + TAUBF_BB_PERP;
    2487             : 
    2488           0 :     AB = DE;
    2489           0 :     GN = DE;
    2490           0 :     NK = W - DE;
    2491           0 :     BC = NK;
    2492           0 :     AN = std::sqrt(S * S + DE * DE);
    2493           0 :     AK = std::sqrt(W * W + S * S);
    2494           0 :     BG = AN;
    2495           0 :     CG = AK;
    2496           0 :     BK = std::sqrt(S * S + BC * BC);
    2497           0 :     CN = std::sqrt(S * S + NK * NK);
    2498             : 
    2499           0 :     Z1_BB = TAUFF_BB_PARL;
    2500           0 :     Z1_BD = TAUFF_BD_PARL;
    2501           0 :     Z2_BD = Z1_BB * RHOBF_BT_PERP * S / GN;
    2502           0 :     Z6_BB = TAUFF_BB_PERP * S / DE;
    2503           0 :     Z6_BD = TAUFF_BD_PERP * S / DE;
    2504           0 :     Z3_BD = Z6_BB * RHOBF_BT_PERP;
    2505           0 :     Z8_BD = RHOFF_BT_PERP * S / DE;
    2506           0 :     Z11_BD = Z6_BB * TAUBF_BT_PERP;
    2507           0 :     Z12_BD = Z1_BB * TAUBF_BT_PERP * S / GN;
    2508             : 
    2509           0 :     F12 = (S + GN - AN) / (2.0 * S);
    2510           0 :     F13 = (W + AN - (GN + AK)) / (2.0 * S);
    2511           0 :     F15 = (W + BG - (AB + CG)) / (2.0 * S);
    2512           0 :     F16 = (S + AB - BG) / (2.0 * S);
    2513           0 :     F21 = (S + GN - AN) / (2.0 * GN);
    2514           0 :     F25 = (S + CG - (BG + CN)) / (2.0 * GN);
    2515           0 :     F26 = (AN + BG - 2.0 * S) / (2.0 * GN);
    2516           0 :     F31 = (W + AN - (GN + AK)) / (2.0 * NK);
    2517           0 :     F35 = (BK + CN - 2.0 * S) / (2.0 * NK);
    2518           0 :     F36 = (S + AK - (AN + BK)) / (2.0 * NK);
    2519           0 :     F41 = (AK + CG - 2.0 * W) / (2.0 * S);
    2520           0 :     F42 = (W + CN - (CG + NK)) / (2.0 * S);
    2521           0 :     F43 = (S + NK - CN) / (2.0 * S);
    2522           0 :     F45 = (S + BC - BK) / (2.0 * S);
    2523           0 :     F46 = (W + BK - (AK + BC)) / (2.0 * S);
    2524           0 :     F51 = (W + BG - (AB + CG)) / (2.0 * BC);
    2525           0 :     F52 = (S + CG - (BG + CN)) / (2.0 * BC);
    2526           0 :     F53 = (BK + CN - 2.0 * S) / (2.0 * BC);
    2527           0 :     F54 = (S + BC - BK) / (2.0 * BC);
    2528           0 :     F61 = (S + AB - BG) / (2.0 * AB);
    2529           0 :     F62 = (AN + BG - 2.0 * S) / (2.0 * AB);
    2530           0 :     F63 = (S + AK - (AN + BK)) / (2.0 * AB);
    2531           0 :     F78 = F12;
    2532           0 :     F79 = F13;
    2533           0 :     F710 = (AK + CG - 2.0 * W) / (2.0 * S);
    2534           0 :     F711 = F15;
    2535           0 :     F712 = F16;
    2536           0 :     F810 = (W + CN - (CG + NK)) / (2.0 * S);
    2537           0 :     F811 = F25;
    2538           0 :     F812 = F26;
    2539           0 :     F910 = (S + NK - CN) / (2.0 * NK);
    2540           0 :     F911 = F35;
    2541           0 :     F912 = F36;
    2542           0 :     F108 = F42;
    2543           0 :     F109 = F43;
    2544           0 :     F1011 = F45;
    2545           0 :     F1012 = F46;
    2546           0 :     F118 = F52;
    2547           0 :     F119 = F53;
    2548           0 :     F1110 = (S + BC - BK) / (2.0 * NK);
    2549           0 :     F128 = F62;
    2550           0 :     F129 = F63;
    2551           0 :     F1210 = (W + BK - (AK + BC)) / (2.0 * GN);
    2552             : 
    2553           0 :     A = 0.0;    // INITIALIZE RADIOSITY MATRIX COEFFICIENTS
    2554           0 :     XSOL = 0.0; // INITIALIZE SOLUTION VECTOR COEFFICIENTS
    2555             : 
    2556             :     // POPULATE THE COEFFICIENTS OF THE RADIOSITY MATRIX
    2557             : 
    2558           0 :     A(1, 1) = 1.0;
    2559           0 :     A(2, 1) = -RHOBF_DD * F12;
    2560           0 :     A(3, 1) = -RHOBF_DD * F13;
    2561           0 :     A(4, 1) = -RHOBF_DD * F15;
    2562           0 :     A(5, 1) = -RHOBF_DD * F16;
    2563           0 :     A(6, 1) = 0.0;
    2564           0 :     A(7, 1) = 0.0;
    2565           0 :     A(8, 1) = 0.0;
    2566           0 :     A(9, 1) = 0.0;
    2567           0 :     A(10, 1) = 0.0;
    2568           0 :     A(11, 1) = Z1_BD;
    2569           0 :     A(1, 2) = -RHOBF_DD * F21;
    2570           0 :     A(2, 2) = 1.0;
    2571           0 :     A(3, 2) = 0.0;
    2572           0 :     A(4, 2) = -RHOBF_DD * F25;
    2573           0 :     A(5, 2) = -RHOBF_DD * F26;
    2574           0 :     A(6, 2) = -TAUFF_DD * F128;
    2575           0 :     A(7, 2) = -TAUFF_DD * F129;
    2576           0 :     A(8, 2) = -TAUFF_DD * F1210;
    2577           0 :     A(9, 2) = 0.0;
    2578           0 :     A(10, 2) = 0.0;
    2579           0 :     A(11, 2) = Z2_BD;
    2580           0 :     A(1, 3) = -RHOBF_DD * F31;
    2581           0 :     A(2, 3) = 0.0;
    2582           0 :     A(3, 3) = 1.0;
    2583           0 :     A(4, 3) = -RHOBF_DD * F35;
    2584           0 :     A(5, 3) = -RHOBF_DD * F36;
    2585           0 :     A(6, 3) = -TAUFF_DD * F118;
    2586           0 :     A(7, 3) = -TAUFF_DD * F119;
    2587           0 :     A(8, 3) = -TAUFF_DD * F1110;
    2588           0 :     A(9, 3) = 0.0;
    2589           0 :     A(10, 3) = 0.0;
    2590           0 :     A(11, 3) = Z3_BD;
    2591           0 :     A(1, 4) = -RHOBF_DD * F51;
    2592           0 :     A(2, 4) = -RHOBF_DD * F52;
    2593           0 :     A(3, 4) = -RHOBF_DD * F53;
    2594           0 :     A(4, 4) = 1.0;
    2595           0 :     A(5, 4) = 0.0;
    2596           0 :     A(6, 4) = 0.0;
    2597           0 :     A(7, 4) = 0.0;
    2598           0 :     A(8, 4) = -TAUFF_DD * F910;
    2599           0 :     A(9, 4) = -TAUFF_DD * F911;
    2600           0 :     A(10, 4) = -TAUFF_DD * F912;
    2601           0 :     A(11, 4) = 0.0;
    2602           0 :     A(1, 5) = -RHOBF_DD * F61;
    2603           0 :     A(2, 5) = -RHOBF_DD * F62;
    2604           0 :     A(3, 5) = -RHOBF_DD * F63;
    2605           0 :     A(4, 5) = 0.0;
    2606           0 :     A(5, 5) = 1.0;
    2607           0 :     A(6, 5) = 0.0;
    2608           0 :     A(7, 5) = 0.0;
    2609           0 :     A(8, 5) = -TAUFF_DD * F810;
    2610           0 :     A(9, 5) = -TAUFF_DD * F811;
    2611           0 :     A(10, 5) = -TAUFF_DD * F812;
    2612           0 :     A(11, 5) = Z6_BD;
    2613           0 :     A(1, 6) = -TAUBF_DD * F61;
    2614           0 :     A(2, 6) = -TAUBF_DD * F62;
    2615           0 :     A(3, 6) = -TAUBF_DD * F63;
    2616           0 :     A(4, 6) = 0.0;
    2617           0 :     A(5, 6) = 0.0;
    2618           0 :     A(6, 6) = 1.0;
    2619           0 :     A(7, 6) = 0.0;
    2620           0 :     A(8, 6) = -RHOFF_DD * F810;
    2621           0 :     A(9, 6) = -RHOFF_DD * F811;
    2622           0 :     A(10, 6) = -RHOFF_DD * F812;
    2623           0 :     A(11, 6) = Z8_BD;
    2624           0 :     A(1, 7) = -TAUBF_DD * F51;
    2625           0 :     A(2, 7) = -TAUBF_DD * F52;
    2626           0 :     A(3, 7) = -TAUBF_DD * F53;
    2627           0 :     A(4, 7) = 0.0;
    2628           0 :     A(5, 7) = 0.0;
    2629           0 :     A(6, 7) = 0.0;
    2630           0 :     A(7, 7) = 1.0;
    2631           0 :     A(8, 7) = -RHOFF_DD * F910;
    2632           0 :     A(9, 7) = -RHOFF_DD * F911;
    2633           0 :     A(10, 7) = -RHOFF_DD * F912;
    2634           0 :     A(11, 7) = 0.0;
    2635           0 :     A(1, 8) = 0.0;
    2636           0 :     A(2, 8) = 0.0;
    2637           0 :     A(3, 8) = 0.0;
    2638           0 :     A(4, 8) = 0.0;
    2639           0 :     A(5, 8) = 0.0;
    2640           0 :     A(6, 8) = -RHOFF_DD * F108;
    2641           0 :     A(7, 8) = -RHOFF_DD * F109;
    2642           0 :     A(8, 8) = 1.0;
    2643           0 :     A(9, 8) = -RHOFF_DD * F1011;
    2644           0 :     A(10, 8) = -RHOFF_DD * F1012;
    2645           0 :     A(11, 8) = 0.0;
    2646           0 :     A(1, 9) = -TAUBF_DD * F31;
    2647           0 :     A(2, 9) = 0.0;
    2648           0 :     A(3, 9) = 0.0;
    2649           0 :     A(4, 9) = -TAUBF_DD * F35;
    2650           0 :     A(5, 9) = -TAUBF_DD * F36;
    2651           0 :     A(6, 9) = -RHOFF_DD * F118;
    2652           0 :     A(7, 9) = -RHOFF_DD * F119;
    2653           0 :     A(8, 9) = -RHOFF_DD * F1110;
    2654           0 :     A(9, 9) = 1.0;
    2655           0 :     A(10, 9) = 0.0;
    2656           0 :     A(11, 9) = Z11_BD;
    2657           0 :     A(1, 10) = -TAUBF_DD * F21;
    2658           0 :     A(2, 10) = 0.0;
    2659           0 :     A(3, 10) = 0.0;
    2660           0 :     A(4, 10) = -TAUBF_DD * F25;
    2661           0 :     A(5, 10) = -TAUBF_DD * F26;
    2662           0 :     A(6, 10) = -RHOFF_DD * F128;
    2663           0 :     A(7, 10) = -RHOFF_DD * F129;
    2664           0 :     A(8, 10) = -RHOFF_DD * F1210;
    2665           0 :     A(9, 10) = 0.0;
    2666           0 :     A(10, 10) = 1.0;
    2667           0 :     A(11, 10) = Z12_BD;
    2668             : 
    2669           0 :     SOLMATS(N, A, XSOL);
    2670             : 
    2671           0 :     J1 = XSOL(1);
    2672           0 :     J2 = XSOL(2);
    2673           0 :     J3 = XSOL(3);
    2674           0 :     J5 = XSOL(4);
    2675           0 :     J6 = XSOL(5);
    2676           0 :     J8 = XSOL(6);
    2677           0 :     J9 = XSOL(7);
    2678           0 :     J10 = XSOL(8);
    2679           0 :     J11 = XSOL(9);
    2680           0 :     J12 = XSOL(10);
    2681             : 
    2682           0 :     G1 = F12 * J2 + F13 * J3 + F15 * J5 + F16 * J6;
    2683           0 :     G4 = F41 * J1 + F42 * J2 + F43 * J3 + F45 * J5 + F46 * J6;
    2684           0 :     G7 = F78 * J8 + F79 * J9 + F710 * J10 + F711 * J11 + F712 * J12;
    2685           0 :     G10 = F108 * J8 + F109 * J9 + F1011 * J11 + F1012 * J12;
    2686             : 
    2687           0 :     TAU_BB = 0.0;
    2688           0 :     TAU_BD = (G4 + TAUFF_DD * G10) / 2.0;
    2689           0 :     RHO_BD = (RHOFF_BT_PARL + TAUBF_DD * G1 + G7) / 2.0;
    2690           0 : }
    2691             : 
    2692           0 : void PD_BEAM_CASE_III(Real64 const S,       // pleat spacing (> 0)
    2693             :                       Real64 const W,       // pleat depth (>=0, same units as S)
    2694             :                       Real64 const OMEGA_H, // horizontal profile angle, radians
    2695             :                       Real64 const DE,      // width of illumination on pleat bottom (same units as S)
    2696             :                       Real64 const RHOFF_BT_PARL,
    2697             :                       Real64 const TAUFF_BB_PARL,
    2698             :                       Real64 const TAUFF_BD_PARL,
    2699             :                       [[maybe_unused]] Real64 const RHOBF_BT_PARL,
    2700             :                       [[maybe_unused]] Real64 const TAUBF_BB_PARL,
    2701             :                       [[maybe_unused]] Real64 const TAUBF_BD_PARL,
    2702             :                       Real64 const RHOFF_BT_PERP,
    2703             :                       Real64 const TAUFF_BB_PERP,
    2704             :                       Real64 const TAUFF_BD_PERP,
    2705             :                       Real64 const RHOBF_BT_PERP,
    2706             :                       Real64 const TAUBF_BB_PERP,
    2707             :                       Real64 const TAUBF_BD_PERP,
    2708             :                       Real64 const RHOBF_DD, // fabric back diffuse-diffuse reflectance
    2709             :                       Real64 const RHOFF_DD, // fabric front diffuse-diffuse reflectance
    2710             :                       Real64 const TAUFF_DD, // fabric front diffuse-diffuse transmittance
    2711             :                       Real64 const TAUBF_DD, // fabric back diffuse-diffuse transmittance
    2712             :                       Real64 &RHO_BD,        // returned: drape front beam-diffuse reflectance
    2713             :                       Real64 &TAU_BD,        // returned: drape front beam-diffuse transmittance
    2714             :                       Real64 &TAU_BB         // returned: drape front beam-beam transmittance
    2715             : )
    2716             : {
    2717             : 
    2718             :     // SUBROUTINE INFORMATION:
    2719             :     //       AUTHOR         John L. Wright, University of Waterloo,
    2720             :     //                      Mechanical Engineering, Advanced Glazing System Laboratory
    2721             :     //       DATE WRITTEN   Unknown
    2722             :     //       MODIFIED       na
    2723             :     //       RE-ENGINEERED  na
    2724             : 
    2725             :     // PURPOSE OF THIS SUBROUTINE:
    2726             :     //  calculates the effective front-side solar optical properties of a drapery layer.
    2727             :     // METHODOLOGY EMPLOYED:
    2728             :     // TWELVE SURFACE FLAT-FABRIC MODEL WITH RECTANGULAR ENCLOSURE
    2729             : 
    2730             :     // fabric properties at current (off-normal) incidence
    2731             :     //   _PARL = surface parallel to window (pleat top/bot)
    2732             :     //   _PERP = surface perpendicular to window (pleat side)
    2733             : 
    2734             :     // SUBROUTINE PARAMETER DEFINITIONS:
    2735           0 :     int constexpr N(10);
    2736             : 
    2737             :     Real64 TAUBF_BT_PERP;
    2738             :     Real64 AB; // lengths for surfaces and diagonal strings
    2739             :     Real64 GN;
    2740             :     Real64 NK;
    2741             :     Real64 BC;
    2742             :     Real64 AN;
    2743             :     Real64 AK;
    2744             :     Real64 BG;
    2745             :     Real64 CG;
    2746             :     Real64 BK;
    2747             :     Real64 CN;
    2748             :     Real64 Z1_BB; // beam source terms
    2749             :     Real64 Z6_BB;
    2750             :     Real64 Z1_BD; // diffuse source terms
    2751             :     Real64 Z2_BD;
    2752             :     Real64 Z6_BD;
    2753             :     Real64 Z3_BD;
    2754             :     Real64 Z8_BD;
    2755             :     Real64 Z11_BD;
    2756             :     Real64 Z12_BD;
    2757             :     // shape factors
    2758             :     Real64 F12;
    2759             :     Real64 F13;
    2760             :     Real64 F15;
    2761             :     Real64 F16;
    2762             :     Real64 F21;
    2763             :     Real64 F25;
    2764             :     Real64 F26;
    2765             :     Real64 F31;
    2766             :     Real64 F35;
    2767             :     Real64 F36;
    2768             :     Real64 F41;
    2769             :     Real64 F42;
    2770             :     Real64 F43;
    2771             :     Real64 F45;
    2772             :     Real64 F46;
    2773             :     Real64 F51;
    2774             :     Real64 F52;
    2775             :     Real64 F53;
    2776             :     Real64 F54;
    2777             :     Real64 F61;
    2778             :     Real64 F62;
    2779             :     Real64 F63;
    2780             :     Real64 F78;
    2781             :     Real64 F79;
    2782             :     Real64 F710;
    2783             :     Real64 F711;
    2784             :     Real64 F712;
    2785             :     Real64 F810;
    2786             :     Real64 F811;
    2787             :     Real64 F812;
    2788             :     Real64 F910;
    2789             :     Real64 F911;
    2790             :     Real64 F912;
    2791             :     Real64 F108;
    2792             :     Real64 F109;
    2793             :     Real64 F1011;
    2794             :     Real64 F1012;
    2795             :     Real64 F118;
    2796             :     Real64 F119;
    2797             :     Real64 F1110;
    2798             :     Real64 F128;
    2799             :     Real64 F129;
    2800             :     Real64 F1210;
    2801             :     Real64 J1; // radiosity, surface i
    2802             :     Real64 J2;
    2803             :     Real64 J3;
    2804             :     Real64 J5;
    2805             :     Real64 J6;
    2806             :     Real64 J8;
    2807             :     Real64 J9;
    2808             :     Real64 J10;
    2809             :     Real64 J11;
    2810             :     Real64 J12;
    2811             :     Real64 G1; // irradiance, surface i
    2812             :     Real64 G4;
    2813             :     Real64 G7;
    2814             :     Real64 G10;
    2815             : 
    2816           0 :     Array2D<Real64> A(N + 2, N); // coefficients of the radiosity equations matrix
    2817           0 :     Array1D<Real64> XSOL(N);     // solution vector (obtained after solving the radiosity equations matrix)
    2818             : 
    2819           0 :     TAUBF_BT_PERP = TAUBF_BD_PERP + TAUBF_BB_PERP;
    2820             : 
    2821           0 :     AB = DE;
    2822           0 :     GN = DE;
    2823           0 :     NK = W - DE;
    2824           0 :     BC = NK;
    2825           0 :     AN = std::sqrt(S * S + DE * DE);
    2826           0 :     AK = std::sqrt(W * W + S * S);
    2827           0 :     BG = AN;
    2828           0 :     CG = AK;
    2829           0 :     BK = std::sqrt(S * S + BC * BC);
    2830           0 :     CN = std::sqrt(S * S + NK * NK);
    2831             : 
    2832           0 :     Z1_BB = TAUFF_BB_PARL;
    2833           0 :     Z1_BD = TAUFF_BD_PARL;
    2834           0 :     Z2_BD = Z1_BB * RHOBF_BT_PERP * S / GN;
    2835           0 :     Z6_BB = TAUFF_BB_PERP * S / DE;
    2836           0 :     Z6_BD = TAUFF_BD_PERP * S / DE;
    2837           0 :     Z3_BD = Z6_BB * RHOBF_BT_PERP;
    2838           0 :     Z8_BD = RHOFF_BT_PERP * S / DE;
    2839           0 :     Z11_BD = Z6_BB * TAUBF_BT_PERP;
    2840           0 :     Z12_BD = Z1_BB * TAUBF_BT_PERP * S / GN;
    2841             : 
    2842           0 :     F12 = (S + GN - AN) / (2.0 * S);
    2843           0 :     F13 = (W + AN - (GN + AK)) / (2.0 * S);
    2844           0 :     F15 = (W + BG - (AB + CG)) / (2.0 * S);
    2845           0 :     F16 = (S + AB - BG) / (2.0 * S);
    2846           0 :     F21 = (S + GN - AN) / (2.0 * GN);
    2847           0 :     F25 = (S + CG - (BG + CN)) / (2.0 * GN);
    2848           0 :     F26 = (AN + BG - 2.0 * S) / (2.0 * GN);
    2849           0 :     F31 = (W + AN - (GN + AK)) / (2.0 * NK);
    2850           0 :     F35 = (BK + CN - 2.0 * S) / (2.0 * NK);
    2851           0 :     F36 = (S + AK - (AN + BK)) / (2.0 * NK);
    2852           0 :     F41 = (AK + CG - 2.0 * W) / (2.0 * S);
    2853           0 :     F42 = (W + CN - (CG + NK)) / (2.0 * S);
    2854           0 :     F43 = (S + NK - CN) / (2.0 * S);
    2855           0 :     F45 = (S + BC - BK) / (2.0 * S);
    2856           0 :     F46 = (W + BK - (AK + BC)) / (2.0 * S);
    2857           0 :     F51 = (W + BG - (AB + CG)) / (2.0 * BC);
    2858           0 :     F52 = (S + CG - (BG + CN)) / (2.0 * BC);
    2859           0 :     F53 = (BK + CN - 2.0 * S) / (2.0 * BC);
    2860           0 :     F54 = (S + BC - BK) / (2.0 * BC);
    2861           0 :     F61 = (S + AB - BG) / (2.0 * AB);
    2862           0 :     F62 = (AN + BG - 2.0 * S) / (2.0 * AB);
    2863           0 :     F63 = (S + AK - (AN + BK)) / (2.0 * AB);
    2864           0 :     F78 = F12;
    2865           0 :     F79 = F13;
    2866           0 :     F710 = (AK + CG - 2.0 * W) / (2.0 * S);
    2867           0 :     F711 = F15;
    2868           0 :     F712 = F16;
    2869           0 :     F810 = (W + CN - (CG + NK)) / (2.0 * S);
    2870           0 :     F811 = F25;
    2871           0 :     F812 = F26;
    2872           0 :     F910 = (S + NK - CN) / (2.0 * NK);
    2873           0 :     F911 = F35;
    2874           0 :     F912 = F36;
    2875           0 :     F108 = F42;
    2876           0 :     F109 = F43;
    2877           0 :     F1011 = F45;
    2878           0 :     F1012 = F46;
    2879           0 :     F118 = F52;
    2880           0 :     F119 = F53;
    2881           0 :     F1110 = (S + BC - BK) / (2.0 * NK);
    2882           0 :     F128 = F62;
    2883           0 :     F129 = F63;
    2884           0 :     F1210 = (W + BK - (AK + BC)) / (2.0 * GN);
    2885             : 
    2886           0 :     A = 0.0;    // INITIALIZE RADIOSITY MATRIX COEFFICIENTS
    2887           0 :     XSOL = 0.0; // INITIALIZE SOLUTION VECTOR COEFFICIENTS
    2888             : 
    2889             :     // POPULATE THE COEFFICIENTS OF THE RADIOSITY MATRIX
    2890             : 
    2891           0 :     A(1, 1) = 1.0;
    2892           0 :     A(2, 1) = -RHOBF_DD * F12;
    2893           0 :     A(3, 1) = -RHOBF_DD * F13;
    2894           0 :     A(4, 1) = -RHOBF_DD * F15;
    2895           0 :     A(5, 1) = -RHOBF_DD * F16;
    2896           0 :     A(6, 1) = 0.0;
    2897           0 :     A(7, 1) = 0.0;
    2898           0 :     A(8, 1) = 0.0;
    2899           0 :     A(9, 1) = 0.0;
    2900           0 :     A(10, 1) = 0.0;
    2901           0 :     A(11, 1) = Z1_BD;
    2902           0 :     A(1, 2) = -RHOBF_DD * F21;
    2903           0 :     A(2, 2) = 1.0;
    2904           0 :     A(3, 2) = 0.0;
    2905           0 :     A(4, 2) = -RHOBF_DD * F25;
    2906           0 :     A(5, 2) = -RHOBF_DD * F26;
    2907           0 :     A(6, 2) = -TAUFF_DD * F128;
    2908           0 :     A(7, 2) = -TAUFF_DD * F129;
    2909           0 :     A(8, 2) = -TAUFF_DD * F1210;
    2910           0 :     A(9, 2) = 0.0;
    2911           0 :     A(10, 2) = 0.0;
    2912           0 :     A(11, 2) = Z2_BD;
    2913           0 :     A(1, 3) = -RHOBF_DD * F31;
    2914           0 :     A(2, 3) = 0.0;
    2915           0 :     A(3, 3) = 1.0;
    2916           0 :     A(4, 3) = -RHOBF_DD * F35;
    2917           0 :     A(5, 3) = -RHOBF_DD * F36;
    2918           0 :     A(6, 3) = -TAUFF_DD * F118;
    2919           0 :     A(7, 3) = -TAUFF_DD * F119;
    2920           0 :     A(8, 3) = -TAUFF_DD * F1110;
    2921           0 :     A(9, 3) = 0.0;
    2922           0 :     A(10, 3) = 0.0;
    2923           0 :     A(11, 3) = Z3_BD;
    2924           0 :     A(1, 4) = -RHOBF_DD * F51;
    2925           0 :     A(2, 4) = -RHOBF_DD * F52;
    2926           0 :     A(3, 4) = -RHOBF_DD * F53;
    2927           0 :     A(4, 4) = 1.0;
    2928           0 :     A(5, 4) = 0.0;
    2929           0 :     A(6, 4) = 0.0;
    2930           0 :     A(7, 4) = 0.0;
    2931           0 :     A(8, 4) = -TAUFF_DD * F910;
    2932           0 :     A(9, 4) = -TAUFF_DD * F911;
    2933           0 :     A(10, 4) = -TAUFF_DD * F912;
    2934           0 :     A(11, 4) = 0.0;
    2935           0 :     A(1, 5) = -RHOBF_DD * F61;
    2936           0 :     A(2, 5) = -RHOBF_DD * F62;
    2937           0 :     A(3, 5) = -RHOBF_DD * F63;
    2938           0 :     A(4, 5) = 0.0;
    2939           0 :     A(5, 5) = 1.0;
    2940           0 :     A(6, 5) = 0.0;
    2941           0 :     A(7, 5) = 0.0;
    2942           0 :     A(8, 5) = -TAUFF_DD * F810;
    2943           0 :     A(9, 5) = -TAUFF_DD * F811;
    2944           0 :     A(10, 5) = -TAUFF_DD * F812;
    2945           0 :     A(11, 5) = Z6_BD;
    2946           0 :     A(1, 6) = -TAUBF_DD * F61;
    2947           0 :     A(2, 6) = -TAUBF_DD * F62;
    2948           0 :     A(3, 6) = -TAUBF_DD * F63;
    2949           0 :     A(4, 6) = 0.0;
    2950           0 :     A(5, 6) = 0.0;
    2951           0 :     A(6, 6) = 1.0;
    2952           0 :     A(7, 6) = 0.0;
    2953           0 :     A(8, 6) = -RHOFF_DD * F810;
    2954           0 :     A(9, 6) = -RHOFF_DD * F811;
    2955           0 :     A(10, 6) = -RHOFF_DD * F812;
    2956           0 :     A(11, 6) = Z8_BD;
    2957           0 :     A(1, 7) = -TAUBF_DD * F51;
    2958           0 :     A(2, 7) = -TAUBF_DD * F52;
    2959           0 :     A(3, 7) = -TAUBF_DD * F53;
    2960           0 :     A(4, 7) = 0.0;
    2961           0 :     A(5, 7) = 0.0;
    2962           0 :     A(6, 7) = 0.0;
    2963           0 :     A(7, 7) = 1.0;
    2964           0 :     A(8, 7) = -RHOFF_DD * F910;
    2965           0 :     A(9, 7) = -RHOFF_DD * F911;
    2966           0 :     A(10, 7) = -RHOFF_DD * F912;
    2967           0 :     A(11, 7) = 0.0;
    2968           0 :     A(1, 8) = 0.0;
    2969           0 :     A(2, 8) = 0.0;
    2970           0 :     A(3, 8) = 0.0;
    2971           0 :     A(4, 8) = 0.0;
    2972           0 :     A(5, 8) = 0.0;
    2973           0 :     A(6, 8) = -RHOFF_DD * F108;
    2974           0 :     A(7, 8) = -RHOFF_DD * F109;
    2975           0 :     A(8, 8) = 1.0;
    2976           0 :     A(9, 8) = -RHOFF_DD * F1011;
    2977           0 :     A(10, 8) = -RHOFF_DD * F1012;
    2978           0 :     A(11, 8) = 0.0;
    2979           0 :     A(1, 9) = -TAUBF_DD * F31;
    2980           0 :     A(2, 9) = 0.0;
    2981           0 :     A(3, 9) = 0.0;
    2982           0 :     A(4, 9) = -TAUBF_DD * F35;
    2983           0 :     A(5, 9) = -TAUBF_DD * F36;
    2984           0 :     A(6, 9) = -RHOFF_DD * F118;
    2985           0 :     A(7, 9) = -RHOFF_DD * F119;
    2986           0 :     A(8, 9) = -RHOFF_DD * F1110;
    2987           0 :     A(9, 9) = 1.0;
    2988           0 :     A(10, 9) = 0.0;
    2989           0 :     A(11, 9) = Z11_BD;
    2990           0 :     A(1, 10) = -TAUBF_DD * F21;
    2991           0 :     A(2, 10) = 0.0;
    2992           0 :     A(3, 10) = 0.0;
    2993           0 :     A(4, 10) = -TAUBF_DD * F25;
    2994           0 :     A(5, 10) = -TAUBF_DD * F26;
    2995           0 :     A(6, 10) = -RHOFF_DD * F128;
    2996           0 :     A(7, 10) = -RHOFF_DD * F129;
    2997           0 :     A(8, 10) = -RHOFF_DD * F1210;
    2998           0 :     A(9, 10) = 0.0;
    2999           0 :     A(10, 10) = 1.0;
    3000           0 :     A(11, 10) = Z12_BD;
    3001             : 
    3002           0 :     SOLMATS(N, A, XSOL);
    3003             : 
    3004           0 :     J1 = XSOL(1);
    3005           0 :     J2 = XSOL(2);
    3006           0 :     J3 = XSOL(3);
    3007           0 :     J5 = XSOL(4);
    3008           0 :     J6 = XSOL(5);
    3009           0 :     J8 = XSOL(6);
    3010           0 :     J9 = XSOL(7);
    3011           0 :     J10 = XSOL(8);
    3012           0 :     J11 = XSOL(9);
    3013           0 :     J12 = XSOL(10);
    3014             : 
    3015           0 :     G1 = F12 * J2 + F13 * J3 + F15 * J5 + F16 * J6;
    3016           0 :     G4 = F41 * J1 + F42 * J2 + F43 * J3 + F45 * J5 + F46 * J6;
    3017           0 :     G7 = F78 * J8 + F79 * J9 + F710 * J10 + F711 * J11 + F712 * J12;
    3018           0 :     G10 = F108 * J8 + F109 * J9 + F1011 * J11 + F1012 * J12;
    3019             : 
    3020           0 :     TAU_BB = (TAUFF_BB_PERP * (AB - NK) * std::abs(std::sin(OMEGA_H))) / (2.0 * S * std::abs(std::cos(OMEGA_H)));
    3021           0 :     TAU_BD = (G4 + TAUFF_DD * G10) / 2.0;
    3022           0 :     RHO_BD = (RHOFF_BT_PARL + TAUBF_DD * G1 + G7) / 2.0;
    3023           0 : }
    3024             : 
    3025           0 : void PD_BEAM_CASE_IV(Real64 const S,                        // pleat spacing (> 0)
    3026             :                      Real64 const W,                        // pleat depth (>=0, same units as S)
    3027             :                      [[maybe_unused]] Real64 const OMEGA_H, // horizontal profile angle, radians
    3028             :                      [[maybe_unused]] Real64 const DE,      // width of illumination on pleat bottom (same units as S)
    3029             :                      Real64 const RHOFF_BT_PARL,
    3030             :                      Real64 const TAUFF_BB_PARL,
    3031             :                      Real64 const TAUFF_BD_PARL,
    3032             :                      [[maybe_unused]] Real64 const RHOBF_BT_PARL,
    3033             :                      [[maybe_unused]] Real64 const TAUBF_BB_PARL,
    3034             :                      [[maybe_unused]] Real64 const TAUBF_BD_PARL,
    3035             :                      Real64 const RHOFF_BT_PERP,
    3036             :                      Real64 const TAUFF_BB_PERP,
    3037             :                      Real64 const TAUFF_BD_PERP,
    3038             :                      Real64 const RHOBF_BT_PERP,
    3039             :                      Real64 const TAUBF_BB_PERP,
    3040             :                      Real64 const TAUBF_BD_PERP,
    3041             :                      Real64 const RHOBF_DD, // fabric back diffuse-diffuse reflectance
    3042             :                      Real64 const RHOFF_DD, // fabric front diffuse-diffuse reflectance
    3043             :                      Real64 const TAUFF_DD, // fabric front diffuse-diffuse transmittance
    3044             :                      Real64 const TAUBF_DD, // fabric back diffuse-diffuse transmittance
    3045             :                      Real64 &RHO_BD,        // returned: drape front beam-diffuse reflectance
    3046             :                      Real64 &TAU_BD,        // returned: drape front beam-diffuse transmittance
    3047             :                      Real64 &TAU_BB         // returned: drape front beam-beam transmittance
    3048             : )
    3049             : {
    3050             :     // SUBROUTINE INFORMATION:
    3051             :     //       AUTHOR         John L. Wright, University of Waterloo,
    3052             :     //                      Mechanical Engineering, Advanced Glazing System Laboratory
    3053             :     //       DATE WRITTEN   Unknown
    3054             :     //       MODIFIED       na
    3055             :     //       RE-ENGINEERED  na
    3056             : 
    3057             :     // PURPOSE OF THIS SUBROUTINE:
    3058             :     //  calculates the effective front-side solar optical properties of a drapery layer.
    3059             :     // METHODOLOGY EMPLOYED:
    3060             :     // Eight surface flat-fabric model with rectangular enclosure
    3061             : 
    3062             :     // fabric properties at current (off-normal) incidence
    3063             :     //   _PARL = surface parallel to window (pleat top/bot)
    3064             :     //   _PERP = surface perpendicular to window (pleat side)
    3065             :     // SUBROUTINE PARAMETER DEFINITIONS:
    3066           0 :     int constexpr N(6);
    3067             : 
    3068             :     Real64 TAUBF_BT_PERP;
    3069             :     Real64 AK; // length of diagonal strings
    3070             :     Real64 CG;
    3071             :     Real64 Z1_BB; // beam source term
    3072             :     Real64 Z1_BD; // diffuse source terms
    3073             :     Real64 Z2_BD;
    3074             :     Real64 Z4_BD;
    3075             :     Real64 Z6_BD;
    3076             :     Real64 Z8_BD;
    3077             :     // shape factors
    3078             :     Real64 F12;
    3079             :     Real64 F14;
    3080             :     Real64 F21;
    3081             :     Real64 F24;
    3082             :     Real64 F31;
    3083             :     Real64 F32;
    3084             :     Real64 F34;
    3085             :     Real64 F41;
    3086             :     Real64 F42;
    3087             :     Real64 F56;
    3088             :     Real64 F57;
    3089             :     Real64 F58;
    3090             :     Real64 F67;
    3091             :     Real64 F68;
    3092             :     Real64 F76;
    3093             :     Real64 F78;
    3094             :     Real64 F86;
    3095             :     Real64 F87;
    3096             :     Real64 J1; // radiosity, surface i
    3097             :     Real64 J2;
    3098             :     Real64 J4;
    3099             :     Real64 J6;
    3100             :     Real64 J7;
    3101             :     Real64 J8;
    3102             :     Real64 G1; // irradiance, surface i
    3103             :     Real64 G3;
    3104             :     Real64 G5;
    3105             :     Real64 G7;
    3106           0 :     Array2D<Real64> A(N + 2, N); // coefficients of the radiosity equations matrix
    3107           0 :     Array1D<Real64> XSOL(N);     // solution vector (obtained after solving the radiosity equations matrix)
    3108             : 
    3109           0 :     TAUBF_BT_PERP = TAUBF_BD_PERP + TAUBF_BB_PERP;
    3110             : 
    3111           0 :     AK = std::sqrt(W * W + S * S);
    3112           0 :     CG = AK;
    3113             : 
    3114           0 :     Z1_BB = TAUFF_BB_PARL;
    3115           0 :     Z1_BD = TAUFF_BD_PARL;
    3116           0 :     Z2_BD = Z1_BB * RHOBF_BT_PERP * S / W;
    3117           0 :     Z4_BD = TAUFF_BD_PERP * S / W;
    3118           0 :     Z6_BD = RHOFF_BT_PERP * S / W;
    3119           0 :     Z8_BD = Z1_BB * TAUBF_BT_PERP * S / W;
    3120             : 
    3121           0 :     F12 = (S + W - AK) / (2.0 * S);
    3122           0 :     F14 = (S + W - CG) / (2.0 * S);
    3123           0 :     F21 = (S + W - AK) / (2.0 * W);
    3124           0 :     F24 = (AK + CG - 2.0 * S) / (2.0 * W);
    3125           0 :     F31 = (AK + CG - 2.0 * W) / (2.0 * S);
    3126           0 :     F32 = F12;
    3127           0 :     F34 = F12;
    3128           0 :     F41 = F21;
    3129           0 :     F42 = F24;
    3130           0 :     F56 = F12;
    3131           0 :     F57 = F31;
    3132           0 :     F58 = F14;
    3133           0 :     F67 = F41;
    3134           0 :     F68 = F24;
    3135           0 :     F76 = F32;
    3136           0 :     F78 = F34;
    3137           0 :     F86 = F42;
    3138           0 :     F87 = F21;
    3139             : 
    3140           0 :     A = 0.0;    // INITIALIZE RADIOSITY MATRIX COEFFICIENTS
    3141           0 :     XSOL = 0.0; // INITIALIZE SOLUTION VECTOR COEFFICIENTS
    3142             : 
    3143             :     // POPULATE THE COEFFICIENTS OF THE RADIOSITY MATRIX
    3144             : 
    3145           0 :     A(1, 1) = 1.0;
    3146           0 :     A(2, 1) = -RHOBF_DD * F12;
    3147           0 :     A(3, 1) = -RHOBF_DD * F14;
    3148           0 :     A(4, 1) = 0.0;
    3149           0 :     A(5, 1) = 0.0;
    3150           0 :     A(6, 1) = 0.0;
    3151           0 :     A(7, 1) = Z1_BD;
    3152           0 :     A(1, 2) = -RHOBF_DD * F21;
    3153           0 :     A(2, 2) = 1.0;
    3154           0 :     A(3, 2) = -RHOBF_DD * F24;
    3155           0 :     A(4, 2) = -TAUFF_DD * F86;
    3156           0 :     A(5, 2) = -TAUFF_DD * F87;
    3157           0 :     A(6, 2) = 0.0;
    3158           0 :     A(7, 2) = Z2_BD;
    3159           0 :     A(1, 3) = -RHOBF_DD * F41;
    3160           0 :     A(2, 3) = -RHOBF_DD * F42;
    3161           0 :     A(3, 3) = 1.0;
    3162           0 :     A(4, 3) = 0.0;
    3163           0 :     A(5, 3) = -TAUFF_DD * F67;
    3164           0 :     A(6, 3) = -TAUFF_DD * F68;
    3165           0 :     A(7, 3) = Z4_BD;
    3166           0 :     A(1, 4) = -TAUBF_DD * F41;
    3167           0 :     A(2, 4) = -TAUBF_DD * F42;
    3168           0 :     A(3, 4) = 0.0;
    3169           0 :     A(4, 4) = 1.0;
    3170           0 :     A(5, 4) = -RHOFF_DD * F67;
    3171           0 :     A(6, 4) = -RHOFF_DD * F68;
    3172           0 :     A(7, 4) = Z6_BD;
    3173           0 :     A(1, 5) = 0.0;
    3174           0 :     A(2, 5) = 0.0;
    3175           0 :     A(3, 5) = 0.0;
    3176           0 :     A(4, 5) = -RHOFF_DD * F76;
    3177           0 :     A(5, 5) = 1.0;
    3178           0 :     A(6, 5) = -RHOFF_DD * F78;
    3179           0 :     A(7, 5) = 0.0;
    3180           0 :     A(1, 6) = -TAUBF_DD * F21;
    3181           0 :     A(2, 6) = 0.0;
    3182           0 :     A(3, 6) = -TAUBF_DD * F24;
    3183           0 :     A(4, 6) = -RHOFF_DD * F86;
    3184           0 :     A(5, 6) = -RHOFF_DD * F87;
    3185           0 :     A(6, 6) = 1.0;
    3186           0 :     A(7, 6) = Z8_BD;
    3187             : 
    3188           0 :     SOLMATS(N, A, XSOL);
    3189             : 
    3190           0 :     J1 = XSOL(1);
    3191           0 :     J2 = XSOL(2);
    3192           0 :     J4 = XSOL(3);
    3193           0 :     J6 = XSOL(4);
    3194           0 :     J7 = XSOL(5);
    3195           0 :     J8 = XSOL(6);
    3196             : 
    3197           0 :     G1 = F12 * J2 + F14 * J4;
    3198           0 :     G3 = F31 * J1 + F32 * J2 + F34 * J4;
    3199           0 :     G5 = F56 * J6 + F57 * J7 + F58 * J8;
    3200           0 :     G7 = F76 * J6 + F78 * J8;
    3201             : 
    3202           0 :     TAU_BB = TAUFF_BB_PERP / 2.0;
    3203           0 :     TAU_BD = (G3 + TAUFF_DD * G7) / 2.0;
    3204           0 :     RHO_BD = (RHOFF_BT_PARL + TAUBF_DD * G1 + G5) / 2.0;
    3205           0 : }
    3206             : 
    3207           0 : void PD_BEAM_CASE_V(Real64 const S,       // pleat spacing (> 0)
    3208             :                     Real64 const W,       // pleat depth (>=0, same units as S)
    3209             :                     Real64 const OMEGA_H, // horizontal profile angle, radians
    3210             :                     Real64 const DE,      // width of illumination on pleat bottom (same units as S)
    3211             :                     Real64 const RHOFF_BT_PARL,
    3212             :                     Real64 const TAUFF_BB_PARL,
    3213             :                     Real64 const TAUFF_BD_PARL,
    3214             :                     [[maybe_unused]] Real64 const RHOBF_BT_PARL,
    3215             :                     [[maybe_unused]] Real64 const TAUBF_BB_PARL,
    3216             :                     [[maybe_unused]] Real64 const TAUBF_BD_PARL,
    3217             :                     Real64 const RHOFF_BT_PERP,
    3218             :                     Real64 const TAUFF_BB_PERP,
    3219             :                     Real64 const TAUFF_BD_PERP,
    3220             :                     Real64 const RHOBF_BT_PERP,
    3221             :                     Real64 const TAUBF_BB_PERP,
    3222             :                     Real64 const TAUBF_BD_PERP,
    3223             :                     Real64 const RHOBF_DD, // fabric back diffuse-diffuse reflectance
    3224             :                     Real64 const RHOFF_DD, // fabric front diffuse-diffuse reflectance
    3225             :                     Real64 const TAUFF_DD, // fabric front diffuse-diffuse transmittance
    3226             :                     Real64 const TAUBF_DD, // fabric back diffuse-diffuse transmittance
    3227             :                     Real64 &RHO_BD,        // returned: drape front beam-diffuse reflectance
    3228             :                     Real64 &TAU_BD,        // returned: drape front beam-diffuse transmittance
    3229             :                     Real64 &TAU_BB         // returned: drape front beam-beam transmittance
    3230             : )
    3231             : {
    3232             : 
    3233             :     // SUBROUTINE INFORMATION:
    3234             :     //       AUTHOR         John L. Wright, University of Waterloo,
    3235             :     //                      Mechanical Engineering, Advanced Glazing System Laboratory
    3236             :     //       DATE WRITTEN   Unknown
    3237             :     //       MODIFIED       na
    3238             :     //       RE-ENGINEERED  na
    3239             : 
    3240             :     // PURPOSE OF THIS SUBROUTINE:
    3241             :     //  calculates the effective front-side solar optical properties of a drapery layer.
    3242             :     // METHODOLOGY EMPLOYED:
    3243             :     // NINE SURFACE FLAT-FABRIC MODEL WITH RECTANGULAR ENCLOSURE
    3244             : 
    3245             :     // fabric properties at current (off-normal) incidence
    3246             :     //   _PARL = surface parallel to window (pleat top/bot)
    3247             :     //   _PERP = surface perpendicular to window (pleat side)
    3248             :     // SUBROUTINE PARAMETER DEFINITIONS:
    3249           0 :     int constexpr N(7);
    3250             : 
    3251             :     Real64 TAUBF_BT_PERP;
    3252             :     Real64 AK; // lengths of surfaces and diagonal strings
    3253             :     Real64 CG;
    3254             :     Real64 MK;
    3255             :     Real64 DK;
    3256             :     Real64 MF;
    3257             :     Real64 DM;
    3258             :     Real64 GM;
    3259             :     Real64 GF;
    3260             :     Real64 Z1_BB; // beam source term
    3261             :     Real64 Z1_BD; // diffuse source terms
    3262             :     Real64 Z2_BD;
    3263             :     Real64 Z4_BD;
    3264             :     Real64 Z6_BD;
    3265             :     Real64 Z7_BD;
    3266             :     Real64 Z9_BD;
    3267             :     // shape factors
    3268             :     Real64 F12;
    3269             :     Real64 F14;
    3270             :     Real64 F21;
    3271             :     Real64 F24;
    3272             :     Real64 F31;
    3273             :     Real64 F32;
    3274             :     Real64 F34;
    3275             :     Real64 F41;
    3276             :     Real64 F42;
    3277             :     Real64 F56;
    3278             :     Real64 F57;
    3279             :     Real64 F58;
    3280             :     Real64 F59;
    3281             :     Real64 F67;
    3282             :     Real64 F68;
    3283             :     Real64 F69;
    3284             :     Real64 F76;
    3285             :     Real64 F79;
    3286             :     Real64 F86;
    3287             :     Real64 F89;
    3288             :     Real64 F96;
    3289             :     Real64 F97;
    3290             :     Real64 F98;
    3291             :     Real64 J1; // radiosities
    3292             :     Real64 J2;
    3293             :     Real64 J4;
    3294             :     Real64 J6;
    3295             :     Real64 J7;
    3296             :     Real64 J8;
    3297             :     Real64 J9;
    3298             :     Real64 G1; // irradiances
    3299             :     Real64 G3;
    3300             :     Real64 G5;
    3301             :     Real64 G7;
    3302             :     Real64 G8;
    3303             : 
    3304           0 :     Array2D<Real64> A(N + 2, N); // coefficients of the radiosity equations matrix
    3305           0 :     Array1D<Real64> XSOL(N);     // solution vector (obtained after solving the radiosity equations matrix)
    3306             : 
    3307           0 :     TAUBF_BT_PERP = TAUBF_BD_PERP + TAUBF_BB_PERP;
    3308             : 
    3309           0 :     AK = std::sqrt(W * W + S * S);
    3310           0 :     CG = AK;
    3311           0 :     Real64 const cos_OMEGA_H(std::abs(std::cos(OMEGA_H)));
    3312           0 :     Real64 const sin_OMEGA_H(std::abs(std::sin(OMEGA_H)));
    3313           0 :     MK = (W * sin_OMEGA_H) / cos_OMEGA_H;
    3314           0 :     DK = AK;
    3315           0 :     MF = S - MK;
    3316           0 :     DM = std::sqrt(W * W + MF * MF);
    3317           0 :     GM = std::sqrt(W * W + MK * MK);
    3318           0 :     GF = AK;
    3319             : 
    3320           0 :     Z1_BB = TAUFF_BB_PARL;
    3321           0 :     Z1_BD = TAUFF_BD_PARL;
    3322           0 :     Z2_BD = Z1_BB * RHOBF_BT_PERP * S / DE;
    3323           0 :     Z4_BD = TAUFF_BD_PERP * S / DE;
    3324           0 :     Z6_BD = RHOFF_BT_PERP * S / DE;
    3325           0 :     Z7_BD = RHOFF_BT_PARL;
    3326           0 :     Z9_BD = Z1_BB * TAUBF_BT_PERP * S / DE;
    3327             : 
    3328           0 :     F12 = (S + W - AK) / (2.0 * S);
    3329           0 :     F14 = (S + W - CG) / (2.0 * S);
    3330           0 :     F21 = (S + W - AK) / (2.0 * W);
    3331           0 :     F24 = (AK + CG - 2.0 * S) / (2.0 * W);
    3332           0 :     F31 = (AK + CG - 2.0 * W) / (2.0 * S);
    3333           0 :     F32 = F14;
    3334           0 :     F34 = F12;
    3335           0 :     F41 = F21;
    3336           0 :     F42 = F24;
    3337           0 :     F56 = F12;
    3338           0 :     F57 = (DM + GF - (GM + W)) / (2.0 * S);
    3339           0 :     F58 = (DK + GM - (DM + W)) / (2.0 * S);
    3340           0 :     F59 = F14;
    3341           0 :     F67 = (W + MF - DM) / (2.0 * W);
    3342           0 :     F68 = (DM + S - (DK + MF)) / (2.0 * W);
    3343           0 :     F69 = F24;
    3344           0 :     F76 = (W + MF - DM) / (2.0 * MF);
    3345           0 :     F79 = (GM + S - (GF + MK)) / (2.0 * MF);
    3346           0 :     F86 = (DM + S - (DK + MF)) / (2.0 * MK);
    3347           0 :     F89 = (W + MK - GM) / (2.0 * MK);
    3348           0 :     F96 = F42;
    3349           0 :     F97 = (GM + S - (GF + MK)) / (2.0 * W);
    3350           0 :     F98 = (W + MK - GM) / (2.0 * W);
    3351             : 
    3352           0 :     A = 0.0;    // INITIALIZE RADIOSITY MATRIX COEFFICIENTS
    3353           0 :     XSOL = 0.0; // INITIALIZE SOLUTION VECTOR COEFFICIENTS
    3354             : 
    3355             :     // POPULATE THE COEFFICIENTS OF THE RADIOSITY MATRIX
    3356             : 
    3357           0 :     A(1, 1) = 1.0;
    3358           0 :     A(2, 1) = -RHOBF_DD * F12;
    3359           0 :     A(3, 1) = -RHOBF_DD * F14;
    3360           0 :     A(4, 1) = 0.0;
    3361           0 :     A(5, 1) = 0.0;
    3362           0 :     A(6, 1) = 0.0;
    3363           0 :     A(7, 1) = 0.0;
    3364           0 :     A(8, 1) = Z1_BD;
    3365           0 :     A(1, 2) = -RHOBF_DD * F21;
    3366           0 :     A(2, 2) = 1.0;
    3367           0 :     A(3, 2) = -RHOBF_DD * F24;
    3368           0 :     A(4, 2) = -TAUFF_DD * F96;
    3369           0 :     A(5, 2) = -TAUFF_DD * F97;
    3370           0 :     A(6, 2) = -TAUFF_DD * F98;
    3371           0 :     A(7, 2) = 0.0;
    3372           0 :     A(8, 2) = Z2_BD;
    3373           0 :     A(1, 3) = -RHOBF_DD * F41;
    3374           0 :     A(2, 3) = -RHOBF_DD * F42;
    3375           0 :     A(3, 3) = 1.0;
    3376           0 :     A(4, 3) = 0.0;
    3377           0 :     A(5, 3) = -TAUFF_DD * F67;
    3378           0 :     A(6, 3) = -TAUFF_DD * F68;
    3379           0 :     A(7, 3) = -TAUFF_DD * F69;
    3380           0 :     A(8, 3) = Z4_BD;
    3381           0 :     A(1, 4) = -TAUBF_DD * F41;
    3382           0 :     A(2, 4) = -TAUBF_DD * F42;
    3383           0 :     A(3, 4) = 0.0;
    3384           0 :     A(4, 4) = 1.0;
    3385           0 :     A(5, 4) = -RHOFF_DD * F67;
    3386           0 :     A(6, 4) = -RHOFF_DD * F68;
    3387           0 :     A(7, 4) = -RHOFF_DD * F69;
    3388           0 :     A(8, 4) = Z6_BD;
    3389           0 :     A(1, 5) = 0.0;
    3390           0 :     A(2, 5) = 0.0;
    3391           0 :     A(3, 5) = 0.0;
    3392           0 :     A(4, 5) = -RHOFF_DD * F76;
    3393           0 :     A(5, 5) = 1.0;
    3394           0 :     A(6, 5) = 0.0;
    3395           0 :     A(7, 5) = -RHOFF_DD * F79;
    3396           0 :     A(8, 5) = Z7_BD;
    3397           0 :     A(1, 6) = 0.0;
    3398           0 :     A(2, 6) = 0.0;
    3399           0 :     A(3, 6) = 0.0;
    3400           0 :     A(4, 6) = -RHOFF_DD * F86;
    3401           0 :     A(5, 6) = 0.0;
    3402           0 :     A(6, 6) = 1.0;
    3403           0 :     A(7, 6) = -RHOFF_DD * F89;
    3404           0 :     A(8, 6) = 0.0;
    3405           0 :     A(1, 7) = -TAUBF_DD * F21;
    3406           0 :     A(2, 7) = 0.0;
    3407           0 :     A(3, 7) = -TAUBF_DD * F24;
    3408           0 :     A(4, 7) = -RHOFF_DD * F96;
    3409           0 :     A(5, 7) = -RHOFF_DD * F97;
    3410           0 :     A(6, 7) = -RHOFF_DD * F98;
    3411           0 :     A(7, 7) = 1.0;
    3412           0 :     A(8, 7) = Z9_BD;
    3413             : 
    3414           0 :     SOLMATS(N, A, XSOL);
    3415             : 
    3416           0 :     J1 = XSOL(1);
    3417           0 :     J2 = XSOL(2);
    3418           0 :     J4 = XSOL(3);
    3419           0 :     J6 = XSOL(4);
    3420           0 :     J7 = XSOL(5);
    3421           0 :     J8 = XSOL(6);
    3422           0 :     J9 = XSOL(7);
    3423             : 
    3424           0 :     G1 = F12 * J2 + F14 * J4;
    3425           0 :     G3 = F31 * J1 + F32 * J2 + F34 * J4;
    3426           0 :     G5 = F56 * J6 + F57 * J7 + F58 * J8 + F59 * J9;
    3427           0 :     G7 = F76 * J6 + F79 * J9;
    3428           0 :     G8 = F86 * J6 + F89 * J9;
    3429             : 
    3430           0 :     TAU_BB = (2.0 * (DE - W) * sin_OMEGA_H * TAUFF_BB_PARL + (S * cos_OMEGA_H - (DE - W) * sin_OMEGA_H) * TAUFF_BB_PERP) / (2.0 * S * cos_OMEGA_H);
    3431           0 :     TAU_BD = (S * G3 + TAUFF_DD * (MK * G8 + MF * G7) + MF * TAUFF_BD_PARL) / (2.0 * S);
    3432           0 :     RHO_BD = (RHOFF_BT_PARL + TAUBF_DD * G1 + G5) / 2.0;
    3433           0 : }
    3434             : 
    3435           0 : void PD_BEAM_CASE_VI(Real64 const S,                        // pleat spacing (> 0)
    3436             :                      Real64 const W,                        // pleat depth (>=0, same units as S)
    3437             :                      [[maybe_unused]] Real64 const OMEGA_H, // horizontal profile angle, radians
    3438             :                      [[maybe_unused]] Real64 const DE,      // width of illumination on pleat bottom (same units as S)
    3439             :                      Real64 const RHOFF_BT_PARL,
    3440             :                      Real64 const TAUFF_BB_PARL,
    3441             :                      Real64 const TAUFF_BD_PARL,
    3442             :                      [[maybe_unused]] Real64 const RHOBF_BT_PARL,
    3443             :                      [[maybe_unused]] Real64 const TAUBF_BB_PARL,
    3444             :                      [[maybe_unused]] Real64 const TAUBF_BD_PARL,
    3445             :                      [[maybe_unused]] Real64 const RHOFF_BT_PERP,
    3446             :                      [[maybe_unused]] Real64 const TAUFF_BB_PERP,
    3447             :                      [[maybe_unused]] Real64 const TAUFF_BD_PERP,
    3448             :                      [[maybe_unused]] Real64 const RHOBF_BT_PERP,
    3449             :                      [[maybe_unused]] Real64 const TAUBF_BB_PERP,
    3450             :                      [[maybe_unused]] Real64 const TAUBF_BD_PERP,
    3451             :                      Real64 const RHOBF_DD, // fabric back diffuse-diffuse reflectance
    3452             :                      Real64 const RHOFF_DD, // fabric front diffuse-diffuse reflectance
    3453             :                      Real64 const TAUFF_DD, // fabric front diffuse-diffuse transmittance
    3454             :                      Real64 const TAUBF_DD, // fabric back diffuse-diffuse transmittance
    3455             :                      Real64 &RHO_BD,        // returned: drape front beam-diffuse reflectance
    3456             :                      Real64 &TAU_BD,        // returned: drape front beam-diffuse transmittance
    3457             :                      Real64 &TAU_BB         // returned: drape front beam-beam transmittance
    3458             : )
    3459             : {
    3460             : 
    3461             :     // SUBROUTINE INFORMATION:
    3462             :     //       AUTHOR         John L. Wright, University of Waterloo,
    3463             :     //                      Mechanical Engineering, Advanced Glazing System Laboratory
    3464             :     //       DATE WRITTEN   Unknown
    3465             :     //       MODIFIED       na
    3466             :     //       RE-ENGINEERED  na
    3467             : 
    3468             :     // PURPOSE OF THIS SUBROUTINE:
    3469             :     //  calculates the effective front-side solar optical properties of a drapery layer.
    3470             :     // METHODOLOGY EMPLOYED:
    3471             :     // EIGHT SURFACE FLAT-FABRIC MODEL WITH RECTANGULAR ENCLOSURE
    3472             : 
    3473             :     // fabric properties at current (off-normal) incidence
    3474             :     //   _PARL = surface parallel to window (pleat top/bot)
    3475             :     //   _PERP = surface perpendicular to window (pleat side)
    3476             :     // SUBROUTINE PARAMETER DEFINITIONS:
    3477           0 :     int constexpr N(6);
    3478             : 
    3479             :     Real64 AK; // length of diagonal strings
    3480             :     Real64 CG;
    3481             :     Real64 Z1_BD; // diffuse source termps
    3482             :     Real64 Z7_BD;
    3483             :     // shape factors
    3484             :     Real64 F12;
    3485             :     Real64 F14;
    3486             :     Real64 F21;
    3487             :     Real64 F24;
    3488             :     Real64 F31;
    3489             :     Real64 F32;
    3490             :     Real64 F34;
    3491             :     Real64 F41;
    3492             :     Real64 F42;
    3493             :     Real64 F56;
    3494             :     Real64 F57;
    3495             :     Real64 F58;
    3496             :     Real64 F67;
    3497             :     Real64 F68;
    3498             :     Real64 F76;
    3499             :     Real64 F78;
    3500             :     Real64 F86;
    3501             :     Real64 F87;
    3502             :     Real64 J1; // radiosity, surface i
    3503             :     Real64 J2;
    3504             :     Real64 J4;
    3505             :     Real64 J6;
    3506             :     Real64 J7;
    3507             :     Real64 J8;
    3508             :     Real64 G1; // irradiance, surface i
    3509             :     Real64 G3;
    3510             :     Real64 G5;
    3511             :     Real64 G7;
    3512           0 :     Array2D<Real64> A(N + 2, N); // coefficients of the radiosity equations matrix
    3513           0 :     Array1D<Real64> XSOL(N);     // solution vector (obtained after solving the radiosity equations matrix)
    3514             : 
    3515           0 :     AK = std::sqrt(W * W + S * S);
    3516           0 :     CG = AK;
    3517             : 
    3518           0 :     Z1_BD = TAUFF_BD_PARL;
    3519           0 :     Z7_BD = RHOFF_BT_PARL;
    3520             : 
    3521           0 :     F12 = (S + W - AK) / (2.0 * S);
    3522           0 :     F14 = (S + W - CG) / (2.0 * S);
    3523           0 :     F21 = (S + W - AK) / (2.0 * W);
    3524           0 :     F24 = (AK + CG - 2.0 * S) / (2.0 * W);
    3525           0 :     F31 = (AK + CG - 2.0 * W) / (2.0 * S);
    3526           0 :     F32 = F12;
    3527           0 :     F34 = F14;
    3528           0 :     F41 = F21;
    3529           0 :     F42 = F24;
    3530           0 :     F56 = F12;
    3531           0 :     F57 = F31;
    3532           0 :     F58 = F14;
    3533           0 :     F67 = F41;
    3534           0 :     F68 = F24;
    3535           0 :     F76 = F14;
    3536           0 :     F78 = F14;
    3537           0 :     F86 = F42;
    3538           0 :     F87 = F21;
    3539             : 
    3540           0 :     A = 0.0;
    3541           0 :     XSOL = 0.0;
    3542             : 
    3543             :     // POPULATE THE COEFFICIENTS OF THE RADIOSITY MATRIX
    3544             : 
    3545           0 :     A(1, 1) = 1.0;
    3546           0 :     A(2, 1) = -RHOBF_DD * F12;
    3547           0 :     A(3, 1) = -RHOBF_DD * F14;
    3548           0 :     A(4, 1) = 0.0;
    3549           0 :     A(5, 1) = 0.0;
    3550           0 :     A(6, 1) = 0.0;
    3551           0 :     A(7, 1) = Z1_BD;
    3552           0 :     A(1, 2) = -RHOBF_DD * F21;
    3553           0 :     A(2, 2) = 1.0;
    3554           0 :     A(3, 2) = -RHOBF_DD * F24;
    3555           0 :     A(4, 2) = -TAUFF_DD * F86;
    3556           0 :     A(5, 2) = -TAUFF_DD * F87;
    3557           0 :     A(6, 2) = 0.0;
    3558           0 :     A(7, 2) = 0.0;
    3559           0 :     A(1, 3) = -RHOBF_DD * F41;
    3560           0 :     A(2, 3) = -RHOBF_DD * F42;
    3561           0 :     A(3, 3) = 1.0;
    3562           0 :     A(4, 3) = 0.0;
    3563           0 :     A(5, 3) = -TAUFF_DD * F67;
    3564           0 :     A(6, 3) = -TAUFF_DD * F68;
    3565           0 :     A(7, 3) = 0.0;
    3566           0 :     A(1, 4) = -TAUBF_DD * F41;
    3567           0 :     A(2, 4) = -TAUBF_DD * F42;
    3568           0 :     A(3, 4) = 0.0;
    3569           0 :     A(4, 4) = 1.0;
    3570           0 :     A(5, 4) = -RHOFF_DD * F67;
    3571           0 :     A(6, 4) = -RHOFF_DD * F68;
    3572           0 :     A(7, 4) = 0.0;
    3573           0 :     A(1, 5) = 0.0;
    3574           0 :     A(2, 5) = 0.0;
    3575           0 :     A(3, 5) = 0.0;
    3576           0 :     A(4, 5) = -RHOFF_DD * F76;
    3577           0 :     A(5, 5) = 1.0;
    3578           0 :     A(6, 5) = -RHOFF_DD * F78;
    3579           0 :     A(7, 5) = Z7_BD;
    3580           0 :     A(1, 6) = -TAUBF_DD * F21;
    3581           0 :     A(2, 6) = 0.0;
    3582           0 :     A(3, 6) = -TAUBF_DD * F24;
    3583           0 :     A(4, 6) = -RHOFF_DD * F86;
    3584           0 :     A(5, 6) = -RHOFF_DD * F87;
    3585           0 :     A(6, 6) = 1.0;
    3586           0 :     A(7, 6) = 0.0;
    3587             : 
    3588           0 :     SOLMATS(N, A, XSOL);
    3589             : 
    3590           0 :     J1 = XSOL(1);
    3591           0 :     J2 = XSOL(2);
    3592           0 :     J4 = XSOL(3);
    3593           0 :     J6 = XSOL(4);
    3594           0 :     J7 = XSOL(5);
    3595           0 :     J8 = XSOL(6);
    3596             : 
    3597           0 :     G1 = F12 * J2 + F14 * J4;
    3598           0 :     G3 = F31 * J1 + F32 * J2 + F34 * J4;
    3599           0 :     G5 = F56 * J6 + F57 * J7 + F58 * J8;
    3600           0 :     G7 = F76 * J6 + F78 * J8;
    3601             : 
    3602           0 :     TAU_BB = TAUFF_BB_PARL;
    3603           0 :     TAU_BD = (G3 + TAUFF_DD * G7 + TAUFF_BD_PARL) / 2.0;
    3604           0 :     RHO_BD = (RHOFF_BT_PARL + TAUBF_DD * G1 + G5) / 2.0;
    3605           0 : }
    3606             : 
    3607           0 : void VB_DIFF(EnergyPlusData &state,
    3608             :              Real64 const S,           // slat spacing (any length units; same units as W)
    3609             :              Real64 const W,           // slat tip-to-tip width (any length units; same units as S)
    3610             :              Real64 const PHI,         // slat angle, radians (-PI/2 <= PHI <= PI/2)
    3611             :              Real64 const RHODFS_SLAT, // reflectance of downward-facing slat surfaces (concave?)
    3612             :              Real64 const RHOUFS_SLAT, // reflectance of upward-facing slat surfaces (convex?)
    3613             :              Real64 const TAU_SLAT,    // diffuse transmitance of slats
    3614             :              Real64 &RHOFVB,           // returned: front side effective diffuse reflectance of venetian blind
    3615             :              Real64 &TAUVB             // returned: effective diffuse transmittance of venetian blind
    3616             : )
    3617             : {
    3618             :     // SUBROUTINE INFORMATION:
    3619             :     //       AUTHOR         John L. Wright, University of Waterloo,
    3620             :     //                      Mechanical Engineering, Advanced Glazing System Laboratory
    3621             :     //       DATE WRITTEN   Unknown
    3622             :     //       MODIFIED       na
    3623             :     //       RE-ENGINEERED  na
    3624             : 
    3625             :     // PURPOSE OF THIS SUBROUTINE:
    3626             :     //  Calculates the venetian blind layer effective diffuse transmittance and reflectance.
    3627             :     // METHODOLOGY EMPLOYED:
    3628             :     // four surface flat-slat model with slat transmittance
    3629             : 
    3630             :     // SUBROUTINE ARGUMENT DEFINITIONS:
    3631             :     //    must be > 0
    3632             :     //   must be > 0
    3633             :     //   ltyVBHOR: + = front-side slat tip below horizontal
    3634             :     //   ltyVBVER: + = front-side slat tip is counter-
    3635             :     //                 clockwise from normal (viewed from above)
    3636             :     // SUBROUTINE PARAMETER DEFINITIONS:
    3637             :     static constexpr std::string_view Tau_Name("VB_DIFF Tau");
    3638             :     static constexpr std::string_view RhoF_Name("VB_DIFF RhoF");
    3639             : 
    3640             :     Real64 CD; // lengths of the diagonal strings used in the four-surface model
    3641             :     Real64 AF;
    3642             :     Real64 F13; // shape factors
    3643             :     Real64 F14;
    3644             :     Real64 F12;
    3645             :     Real64 F31;
    3646             :     Real64 F41;
    3647             :     Real64 FSS;
    3648             :     Real64 C3; // temporaries
    3649             :     Real64 B3;
    3650             :     Real64 C4;
    3651             :     Real64 B4;
    3652             :     Real64 K3;
    3653             :     Real64 K4;
    3654             :     Real64 DEN;
    3655             : 
    3656           0 :     Real64 const W_cos_PHI_2(pow_2(W * std::cos(PHI)));
    3657           0 :     Real64 const W_sin_PHI(W * std::sin(PHI));
    3658           0 :     CD = std::sqrt(W_cos_PHI_2 + pow_2(S + W_sin_PHI));
    3659           0 :     AF = std::sqrt(W_cos_PHI_2 + pow_2(S - W_sin_PHI));
    3660             : 
    3661           0 :     F13 = (W + S - CD) / (2.0 * S);    // SHAPE FACTOR FRONT OPENING TO TOP SLAT
    3662           0 :     F14 = (W + S - AF) / (2.0 * S);    // SHAPE FACTOR FRONT OPENING TO BOTTOM SLAT
    3663           0 :     FSS = 1.0 - (S / W) * (F13 + F14); // SLAT-TO-SLAT SHAPE FACTOR
    3664           0 :     F31 = (S / W) * F13;               // SHAPE FACTOR - TOP TO FRONT
    3665           0 :     F41 = (S / W) * F14;               // SHAPE FACTOR - BOTTOM TO FRONT
    3666           0 :     F12 = 1.0 - F13 - F14;             // FRONT OPENING TO BACK OPENING SHAPE FACTOR
    3667           0 :     DEN = 1.0 - (TAU_SLAT * FSS);      // DENOMINATOR - USED FOUR TIMES
    3668           0 :     C3 = (RHODFS_SLAT * F31 + TAU_SLAT * F41) / DEN;
    3669           0 :     B3 = (RHODFS_SLAT * FSS) / DEN;
    3670           0 :     C4 = (RHOUFS_SLAT * F41 + TAU_SLAT * F31) / DEN;
    3671           0 :     B4 = (RHOUFS_SLAT * FSS) / DEN;
    3672             : 
    3673           0 :     K3 = (C3 + (B3 * C4)) / (1.0 - (B3 * B4));
    3674           0 :     K4 = (C4 + (B4 * C3)) / (1.0 - (B3 * B4));
    3675             :     // transmittance of VB (equal front/back)
    3676           0 :     TAUVB = P01(state, F12 + (F14 * K3) + (F13 * K4), Tau_Name);
    3677             :     // diffuse reflectance of VB front-side
    3678           0 :     RHOFVB = P01(state, (F13 * K3) + (F14 * K4), RhoF_Name);
    3679           0 : }
    3680             : 
    3681           0 : Real64 VB_SLAT_RADIUS_RATIO(Real64 const W, // slat tip-to-tip (chord) width (any units; same units as C) must be > 0
    3682             :                             Real64 const C  // slat crown height (any units, same units as W) must be >= 0
    3683             : )
    3684             : {
    3685             :     //       AUTHOR         ASHRAE 1311-RP
    3686             :     //       DATE WRITTEN   unknown
    3687             :     //       MODIFIED       na
    3688             :     //       RE-ENGINEERED  na
    3689             : 
    3690             :     // PURPOSE OF THIS FUNCTION:
    3691             :     //  Returns curved slat radius ratio (W / R)
    3692             : 
    3693             :     // Return value
    3694             :     Real64 VB_SLAT_RADIUS_RATIO;
    3695             : 
    3696             :     Real64 CX;
    3697             : 
    3698           0 :     if (C <= 0.0 || W <= 0.0) {
    3699             :         // it is flat
    3700           0 :         VB_SLAT_RADIUS_RATIO = 0.0;
    3701             :     } else {
    3702           0 :         CX = min(C, W / 2.001);
    3703           0 :         VB_SLAT_RADIUS_RATIO = 2.0 * W * CX / (CX * CX + W * W / 4);
    3704             :     }
    3705           0 :     return VB_SLAT_RADIUS_RATIO;
    3706             : }
    3707             : 
    3708           0 : void VB_SOL46_CURVE(EnergyPlusData &state,
    3709             :                     Real64 const S,           // slat spacing (any length units; same units as W)
    3710             :                     Real64 const W,           // slat tip-to-tip (chord) width (any length units; same units as S)
    3711             :                     Real64 const SL_WR,       // slat curvature radius ratio (= W/R)
    3712             :                     Real64 const PHIx,        // slat angle, radians (-PI/2 <= PHI <= PI/2)
    3713             :                     Real64 const OMEGAx,      // incident beam profile angle (radians)
    3714             :                     Real64 const RHODFS_SLAT, // SW (solar) reflectance downward-facing slat surfaces (concave?)
    3715             :                     Real64 const RHOUFS_SLAT, // SW (solar) reflectance upward-facing slat surfaces (convex?)
    3716             :                     Real64 const TAU_SLAT,    // SW (solar) transmittance of slats
    3717             :                     Real64 &RHO_BD,           // returned: effective SW (solar) beam-to-diffuse reflectance front side
    3718             :                     Real64 &TAU_BB,           // returned: effective SW (solar) beam-to-beam transmittance front side
    3719             :                     Real64 &TAU_BD            // returned: effective SW (solar) beam-to-diffuse transmittance front side
    3720             : )
    3721             : {
    3722             :     // SUBROUTINE INFORMATION:
    3723             :     //       AUTHOR         John L. Wright, University of Waterloo,
    3724             :     //                      Mechanical Engineering, Advanced Glazing System Laboratory
    3725             :     //       DATE WRITTEN   Unknown
    3726             :     //       MODIFIED       na
    3727             :     //       RE-ENGINEERED  na
    3728             : 
    3729             :     // PURPOSE OF THIS SUBROUTINE:
    3730             :     //  Calculates the venetian blind layer effective solar transmittance and reflectance.
    3731             :     // METHODOLOGY EMPLOYED:
    3732             :     // Four and six surface curve-slat model with slat transmittance. For back side
    3733             :     // reflectance call this routine a second time with the same input data - except
    3734             :     // negative the slat angle, PHI_DEG.
    3735             : 
    3736             :     // SUBROUTINE ARGUMENT DEFINITIONS:
    3737             :     //    must be > 0
    3738             :     //   must be > 0
    3739             :     //   0 = flat
    3740             :     //   ltyVBHOR: + = front-side slat tip below horizontal
    3741             :     //   ltyVBVER: + = front-side slat tip is counter-
    3742             :     //                 clockwise from normal (viewed from above)
    3743             :     //   ltyVBHOR: +=above horizontal
    3744             :     //   ltyVBVER: +=clockwise when viewed from above
    3745             :     //   Note: All solar slat properties are incident-to-diffuse
    3746             :     //         Specular effects not covered by model
    3747             : 
    3748             :     Real64 DE; // distance from front tip of any slat to shadow (caused by the adjacent slat) on
    3749             :     // the plane of the same slat; DE may be greater than the slat width, W
    3750             :     Real64 PHI;
    3751             :     Real64 OMEGA;
    3752             :     Real64 SL_RAD;
    3753             :     Real64 SL_THETA;
    3754             :     Real64 Slope;
    3755             :     Real64 T_CORR_D;
    3756             :     Real64 T_CORR_F;
    3757             :     Real64 RHO_TEMP;
    3758             :     Real64 TAU_TEMP;
    3759             :     Real64 XA;
    3760             :     Real64 XB;
    3761             :     Real64 XC;
    3762             :     Real64 XD;
    3763             :     Real64 XE;
    3764           0 :     Real64 XF(0);
    3765             :     Real64 YA;
    3766             :     Real64 YB;
    3767             :     Real64 YC;
    3768             :     Real64 YD;
    3769             :     Real64 YE;
    3770           0 :     Real64 YF(0);
    3771             :     int CORR;
    3772             : 
    3773           0 :     DE = 0.0; // INITIALIZE DE
    3774           0 :     CORR = 1;
    3775             : 
    3776             :     // limit slat angle to +/- 90 deg
    3777           0 :     PHI = max(-Constant::DegToRadians * 90.0, min(Constant::DegToRadians * 90.0, PHIx));
    3778             :     // limit profile angle to +/- 89.5 deg
    3779           0 :     OMEGA = max(-Constant::DegToRadians * 89.5, min(Constant::DegToRadians * 89.5, OMEGAx));
    3780             : 
    3781           0 :     SL_RAD = W / max(SL_WR, 0.0000001);
    3782           0 :     SL_THETA = 2.0 * std::asin(0.5 * SL_WR);
    3783             : 
    3784           0 :     if (CORR > 0) { // CORRECT FOR SLAT CURVATURE BY SETTING CORR = 1
    3785             : 
    3786             :         //  DETERMINE BOUNDS FOR CURVATURE CORRECTION AND APPLY CORRECTION TO BEAM-BEAM TRANSMITTANCE
    3787           0 :         if (std::abs(PHI + OMEGA) < SL_THETA / 2.0) {
    3788             :             //  CALCULATE BEAM TRANSMISSION
    3789           0 :             XA = SL_RAD * std::sin(-SL_THETA / 2.0); // Glass-side end coordinate
    3790           0 :             YA = SL_RAD * std::cos(-SL_THETA / 2.0);
    3791           0 :             XB = -XA; // Indoor-side end coordinate
    3792           0 :             YB = YA;
    3793           0 :             YC = SL_RAD * std::cos(PHI + OMEGA); // Tangent to slat in irradiance direction
    3794           0 :             XC = std::sqrt(pow_2(SL_RAD) - pow_2(YC));
    3795           0 :             Slope = -XC / YC;
    3796           0 :             if (std::abs(Slope) < state.dataWindowEquivalentLayer->SMALL_ERROR) {
    3797           0 :                 XD = 0.0;
    3798           0 :                 YD = YA;
    3799           0 :                 XE = 0.0;
    3800           0 :                 YE = YD;
    3801             :                 // Bug XF, YF not set but used below (XE, YE are set but NOT used)
    3802             :             } else {
    3803           0 :                 if ((PHI + OMEGA) < 0.0) {
    3804           0 :                     XC = -XC;
    3805           0 :                     Slope = -Slope;
    3806           0 :                     XD = (YB - Slope * XB) / (-1.0 / Slope - Slope);
    3807           0 :                     XF = (YA - Slope * XA) / (-1.0 / Slope - Slope);
    3808           0 :                     XE = XA + 2.0 * std::abs(XA - XF);
    3809             :                 } else {
    3810           0 :                     XD = (YA - Slope * XA) / (-1.0 / Slope - Slope);
    3811           0 :                     XF = (YB - Slope * XB) / (-1.0 / Slope - Slope);
    3812           0 :                     XE = XB - 2.0 * std::abs(XB - XF);
    3813             :                 }
    3814           0 :                 YD = -XD / Slope;
    3815           0 :                 YE = -XE / Slope;
    3816           0 :                 YF = -XF / Slope;
    3817             :             }
    3818             : 
    3819           0 :             T_CORR_D = std::sqrt(pow_2(XC - XD) + pow_2(YC - YD)); // Slat thickness perpendicular to light direction
    3820           0 :             T_CORR_F = std::sqrt(pow_2(XC - XF) + pow_2(YC - YF));
    3821             : 
    3822           0 :             TAU_BB = 1.0 - T_CORR_D / (S * std::cos(OMEGA));
    3823             : 
    3824             :         } else {
    3825             :             // DO NOT APPLY CURVATURE CORRECTION TO BEAM-BEAM TRANSMITTANCE
    3826           0 :             if (std::abs(OMEGA + PHI) < 0.0001) {
    3827           0 :                 DE = S * 1000000.0;
    3828             :             } else {
    3829           0 :                 DE = S * std::abs(std::cos(OMEGA) / std::sin(OMEGA + PHI));
    3830             :             }
    3831             :             //  CHECK TO SEE IF THERE IS DIRECT BEAM TRANSMISSION
    3832           0 :             if ((DE / W) > (1.0 - state.dataWindowEquivalentLayer->SMALL_ERROR)) { // YES
    3833           0 :                 TAU_BB = max(0.0, (DE - W) / DE);
    3834             :             } else { // NO
    3835           0 :                 TAU_BB = 0.0;
    3836             :             }
    3837             :         }
    3838             : 
    3839             :         // CHECK TO SEE IF CURVATURE CORRECTION INCLUDES DOUBLE BLOCKAGE
    3840             :         // (TAU_BB < 0.0 AND SET TAU_BB = 0.0)
    3841           0 :         if (TAU_BB < 0.0) { // YES, THERE IS DOUBLE BLOCKAGE
    3842             : 
    3843           0 :             TAU_BB = 0.0;
    3844             : 
    3845             :             // DO NOT APPLY CURVATURE CORRECTION TO RHO_BD, TAU_BD IF TAU_BB < 0.0
    3846           0 :             if (std::abs(OMEGA + PHI) < 0.0001) {
    3847           0 :                 DE = S * 1000000.0;
    3848             :             } else {
    3849           0 :                 DE = S * std::abs(std::cos(OMEGA) / std::sin(OMEGA + PHI));
    3850             :             }
    3851           0 :             if ((DE / W) > (1.0 - state.dataWindowEquivalentLayer->SMALL_ERROR)) { // YES
    3852           0 :                 VB_SOL4(state, S, W, OMEGA, DE, PHI, RHODFS_SLAT, RHOUFS_SLAT, TAU_SLAT, RHO_BD, TAU_BD);
    3853             : 
    3854             :             } else { // NO
    3855           0 :                 VB_SOL6(state, S, W, OMEGA, DE, PHI, RHODFS_SLAT, RHOUFS_SLAT, TAU_SLAT, RHO_BD, TAU_BD);
    3856             :             }
    3857             : 
    3858             :         } else { // NO, THERE IS NO DOUBLE BLOCKAGE
    3859             : 
    3860           0 :             if (std::abs(PHI + OMEGA) < (SL_THETA / 2.0)) { // YES, APPLY CURVATURE CORRECTION
    3861             : 
    3862           0 :                 XA = SL_RAD * std::sin(-SL_THETA / 2.0); // Glass-side end coordinate
    3863           0 :                 YA = SL_RAD * std::cos(-SL_THETA / 2.0);
    3864           0 :                 XB = -XA; // Indoor-side end coordinate
    3865           0 :                 YB = YA;
    3866           0 :                 YC = SL_RAD * std::cos(PHI + OMEGA); // Tangent to slat in irradiance direction
    3867           0 :                 XC = std::sqrt(pow_2(SL_RAD) - pow_2(YC));
    3868           0 :                 Slope = -XC / YC;
    3869           0 :                 if (std::abs(Slope) < state.dataWindowEquivalentLayer->SMALL_ERROR) {
    3870           0 :                     XD = 0.0;
    3871           0 :                     YD = YA;
    3872           0 :                     XE = 0.0;
    3873           0 :                     YE = YD;
    3874             :                     // Bug XF, YF not set but used below (XE, YE are set but NOT used)
    3875             :                 } else {
    3876           0 :                     if ((PHI + OMEGA) < 0.0) {
    3877           0 :                         XC = -XC;
    3878           0 :                         Slope = -Slope;
    3879           0 :                         XD = (YB - Slope * XB) / (-1.0 / Slope - Slope);
    3880           0 :                         XF = (YA - Slope * XA) / (-1.0 / Slope - Slope);
    3881           0 :                         XE = XA + 2.0 * std::abs(XA - XF);
    3882             :                     } else {
    3883           0 :                         XD = (YA - Slope * XA) / (-1.0 / Slope - Slope);
    3884           0 :                         XF = (YB - Slope * XB) / (-1.0 / Slope - Slope);
    3885           0 :                         XE = XB - 2.0 * std::abs(XB - XF);
    3886             :                     }
    3887           0 :                     YD = -XD / Slope;
    3888           0 :                     YE = -XE / Slope;
    3889           0 :                     YF = -XF / Slope;
    3890             :                 }
    3891           0 :                 T_CORR_D = std::sqrt(pow_2(XC - XD) + pow_2(YC - YD)); // Slat thickness perpendicular to light direction
    3892           0 :                 T_CORR_F = std::sqrt(pow_2(XC - XF) + pow_2(YC - YF));
    3893             : 
    3894           0 :                 if ((PHI + OMEGA) >= 0.0) { // Slat is lit from above
    3895           0 :                     DE = XC - XA;
    3896           0 :                     VB_SOL6(state, S, W, OMEGA, DE, PHI, RHODFS_SLAT, RHOUFS_SLAT, TAU_SLAT, RHO_BD, TAU_BD);
    3897           0 :                     Real64 const S_cos_OMEGA_inv(1.0 / (S * std::cos(OMEGA)));
    3898           0 :                     RHO_BD *= T_CORR_D * S_cos_OMEGA_inv;
    3899           0 :                     TAU_BD *= T_CORR_D * S_cos_OMEGA_inv;
    3900             :                 } else { // Slat is lit from below
    3901           0 :                     DE = XC - XA;
    3902           0 :                     VB_SOL6(state, S, W, OMEGA, DE, PHI, RHODFS_SLAT, RHOUFS_SLAT, TAU_SLAT, RHO_BD, TAU_BD);
    3903           0 :                     Real64 const S_cos_OMEGA_inv(1.0 / (S * std::cos(OMEGA)));
    3904           0 :                     RHO_TEMP = RHO_BD * T_CORR_F * S_cos_OMEGA_inv;
    3905           0 :                     TAU_TEMP = TAU_BD * T_CORR_F * S_cos_OMEGA_inv;
    3906           0 :                     DE = std::abs(XB - XF);
    3907           0 :                     VB_SOL6(state, S, W, OMEGA, DE, PHI, RHODFS_SLAT, RHOUFS_SLAT, TAU_SLAT, RHO_BD, TAU_BD);
    3908           0 :                     RHO_BD = RHO_BD * (T_CORR_D - T_CORR_F) * S_cos_OMEGA_inv + RHO_TEMP;
    3909           0 :                     TAU_BD = TAU_BD * (T_CORR_D - T_CORR_F) * S_cos_OMEGA_inv + TAU_TEMP;
    3910             :                 }
    3911             : 
    3912             :             } else { // NO, DO NOT APPLY CURVATURE CORRECTION
    3913           0 :                 if (std::abs(OMEGA + PHI) < 0.0001) {
    3914           0 :                     DE = S * 1000000.0;
    3915             :                 } else {
    3916           0 :                     DE = S * std::abs(std::cos(OMEGA) / std::sin(OMEGA + PHI));
    3917             :                 }
    3918           0 :                 if (DE / W > 1.0 - state.dataWindowEquivalentLayer->SMALL_ERROR) { // YES
    3919           0 :                     VB_SOL4(state, S, W, OMEGA, DE, PHI, RHODFS_SLAT, RHOUFS_SLAT, TAU_SLAT, RHO_BD, TAU_BD);
    3920             : 
    3921             :                 } else { // NO
    3922           0 :                     VB_SOL6(state, S, W, OMEGA, DE, PHI, RHODFS_SLAT, RHOUFS_SLAT, TAU_SLAT, RHO_BD, TAU_BD);
    3923             :                 }
    3924             :             }
    3925             :         }
    3926             : 
    3927             :     } else { // DO NOT CORRECT FOR SLAT CURVATURE
    3928             : 
    3929             :         //  CHECK TO SEE IF BEAM IS ALLIGNED WITH SLATS
    3930           0 :         if (std::abs(PHI + OMEGA) < state.dataWindowEquivalentLayer->SMALL_ERROR) { // YES!
    3931           0 :             RHO_BD = 0.0;
    3932           0 :             TAU_BB = 1.0;
    3933           0 :             TAU_BD = 0.0;
    3934             : 
    3935             :         } else { // BEAM NOT ALIGNED WITH SLATS
    3936           0 :             RHO_BD = 0.0;
    3937           0 :             TAU_BB = 0.0;
    3938           0 :             TAU_BD = 0.0;
    3939           0 :             DE = S * std::abs(std::cos(OMEGA) / std::sin(OMEGA + PHI));
    3940             :             //  CHECK TO SEE IF THERE IS DIRECT BEAM TRANSMISSION
    3941           0 :             if ((DE / W) > (1.0 - state.dataWindowEquivalentLayer->SMALL_ERROR)) { // YES
    3942           0 :                 TAU_BB = (DE - W) / DE;
    3943           0 :                 if (TAU_BB < 0.0) TAU_BB = 0.0;
    3944           0 :                 VB_SOL4(state, S, W, OMEGA, DE, PHI, RHODFS_SLAT, RHOUFS_SLAT, TAU_SLAT, RHO_BD, TAU_BD);
    3945             :             } else { // NO
    3946           0 :                 TAU_BB = 0.0;
    3947           0 :                 VB_SOL6(state, S, W, OMEGA, DE, PHI, RHODFS_SLAT, RHOUFS_SLAT, TAU_SLAT, RHO_BD, TAU_BD);
    3948             :             } //  END CHECK FOR DIRECT BEAM TRANSMISSION
    3949             :         }     // END CHECK TO SEE IF BEAM ALLIGNED WITH SLATS
    3950             :     }
    3951           0 : }
    3952             : 
    3953           0 : void VB_SOL4(EnergyPlusData &state,
    3954             :              Real64 const S,           // slat spacing (any length units; same units as W)
    3955             :              Real64 const W,           // slat tip-to-tip width (any length units; same units as S)
    3956             :              Real64 const OMEGA,       // incident beam profile angle (radians)
    3957             :              Real64 const DE,          // distance from front tip of any slat to shadow (caused by the adjacent slat) on
    3958             :              Real64 const PHI,         // slat angle, radians (-PI/2 <= PHI <= PI/2)
    3959             :              Real64 const RHODFS_SLAT, // solar reflectance downward-facing slat surfaces (concave?)
    3960             :              Real64 const RHOUFS_SLAT, // solar reflectance upward-facing slat surfaces (convex?)
    3961             :              Real64 const TAU_SLAT,    // solar transmittance of slat
    3962             :              Real64 &RHO_BD,           // returned: solar beam-to-diffuse reflectance the venetian blind (front side)
    3963             :              Real64 &TAU_BD            // returned: solar beam-to-diffuse transmittance of the venetian blind (front side)
    3964             : )
    3965             : {
    3966             :     // SUBROUTINE INFORMATION:
    3967             :     //       AUTHOR         John L. Wright, University of Waterloo,
    3968             :     //                      Mechanical Engineering, Advanced Glazing System Laboratory
    3969             :     //       DATE WRITTEN   Unknown
    3970             :     //       MODIFIED       na
    3971             :     //       RE-ENGINEERED  na
    3972             : 
    3973             :     // PURPOSE OF THIS SUBROUTINE:
    3974             :     //  Calculates the venetian blind layer effective solar transmittance and reflectance.
    3975             :     // METHODOLOGY EMPLOYED:
    3976             :     //  Four surface Flat-Plate Model with slat transmittance
    3977             : 
    3978             :     // SUBROUTINE ARGUMENT DEFINITIONS:
    3979             :     //    must be > 0
    3980             :     //   must be > 0
    3981             :     //   ltyVBHOR: +=above horizontal
    3982             :     //   ltyVBVER: +=clockwise when viewed from above
    3983             :     //    the plane of the same slat de may be greater than the slat width, w
    3984             :     //   ltyVBHOR: + = front-side slat tip below horizontal
    3985             :     //   ltyVBVER: + = front-side slat tip is counter-
    3986             :     //                 clockwise from normal (viewed from above)
    3987             :     //    Note: all solar slat properties - incident-to-diffuse
    3988             : 
    3989             :     Real64 AF; // lengths of diagonal strings used in the four-surface model
    3990             :     Real64 CD;
    3991             :     Real64 F13; // Shape factors
    3992             :     Real64 F14;
    3993             :     Real64 F23;
    3994             :     Real64 F24;
    3995             :     Real64 F34;
    3996             :     Real64 F43;
    3997             :     Real64 Z3; // diffuse source terms from surfaces 3 and 4 due to incident beam radiation
    3998             :     Real64 Z4;
    3999             :     Real64 J3; // radiosity, surface i
    4000             :     Real64 J4;
    4001             :     Real64 B3; // temporaries
    4002             :     Real64 B4;
    4003             :     Real64 C3;
    4004             :     Real64 C4;
    4005             : 
    4006           0 :     Real64 const W_cos_PHI_2(pow_2(W * std::cos(PHI)));
    4007           0 :     Real64 const W_sin_PHI(W * std::sin(PHI));
    4008           0 :     AF = std::sqrt(W_cos_PHI_2 + pow_2(S - W_sin_PHI));
    4009           0 :     CD = std::sqrt(W_cos_PHI_2 + pow_2(S + W_sin_PHI));
    4010             :     //  CHECK TO SEE WHICH SIDE OF SLAT IS SUNLIT
    4011           0 :     if (PHI + OMEGA >= 0.0) { // SUN SHINES ON TOP OF SLAT
    4012             : 
    4013           0 :         Z3 = TAU_SLAT * S / DE;
    4014           0 :         Z4 = RHOUFS_SLAT * S / DE;
    4015             :         //  PRINT *, PHI, OMEGA, DE, 'TOPLIT'
    4016             : 
    4017             :     } else { // SUN SHINES ON BOTTOM OF SLAT
    4018           0 :         Z3 = RHODFS_SLAT * S / DE;
    4019           0 :         Z4 = TAU_SLAT * S / DE;
    4020             :         //      PRINT *, PHI, OMEGA, DE, 'BOTLIT'
    4021             :     }
    4022             :     //  CHECK TO SEE IF VENETIAN BLIND IS CLOSED
    4023           0 :     if (std::abs(PHI - Constant::PiOvr2) < state.dataWindowEquivalentLayer->SMALL_ERROR) { // VENETIAN BLIND IS CLOSED
    4024             : 
    4025             :         // CHECK TO SEE IF THERE ARE GAPS IN BETWEEN SLATS WHEN THE BLIND IS CLOSED
    4026           0 :         if (W < S) { // YES, THERE ARE GAPS IN BETWEEN SLATS
    4027           0 :             RHO_BD = (W / S) * RHOUFS_SLAT;
    4028           0 :             TAU_BD = (W / S) * TAU_SLAT;
    4029             :         } else { // NO, THERE ARE NO GAPS IN BETWEEN SLATS
    4030           0 :             RHO_BD = RHOUFS_SLAT;
    4031           0 :             TAU_BD = TAU_SLAT;
    4032             :         } // END OF CHECK FOR GAPS IN BETWEEN SLATS
    4033             : 
    4034             :     } else { // VENETIAN BLIND IS OPENED
    4035             : 
    4036           0 :         F13 = (S + W - CD) / (2.0 * S);
    4037           0 :         F14 = (S + W - AF) / (2.0 * S);
    4038           0 :         F23 = (S + W - AF) / (2.0 * S);
    4039           0 :         F24 = (S + W - CD) / (2.0 * S);
    4040           0 :         F34 = (CD + AF - 2.0 * S) / (2.0 * W);
    4041           0 :         F43 = (CD + AF - 2.0 * S) / (2.0 * W);
    4042             : 
    4043           0 :         C3 = 1.0 / (1.0 - TAU_SLAT * F43);
    4044           0 :         B3 = (RHODFS_SLAT * F34) / (1.0 - TAU_SLAT * F43);
    4045           0 :         C4 = 1.0 / (1.0 - TAU_SLAT * F34);
    4046           0 :         B4 = (RHOUFS_SLAT * F43) / (1.0 - TAU_SLAT * F34);
    4047           0 :         J3 = (C3 * Z3 + B3 * C4 * Z4) / (1.0 - B3 * B4);
    4048           0 :         J4 = (C4 * Z4 + B4 * C3 * Z3) / (1.0 - B3 * B4);
    4049             : 
    4050           0 :         RHO_BD = F13 * J3 + F14 * J4;
    4051           0 :         TAU_BD = F23 * J3 + F24 * J4;
    4052             : 
    4053             :     } // END OF CHECK FOR CLOSED BLIND
    4054           0 : }
    4055             : 
    4056           0 : void VB_SOL6(EnergyPlusData &state,
    4057             :              Real64 const S,           // slat spacing (any length units; same units as W)
    4058             :              Real64 const W,           // slat tip-to-tip width (any length units; same units as S)
    4059             :              Real64 const OMEGA,       // incident beam profile angle (radians)
    4060             :              Real64 const DE,          // distance from front tip of any slat to shadow (caused by the adjacent slat) on
    4061             :              Real64 const PHI,         // slat angle, radians (-PI/2 <= PHI <= PI/2)
    4062             :              Real64 const RHODFS_SLAT, // solar reflectance downward-facing slat surfaces (concave)
    4063             :              Real64 const RHOUFS_SLAT, // solar reflectance upward-facing slat surfaces (convex)
    4064             :              Real64 const TAU_SLAT,    // solar transmittance of slat
    4065             :              Real64 &RHO_BD,           // returned: solar beam-to-diffuse reflectance the venetian blind (front side)
    4066             :              Real64 &TAU_BD            // returned: solar beam-to-diffuse transmittance of the venetian blind (front side)
    4067             : )
    4068             : {
    4069             :     // SUBROUTINE INFORMATION:
    4070             :     //       AUTHOR         John L. Wright, University of Waterloo,
    4071             :     //                      Mechanical Engineering, Advanced Glazing System Laboratory
    4072             :     //       DATE WRITTEN   Unknown
    4073             :     //       MODIFIED       na
    4074             :     //       RE-ENGINEERED  na
    4075             : 
    4076             :     // PURPOSE OF THIS SUBROUTINE:
    4077             :     //  Calculates the venetian blind layer effective solar transmittance and reflectance.
    4078             :     // METHODOLOGY EMPLOYED:
    4079             :     //  six surface flat-slat model with slat transmittance. If you want the back
    4080             :     //  side reflectance call the routine a second time with the same input data
    4081             :     //  except negative the slat angle, PHI_DEG
    4082             : 
    4083             :     // SUBROUTINE ARGUMENT DEFINITIONS:
    4084             :     //    must be > 0
    4085             :     //   must be > 0
    4086             :     //   ltyVBHOR: +=above horizontal
    4087             :     //   ltyVBVER: +=clockwise when viewed from above
    4088             :     //    the plane of the same slat DE may be greater than the slat width, w
    4089             :     //   ltyVBHOR: + = front-side slat tip below horizontal
    4090             :     //   ltyVBVER: + = front-side slat tip is counter-
    4091             :     //                 clockwise from normal (viewed from above)
    4092             :     //    Note: all solar slat properties - incident-to-diffuse
    4093           0 :     int constexpr N(4);
    4094             : 
    4095             :     Real64 AB; // lengths of slat segments and diagonal strings
    4096             :     Real64 AE;
    4097             :     Real64 AF;
    4098             :     Real64 BC;
    4099             :     Real64 BD;
    4100             :     Real64 BF;
    4101             :     Real64 CD;
    4102             :     Real64 CE;
    4103             :     Real64 EF;
    4104             :     //  used in the six-surface model
    4105             :     Real64 F13; // shape factors
    4106             :     Real64 F14;
    4107             :     Real64 F23;
    4108             :     Real64 F24;
    4109             :     Real64 F34;
    4110             :     Real64 F36;
    4111             :     Real64 F15;
    4112             :     Real64 F16;
    4113             :     Real64 F43;
    4114             :     Real64 F45;
    4115             :     Real64 F54;
    4116             :     Real64 F56;
    4117             :     Real64 F63;
    4118             :     Real64 F65;
    4119             :     Real64 F25;
    4120             :     Real64 F26;
    4121             :     Real64 Z3; // diffuse source terms from surfaces 3 and 4 due to incident beam radiation
    4122             :     Real64 Z4;
    4123             :     Real64 J3; // radiosity, surface i
    4124             :     Real64 J4;
    4125             :     Real64 J5;
    4126             :     Real64 J6;
    4127           0 :     Array2D<Real64> A(N + 2, N); // coefficients of the radiosity equations matrix
    4128           0 :     Array1D<Real64> XSOL(N);     // solution vector (obtained after solving the radiosity equations matrix)
    4129             : 
    4130             :     //  CHECK TO SEE WHICH SIDE OF SLAT IS SUNLIT
    4131           0 :     if ((PHI + OMEGA) >= 0.0) { // SUN SHINES ON TOP OF SLAT
    4132           0 :         Z3 = TAU_SLAT * S / DE;
    4133           0 :         Z4 = RHOUFS_SLAT * S / DE;
    4134             :         //      PRINT *, PHI, OMEGA, DE, 'TOPLIT'
    4135             : 
    4136             :     } else { // SUN SHINES ON BOTTOM OF SLAT
    4137           0 :         Z3 = RHODFS_SLAT * S / DE;
    4138           0 :         Z4 = TAU_SLAT * S / DE;
    4139             :         //      PRINT *, PHI, OMEGA, DE, 'BOTLIT'
    4140             :     }
    4141             : 
    4142             :     //  CHECK TO SEE IF VENETIAN BLIND IS CLOSED
    4143           0 :     if (std::abs(PHI - Constant::PiOvr2) < state.dataWindowEquivalentLayer->SMALL_ERROR) { // VENETIAN BLIND IS CLOSED
    4144             : 
    4145             :         // CHECK TO SEE IF THERE ARE GAPS IN BETWEEN SLATS WHEN THE BLIND IS CLOSED
    4146           0 :         if (W < S) { // YES, THERE ARE GAPS IN BETWEEN SLATS
    4147           0 :             RHO_BD = (W / S) * RHOUFS_SLAT;
    4148           0 :             TAU_BD = (W / S) * TAU_SLAT;
    4149             :         } else { // NO, THERE ARE NO GAPS IN BETWEEN SLATS
    4150           0 :             RHO_BD = RHOUFS_SLAT;
    4151           0 :             TAU_BD = TAU_SLAT;
    4152             :         } // END OF CHECK FOR GAPS IN BETWEEN SLATS
    4153             : 
    4154             :     } else { // VENETIAN BLIND IS OPENED
    4155           0 :         AB = DE;
    4156           0 :         Real64 const cos_PHI(std::cos(PHI));
    4157           0 :         Real64 const sin_PHI(std::sin(PHI));
    4158           0 :         Real64 const W_cos_PHI_2(pow_2(W * cos_PHI));
    4159           0 :         AF = std::sqrt(W_cos_PHI_2 + pow_2(S - W * sin_PHI));
    4160           0 :         BC = W - AB;
    4161           0 :         EF = BC;
    4162           0 :         Real64 const DE_cos_PHI_2(pow_2(DE * cos_PHI));
    4163           0 :         Real64 const EF_cos_PHI_2(pow_2(EF * cos_PHI));
    4164           0 :         BD = std::sqrt(DE_cos_PHI_2 + pow_2(S + DE * sin_PHI));
    4165           0 :         BF = std::sqrt(EF_cos_PHI_2 + pow_2(S - EF * sin_PHI));
    4166           0 :         CD = std::sqrt(W_cos_PHI_2 + pow_2(S + W * sin_PHI));
    4167           0 :         CE = std::sqrt(EF_cos_PHI_2 + pow_2(S + EF * sin_PHI));
    4168           0 :         AE = std::sqrt(DE_cos_PHI_2 + pow_2(S - DE * sin_PHI));
    4169             : 
    4170           0 :         F13 = (S + AB - BD) / (2.0 * S);
    4171           0 :         F14 = (S + DE - AE) / (2.0 * S);
    4172           0 :         F15 = (W + BD - (AB + CD)) / (2.0 * S);
    4173           0 :         F16 = (W + AE - (AF + DE)) / (2.0 * S);
    4174           0 :         F23 = (W + BF - (BC + AF)) / (2.0 * S);
    4175           0 :         F24 = (W + CE - (CD + EF)) / (2.0 * S);
    4176           0 :         F25 = (S + BC - BF) / (2.0 * S);
    4177           0 :         F26 = (S + EF - CE) / (2.0 * S);
    4178           0 :         F34 = (AE + BD - 2.0 * S) / (2.0 * AB);
    4179           0 :         F36 = (AF + S - (AE + BF)) / (2.0 * AB);
    4180           0 :         F43 = (AE + BD - 2.0 * S) / (2.0 * DE);
    4181           0 :         F45 = (CD + S - (BD + CE)) / (2.0 * DE);
    4182           0 :         F54 = (CD + S - (BD + CE)) / (2.0 * BC);
    4183           0 :         F56 = (CE + BF - 2.0 * S) / (2.0 * BC);
    4184           0 :         F63 = (AF + S - (AE + BF)) / (2.0 * EF);
    4185           0 :         F65 = (BF + CE - 2.0 * S) / (2.0 * EF);
    4186             : 
    4187             :         // POPULATE THE COEFFICIENTS OF THE RADIOSITY MATRIX
    4188             : 
    4189           0 :         A(1, 1) = 1.0 - TAU_SLAT * F43;
    4190           0 :         A(2, 1) = -RHODFS_SLAT * F34;
    4191           0 :         A(3, 1) = -TAU_SLAT * F45;
    4192           0 :         A(4, 1) = -RHODFS_SLAT * F36;
    4193           0 :         A(5, 1) = Z3;
    4194           0 :         A(1, 2) = -RHOUFS_SLAT * F43;
    4195           0 :         A(2, 2) = 1.0 - TAU_SLAT * F34;
    4196           0 :         A(3, 2) = -RHOUFS_SLAT * F45;
    4197           0 :         A(4, 2) = -TAU_SLAT * F36;
    4198           0 :         A(5, 2) = Z4;
    4199           0 :         A(1, 3) = -TAU_SLAT * F63;
    4200           0 :         A(2, 3) = -RHODFS_SLAT * F54;
    4201           0 :         A(3, 3) = 1.0 - TAU_SLAT * F65;
    4202           0 :         A(4, 3) = -RHODFS_SLAT * F56;
    4203           0 :         A(5, 3) = 0.0;
    4204           0 :         A(1, 4) = -RHOUFS_SLAT * F63;
    4205           0 :         A(2, 4) = -TAU_SLAT * F54;
    4206           0 :         A(3, 4) = -RHOUFS_SLAT * F65;
    4207           0 :         A(4, 4) = 1.0 - TAU_SLAT * F56;
    4208           0 :         A(5, 4) = 0.0;
    4209             : 
    4210           0 :         SOLMATS(N, A, XSOL);
    4211             : 
    4212           0 :         J3 = XSOL(1);
    4213           0 :         J4 = XSOL(2);
    4214           0 :         J5 = XSOL(3);
    4215           0 :         J6 = XSOL(4);
    4216             : 
    4217           0 :         RHO_BD = F13 * J3 + F14 * J4 + F15 * J5 + F16 * J6;
    4218           0 :         TAU_BD = F23 * J3 + F24 * J4 + F25 * J5 + F26 * J6;
    4219             :     } // END OF CHECK FOR CLOSED BLIND
    4220           0 : }
    4221             : 
    4222       28550 : void SOLMATS(int const N,          // # of active rows in A
    4223             :              Array2S<Real64> A,    // matrix, minimum required dimensions: A( N, N+2)
    4224             :              Array1D<Real64> &XSOL // returned: solution vector, min req dimension: XSOL( N)
    4225             : )
    4226             : {
    4227             :     // SUBROUTINE INFORMATION:
    4228             :     //       AUTHOR         John L. Wright, University of Waterloo,
    4229             :     //                      Mechanical Engineering, Advanced Glazing System Laboratory
    4230             :     //       DATE WRITTEN   Unknown
    4231             :     //       MODIFIED       na
    4232             :     //       RE-ENGINEERED  na
    4233             : 
    4234             :     // PURPOSE OF THIS SUBROUTINE:
    4235             :     //  Matrix solver.
    4236             :     // METHODOLOGY EMPLOYED:
    4237             :     //  Solves matrix by the elimination method supplemented by a search for the
    4238             :     //  largest pivotal element at each stage
    4239             : 
    4240             :     Real64 CMAX;
    4241             :     Real64 TEMP;
    4242             :     Real64 C;
    4243             :     Real64 Y;
    4244             :     Real64 D;
    4245             :     int NM1;
    4246             :     int NP1;
    4247             :     int NP2;
    4248             :     int I;
    4249             :     int J;
    4250             :     int L;
    4251             :     int LP;
    4252             :     int NOS;
    4253             :     int NI;
    4254             :     int NJ;
    4255             : 
    4256       28550 :     NM1 = N - 1;
    4257       28550 :     NP1 = N + 1;
    4258       28550 :     NP2 = N + 2;
    4259             : 
    4260      404177 :     for (I = 1; I <= N; ++I) {
    4261      375627 :         A(NP2, I) = 0.0;
    4262             :         // DO 1 J=1,NP1    ! TODO ?
    4263             :     }
    4264             : 
    4265      404177 :     for (I = 1; I <= N; ++I) {
    4266     6473139 :         for (J = 1; J <= NP1; ++J) {
    4267     6097512 :             A(NP2, I) += A(J, I);
    4268             :         }
    4269             :     }
    4270             : 
    4271      375627 :     for (L = 1; L <= N - 1; ++L) {
    4272      347077 :         CMAX = A(L, L);
    4273      347077 :         LP = L + 1;
    4274      347077 :         NOS = L;
    4275             : 
    4276     3020206 :         for (I = LP; I <= N; ++I) {
    4277     2673129 :             if (std::abs(CMAX) < std::abs(A(L, I))) {
    4278       49956 :                 CMAX = A(L, I);
    4279       49956 :                 NOS = I;
    4280             :             }
    4281             :         }
    4282             : 
    4283             :         // Swap rows
    4284      347077 :         if (NOS != L) {
    4285     1063140 :             for (J = 1; J <= NP2; ++J) {
    4286     1013184 :                 TEMP = A(J, L);
    4287     1013184 :                 A(J, L) = A(J, NOS);
    4288     1013184 :                 A(J, NOS) = TEMP;
    4289             :             }
    4290             :         }
    4291             : 
    4292     3020206 :         for (I = LP; I <= N; ++I) {
    4293     2673129 :             C = 0.0;
    4294     2673129 :             Y = -A(L, I) / A(L, L);
    4295    40420647 :             for (J = L; J <= NP2; ++J) {
    4296    37747518 :                 A(J, I) += Y * A(J, L);
    4297             :             }
    4298    37747518 :             for (J = L; J <= NP1; ++J) {
    4299    35074389 :                 C += A(J, I);
    4300             :             }
    4301             :         }
    4302             :     }
    4303             : 
    4304             :     // back-substitute
    4305       28550 :     XSOL(N) = A(NP1, N) / A(N, N);
    4306      375627 :     for (I = 1; I <= NM1; ++I) {
    4307      347077 :         NI = N - I;
    4308      347077 :         D = 0.0;
    4309     3020206 :         for (J = 1; J <= I; ++J) {
    4310     2673129 :             NJ = N + 1 - J;
    4311     2673129 :             D += A(NJ, NI) * XSOL(NJ);
    4312             :         }
    4313      347077 :         XSOL(NI) = (A(NP1, NI) - D) / A(NI, NI);
    4314             :     }
    4315       28550 : }
    4316             : 
    4317        8064 : void ASHWAT_ThermalCalc(EnergyPlusData &state,
    4318             :                         CFSTY &FS,        // fenestration system
    4319             :                         Real64 const TIN, // indoor / outdoor air temperature, K
    4320             :                         Real64 const TOUT,
    4321             :                         Real64 const HCIN, // indoor / outdoor convective heat transfer
    4322             :                         Real64 const HCOUT,
    4323             :                         Real64 const TRMOUT,
    4324             :                         Real64 const TRMIN,           // indoor / outdoor mean radiant temp, K
    4325             :                         Array1S<Real64> const SOURCE, // absorbed solar by layer, W/m2
    4326             :                         Real64 const TOL,             // convergence tolerance, usually
    4327             :                         Array1D<Real64> &QOCF,        // returned: heat flux to layer i from gaps i-1 and i
    4328             :                         Real64 &QOCFRoom,             // returned: open channel heat gain to room, W/m2
    4329             :                         Array1D<Real64> &T,           // returned: layer temperatures, 1=outside-most layer, K
    4330             :                         Array1D<Real64> &Q,           // returned: heat flux at ith gap (betw layers i and i+1), W/m2
    4331             :                         Array1D<Real64> &JF,          // returned: front (outside facing) radiosity of surfaces, W/m2
    4332             :                         Array1D<Real64> &JB,          // returned: back (inside facing) radiosity, W/m2
    4333             :                         Array1D<Real64> &HC           // returned: gap convective heat transfer coefficient, W/m2K
    4334             : )
    4335             : {
    4336             :     // SUBROUTINE INFORMATION:
    4337             :     //       AUTHOR         JOHN L. WRIGHT (University of Waterloo, Mechanical Engineering)
    4338             :     //                      Chip Barnaby (WrightSoft)
    4339             :     //       DATE WRITTEN   LATEST MODIFICATIONS, February 2008
    4340             :     //       MODIFIED       Bereket Nigusse, June 2013
    4341             :     //                      added standard 155099 inside convection
    4342             :     //                      coefficient calculation for U-Factor
    4343             :     //       RE-ENGINEERED  na
    4344             : 
    4345             :     // PURPOSE OF THIS SUBROUTINE:
    4346             :     //     Subroutine to calculate the glazing temperatures of the
    4347             :     //     various elements of a window/shade array while solving an energy
    4348             :     //     balance which accounts for absorbed solar radiation, indoor-
    4349             :     //     outdoor temperature difference, any combination of hemispherical
    4350             :     //     IR optical properties of the various glazings/shading layers.
    4351             :     //     Mean radiant temperatures can differ from air temperature on
    4352             :     //     both the indoor and outdoor sides.
    4353             :     //     It is also possible to allow air-flow between the two layers
    4354             :     //     adjacent to the indoor side and/or the two layers adjacent the
    4355             :     //     outdoor side. U-factor and SHGC calculations are also included (optional)
    4356             : 
    4357             :     // METHODOLOGY EMPLOYED:
    4358             :     // Uses the net radiation method developed for ASHWAT fenestration
    4359             :     // model by John Wright, the University of WaterLoo
    4360             : 
    4361             :     // REFERENCES:
    4362             :     //  ASHRAE RP-1311
    4363             : 
    4364             :     // Argument array dimensioning
    4365        8064 :     EP_SIZE_CHECK(QOCF, FS.NL);
    4366        8064 :     EP_SIZE_CHECK(T, FS.NL);
    4367        8064 :     EP_SIZE_CHECK(JF, FS.NL + 1);
    4368        8064 :     EP_SIZE_CHECK(JB, FS.NL + 1);
    4369        8064 :     EP_SIZE_CHECK(HC, FS.NL + 1);
    4370             : 
    4371             :     // Locals
    4372             :     // FUNCTION ARGUMENT DEFINITIONS:
    4373             :     //   FS.NL determines # of layers modelled
    4374             :     //   coefficient, W/m2K
    4375             :     //   = outside direct + outside diffuse + inside diffuse
    4376             :     //   0.001 (good) or 0.0001 (tight)
    4377             :     //   due to open channel flow, W/m2
    4378             :     //   + = heat flow indoor to outdoor
    4379             :     //   JF( NL+1) = room radiosity
    4380             :     //   JB[ 0] = outside environment radiosity
    4381             :     //   0=outside, 1=betw layer 1-2, ..., NL=inside
    4382             : 
    4383             :     // FUNCTION PARAMETER DEFINITIONS:
    4384        8064 :     constexpr int MaxIter(100); // maximum number of iterations allowed
    4385             :     static constexpr std::string_view RoutineName("ASHWAT_ThermalCalc: ");
    4386             : 
    4387             :     Real64 ALPHA;
    4388             :     Real64 HCOCFout;
    4389       16128 :     Array2D<Real64> A(3 * FS.NL + 4, 3 * FS.NL + 2);
    4390        8064 :     Array1D<Real64> XSOL(3 * FS.NL + 2);
    4391             :     Real64 MAXERR;
    4392        8064 :     Array1D<Real64> TNEW(FS.NL);        // latest estimate of layer temperatures, K
    4393        8064 :     Array1D<Real64> EB({0, FS.NL + 1}); // black emissive power by layer, W/m2
    4394             :                                         //   EB( 0) = outdoor environment, EB( NL+1) = indoor environment
    4395        8064 :     Array1D<Real64> HHAT({0, FS.NL});   // convective heat transfer coefficient (W/m2.K4)
    4396             :                                         //   based on EB, NOT temperature difference
    4397             :     Real64 RHOF_ROOM;                   // effective longwave room-side properties
    4398             :     Real64 TAU_ROOM;
    4399             :     Real64 EPSF_ROOM;
    4400             :     Real64 RHOB_OUT; // effective longwave outdoor environment properties
    4401             :     Real64 TAU_OUT;
    4402             :     Real64 EPSB_OUT;
    4403        8064 :     Array1D<Real64> QNET(FS.NL); // checksum - net heat flux to a layer - should be zero - not needed
    4404             :     int ADIM;                    // dimension of the A matrix
    4405             :     int CONVRG;
    4406             :     int NL;
    4407             :     int I;
    4408             :     int J;
    4409             :     int L;
    4410             :     int ITRY;
    4411             :     int hin_scheme;                   // flags different schemes for indoor convection coefficients
    4412        8064 :     Array1D_int ISDL({0, FS.NL + 1}); // Flag to mark diathermanous layers, 0=opaque
    4413        8064 :     Array1D<Real64> QOCF_F(FS.NL);    // heat flux to outdoor-facing surface of layer i, from gap i-1,
    4414             :                                       //   due to open channel flow, W/m2
    4415        8064 :     Array1D<Real64> QOCF_B(FS.NL);    // heat flux to indoor-facing surface of layer i, from gap i,
    4416             :                                       //   due to open channel flow, W/m2
    4417        8064 :     Array1D<Real64> HR({0, FS.NL});   // Radiant heat transfer coefficient [W/m2K]
    4418        8064 :     Array1D<Real64> HJR(FS.NL);       // radiative and convective jump heat transfer coefficients
    4419        8064 :     Array1D<Real64> HJC(FS.NL);
    4420        8064 :     Array1D<Real64> RHOF({0, FS.NL + 1}); // longwave reflectance, front    !  these variables help simplify
    4421        8064 :     Array1D<Real64> RHOB({0, FS.NL + 1}); // longwave reflectance, back     !  the code because it is useful to
    4422        8064 :     Array1D<Real64> EPSF({0, FS.NL + 1}); // longwave emisivity,   front    !  increase the scope of the arrays
    4423        8064 :     Array1D<Real64> EPSB({0, FS.NL + 1}); // longwave emisivity,   back     !  to include indoor and outdoor
    4424        8064 :     Array1D<Real64> TAU({0, FS.NL + 1});  // longwave transmittance         !  nodes - more general
    4425       16128 :     Array2D<Real64> HC2D(6, 6);           // convective heat transfer coefficients between layers i and j
    4426       16128 :     Array2D<Real64> HR2D(6, 6);           // radiant heat transfer coefficients between layers i and j
    4427        8064 :     Array1D<Real64> HCIout(6);            // convective and radiant heat transfer coefficients between
    4428        8064 :     Array1D<Real64> HRIout(6);
    4429             :     // layer i and outdoor air or mean radiant temperature, resp.
    4430        8064 :     Array1D<Real64> HCIin(6); // convective and radiant heat transfer coefficients between
    4431        8064 :     Array1D<Real64> HRIin(6);
    4432             :     // layer i and indoor air or mean radiant temperature, resp.
    4433             :     //  Indoor side convection coefficients - used for Open Channel Flow on indoor side
    4434             :     Real64 HFS;                          // nominal height of fen system (assumed 1 m)
    4435             :     Real64 TOC_EFF;                      // effective thickness of open channel, m
    4436             :     Real64 ConvF;                        // convection factor: accounts for enhanced convection
    4437             :                                          //   for e.g. VB adjacent to open channel
    4438             :     Real64 HC_GA;                        // convection - glass to air
    4439             :     Real64 HC_SA;                        // convection - shade (both sides) to air
    4440             :     Real64 HC_GS;                        // convection - glass to shade (one side)
    4441        8064 :     Array1D<Real64> SOURCEdv(FS.NL + 1); // indices of merit
    4442             :     Real64 QGAIN;                        // total gain to conditioned space [[W/m2]
    4443             : 
    4444        8064 :     NL = FS.NL; // working copy
    4445        8064 :     if (NL < 1) return;
    4446             : 
    4447        8064 :     HCOCFout = HCOUT; // outdoor side
    4448             : 
    4449        8064 :     HHAT = 0.0;
    4450        8064 :     HC = 0.0;
    4451        8064 :     HR = 0.0;
    4452        8064 :     T = 0.0;
    4453        8064 :     TNEW = 0.0;
    4454        8064 :     EB = 0.0;
    4455        8064 :     JF = 0.0;
    4456        8064 :     JB = 0.0;
    4457        8064 :     Q = 0.0;
    4458        8064 :     QOCF_F = 0.0;
    4459        8064 :     QOCF_B = 0.0;
    4460        8064 :     QOCF = 0.0;
    4461        8064 :     QOCFRoom = 0.0;
    4462        8064 :     QNET = 0.0;
    4463        8064 :     QGAIN = 0.0;
    4464        8064 :     TAU = 0.0;
    4465        8064 :     RHOF = 0.0;
    4466        8064 :     RHOB = 0.0;
    4467        8064 :     EPSF = 0.0;
    4468        8064 :     EPSB = 0.0;
    4469        8064 :     HC_GA = 0.0;
    4470        8064 :     HC_SA = 0.0;
    4471        8064 :     HC_GS = 0.0;
    4472             : 
    4473        8064 :     ITRY = 0;
    4474             : 
    4475        8064 :     EB(0) = Constant::StefanBoltzmann * pow_4(TOUT);
    4476        8064 :     EB(NL + 1) = Constant::StefanBoltzmann * pow_4(TIN);
    4477             : 
    4478        8064 :     ADIM = 3 * NL + 2; // DIMENSION OF A-MATRIX
    4479             : 
    4480             :     // organize longwave radiant properties - book-keeping
    4481             : 
    4482        8064 :     TAU_ROOM = 0.0;                         // must always be zero
    4483        8064 :     RHOF_ROOM = 0.0;                        // almost always zero
    4484        8064 :     EPSF_ROOM = 1.0 - TAU_ROOM - RHOF_ROOM; // almost always unity
    4485        8064 :     RHOF(NL + 1) = RHOF_ROOM;
    4486        8064 :     EPSF(NL + 1) = EPSF_ROOM;
    4487        8064 :     TAU(NL + 1) = TAU_ROOM;
    4488             : 
    4489       37632 :     for (I = 1; I <= NL; ++I) {
    4490       29568 :         EPSF(I) = FS.L(I).LWP_EL.EPSLF;
    4491       29568 :         EPSB(I) = FS.L(I).LWP_EL.EPSLB;
    4492       29568 :         TAU(I) = FS.L(I).LWP_EL.TAUL;
    4493       29568 :         RHOF(I) = 1.0 - FS.L(I).LWP_EL.EPSLF - FS.L(I).LWP_EL.TAUL;
    4494       29568 :         RHOB(I) = 1.0 - FS.L(I).LWP_EL.EPSLB - FS.L(I).LWP_EL.TAUL;
    4495             :     }
    4496             : 
    4497        8064 :     TAU_OUT = 0.0;                       // must always be zero
    4498        8064 :     RHOB_OUT = 0.0;                      // DON'T CHANGE
    4499        8064 :     EPSB_OUT = 1.0 - TAU_OUT - RHOB_OUT; // should always be unity
    4500        8064 :     TAU(0) = TAU_OUT;
    4501        8064 :     EPSB(0) = EPSB_OUT;
    4502        8064 :     RHOB(0) = RHOB_OUT;
    4503             : 
    4504             :     // Later could add RHOF_ROOM to the parameter list
    4505             :     // Relaxation needed to keep solver stable if OCF is present
    4506             : 
    4507        8064 :     ALPHA = 1.0;
    4508        8064 :     if (NL >= 2) {
    4509        8064 :         if (FS.G(NL - 1).GTYPE == state.dataWindowEquivalentLayer->gtyOPENin) ALPHA = 0.5;
    4510        8064 :         if (FS.G(1).GTYPE == state.dataWindowEquivalentLayer->gtyOPENout) ALPHA = 0.10;
    4511             :     }
    4512             : 
    4513             :     //   FIRST ESTIMATE OF GLAZING TEMPERATURES AND BLACK EMISSIVE POWERS
    4514       37632 :     for (I = 1; I <= NL; ++I) {
    4515       29568 :         T(I) = TOUT + double(I) / double(NL + 1) * (TIN - TOUT);
    4516       29568 :         EB(I) = Constant::StefanBoltzmann * pow_4(T(I));
    4517             :     }
    4518             : 
    4519        8064 :     CONVRG = 0;
    4520             : 
    4521             :     //  Start the solver
    4522             :     //  ITERATION RE-ENTRY
    4523             : 
    4524        8064 :     Real64 const TIN_2(pow_2(TIN));
    4525        8064 :     Real64 const TOUT_2(pow_2(TOUT));
    4526        8064 :     Real64 const TRMOUT_4(pow_4(TRMOUT));
    4527        8064 :     Real64 const TRMIN_4(pow_4(TRMIN));
    4528             : 
    4529       28469 :     for (ITRY = 1; ITRY <= MaxIter; ++ITRY) {
    4530             : 
    4531             :         //  CALCULATE GAS LAYER CONVECTIVE HEAT TRANSFER COEFFICIENTS
    4532             : 
    4533       28469 :         hin_scheme = 3; //  different schemes for calculating convection
    4534             :                         //  coefficients glass-to-air and shade-to-air
    4535             :                         //  if open channel air flow is allowed
    4536             :                         //  see the corresponding subroutines for detail
    4537             :                         //  = 1 gives dependence of height, spacing, delta-T
    4538             :                         //  = 2 gives dependence of spacing, delta-T but
    4539             :                         //    returns unrealistic values for large spacing
    4540             :                         //  = 3 glass-shade spacing dependence only on HCIN
    4541             :                         //  = negative, applies HCIN without adjusting for
    4542             :                         //    temperature, height, spacing, slat angle
    4543             :                         //  Recommended -> hin_scheme=3 for use with HBX,
    4544             :                         //              simplicity, right trends wrt spacing
    4545             : 
    4546             :         // start by assuming no open channel flow on indoor side
    4547             : 
    4548       28469 :         HC[NL] = HCIN; //  default - HC[NL] supplied by calling routine
    4549             :                        //  use this for HBX
    4550             :                        // or
    4551             :                        // trigger calculation of HC[NL] using ASHRAE correlation
    4552             :                        //  HC[NL] = HIC_ASHRAE(1.0d0, T(NL), TIN)  ! h - flat plate
    4553             :                        // Add by BAN June 2013 for standard ratings U-value and SHGC calc only
    4554             :                        // if (present(HCInFlag)) {
    4555             :                        //     if (HCInFlag) HC[NL] = HCInWindowStandardRatings(Height, T(NL), TIN);
    4556             :                        // }
    4557       28469 :         HC[0] = HCOUT; // HC[0] supplied by calling routine as HCOUT
    4558             : 
    4559             :         // Check for open channels -  only possible with at least two layers
    4560       28469 :         if (NL >= 2) {
    4561      106044 :             for (I = 1; I <= NL - 1; ++I) { // Scan gaps between layers
    4562             : 
    4563             :                 // DEAL WITH INDOOR OPEN CHANNEL FLOW HERE
    4564       77575 :                 if ((I == NL - 1) && (FS.G(I).GTYPE == state.dataWindowEquivalentLayer->gtyOPENin)) {
    4565             : 
    4566             :                     // TOC_EFF = FS%G( I)%TAS_EFF / 1000.    ! effective thickness of OC gap, m
    4567           0 :                     TOC_EFF = FS.G(I).TAS_EFF; // effective thickness of OC gap, m Modified by BAN May 9, 2013
    4568           0 :                     HFS = 1.0;                 // nominal height of system (m)
    4569             : 
    4570             :                     // convection - glass to air
    4571           0 :                     GLtoAMB(state, TOC_EFF, HFS, T(NL - 1), TIN, HCIN, HC_GA, hin_scheme);
    4572             :                     // CALL GLtoAMB( 1.0, HFS, T( NL-1), TIN, HCIN, HC_GA, hin_scheme)
    4573             :                     //   ^ VERY WIDE GAP
    4574             : 
    4575             :                     // convection - shade (both sides) to air
    4576           0 :                     ConvF = ConvectionFactor(FS.L(I + 1));
    4577           0 :                     HC_SA = ConvF * SLtoAMB(state, TOC_EFF, HFS, T(NL), TIN, HCIN, hin_scheme);
    4578             :                     // HC_SA = ConvF * SLtoAMB( 1.0, HFS, T(NL), TIN, HCIN, hin_scheme)
    4579             :                     //  ^ VERY WIDE GAP
    4580             : 
    4581             :                     // convection - glass to shade (one side)
    4582           0 :                     SLtoGL(state, TOC_EFF, T(NL), T(NL - 1), HC_GS, 1);
    4583             :                     // CALL  SLtoGL( 1.0, T(NL), T(NL-1), HC_GS, 2)   !  REMOVE LATER
    4584             :                     //  ^ VERY WIDE GAP, should return near zero
    4585             :                     //  Don't use hin_scheme as last parameter - set manually
    4586             :                     //  1 = Conduction, 2 = slight Ra penalty
    4587             :                     //  Set negative for default HC_GS=0
    4588             :                     //  Recommended:  2
    4589           0 :                     HC[NL - 1] = HC_GS;
    4590           0 :                     HC[NL] = HCIN * ConvF;
    4591           0 :                     QOCF_B(NL - 1) = (TIN - T(NL - 1)) * HC_GA;
    4592           0 :                     QOCF_F(NL) = (TIN - T(NL)) * (HC_SA - HC[NL]);
    4593           0 :                     QOCFRoom = -QOCF_B(NL - 1) - QOCF_F(NL);
    4594             :                     // end of gap open to indoor side
    4595             : 
    4596       77575 :                 } else if ((I == 1) && (FS.G(I).GTYPE == state.dataWindowEquivalentLayer->gtyOPENout)) {
    4597             :                     // outdoor open channel
    4598           0 :                     QOCF_B(1) = (TOUT - T(1)) * HCOCFout;
    4599           0 :                     QOCF_F(2) = (TOUT - T(2)) * HCOCFout;
    4600           0 :                     HC[1] = 0.0;
    4601           0 :                     HC[0] = HCOCFout;
    4602             :                 } else {
    4603             :                     // normal gap
    4604       77575 :                     HC[I] = HConvGap(FS.G(I), T(I), T(I + 1));
    4605             :                 }
    4606             :             } //  end scan through gaps
    4607             : 
    4608             :             // total OCF gain to each layer
    4609       28469 :             QOCF = QOCF_F + QOCF_B;
    4610             : 
    4611             :         } //  end IF (NL .GE. 2)
    4612             : 
    4613             :         //  CONVERT TEMPERATURE POTENTIAL CONVECTIVE COEFFICIENTS to
    4614             :         //  BLACK EMISSIVE POWER POTENTIAL CONVECTIVE COEFFICIENTS
    4615             : 
    4616       28469 :         HHAT(0) = HC[0] * (1.0 / Constant::StefanBoltzmann) / ((TOUT_2 + pow_2(T(1))) * (TOUT + T(1)));
    4617             : 
    4618       28469 :         Real64 T_I_2(pow_2(T(1))), T_IP_2;
    4619      106044 :         for (I = 1; I <= NL - 1; ++I) { // Scan the cavities
    4620       77575 :             T_IP_2 = pow_2(T(I + 1));
    4621       77575 :             HHAT(I) = HC[I] * (1.0 / Constant::StefanBoltzmann) / ((T_I_2 + T_IP_2) * (T(I) + T(I + 1)));
    4622       77575 :             T_I_2 = T_IP_2;
    4623             :         }
    4624             : 
    4625       28469 :         HHAT(NL) = HC[NL] * (1.0 / Constant::StefanBoltzmann) / ((pow_2(T(NL)) + TIN_2) * (T(NL) + TIN));
    4626             : 
    4627             :         //  SET UP MATRIX
    4628       28469 :         XSOL = 0.0;
    4629       28469 :         A = 0.0;
    4630             : 
    4631       28469 :         L = 1;
    4632       28469 :         A(1, L) = 1.0;
    4633       28469 :         A(2, L) = -1.0 * RHOB(0); //  -1.0 * RHOB_OUT
    4634       28469 :         A(ADIM + 1, L) = EPSB_OUT * Constant::StefanBoltzmann * TRMOUT_4;
    4635             : 
    4636      134513 :         for (I = 1; I <= NL; ++I) {
    4637      106044 :             L = 3 * I - 1;
    4638      106044 :             A(3 * I - 2, L) = RHOF(I);
    4639      106044 :             A(3 * I - 1, L) = -1.0;
    4640      106044 :             A(3 * I, L) = EPSF(I);    //  LWP( I)%EPSLF
    4641      106044 :             A(3 * I + 2, L) = TAU(I); //  LWP( I)%TAUL
    4642      106044 :             A(ADIM + 1, L) = 0.0;
    4643             : 
    4644      106044 :             L = 3 * I;
    4645      106044 :             if (NL == 1) {
    4646           0 :                 A(1, L) = 1.0; // Single layer
    4647           0 :                 A(2, L) = -1.0;
    4648           0 :                 A(3, L) = -1.0 * (HHAT(0) + HHAT(1));
    4649           0 :                 A(4, L) = -1.0;
    4650           0 :                 A(5, L) = 1.0;
    4651           0 :                 A(ADIM + 1, L) = -1.0 * (HHAT(0) * EB(0) + HHAT(1) * EB(2) + SOURCE(1) + QOCF(1));
    4652      106044 :             } else if (I == 1) {
    4653       28469 :                 A(1, L) = 1.0; //  Outdoor layer
    4654       28469 :                 A(2, L) = -1.0;
    4655       28469 :                 A(3, L) = -1.0 * (HHAT(0) + HHAT(1));
    4656       28469 :                 A(4, L) = -1.0;
    4657       28469 :                 A(5, L) = 1.0;
    4658       28469 :                 A(6, L) = HHAT(1);
    4659       28469 :                 A(ADIM + 1, L) = -1.0 * (HHAT(0) * EB(0) + SOURCE(1) + QOCF(1));
    4660       77575 :             } else if (I == NL) {
    4661       28469 :                 A(3 * NL - 3, L) = HHAT(NL - 1); // Indoor layer
    4662       28469 :                 A(3 * NL - 2, L) = 1.0;
    4663       28469 :                 A(3 * NL - 1, L) = -1.0;
    4664       28469 :                 A(3 * NL, L) = -1.0 * (HHAT(NL) + HHAT(NL - 1));
    4665       28469 :                 A(3 * NL + 1, L) = -1.0;
    4666       28469 :                 A(3 * NL + 2, L) = 1.0;
    4667       28469 :                 A(ADIM + 1, L) = -1.0 * (HHAT(NL) * EB(NL + 1) + SOURCE(NL) + QOCF(NL));
    4668             :             } else {
    4669       49106 :                 A(3 * I - 3, L) = HHAT(I - 1);
    4670       49106 :                 A(3 * I - 2, L) = 1.0;
    4671       49106 :                 A(3 * I - 1, L) = -1.0;
    4672       49106 :                 A(3 * I, L) = -1.0 * (HHAT(I) + HHAT(I - 1));
    4673       49106 :                 A(3 * I + 1, L) = -1.0;
    4674       49106 :                 A(3 * I + 2, L) = 1.0;
    4675       49106 :                 A(3 * I + 3, L) = HHAT(I);
    4676       49106 :                 A(ADIM + 1, L) = -1.0 * (SOURCE(I) + QOCF(I));
    4677             :             }
    4678      106044 :             L = 3 * I + 1;
    4679      106044 :             A(3 * I - 2, L) = TAU(I); //   LWP( I)%TAUL
    4680      106044 :             A(3 * I, L) = EPSB(I);    //   LWP( I)%EPSLB
    4681      106044 :             A(3 * I + 1, L) = -1.0;
    4682      106044 :             A(3 * I + 2, L) = RHOB(I);
    4683      106044 :             A(ADIM + 1, L) = 0.0;
    4684             :         }
    4685             : 
    4686       28469 :         L = 3 * NL + 2;
    4687       28469 :         A(3 * NL + 1, L) = -1.0 * RHOF(NL + 1); //   - 1.0 * RHOF_ROOM
    4688       28469 :         A(3 * NL + 2, L) = 1.0;
    4689       28469 :         A(ADIM + 1, L) = EPSF_ROOM * Constant::StefanBoltzmann * TRMIN_4;
    4690             : 
    4691             :         //  SOLVE MATRIX
    4692             :         //  Call SOLMATS for single precision matrix solution
    4693       28469 :         SOLMATS(ADIM, A, XSOL);
    4694             : 
    4695             :         //  UNPACK SOLUTION VECTOR AND RECORD LARGEST TEMPERATURE CHANGE
    4696       28469 :         JB[0] = XSOL(1);
    4697             : 
    4698       28469 :         MAXERR = 0.0;
    4699      134513 :         for (I = 1; I <= NL; ++I) {
    4700      106044 :             J = 3 * I - 1;
    4701      106044 :             JF(I) = XSOL(J);
    4702      106044 :             ++J;
    4703      106044 :             EB(I) = max(1.0, XSOL(J)); // prevent impossible temps
    4704      106044 :             TNEW(I) = root_4(EB(I) / Constant::StefanBoltzmann);
    4705      106044 :             ++J;
    4706      106044 :             JB[I] = XSOL(J);
    4707      106044 :             MAXERR = max(MAXERR, std::abs(TNEW(I) - T(I)) / TNEW(I));
    4708             :         }
    4709             : 
    4710       28469 :         JF(NL + 1) = XSOL(ADIM);
    4711             : 
    4712             :         //  CALCULATE HEAT FLUX AT EACH GAP, Q
    4713      162982 :         for (I = 0; I <= NL; ++I) { // Loop gaps (including inside and outside
    4714      134513 :             Q(I) = JF(I + 1) - JB[I] + HHAT(I) * (EB(I + 1) - EB(I));
    4715             :         }
    4716             : 
    4717             :         //  A CHECK - NET HEAT FLUX INTO ANY LAYER, AT STEADY-STATE,
    4718             :         //  SHOULD BE ZERO
    4719      134513 :         for (I = 1; I <= NL; ++I) {
    4720      106044 :             QNET(I) = SOURCE(I) + QOCF(I) + Q(I) - Q(I - 1);
    4721             :         }
    4722             : 
    4723             :         //  UPDATE GLAZING TEMPERATURES AND BLACK EMISSIVE POWERS
    4724      134513 :         for (I = 1; I <= NL; ++I) {
    4725      106044 :             T(I) += ALPHA * (TNEW(I) - T(I));
    4726      106044 :             EB(I) = Constant::StefanBoltzmann * pow_4(T(I));
    4727             :         }
    4728             : 
    4729             :         //  CHECK FOR CONVERGENCE
    4730       28469 :         if (CONVRG > 0) break;
    4731       20405 :         if (MAXERR < TOL) ++CONVRG;
    4732             : 
    4733             :     } // main iteration
    4734             : 
    4735        8064 :     if (CONVRG == 0) {
    4736             : 
    4737           0 :         if (FS.WEQLSolverErrorIndex < 1) {
    4738           0 :             ++FS.WEQLSolverErrorIndex;
    4739           0 :             ShowSevereError(state, format("CONSTRUCTION:WINDOWEQUIVALENTLAYER = \"{}\"", FS.Name));
    4740           0 :             ShowContinueError(state, format("{}Net radiation analysis did not converge", RoutineName));
    4741           0 :             ShowContinueError(state, format("...Maximum error is = {:.6T}", MAXERR));
    4742           0 :             ShowContinueError(state, format("...Convergence tolerance is = {:.6T}", TOL));
    4743           0 :             ShowContinueErrorTimeStamp(state, "");
    4744             :         } else {
    4745           0 :             ShowRecurringWarningErrorAtEnd(state,
    4746           0 :                                            "CONSTRUCTION:WINDOWEQUIVALENTLAYER = \"" + FS.Name + "\"; " + std::string{RoutineName} +
    4747             :                                                "Net radiation analysis did not converge error continues.",
    4748           0 :                                            FS.WEQLSolverErrorIndex);
    4749             :         }
    4750             :     }
    4751             : 
    4752             :     //  NOTE:  HC_SA, HC_GA and HC_SG are only available if there is
    4753             :     //         an open channel on the indoor side and the calculation of
    4754             :     //         these coefficients was triggered earlier
    4755        8064 :     QGAIN = SOURCE(NL + 1) + HC[NL] * (T(NL) - TIN) + JB[NL] - JF(NL + 1);
    4756             :     // Modified by BAN May 3, 2013 to avoid zero layer index
    4757        8064 :     if (NL >= 2) {
    4758        8064 :         if (FS.G(NL - 1).GTYPE == state.dataWindowEquivalentLayer->gtyOPENin) {
    4759           0 :             QGAIN = SOURCE(NL + 1) + (HC_SA / 2.0) * (T(NL) - TIN) + JB[NL] - JF(NL + 1);
    4760           0 :             QGAIN += HC_GA * (T(NL - 1) - TIN) + (HC_SA / 2.0) * (T(NL) - TIN);
    4761             :         }
    4762             :     }
    4763        8064 : }
    4764             : 
    4765           9 : bool ASHWAT_ThermalRatings(EnergyPlusData &state,
    4766             :                            CFSTY const &FS,  // fenestration system
    4767             :                            Real64 const TIN, // indoor / outdoor air temperature, K
    4768             :                            Real64 const TOUT,
    4769             :                            Real64 const HCIN, // indoor / outdoor convective heat transfer
    4770             :                            Real64 const HCOUT,
    4771             :                            Real64 const TRMOUT,
    4772             :                            Real64 const TRMIN,           // indoor / outdoor mean radiant temp, K
    4773             :                            Real64 const ISOL,            // total incident solar, W/m2 (values used for SOURCE derivation)
    4774             :                            Array1S<Real64> const SOURCE, // absorbed solar by layer, W/m2
    4775             :                            Real64 const TOL,             // convergence tolerance, usually
    4776             :                            Array1D<Real64> &QOCF,        // returned: heat flux to layer i from gaps i-1 and i
    4777             :                            Real64 &QOCFRoom,             // returned: open channel heat gain to room, W/m2
    4778             :                            Array1D<Real64> &T,           // returned: layer temperatures, 1=outside-most layer, K
    4779             :                            Array1D<Real64> &Q,           // returned: heat flux at ith gap (betw layers i and i+1), W/m2
    4780             :                            Array1D<Real64> &JF,          // returned: front (outside facing) radiosity of surfaces, W/m2
    4781             :                            Array1D<Real64> &JB,          // returned: back (inside facing) radiosity, W/m2
    4782             :                            Array1D<Real64> &HC,          // returned: gap convective heat transfer coefficient, W/m2K
    4783             :                            Real64 &UCG,                  // returned: center-glass U-factor, W/m2-K
    4784             :                            Real64 &SHGC,                 // returned: center-glass SHGC (Solar Heat Gain Coefficient)
    4785             :                            bool const HCInFlag           // If true uses ISO Std 150099 routine for HCIn calc
    4786             : )
    4787             : {
    4788             :     // SUBROUTINE INFORMATION:
    4789             :     //       AUTHOR         JOHN L. WRIGHT (University of Waterloo, Mechanical Engineering)
    4790             :     //                      Chip Barnaby (WrightSoft)
    4791             :     //       DATE WRITTEN   LATEST MODIFICATIONS, February 2008
    4792             :     //       MODIFIED       Bereket Nigusse, June 2013
    4793             :     //                      added standard 155099 inside convection
    4794             :     //                      coefficient calculation for U-Factor
    4795             :     //       RE-ENGINEERED  na
    4796             : 
    4797             :     // PURPOSE OF THIS SUBROUTINE:
    4798             :     //     Subroutine to calculate the glazing temperatures of the
    4799             :     //     various elements of a window/shade array while solving an energy
    4800             :     //     balance which accounts for absorbed solar radiation, indoor-
    4801             :     //     outdoor temperature difference, any combination of hemispherical
    4802             :     //     IR optical properties of the various glazings/shading layers.
    4803             :     //     Mean radiant temperatures can differ from air temperature on
    4804             :     //     both the indoor and outdoor sides.
    4805             :     //     It is also possible to allow air-flow between the two layers
    4806             :     //     adjacent to the indoor side and/or the two layers adjacent the
    4807             :     //     outdoor side. U-factor and SHGC calculations are also included (optional)
    4808             : 
    4809             :     // METHODOLOGY EMPLOYED:
    4810             :     // Uses the net radiation method developed for ASHWAT fenestration
    4811             :     // model by John Wright, the University of WaterLoo
    4812             : 
    4813             :     // REFERENCES:
    4814             :     //  ASHRAE RP-1311
    4815             : 
    4816             :     bool ASHWAT_ThermalRatings;
    4817             : 
    4818             :     // Argument array dimensioning
    4819           9 :     EP_SIZE_CHECK(QOCF, FS.NL);
    4820           9 :     EP_SIZE_CHECK(T, FS.NL);
    4821           9 :     EP_SIZE_CHECK(JF, FS.NL + 1);
    4822           9 :     EP_SIZE_CHECK(JB, FS.NL + 1);
    4823           9 :     EP_SIZE_CHECK(HC, FS.NL + 1);
    4824             : 
    4825             :     // Locals
    4826             :     // FUNCTION ARGUMENT DEFINITIONS:
    4827             :     //   FS.NL determines # of layers modelled
    4828             :     //   coefficient, W/m2K
    4829             :     //   = outside direct + outside diffuse + inside diffuse
    4830             :     //   0.001 (good) or 0.0001 (tight)
    4831             :     //   due to open channel flow, W/m2
    4832             :     //   + = heat flow indoor to outdoor
    4833             :     //   JF( NL+1) = room radiosity
    4834             :     //   JB[ 0] = outside environment radiosity
    4835             :     //   0=outside, 1=betw layer 1-2, ..., NL=inside
    4836             : 
    4837             :     // FUNCTION PARAMETER DEFINITIONS:
    4838           9 :     Real64 constexpr Height(1.0); // Window height (m) for standard ratings calculation
    4839           9 :     int constexpr MaxIter(100);   // maximum number of iterations allowed
    4840             : 
    4841             :     Real64 ALPHA;
    4842             :     Real64 HCOCFout;
    4843          18 :     Array2D<Real64> A(3 * FS.NL + 4, 3 * FS.NL + 2);
    4844           9 :     Array1D<Real64> XSOL(3 * FS.NL + 2);
    4845             :     Real64 MAXERR;
    4846           9 :     Array1D<Real64> TNEW(FS.NL);        // latest estimate of layer temperatures, K
    4847           9 :     Array1D<Real64> EB({0, FS.NL + 1}); // black emissive power by layer, W/m2
    4848             :                                         //   EB( 0) = outdoor environment, EB( NL+1) = indoor environment
    4849           9 :     Array1D<Real64> HHAT({0, FS.NL});   // convective heat transfer coefficient (W/m2.K4)
    4850             :                                         //   based on EB, NOT temperature difference
    4851             :     Real64 RHOF_ROOM;                   // effective longwave room-side properties
    4852             :     Real64 TAU_ROOM;
    4853             :     Real64 EPSF_ROOM;
    4854             :     Real64 RHOB_OUT; // effective longwave outdoor environment properties
    4855             :     Real64 TAU_OUT;
    4856             :     Real64 EPSB_OUT;
    4857           9 :     Array1D<Real64> QNET(FS.NL); // checksum - net heat flux to a layer - should be zero - not needed
    4858             :     int ADIM;                    // dimension of the A matrix
    4859             :     int CONVRG;
    4860             :     int NL;
    4861             :     int I;
    4862             :     int J;
    4863             :     int L;
    4864             :     int ITRY;
    4865             :     int hin_scheme;                   // flags different schemes for indoor convection coefficients
    4866           9 :     Array1D_int ISDL({0, FS.NL + 1}); // Flag to mark diathermanous layers, 0=opaque
    4867             :     int NDLIAR;                       // Number of Diathermanous Layers In A Row (i.e., consecutive)
    4868             :     int IB;                           // Counter begin and end limits
    4869             :     int IE;
    4870             :     int IDV;                       // Integer dummy variable, general utility
    4871           9 :     Array1D<Real64> QOCF_F(FS.NL); // heat flux to outdoor-facing surface of layer i, from gap i-1,
    4872             :                                    //   due to open channel flow, W/m2
    4873           9 :     Array1D<Real64> QOCF_B(FS.NL); // heat flux to indoor-facing surface of layer i, from gap i,
    4874             :                                    //   due to open channel flow, W/m2
    4875             :     Real64 Rvalue;                 // R-value in IP units [hr.ft2.F/BTU]
    4876             :     Real64 TAE_IN;                 // Indoor and outdoor effective ambient temperatures [K]
    4877             :     Real64 TAE_OUT;
    4878           9 :     Array1D<Real64> HR({0, FS.NL}); // Radiant heat transfer coefficient [W/m2K]
    4879           9 :     Array1D<Real64> HJR(FS.NL);     // radiative and convective jump heat transfer coefficients
    4880           9 :     Array1D<Real64> HJC(FS.NL);
    4881             :     Real64 FHR_OUT; // hre/(hre+hce) fraction radiant h, outdoor or indoor, used for TAE
    4882             :     Real64 FHR_IN;
    4883             :     Real64 Q_IN;                          // net gain to the room [W/m2], including transmitted solar
    4884           9 :     Array1D<Real64> RHOF({0, FS.NL + 1}); // longwave reflectance, front    !  these variables help simplify
    4885           9 :     Array1D<Real64> RHOB({0, FS.NL + 1}); // longwave reflectance, back     !  the code because it is useful to
    4886           9 :     Array1D<Real64> EPSF({0, FS.NL + 1}); // longwave emisivity,   front    !  increase the scope of the arrays
    4887           9 :     Array1D<Real64> EPSB({0, FS.NL + 1}); // longwave emisivity,   back     !  to include indoor and outdoor
    4888           9 :     Array1D<Real64> TAU({0, FS.NL + 1});  // longwave transmittance         !  nodes - more general
    4889             :     Real64 RTOT;                          // total resistance from TAE_OUT to TAE_IN [m2K/W]
    4890          18 :     Array2D<Real64> HC2D(6, 6);           // convective heat transfer coefficients between layers i and j
    4891          18 :     Array2D<Real64> HR2D(6, 6);           // radiant heat transfer coefficients between layers i and j
    4892           9 :     Array1D<Real64> HCIout(6);            // convective and radiant heat transfer coefficients between
    4893           9 :     Array1D<Real64> HRIout(6);
    4894             :     // layer i and outdoor air or mean radiant temperature, resp.
    4895           9 :     Array1D<Real64> HCIin(6); // convective and radiant heat transfer coefficients between
    4896           9 :     Array1D<Real64> HRIin(6);
    4897             :     // layer i and indoor air or mean radiant temperature, resp.
    4898             :     Real64 HCinout; // convective and radiant heat transfer coefficients between
    4899             :     Real64 HRinout;
    4900             :     // indoor and outdoor air or mean radiant temperatures
    4901             :     // (almost always zero)
    4902             :     //  Indoor side convection coefficients - used for Open Channel Flow on indoor side
    4903             :     Real64 HFS;     // nominal height of fen system (assumed 1 m)
    4904             :     Real64 TOC_EFF; // effective thickness of open channel, m
    4905             :     Real64 ConvF;   // convection factor: accounts for enhanced convection
    4906             :                     //   for e.g. VB adjacent to open channel
    4907             :     Real64 HC_GA;   // convection - glass to air
    4908             :     Real64 HC_SA;   // convection - shade (both sides) to air
    4909             :     Real64 HC_GS;   // convection - glass to shade (one side)
    4910             :     Real64 TINdv;   // dummy variables used
    4911             :     Real64 TOUTdv;
    4912             :     Real64 TRMINdv; // for boundary conditions in calculating
    4913             :     Real64 TRMOUTdv;
    4914           9 :     Array1D<Real64> SOURCEdv(FS.NL + 1); // indices of merit
    4915             :     Real64 QGAIN;                        // total gain to conditioned space [[W/m2]
    4916             :     Real64 SaveHCNLm;                    // place to save HC[NL-1] - two resistance networks differ
    4917             :     Real64 SaveHCNL;                     // place to save HC[NL]   - two resistance networks differ
    4918             :                                          // in their definitions of these heat transfer coefficients
    4919             : 
    4920           9 :     ASHWAT_ThermalRatings = false; // init to failure
    4921           9 :     NL = FS.NL;                    // working copy
    4922           9 :     if (NL < 1) return ASHWAT_ThermalRatings;
    4923             : 
    4924           9 :     HCOCFout = HCOUT; // outdoor side
    4925             : 
    4926           9 :     HHAT = 0.0;
    4927           9 :     HC = 0.0;
    4928           9 :     HR = 0.0;
    4929           9 :     T = 0.0;
    4930           9 :     TNEW = 0.0;
    4931           9 :     EB = 0.0;
    4932           9 :     JF = 0.0;
    4933           9 :     JB = 0.0;
    4934           9 :     Q = 0.0;
    4935           9 :     QOCF_F = 0.0;
    4936           9 :     QOCF_B = 0.0;
    4937           9 :     QOCF = 0.0;
    4938           9 :     QOCFRoom = 0.0;
    4939           9 :     QNET = 0.0;
    4940           9 :     QGAIN = 0.0;
    4941           9 :     TAU = 0.0;
    4942           9 :     RHOF = 0.0;
    4943           9 :     RHOB = 0.0;
    4944           9 :     EPSF = 0.0;
    4945           9 :     EPSB = 0.0;
    4946           9 :     HC_GA = 0.0;
    4947           9 :     HC_SA = 0.0;
    4948           9 :     HC_GS = 0.0;
    4949             : 
    4950           9 :     ITRY = 0;
    4951             : 
    4952           9 :     EB(0) = Constant::StefanBoltzmann * pow_4(TOUT);
    4953           9 :     EB(NL + 1) = Constant::StefanBoltzmann * pow_4(TIN);
    4954             : 
    4955           9 :     ADIM = 3 * NL + 2; // DIMENSION OF A-MATRIX
    4956             : 
    4957             :     // organize longwave radiant properties - book-keeping
    4958             : 
    4959           9 :     TAU_ROOM = 0.0;                         // must always be zero
    4960           9 :     RHOF_ROOM = 0.0;                        // almost always zero
    4961           9 :     EPSF_ROOM = 1.0 - TAU_ROOM - RHOF_ROOM; // almost always unity
    4962           9 :     RHOF(NL + 1) = RHOF_ROOM;
    4963           9 :     EPSF(NL + 1) = EPSF_ROOM;
    4964           9 :     TAU(NL + 1) = TAU_ROOM;
    4965             : 
    4966          42 :     for (I = 1; I <= NL; ++I) {
    4967          33 :         EPSF(I) = FS.L(I).LWP_EL.EPSLF;
    4968          33 :         EPSB(I) = FS.L(I).LWP_EL.EPSLB;
    4969          33 :         TAU(I) = FS.L(I).LWP_EL.TAUL;
    4970          33 :         RHOF(I) = 1.0 - FS.L(I).LWP_EL.EPSLF - FS.L(I).LWP_EL.TAUL;
    4971          33 :         RHOB(I) = 1.0 - FS.L(I).LWP_EL.EPSLB - FS.L(I).LWP_EL.TAUL;
    4972             :     }
    4973             : 
    4974           9 :     TAU_OUT = 0.0;                       // must always be zero
    4975           9 :     RHOB_OUT = 0.0;                      // DON'T CHANGE
    4976           9 :     EPSB_OUT = 1.0 - TAU_OUT - RHOB_OUT; // should always be unity
    4977           9 :     TAU(0) = TAU_OUT;
    4978           9 :     EPSB(0) = EPSB_OUT;
    4979           9 :     RHOB(0) = RHOB_OUT;
    4980             : 
    4981             :     // Later could add RHOF_ROOM to the parameter list
    4982             :     // Relaxation needed to keep solver stable if OCF is present
    4983             : 
    4984           9 :     ALPHA = 1.0;
    4985           9 :     if (NL >= 2) {
    4986           9 :         if (FS.G(NL - 1).GTYPE == state.dataWindowEquivalentLayer->gtyOPENin) ALPHA = 0.5;
    4987           9 :         if (FS.G(1).GTYPE == state.dataWindowEquivalentLayer->gtyOPENout) ALPHA = 0.10;
    4988             :     }
    4989             : 
    4990             :     //   FIRST ESTIMATE OF GLAZING TEMPERATURES AND BLACK EMISSIVE POWERS
    4991          42 :     for (I = 1; I <= NL; ++I) {
    4992          33 :         T(I) = TOUT + double(I) / double(NL + 1) * (TIN - TOUT);
    4993          33 :         EB(I) = Constant::StefanBoltzmann * pow_4(T(I));
    4994             :     }
    4995             : 
    4996           9 :     CONVRG = 0;
    4997             : 
    4998             :     //  Start the solver
    4999             :     //  ITERATION RE-ENTRY
    5000             : 
    5001           9 :     Real64 const TIN_2(pow_2(TIN));
    5002           9 :     Real64 const TOUT_2(pow_2(TOUT));
    5003           9 :     Real64 const TRMOUT_4(pow_4(TRMOUT));
    5004           9 :     Real64 const TRMIN_4(pow_4(TRMIN));
    5005             : 
    5006          27 :     for (ITRY = 1; ITRY <= MaxIter; ++ITRY) {
    5007             : 
    5008             :         //  CALCULATE GAS LAYER CONVECTIVE HEAT TRANSFER COEFFICIENTS
    5009             : 
    5010          27 :         hin_scheme = 3; //  different schemes for calculating convection
    5011             :                         //  coefficients glass-to-air and shade-to-air
    5012             :                         //  if open channel air flow is allowed
    5013             :                         //  see the corresponding subroutines for detail
    5014             :                         //  = 1 gives dependence of height, spacing, delta-T
    5015             :                         //  = 2 gives dependence of spacing, delta-T but
    5016             :                         //    returns unrealistic values for large spacing
    5017             :                         //  = 3 glass-shade spacing dependence only on HCIN
    5018             :                         //  = negative, applies HCIN without adjusting for
    5019             :                         //    temperature, height, spacing, slat angle
    5020             :                         //  Recommended -> hin_scheme=3 for use with HBX,
    5021             :                         //              simplicity, right trends wrt spacing
    5022             : 
    5023             :         // start by assuming no open channel flow on indoor side
    5024             : 
    5025          27 :         HC[NL] = HCIN; //  default - HC[NL] supplied by calling routine
    5026             :                        //  use this for HBX
    5027             :                        // or
    5028             :                        // trigger calculation of HC[NL] using ASHRAE correlation
    5029             :                        //  HC[NL] = HIC_ASHRAE(1.0d0, T(NL), TIN)  ! h - flat plate
    5030             :                        // Add by BAN June 2013 for standard ratings U-value and SHGC calc only
    5031          27 :         if (HCInFlag) HC[NL] = HCInWindowStandardRatings(state, Height, T(NL), TIN);
    5032          27 :         HC[0] = HCOUT; // HC[0] supplied by calling routine as HCOUT
    5033             : 
    5034             :         // Check for open channels -  only possible with at least two layers
    5035          27 :         if (NL >= 2) {
    5036          99 :             for (I = 1; I <= NL - 1; ++I) { // Scan gaps between layers
    5037             : 
    5038             :                 // DEAL WITH INDOOR OPEN CHANNEL FLOW HERE
    5039          72 :                 if ((I == NL - 1) && (FS.G(I).GTYPE == state.dataWindowEquivalentLayer->gtyOPENin)) {
    5040             : 
    5041             :                     // TOC_EFF = FS%G( I)%TAS_EFF / 1000.    ! effective thickness of OC gap, m
    5042           0 :                     TOC_EFF = FS.G(I).TAS_EFF; // effective thickness of OC gap, m Modified by BAN May 9, 2013
    5043           0 :                     HFS = 1.0;                 // nominal height of system (m)
    5044             : 
    5045             :                     // convection - glass to air
    5046           0 :                     GLtoAMB(state, TOC_EFF, HFS, T(NL - 1), TIN, HCIN, HC_GA, hin_scheme);
    5047             :                     // CALL GLtoAMB( 1.0, HFS, T( NL-1), TIN, HCIN, HC_GA, hin_scheme)
    5048             :                     //   ^ VERY WIDE GAP
    5049             : 
    5050             :                     // convection - shade (both sides) to air
    5051           0 :                     ConvF = ConvectionFactor(FS.L(I + 1));
    5052           0 :                     HC_SA = ConvF * SLtoAMB(state, TOC_EFF, HFS, T(NL), TIN, HCIN, hin_scheme);
    5053             :                     // HC_SA = ConvF * SLtoAMB( 1.0, HFS, T(NL), TIN, HCIN, hin_scheme)
    5054             :                     //  ^ VERY WIDE GAP
    5055             : 
    5056             :                     // convection - glass to shade (one side)
    5057           0 :                     SLtoGL(state, TOC_EFF, T(NL), T(NL - 1), HC_GS, 1);
    5058             :                     // CALL  SLtoGL( 1.0, T(NL), T(NL-1), HC_GS, 2)   !  REMOVE LATER
    5059             :                     //  ^ VERY WIDE GAP, should return near zero
    5060             :                     //  Don't use hin_scheme as last parameter - set manually
    5061             :                     //  1 = Conduction, 2 = slight Ra penalty
    5062             :                     //  Set negative for default HC_GS=0
    5063             :                     //  Recommended:  2
    5064           0 :                     HC[NL - 1] = HC_GS;
    5065           0 :                     HC[NL] = HCIN * ConvF;
    5066           0 :                     QOCF_B(NL - 1) = (TIN - T(NL - 1)) * HC_GA;
    5067           0 :                     QOCF_F(NL) = (TIN - T(NL)) * (HC_SA - HC[NL]);
    5068           0 :                     QOCFRoom = -QOCF_B(NL - 1) - QOCF_F(NL);
    5069             :                     // end of gap open to indoor side
    5070             : 
    5071          72 :                 } else if ((I == 1) && (FS.G(I).GTYPE == state.dataWindowEquivalentLayer->gtyOPENout)) {
    5072             :                     // outdoor open channel
    5073           0 :                     QOCF_B(1) = (TOUT - T(1)) * HCOCFout;
    5074           0 :                     QOCF_F(2) = (TOUT - T(2)) * HCOCFout;
    5075           0 :                     HC[1] = 0.0;
    5076           0 :                     HC[0] = HCOCFout;
    5077             :                 } else {
    5078             :                     // normal gap
    5079          72 :                     HC[I] = HConvGap(FS.G(I), T(I), T(I + 1));
    5080             :                 }
    5081             :             } //  end scan through gaps
    5082             : 
    5083             :             // total OCF gain to each layer
    5084          27 :             QOCF = QOCF_F + QOCF_B;
    5085             : 
    5086             :         } //  end IF (NL .GE. 2)
    5087             : 
    5088             :         //  CONVERT TEMPERATURE POTENTIAL CONVECTIVE COEFFICIENTS to
    5089             :         //  BLACK EMISSIVE POWER POTENTIAL CONVECTIVE COEFFICIENTS
    5090             : 
    5091          27 :         HHAT(0) = HC[0] * (1.0 / Constant::StefanBoltzmann) / ((TOUT_2 + pow_2(T(1))) * (TOUT + T(1)));
    5092             : 
    5093          27 :         Real64 T_I_2(pow_2(T(1))), T_IP_2;
    5094          99 :         for (I = 1; I <= NL - 1; ++I) { // Scan the cavities
    5095          72 :             T_IP_2 = pow_2(T(I + 1));
    5096          72 :             HHAT(I) = HC[I] * (1.0 / Constant::StefanBoltzmann) / ((T_I_2 + T_IP_2) * (T(I) + T(I + 1)));
    5097          72 :             T_I_2 = T_IP_2;
    5098             :         }
    5099             : 
    5100          27 :         HHAT(NL) = HC[NL] * (1.0 / Constant::StefanBoltzmann) / ((pow_2(T(NL)) + TIN_2) * (T(NL) + TIN));
    5101             : 
    5102             :         //  SET UP MATRIX
    5103          27 :         XSOL = 0.0;
    5104          27 :         A = 0.0;
    5105             : 
    5106          27 :         L = 1;
    5107          27 :         A(1, L) = 1.0;
    5108          27 :         A(2, L) = -1.0 * RHOB(0); //  -1.0 * RHOB_OUT
    5109          27 :         A(ADIM + 1, L) = EPSB_OUT * Constant::StefanBoltzmann * TRMOUT_4;
    5110             : 
    5111         126 :         for (I = 1; I <= NL; ++I) {
    5112          99 :             L = 3 * I - 1;
    5113          99 :             A(3 * I - 2, L) = RHOF(I);
    5114          99 :             A(3 * I - 1, L) = -1.0;
    5115          99 :             A(3 * I, L) = EPSF(I);    //  LWP( I)%EPSLF
    5116          99 :             A(3 * I + 2, L) = TAU(I); //  LWP( I)%TAUL
    5117          99 :             A(ADIM + 1, L) = 0.0;
    5118             : 
    5119          99 :             L = 3 * I;
    5120          99 :             if (NL == 1) {
    5121           0 :                 A(1, L) = 1.0; // Single layer
    5122           0 :                 A(2, L) = -1.0;
    5123           0 :                 A(3, L) = -1.0 * (HHAT(0) + HHAT(1));
    5124           0 :                 A(4, L) = -1.0;
    5125           0 :                 A(5, L) = 1.0;
    5126           0 :                 A(ADIM + 1, L) = -1.0 * (HHAT(0) * EB(0) + HHAT(1) * EB(2) + SOURCE(1) + QOCF(1));
    5127          99 :             } else if (I == 1) {
    5128          27 :                 A(1, L) = 1.0; //  Outdoor layer
    5129          27 :                 A(2, L) = -1.0;
    5130          27 :                 A(3, L) = -1.0 * (HHAT(0) + HHAT(1));
    5131          27 :                 A(4, L) = -1.0;
    5132          27 :                 A(5, L) = 1.0;
    5133          27 :                 A(6, L) = HHAT(1);
    5134          27 :                 A(ADIM + 1, L) = -1.0 * (HHAT(0) * EB(0) + SOURCE(1) + QOCF(1));
    5135          72 :             } else if (I == NL) {
    5136          27 :                 A(3 * NL - 3, L) = HHAT(NL - 1); // Indoor layer
    5137          27 :                 A(3 * NL - 2, L) = 1.0;
    5138          27 :                 A(3 * NL - 1, L) = -1.0;
    5139          27 :                 A(3 * NL, L) = -1.0 * (HHAT(NL) + HHAT(NL - 1));
    5140          27 :                 A(3 * NL + 1, L) = -1.0;
    5141          27 :                 A(3 * NL + 2, L) = 1.0;
    5142          27 :                 A(ADIM + 1, L) = -1.0 * (HHAT(NL) * EB(NL + 1) + SOURCE(NL) + QOCF(NL));
    5143             :             } else {
    5144          45 :                 A(3 * I - 3, L) = HHAT(I - 1);
    5145          45 :                 A(3 * I - 2, L) = 1.0;
    5146          45 :                 A(3 * I - 1, L) = -1.0;
    5147          45 :                 A(3 * I, L) = -1.0 * (HHAT(I) + HHAT(I - 1));
    5148          45 :                 A(3 * I + 1, L) = -1.0;
    5149          45 :                 A(3 * I + 2, L) = 1.0;
    5150          45 :                 A(3 * I + 3, L) = HHAT(I);
    5151          45 :                 A(ADIM + 1, L) = -1.0 * (SOURCE(I) + QOCF(I));
    5152             :             }
    5153          99 :             L = 3 * I + 1;
    5154          99 :             A(3 * I - 2, L) = TAU(I); //   LWP( I)%TAUL
    5155          99 :             A(3 * I, L) = EPSB(I);    //   LWP( I)%EPSLB
    5156          99 :             A(3 * I + 1, L) = -1.0;
    5157          99 :             A(3 * I + 2, L) = RHOB(I);
    5158          99 :             A(ADIM + 1, L) = 0.0;
    5159             :         }
    5160             : 
    5161          27 :         L = 3 * NL + 2;
    5162          27 :         A(3 * NL + 1, L) = -1.0 * RHOF(NL + 1); //   - 1.0 * RHOF_ROOM
    5163          27 :         A(3 * NL + 2, L) = 1.0;
    5164          27 :         A(ADIM + 1, L) = EPSF_ROOM * Constant::StefanBoltzmann * TRMIN_4;
    5165             : 
    5166             :         //  SOLVE MATRIX
    5167             :         //  Call SOLMATS for single precision matrix solution
    5168          27 :         SOLMATS(ADIM, A, XSOL);
    5169             : 
    5170             :         //  UNPACK SOLUTION VECTOR AND RECORD LARGEST TEMPERATURE CHANGE
    5171          27 :         JB[0] = XSOL(1);
    5172             : 
    5173          27 :         MAXERR = 0.0;
    5174         126 :         for (I = 1; I <= NL; ++I) {
    5175          99 :             J = 3 * I - 1;
    5176          99 :             JF(I) = XSOL(J);
    5177          99 :             ++J;
    5178          99 :             EB(I) = max(1.0, XSOL(J)); // prevent impossible temps
    5179          99 :             TNEW(I) = root_4(EB(I) / Constant::StefanBoltzmann);
    5180          99 :             ++J;
    5181          99 :             JB[I] = XSOL(J);
    5182          99 :             MAXERR = max(MAXERR, std::abs(TNEW(I) - T(I)) / TNEW(I));
    5183             :         }
    5184             : 
    5185          27 :         JF(NL + 1) = XSOL(ADIM);
    5186             : 
    5187             :         //  CALCULATE HEAT FLUX AT EACH GAP, Q
    5188         153 :         for (I = 0; I <= NL; ++I) { // Loop gaps (including inside and outside
    5189         126 :             Q(I) = JF(I + 1) - JB[I] + HHAT(I) * (EB(I + 1) - EB(I));
    5190             :         }
    5191             : 
    5192             :         //  A CHECK - NET HEAT FLUX INTO ANY LAYER, AT STEADY-STATE,
    5193             :         //  SHOULD BE ZERO
    5194         126 :         for (I = 1; I <= NL; ++I) {
    5195          99 :             QNET(I) = SOURCE(I) + QOCF(I) + Q(I) - Q(I - 1);
    5196             :         }
    5197             : 
    5198             :         //  UPDATE GLAZING TEMPERATURES AND BLACK EMISSIVE POWERS
    5199         126 :         for (I = 1; I <= NL; ++I) {
    5200          99 :             T(I) += ALPHA * (TNEW(I) - T(I));
    5201          99 :             EB(I) = Constant::StefanBoltzmann * pow_4(T(I));
    5202             :         }
    5203             : 
    5204             :         //  CHECK FOR CONVERGENCE
    5205          27 :         if (CONVRG > 0) break;
    5206          18 :         if (MAXERR < TOL) ++CONVRG;
    5207             : 
    5208             :     } // main iteration
    5209             : 
    5210             :     // if (CONVRG == 0) {
    5211             : 
    5212             :     //    if (FS.WEQLSolverErrorIndex < 1) {
    5213             :     //        ++FS.WEQLSolverErrorIndex;
    5214             :     //        ShowSevereError(state, format("CONSTRUCTION:WINDOWEQUIVALENTLAYER = \"{}\"", FS.Name));
    5215             :     //        ShowContinueError(state, format("{}Net radiation analysis did not converge", RoutineName));
    5216             :     //        ShowContinueError(state, format("...Maximum error is = {:.6T}", MAXERR));
    5217             :     //        ShowContinueError(state, format("...Convergence tolerance is = {:.6T}", TOL));
    5218             :     //        ShowContinueErrorTimeStamp(state, "");
    5219             :     //    } else {
    5220             :     //        ShowRecurringWarningErrorAtEnd(state, "CONSTRUCTION:WINDOWEQUIVALENTLAYER = \"" + FS.Name + "\"; " + std::string{RoutineName} +
    5221             :     //                                           "Net radiation analysis did not converge error continues.",
    5222             :     //                                       FS.WEQLSolverErrorIndex);
    5223             :     //    }
    5224             :     //}
    5225             : 
    5226             :     //  NOTE:  HC_SA, HC_GA and HC_SG are only available if there is
    5227             :     //         an open channel on the indoor side and the calculation of
    5228             :     //         these coefficients was triggered earlier
    5229           9 :     QGAIN = SOURCE(NL + 1) + HC[NL] * (T(NL) - TIN) + JB[NL] - JF(NL + 1);
    5230             :     // Modified by BAN May 3, 2013 to avoid zero layer index
    5231           9 :     if (NL >= 2) {
    5232           9 :         if (FS.G(NL - 1).GTYPE == state.dataWindowEquivalentLayer->gtyOPENin) {
    5233           0 :             QGAIN = SOURCE(NL + 1) + (HC_SA / 2.0) * (T(NL) - TIN) + JB[NL] - JF(NL + 1);
    5234           0 :             QGAIN += HC_GA * (T(NL - 1) - TIN) + (HC_SA / 2.0) * (T(NL) - TIN);
    5235             :         }
    5236             :     }
    5237             : 
    5238           9 :     ASHWAT_ThermalRatings = true;
    5239             : 
    5240             :     // New code follows from here - for calculating Ucg and SHGC
    5241             :     // NOTE: This code can be bypassed if
    5242             :     //       indices of merit are not needed
    5243             : 
    5244             :     //  Initialize various things
    5245           9 :     HR = 0.0;
    5246           9 :     HJC = 0.0;
    5247           9 :     HJR = 0.0;
    5248           9 :     TAE_OUT = 0.0;
    5249           9 :     TAE_IN = 0.0;
    5250           9 :     FHR_OUT = 0.0;
    5251           9 :     FHR_IN = 0.0;
    5252           9 :     Q_IN = 0.0;
    5253           9 :     RTOT = 0.0;
    5254           9 :     UCG = 0.0;
    5255           9 :     SHGC = 0.0;
    5256           9 :     Rvalue = 0.0;
    5257           9 :     HC2D = 0.0;
    5258           9 :     HR2D = 0.0;
    5259           9 :     HCIout = 0.0;
    5260           9 :     HRIout = 0.0;
    5261           9 :     HCIin = 0.0;
    5262           9 :     HRIin = 0.0;
    5263           9 :     HCinout = 0.0;
    5264           9 :     HRinout = 0.0;
    5265           9 :     TNEW = 0.0;
    5266           9 :     TINdv = 0.0;
    5267           9 :     TOUTdv = 0.0;
    5268           9 :     TRMINdv = 0.0;
    5269           9 :     TRMOUTdv = 0.0;
    5270           9 :     SOURCEdv = 0.0;
    5271             : 
    5272             :     //  Identify the diathermanous layers
    5273           9 :     ISDL = 0;
    5274          42 :     for (I = 1; I <= NL; ++I) {
    5275          33 :         if (FS.L(I).LWP_EL.TAUL > 0.001)
    5276          12 :             ISDL(I) = 1; // layer is diathermanous
    5277             :                          // of tau_lw > 0.001 (ie 0.1%)
    5278             :                          // Note:  ISDL(0) and ISDL(NL+1)
    5279             :                          //        must both be zero
    5280             :     }                    // end loop to calculate ISDL(i)
    5281             : 
    5282             :     //  determine the largest number of consecutive diathermanous layers, NDLIAR
    5283             :     //                   i.e., the number of diathermanous layers in a row
    5284           9 :     NDLIAR = 0;
    5285           9 :     IDV = 0;
    5286          42 :     for (I = 1; I <= NL; ++I) {
    5287          33 :         if (ISDL(I) == 1) {
    5288          12 :             ++IDV;
    5289             :         } else {
    5290          21 :             IDV = 0;
    5291             :         }
    5292          33 :         if (IDV > NDLIAR) NDLIAR = IDV;
    5293             :     } // end loop to calculate NDLIAR
    5294             : 
    5295           9 :     if (NDLIAR > 1)
    5296           0 :         return ASHWAT_ThermalRatings; // cannot handle two (or more) consecutive
    5297             :                                       // diathermanous layers, U/SHGC calculation
    5298             :                                       // will be skipped entirely
    5299             :                                       // CHANGE TO (NDLIAR .GT. 2) ONCE
    5300             :                                       // SUBROUTINE DL2_RES IS AVAILABLE
    5301             : 
    5302             :     //   calculate radiant heat transfer coefficents between adjacent opaque
    5303             :     //   layers
    5304          51 :     for (I = 0; I <= NL; ++I) { // scan through all gaps - including indoor/outdoor
    5305          42 :         if ((ISDL(I) == 0) && (ISDL(I + 1) == 0)) {
    5306          18 :             if (I == 0) { //  outdoor side
    5307           6 :                 HR(I) = HRadPar(T(1), TRMOUT, EPSF(1), EPSB(0));
    5308          12 :             } else if (I == NL) { //  indoor side
    5309           6 :                 HR(I) = HRadPar(T(NL), TRMIN, EPSF(NL + 1), EPSB(NL));
    5310             :             } else { //  cavities
    5311           6 :                 HR(I) = HRadPar(T(I), T(I + 1), EPSF(I + 1), EPSB(I));
    5312             :             }
    5313             :         }
    5314             :     } // end loop through gaps
    5315             : 
    5316             :     //   calculate radiant heat transfer coefficents at single diathermanous
    5317             :     //   layers,three coefficients in each case
    5318             : 
    5319          42 :     for (I = 0; I <= NL - 1; ++I) { // scan through all layers - look for single DL
    5320             :                                     // layers between two opaque layers
    5321          33 :         if ((ISDL(I) == 0) && (ISDL(I + 1) == 1) && (ISDL(I + 2) == 0)) {
    5322          12 :             if (I == 0) { //  outdoor layer is diathermanous
    5323           3 :                 if (NL == 1) {
    5324           0 :                     DL_RES_r2(TRMOUT, T(1), TRMIN, RHOB(0), RHOF(1), RHOB(1), TAU(1), RHOF(2), HJR(1), HR(0), HR(1));
    5325             :                 } else {
    5326           3 :                     DL_RES_r2(TRMOUT, T(1), T(2), RHOB(0), RHOF(1), RHOB(1), TAU(1), RHOF(2), HJR(1), HR(0), HR(1));
    5327             :                 }
    5328             :             } else {               //  with IF (I .EQ. 0)   i.e., i != 0
    5329           9 :                 if (I == NL - 1) { //  indoor layer is diathermanous
    5330           3 :                     DL_RES_r2(T(NL - 1), T(NL), TRMIN, RHOB(NL - 1), RHOF(NL), RHOB(NL), TAU(NL), RHOF(NL + 1), HJR(NL), HR(NL - 1), HR(NL));
    5331             :                 } else { // some intermediate layer is diathermanous
    5332           6 :                     DL_RES_r2(T(I), T(I + 1), T(I + 2), RHOB(I), RHOF(I + 1), RHOB(I + 1), TAU(I + 1), RHOF(I + 2), HJR(I + 1), HR(I), HR(I + 1));
    5333             :                 } //   end of IF/ELSE (I .EQ. NL-1)
    5334             :             }     //  end of IF/ELSE (I .EQ. 0)
    5335             :         }         //  end of IF(ISDL(I) .EQ. 0) .AND. .....
    5336             :     }             //   end of scan through all layers
    5337             : 
    5338             :     //   calculate radiant heat transfer coefficents at double diathermanous
    5339             :     //   layers,six coefficients in each case
    5340             :     //   THIS SECTION NOT ACTIVE YET
    5341             : 
    5342           9 :     if (NL >= 2) {
    5343          33 :         for (I = 0; I <= NL - 2; ++I) { // scan through all layers - look for double DL
    5344             :                                         // layers between two opaque layers
    5345          24 :             if ((ISDL(I) == 0) && (ISDL(I + 1) == 1) && (ISDL(I + 2) == 1) && (ISDL(I + 3) == 0)) {
    5346           0 :                 if (I == 0) {
    5347             :                     //                CALL DL2_RES(TRMOUT, T(1), T(2), T(3) etc)
    5348             :                 } else {
    5349           0 :                     if (I == NL - 2) {
    5350             :                         //                CALL DL2_RES(T(NL-2), T(NL-1), T(NL), TRMIN, etc)
    5351             :                     } else {
    5352             :                         //                CALL DL2_RES(T(I), T(I+1), T(I+2), T(I+3) etc)
    5353             :                     } //   end of IF/ELSE (I .EQ. NL-1)
    5354             :                 }     //  end of IF/ELSE (I .EQ. 0)
    5355             :             }         //  end of IF(ISDL(I) .EQ. 0) .AND. .....
    5356             :         }             //   end of scan through all layers
    5357             :     }
    5358             : 
    5359             :     //  calculate convective OCF/jump heat transfer coefficients
    5360             : 
    5361           9 :     if (NL >= 2) { // no OCF unless at least two layers exist
    5362             :                    //  It is not possible for both of the following cases to be
    5363             :                    //  true for the same gap (i.e., for NL=2)
    5364             : 
    5365           9 :         if (FS.G(NL - 1).GTYPE == state.dataWindowEquivalentLayer->gtyOPENin) {
    5366           0 :             SaveHCNLm = HC[NL - 1];
    5367           0 :             SaveHCNL = HC[NL];
    5368           0 :             HC[NL - 1] = HC_GS;
    5369           0 :             HC[NL] = HC_SA;
    5370           0 :             HJC(NL) = HC_GA;
    5371             :         }
    5372             : 
    5373           9 :         HC[0] = HCOUT;
    5374           9 :         if (FS.G(1).GTYPE == state.dataWindowEquivalentLayer->gtyOPENout) {
    5375           0 :             HC[0] = HCOUT + HCOCFout;
    5376           0 :             HJC(1) = HCOCFout;
    5377             :         }
    5378             :     }
    5379             : 
    5380             :     //  copy convective heat transfer coefficients to 2D arrays
    5381             :     //  adjacent layers
    5382           9 :     IB = 1;
    5383           9 :     IE = NL - 1;
    5384           9 :     if (IB <= IE) {
    5385          33 :         for (I = IB; I <= IE; ++I) {
    5386          24 :             HC2D(I + 1, I) = HC[I];
    5387          24 :             HC2D(I, I + 1) = HC2D(I + 1, I);
    5388             :         }
    5389             :     }
    5390             : 
    5391             :     //  jumpers
    5392           9 :     IB = 2;
    5393           9 :     IE = NL - 1;
    5394           9 :     if (IB <= IE) {
    5395          21 :         for (I = IB; I <= IE; ++I) {
    5396          15 :             HC2D(I + 1, I - 1) = HJC(I);
    5397          15 :             HC2D(I - 1, I + 1) = HC2D(I + 1, I - 1);
    5398             :         }
    5399             :     }
    5400             : 
    5401             :     //  double jumpers  - NOT ACTIVE YET
    5402           9 :     IB = 2;
    5403           9 :     IE = NL - 2;
    5404           9 :     if (IB <= IE) {
    5405          12 :         for (I = IB; I <= IE; ++I) {
    5406             :             //         HC2D(I-1,I+2) = H2JC(I)
    5407             :             //         HC2D(I+2,I-1) = HC2D(I-1,I+2)
    5408             :         }
    5409             :     }
    5410             : 
    5411             :     //  outdoor side
    5412           9 :     HCIout(1) = HC[0];
    5413           9 :     if (NL >= 2) HCIout(2) = HJC(1);
    5414             : 
    5415             :     //  indoor side
    5416           9 :     HCIin(NL) = HC[NL];
    5417           9 :     if (NL >= 2) HCIin(NL - 1) = HJC(NL);
    5418             : 
    5419             :     //  special case - indoor-to-outdoor convection (?)
    5420           9 :     HCinout = 0.0;
    5421             : 
    5422             :     //  copy radiative heat transfer coefficients to 2D arrays
    5423             :     //  adjacent layers
    5424           9 :     IB = 1;
    5425           9 :     IE = NL - 1;
    5426           9 :     if (IB <= IE) {
    5427          33 :         for (I = IB; I <= IE; ++I) {
    5428          24 :             HR2D(I + 1, I) = HR(I);
    5429          24 :             HR2D(I, I + 1) = HR2D(I + 1, I);
    5430             :         }
    5431             :     }
    5432             : 
    5433             :     //  jumpers
    5434           9 :     IB = 2;
    5435           9 :     IE = NL - 1;
    5436           9 :     if (IB <= IE) {
    5437          21 :         for (I = IB; I <= IE; ++I) {
    5438          15 :             HR2D(I + 1, I - 1) = HJR(I);
    5439          15 :             HR2D(I - 1, I + 1) = HR2D(I + 1, I - 1);
    5440             :         }
    5441             :     }
    5442             : 
    5443             :     //  double jumpers
    5444           9 :     IB = 2;
    5445           9 :     IE = NL - 2;
    5446           9 :     if (IB <= IE) {
    5447          12 :         for (I = IB; I <= IE; ++I) {
    5448             :             //         HR2D(I-1,I+2) = H2JR(I)
    5449             :             //         HR2D(I+2,I-1) = HR2D(I-1,I+2)
    5450             :         }
    5451             :     }
    5452             : 
    5453             :     //  outdoor side
    5454           9 :     HRIout(1) = HR(0);
    5455           9 :     if (NL >= 2) HRIout(2) = HJR(1);
    5456             : 
    5457             :     //  indoor side
    5458           9 :     HRIin(NL) = HR(NL);
    5459           9 :     if (NL >= 2) HRIin(NL - 1) = HJR(NL);
    5460             : 
    5461             :     //  special case - indoor-to-outdoor radiation
    5462           9 :     if (NL == 1) HRinout = HJR(1);
    5463             :     //       IF(NL .EQ. 2)  HRinout=H2JR(1)
    5464             : 
    5465             :     //  CONFIRM VALIDITY OF CODE
    5466             : 
    5467             :     // if (1 == 0) { //  was used for debugging - successfully
    5468             :     //              //  and can now be bypassed
    5469             :     //              //  - code in this section generates the
    5470             :     //              //  same solution of temperatures (TNEW(i))
    5471             :     //              //  that was found by the net radiation
    5472             :     //              //  solver above (T(i))
    5473             : 
    5474             :     //    ADIM = NL;
    5475             :     //    A = 0.0;
    5476             :     //    XSOL = 0.0;
    5477             :     //    TOUTdv = TOUT;     // solution for TNEW should
    5478             :     //    TRMOUTdv = TRMOUT; // match existing solution
    5479             :     //    TINdv = TIN;       // for T
    5480             :     //    TRMINdv = TRMIN;
    5481             :     //    SOURCEdv = SOURCE;
    5482             : 
    5483             :     //    for (I = 1; I <= NL; ++I) {
    5484             :     //        A(ADIM + 1, I) = HCIout(I) * TOUTdv + HRIout(I) * TRMOUTdv + HCIin(I) * TINdv + HRIin(I) * TRMINdv + SOURCEdv(I);
    5485             :     //        A(I, I) = HCIout(I) + HRIout(I) + HCIin(I) + HRIin(I);
    5486             :     //        for (J = 1; J <= NL; ++J) {
    5487             :     //            if (J != I) {
    5488             :     //                A(I, I) += HC2D(J, I) + HR2D(J, I);
    5489             :     //                A(J, I) = -1.0 * (HC2D(J, I) + HR2D(J, I));
    5490             :     //            }
    5491             :     //        }
    5492             :     //    }
    5493             : 
    5494             :     //    //  SOLVE MATRIX
    5495             :     //    //  Call SOLMATS for single precision matrix solution
    5496             :     //    SOLMATS(ADIM, A, XSOL);
    5497             : 
    5498             :     //    //  UNPACK SOLUTION VECTOR
    5499             : 
    5500             :     //    SUMERR = 0.0;
    5501             :     //    for (I = 1; I <= NL; ++I) {
    5502             :     //        TNEW(I) = XSOL(I);
    5503             :     //        SUMERR += std::abs(TNEW(I) - T(I));
    5504             :     //    }
    5505             : 
    5506             :     //} //   end (1 .EQ. 0)    code disabled
    5507             : 
    5508             :     //  calculate U-factor
    5509             : 
    5510           9 :     ADIM = NL;
    5511           9 :     A = 0.0;
    5512           9 :     XSOL = 0.0;
    5513           9 :     TNEW = 0.0;
    5514           9 :     TOUTdv = 1.0;
    5515           9 :     TRMOUTdv = 1.0;
    5516           9 :     TINdv = 0.0;
    5517           9 :     TRMINdv = 0.0;
    5518           9 :     SOURCEdv = 0.0;
    5519             : 
    5520          42 :     for (I = 1; I <= NL; ++I) {
    5521          33 :         A(ADIM + 1, I) = HCIout(I) * TOUTdv + HRIout(I) * TRMOUTdv + HCIin(I) * TINdv + HRIin(I) * TRMINdv + SOURCEdv(I);
    5522          33 :         A(I, I) = HCIout(I) + HRIout(I) + HCIin(I) + HRIin(I);
    5523         180 :         for (J = 1; J <= NL; ++J) {
    5524         147 :             if (J != I) {
    5525         114 :                 A(I, I) += HC2D(J, I) + HR2D(J, I);
    5526         114 :                 A(J, I) = -1.0 * (HC2D(J, I) + HR2D(J, I));
    5527             :             }
    5528             :         }
    5529             :     }
    5530             : 
    5531             :     //  SOLVE MATRIX
    5532             :     //  Call SOLMATS for single precision matrix solution
    5533           9 :     SOLMATS(ADIM, A, XSOL);
    5534             :     //  UNPACK SOLUTION VECTOR
    5535             : 
    5536          42 :     for (I = 1; I <= NL; ++I) {
    5537          33 :         TNEW(I) = XSOL(I);
    5538             :     }
    5539             : 
    5540           9 :     Q_IN = HCinout * (TOUTdv - TINdv) + HRinout * (TRMOUTdv - TRMINdv);
    5541          42 :     for (I = 1; I <= NL; ++I) {
    5542          33 :         Q_IN += HCIin(I) * (TNEW(I) - TINdv) + HRIin(I) * (TNEW(I) - TRMINdv);
    5543             :     }
    5544           9 :     Q_IN += SOURCEdv(NL + 1); // this line not needed
    5545           9 :     UCG = Q_IN;
    5546           9 :     Rvalue = 5.678 / UCG;
    5547             : 
    5548             :     //  calculate SHGC
    5549             : 
    5550           9 :     SHGC = 0.0;
    5551           9 :     if (std::abs(ISOL) > 0.01) {
    5552           3 :         ADIM = NL;
    5553           3 :         A = 0.0;
    5554           3 :         XSOL = 0.0;
    5555           3 :         TNEW = 0.0;
    5556           3 :         TOUTdv = 0.0;
    5557           3 :         TRMOUTdv = 0.0;
    5558           3 :         TINdv = 0.0;
    5559           3 :         TRMINdv = 0.0;
    5560          17 :         for (I = 1; I <= NL + 1; ++I) {
    5561          14 :             SOURCEdv(I) = SOURCE(I);
    5562             :         }
    5563             : 
    5564          14 :         for (I = 1; I <= NL; ++I) {
    5565          11 :             A(ADIM + 1, I) = HCIout(I) * TOUTdv + HRIout(I) * TRMOUTdv + HCIin(I) * TINdv + HRIin(I) * TRMINdv + SOURCEdv(I);
    5566          11 :             A(I, I) = HCIout(I) + HRIout(I) + HCIin(I) + HRIin(I);
    5567          60 :             for (J = 1; J <= NL; ++J) {
    5568          49 :                 if (J != I) {
    5569          38 :                     A(I, I) += HC2D(J, I) + HR2D(J, I);
    5570          38 :                     A(J, I) = -1.0 * (HC2D(J, I) + HR2D(J, I));
    5571             :                 }
    5572             :             }
    5573             :         }
    5574             : 
    5575             :         //  SOLVE MATRIX
    5576             :         //  Call SOLMATS for single precision matrix solution
    5577           3 :         SOLMATS(ADIM, A, XSOL);
    5578             : 
    5579             :         //  UNPACK SOLUTION VECTOR
    5580          14 :         for (I = 1; I <= NL; ++I) {
    5581          11 :             TNEW(I) = XSOL(I);
    5582             :         }
    5583             : 
    5584           3 :         Q_IN = HCinout * (TOUTdv - TINdv) + HRinout * (TRMOUTdv - TRMINdv);
    5585          14 :         for (I = 1; I <= NL; ++I) {
    5586          11 :             Q_IN += HCIin(I) * (TNEW(I) - TINdv) + HRIin(I) * (TNEW(I) - TRMINdv);
    5587             :         }
    5588           3 :         Q_IN += SOURCEdv(NL + 1);
    5589             : 
    5590           3 :         SHGC = Q_IN / ISOL; // only executed if ISOL > 0.01 [W/m2]
    5591             : 
    5592             :     } //  end if (ABS(ISOL) .GT. 0.01)
    5593             : 
    5594             :     //  calculate FHR_OUT
    5595             : 
    5596           9 :     ADIM = NL;
    5597           9 :     A = 0.0;
    5598           9 :     XSOL = 0.0;
    5599           9 :     TNEW = 0.0;
    5600           9 :     TOUTdv = 1.0;
    5601           9 :     TRMOUTdv = 0.0;
    5602           9 :     TINdv = 0.0;
    5603           9 :     TRMINdv = 0.0;
    5604           9 :     SOURCEdv = 0.0;
    5605             : 
    5606          42 :     for (I = 1; I <= NL; ++I) {
    5607          33 :         A(ADIM + 1, I) = HCIout(I) * TOUTdv + HRIout(I) * TRMOUTdv + HCIin(I) * TINdv + HRIin(I) * TRMINdv + SOURCEdv(I);
    5608          33 :         A(I, I) = HCIout(I) + HRIout(I) + HCIin(I) + HRIin(I);
    5609         180 :         for (J = 1; J <= NL; ++J) {
    5610         147 :             if (J != I) {
    5611         114 :                 A(I, I) += HC2D(J, I) + HR2D(J, I);
    5612         114 :                 A(J, I) = -1.0 * (HC2D(J, I) + HR2D(J, I));
    5613             :             }
    5614             :         }
    5615             :     }
    5616             : 
    5617             :     //  SOLVE MATRIX
    5618             :     //  Call SOLMATS for single precision matrix solution
    5619           9 :     SOLMATS(ADIM, A, XSOL);
    5620             : 
    5621             :     //  UNPACK SOLUTION VECTOR
    5622             : 
    5623          42 :     for (I = 1; I <= NL; ++I) {
    5624          33 :         TNEW(I) = XSOL(I);
    5625             :     }
    5626             : 
    5627           9 :     Q_IN = HCinout * (TOUTdv - TINdv) + HRinout * (TRMOUTdv - TRMINdv);
    5628          42 :     for (I = 1; I <= NL; ++I) {
    5629          33 :         Q_IN += HCIin(I) * (TNEW(I) - TINdv) + HRIin(I) * (TNEW(I) - TRMINdv);
    5630             :     }
    5631           9 :     Q_IN += SOURCEdv(NL + 1);
    5632             : 
    5633           9 :     FHR_OUT = 1.0 - (Q_IN / UCG);
    5634           9 :     TAE_OUT = FHR_OUT * TRMOUT + (1.0 - FHR_OUT) * TOUT;
    5635             : 
    5636             :     //  calculate FHR_IN
    5637             : 
    5638           9 :     ADIM = NL;
    5639           9 :     A = 0.0;
    5640           9 :     XSOL = 0.0;
    5641           9 :     TNEW = 0.0;
    5642           9 :     TOUTdv = 0.0;
    5643           9 :     TRMOUTdv = 0.0;
    5644           9 :     TINdv = 1.0;
    5645           9 :     TRMINdv = 0.0;
    5646           9 :     SOURCEdv = 0.0;
    5647             : 
    5648          42 :     for (I = 1; I <= NL; ++I) {
    5649          33 :         A(ADIM + 1, I) = HCIout(I) * TOUTdv + HRIout(I) * TRMOUTdv + HCIin(I) * TINdv + HRIin(I) * TRMINdv + SOURCEdv(I);
    5650          33 :         A(I, I) = HCIout(I) + HRIout(I) + HCIin(I) + HRIin(I);
    5651         180 :         for (J = 1; J <= NL; ++J) {
    5652         147 :             if (J != I) {
    5653         114 :                 A(I, I) += HC2D(J, I) + HR2D(J, I);
    5654         114 :                 A(J, I) = -1.0 * (HC2D(J, I) + HR2D(J, I));
    5655             :             }
    5656             :         }
    5657             :     }
    5658             : 
    5659             :     //  SOLVE MATRIX
    5660             :     //  Call SOLMATS for single precision matrix solution
    5661           9 :     SOLMATS(ADIM, A, XSOL);
    5662             : 
    5663             :     //  UNPACK SOLUTION VECTOR
    5664             : 
    5665          42 :     for (I = 1; I <= NL; ++I) {
    5666          33 :         TNEW(I) = XSOL(I);
    5667             :     }
    5668             : 
    5669           9 :     Q_IN = HCinout * (TOUTdv - TINdv) + HRinout * (TRMOUTdv - TRMINdv);
    5670          42 :     for (I = 1; I <= NL; ++I) {
    5671          33 :         Q_IN += HCIin(I) * (TNEW(I) - TINdv) + HRIin(I) * (TNEW(I) - TRMINdv);
    5672             :     }
    5673           9 :     Q_IN += SOURCEdv(NL + 1);
    5674             : 
    5675           9 :     FHR_IN = 1.0 + (Q_IN / UCG);
    5676           9 :     TAE_IN = FHR_IN * TRMIN + (1.0 - FHR_IN) * TIN;
    5677             : 
    5678             :     //   double check heat gain to room
    5679             :     //   Q_IN calculated this way should be equal to QGAIN calculated
    5680             :     //   above with raw results from the net radiation solution
    5681             :     //   The difference between the two is printed below
    5682             :     //   Both include the directly transmitted solar gain
    5683             : 
    5684           9 :     Q_IN = UCG * (TAE_OUT - TAE_IN) + SHGC * ISOL;
    5685             : 
    5686             :     // End of new code - for calculating Ucg and SHGC
    5687             :     //  restore convective heat transfer coefficients if alterred earlier
    5688             :     //  for more general resistor network - otherwise mainline will
    5689             :     //  receive faulty data
    5690           9 :     if (NL >= 2) { // no OCF unless at least two layers exist
    5691           9 :         if (FS.G(NL - 1).GTYPE == state.dataWindowEquivalentLayer->gtyOPENin) {
    5692           0 :             HC[NL - 1] = SaveHCNLm;
    5693           0 :             HC[NL] = SaveHCNL;
    5694             :         }
    5695             :     }
    5696             : 
    5697           9 :     return ASHWAT_ThermalRatings;
    5698           9 : }
    5699             : 
    5700          12 : void DL_RES_r2(Real64 const Tg,    // mean glass layer temperature, {K}
    5701             :                Real64 const Td,    // mean diathermanous layer temperature, {K}
    5702             :                Real64 const Tm,    // mean radiant room temperature, {K}
    5703             :                Real64 const rhog,  // reflectance of glass layer, {-}
    5704             :                Real64 const rhodf, // front reflectance of diathermanous layer, {-}
    5705             :                Real64 const rhodb, // back reflectance of diathermanous layer, {-}
    5706             :                Real64 const taud,  // transmittance of diathermanous layer, {-}
    5707             :                Real64 const rhom,  // reflectance of the room, {-}
    5708             :                Real64 &hr_gm,      // heat transfer coefficient between left and right surface {W/m2K}
    5709             :                Real64 &hr_gd,      // heat transfer coefficient between left and middle surface {W/m2K}
    5710             :                Real64 &hr_md       // heat transfer coefficient between right and middle surface {W/m2K}
    5711             : )
    5712             : {
    5713             :     // SUBROUTINE INFORMATION:
    5714             :     //       AUTHOR         John L. Wright, University of Waterloo,
    5715             :     //                      Mechanical Engineering, Advanced Glazing System Laboratory
    5716             :     //       DATE WRITTEN   Unknown
    5717             :     //       MODIFIED       na
    5718             :     //       RE-ENGINEERED  na
    5719             : 
    5720             :     // PURPOSE OF THIS SUBROUTINE:
    5721             :     //  Returns the radiant heat transfer coefficients between parallel surfaces:
    5722             :     // METHODOLOGY EMPLOYED:
    5723             :     //  Solves radiant heat transfer coefficients between three parallel surfaces.
    5724             :     //  The left and right surfcaes are opaque with reflectance rhog and rhom, respectively.
    5725             :     //  And the middle layer is diathermanous with transmittance taud AND reflectance rhodf
    5726             :     //  and rhodb on the left and rightsides, respectively.
    5727             :     //  The subscripts g, d and m apply to Glass, Diathermanous layer, and mean-radiant room
    5728             :     //  temperature in a configuration of a window with an indoor-side shading attachment
    5729             :     //  but the analysis can be applied to any three layers in the configuration described
    5730             :     //  above.
    5731             : 
    5732             :     Real64 Epsg;
    5733             :     Real64 Epsdf;
    5734             :     Real64 Epsdb;
    5735             :     Real64 Epsm;
    5736          24 :     Array2D<Real64> A(22, 20);
    5737          12 :     Array1D<Real64> X(20);
    5738             :     // real FSg_g, FSdf_g, FSdb_g, FSm_g
    5739             :     Real64 FSg_df;
    5740             :     Real64 FSm_df;
    5741             :     Real64 FSg_db;
    5742             :     Real64 FSm_db;
    5743             :     Real64 FSg_m;
    5744             : 
    5745             :     //  Calculate 4 emissivities/absorptivities
    5746             : 
    5747          12 :     Epsg = 1.0 - rhog;
    5748          12 :     Epsdf = 1.0 - rhodf - taud;
    5749          12 :     Epsdb = 1.0 - rhodb - taud;
    5750          12 :     Epsm = 1.0 - rhom;
    5751             : 
    5752             :     //  Calculate script F shape factors
    5753             :     //  FSx_y is the portion of radiation emitted
    5754             :     //  by surface x that arrives at surface y
    5755             :     //  via any path - including reflections
    5756             :     //  By reciprocity FSxy=FSyx
    5757             : 
    5758             :     // step 1:  unit emission from (g) only
    5759             : 
    5760          12 :     SETUP4x4_A(rhog, rhodf, rhodb, taud, rhom, A);
    5761          12 :     A(5, 1) = 1.0; // unit source of radiation
    5762          12 :     SOLMATS(4, A, X);
    5763          12 :     FSg_df = X(1);
    5764             :     //  FSg_g   = X(2)
    5765          12 :     FSg_m = X(3);
    5766          12 :     FSg_db = X(4);
    5767             : 
    5768             :     // step 2:  unit emission from (df) only
    5769             : 
    5770             :     //   call SETUP4x4_A(rhog,rhodf,rhodb,taud,rhom,A)
    5771             :     //   A(2,5) = 1.0        ! unit source of radiation
    5772             :     //   call SOLMATS(4,A,X)
    5773             :     //   FSdf_df  = X(1)
    5774             :     //   FSdf_g   = X(2)
    5775             :     //   FSdf_m   = X(3)
    5776             :     //   FSdf_db  = X(4)
    5777             : 
    5778             :     // step 3:  unit emission from (db) only
    5779             : 
    5780             :     //   call SETUP4x4_A(rhog,rhodf,rhodb,taud,rhom,A)
    5781             :     //   A(3,5) = 1.0        ! unit source of radiation
    5782             :     //   call SOLMATS(4,A,X)
    5783             :     //   FSdb_df  = X(1)
    5784             :     //   FSdb_g   = X(2)
    5785             :     //   FSdb_m   = X(3)
    5786             :     //   FSdb_db  = X(4)
    5787             : 
    5788             :     // step 4:  unit emission from (m) only
    5789             : 
    5790          12 :     SETUP4x4_A(rhog, rhodf, rhodb, taud, rhom, A);
    5791          12 :     A(5, 4) = 1.0; // unit source of radiation
    5792          12 :     SOLMATS(4, A, X);
    5793          12 :     FSm_df = X(1);
    5794             :     //  FSm_g   = X(2)
    5795             :     //  FSm_m   = X(3)
    5796          12 :     FSm_db = X(4);
    5797             : 
    5798             :     //  calculate heat transfer coefficients
    5799             :     //  hr_xy is the heat transfer coefficient from x to y [W/m2]
    5800             :     //  Note:  If the emissivity of either surface x or surface y is zero
    5801             :     //         then q_xy will also be zero
    5802             :     //  Note:  This code has no problem with temperatures being equal
    5803             : 
    5804          12 :     Real64 const Td_2(pow_2(Td));
    5805          12 :     Real64 const Tg_2(pow_2(Tg));
    5806          12 :     Real64 const Tm_2(pow_2(Tm));
    5807          12 :     hr_gm = Epsg * Epsm * FSg_m * Constant::StefanBoltzmann * (Tg + Tm) * (Tg_2 + Tm_2);
    5808          12 :     hr_gd = Epsg * Epsdf * FSg_df * Constant::StefanBoltzmann * (Td + Tg) * (Td_2 + Tg_2) +
    5809          12 :             Epsg * Epsdb * FSg_db * Constant::StefanBoltzmann * (Td + Tg) * (Td_2 + Tg_2);
    5810          12 :     hr_md = Epsm * Epsdf * FSm_df * Constant::StefanBoltzmann * (Td + Tm) * (Td_2 + Tm_2) +
    5811          12 :             Epsm * Epsdb * FSm_db * Constant::StefanBoltzmann * (Td + Tm) * (Td_2 + Tm_2);
    5812          12 : }
    5813             : 
    5814          24 : void SETUP4x4_A(Real64 const rhog, Real64 const rhodf, Real64 const rhodb, Real64 const taud, Real64 const rhom, Array2A<Real64> A)
    5815             : {
    5816             :     // SUBROUTINE INFORMATION:
    5817             :     //       AUTHOR         John L. Wright, University of Waterloo,
    5818             :     //                      Mechanical Engineering, Advanced Glazing System Laboratory
    5819             :     //       DATE WRITTEN   Unknown
    5820             :     //       MODIFIED       na
    5821             :     //       RE-ENGINEERED  na
    5822             : 
    5823             :     // PURPOSE OF THIS SUBROUTINE:
    5824             :     //  Returns the 4 X 4 matrix for DL_RES_r2 routine:
    5825             :     // METHODOLOGY EMPLOYED:
    5826             :     //  fills in the matrix coefficients
    5827             : 
    5828             :     // Argument array dimensioning
    5829          24 :     A.dim(22, 20);
    5830             : 
    5831          24 :     A = 0.0;
    5832          24 :     A(1, 1) = 1.0;
    5833          24 :     A(2, 1) = -1.0 * rhog;
    5834          24 :     A(1, 2) = -1.0 * rhodf;
    5835          24 :     A(2, 2) = 1.0;
    5836          24 :     A(4, 2) = -1.0 * taud;
    5837          24 :     A(1, 3) = -1.0 * taud;
    5838          24 :     A(3, 3) = 1.0;
    5839          24 :     A(4, 3) = -1.0 * rhodb;
    5840          24 :     A(3, 4) = -1.0 * rhom;
    5841          24 :     A(4, 4) = 1.0;
    5842          24 : }
    5843             : 
    5844       77647 : Real64 FRA(Real64 const TM, // mean gas temp, K
    5845             :            Real64 const T,  // gas layer thickness, m
    5846             :            Real64 const DT, // temp difference across layer, K
    5847             :            Real64 const AK, // gas conductance coeffs, K = AK + BK*TM + CK*TM*TM
    5848             :            Real64 const BK,
    5849             :            Real64 const CK,
    5850             :            Real64 const ACP, // gas specific heat coeffs, CP = ACP + BCP*TM + CCP*TM*TM
    5851             :            Real64 const BCP,
    5852             :            [[maybe_unused]] Real64 const CCP,
    5853             :            Real64 const AVISC, // gas viscosity coeffs, VISC = AVISC + BVISC*TM + CVISC*TM*TM
    5854             :            Real64 const BVISC,
    5855             :            [[maybe_unused]] Real64 const CVISC,
    5856             :            Real64 const RHOGAS // gas density, kg/m3
    5857             : )
    5858             : {
    5859             :     //       AUTHOR         (John Wright, University of WaterLoo, ASHRAE 1311-RP)
    5860             :     //       DATE WRITTEN   unknown
    5861             :     //       MODIFIED       Bereket Nigusse, FSEC/UCF, May 2013
    5862             :     //       RE-ENGINEERED  na
    5863             : 
    5864             :     // PURPOSE OF THIS FUNCTION:
    5865             :     // Returns Rayleigh number given surface temperatures, and coefficients of
    5866             :     // quadratic correlations as a function of temperature for gas properties
    5867             : 
    5868             :     // METHODOLOGY EMPLOYED:
    5869             :     //  Ra = Gr * Pr
    5870             : 
    5871             :     // REFERENCES:
    5872             :     //  ASHRAE 1311-RP
    5873             : 
    5874             :     // Return value
    5875             :     Real64 FRA;
    5876             : 
    5877             :     // FUNCTION ARGUMENT DEFINITIONS:
    5878             :     //   (as adjusted e.g. re VB models)
    5879             : 
    5880             :     Real64 Z;
    5881             :     Real64 K;
    5882             :     Real64 CP;
    5883             :     Real64 VISC;
    5884             : 
    5885       77647 :     Z = 1.0;
    5886       77647 :     K = AK + BK * TM + CK * TM * TM;
    5887       77647 :     CP = ACP + BCP * TM + BCP * TM * TM;
    5888       77647 :     VISC = AVISC + BVISC * TM + BVISC * TM * TM;
    5889             : 
    5890       77647 :     FRA = (Constant::GravityConstant * RHOGAS * RHOGAS * DT * T * T * T * CP) / (VISC * K * TM * Z * Z);
    5891             : 
    5892       77647 :     return FRA;
    5893             : }
    5894             : 
    5895       77647 : Real64 FNU(Real64 const RA) // Rayleigh number
    5896             : {
    5897             :     //       AUTHOR         (John Wright, University of WaterLoo, ASHRAE 1311-RP)
    5898             :     //       DATE WRITTEN
    5899             :     //       MODIFIED       Bereket Nigusse, FSEC/UCF, May 2013
    5900             :     //       RE-ENGINEERED  na
    5901             : 
    5902             :     // PURPOSE OF THIS FUNCTION:
    5903             :     // Returns Nusselt number given Rayleigh number
    5904             : 
    5905             :     // METHODOLOGY EMPLOYED:
    5906             :     // Uses empirical correlation
    5907             : 
    5908             :     // REFERENCES:
    5909             :     //  ASHRAE 1311-RP
    5910             : 
    5911             :     // Return value
    5912             :     Real64 FNU;
    5913             : 
    5914       77647 :     Real64 const ARA(std::abs(RA));
    5915       77647 :     if (ARA <= 10000.0) {
    5916       77647 :         FNU = 1.0 + 1.75967e-10 * std::pow(ARA, 2.2984755);
    5917           0 :     } else if (ARA <= 50000.0) {
    5918           0 :         FNU = 0.028154 * std::pow(ARA, 0.413993);
    5919             :     } else {
    5920           0 :         FNU = 0.0673838 * std::pow(ARA, 1.0 / 3.0);
    5921             :     }
    5922       77647 :     return FNU;
    5923             : }
    5924             : 
    5925       77647 : Real64 HConvGap(CFSGAP const &G, // gap
    5926             :                 Real64 const T1, // bounding surface temps (K)
    5927             :                 Real64 const T2)
    5928             : {
    5929             :     //       AUTHOR         (University of WaterLoo, ASHRAE 1311-RP)
    5930             :     //       DATE WRITTEN   unknown
    5931             :     //       MODIFIED       Bereket Nigusse, FSEC/UCF, May 2013
    5932             :     //       RE-ENGINEERED  na
    5933             :     // PURPOSE OF THIS FUNCTION:
    5934             :     // Returns convective coefficient for a gap separated between two surfaces at
    5935             :     // temperatures T1 and T2 , W/m2-K
    5936             :     // METHODOLOGY EMPLOYED:
    5937             :     //  HConv = "Nusselt Number" * "Conductivity Of Gas"  / "Thickness Of Gap"
    5938             :     // REFERENCES:
    5939             :     //  ASHRAE 1311-RP
    5940             : 
    5941             :     // Return value
    5942             :     Real64 HConvGap;
    5943             : 
    5944             :     Real64 TM;   // Mean temperature, K
    5945             :     Real64 DT;   // temperature difference, (K)
    5946             :     Real64 RA;   // Rayleigh Number, (-)
    5947             :     Real64 NU;   // Nusselt Number, (-)
    5948             :     Real64 KGAS; // Gas conductivity at film temp, (W/m.K)
    5949             :     Real64 T;    // effective gap spacing, m
    5950             : 
    5951       77647 :     T = G.TAS_EFF;
    5952       77647 :     TM = (T1 + T2) / 2.0;
    5953       77647 :     DT = T1 - T2;
    5954       77647 :     RA = FRA(TM, T, DT, G.FG.AK, G.FG.BK, G.FG.CK, G.FG.ACP, G.FG.BCP, G.FG.CCP, G.FG.AVISC, G.FG.BVISC, G.FG.CVISC, G.RHOGAS);
    5955       77647 :     NU = FNU(RA);
    5956             : 
    5957       77647 :     KGAS = G.FG.AK + G.FG.BK * TM + G.FG.CK * TM * TM;
    5958       77647 :     HConvGap = NU * KGAS / T;
    5959       77647 :     return HConvGap;
    5960             : }
    5961             : 
    5962          18 : Real64 HRadPar(Real64 const T1, // bounding surface temps [K]
    5963             :                Real64 const T2,
    5964             :                Real64 const E1, // bounding surface emissivities
    5965             :                Real64 const E2)
    5966             : {
    5967             :     //       AUTHOR         ASHRAE 1311-RP
    5968             :     //       DATE WRITTEN   unknown
    5969             :     //       MODIFIED       na
    5970             :     //       RE-ENGINEERED  na
    5971             :     // PURPOSE OF THIS FUNCTION:
    5972             :     // Returns radiative coefficient between two surfaces, hr, W/m2-K
    5973             :     // METHODOLOGY EMPLOYED:
    5974             :     //  Radiative coefficient for parallel, opaque plates configuration and
    5975             :     //  automatically reverts to small-object-in-large-enclosure if one of
    5976             :     //  the emissivities is set to unity  i.e., set E1=1 and surface 2 is the
    5977             :     //  small object with hr based on area A2 If one emissivity is zero then
    5978             :     //  hr=0, division by zero is, avoided even if T1=T2.
    5979             :     // REFERENCES:
    5980             :     //  ASHRAE 1311-RP
    5981             : 
    5982             :     // Return value
    5983             :     Real64 HRadPar;
    5984             : 
    5985             :     Real64 DV; // dummy variable
    5986             : 
    5987          18 :     HRadPar = 0.0;
    5988          18 :     if ((E1 > 0.001) && (E2 > 0.001)) {
    5989          18 :         DV = (1.0 / E1) + (1.0 / E2) - 1.0;
    5990          18 :         HRadPar = (Constant::StefanBoltzmann / DV) * (T1 + T2) * (pow_2(T1) + pow_2(T2));
    5991             :     }
    5992          18 :     return HRadPar;
    5993             : }
    5994             : 
    5995           0 : Real64 HIC_ASHRAE(Real64 const L,  // glazing height, m
    5996             :                   Real64 const TG, // glazing inside surf temp, C or K
    5997             :                   Real64 const TI  // inside air temp, C or K
    5998             : )
    5999             : {
    6000             :     //       AUTHOR         ASHRAE 1311-RP
    6001             :     //       DATE WRITTEN   unknown
    6002             :     //       MODIFIED       na
    6003             :     //       RE-ENGINEERED  na
    6004             :     // PURPOSE OF THIS FUNCTION:
    6005             :     // Returns inside surface convective coefficient, W/m2-K
    6006             : 
    6007             :     // REFERENCES:
    6008             :     //  Footnote on Table 2, p. 31.6 (Fenestration) HOF 2005
    6009             : 
    6010             :     // Return value
    6011             :     Real64 HIC_ASHRAE;
    6012             : 
    6013           0 :     HIC_ASHRAE = 1.46 * root_4(std::abs(TG - TI) / max(L, 0.001));
    6014           0 :     return HIC_ASHRAE;
    6015             : }
    6016             : 
    6017           0 : void SLtoGL(EnergyPlusData &state,
    6018             :             Real64 const breal, // distance from shade to glass (m)
    6019             :             Real64 const Ts,    // shade temperature (K)
    6020             :             Real64 const Tg,    // glass temperature (K)
    6021             :             Real64 &hsg,        // the heat transfer coefficient, shade-to-glass, {W/m2K}
    6022             :             int const scheme)
    6023             : {
    6024             :     // SUBROUTINE INFORMATION:
    6025             :     //       AUTHOR         John L. Wright, University of Waterloo,
    6026             :     //                      Mechanical Engineering, Advanced Glazing System Laboratory
    6027             :     //       DATE WRITTEN   Unknown
    6028             :     //       MODIFIED       na
    6029             :     //       RE-ENGINEERED  na
    6030             : 
    6031             :     // PURPOSE OF THIS SUBROUTINE:
    6032             :     //  Returns the heat transfer coefficient, shade-to-glass
    6033             : 
    6034             :     Real64 b;
    6035             :     Real64 Tavg;
    6036             :     Real64 rho;
    6037             :     Real64 beta;
    6038             :     Real64 dvisc;
    6039             :     Real64 Cp;
    6040             :     Real64 k;
    6041             :     Real64 Rabsg;
    6042             :     Real64 Nubsg;
    6043             : 
    6044           0 :     hsg = 0.0; //  default - large spacing, b
    6045             : 
    6046           0 :     if (scheme == 1) { //  simple conduction layer, Nu=1
    6047             : 
    6048           0 :         b = breal;
    6049           0 :         if (b < 0.00001) b = 0.00001; // avoid division by zero in
    6050             :         // calculation of this scheme
    6051             : 
    6052           0 :         Tavg = (Ts + Tg) / 2.0;                                      // T for properties calculations
    6053           0 :         k = 0.02538 + ((Tavg - 290.0) / 10.0) * (0.02614 - 0.02538); // conductivity (W/m.K)
    6054           0 :         hsg = k / b;
    6055             : 
    6056           0 :     } else if (scheme == 2) { // similar to Nu=1 but small penalty at
    6057             :         // larger Ra    (Collins)
    6058           0 :         b = breal;
    6059           0 :         if (b < 0.00001) b = 0.00001; // avoid division by zero in
    6060             :         // calculation of this scheme
    6061             : 
    6062           0 :         Tavg = (Ts + Tg) / 2.0; // T for properties calculations
    6063             : 
    6064             :         // properties of AIR
    6065           0 :         rho = state.dataWindowEquivalentLayer->PAtmSeaLevel / (287.097 * Tavg); // density (kg/m3) <- temperature in (K)
    6066           0 :         beta = 1.0 / Tavg;                                                      // thermal expansion coef(/K)
    6067           0 :         dvisc = (18.05 + ((Tavg - 290.0) / 10.0) * (18.53 - 18.05)) * 1.0e-6;
    6068             :         //  dynamic viscosity (kg/m.sec) or (N.sec/m2)
    6069           0 :         Cp = 1044.66 - 0.31597 * Tavg + 0.000707908 * pow_2(Tavg) - 0.00000027034 * pow_3(Tavg);
    6070             :         //  specific heat at constant pressure (J/kg.K)
    6071           0 :         k = 0.02538 + ((Tavg - 290.0) / 10.0) * (0.02614 - 0.02538); // conductivity (W/m.K)
    6072             : 
    6073           0 :         Rabsg = (9.81 * beta * pow_3(b) * std::abs(Ts - Tg) * pow_2(rho) * Cp) / (dvisc * k);
    6074           0 :         Nubsg = 1.0 + 0.2 * (1.0 - std::exp(-0.005 * Rabsg));
    6075             : 
    6076           0 :         hsg = Nubsg * k / b;
    6077             :     } //  end of scheme .eq. 2
    6078           0 : }
    6079             : 
    6080           0 : Real64 SLtoAMB(EnergyPlusData &state,
    6081             :                Real64 const b,     // distance from shade to glass (m) where air flow takes place
    6082             :                Real64 const L,     // window height, m (usually taken as 1 m)
    6083             :                Real64 const Ts,    // shade temperature, K
    6084             :                Real64 const Tamb,  // room air temperature, K
    6085             :                Real64 const hc_in, // indoor (room) convective transfer coeff, W/m2K)
    6086             :                int const scheme    // flag to select model, scheme=2 has problems
    6087             : )
    6088             : {
    6089             :     //       AUTHOR         ASHRAE 1311-RP
    6090             :     //       DATE WRITTEN   unknown
    6091             :     //       MODIFIED       na
    6092             :     //       RE-ENGINEERED  na
    6093             :     // PURPOSE OF THIS FUNCTION:
    6094             :     // Returns shade to room air heat transfer coefficient
    6095             :     // METHODOLOGY EMPLOYED:
    6096             :     // fill gas is always air, orientation is always vertical
    6097             :     // hsamb should be h-flatplate at b=0 and 2*h-flatplate at b=large.  Note
    6098             :     // that hsamb is the same at slat angle = 0, 90, -90 degrees but increase
    6099             :     // by 20% at slat angle =45 degrees to mimic air pumping between slats
    6100             :     // therefore, specify slat angle=0 or 90 or -90 is shade is other than
    6101             :     // a venetian blind
    6102             : 
    6103             :     // Return value
    6104             :     Real64 SLtoAMB;
    6105             : 
    6106             :     // FUNCTION ARGUMENT DEFINITIONS:
    6107             :     //  scheme=3 recommended
    6108             : 
    6109             :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
    6110             :     // a
    6111             :     Real64 Tavg;
    6112             :     Real64 rho;
    6113             :     Real64 beta;
    6114             :     Real64 dvisc;
    6115             :     Real64 Cp;
    6116             :     Real64 k;
    6117             :     Real64 Rabsa;
    6118             :     Real64 hfp;
    6119             : 
    6120           0 :     SLtoAMB = 2.0 * hc_in; //    DEFAULT - convection from both sides
    6121             :     //    of shading layer - large spacing, b
    6122             : 
    6123           0 :     if (scheme == 1) {
    6124             :         // properties of AIR
    6125           0 :         Tavg = (Ts + Tamb) / 2.0;
    6126           0 :         rho = state.dataWindowEquivalentLayer->PAtmSeaLevel / (287.097 * Tavg); // density (kg/m3) <- temperature in (K)
    6127           0 :         beta = 1.0 / Tavg;                                                      // thermal expansion coef(/K)
    6128           0 :         dvisc = (18.05 + ((Tavg - 290.0) / 10.0) * (18.53 - 18.05)) * 1.0e-6;
    6129             :         //  dynamic viscosity (kg/m.sec) or (N.sec/m2)
    6130           0 :         Cp = 1044.66 - 0.31597 * Tavg + 0.000707908 * pow_2(Tavg) - 0.00000027034 * pow_3(Tavg);
    6131             :         //  specific heat at constant pressure (J/kg.K)
    6132           0 :         k = 0.02538 + ((Tavg - 290.0) / 10.0) * (0.02614 - 0.02538); // conductivity (W/m.K)
    6133             : 
    6134           0 :         Rabsa = (9.81 * beta * pow_3(b) * std::abs(Ts - Tamb) * pow_2(rho) * Cp) / (dvisc * k);
    6135           0 :         if (Rabsa <= 1.0) {
    6136           0 :             Rabsa = 1.0;
    6137             :         }
    6138             : 
    6139           0 :         hfp = HIC_ASHRAE(L, Ts, Tamb); // h - flat plate, influence by
    6140             :         // window height and temperature
    6141             :         // difference.  Note:  hfp goes to
    6142             :         // zero as delta-T goes to zero
    6143             : 
    6144             :         //  now adjust for distance from window glass
    6145           0 :         SLtoAMB = hfp * (1.0 + std::exp(-6000.0 / Rabsa));
    6146             :         //  SLtoAmb goes to 2*hfp at large b and hfp at small b and small (20%)
    6147             :         //  penalty is applied if slat angle is not zero or +/- 90 degrees
    6148             :         //  Note:  influence of distance is lost if delta-T goes to zero
    6149             :         //  Note:  as delta-T -> zero, Rabga->0, SLtoAmb -> hfp, not 2hfp,
    6150             :         //        for any spacing, even large b.  This is a problem
    6151             : 
    6152           0 :     } else if (scheme == 2) {
    6153             :         // properties of AIR
    6154           0 :         Tavg = (Ts + Tamb) / 2.0;
    6155           0 :         rho = state.dataWindowEquivalentLayer->PAtmSeaLevel / (287.097 * Tavg); // density (kg/m3) <- temperature in (K)
    6156           0 :         beta = 1.0 / Tavg;                                                      // thermal expansion coef(/K)
    6157           0 :         dvisc = (18.05 + ((Tavg - 290.0) / 10.0) * (18.53 - 18.05)) * 1.0e-6;
    6158             :         //  dynamic viscosity (kg/m.sec) or (N.sec/m2)
    6159           0 :         Cp = 1044.66 - 0.31597 * Tavg + 0.000707908 * pow_2(Tavg) - 0.00000027034 * pow_3(Tavg);
    6160             :         //  specific heat at constant pressure (J/kg.K)
    6161           0 :         k = 0.02538 + ((Tavg - 290.0) / 10.0) * (0.02614 - 0.02538); // conductivity (W/m.K)
    6162             : 
    6163           0 :         Rabsa = (9.81 * beta * pow_3(b) * std::abs(Ts - Tamb) * pow_2(rho) * Cp) / (dvisc * k);
    6164           0 :         if (Rabsa <= 1.0) {
    6165           0 :             Rabsa = 1.0;
    6166             :         }
    6167             : 
    6168           0 :         hfp = hc_in; // h - flat plate - from calling routine
    6169             :         // Note:  using this approach, L no longer has influence on hfp
    6170             : 
    6171             :         // now adjust for distance from window glass
    6172           0 :         SLtoAMB = hfp * (1.0 + std::exp(-6000.0 / Rabsa));
    6173             :         // Note:  as delta-T -> zero, Rabga->0, SLtoAmb -> hfp, not 2hfp,
    6174             :         //        for any spacing, even large b.  This is a problem
    6175             : 
    6176           0 :     } else if (scheme == 3) {
    6177             : 
    6178           0 :         hfp = hc_in; // h - flat plate - from calling routine
    6179             :         // now adjust for distance from window glass
    6180           0 :         SLtoAMB = hfp * (2.0 - std::exp(-4.6 * b / 0.1));
    6181             :         // Note:  using this approach, L and temperatures no longer have
    6182             :         //                               influence on result
    6183             :         //  SLtoAmb = 2*hc_in when glass/shade spacing, b, is large
    6184             :         //  SLtoAmb = hc_in when glass/shade spacing, b, is zero
    6185             :         //  The exponential decay is 99% complete at b=4 inches = 0.1 m
    6186             :         //                                               ln(0.01) = -4.6
    6187             :         //  This coefficient could be fine tuned in future versions, perhaps
    6188             :         //  as a function of boundary layer thickness for specific values
    6189             :         //  of glass and shade temperatures
    6190             :     } //  end of scheme .eq. 3
    6191           0 :     return SLtoAMB;
    6192             : }
    6193             : 
    6194           0 : void GLtoAMB(EnergyPlusData &state,
    6195             :              Real64 const b,     // distance from shade to glass {m}
    6196             :              Real64 const L,     // window height {m}, usually taken as 1 meter
    6197             :              Real64 const Tg,    // glass temperature {K}
    6198             :              Real64 const Tamb,  // room air temperature, {K}
    6199             :              Real64 const hc_in, // inside convection coefficient, {W/m2K}
    6200             :              Real64 &hgamb,      // glass to room air heat transfer coefficient
    6201             :              int const scheme)
    6202             : {
    6203             :     // SUBROUTINE INFORMATION:
    6204             :     //       AUTHOR         John L. Wright, University of Waterloo,
    6205             :     //                      Mechanical Engineering, Advanced Glazing System Laboratory
    6206             :     //       DATE WRITTEN   Unknown
    6207             :     //       MODIFIED       na
    6208             :     //       RE-ENGINEERED  na
    6209             : 
    6210             :     // PURPOSE OF THIS SUBROUTINE:
    6211             :     //  Returns the glass to room air heat transfer coefficient
    6212             :     // METHODOLOGY EMPLOYED:
    6213             :     // scheme = flag to select model, scheme=2 has problems, scheme=3 recommended
    6214             :     // fill gas is always air, orientation is always vertical
    6215             :     // hgamb should be zero at b=0, h-flatplate at b=large
    6216             : 
    6217             :     Real64 Tavg;
    6218             :     Real64 rho;
    6219             :     Real64 beta;
    6220             :     Real64 dvisc;
    6221             :     Real64 Cp;
    6222             :     Real64 k;
    6223             :     Real64 Rabga;
    6224             :     Real64 hfp;
    6225             : 
    6226           0 :     hgamb = hc_in; // default - good for large glass/shade spacing
    6227             : 
    6228           0 :     if (scheme == 1) { //  Collins
    6229             : 
    6230           0 :         Tavg = (Tg + Tamb) / 2.0; // T for properties calculations
    6231             : 
    6232             :         // properties of AIR
    6233           0 :         rho = state.dataWindowEquivalentLayer->PAtmSeaLevel / (287.097 * Tavg); // density (kg/m3) <- temperature in (K)
    6234           0 :         beta = 1.0 / Tavg;                                                      // thermal expansion coef(/K)
    6235           0 :         dvisc = (18.05 + ((Tavg - 290.0) / 10.0) * (18.53 - 18.05)) * 1.0e-6;
    6236             :         //  dynamic viscosity (kg/m.sec) or (N.sec/m2)
    6237           0 :         Cp = 1044.66 - 0.31597 * Tavg + 0.000707908 * pow_2(Tavg) - 0.00000027034 * pow_3(Tavg);
    6238             :         //  specific heat at constant pressure (J/kg.K)
    6239           0 :         k = 0.02538 + ((Tavg - 290.0) / 10.0) * (0.02614 - 0.02538); // conductivity (W/m.K)
    6240             : 
    6241           0 :         Rabga = (9.81 * beta * pow_3(b) * std::abs(Tg - Tamb) * pow_2(rho) * Cp) / (dvisc * k);
    6242           0 :         if (Rabga <= 1.0) {
    6243           0 :             Rabga = 1.0;
    6244             :         }
    6245             : 
    6246           0 :         hfp = HIC_ASHRAE(L, Tg, Tamb); // h - flat plate
    6247             :         // Note:  as delta-T goes to zero, hfp will also go to zero
    6248             : 
    6249           0 :         hgamb = hfp * std::exp(-50.0 / Rabga);
    6250             :         // Note:  as delta-T -> zero, Rabga->0, hgamb -> zero too
    6251             :         //        for any spacing, even large b.  This is a problem
    6252             : 
    6253           0 :     } else if (scheme == 2) {
    6254             : 
    6255           0 :         Tavg = (Tg + Tamb) / 2.0; // T for properties calculations
    6256             : 
    6257             :         // properties of AIR
    6258           0 :         rho = state.dataWindowEquivalentLayer->PAtmSeaLevel / (287.097 * Tavg); // density (kg/m3) <- temperature in (K)
    6259           0 :         beta = 1.0 / Tavg;                                                      // thermal expansion coef(/K)
    6260           0 :         dvisc = (18.05 + ((Tavg - 290.0) / 10.0) * (18.53 - 18.05)) * 1.0e-6;
    6261             :         //  dynamic viscosity (kg/m.sec) or (N.sec/m2)
    6262           0 :         Cp = 1044.66 - 0.31597 * Tavg + 0.000707908 * pow_2(Tavg) - 0.00000027034 * pow_3(Tavg);
    6263             :         //  specific heat at constant pressure (J/kg.K)
    6264           0 :         k = 0.02538 + ((Tavg - 290.0) / 10.0) * (0.02614 - 0.02538); // conductivity (W/m.K)
    6265             : 
    6266           0 :         Rabga = (9.81 * beta * pow_3(b) * std::abs(Tg - Tamb) * pow_2(rho) * Cp) / (dvisc * k);
    6267           0 :         if (Rabga <= 1.0) {
    6268           0 :             Rabga = 1.0;
    6269             :         }
    6270             : 
    6271           0 :         hfp = hc_in; // h - flat plate - from calling routine
    6272             :         // Note:  using this approach, L no longer has influence on result
    6273             :         //       but temperature does and it will drive hgamb to zero when
    6274             :         //       the temperature difference goes to zero
    6275             : 
    6276           0 :         hgamb = hfp * std::exp(-50.0 / Rabga);
    6277             :         // Note:  as delta-T -> zero, Rabga->0, hgamb -> zero too
    6278             :         //        for any spacing, even large b.  This is a problem
    6279             : 
    6280           0 :     } else if (scheme == 3) {
    6281             : 
    6282           0 :         hfp = hc_in; // h - flat plate - from calling routine
    6283           0 :         hgamb = hfp * (1.0 - std::exp(-4.6 * b / 0.1));
    6284             :         // Note:  using this approach, L and temperatures no longer have
    6285             :         //                               influence on result
    6286             :         //  hgamb = hc_in when glass/shade spacing, b, is large
    6287             :         //  hgamb = zero  when glass/shade spacing, b, is zero
    6288             :         //  The exponential decay is 99% complete at b=4 inches = 0.1 m
    6289             :         //                                               ln(0.01) = -4.6
    6290             :         //  This coefficient could be fine tuned in future versions, perhaps
    6291             :         //  as a function of boundary layer thickness for specific values
    6292             :         //  of glass and shade temperatures
    6293             : 
    6294             :     } //  end of scheme .eq. 3
    6295           0 : }
    6296             : 
    6297           0 : Real64 ConvectionFactor(CFSLAYER const &L) // window layer
    6298             : {
    6299             :     //       AUTHOR         ASHRAE 1311-RP
    6300             :     //       DATE WRITTEN   unknown
    6301             :     //       MODIFIED       na
    6302             :     //       RE-ENGINEERED  na
    6303             :     // PURPOSE OF THIS FUNCTION:
    6304             :     //  Modifies convection rate per shade configuration, layer convection enhancement
    6305             : 
    6306             :     // Return value
    6307             :     Real64 ConvectionFactor;
    6308             : 
    6309             :     Real64 SlatADeg;
    6310             : 
    6311           0 :     if (L.LTYPE == LayerType::VBHOR) {
    6312             :         // horiz VB: enhanced convection at +/- 45 due to "pumping"
    6313           0 :         SlatADeg = min(90.0, std::abs(L.PHI_DEG));
    6314           0 :         ConvectionFactor = 1.0 + 0.2 * std::sin(2.0 * SlatADeg);
    6315             :     } else {
    6316           0 :         ConvectionFactor = 1.0;
    6317             :     }
    6318           0 :     return ConvectionFactor;
    6319             : }
    6320             : 
    6321           6 : bool CFSUFactor(EnergyPlusData &state,
    6322             :                 CFSTY const &FS,    // fenestration system
    6323             :                 Real64 const TOUT,  // outdoor temperature, C (air and MRT)
    6324             :                 Real64 const HCOUT, // outdoor convective coefficient, W/m2-K
    6325             :                 Real64 const TIN,   // indoor air temperature, C
    6326             :                 Real64 const HCIN,  // indoor convective coefficient, W/m2-K
    6327             :                 Real64 &U           // returned: U factor, W/m2-K
    6328             : )
    6329             : {
    6330             :     // FUNCTION INFORMATION:
    6331             :     //       AUTHOR         unknown (University of WaterLoo, ASHRAE 1311-RP)
    6332             :     //       DATE WRITTEN   unknown
    6333             :     //       MODIFIED       Bereket Nigusse, FSEC/UCF, June 2013
    6334             :     //       RE-ENGINEERED  na
    6335             : 
    6336             :     // PURPOSE OF THIS FUNCTION:
    6337             :     // ! returns .TRUE. if the U-value calculation succeeded, .FALSE. if error
    6338             : 
    6339             :     // METHODOLOGY EMPLOYED:
    6340             :     //  uses net radiation method to solve for window surface temperatures and
    6341             :     //  heat fluxes. Then calculates the U-value from the flux and over all
    6342             :     //  temperature difference.
    6343             : 
    6344             :     // REFERENCES:
    6345             :     //  ASHRAE 1311-RP
    6346             : 
    6347             :     // Return value
    6348             :     bool CFSUFactor;
    6349             : 
    6350             :     // Locals
    6351             :     // FUNCTION ARGUMENT DEFINITIONS:
    6352             :     // for conditions specified (no incident solar)
    6353             :     // FUNCTION PARAMETER DEFINITIONS:
    6354           6 :     Real64 constexpr TOL(0.01); // 0.0001d0
    6355             : 
    6356             :     int NL;
    6357             :     Real64 TOABS;
    6358             :     Real64 TRMOUT;
    6359             :     Real64 TIABS;
    6360             :     Real64 TRMIN;
    6361           6 :     Array1D<Real64> QOCF(FS.NL);
    6362             :     Real64 QOCFRoom;
    6363           6 :     Array1D<Real64> JB({0, FS.NL});
    6364           6 :     Array1D<Real64> JF({1, FS.NL + 1});
    6365           6 :     Array1D<Real64> T(FS.NL);
    6366           6 :     Array1D<Real64> Q({0, FS.NL});
    6367           6 :     Array1D<Real64> H({0, FS.NL + 1});
    6368           6 :     Array1D<Real64> SOURCE(FS.NL + 1);
    6369             :     Real64 ISOL;
    6370             :     Real64 SHGC;
    6371             : 
    6372           6 :     CFSUFactor = false;
    6373           6 :     if (std::abs(TOUT - TIN) < 0.01) {
    6374           0 :         U = -1.0;
    6375           0 :         return CFSUFactor;
    6376             :     }
    6377             : 
    6378           6 :     TOABS = TOUT + Constant::Kelvin;
    6379           6 :     TRMOUT = TOABS;
    6380           6 :     TIABS = TIN + Constant::Kelvin;
    6381           6 :     TRMIN = TIABS;
    6382             : 
    6383           6 :     NL = FS.NL;
    6384           6 :     ISOL = 0.0; // no solar winter condition
    6385           6 :     SOURCE = 0.0;
    6386             : 
    6387           6 :     CFSUFactor = ASHWAT_ThermalRatings(
    6388          12 :         state, FS, TIABS, TOABS, HCIN, HCOUT, TRMOUT, TRMIN, ISOL, SOURCE({1, NL + 1}), TOL, QOCF, QOCFRoom, T, Q, JF, JB, H, U, SHGC, true);
    6389             : 
    6390           6 :     return CFSUFactor;
    6391           6 : }
    6392             : 
    6393        1401 : void ASHWAT_Solar(int const NL,                                 // # of layers
    6394             :                   Array1S<CFSSWP> const LSWP_ON,                // layer SW (solar) properties (off-normal adjusted)
    6395             :                   CFSSWP const &SWP_ROOM,                       // effective SW (solar) properties of room
    6396             :                   Real64 const IBEAM,                           // incident beam insolation (W/m2 aperture)
    6397             :                   Real64 const IDIFF,                           // incident diffuse insolation (W/m2 aperture)
    6398             :                   Real64 const ILIGHTS,                         // incident diffuse insolation (W/m2 aperture)
    6399             :                   Array1S<Real64> SOURCE,                       // returned: layer-by-layer flux of absorbed
    6400             :                   ObjexxFCL::Optional<Array1S<Real64>> SourceBD // returned: layer-by-layer flux of absorbed
    6401             : )
    6402             : {
    6403             :     // SUBROUTINE INFORMATION:
    6404             :     //       AUTHOR         JOHN L. WRIGHT and NATHAN KOTEY,
    6405             :     //       DATE WRITTEN   June, 2006
    6406             :     //       MODIFIED       Bereket Nigusse, JUNE 2013
    6407             :     //       RE-ENGINEERED  na
    6408             : 
    6409             :     // PURPOSE OF THIS SUBROUTINE:
    6410             :     // Returns the optical properties of multi-layer fenestration system model given optical
    6411             :     // properties of the layers
    6412             :     // METHODOLOGY EMPLOYED:
    6413             :     //    Ues combination net radiation method and TDMA solver
    6414             :     // REFERENCES:
    6415             :     //  JOHN L. WRIGHT and NATHAN KOTEY (2006). Solar Absorption By each Element in a Glazing/Shading
    6416             :     //   Layer Array, ASHRAE Transactions, Vol. 112, Pt. 2. pp. 3-12.
    6417             :     //   University of Waterloo, Mechanical Engineering
    6418             :     //   Advanced Glazing System Laboratory
    6419             : 
    6420             :     // SUBROUTINE ARGUMENT DEFINITIONS:
    6421             :     //   1=outside .. NL=inside
    6422             :     //   generally black or minimally reflective
    6423             :     //     on inside surface (e.g., from lights)
    6424             :     //  solar radiation (beam-beam + beam-diffuse) (W/m2)
    6425             :     // SOURCE(NL+1) is the flux of solar radiation
    6426             :     //  absorbed in conditioned space (W/m2 aperture area)
    6427             :     //  beam-diffuse solar radiation (W/m2)
    6428             :     // SOURCE_BD(NL+1) is the flux of beam-diffuse solar radiation
    6429             :     //  absorbed in conditioned space (W/m2 aperture area)
    6430             :     // or this beam-diffuse solar transmittance of the system
    6431             : 
    6432        1401 :     Array1D<Real64> BPLUS({0, NL}); // beam solar fluxes flowing in outward and inward directions
    6433        1401 :     Array1D<Real64> BMINUS({0, NL});
    6434             :     //   correspond to Edwards QPLUS and QMINUS (except note
    6435             :     //   reverse layer numbering)
    6436        1401 :     Array1D<Real64> CPLUS({0, NL}); // diffuse solar fluxes caused by BPLUS and BMINUS;
    6437        1401 :     Array1D<Real64> CMINUS({0, NL});
    6438             :     //   appear as sources in diffuse calculation
    6439        1401 :     Array1D<Real64> DPLUS({0, NL}); // diffuse solar fluxes flowing in outward and inward
    6440        1401 :     Array1D<Real64> DMINUS({0, NL});
    6441             :     //   directions (W/m2)
    6442        1401 :     Array1D<Real64> AP(2 * NL);
    6443        1401 :     Array1D<Real64> AE(2 * NL);
    6444        1401 :     Array1D<Real64> AW(2 * NL);
    6445        1401 :     Array1D<Real64> BP(2 * NL);
    6446        1401 :     Array1D<Real64> X(2 * NL);
    6447             :     Real64 CHKSUM;
    6448        1401 :     Array1D<Real64> BeamDiffuseAbs(NL + 1); // beam-diffuse absorbed fraction of beam radiation (W/m2)
    6449             :     int N_TDMA;
    6450             :     int I;
    6451             :     int LINE;
    6452             : 
    6453        1401 :     if (NL < 1) return;
    6454             : 
    6455             :     //  STEP ONE: THE BEAM-BEAM ANALYSIS TO FIND BPLUS AND BMINUS
    6456        1401 :     NETRAD(NL, LSWP_ON, SWP_ROOM.RHOSFBB, IBEAM, BPLUS, BMINUS);
    6457             : 
    6458             :     //  STEP TWO: CALCULATE THE DIFFUSE-CAUSED-BY-BEAM SOURCES CPLUS AND CMINUS
    6459        1401 :     CPLUS(NL) = SWP_ROOM.RHOSFBD * BMINUS(NL);
    6460        6342 :     for (I = NL; I >= 1; --I) { // March through layers, indoor to outdoor
    6461        4941 :         CPLUS(I - 1) = LSWP_ON(I).RHOSFBD * BMINUS(I - 1) + LSWP_ON(I).TAUSBBD * BPLUS(I);
    6462        4941 :         CMINUS(I) = LSWP_ON(I).RHOSBBD * BPLUS(I) + LSWP_ON(I).TAUSFBD * BMINUS(I - 1);
    6463             :     }
    6464        1401 :     CMINUS(0) = 0.0;
    6465             : 
    6466             :     //  STEP THREE: DIFFUSE FLUXES, DPLUS AND DMINUS,
    6467             :     //  CAUSED BY DIFFUSE INCIDENT, IDIFF ON THE OUTDOOR SIDE
    6468             :     //  AND BY ILIGHTS ON THE INDOOR SIDE, AND BY
    6469             :     //  DIFFUSE SOURCE (FROM BEAM) FLUXES, CPLUS AND CMINUS
    6470             : 
    6471        1401 :     N_TDMA = 2 * NL;
    6472             : 
    6473        6342 :     for (I = 1; I <= NL; ++I) {
    6474        4941 :         LINE = (2 * I) - 1;
    6475        4941 :         AP(LINE) = LSWP_ON(I).RHOSBDD;
    6476        4941 :         AE(LINE) = 1.0;
    6477        4941 :         if (LINE != 1) { // default
    6478        3540 :             AW(LINE) = -1.0 * LSWP_ON(I).TAUS_DD;
    6479        3540 :             BP(LINE) = -1.0 * CMINUS(I);
    6480             :         } else { //  special case at west-most node
    6481        1401 :             AW(1) = 0.0;
    6482        1401 :             BP(1) = -1.0 * LSWP_ON(1).TAUS_DD * IDIFF - CMINUS(1);
    6483             :         }
    6484             : 
    6485        4941 :         LINE = (2 * I);
    6486        4941 :         AW(LINE) = 1.0;
    6487        4941 :         if (LINE != N_TDMA) { // default
    6488        3540 :             AP(LINE) = LSWP_ON(I + 1).RHOSFDD;
    6489        3540 :             AE(LINE) = -1.0 * LSWP_ON(I + 1).TAUS_DD;
    6490        3540 :             BP(LINE) = -1.0 * CPLUS(I);
    6491             :         } else { //  special case at east-most node
    6492        1401 :             AP(LINE) = SWP_ROOM.RHOSFDD;
    6493        1401 :             BP(N_TDMA) = -1.0 * (CPLUS(NL) + ILIGHTS);
    6494        1401 :             AE(N_TDMA) = 0.0;
    6495             :         }
    6496             :     }
    6497             : 
    6498        1401 :     AUTOTDMA(X, AP, AE, AW, BP, N_TDMA);
    6499             : 
    6500             :     //   UNPACK TDMA SOLUTION VECTOR
    6501        6342 :     for (I = 1; I <= NL; ++I) {
    6502        4941 :         LINE = (2 * I) - 1;
    6503        4941 :         DPLUS(I) = X(LINE);
    6504        4941 :         LINE = (2 * I);
    6505        4941 :         DMINUS(I) = X(LINE);
    6506             :     }
    6507             : 
    6508             :     //  Finish up diffuse calculations
    6509        1401 :     DMINUS(0) = IDIFF;
    6510        1401 :     DPLUS(0) = LSWP_ON(1).RHOSFDD * DMINUS(0) + LSWP_ON(1).TAUS_DD * DPLUS(1) + CPLUS(0);
    6511             : 
    6512             :     //  STEP FOUR: ABSORBED SOLAR RADIATION AT EACH LAYER/NODE
    6513        1401 :     SOURCE = 0.0;
    6514        1401 :     SOURCE(NL + 1) = BMINUS(NL) - BPLUS(NL) + DMINUS(NL) - DPLUS(NL) + ILIGHTS; // SOLAR FLUX | TRANSMITTED TO | ROOM
    6515             : 
    6516             :     //  NOTE:  In calculating SOURCE(room) there is a trick included in the
    6517             :     //         previous line:  ILIGHTS is added because it is included
    6518             :     //         in DPLUS(NL) but ILIGHTS should not be included in this
    6519             :     //         type of calculation of SOURCE(i).  No similar adjustment
    6520             :     //         is needed for any of the other values of SOURCE(i)
    6521             :     //         As an alternative get the same result using:
    6522             :     //     SOURCE(NL+1) = BMINUS(NL)*(1.0 - SWP_ROOM%RHOSFBB - SWP_ROOM%RHOSFBD) +
    6523             :     //    &               DMINUS(NL)*(1.0 - SWP_ROOM%RHOSFDD)
    6524             :     //         Take your pick
    6525             : 
    6526             :     // Added by BAN, June 7, 2013 to extract the beam-diffuse component for use
    6527             :     // in the EnergyPLus heat balance.  EnergyPlus requires the beam-beam and
    6528             :     // Beam-diffuse components separately.
    6529        1401 :     BeamDiffuseAbs = 0.0;
    6530        1401 :     BeamDiffuseAbs(NL + 1) = DMINUS(NL) - DPLUS(NL); // beam-diffuse transmitted to the room
    6531        6342 :     for (I = 1; I <= NL; ++I) {
    6532        4941 :         SOURCE(I) = BPLUS(I) - BMINUS(I) - BPLUS(I - 1) + BMINUS(I - 1) + DPLUS(I) - DMINUS(I) - DPLUS(I - 1) + DMINUS(I - 1);
    6533             :         // Added by BAN June 7, 2013
    6534        4941 :         BeamDiffuseAbs(I) = 0.0;
    6535             :     }
    6536             : 
    6537        1401 :     if (present(SourceBD)) {
    6538        1389 :         SourceBD = BeamDiffuseAbs;
    6539             :     }
    6540             :     //  CHECKSUM - ALL INCOMING SOLAR FLUX MUST GO SOMEWHERE, SHOULD EQUAL ZERO
    6541        1401 :     CHKSUM = IBEAM + IDIFF + ILIGHTS - BPLUS(0) - DPLUS(0);
    6542        7743 :     for (I = 1; I <= NL + 1; ++I) {
    6543        6342 :         CHKSUM -= SOURCE(I);
    6544             :     }
    6545        1401 : }
    6546             : 
    6547        1401 : void NETRAD(int const NL,                  // # of layers, 1=outside .. NL=inside
    6548             :             Array1S<CFSSWP> const LSWP_ON, // layer SW (solar) properties (off-normal adjusted)
    6549             :             Real64 const RHO_room,         // effective solar reflectance of room (at inside)
    6550             :             Real64 const ISOL,             // incident flux (W/m2)
    6551             :             Array1D<Real64> &QPLUS,        // returned: see Edwards paper
    6552             :             Array1D<Real64> &QMINUS        // returned: see Edwards paper
    6553             : )
    6554             : {
    6555             :     // SUBROUTINE INFORMATION:
    6556             :     //       AUTHOR         JOHN L. WRIGHT
    6557             :     //       DATE WRITTEN   unknown
    6558             :     //       MODIFIED       na
    6559             :     //       RE-ENGINEERED  Autodesk:F2C++ Reworked to avoid complex member array usage
    6560             : 
    6561             :     // PURPOSE OF THIS SUBROUTINE:
    6562             :     // Returns the solar radiant fluxes between glazing layers
    6563             :     // METHODOLOGY EMPLOYED:
    6564             :     //  Net Radiation Method by LARGELY EDWARDS
    6565             :     //  TED, RED, QPLUS, QMINUS correspond to variables found in "Edwards"
    6566             :     //  but with reversed layers order indexing (layer 1=outside .. NL=inside)
    6567             :     //  GAP I is between layer I and I+1
    6568             : 
    6569        1401 :     if (NL < 1) return;
    6570             : 
    6571        1401 :     Array1D<Real64> TED(NL + 1);
    6572        1401 :     Array1D<Real64> RED(NL + 1);
    6573             : 
    6574             :     //   Reflectance and Transmittance
    6575             : 
    6576        1401 :     RED(NL + 1) = RHO_room;
    6577        1401 :     TED(NL + 1) = 0.0;
    6578        6342 :     for (int i = NL; i >= 1; --i) {
    6579        4941 :         CFSSWP const &LSWP_ON_i(LSWP_ON(i));
    6580        4941 :         TED(i) = LSWP_ON_i.TAUSFBB / max(0.00001, 1.0 - LSWP_ON_i.RHOSBBB * RED(i + 1));
    6581        4941 :         RED(i) = LSWP_ON_i.RHOSBBB + TED(i) * LSWP_ON_i.TAUSBBB * RED(i + 1);
    6582             :     }
    6583             : 
    6584             :     //   Outward and Inward Solar Fluxes, QPLUS AND QMINUS, Respectively
    6585        1401 :     QMINUS(0) = ISOL;
    6586        1401 :     QPLUS(0) = QMINUS(0) * RED(1);
    6587        6342 :     for (int i = 1; i <= NL; ++i) {
    6588        4941 :         QMINUS(i) = QMINUS(i - 1) * TED(i);
    6589        4941 :         QPLUS(i) = QMINUS(i) * RED(i + 1);
    6590             :     }
    6591        1401 : }
    6592             : 
    6593           0 : void TDMA_R(
    6594             :     Array1D<Real64> &X, const Array1D<Real64> &AP, const Array1D<Real64> &AE, const Array1D<Real64> &AW, const Array1D<Real64> &BP, int const N)
    6595             : {
    6596             :     // SUBROUTINE INFORMATION:
    6597             :     //       AUTHOR         JOHN L. WRIGHT
    6598             :     //       DATE WRITTEN   unknown
    6599             :     //       MODIFIED       na
    6600             :     //       RE-ENGINEERED  na
    6601             : 
    6602             :     // PURPOSE OF THIS SUBROUTINE:
    6603             :     // TDMA solver
    6604             :     // METHODOLOGY EMPLOYED:
    6605             :     //  1-D TDMA reverse solver. East/West sweep followed by West/East sweep
    6606             : 
    6607             :     int J;
    6608           0 :     Array1D<Real64> ALPHA(N);
    6609           0 :     Array1D<Real64> BETA(N);
    6610             : 
    6611           0 :     ALPHA(N) = AW(N) / AP(N);
    6612           0 :     BETA(N) = BP(N) / AP(N);
    6613             : 
    6614           0 :     for (J = N - 1; J >= 1; --J) {
    6615           0 :         ALPHA(J) = AW(J) / (AP(J) - (ALPHA(J + 1) * AE(J)));
    6616           0 :         BETA(J) = ((AE(J) * BETA(J + 1)) + BP(J)) / (AP(J) - (ALPHA(J + 1) * AE(J)));
    6617             :     }
    6618             : 
    6619           0 :     X(1) = BETA(1);
    6620           0 :     for (J = 2; J <= N; ++J) {
    6621           0 :         X(J) = (ALPHA(J) * X(J - 1)) + BETA(J);
    6622             :     }
    6623           0 : }
    6624             : 
    6625        1401 : void TDMA(Array1D<Real64> &X, const Array1D<Real64> &AP, const Array1D<Real64> &AE, const Array1D<Real64> &AW, const Array1D<Real64> &BP, int const N)
    6626             : {
    6627             :     // SUBROUTINE INFORMATION:
    6628             :     //       AUTHOR         JOHN L. WRIGHT
    6629             :     //       DATE WRITTEN   unknown
    6630             :     //       MODIFIED       na
    6631             :     //       RE-ENGINEERED  na
    6632             : 
    6633             :     // PURPOSE OF THIS SUBROUTINE:
    6634             :     // Matrix solver
    6635             :     // METHODOLOGY EMPLOYED:
    6636             :     //  1-D TDMA solver.
    6637             : 
    6638             :     int J;
    6639        1401 :     Array1D<Real64> ALPHA(N);
    6640        1401 :     Array1D<Real64> BETA(N);
    6641             :     Real64 D;
    6642             : 
    6643        1401 :     ALPHA(1) = AE(1) / AP(1);
    6644        1401 :     BETA(1) = BP(1) / AP(1);
    6645             : 
    6646        9882 :     for (J = 2; J <= N; ++J) {
    6647        8481 :         D = AP(J) - (ALPHA(J - 1) * AW(J));
    6648        8481 :         if (std::abs(D) < 0.0001) {
    6649           0 :             ALPHA(J) = 0.0;
    6650           0 :             BETA(J) = 0.0;
    6651             :         } else {
    6652        8481 :             ALPHA(J) = AE(J) / D;
    6653        8481 :             BETA(J) = ((AW(J) * BETA(J - 1)) + BP(J)) / D;
    6654             :         }
    6655             :     }
    6656             : 
    6657        1401 :     X(N) = BETA(N);
    6658        9882 :     for (J = N - 1; J >= 1; --J) {
    6659        8481 :         X(J) = (ALPHA(J) * X(J + 1)) + BETA(J);
    6660             :     }
    6661        1401 : }
    6662             : 
    6663        1401 : void AUTOTDMA(Array1D<Real64> &X, Array1D<Real64> &AP, const Array1D<Real64> &AE, const Array1D<Real64> &AW, const Array1D<Real64> &BP, int &N)
    6664             : {
    6665             :     // SUBROUTINE INFORMATION:
    6666             :     //       AUTHOR         JOHN L. WRIGHT
    6667             :     //       DATE WRITTEN   unknown
    6668             :     //       MODIFIED       na
    6669             :     //       RE-ENGINEERED  na
    6670             : 
    6671             :     // PURPOSE OF THIS SUBROUTINE:
    6672             :     // Matrix solver manager routine
    6673             :     // METHODOLOGY EMPLOYED:
    6674             :     //  1-D TDMA solver.
    6675             : 
    6676             :     //  Call TDMA for forward (i.e., west-to-east and back) calculation
    6677             :     //  or TDMA_R for reverse (i.e., east-to-west and back) calculation
    6678             :     //      TDMA   won't tolerate RHOSFxx(1)=0   (i.e., ap(1)=0)
    6679             :     //  but TDMA_R won't tolerate RHOSBxx(N-1)=0 (i.e., ap(n)=0)
    6680             :     //  where n-1 refers to the outdoor layer (glazing or shading layer)
    6681             : 
    6682             :     //  This if-statement will catch the situation where RHOSFxx(1)=0.
    6683             :     //  i.e., AP(1)=0.
    6684             : 
    6685        1401 :     if (AP(1) < AP(N)) {
    6686           0 :         TDMA_R(X, AP, AE, AW, BP, N);
    6687             :     } else {
    6688             :         //  This "fix" (on the next line) is only used as a last resort
    6689             :         //  The if-statement will catch the very unusual situation where both
    6690             :         //  RHOSBxx(N-1)=0.   AND     RHOSFxx(1)=0.
    6691        1401 :         if (AP(1) < 0.0001) AP(1) = 0.0001;
    6692        1401 :         TDMA(X, AP, AE, AW, BP, N);
    6693             :     }
    6694        1401 : }
    6695             : 
    6696        4897 : void ASHWAT_OffNormalProperties(EnergyPlusData &state,
    6697             :                                 CFSLAYER const &L,    // layer for which to derive off-normal properties
    6698             :                                 Real64 const THETA,   // solar beam angle of incidence, from normal, radians
    6699             :                                 Real64 const OMEGA_V, // solar beam vertical profile angle, +=above horizontal, radians
    6700             :                                 Real64 const OMEGA_H, // solar beam horizontal profile angle, +=clockwise when viewed
    6701             :                                 CFSSWP &LSWP_ON       // returned: off-normal properties
    6702             : )
    6703             : {
    6704             :     // SUBROUTINE INFORMATION:
    6705             :     //       AUTHOR         JOHN L. WRIGHT, University of Waterloo, Mechanical Engineering
    6706             :     //                      Advanced Glazing System Laboratory
    6707             :     //       DATE WRITTEN   unknown
    6708             :     //       MODIFIED       na
    6709             :     //       RE-ENGINEERED  na
    6710             : 
    6711             :     // PURPOSE OF THIS SUBROUTINE:
    6712             :     // Returns off-normal properties (total solar, beam-beam and beam diffuse) given
    6713             :     // direct-normal, total solar, beam-beam and beam diffuse properties of layers
    6714             : 
    6715             :     // SUBROUTINE ARGUMENT DEFINITIONS:
    6716             :     //   Used: LTYPE, SWP_EL, geometry
    6717             :     //   Note: not altered (return is in LSWP_ON)
    6718             :     //    0 <= THETA <= PI/2
    6719             :     //   = solar elevation angle for a vertical wall with
    6720             :     //     wall-solar azimuth angle equal to zero
    6721             :     //   from above (radians)
    6722             :     //   = wall-solar azimuth angle for a vertical wall
    6723             :     //     Used for PD and vertical VB
    6724             : 
    6725             :     bool OKAY;
    6726             : 
    6727        4897 :     LSWP_ON = L.SWP_EL; // init to normal properties
    6728             :     //  calls below modify in place
    6729             : 
    6730        4897 :     if (IsGlazeLayerX(L)) {
    6731             :         // specular glazing
    6732             :         // HBX note: ltyGZS here iff modelOption F=x; spectral cases elsewhere
    6733        3592 :         Specular_SWP(LSWP_ON, THETA);
    6734        1305 :     } else if (L.LTYPE == LayerType::VBHOR) {
    6735           0 :         OKAY = VB_SWP(state, L, LSWP_ON, OMEGA_V);
    6736        1305 :     } else if (L.LTYPE == LayerType::VBVER) {
    6737           0 :         OKAY = VB_SWP(state, L, LSWP_ON, OMEGA_H);
    6738        1305 :     } else if (L.LTYPE == LayerType::DRAPE) {
    6739           0 :         OKAY = PD_SWP(state, L, LSWP_ON, OMEGA_V, OMEGA_H);
    6740        1305 :     } else if (L.LTYPE == LayerType::ROLLB) {
    6741         898 :         OKAY = RB_SWP(state, L, LSWP_ON, THETA);
    6742         407 :     } else if (L.LTYPE == LayerType::INSCRN) {
    6743         407 :         OKAY = IS_SWP(state, L, LSWP_ON, THETA);
    6744           0 :     } else if (L.LTYPE == LayerType::NONE || L.LTYPE == LayerType::ROOM) {
    6745             :         // none or room: do nothing
    6746             :     } else {
    6747             :         // placeholder for add'l non-specular layers
    6748             :     }
    6749        4897 : }
    6750             : 
    6751        3592 : bool Specular_OffNormal(Real64 const THETA, // solar beam angle of incidence, from normal radians
    6752             :                         Real64 &RAT_1MR,    // returned: ratio of off-normal to normal solar (1-reflectance)
    6753             :                         Real64 &RAT_TAU     // returned: ratio of off-normal to normal solar transmittance
    6754             : )
    6755             : {
    6756             :     // FUNCTION INFORMATION:
    6757             :     //       AUTHOR         JOHN L. WRIGHT, University of Waterloo, Mechanical Engineering
    6758             :     //                      Advanced Glazing System Laboratory
    6759             :     //       DATE WRITTEN   unknown
    6760             :     //       MODIFIED       na
    6761             :     //       RE-ENGINEERED  na
    6762             : 
    6763             :     // PURPOSE OF THIS FUNCTION:
    6764             :     // Returns ratio of off-normal to normal of opetical properties.
    6765             :     // METHODOLOGY EMPLOYED:
    6766             :     //  Uses a reference glass property.
    6767             :     // returns TRUE if RAT_TAU < 1 or RAT_1MR < 1 (and thus Specular_Adjust s/b called)
    6768             :     //    else FALSE
    6769             :     // Return value
    6770             :     bool Specular_OffNormal;
    6771             : 
    6772             :     // FUNCTION ARGUMENT DEFINITIONS:
    6773             :     //    0 <= THETA <= PI/2
    6774             :     //   NOTE: rhoAdj = 1-(1-rho)*RAT_1MR
    6775             : 
    6776             :     Real64 TAU0;
    6777             :     Real64 RHO0;
    6778             :     Real64 THETA1;
    6779             :     Real64 THETA2;
    6780             :     Real64 TAU_ON;
    6781             :     Real64 RHO_ON;
    6782             :     Real64 TAU_A;
    6783             :     Real64 RPERP; // interface reflectance with respect to perpendicular
    6784             :     Real64 RPARL;
    6785             :     // and parallel polarization components of solar radiation
    6786             :     Real64 TAUPERP;
    6787             :     Real64 TAUPARL;
    6788             :     Real64 RHOPERP;
    6789             :     Real64 RHOPARL;
    6790             :     Real64 N2; // reference refractive index for generating general off-normal
    6791             :     //  curves for specular glazings
    6792             :     Real64 KL; // extinction coefficient - thickness product, also used as a
    6793             :     //  reference value to generate off-normal curves for specular layers
    6794             : 
    6795        3592 :     Specular_OffNormal = true;
    6796        3592 :     THETA1 = std::abs(THETA);
    6797        3592 :     if (THETA1 > Constant::PiOvr2 - Constant::DegToRadians) {
    6798             :         // theta > 89 deg
    6799          56 :         RAT_TAU = 0.0;
    6800          56 :         RAT_1MR = 0.0;
    6801        3536 :     } else if (THETA1 >= Constant::DegToRadians) {
    6802             :         // theta >= 1 deg
    6803        3528 :         N2 = 1.526;
    6804        3528 :         KL = 55.0 * 0.006;
    6805        3528 :         TAU_A = std::exp(-1.0 * KL);
    6806        3528 :         RPERP = pow_2((N2 - 1.0) / (N2 + 1.0));
    6807        3528 :         TAU0 = TAU_A * (1.0 - RPERP) * (1.0 - RPERP) / (1.0 - (RPERP * RPERP * TAU_A * TAU_A));
    6808        3528 :         RHO0 = RPERP * (1.0 + (TAU_A * TAU0));
    6809        3528 :         THETA2 = std::asin((std::sin(THETA1)) / N2);
    6810        3528 :         TAU_A = std::exp(-1.0 * KL / std::cos(THETA2));
    6811        3528 :         RPERP = pow_2(std::sin(THETA2 - THETA1) / std::sin(THETA2 + THETA1));
    6812        3528 :         RPARL = pow_2(std::tan(THETA2 - THETA1) / std::tan(THETA2 + THETA1));
    6813        3528 :         TAUPERP = TAU_A * (1.0 - RPERP) * (1.0 - RPERP) / (1.0 - (RPERP * RPERP * TAU_A * TAU_A));
    6814        3528 :         TAUPARL = TAU_A * (1.0 - RPARL) * (1.0 - RPARL) / (1.0 - (RPARL * RPARL * TAU_A * TAU_A));
    6815        3528 :         RHOPERP = RPERP * (1.0 + (TAU_A * TAUPERP));
    6816        3528 :         RHOPARL = RPARL * (1.0 + (TAU_A * TAUPARL));
    6817        3528 :         TAU_ON = (TAUPERP + TAUPARL) / 2.0;
    6818        3528 :         RHO_ON = (RHOPERP + RHOPARL) / 2.0;
    6819        3528 :         RAT_TAU = TAU_ON / TAU0;
    6820        3528 :         RAT_1MR = (1.0 - RHO_ON) / (1.0 - RHO0);
    6821             :     } else {
    6822           8 :         Specular_OffNormal = false;
    6823           8 :         RAT_TAU = 1.0;
    6824           8 :         RAT_1MR = 1.0;
    6825             :     }
    6826        3592 :     return Specular_OffNormal;
    6827             : }
    6828             : 
    6829        3592 : void Specular_SWP(CFSSWP &SWP,       // short wave properties (adjusted in place)
    6830             :                   Real64 const OMEGA // incident angle, radians
    6831             : )
    6832             : {
    6833             :     // SUBROUTINE INFORMATION:
    6834             :     //       AUTHOR         JOHN L. WRIGHT, University of Waterloo, Mechanical Engineering
    6835             :     //                      Advanced Glazing System Laboratory
    6836             :     //       DATE WRITTEN   unknown
    6837             :     //       MODIFIED       na
    6838             :     //       RE-ENGINEERED  na
    6839             : 
    6840             :     // PURPOSE OF THIS SUBROUTINE:
    6841             :     // Manages the off-normal solar properties calculation
    6842             : 
    6843             :     Real64 RAT_1MR; // adjustment factors, see Specular_OffNormal()
    6844             :     Real64 RAT_TAU; // adjustment factors, see Specular_OffNormal()
    6845             : 
    6846        3592 :     bool Specular_OffNormalReturn = Specular_OffNormal(OMEGA, RAT_1MR, RAT_TAU);
    6847        3592 :     if (Specular_OffNormalReturn) {
    6848        3584 :         Specular_Adjust(SWP, RAT_1MR, RAT_TAU);
    6849             :     }
    6850        3592 : }
    6851             : 
    6852        3584 : void Specular_Adjust(CFSSWP &SWP,          // short wave properties (adjusted in place)
    6853             :                      Real64 const RAT_1MR, // adjustment factors, see Specular_OffNormal()
    6854             :                      Real64 const RAT_TAU  // adjustment factors, see Specular_OffNormal()
    6855             : )
    6856             : {
    6857             :     // SUBROUTINE INFORMATION:
    6858             :     //       AUTHOR         JOHN L. WRIGHT, University of Waterloo, Mechanical Engineering
    6859             :     //                      Advanced Glazing System Laboratory
    6860             :     //       DATE WRITTEN   unknown
    6861             :     //       MODIFIED       na
    6862             :     //       RE-ENGINEERED  na
    6863             : 
    6864             :     // PURPOSE OF THIS SUBROUTINE:
    6865             :     // adjusts the off-normal solar properties
    6866             : 
    6867        3584 :     SWP.TAUSFBB *= RAT_TAU;
    6868        3584 :     SWP.TAUSBBB *= RAT_TAU;
    6869        3584 :     SWP.RHOSFBB = 1.0 - RAT_1MR * (1.0 - SWP.RHOSFBB);
    6870        3584 :     SWP.RHOSBBB = 1.0 - RAT_1MR * (1.0 - SWP.RHOSBBB);
    6871        3584 : }
    6872             : 
    6873           0 : void Specular_RATDiff(EnergyPlusData &state, Real64 &RAT_1MRDiff, Real64 &RAT_TAUDiff)
    6874             : {
    6875             :     // SUBROUTINE INFORMATION:
    6876             :     //       AUTHOR         JOHN L. WRIGHT, University of Waterloo, Mechanical Engineering
    6877             :     //                      Advanced Glazing System Laboratory
    6878             :     //       DATE WRITTEN   unknown
    6879             :     //       MODIFIED       na
    6880             :     //       RE-ENGINEERED  na
    6881             : 
    6882             :     // PURPOSE OF THIS SUBROUTINE:
    6883             :     //  Returns property ratios for estimating diffuse properties.
    6884             : 
    6885           0 :     Array1D<Real64> P(state.dataWindowEquivalentLayer->hipDIM);
    6886             : 
    6887           0 :     if (state.dataWindowEquivalentLayer->XTAUDiff < 0.0) {
    6888             :         // calculate and save on first call
    6889           0 :         state.dataWindowEquivalentLayer->X1MRDiff = HEMINT(state, Specular_F, state.dataWindowEquivalentLayer->hipRHO, P);
    6890           0 :         state.dataWindowEquivalentLayer->XTAUDiff = HEMINT(state, Specular_F, state.dataWindowEquivalentLayer->hipTAU, P);
    6891             :     }
    6892           0 :     RAT_TAUDiff = state.dataWindowEquivalentLayer->XTAUDiff;
    6893           0 :     RAT_1MRDiff = state.dataWindowEquivalentLayer->X1MRDiff;
    6894           0 : }
    6895             : 
    6896           0 : Real64 Specular_F(EnergyPlusData &state,
    6897             :                   Real64 const THETA,                       // incidence angle, radians
    6898             :                   int const OPT,                            // options (unused)
    6899             :                   [[maybe_unused]] const Array1D<Real64> &P // parameters (none defined)
    6900             : )
    6901             : {
    6902             :     // FUNCTION INFORMATION:
    6903             :     //       AUTHOR         JOHN L. WRIGHT, University of Waterloo, Mechanical Engineering
    6904             :     //                      Advanced Glazing System Laboratory
    6905             :     //       DATE WRITTEN   unknown
    6906             :     //       MODIFIED       na
    6907             :     //       RE-ENGINEERED  na
    6908             : 
    6909             :     // PURPOSE OF THIS FUNCTION:
    6910             :     // integrand fcn for specular properties.
    6911             : 
    6912             :     // Return value
    6913             :     Real64 Specular_F;
    6914             : 
    6915             :     // Argument array dimensioning
    6916             :     // EP_SIZE_CHECK(P, hipDIM);
    6917             : 
    6918             :     // FUNCTION ARGUMENT DEFINITIONS:
    6919             :     //   1: reflectance
    6920             :     //   2: transmittance
    6921             : 
    6922             :     Real64 RAT_TAU;
    6923             :     Real64 RAT_1MR;
    6924             : 
    6925             :     // Modified by BAN April 19, 2013
    6926           0 :     Specular_OffNormal(THETA, RAT_1MR, RAT_TAU);
    6927             : 
    6928           0 :     if (OPT == state.dataWindowEquivalentLayer->hipRHO) {
    6929           0 :         Specular_F = RAT_1MR;
    6930           0 :     } else if (OPT == state.dataWindowEquivalentLayer->hipTAU) {
    6931           0 :         Specular_F = RAT_TAU;
    6932             :     } else {
    6933           0 :         Specular_F = -1.0;
    6934             :     }
    6935           0 :     return Specular_F;
    6936             : }
    6937             : 
    6938           0 : void Specular_EstimateDiffuseProps(EnergyPlusData &state, CFSSWP &SWP) // short wave properties
    6939             : {
    6940             :     // SUBROUTINE INFORMATION:
    6941             :     //       AUTHOR         JOHN L. WRIGHT, University of Waterloo, Mechanical Engineering
    6942             :     //                      Advanced Glazing System Laboratory
    6943             :     //       DATE WRITTEN   unknown
    6944             :     //       MODIFIED       na
    6945             :     //       RE-ENGINEERED  na
    6946             : 
    6947             :     // PURPOSE OF THIS SUBROUTINE:
    6948             :     // Estimates diffuse-diffuse properties.
    6949             : 
    6950             :     Real64 RAT_TAU;
    6951             :     Real64 RAT_1MR;
    6952             : 
    6953             :     // #if 1
    6954           0 :     Specular_RATDiff(state, RAT_1MR, RAT_TAU);
    6955             :     // #else
    6956             :     //     ! estimate diffuse properties as 60 deg angle of incidence
    6957             :     //     CALL Specular_RAT60( RAT_TAU, RAT_1MR)
    6958             :     // #endif
    6959           0 :     SWP.TAUS_DD = RAT_TAU * SWP.TAUSFBB;
    6960           0 :     SWP.RHOSFDD = 1.0 - RAT_1MR * (1.0 - SWP.RHOSFBB);
    6961           0 :     SWP.RHOSBDD = 1.0 - RAT_1MR * (1.0 - SWP.RHOSBBB);
    6962           0 : }
    6963             : 
    6964           3 : bool RB_LWP(CFSLAYER const &L, // RB layer
    6965             :             CFSLWP &LLWP       // returned: equivalent layer long wave properties
    6966             : )
    6967             : {
    6968             :     // FUNCTION INFORMATION:
    6969             :     //       AUTHOR         ASHRAE 1311-RP
    6970             :     //       DATE WRITTEN   unknown
    6971             :     //       MODIFIED       na
    6972             :     //       RE-ENGINEERED  na
    6973             : 
    6974             :     // PURPOSE OF THIS FUNCTION:
    6975             :     // Modifies roller blind longwave properties. If not roller blind layer
    6976             :     // returns False.
    6977             : 
    6978             :     // Return value
    6979             :     bool RB_LWP;
    6980             : 
    6981             :     Real64 TAULX;
    6982             :     Real64 OPENNESS;
    6983             : 
    6984           3 :     RB_LWP = false;
    6985           3 :     if (L.LTYPE != LayerType::ROLLB) return RB_LWP;
    6986             : 
    6987           3 :     OPENNESS = L.SWP_MAT.TAUSFBB;
    6988             : 
    6989           3 :     OPENNESS_LW(OPENNESS, L.LWP_MAT.EPSLF, L.LWP_MAT.TAUL, LLWP.EPSLF, LLWP.TAUL);
    6990             : 
    6991           3 :     OPENNESS_LW(OPENNESS, L.LWP_MAT.EPSLB, L.LWP_MAT.TAUL, LLWP.EPSLB, TAULX);
    6992             : 
    6993           3 :     RB_LWP = true;
    6994           3 :     return RB_LWP;
    6995             : }
    6996             : 
    6997         901 : bool RB_SWP(EnergyPlusData &state,
    6998             :             CFSLAYER const &L, // RB layer
    6999             :             CFSSWP &LSWP,      // returned: equivalent layer properties set
    7000             :             const Real64 THETA // incident angle, 0 <= theta <= PI/2
    7001             : )
    7002             : {
    7003             :     // FUNCTION INFORMATION:
    7004             :     //       AUTHOR         ASHRAE 1311-RP
    7005             :     //       DATE WRITTEN   unknown
    7006             :     //       MODIFIED       Jason W. DeGraw 2023
    7007             :     //       RE-ENGINEERED  na
    7008             : 
    7009             :     // PURPOSE OF THIS FUNCTION:
    7010             :     //  Modifies roller blind shortwave properties. If not roller blind layer
    7011             :     //  returns False.
    7012             : 
    7013             :     // FUNCTION ARGUMENT DEFINITIONS:
    7014             :     //   sets ONLY RHOSFDD, RHOSBDD, TAUS_DD
    7015             :     //  if missing, derive diffuse properties
    7016             : 
    7017         901 :     if (L.LTYPE != LayerType::ROLLB) return false;
    7018             : 
    7019             :     // normal beam-total properties of fabric
    7020         901 :     Real64 RHOFF_BT0 = L.SWP_MAT.RHOSFBB + L.SWP_MAT.RHOSFBD; // front rho
    7021         901 :     Real64 RHOBF_BT0 = L.SWP_MAT.RHOSBBB + L.SWP_MAT.RHOSBBD; // back rho
    7022             : 
    7023         901 :     Real64 TAUFF_BT0 = L.SWP_MAT.TAUSFBB + L.SWP_MAT.TAUSFBD; // front tau
    7024         901 :     Real64 TAUBF_BT0 = L.SWP_MAT.TAUSBBB + L.SWP_MAT.TAUSBBD; // back tau
    7025             : 
    7026         901 :     RB_BEAM(state, THETA, RHOFF_BT0, TAUFF_BT0, L.SWP_MAT.TAUSFBB, LSWP.RHOSFBD, LSWP.TAUSFBB, LSWP.TAUSFBD);
    7027             : 
    7028         901 :     RB_BEAM(state, THETA, RHOBF_BT0, TAUBF_BT0, L.SWP_MAT.TAUSBBB, LSWP.RHOSBBD, LSWP.TAUSBBB, LSWP.TAUSBBD);
    7029             : 
    7030         901 :     return true;
    7031             : }
    7032             : 
    7033           3 : bool RB_SWP(EnergyPlusData &state,
    7034             :             CFSLAYER const &L, // RB layer
    7035             :             CFSSWP &LSWP       // returned: equivalent layer properties set
    7036             : )
    7037             : {
    7038             :     // FUNCTION INFORMATION:
    7039             :     //       AUTHOR         ASHRAE 1311-RP
    7040             :     //       DATE WRITTEN   unknown
    7041             :     //       MODIFIED       Jason W. DeGraw 2023
    7042             :     //       RE-ENGINEERED  na
    7043             : 
    7044             :     // PURPOSE OF THIS FUNCTION:
    7045             :     //  Modifies roller blind shortwave properties. If not roller blind layer
    7046             :     //  returns False.
    7047             : 
    7048             :     // FUNCTION ARGUMENT DEFINITIONS:
    7049             :     //   sets ONLY RHOSFDD, RHOSBDD, TAUS_DD
    7050             :     //  if missing, derive diffuse properties
    7051             : 
    7052           3 :     if (L.LTYPE != LayerType::ROLLB) return false;
    7053             : 
    7054             :     // normal beam-total properties of fabric
    7055           3 :     Real64 RHOFF_BT0 = L.SWP_MAT.RHOSFBB + L.SWP_MAT.RHOSFBD; // front rho
    7056           3 :     Real64 RHOBF_BT0 = L.SWP_MAT.RHOSBBB + L.SWP_MAT.RHOSBBD; // back rho
    7057             : 
    7058           3 :     Real64 TAUFF_BT0 = L.SWP_MAT.TAUSFBB + L.SWP_MAT.TAUSFBD; // front tau
    7059           3 :     Real64 TAUBF_BT0 = L.SWP_MAT.TAUSBBB + L.SWP_MAT.TAUSBBD; // back tau
    7060             : 
    7061             :     // front
    7062           3 :     RB_DIFF(state, RHOFF_BT0, TAUFF_BT0, L.SWP_MAT.TAUSFBB, LSWP.RHOSFDD, LSWP.TAUS_DD);
    7063             :     // back
    7064             :     Real64 TAUX; // This gets used as output of RB_DIFF and is then discarded
    7065           3 :     RB_DIFF(state, RHOBF_BT0, TAUBF_BT0, L.SWP_MAT.TAUSBBB, LSWP.RHOSBDD, TAUX);
    7066             : 
    7067           3 :     return true;
    7068             : }
    7069             : 
    7070           2 : bool IS_LWP(CFSLAYER const &L, // IS layer
    7071             :             CFSLWP &LLWP       // returned: equivalent layer long wave properties
    7072             : )
    7073             : {
    7074             :     // FUNCTION INFORMATION:
    7075             :     //       AUTHOR         ASHRAE 1311-RP
    7076             :     //       DATE WRITTEN   unknown
    7077             :     //       MODIFIED       na
    7078             :     //       RE-ENGINEERED  na
    7079             : 
    7080             :     // PURPOSE OF THIS FUNCTION:
    7081             :     //  Modifies Insect Screen longwave properties. If not Insect Screen layer
    7082             :     //  returns False.
    7083             : 
    7084             :     // Return value
    7085             :     bool IS_LWP;
    7086             : 
    7087             :     Real64 OPENNESS;
    7088             :     Real64 TAULX;
    7089             : 
    7090           2 :     IS_LWP = false;
    7091           2 :     if (L.LTYPE != LayerType::INSCRN) return IS_LWP;
    7092             : 
    7093           2 :     OPENNESS = L.SWP_MAT.TAUSFBB;
    7094             : 
    7095           2 :     OPENNESS_LW(OPENNESS, L.LWP_MAT.EPSLF, L.LWP_MAT.TAUL, LLWP.EPSLF, LLWP.TAUL);
    7096             : 
    7097           2 :     OPENNESS_LW(OPENNESS, L.LWP_MAT.EPSLB, L.LWP_MAT.TAUL, LLWP.EPSLB, TAULX);
    7098           2 :     IS_LWP = true;
    7099           2 :     return IS_LWP;
    7100             : }
    7101             : 
    7102         409 : bool IS_SWP(EnergyPlusData &state,
    7103             :             CFSLAYER const &L, // PD layer
    7104             :             CFSSWP &LSWP,      // returned: equivalent layer properties set
    7105             :             const Real64 THETA // incident angle, 0 <= theta <= PI/2
    7106             : )
    7107             : {
    7108             :     // FUNCTION INFORMATION:
    7109             :     //       AUTHOR         ASHRAE 1311-RP
    7110             :     //       DATE WRITTEN   unknown
    7111             :     //       MODIFIED       Jason W. DeGraw 2023
    7112             :     //       RE-ENGINEERED  na
    7113             : 
    7114             :     // PURPOSE OF THIS FUNCTION:
    7115             :     // Modifies Insect Screen shortwave properties. If not Insect Screen layer
    7116             :     // returns False.
    7117             : 
    7118             :     // FUNCTION ARGUMENT DEFINITIONS:
    7119             :     //   sets ONLY RHOSFDD, RHOSBDD, TAUS_DD
    7120             :     //  if missing, derive diffuse properties
    7121             : 
    7122         409 :     if (L.LTYPE != LayerType::INSCRN) return false;
    7123             : 
    7124             :     // normal beam-total properties
    7125         409 :     Real64 RHOFF_BT0 = L.SWP_MAT.RHOSFBB + L.SWP_MAT.RHOSFBD; // front rho
    7126         409 :     Real64 RHOBF_BT0 = L.SWP_MAT.RHOSBBB + L.SWP_MAT.RHOSBBD; // back rho
    7127             : 
    7128         409 :     Real64 TAUFF_BT0 = L.SWP_MAT.TAUSFBB + L.SWP_MAT.TAUSFBD; // front tau
    7129         409 :     Real64 TAUBF_BT0 = L.SWP_MAT.TAUSBBB + L.SWP_MAT.TAUSBBD; // back tau
    7130             : 
    7131             :     // front
    7132         409 :     IS_BEAM(state, THETA, RHOFF_BT0, TAUFF_BT0, L.SWP_MAT.TAUSFBB, LSWP.RHOSFBD, LSWP.TAUSFBB, LSWP.TAUSFBD);
    7133             : 
    7134             :     // back -- call with reverse material properies
    7135         409 :     IS_BEAM(state, THETA, RHOBF_BT0, TAUBF_BT0, L.SWP_MAT.TAUSBBB, LSWP.RHOSBBD, LSWP.TAUSBBB, LSWP.TAUSBBD);
    7136             : 
    7137         409 :     return true;
    7138             : }
    7139             : 
    7140           2 : bool IS_SWP(EnergyPlusData &state,
    7141             :             CFSLAYER const &L, // PD layer
    7142             :             CFSSWP &LSWP       // returned: equivalent layer properties set
    7143             : )
    7144             : {
    7145             :     // FUNCTION INFORMATION:
    7146             :     //       AUTHOR         ASHRAE 1311-RP
    7147             :     //       DATE WRITTEN   unknown
    7148             :     //       MODIFIED       Jason W. DeGraw 2023
    7149             :     //       RE-ENGINEERED  na
    7150             : 
    7151             :     // PURPOSE OF THIS FUNCTION:
    7152             :     // Modifies Insect Screen shortwave properties. If not Insect Screen layer
    7153             :     // returns False.
    7154             : 
    7155             :     // FUNCTION ARGUMENT DEFINITIONS:
    7156             :     //   sets ONLY RHOSFDD, RHOSBDD, TAUS_DD
    7157             :     //  if missing, derive diffuse properties
    7158             : 
    7159           2 :     if (L.LTYPE != LayerType::INSCRN) return false;
    7160             : 
    7161             :     // normal beam-total properties
    7162           2 :     Real64 RHOFF_BT0 = L.SWP_MAT.RHOSFBB + L.SWP_MAT.RHOSFBD; // front rho
    7163           2 :     Real64 RHOBF_BT0 = L.SWP_MAT.RHOSBBB + L.SWP_MAT.RHOSBBD; // back rho
    7164             : 
    7165           2 :     Real64 TAUFF_BT0 = L.SWP_MAT.TAUSFBB + L.SWP_MAT.TAUSFBD; // front tau
    7166           2 :     Real64 TAUBF_BT0 = L.SWP_MAT.TAUSBBB + L.SWP_MAT.TAUSBBD; // back tau
    7167             : 
    7168             :     // front
    7169           2 :     IS_DIFF(state, RHOFF_BT0, TAUFF_BT0, L.SWP_MAT.TAUSFBB, LSWP.RHOSFDD, LSWP.TAUS_DD);
    7170             :     // back
    7171             :     Real64 TAUX; // This gets used as output of IS_DIFF and is then discarded
    7172           2 :     IS_DIFF(state, RHOBF_BT0, TAUBF_BT0, L.SWP_MAT.TAUSBBB, LSWP.RHOSBDD, TAUX);
    7173             : 
    7174           2 :     return true;
    7175             : }
    7176             : 
    7177           0 : void Fabric_EstimateDiffuseProps(EnergyPlusData &state, CFSSWP &SWP) // fabric short wave properties
    7178             : {
    7179             :     // SUBROUTINE INFORMATION:
    7180             :     //       AUTHOR         JOHN L. WRIGHT, University of Waterloo, Mechanical Engineering
    7181             :     //                      Advanced Glazing System Laboratory
    7182             :     //       DATE WRITTEN   unknown
    7183             :     //       MODIFIED       na
    7184             :     //       RE-ENGINEERED  na
    7185             : 
    7186             :     // PURPOSE OF THIS SUBROUTINE:
    7187             :     // Estimates diffuse properties of drape fabrics.
    7188             :     // sets RHOSFDD, RHOSBDD, TAUS_DD
    7189             : 
    7190             :     Real64 RHOBF_BT0; // total back reflectance
    7191             :     Real64 RHOFF_BT0; // total front reflectance
    7192             :     Real64 TAUBF_BT0; // total back transmittance
    7193             :     Real64 TAUFF_BT0; // total front transmittance
    7194             :     Real64 TAUX;
    7195             : 
    7196           0 :     RHOFF_BT0 = SWP.RHOSFBB + SWP.RHOSFBD; // front rho
    7197           0 :     RHOBF_BT0 = SWP.RHOSBBB + SWP.RHOSBBD; // back rho
    7198           0 :     TAUFF_BT0 = SWP.TAUSFBB + SWP.TAUSFBD; // front tau
    7199           0 :     TAUBF_BT0 = SWP.TAUSBBB + SWP.TAUSBBD; // back tau
    7200           0 :     FM_DIFF(state, RHOFF_BT0, TAUFF_BT0, SWP.TAUSFBB, SWP.RHOSFDD, SWP.TAUS_DD);
    7201           0 :     FM_DIFF(state, RHOBF_BT0, TAUBF_BT0, SWP.TAUSBBB, SWP.RHOSBDD, TAUX);
    7202           0 : }
    7203             : 
    7204           0 : bool PD_LWP(EnergyPlusData &state,
    7205             :             CFSLAYER const &L, // PD layer
    7206             :             CFSLWP &LLWP       // returned: equivalent layer long wave properties
    7207             : )
    7208             : {
    7209             :     // FUNCTION INFORMATION:
    7210             :     //       AUTHOR         ASHRAE 1311-RP
    7211             :     //       DATE WRITTEN   unknown
    7212             :     //       MODIFIED       na
    7213             :     //       RE-ENGINEERED  na
    7214             : 
    7215             :     // PURPOSE OF THIS FUNCTION:
    7216             :     //  Modifies Drape longwave properties for openness. If not Drape Fabric layer
    7217             :     //  returns False.
    7218             : 
    7219             :     // Return value
    7220             :     bool PD_LWP;
    7221             : 
    7222             :     Real64 TAULX;
    7223             :     Real64 OPENNESS_FABRIC;
    7224             : 
    7225           0 :     PD_LWP = false;
    7226           0 :     if (L.LTYPE != LayerType::DRAPE) return PD_LWP;
    7227             : 
    7228           0 :     OPENNESS_FABRIC = L.SWP_MAT.TAUSFBB;
    7229             : 
    7230           0 :     PD_LW(state, L.S, L.W, OPENNESS_FABRIC, L.LWP_MAT.EPSLF, L.LWP_MAT.EPSLB, L.LWP_MAT.TAUL, LLWP.EPSLF, LLWP.TAUL);
    7231             : 
    7232           0 :     PD_LW(state, L.S, L.W, OPENNESS_FABRIC, L.LWP_MAT.EPSLB, L.LWP_MAT.EPSLF, L.LWP_MAT.TAUL, LLWP.EPSLB, TAULX);
    7233             : 
    7234           0 :     PD_LWP = true;
    7235           0 :     return PD_LWP;
    7236             : }
    7237             : 
    7238           0 : bool PD_SWP(EnergyPlusData &state,
    7239             :             CFSLAYER const &L,      // PD layer
    7240             :             CFSSWP &LSWP,           // returned: equivalent layer properties set
    7241             :             const Real64 OHM_V_RAD, // vertical VB profile angles, radians
    7242             :             const Real64 OHM_H_RAD  // horizonatl VB profile angles, radians
    7243             : )
    7244             : {
    7245             :     // FUNCTION INFORMATION:
    7246             :     //       AUTHOR         ASHRAE 1311-RP
    7247             :     //       DATE WRITTEN   unknown
    7248             :     //       MODIFIED       Jason W. DeGraw 2023
    7249             :     //       RE-ENGINEERED  na
    7250             : 
    7251             :     // PURPOSE OF THIS FUNCTION:
    7252             :     // Modifies drape fabric shortwave properties for openness. If not drape Fabric layer
    7253             :     // returns false. If profile angles not specified diffuse properties are returned.
    7254             : 
    7255           0 :     if (!(L.LTYPE == LayerType::DRAPE)) return false;
    7256             : 
    7257             :     // normal beam-total properties of fabric
    7258           0 :     Real64 RHOFF_BT0 = L.SWP_MAT.RHOSFBB + L.SWP_MAT.RHOSFBD; // front rho
    7259           0 :     Real64 RHOBF_BT0 = L.SWP_MAT.RHOSBBB + L.SWP_MAT.RHOSBBD; // back rho
    7260             : 
    7261             :     // drape front properties
    7262           0 :     PD_BEAM(state,
    7263           0 :             L.S,
    7264           0 :             L.W,
    7265             :             OHM_V_RAD,
    7266             :             OHM_H_RAD,
    7267             :             RHOFF_BT0,
    7268           0 :             L.SWP_MAT.TAUSFBB,
    7269           0 :             L.SWP_MAT.TAUSFBD,
    7270           0 :             L.SWP_MAT.RHOSFDD,
    7271           0 :             L.SWP_MAT.TAUS_DD,
    7272             :             RHOBF_BT0,
    7273           0 :             L.SWP_MAT.TAUSBBB,
    7274           0 :             L.SWP_MAT.TAUSBBD,
    7275           0 :             L.SWP_MAT.RHOSBDD,
    7276           0 :             L.SWP_MAT.TAUS_DD,
    7277           0 :             LSWP.RHOSFBD,
    7278           0 :             LSWP.TAUSFBB,
    7279           0 :             LSWP.TAUSFBD);
    7280             : 
    7281             :     // drape back properties: call with reversed fabric properies
    7282           0 :     PD_BEAM(state,
    7283           0 :             L.S,
    7284           0 :             L.W,
    7285             :             OHM_V_RAD,
    7286             :             OHM_H_RAD,
    7287             :             RHOBF_BT0,
    7288           0 :             L.SWP_MAT.TAUSBBB,
    7289           0 :             L.SWP_MAT.TAUSBBD,
    7290           0 :             L.SWP_MAT.RHOSBDD,
    7291           0 :             L.SWP_MAT.TAUS_DD,
    7292             :             RHOFF_BT0,
    7293           0 :             L.SWP_MAT.TAUSFBB,
    7294           0 :             L.SWP_MAT.TAUSFBD,
    7295           0 :             L.SWP_MAT.RHOSFDD,
    7296           0 :             L.SWP_MAT.TAUS_DD,
    7297           0 :             LSWP.RHOSBBD,
    7298           0 :             LSWP.TAUSBBB,
    7299           0 :             LSWP.TAUSBBD);
    7300             : 
    7301           0 :     return true;
    7302             : }
    7303             : 
    7304           0 : bool PD_SWP(EnergyPlusData &state,
    7305             :             CFSLAYER const &L, // PD layer
    7306             :             CFSSWP &LSWP       // returned: equivalent layer properties set
    7307             : )
    7308             : {
    7309             :     // FUNCTION INFORMATION:
    7310             :     //       AUTHOR         ASHRAE 1311-RP
    7311             :     //       DATE WRITTEN   unknown
    7312             :     //       MODIFIED       Jason W. DeGraw
    7313             :     //       RE-ENGINEERED  na
    7314             : 
    7315             :     // PURPOSE OF THIS FUNCTION:
    7316             :     // Modifies drape fabric shortwave properties for openness. If not drape Fabric layer
    7317             :     // returns false. If profile angles not specified diffuse properties are returned.
    7318             : 
    7319             :     Real64 TAUX; // This gets used as output of PD_DIFF and is then discarded
    7320             : 
    7321           0 :     if (!(L.LTYPE == LayerType::DRAPE)) return false;
    7322             : 
    7323           0 :     PD_DIFF(state, L.S, L.W, L.SWP_MAT.RHOSFDD, L.SWP_MAT.RHOSBDD, L.SWP_MAT.TAUS_DD, LSWP.RHOSFDD, LSWP.TAUS_DD);
    7324             : 
    7325           0 :     PD_DIFF(state, L.S, L.W, L.SWP_MAT.RHOSBDD, L.SWP_MAT.RHOSFDD, L.SWP_MAT.TAUS_DD, LSWP.RHOSBDD, TAUX);
    7326             : 
    7327           0 :     return true;
    7328             : }
    7329             : 
    7330           0 : bool VB_LWP(EnergyPlusData &state,
    7331             :             CFSLAYER const &L, // VB layer
    7332             :             CFSLWP &LLWP       // returned: equivalent layer long wave properties
    7333             : )
    7334             : {
    7335             :     // FUNCTION INFORMATION:
    7336             :     //       AUTHOR         ASHRAE 1311-RP
    7337             :     //       DATE WRITTEN   unknown
    7338             :     //       MODIFIED       na
    7339             :     //       RE-ENGINEERED  na
    7340             : 
    7341             :     // PURPOSE OF THIS FUNCTION:
    7342             :     // Return venetian blind longwave properties from slat properties and geometry.
    7343             :     // If not VB layer returns False.
    7344             : 
    7345             :     // Return value
    7346             :     bool VB_LWP;
    7347             : 
    7348             :     Real64 RHODFS_SLAT;
    7349             :     Real64 RHOUFS_SLAT;
    7350             :     Real64 RHOLF;
    7351             :     Real64 RHOLB;
    7352             :     Real64 TAULX;
    7353             : 
    7354           0 :     VB_LWP = false;
    7355           0 :     if (!IsVBLayer(L)) return VB_LWP;
    7356             : 
    7357             :     // slat reflectances
    7358           0 :     RHODFS_SLAT = 1.0 - L.LWP_MAT.EPSLB - L.LWP_MAT.TAUL; // downward surface
    7359           0 :     RHOUFS_SLAT = 1.0 - L.LWP_MAT.EPSLF - L.LWP_MAT.TAUL; // upward surface
    7360             : 
    7361             :     // TODO: are there cases where 2 calls not needed (RHODFS_SLAT == RHOUFS_SLAT??)
    7362           0 :     VB_DIFF(state, L.S, L.W, Constant::DegToRadians * L.PHI_DEG, RHODFS_SLAT, RHOUFS_SLAT, L.LWP_MAT.TAUL, RHOLF, LLWP.TAUL);
    7363           0 :     LLWP.EPSLF = 1.0 - RHOLF - LLWP.TAUL;
    7364             : 
    7365           0 :     VB_DIFF(state, L.S, L.W, -Constant::DegToRadians * L.PHI_DEG, RHODFS_SLAT, RHOUFS_SLAT, L.LWP_MAT.TAUL, RHOLB, TAULX);
    7366           0 :     LLWP.EPSLB = 1.0 - RHOLB - LLWP.TAUL;
    7367             : 
    7368           0 :     VB_LWP = true;
    7369           0 :     return VB_LWP;
    7370             : }
    7371             : 
    7372           0 : bool VB_SWP(EnergyPlusData &state,
    7373             :             CFSLAYER const &L, // VB layer
    7374             :             CFSSWP &LSWP,      // returned: equivalent off-normal properties
    7375             :             const Real64 OMEGA // incident profile angle (radians)
    7376             : )
    7377             : {
    7378             :     // FUNCTION INFORMATION:
    7379             :     //       AUTHOR         ASHRAE 1311-RP
    7380             :     //       DATE WRITTEN   unknown
    7381             :     //       MODIFIED       Jason W. DeGraw
    7382             :     //       RE-ENGINEERED  na
    7383             : 
    7384             :     // PURPOSE OF THIS FUNCTION:
    7385             :     // Returns venetian blind off-normal short wave properties. If not VB layer
    7386             :     // returns False.
    7387             : 
    7388             :     // FUNCTION ARGUMENT DEFINITIONS:
    7389             :     //   sets: RHOSFBD, TAUSFBB, TAUSFBD
    7390             : 
    7391           0 :     if (!IsVBLayer(L)) return false;
    7392             : 
    7393           0 :     Real64 SL_WR = VB_SLAT_RADIUS_RATIO(L.W, L.C);
    7394             : 
    7395             :     // modify angle-dependent values for actual profile angle
    7396           0 :     VB_SOL46_CURVE(state,
    7397           0 :                    L.S,
    7398           0 :                    L.W,
    7399             :                    SL_WR,
    7400           0 :                    Constant::DegToRadians * L.PHI_DEG,
    7401             :                    OMEGA,
    7402           0 :                    L.SWP_MAT.RHOSBDD,
    7403           0 :                    L.SWP_MAT.RHOSFDD,
    7404           0 :                    L.SWP_MAT.TAUS_DD,
    7405           0 :                    LSWP.RHOSFBD,
    7406           0 :                    LSWP.TAUSFBB,
    7407           0 :                    LSWP.TAUSFBD);
    7408             : 
    7409           0 :     VB_SOL46_CURVE(state,
    7410           0 :                    L.S,
    7411           0 :                    L.W,
    7412             :                    SL_WR,
    7413           0 :                    -Constant::DegToRadians * L.PHI_DEG,
    7414             :                    OMEGA,
    7415           0 :                    L.SWP_MAT.RHOSBDD,
    7416           0 :                    L.SWP_MAT.RHOSFDD,
    7417           0 :                    L.SWP_MAT.TAUS_DD,
    7418           0 :                    LSWP.RHOSBBD,
    7419           0 :                    LSWP.TAUSBBB,
    7420           0 :                    LSWP.TAUSBBD);
    7421             : 
    7422           0 :     return true;
    7423             : }
    7424             : 
    7425           0 : bool VB_SWP(EnergyPlusData &state,
    7426             :             CFSLAYER const &L, // VB layer
    7427             :             CFSSWP &LSWP       // returned: equivalent off-normal properties
    7428             : )
    7429             : {
    7430             :     // FUNCTION INFORMATION:
    7431             :     //       AUTHOR         ASHRAE 1311-RP
    7432             :     //       DATE WRITTEN   unknown
    7433             :     //       MODIFIED       Jason W. DeGraw
    7434             :     //       RE-ENGINEERED  na
    7435             : 
    7436             :     // PURPOSE OF THIS FUNCTION:
    7437             :     // Returns venetian blind off-normal short wave properties. If not VB layer
    7438             :     // returns False.
    7439             : 
    7440             :     // FUNCTION ARGUMENT DEFINITIONS:
    7441             :     //   sets: RHOSFBD, TAUSFBB, TAUSFBD
    7442             : 
    7443             :     Real64 SL_WR;
    7444             :     Real64 TAUX; // This gets used as output of VB_DIFF and is then discarded
    7445             : 
    7446           0 :     if (!IsVBLayer(L)) return false;
    7447             : 
    7448           0 :     SL_WR = VB_SLAT_RADIUS_RATIO(L.W, L.C);
    7449             : 
    7450           0 :     VB_DIFF(state, L.S, L.W, Constant::DegToRadians * L.PHI_DEG, L.SWP_MAT.RHOSBDD, L.SWP_MAT.RHOSFDD, L.SWP_MAT.TAUS_DD, LSWP.RHOSFDD, LSWP.TAUS_DD);
    7451             : 
    7452           0 :     VB_DIFF(state, L.S, L.W, -Constant::DegToRadians * L.PHI_DEG, L.SWP_MAT.RHOSBDD, L.SWP_MAT.RHOSFDD, L.SWP_MAT.TAUS_DD, LSWP.RHOSBDD, TAUX);
    7453             : 
    7454           0 :     return true;
    7455             : }
    7456             : 
    7457           0 : bool VB_ShadeControl(EnergyPlusData &state,
    7458             :                      CFSLAYER &L,           // VB layer
    7459             :                      Real64 const OMEGA_DEG // incident profile angle (degrees)
    7460             : )
    7461             : {
    7462             :     // FUNCTION INFORMATION:
    7463             :     //       AUTHOR         ASHRAE 1311-RP
    7464             :     //       DATE WRITTEN   unknown
    7465             :     //       MODIFIED       na
    7466             :     //       RE-ENGINEERED  na
    7467             : 
    7468             :     // PURPOSE OF THIS FUNCTION:
    7469             :     //  Modifies slat angle if shade control is true. If not uses the fixed
    7470             :     //  slate angle and returns false.
    7471             : 
    7472             :     // Return value
    7473             :     bool VB_ShadeControl;
    7474             : 
    7475             :     // FUNCTION ARGUMENT DEFINITIONS:
    7476             :     //   see comments elsewhere re sign convention
    7477             :     //   < 0 = diffuse
    7478             : 
    7479             :     Real64 SLATA;
    7480             : 
    7481           0 :     SLATA = L.PHI_DEG;
    7482             : 
    7483           0 :     if (L.CNTRL == state.dataWindowEquivalentLayer->lscVBPROF) {
    7484             :         // slatA = profA (max gain)
    7485           0 :         if (OMEGA_DEG < 0.0) {
    7486           0 :             SLATA = -30.0;
    7487             :         } else {
    7488           0 :             SLATA = -OMEGA_DEG;
    7489             :         }
    7490           0 :     } else if (L.CNTRL == state.dataWindowEquivalentLayer->lscVBNOBM) {
    7491             :         // slatA set to just exclude beam
    7492           0 :         if (OMEGA_DEG < 0.0) {
    7493           0 :             SLATA = VB_CriticalSlatAngle(30.0); // assume 30 deg for diffuse
    7494             :         } else {
    7495           0 :             SLATA = VB_CriticalSlatAngle(OMEGA_DEG);
    7496             :         }
    7497             :     }
    7498             : 
    7499           0 :     VB_ShadeControl = std::abs(SLATA - L.PHI_DEG) > 0.01;
    7500           0 :     if (VB_ShadeControl) {
    7501           0 :         L.PHI_DEG = SLATA;
    7502             :     }
    7503           0 :     return VB_ShadeControl;
    7504             : }
    7505             : 
    7506           0 : Real64 VB_CriticalSlatAngle(Real64 const OMEGA_DEG // incident profile angle (degrees)
    7507             : )
    7508             : {
    7509             :     // FUNCTION INFORMATION:
    7510             :     //       AUTHOR         JOHN L. WRIGHT, University of Waterloo, Mechanical Engineering
    7511             :     //                      Advanced Glazing System Laboratory
    7512             :     //       DATE WRITTEN   unknown
    7513             :     //       MODIFIED       na
    7514             :     //       RE-ENGINEERED  na
    7515             : 
    7516             :     // PURPOSE OF THIS FUNCTION:
    7517             :     // Returns slat angle that just excludes beam radiation.
    7518             : 
    7519             :     // Return value
    7520             :     Real64 VB_CriticalSlatAngle;
    7521             : 
    7522             :     // TODO handle vert blind cases etc
    7523             :     // the slat normal points along the profile angle to block the beam solar
    7524           0 :     VB_CriticalSlatAngle = 90.0 - OMEGA_DEG; //
    7525             : 
    7526           0 :     return VB_CriticalSlatAngle;
    7527             : }
    7528             : 
    7529           0 : bool DoShadeControl(EnergyPlusData &state,
    7530             :                     CFSLAYER &L,          // layer (returned updated)
    7531             :                     Real64 const THETA,   // solar beam angle of incidence, from normal, (radians)
    7532             :                     Real64 const OMEGA_V, // solar beam vertical profile angle, +=above horizontal (radians)
    7533             :                     Real64 const OMEGA_H  // solar beam horizontal profile angle, +=clockwise when viewed
    7534             : )
    7535             : {
    7536             :     // FUNCTION INFORMATION:
    7537             :     //       AUTHOR         JOHN L. WRIGHT, University of Waterloo, Mechanical Engineering
    7538             :     //                      Advanced Glazing System Laboratory
    7539             :     //       DATE WRITTEN   unknown
    7540             :     //       MODIFIED       na
    7541             :     //       RE-ENGINEERED  na
    7542             : 
    7543             :     // PURPOSE OF THIS FUNCTION:
    7544             :     // Returns .TRUE. if L is modified for shade control.
    7545             : 
    7546             :     // Return value
    7547             :     bool DoShadeControl;
    7548             : 
    7549             :     // FUNCTION ARGUMENT DEFINITIONS:
    7550             :     // 0 <= THETA <= PI/2
    7551             :     //   = solar elevation angle for a vertical wall with
    7552             :     //     wall-solar azimuth angle equal to zero
    7553             :     //   from above (radians)
    7554             :     //   = wall-solar azimuth angle for a vertical wall
    7555             :     //     Used for PD and vertical VB
    7556             : 
    7557             :     Real64 OMEGA_DEG; // controlling profile angel, degrees
    7558             : 
    7559           0 :     DoShadeControl = false; // default: no shade controls implemented
    7560             : 
    7561             :     // must be consistent with IsControlledShade()
    7562           0 :     if (IsVBLayer(L) && L.CNTRL != state.dataWindowEquivalentLayer->lscNONE) {
    7563           0 :         if (THETA < 0.0 || THETA >= Constant::PiOvr2) {
    7564           0 :             OMEGA_DEG = -1.0; // diffuse only
    7565           0 :         } else if (L.LTYPE == LayerType::VBHOR) {
    7566             :             // horiz VB
    7567           0 :             OMEGA_DEG = state.dataWindowEquivalentLayer->RadiansToDeg * OMEGA_V;
    7568             :         } else {
    7569             :             // vert VB
    7570           0 :             OMEGA_DEG = state.dataWindowEquivalentLayer->RadiansToDeg * OMEGA_H;
    7571             :         }
    7572           0 :         if (VB_ShadeControl(state, L, OMEGA_DEG)) {
    7573           0 :             FinalizeCFSLAYER(state, L);
    7574           0 :             DoShadeControl = true;
    7575             :         }
    7576             :     }
    7577           0 :     return DoShadeControl;
    7578             : }
    7579             : 
    7580          19 : void FinalizeCFSLAYER(EnergyPlusData &state, CFSLAYER &L) // layer, input: LTYPE, LWP_MAT, SWP_MAT
    7581             : {
    7582             :     // SUBROUTINE INFORMATION:
    7583             :     //       AUTHOR         JOHN L. WRIGHT, University of Waterloo, Mechanical Engineering
    7584             :     //                      Advanced Glazing System Laboratory
    7585             :     //       DATE WRITTEN   unknown
    7586             :     //       MODIFIED       na
    7587             :     //       RE-ENGINEERED  na
    7588             :     // PURPOSE OF THIS SUBROUTINE:
    7589             :     //  Sets equivalent layer properties of a construction.
    7590             : 
    7591             :     // SUBROUTINE ARGUMENT DEFINITIONS:
    7592             :     //          geometry (per LTYPE)
    7593             :     //   output: LWP_EL, SWP_EL
    7594             : 
    7595             :     bool LOK;
    7596             :     bool DOK;
    7597             :     bool BOK;
    7598             :     bool CFSLAYERFlag;
    7599             : 
    7600          19 :     LOK = false;
    7601          19 :     DOK = false;
    7602          19 :     BOK = false;
    7603             : 
    7604          19 :     if (IsVBLayer(L)) {
    7605           0 :         LOK = VB_LWP(state, L, L.LWP_EL);
    7606           0 :         DOK = VB_SWP(state, L, L.SWP_EL);      // SW diffuse
    7607           0 :         BOK = VB_SWP(state, L, L.SWP_EL, 0.0); // SW properties w/ profile ang = 0
    7608             :     } else {
    7609          19 :         L.PHI_DEG = 0.0; // phi, C, CNTRL are VB only
    7610          19 :         L.C = 0.0;
    7611          19 :         L.CNTRL = state.dataWindowEquivalentLayer->lscNONE;
    7612          19 :         if (L.LTYPE == LayerType::DRAPE) {
    7613           0 :             LOK = PD_LWP(state, L, L.LWP_EL);
    7614           0 :             DOK = PD_SWP(state, L, L.SWP_EL);           // SW diffuse
    7615           0 :             BOK = PD_SWP(state, L, L.SWP_EL, 0.0, 0.0); // SW properties w/ profile angs = 0
    7616          19 :         } else if (L.LTYPE == LayerType::INSCRN) {
    7617           2 :             LOK = IS_LWP(L, L.LWP_EL);             // LW
    7618           2 :             DOK = IS_SWP(state, L, L.SWP_EL);      // SW diffuse
    7619           2 :             BOK = IS_SWP(state, L, L.SWP_EL, 0.0); // SW beam w/ theta = 0
    7620             :         } else {
    7621          17 :             L.S = 0.0; // geometry mbrs unused
    7622          17 :             L.W = 0.0;
    7623          17 :             if (L.LTYPE == LayerType::ROLLB) {
    7624           3 :                 LOK = RB_LWP(L, L.LWP_EL);             // LW
    7625           3 :                 DOK = RB_SWP(state, L, L.SWP_EL);      // SW diffuse
    7626           3 :                 BOK = RB_SWP(state, L, L.SWP_EL, 0.0); // SW beam w/ theta = 0
    7627             :                                                        // ELSE IF (ISGZSLayer( L)) THEN
    7628             :                 // spectral glazing. Set layer xxx_MAT from GZS file data
    7629             :                 //    BOK = GZSLayerInit( L) .EQ. 0
    7630             :                 //    L%SWP_EL = L%SWP_MAT
    7631             :                 //    L%LWP_EL = L%LWP_MAT
    7632             :                 //    LOK = .TRUE.
    7633             :                 //    DOK = .TRUE.
    7634             :             } else {
    7635             :                 // glazing
    7636          14 :                 L.SWP_EL = L.SWP_MAT;
    7637          14 :                 L.LWP_EL = L.LWP_MAT;
    7638          14 :                 LOK = true;
    7639          14 :                 DOK = true;
    7640          14 :                 BOK = true;
    7641             :             }
    7642             :         }
    7643             :     }
    7644          19 :     CFSLAYERFlag = LOK && DOK && BOK;
    7645          19 : }
    7646             : 
    7647        1305 : bool IsGZSLayer(CFSLAYER const &L)
    7648             : {
    7649             :     // FUNCTION INFORMATION:
    7650             :     //       AUTHOR         JOHN L. WRIGHT, University of Waterloo, Mechanical Engineering
    7651             :     //                      Advanced Glazing System Laboratory
    7652             :     //       DATE WRITTEN   unknown
    7653             :     //       MODIFIED       na
    7654             :     //       RE-ENGINEERED  na
    7655             : 
    7656             :     // PURPOSE OF THIS FUNCTION:
    7657             :     // Returns .TRUE. if Layer has glazing data from external file or returns .FALSE.
    7658             : 
    7659             :     // Return value
    7660             :     bool IsGZSLayer;
    7661             : 
    7662        1305 :     IsGZSLayer = L.LTYPE == LayerType::GZS;
    7663        1305 :     return IsGZSLayer;
    7664             : }
    7665             : 
    7666        4897 : bool IsGlazeLayerX(CFSLAYER const &L)
    7667             : {
    7668             :     // FUNCTION INFORMATION:
    7669             :     //       AUTHOR         JOHN L. WRIGHT, University of Waterloo, Mechanical Engineering
    7670             :     //                      Advanced Glazing System Laboratory
    7671             :     //       DATE WRITTEN   unknown
    7672             :     //       MODIFIED       na
    7673             :     //       RE-ENGINEERED  na
    7674             : 
    7675             :     // PURPOSE OF THIS FUNCTION:
    7676             :     // Returns .TRUE. if Layer has glazing (including GZS) or returns .FALSE.
    7677             : 
    7678             :     // Return value
    7679             :     bool IsGlazeLayerX;
    7680             : 
    7681        4897 :     IsGlazeLayerX = L.LTYPE == LayerType::GLAZE || IsGZSLayer(L);
    7682        4897 :     return IsGlazeLayerX;
    7683             : }
    7684             : 
    7685          11 : bool IsControlledShade(EnergyPlusData &state, CFSLAYER const &L)
    7686             : {
    7687             :     // FUNCTION INFORMATION:
    7688             :     //       AUTHOR         JOHN L. WRIGHT, University of Waterloo, Mechanical Engineering
    7689             :     //                      Advanced Glazing System Laboratory
    7690             :     //       DATE WRITTEN   unknown
    7691             :     //       MODIFIED       na
    7692             :     //       RE-ENGINEERED  na
    7693             : 
    7694             :     // PURPOSE OF THIS FUNCTION:
    7695             :     // Returns .TRUE. if Layer is Venetian blind and is controlled or returns .FALSE.
    7696             : 
    7697             :     // Return value
    7698             :     bool IsControlledShade;
    7699             : 
    7700          11 :     IsControlledShade = IsVBLayer(L) && L.CNTRL != state.dataWindowEquivalentLayer->lscNONE;
    7701          11 :     return IsControlledShade;
    7702             : }
    7703             : 
    7704        4938 : bool IsVBLayer(CFSLAYER const &L)
    7705             : {
    7706             :     // FUNCTION INFORMATION:
    7707             :     //       AUTHOR         JOHN L. WRIGHT, University of Waterloo, Mechanical Engineering
    7708             :     //                      Advanced Glazing System Laboratory
    7709             :     //       DATE WRITTEN   unknown
    7710             :     //       MODIFIED       na
    7711             :     //       RE-ENGINEERED  na
    7712             : 
    7713             :     // PURPOSE OF THIS FUNCTION:
    7714             :     // Returns .TRUE. if Layer is Venetian blind, or returns .FALSE.
    7715             : 
    7716             :     // Return value
    7717             :     bool IsVBLayer;
    7718             : 
    7719        4938 :     IsVBLayer = L.LTYPE == LayerType::VBHOR || L.LTYPE == LayerType::VBVER;
    7720        4938 :     return IsVBLayer;
    7721             : }
    7722             : 
    7723           8 : void BuildGap(EnergyPlusData &state,
    7724             :               CFSGAP &G,       // returned
    7725             :               int const GType, // gap type (gtyOPENin, gtyOPENout or gtySEALED)
    7726             :               Real64 &TAS      // gap thickness, m
    7727             : )
    7728             : {
    7729             : 
    7730             :     // SUBROUTINE INFORMATION:
    7731             :     //       AUTHOR         ASHRAE 1311-RP
    7732             :     //       DATE WRITTEN   unknown
    7733             :     //       MODIFIED       Bereket Nigusse, June 2013, Jason W. DeGraw 2023
    7734             :     //       RE-ENGINEERED  na
    7735             : 
    7736             :     // PURPOSE OF THIS SUBROUTINE:
    7737             :     // fills in the effective gap thickness and calculates the gas density
    7738             :     // The gas density is calculated at a standard manufactuered condition
    7739             :     // if a different condition is not specified.
    7740             : 
    7741             :     // SUBROUTINE ARGUMENT DEFINITIONS:
    7742             :     // at time of manufacture, default = 21 C / 1 ATM
    7743             : 
    7744             :     // SUBROUTINE PARAMETER DEFINITIONS:
    7745           8 :     constexpr Real64 GapThickMin(0.0001); // Minimum gap thickness allowed, m
    7746             :     static constexpr std::string_view RoutineName("BuildGap: ");
    7747             : 
    7748           8 :     if (TAS < GapThickMin) {
    7749           0 :         ShowSevereError(state, format("{}{}", RoutineName, G.Name));
    7750           0 :         ShowContinueError(state, "...specified gap thickness is < 0.0001 m.  Reset to 0.00001 m");
    7751           0 :         TAS = GapThickMin;
    7752             :     }
    7753           8 :     G.TAS = TAS;
    7754           8 :     G.TAS_EFF = G.TAS;
    7755             :     // effective gap thickness will be adjusted later if there is in between
    7756             :     // venetian blind, see AdjustVBGap() routine
    7757             : 
    7758           8 :     G.GTYPE = GType;
    7759           8 :     G.RHOGAS = DensityCFSFillGas(G.FG, state.dataWindowEquivalentLayer->PAtmSeaLevel, 294.15);
    7760           8 : }
    7761             : 
    7762           0 : void AdjustVBGap(CFSGAP &G,        // gap, returned updated
    7763             :                  CFSLAYER const &L // adjacent layer
    7764             : )
    7765             : {
    7766             :     // SUBROUTINE INFORMATION:
    7767             :     //       AUTHOR         ASHRAE 1311-RP
    7768             :     //       DATE WRITTEN   unknown
    7769             :     //       MODIFIED       na
    7770             :     //       RE-ENGINEERED  na
    7771             : 
    7772             :     // PURPOSE OF THIS SUBROUTINE:
    7773             :     // Adjusts thickness of adjacent gaps seperated by
    7774             :     // in between slatted blind.
    7775             : 
    7776             :     // METHODOLOGY EMPLOYED:
    7777             :     // Treat VB layer as if it has 70% of actual thickness
    7778             : 
    7779             :     // REFERENCES:
    7780             :     //  Wright, J. L., N. Y. T. Huang, and M. R. Collins.  2008.
    7781             :     //  "Thermal Resistance of a Window with an Enclosed Venetian Blind: A Simplified Model,"
    7782             :     //  ASHRAE Transactions, Vol. 114, Pt. 1.
    7783             : 
    7784             :     Real64 VBTHICK;
    7785             : 
    7786           0 :     if (!IsVBLayer(L)) return; // insurance
    7787             : 
    7788           0 :     VBTHICK = L.W * std::cos(L.PHI_DEG); // VB layer thickness at slat angle
    7789           0 :     G.TAS_EFF = G.TAS + (L.W - 0.7 * VBTHICK) / 2.0;
    7790             : }
    7791             : 
    7792           8 : float DensityCFSFillGas(CFSFILLGAS const &FG, // gas properties
    7793             :                         Real64 const P,       // pressure, Pa
    7794             :                         Real64 const T        // temperature, K
    7795             : )
    7796             : {
    7797             :     // FUNCTION INFORMATION:
    7798             :     //       AUTHOR         ASHRAE 1311-RP
    7799             :     //       DATE WRITTEN   unknown
    7800             :     //       MODIFIED       na
    7801             :     //       RE-ENGINEERED  na
    7802             :     // PURPOSE OF THIS FUNCTION:
    7803             :     // Returns gas density at P and T, kg/m3
    7804             :     // METHODOLOGY EMPLOYED:
    7805             :     // Uses ideal gas relations
    7806             : 
    7807             :     // Return value
    7808             :     float DensityCFSFillGas;
    7809             : 
    7810           8 :     DensityCFSFillGas = (P * FG.MHAT) / (Constant::UniversalGasConst * max(T, 1.0));
    7811             : 
    7812           8 :     return DensityCFSFillGas;
    7813             : }
    7814             : 
    7815           0 : int CFSNGlz(CFSTY const &FS) // CFS
    7816             : {
    7817             :     // FUNCTION INFORMATION:
    7818             :     //       AUTHOR         ASHRAE 1311-RP
    7819             :     //       DATE WRITTEN   unknown
    7820             :     //       MODIFIED       na
    7821             :     //       RE-ENGINEERED  na
    7822             :     // PURPOSE OF THIS FUNCTION:
    7823             :     // Returns the number of glazing layers
    7824             : 
    7825             :     // Return value
    7826             :     int CFSNGlz;
    7827             : 
    7828             :     int iL;
    7829             : 
    7830           0 :     CFSNGlz = 0;
    7831           0 :     for (iL = 1; iL <= FS.NL; ++iL) {
    7832           0 :         if (IsGlazeLayerX(FS.L(iL))) {
    7833           0 :             ++CFSNGlz;
    7834             :         }
    7835             :     }
    7836           0 :     return CFSNGlz;
    7837             : }
    7838             : 
    7839           3 : int CFSHasControlledShade(EnergyPlusData &state, CFSTY const &FS)
    7840             : {
    7841             :     // FUNCTION INFORMATION:
    7842             :     //       AUTHOR         ASHRAE 1311-RP
    7843             :     //       DATE WRITTEN   unknown
    7844             :     //       MODIFIED       na
    7845             :     //       RE-ENGINEERED  na
    7846             :     // PURPOSE OF THIS FUNCTION:
    7847             :     // Returns index of the controlled layer in a fenestratio. If no
    7848             :     // controlled layer, then returns zero.
    7849             : 
    7850             :     // Return value
    7851             :     int CFSHasControlledShade;
    7852             : 
    7853             :     int iL;
    7854             : 
    7855           3 :     CFSHasControlledShade = 0;
    7856          14 :     for (iL = 1; iL <= FS.NL; ++iL) {
    7857          11 :         if (IsControlledShade(state, FS.L(iL))) {
    7858           0 :             CFSHasControlledShade = iL;
    7859           0 :             break;
    7860             :         }
    7861             :     }
    7862           3 :     return CFSHasControlledShade;
    7863             : }
    7864             : 
    7865          19 : void CheckAndFixCFSLayer(EnergyPlusData &state, CFSLAYER &Layer)
    7866             : {
    7867             :     // SUBROUTINE INFORMATION:
    7868             :     //       AUTHOR         ASHRAE 1311-RP
    7869             :     //       DATE WRITTEN   unknown
    7870             :     //       MODIFIED       na
    7871             :     //       RE-ENGINEERED  na
    7872             :     // PURPOSE OF THIS SUBROUTINE:
    7873             :     // Verify CFS layer validity, sets bad items to valid defaults if possible
    7874             : 
    7875          19 :     FillDefaultsSWP(state, Layer, Layer.SWP_MAT);
    7876          19 :     FinalizeCFSLAYER(state, Layer);
    7877          19 : }
    7878             : 
    7879          19 : void FillDefaultsSWP(EnergyPlusData &state,
    7880             :                      CFSLAYER const &L, // CFSLayer (input properties must be set)
    7881             :                      CFSSWP &SWP        // properties to fill
    7882             : )
    7883             : {
    7884             :     // SUBROUTINE INFORMATION:
    7885             :     //       AUTHOR         The University of WaterLoo
    7886             :     //       DATE WRITTEN   unknown
    7887             :     //       MODIFIED       Bereket Nigusse/FSEC, June 2013
    7888             :     //       RE-ENGINEERED  na
    7889             : 
    7890             :     // PURPOSE OF THIS SUBROUTINE:
    7891             :     // Fills in defaulted short wave optical properties for equivalent window
    7892             :     // layers
    7893             : 
    7894             :     // may be within L
    7895             :     static constexpr std::string_view RoutineName("FillDefaultsSWP: ");
    7896             :     bool OK;
    7897             : 
    7898             :     // default back taus to front (often equal)
    7899          19 :     if (SWP.TAUSBBB < 0.0) SWP.TAUSBBB = SWP.TAUSFBB;
    7900          19 :     if (SWP.TAUSBBD < 0.0) SWP.TAUSBBD = SWP.TAUSFBD;
    7901             : 
    7902          19 :     if (L.LTYPE == LayerType::GLAZE) {
    7903             :         // estimate diffuse properties if any < 0 or autocalculate
    7904          14 :         if (min(SWP.RHOSBDD, SWP.RHOSFDD, SWP.TAUS_DD) < 0.0) {
    7905           0 :             Specular_EstimateDiffuseProps(state, SWP);
    7906             :         }
    7907           5 :     } else if (L.LTYPE == LayerType::VBHOR || L.LTYPE == LayerType::VBVER) {
    7908             : 
    7909           5 :     } else if (L.LTYPE == LayerType::DRAPE) {
    7910             :         // estimate diffuse properties if any < 0
    7911           0 :         if (min(SWP.RHOSBDD, SWP.RHOSFDD, SWP.TAUS_DD) < 0.0) {
    7912           0 :             Fabric_EstimateDiffuseProps(state, SWP);
    7913             :         }
    7914           5 :     } else if (L.LTYPE == LayerType::ROLLB) {
    7915             :         // estimate diffuse properties if any < 0
    7916           3 :         if (min(SWP.RHOSBDD, SWP.RHOSFDD, SWP.TAUS_DD) < 0.0) {
    7917           0 :             OK = RB_SWP(state, L, SWP); // TODO RB
    7918             :         }
    7919           2 :     } else if (L.LTYPE == LayerType::INSCRN) {
    7920           2 :         if (SWP.TAUSFBB < 0.0) {
    7921           0 :             SWP.TAUSFBB = IS_OPENNESS(L.S, L.W);
    7922           0 :             if (SWP.TAUSBBB < 0.0) SWP.TAUSBBB = SWP.TAUSFBB;
    7923             :         }
    7924           2 :         if (min(SWP.RHOSBDD, SWP.RHOSFDD, SWP.TAUS_DD) < 0.0) {
    7925           0 :             OK = IS_SWP(state, L, SWP); // TODO IS
    7926             :         }
    7927           0 :     } else if (L.LTYPE == LayerType::NONE || L.LTYPE == LayerType::ROOM) {
    7928             :         // none or room: do nothing
    7929             :     } else {
    7930           0 :         ShowSevereError(state, format("{}{}.", RoutineName, L.Name));
    7931           0 :         ShowContinueError(state, "...invalid layer type specified.");
    7932             :     }
    7933          19 : }
    7934             : 
    7935           3 : void FinalizeCFS(EnergyPlusData &state, CFSTY &FS)
    7936             : {
    7937             :     // SUBROUTINE INFORMATION:
    7938             :     //       AUTHOR         The University of WaterLoo
    7939             :     //       DATE WRITTEN   unknown
    7940             :     //       MODIFIED       Bereket Nigusse/FSEC, May 2013
    7941             :     //       RE-ENGINEERED  na
    7942             : 
    7943             :     // PURPOSE OF THIS SUBROUTINE:
    7944             :     // Complete CFS after BuildCFS by checking the shade type and
    7945             :     // gap type
    7946             : 
    7947             :     static constexpr std::string_view RoutineName("FinalizeCFS: "); // include trailing blank space
    7948             : 
    7949             :     int iL;
    7950             :     int gType;
    7951             :     bool LVBPREV;
    7952           3 :     std::string CurrentModuleObject;
    7953             :     bool ErrorsFound;
    7954             : 
    7955           3 :     CurrentModuleObject = "WindowConstruction:EquivalentLayer";
    7956           3 :     ErrorsFound = false;
    7957             : 
    7958           3 :     LVBPREV = false; // .TRUE. if previous layer is VB
    7959             : 
    7960          14 :     for (iL = 1; iL <= FS.NL; ++iL) {
    7961          11 :         if (!IsVBLayer(FS.L(iL))) {
    7962          11 :             LVBPREV = false;
    7963           0 :         } else if (LVBPREV) {
    7964           0 :             ShowSevereError(state, format("{}=\"{}\", illegal.", CurrentModuleObject, FS.Name));
    7965           0 :             ShowContinueError(state, "...adjacent VB layers are specified.");
    7966           0 :             ErrorsFound = true;
    7967             :         } else {
    7968           0 :             LVBPREV = true;
    7969           0 :             if (iL > 1) AdjustVBGap(FS.G(iL - 1), FS.L(iL));
    7970           0 :             if (iL < FS.NL) AdjustVBGap(FS.G(iL), FS.L(iL));
    7971             :         }
    7972          11 :         if (iL < FS.NL) {
    7973           8 :             gType = FS.G(iL).GTYPE;
    7974           8 :             if (gType == state.dataWindowEquivalentLayer->gtyOPENout && iL != 1) {
    7975           0 :                 ShowSevereError(state, format("{}=\"{}", CurrentModuleObject, FS.Name));
    7976           0 :                 ShowContinueError(state, format("...invalid EquivalentLayer window gap type specified ={}.", FS.G(iL).Name));
    7977           0 :                 ShowContinueError(state, "...VentedOutDoor gap is not outermost.");
    7978             :             }
    7979           8 :             if (gType == state.dataWindowEquivalentLayer->gtyOPENin && iL != FS.NL - 1) {
    7980           0 :                 ShowSevereError(state, format("{}=\"{}", CurrentModuleObject, FS.Name));
    7981           0 :                 ShowContinueError(state, format("...invalid EquivalentLayer window gap type specified ={}.", FS.G(iL).Name));
    7982           0 :                 ShowContinueError(state, "...VentedIndoor gap is not innermost.");
    7983             :             }
    7984             :         }
    7985             :     }
    7986           3 :     if (ErrorsFound) {
    7987           0 :         ShowFatalError(state, format("{}Program terminates for preceding reason(s).", RoutineName));
    7988             :     }
    7989           3 : }
    7990             : 
    7991       16173 : Real64 EffectiveEPSLF(CFSTY const &FS) // Complex Fenestration
    7992             : {
    7993             :     // FUNCTION INFORMATION:
    7994             :     //       AUTHOR         <unknown>, ASHRAE 1311-RP
    7995             :     //       DATE WRITTEN   unknown
    7996             :     //       MODIFIED       na
    7997             :     //       RE-ENGINEERED  na
    7998             :     // PURPOSE OF THIS FUNCTION:
    7999             :     // Returns effective outside Longwave emissivity. Handles partially
    8000             :     // transparent layers
    8001             : 
    8002             :     // Return value
    8003             :     Real64 EffectiveEPSLF;
    8004             : 
    8005             :     Real64 E;  // Effective emissivity
    8006             :     Real64 TX; // correction factor
    8007             :     int iL;    // layers index
    8008             : 
    8009       16173 :     E = 0.0;
    8010       16173 :     TX = 1.0;
    8011       21564 :     for (iL = 1; iL <= FS.NL + 1; ++iL) {
    8012       21564 :         if (iL == FS.NL + 1) {
    8013           0 :             E += 0.9 * TX;
    8014             :         } else {
    8015       21564 :             E += FS.L(iL).LWP_EL.EPSLF * TX;
    8016       21564 :             if (FS.L(iL).LWP_EL.TAUL < 0.001) break;
    8017        5391 :             TX *= FS.L(iL).LWP_EL.TAUL;
    8018             :         }
    8019             :     }
    8020       16173 :     EffectiveEPSLF = E;
    8021       16173 :     return EffectiveEPSLF;
    8022             : }
    8023             : 
    8024       45837 : Real64 EffectiveEPSLB(CFSTY const &FS) // Complex Fenestration
    8025             : {
    8026             :     // FUNCTION INFORMATION:
    8027             :     //       AUTHOR         <unknown>, ASHRAE 1311-RP
    8028             :     //       DATE WRITTEN   unknown
    8029             :     //       MODIFIED       na
    8030             :     //       RE-ENGINEERED  na
    8031             :     // PURPOSE OF THIS FUNCTION:
    8032             :     // Returns effective inside (room side) Longwave emissivity. Handles partially
    8033             :     // transparent layers
    8034             : 
    8035             :     // Return value
    8036             :     Real64 EffectiveEPSLB;
    8037             : 
    8038             :     Real64 E;  // Effective emissivity
    8039             :     Real64 TX; // correction factor
    8040             :     int iL;    // layers index
    8041             : 
    8042       45837 :     E = 0.0;
    8043       45837 :     TX = 1.0;
    8044       61116 :     for (iL = FS.NL; iL >= 0; --iL) {
    8045       61116 :         if (iL == 0) {
    8046           0 :             E += 0.9 * TX;
    8047             :         } else {
    8048       61116 :             E += FS.L(iL).LWP_EL.EPSLB * TX;
    8049       61116 :             if (FS.L(iL).LWP_EL.TAUL < 0.001) break;
    8050       15279 :             TX *= FS.L(iL).LWP_EL.TAUL;
    8051             :         }
    8052             :     }
    8053       45837 :     EffectiveEPSLB = E;
    8054       45837 :     return EffectiveEPSLB;
    8055             : }
    8056             : 
    8057           3 : bool FEQX(Real64 const a, // values to compare, fractional tolerance
    8058             :           Real64 const b,
    8059             :           Real64 const tolF,
    8060             :           const Real64 tolAbs // absolute tolerance
    8061             : )
    8062             : {
    8063             :     // FUNCTION INFORMATION:
    8064             :     //       AUTHOR         <unknown>, ASHRAE 1311-RP
    8065             :     //       DATE WRITTEN   unknown
    8066             :     //       MODIFIED       na
    8067             :     //       RE-ENGINEERED  na
    8068             :     // PURPOSE OF THIS FUNCTION:
    8069             :     // Returns true if the difference between two real numbers is within the
    8070             :     // tolerance limit specified.
    8071             : 
    8072             :     // Return value
    8073             :     bool FEQX;
    8074             : 
    8075             :     Real64 d;
    8076             :     Real64 tolAbsX;
    8077             : 
    8078           3 :     tolAbsX = max(tolAbs, 1.e-10);
    8079             : 
    8080           3 :     d = std::abs(a - b);
    8081           3 :     if (d < tolAbsX) {
    8082           3 :         FEQX = true;
    8083             :     } else {
    8084           0 :         FEQX = (2.0 * d / (std::abs(a) + std::abs(b))) < tolF;
    8085             :     }
    8086           3 :     return FEQX;
    8087             : }
    8088             : 
    8089           0 : Real64 TRadC(Real64 const J,    // radiosity, W/m2
    8090             :              Real64 const Emiss // surface emissivity
    8091             : )
    8092             : {
    8093             :     // FUNCTION INFORMATION:
    8094             :     //       AUTHOR         <unknown>, ASHRAE 1311-RP
    8095             :     //       DATE WRITTEN   unknown
    8096             :     //       MODIFIED       na
    8097             :     //       RE-ENGINEERED  na
    8098             :     // PURPOSE OF THIS FUNCTION:
    8099             :     // Returns equivalent celsius scale temperature from radiosity
    8100             : 
    8101           0 :     return root_4(J / (Constant::StefanBoltzmann * max(Emiss, 0.001))) - Constant::Kelvin;
    8102             : }
    8103             : 
    8104        4666 : void CalcEQLOpticalProperty(EnergyPlusData &state,
    8105             :                             int const SurfNum,
    8106             :                             SolarArrays const BeamDIffFlag, // identifier index of diffuse and beam SW radiation
    8107             :                             Array2A<Real64> CFSAbs          // absorbed beam solar radiation by layers fraction
    8108             : )
    8109             : {
    8110             : 
    8111             :     // SUBROUTINE INFORMATION:
    8112             :     //       AUTHOR         Bereket Nigusse
    8113             :     //       DATE WRITTEN   May 2013
    8114             :     //       MODIFIED       na
    8115             :     //       RE-ENGINEERED  na
    8116             : 
    8117             :     // PURPOSE OF THIS SUBROUTINE:
    8118             :     // Calculates the system optical properties from the individual layers
    8119             :     // properties at each time step. The values returned are the layer-by-layer
    8120             :     // absorptance and system transmittance for both beam and diffuse radiation.
    8121             : 
    8122             :     // METHODOLOGY EMPLOYED:
    8123             :     // Uses the net radiation method developed for ASHWAT fenestration
    8124             :     // model (ASHRAE RP-1311) by John Wright, the University of WaterLoo
    8125             : 
    8126             :     using Dayltg::ProfileAngle;
    8127             : 
    8128             :     // Argument array dimensioning
    8129        4666 :     CFSAbs.dim(2, CFSMAXNL + 1);
    8130             : 
    8131             :     Real64 ProfAngVer; // Solar vertical profile angle (radians) for horizontal blind
    8132             :     Real64 ProfAngHor; // Solar horizontal profile angle (radians) for vertical blind
    8133             :     Real64 IncAng;     // incident angle degree
    8134        9332 :     Array2D<Real64> Abs1(2, CFSMAXNL + 1);
    8135             :     int Lay;       // window layer index
    8136             :     int EQLNum;    // equivalent layer window construction index
    8137             :     int ConstrNum; // construction index
    8138             : 
    8139        4666 :     auto &CFS = state.dataWindowEquivLayer->CFS;
    8140             : 
    8141        4666 :     IncAng = 0.0; // Autodesk:Init Added to elim use uninitialized
    8142        4666 :     CFSAbs = 0.0;
    8143        4666 :     ProfAngHor = 0.0;
    8144        4666 :     ProfAngVer = 0.0;
    8145        4666 :     ConstrNum = state.dataSurface->Surface(SurfNum).Construction;
    8146        4666 :     EQLNum = state.dataConstruction->Construct(state.dataSurface->Surface(SurfNum).Construction).EQLConsPtr;
    8147        4666 :     if (BeamDIffFlag != SolarArrays::DIFF) {
    8148        1386 :         if (state.dataHeatBal->SurfCosIncAng(state.dataGlobal->HourOfDay, state.dataGlobal->TimeStep, SurfNum) <= 0.0) return;
    8149             : 
    8150        6272 :         for (Lay = 1; Lay <= CFS(EQLNum).NL; ++Lay) {
    8151        4886 :             if (IsVBLayer(CFS(EQLNum).L(Lay))) {
    8152           0 :                 if (CFS(EQLNum).L(Lay).LTYPE == LayerType::VBHOR) {
    8153           0 :                     ProfAngVer = ProfileAngle(state, SurfNum, state.dataEnvrn->SOLCOS, DataWindowEquivalentLayer::Orientation::Horizontal);
    8154           0 :                 } else if (CFS(EQLNum).L(Lay).LTYPE == LayerType::VBVER) {
    8155           0 :                     ProfAngHor = ProfileAngle(state, SurfNum, state.dataEnvrn->SOLCOS, DataWindowEquivalentLayer::Orientation::Vertical);
    8156             :                 }
    8157             :             }
    8158             :         }
    8159             :         // Incident angle
    8160        1386 :         IncAng = std::acos(state.dataHeatBal->SurfCosIncAng(state.dataGlobal->HourOfDay, state.dataGlobal->TimeStep, SurfNum));
    8161        1386 :         CalcEQLWindowOpticalProperty(state, CFS(EQLNum), BeamDIffFlag, Abs1, IncAng, ProfAngVer, ProfAngHor);
    8162        1386 :         CFSAbs(1, {1, CFSMAXNL + 1}) = Abs1(1, {1, CFSMAXNL + 1});
    8163        1386 :         CFSAbs(2, {1, CFSMAXNL + 1}) = Abs1(2, {1, CFSMAXNL + 1});
    8164             :     } else {
    8165        3280 :         if (state.dataWindowEquivalentLayer->EQLDiffPropFlag(EQLNum)) {
    8166          14 :             for (Lay = 1; Lay <= CFS(EQLNum).NL; ++Lay) {
    8167          11 :                 if (IsVBLayer(CFS(EQLNum).L(Lay))) {
    8168           0 :                     if (CFS(EQLNum).L(Lay).LTYPE == LayerType::VBHOR) {
    8169           0 :                         ProfAngVer = ProfileAngle(state, SurfNum, state.dataEnvrn->SOLCOS, DataWindowEquivalentLayer::Orientation::Horizontal);
    8170           0 :                     } else if (CFS(EQLNum).L(Lay).LTYPE == LayerType::VBVER) {
    8171           0 :                         ProfAngHor = ProfileAngle(state, SurfNum, state.dataEnvrn->SOLCOS, DataWindowEquivalentLayer::Orientation::Vertical);
    8172             :                     }
    8173             :                 }
    8174             :             }
    8175           3 :             IncAng = std::acos(state.dataHeatBal->SurfCosIncAng(state.dataGlobal->HourOfDay, state.dataGlobal->TimeStep, SurfNum));
    8176           3 :             CalcEQLWindowOpticalProperty(state, CFS(EQLNum), BeamDIffFlag, Abs1, IncAng, ProfAngVer, ProfAngHor);
    8177           3 :             CFSAbs(_, {1, CFSMAXNL + 1}) = Abs1(_, {1, CFSMAXNL + 1});
    8178           3 :             state.dataWindowEquivalentLayer->CFSDiffAbsTrans(_, {1, CFSMAXNL + 1}, EQLNum) = Abs1(_, {1, CFSMAXNL + 1});
    8179           3 :             state.dataConstruction->Construct(ConstrNum).TransDiff = Abs1(1, CFS(EQLNum).NL + 1);
    8180           3 :             state.dataConstruction->Construct(ConstrNum).AbsDiffFrontEQL({1, CFSMAXNL}) = Abs1(1, {1, CFSMAXNL});
    8181           3 :             state.dataConstruction->Construct(ConstrNum).AbsDiffBackEQL({1, CFSMAXNL}) = Abs1(2, {1, CFSMAXNL});
    8182           3 :             state.dataConstruction->Construct(ConstrNum).ReflectSolDiffFront = CFS(EQLNum).L(1).SWP_EL.RHOSFDD;
    8183           3 :             state.dataConstruction->Construct(ConstrNum).ReflectSolDiffBack = CFS(EQLNum).L(CFS(EQLNum).NL).SWP_EL.RHOSBDD;
    8184           3 :             if (!CFS(EQLNum).ISControlled) state.dataWindowEquivalentLayer->EQLDiffPropFlag(EQLNum) = false;
    8185             :         } else {
    8186        3277 :             CFSAbs(_, {1, CFSMAXNL + 1}) = state.dataWindowEquivalentLayer->CFSDiffAbsTrans(_, {1, CFSMAXNL + 1}, EQLNum);
    8187        3277 :             state.dataConstruction->Construct(ConstrNum).TransDiff = state.dataWindowEquivalentLayer->CFSDiffAbsTrans(1, CFS(EQLNum).NL + 1, EQLNum);
    8188        3277 :             state.dataConstruction->Construct(ConstrNum).AbsDiffFrontEQL({1, CFSMAXNL}) = CFSAbs(1, {1, CFSMAXNL});
    8189        3277 :             state.dataConstruction->Construct(ConstrNum).AbsDiffBackEQL({1, CFSMAXNL}) = CFSAbs(2, {1, CFSMAXNL});
    8190             :         }
    8191             :     }
    8192        4666 :     if (CFS(EQLNum).VBLayerPtr > 0) {
    8193           0 :         state.dataSurface->SurfWinSlatAngThisTSDeg(SurfNum) = CFS(EQLNum).L(CFS(EQLNum).VBLayerPtr).PHI_DEG;
    8194             :     }
    8195        4666 : }
    8196             : 
    8197           3 : void CalcEQLWindowStandardRatings(EnergyPlusData &state, int const ConstrNum) // construction index
    8198             : {
    8199             : 
    8200             :     // SUBROUTINE INFORMATION:
    8201             :     //       AUTHOR         Bereket Nigusse
    8202             :     //       DATE WRITTEN   May 2013
    8203             :     //       MODIFIED       na
    8204             :     //       RE-ENGINEERED  na
    8205             : 
    8206             :     // PURPOSE OF THIS SUBROUTINE:
    8207             :     // Calculates the U-value, SHGC and Normal Transmittance of equivalent layer
    8208             :     // fenestration.
    8209             : 
    8210             :     // METHODOLOGY EMPLOYED:
    8211             :     // Uses routine developed for ASHRAE RP-1311 (ASHWAT Model)
    8212             : 
    8213             :     Real64 UValue;
    8214             :     int EQLNum;
    8215             :     Real64 SHGCSummer;
    8216             :     Real64 TransNormal;
    8217             : 
    8218           3 :     UValue = 0.0;
    8219           3 :     SHGCSummer = 0.0;
    8220           3 :     TransNormal = 0.0;
    8221             : 
    8222           3 :     EQLNum = state.dataConstruction->Construct(ConstrNum).EQLConsPtr;
    8223             : 
    8224             :     // calculate fenestration air-to-air U-value
    8225           3 :     CalcEQLWindowUvalue(state, state.dataWindowEquivLayer->CFS(EQLNum), UValue);
    8226           3 :     state.dataHeatBal->NominalU(ConstrNum) = UValue;
    8227             : 
    8228             :     // calculate the SHGC and Normal Transmittance
    8229           3 :     CalcEQLWindowSHGCAndTransNormal(state, state.dataWindowEquivLayer->CFS(EQLNum), SHGCSummer, TransNormal);
    8230           3 :     state.dataConstruction->Construct(ConstrNum).SummerSHGC = SHGCSummer;
    8231           3 :     state.dataConstruction->Construct(ConstrNum).SolTransNorm = TransNormal;
    8232           3 : }
    8233             : 
    8234       37770 : Real64 EQLWindowInsideEffectiveEmiss(EnergyPlusData &state, int const ConstrNum)
    8235             : {
    8236             :     // FUNCTION INFORMATION:
    8237             :     //       AUTHOR         Bereket A Nigusse
    8238             :     //       DATE WRITTEN   May 2013
    8239             :     //       MODIFIED       na
    8240             :     //       RE-ENGINEERED  na
    8241             : 
    8242             :     // PURPOSE OF THIS FUNCTION:
    8243             :     // Given the consruction number, returns the equivalent layer inside
    8244             :     // face effective longwave emmisivity.
    8245             : 
    8246       37770 :     return EffectiveEPSLB(state.dataWindowEquivLayer->CFS(state.dataConstruction->Construct(ConstrNum).EQLConsPtr));
    8247             : }
    8248             : 
    8249        8109 : Real64 EQLWindowOutsideEffectiveEmiss(EnergyPlusData &state, int const ConstrNum)
    8250             : {
    8251             :     // FUNCTION INFORMATION:
    8252             :     //       AUTHOR         Bereket A Nigusse
    8253             :     //       DATE WRITTEN   May 2013
    8254             :     //       MODIFIED       na
    8255             :     //       RE-ENGINEERED  na
    8256             : 
    8257             :     // PURPOSE OF THIS FUNCTION:
    8258             :     // Given the consruction number, returns the equivalent layer outside
    8259             :     // face effective longwave emmisivity.
    8260             : 
    8261             :     // Return value
    8262             :     Real64 OutSideLWEmiss; // LW outside emissivity
    8263             : 
    8264             :     int EQLNum; // EQL Window object number
    8265             : 
    8266        8109 :     EQLNum = state.dataConstruction->Construct(ConstrNum).EQLConsPtr;
    8267        8109 :     OutSideLWEmiss = EffectiveEPSLF(state.dataWindowEquivLayer->CFS(EQLNum));
    8268             : 
    8269        8109 :     return OutSideLWEmiss;
    8270             : }
    8271             : 
    8272          33 : Real64 HCInWindowStandardRatings(EnergyPlusData &state,
    8273             :                                  Real64 const Height,  // Window height, 1.0 m
    8274             :                                  Real64 const TSurfIn, // Inside surface temperature
    8275             :                                  Real64 const TAirIn   // Zone Air Temperature
    8276             : )
    8277             : {
    8278             :     // FUNCTION INFORMATION:
    8279             :     //       AUTHOR         Bereket Nigusse
    8280             :     //       DATE WRITTEN   June 2013
    8281             :     //       MODIFIED       na
    8282             :     //       RE-ENGINEERED  na
    8283             : 
    8284             :     // PURPOSE OF THIS FUNCTION:
    8285             :     // Return the inside convection coefficient for fenestration ratings.
    8286             :     // This procedure is adopted from WindowTempsForNominalCond routine.
    8287             :     // METHODOLOGY EMPLOYED:
    8288             :     // Uses ISO Standard 15099 method to calculate the inside surface
    8289             :     // convection coefficient for fenestration ratings.
    8290             : 
    8291             :     using Psychrometrics::PsyRhoAirFnPbTdbW;
    8292             : 
    8293             :     // Return value
    8294             :     Real64 hcin; // interior surface convection coefficient
    8295             : 
    8296             :     static constexpr std::string_view RoutineName("HCInWindowStandardRatings");
    8297             : 
    8298             :     Real64 TmeanFilm;       // mean film temperature
    8299             :     Real64 TmeanFilmKelvin; // mean film temperature for property evaluation
    8300             :     Real64 rho;             // density of (apparently dry) air [kg/m3]
    8301             :     Real64 Cp;              // specific heat of air [J/kg-K]
    8302             :     Real64 lambda;          // thermal conductivity of air [W/m-K]
    8303             :     Real64 mu;              // dynamic viscosity of air [kg/m-s]
    8304             :     Real64 RaH;             // Rayleigh number for cavity height [ Non dim]
    8305             :     Real64 TiltDeg;         // glazing tilt in degrees
    8306             :     Real64 sineTilt;        // sine of glazing tilt
    8307             :     Real64 Nuint;           // Nusselt number for interior surface convection
    8308             : 
    8309          33 :     TiltDeg = 90.0;
    8310          33 :     sineTilt = std::sin(TiltDeg * Constant::DegToRadians); // degrees as arg
    8311             : 
    8312             :     // Begin calculating for ISO 15099 method.
    8313             :     // mean film temperature
    8314          33 :     TmeanFilmKelvin = TAirIn + 0.25 * (TSurfIn - TAirIn); // eq. 133 in ISO 15099
    8315          33 :     TmeanFilm = TmeanFilmKelvin - 273.15;
    8316             :     // the following properties are constants or linear relations for "standard" type reporting
    8317          33 :     rho = PsyRhoAirFnPbTdbW(state, 101325.0, TmeanFilm, 0.0, RoutineName); // dry air assumption
    8318             : 
    8319          33 :     lambda = 2.873E-3 + 7.76E-5 * TmeanFilmKelvin; // Table B.1 in ISO 15099
    8320          33 :     mu = 3.723E-6 + 4.94E-8 * TmeanFilmKelvin;     // Table B.2 in ISO 15099
    8321          33 :     Cp = 1002.737 + 1.2324E-2 * TmeanFilmKelvin;   // Table B.3 in ISO 15099
    8322             : 
    8323          33 :     RaH = (pow_2(rho) * pow_3(Height) * Constant::GravityConstant * Cp * std::abs(TSurfIn - TAirIn)) /
    8324          33 :           (TmeanFilmKelvin * mu * lambda); // eq 132 in ISO 15099
    8325             : 
    8326             :     // eq. 135 in ISO 15099 (only need this one because tilt is 90 deg)
    8327          33 :     Nuint = 0.56 * root_4(RaH * sineTilt);
    8328          33 :     hcin = Nuint * lambda / Height;
    8329             : 
    8330          33 :     return hcin;
    8331             : }
    8332             : 
    8333             : } // namespace EnergyPlus::WindowEquivalentLayer

Generated by: LCOV version 1.14