LCOV - code coverage report
Current view: top level - EnergyPlus - WindowEquivalentLayer.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 1448 3308 43.8 %
Date: 2023-01-17 19:17:23 Functions: 59 97 60.8 %

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

Generated by: LCOV version 1.13