LCOV - code coverage report
Current view: top level - EnergyPlus - WindowEquivalentLayer.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 43.6 % 3380 1475
Test Date: 2025-06-02 07:23:51 Functions: 59.6 % 99 59

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

Generated by: LCOV version 2.0-1