LCOV - code coverage report
Current view: top level - EnergyPlus - WindowEquivalentLayer.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 47.2 % 3323 1570
Test Date: 2025-05-22 16:09:37 Functions: 60.6 % 99 60

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

Generated by: LCOV version 2.0-1